mcpField
U
understanding-streamlit-architecture

understanding-streamlit-architecture

github.com/streamlit开发46.2k120 次安装今天更新
代码仓库

关于 understanding-streamlit-architecture

帮助开发者理解 Streamlit 架构并快速定位实现细节的文档技能,涵盖 Python 后端、React 前端及其通信协议。

主要功能

  1. 01梳理后端与前端组件
  2. 02说明 WebSocket 与 Protobuf 通信
  3. 03解释脚本重运行和会话状态
  4. 04提供功能实现导航

适用场景

  1. 01熟悉 Streamlit 的执行模型
  2. 02定位界面元素的前后端代码
  3. 03开发 Streamlit 新功能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/streamlit/streamlit --skill understanding-streamlit-architecture

安装后在 Claude Code 中输入/understanding-streamlit-architecture确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
backend.md
communication.md
element-identity.md
frontend.md
layout.md

详细介绍

理解 Streamlit 架构

Streamlit 是一个客户端-服务应用,使用 Protocol Buffers 进行双向 WebSocket 通信。 将此文件用作快速的心智模型和导航索引;实现细节请使用 references/backend.md、references/frontend.md 和 references/communication.md。

概念术语表

概念描述关键文件
命令在 Streamlit 的公共 API(st.* 命名空间)中暴露的任何函数。命令可以创建元素/组件、控制执行流程或配置应用行为。lib/streamlit/delta_generator.py、lib/streamlit/elements/、lib/streamlit/commands/
元素Streamlit 中所有 UI 组件的统称:组件、容器和显示元素。在 Element.proto 中表示为约 50+ 种类型的 oneof 联合。proto/streamlit/proto/Element.proto、lib/streamlit/elements/
组件交互式元素(按钮、滑块、text_input),通常在用户交互时触发重运行。值可通过返回值或 st.session_state 访问。支持 on_change="ignore" 的组件在浏览器中更新而不会重运行,直到其他内容触发。某些元素会条件性地变为组件(例如带有 on_select 的 dataframe/chart)。lib/streamlit/elements/widgets/、frontend/lib/src/components/widgets/
显示元素非交互式元素(文本、markdown、图片、图表),渲染内容而本身不会触发重运行。lib/streamlit/elements/、frontend/lib/src/components/elements/
容器在空间上对元素进行分组的布局块(侧边栏、列、展开器、标签页、表单)。在元素树中表示为 BlockNode。lib/streamlit/elements/layouts.py、Block.proto
DeltaGeneratorst 对象;将 UI 增量排入队列的 API 入口点。使用 mixin 模式组合所有 st.* 命令。lib/streamlit/delta_generator.py
会话状态每个会话的字典(st.session_state),在重运行之间持久保存数据。存储组件值和用户变量。lib/streamlit/runtime/state/session_state.py
重运行为当前页面重新执行用户脚本。由组件交互、st.rerun()、文件更改或 fragment 定时器触发。在保留会话状态的同时重建元素树。lib/streamlit/runtime/scriptrunner/script_runner.py、lib/streamlit/commands/execution_control.py
表单容器(st.form),批处理组件输入,将重运行推迟到表单提交时。lib/streamlit/elements/form.py、WidgetStateManager.ts
Fragment装饰器(@st.fragment),允许特定 UI 部分部分重运行而无需完整重新执行脚本。lib/streamlit/runtime/fragment.py
缓存装饰器(@st.cache_data、@st.cache_resource),对函数结果进行记忆化以避免冗余计算。lib/streamlit/runtime/caching/
页面多页面应用系统,使用 st.navigation() 和 st.Page() 或从 pages/ 目录自动发现。lib/streamlit/navigation/、lib/streamlit/runtime/pages_manager.py
配置通过 .streamlit/config.toml 进行应用配置,控制服务器、客户端和主题设置。lib/streamlit/config.py、lib/streamlit/config_option.py
主题可自定义的 UI 主题(浅色/深色/自定义),在配置中或通过主题编辑器定义。lib/streamlit/runtime/theme_util.py、frontend/lib/src/theme/
密钥通过 .streamlit/secrets.toml(本地)或平台设置(已部署)进行安全凭据存储。通过 st.secrets 访问。lib/streamlit/runtime/secrets.py
连接数据库/服务抽象(st.connection),内置缓存和密钥集成。lib/streamlit/connections/
自定义组件使用 React/iframe 的用户构建扩展。v1(旧版):declare_component() API。v2(当前):具有改进状态管理的双向组件。frontend/component-lib/、frontend/component-v2-lib/、lib/streamlit/components/v1/、lib/streamlit/components/v2/
静态文件服务static/ 目录中的文件通过 /app/static/* 直接提供(当启用静态服务时)。lib/streamlit/web/server/server.py、lib/streamlit/web/server/starlette/starlette_routes.py
应用测试测试框架(AppTest),用于模拟用户交互和检查渲染输出。lib/streamlit/testing/

核心心智模型

flowchart TB
    subgraph Backend["Backend (Python)"]
        Script[User Script]
        DG[DeltaGenerator]
        Runtime[Runtime/AppSession]
    end

    subgraph Protocol["WebSocket + Protobuf"]
        FM[ForwardMsg]
        BM[BackMsg]
    end

    subgraph Frontend["Frontend (React)"]
        App[App.tsx]
        Tree[AppRoot Tree]
        Renderer[ElementNodeRenderer]
        WSM[WidgetStateManager]
    end

    Script --> DG
    DG --> FM
    FM --> App
    App --> Tree
    Tree --> Renderer
    Renderer --> WSM
    WSM -->|User interaction| BM
    BM --> Runtime
    Runtime -->|Rerun| Script

关键洞见:脚本执行由重跑驱动:大多数组件交互都会触发重跑(整个应用或片段范围)。状态通过 st.session_state 和缓存装饰器持久化。

执行模型

Streamlit 的执行模型与传统 Web 框架不同:

重跑触发条件:

  1. 组件交互:用户点击按钮、移动滑块等(带有 on_change="ignore" 的组件更新时不会重跑)
  2. 源代码更改:文件监视器检测到脚本修改
  3. st.rerun():显式的程序化重跑
  4. 片段定时器:@st.fragment(run_every=...) 周期性重跑

执行顺序的细微之处:

  • 每次重跑时脚本都自上而下执行
  • 回调优先:on_change/on_click 处理程序在主脚本主体之前运行
  • 片段通常会隔离重跑:@st.fragment 内部的组件交互通常只重跑该片段
  • 带键的片段重跑:从组件回调中调用 st.rerun("<key>") 只会重跑指定的 @st.fragment(key=...) 片段
  • 控制流异常:st.stop()、st.rerun()、st.switch_page() 会抛出异常以中止或重定向执行

会话隔离:

  • 每个浏览器标签页 = 单独的 AppSession,拥有自己的 SessionState
  • 刷新页面会创建新会话(除非在 TTL 内重新连接)
  • 会话之间不共享状态(多用户状态请使用外部存储)

跨重跑持久化的内容(同一会话内):

  • st.session_state 的值
  • 缓存函数结果(@st.cache_data、@st.cache_resource)
  • 上传的文件
  • 片段注册信息

每次重跑都会重置的内容:

  • 脚本中的局部变量
  • 组件的返回值(从 SessionState 重新读取)
  • 元素树(从头重建,然后进行差异比较)

架构分层

后端(Python)
组件文件用途
Runtimelib/streamlit/runtime/runtime.py管理应用生命周期和会话的单例
AppSessionlib/streamlit/runtime/app_session.py每个浏览器标签页:ScriptRunner + SessionState + ForwardMsgQueue
ScriptRunnerlib/streamlit/runtime/scriptrunner/script_runner.py在独立线程中执行用户脚本
DeltaGeneratorlib/streamlit/delta_generator.py使用 mixin 模式的 API 入口点
SessionStatelib/streamlit/runtime/state/session_state.py组件值和用户变量
Elementslib/streamlit/elements/st.* 命令的后端实现

后端深入解析:参见 references/backend.md

前端(TypeScript/React)
组件文件用途
Appfrontend/app/src/App.tsx中央协调器
AppRootfrontend/lib/src/render-tree/AppRoot.ts包含 4 个容器的不可变元素树
ElementNodeRendererfrontend/lib/src/components/core/Block/ElementNodeRenderer.tsx将 proto 映射到 React 组件
WidgetStateManagerfrontend/lib/src/WidgetStateManager.ts组件状态、表单、查询参数
ConnectionManagerfrontend/connection/src/ConnectionManager.tsWebSocket 状态机

前端深入解析:参见 references/frontend.md

通信(Protobuf)
Proto用途
ForwardMsg.proto服务器到客户端:增量、会话事件、导航
BackMsg.proto客户端到服务器:带有组件状态的重跑请求
Element.protooneof type 联合中约 50+ 种元素类型
WidgetStates.proto组件值:trigger_value、string_value、bool_value 等

位置:proto/streamlit/proto/

协议深入解析:参见 references/communication.md

核心概念(快速导览)

  • 布局系统:元素的宽度/高度参数、flexbox 容器以及响应式尺寸。
  • 脚本重跑模型:组件交互 -> BackMsg(ClientState)-> 后端更新 SessionState -> 脚本重跑 -> ForwardMsg 增量。
    • 深入阅读:references/communication.md#widget-interaction-to-script-rerun
  • 增量路径系统:元素通过增量路径(例如 [0, 2, 3])寻址,以支持高效的树更新。
    • 深入阅读:references/communication.md#delta-ui-changes
  • active_script_hash 语义:ForwardMsg.metadata.active_script_hash 在多页面和 fragment 重跑之间界定节点归属。
    • 深入阅读:references/communication.md#forwardmsg-metadata-active_script_hash
  • 元素树结构:前端 AppRoot 维护 main、sidebar、event 和 bottom 容器,其中包含 BlockNode/ElementNode。
    • 深入阅读:references/frontend.md#element-tree-frontendlibsrcrender-tree
  • 元素标识语义:增量路径决定节点所在位置;元素 ID 决定有状态元素在重新挂载后能否重新连接到先前的状态。
    • 深入阅读:references/element-identity.md
  • Fragment(@st.fragment):fragment 交互通常会触发 fragment 范围内的重跑,并只更新受影响的区域。当 fragment 使用 @st.fragment(key=...) 声明时,组件回调也可以通过 st.rerun("<key>") 定向到指定的 fragment。

元素标识

  • 增量路径控制节点在渲染树中的放置位置。
  • 元素 ID控制有状态元素在重新挂载后能否重新连接到先前的状态。
  • 组件使用 ID 来连接前端 WidgetStateManager 状态、BackMsg.WidgetStates、后端 SessionState、回调以及 st.session_state。
  • 某些非组件元素也使用 ID 进行仅前端重建(例如图表视图状态或媒体自动播放守卫)。
  • 增量路径变化可能导致元素重新挂载,但稳定的 element.id 仍可让 React 在叶子节点保持在同一渲染父列表下时保留它。

深入阅读:references/element-identity.md

关键实现模式

  • 后端 mixin 组合:DeltaGenerator 通过 mixin 组合 st.* API。
    • 深入阅读:references/backend.md#deltagenerator-libstreamlitdelta_generatorpy
  • 前端访问者模式:渲染树更新/过期清理使用访问者。
    • 深入阅读:references/frontend.md#visitor-pattern
  • 消息去重:ForwardMsg.hash + ref_hash 配合前端 ForwardMsgCache 可减少带宽。
    • 深入阅读:references/communication.md#message-caching

快速参考:添加功能

  1. Proto 定义:proto/streamlit/proto/<Element>.proto
  2. 在 Element.proto 中注册:添加到 oneof type
  3. 后端 mixin:lib/streamlit/elements/<element>.py
  4. 前端组件:frontend/lib/src/components/elements/<Element>/ 或 frontend/lib/src/components/widgets/<Element>/(取决于元素还是组件)
  5. 在 ElementNodeRenderer 中注册:向 switch 语句添加 case
  6. 编译 proto:make protobuf

详细的实现指南请参见 wiki/new-feature-guide.md。

维护本文档

当进行会影响此处记录的任何概念(Runtime、AppSession、DeltaGenerator、元素树、通信协议、元素标识等)的更改时,请更新本技能文件中相关章节(SKILL.md、references/backend.md、references/frontend.md、references/communication.md、references/element-identity.md),以保持其准确。

评论

支持 Markdown