[Ai Agent] 13 用 Streamlit 为 Agents SDK 打造可视化“驾驶舱”
本文阐述Streamlit因与Agent状态同步而成为首选前端,详解其七种核心组件,实战搭建动态转接、流式输出的多智能体可视化驾驶舱。
博客配套代码发布于github:13 Streamlit 快速入门
相关Agent专栏:Ai Agent教学
本系列所有博客均配套Gihub开源代码,开箱即用,仅需配置API_KEY。
如果该Agent教学系列帮到了你,欢迎给我个Star⭐!
知识点:Streamlit | st.session_state | Streamlit组件 | 异步事件流 | 会话持久化
前言、
在 M12 中,我们基于 Agents SDK 实现了一套 Swarm 风格的多智能体系统:多个 Agent 能自动转接、共享上下文、协同调用工具——但它还只是“看不见的引擎”。
现在,是时候给它装上仪表盘、状态灯和操作杆,变成一个真正可交互的 AI 产品。
可别误以为这个前端的架子学起来很吃力:
对 Agent 开发者而言,Streamlit 就是你的前端答案:无需 HTML/CSS/JS,只需写 Python,就能获得:
- 🖨️ 流式打字机效果(逐字输出 LLM 回复)
- 🔄 动态状态栏(实时显示 Agent 转接、工具调用)
- 📊 侧边监控面板(追踪当前Agent、用户上下文)
本章承诺:哪怕你从未用过 Streamlit,30 分钟后,你将拥有一个前后端完全联通、可演示、可交付的多智能体可视化驾驶舱——后端由 Agents SDK 驱动,前端由 Streamlit 渲染。
一、什么是 Streamlit?为什么它是 Agent 开发者的前端首选?
如果 Agent 全栈开发者只能掌握一个前端技术,那一定是 Streamlit。
这不是因为它“简单”,而是因为它的运行模型与 Agent 的本质高度一致。
Agent 是什么?
它不是一个“输入→输出”的函数,而是一个有状态、可中断、能协作的过程:
- 它会思考 → 暂停 → 调用工具 → 转接给另一个 Agent → 等待人工确认 → 继续执行……
这种长周期、多步骤、带中间状态的行为,恰恰是传统 REST API 难以表达的——REST 天生为“无状态、一次性请求”设计。
Streamlit 呢?
它彻底跳出了“前后端分离”的思维,把 Web 应用变成了一种 “可交互的 Python 脚本”:
你写的 Python 代码
↓
Streamlit 运行时(Runtime)
↓
自动渲染成网页界面
没有 HTML,没有 JS,没有 API 路由——你只需写:“当程序运行到这里时,把这句话展示给用户。”
Streamlit 的特殊性在于:你永远不需要思考“这个按钮放左边还是右边”、“气泡怎么对齐”、“侧边栏宽度多少”——你只需按逻辑顺序写下“这里要显示什么”,它就会自动生成一个美观、响应式的界面。
这种“所想即所得”的开发体验,正是它成为 Agent 快速交付首选的原因。
Agent 与 Streamlit 的对应逻辑:
| Agent 特性 | Streamlit 对应机制 |
|---|---|
| 有状态的思考过程 | st.session_state 保存上下文 |
| 多步执行(暂停/继续) | 用户交互触发脚本从头重跑,但状态保留 |
| 可视化中间步骤 | 声明式 UI 组件(如 st.status)实时更新 |
🍽️ 打个比方:
- REST API 像快餐店:下单 → 等待 → 取餐(每次都是全新会话)
- Streamlit 像包厢餐厅:点菜 → 上菜 → 加菜 → 结账,服务员全程记得你的需求(状态连续)
那它只是“Demo 工具”吗?
很多人说 Streamlit 不适合生产,这是对场景的误解。
- 如果你要做百万并发的 ToC 产品?确实不合适。
- 但如果你要做:
- 内部 Agent 工具
- 客户定制化演示
- 快速交付 MVP
- 多智能体系统的可视化调试面板
Streamlit 就是最高效、最低摩擦的交付方式。
我们学它,不是因为“它好学”(虽然确实好学),
而是因为——它天生为 Agent 这类过程型系统而生。
我们先掌握Streamlit的几个组件,用以搭建最基础的框架。
二、快速上手:掌握Streamlit的七种武器
Streamlit 的代码极其简洁——你不需要设计页面结构,只需按执行顺序声明“这里要显示什么”。
而要打造一个具备流式输出、状态追踪、上下文记忆的现代 Agent 界面,仅靠基础组件是不够的。
Streamlit 提供了一套精巧的“七种武器”,分别对应 Agent 交互中的核心能力:
| 能力维度 | 组件 | 作用 |
|---|---|---|
| 交互输入 | st.chat_input | 用户输入入口 |
| 对话展示 | st.chat_message | 渲染聊天气泡 |
| 状态反馈 | st.status + st.empty | 展示思考过程 & 打字机效果 |
| 记忆中枢 | st.session_state | 跨轮次保存对话与 Agent 状态 |
| 全局控制 | st.sidebar + st.rerun | 配置面板 & 主动刷新 |
下面进行逐一详解。
环境搭建
pip install streamlit
在 Python 文件开头引入:
import streamlit as st
1. 交互输入:st.chat_input (输入框)
专为对话场景设计的输入框,回车后自动触发逻辑。
prompt = st.chat_input("请输入问题")
if prompt:
# 处理用户输入
st.write(f"你输入了: {prompt}")

![]()
⚠️ 注意:用户输入后,整个脚本会从头重新运行(这是 Streamlit 的核心机制)。
2. 对话展示:st.chat_message
自动生成类似 ChatGPT 的对话气泡,自动区分用户与机器人,支持头像定制。
# 用户消息
with st.chat_message("user", avatar="👤"):
st.write("你是人吗")
# 助手回复
with st.chat_message("assistant", avatar="🤖"):
st.write("似乎不太像是人")

3. 状态反馈:保存或展示当前状态
st.status (折叠状态栏)
将复杂的中间步骤收纳起来,避免界面杂乱。
with st.status("Agent 正在思考...",expanded=True): # expanded:默认是否打开折叠栏
st.write("正在查询数据库...")
st.write("正在转接专员...")
# 最终更新状态
st.success("处理完成")

✅ 小技巧:后续可通过 status.update(label="新标题", state="complete") 动态更新状态。
st.empty(动态占位符)
先占一个位置,后续可反复更新内容,实现逐字输出(流式效果)。
import time
response = st.empty()
for msg in ["处理中...", "完成!"]:
response.markdown(msg)
time.sleep(1)
4. 记忆中枢:st.session_state
解决“页面刷新就失忆”的问题,本质是一个持久化字典:
# 初始化
if "messages" not in st.session_state:
st.session_state.messages = []
# 读写
st.session_state.messages.append({"role":"user","content":prompt})
✅ 所有跨轮次的状态(对话历史、当前 Agent、用户画像)都应存于此。
5. 全局控制:
st.sidebar(侧边监控面板)
用于放置配置项、用户信息或系统状态,类似 VS Code 左侧栏。
with st.sidebar:
st.write("我是侧边栏")
st.json({"用户": "张三"}) # 自动把字典渲染成漂亮的 JSON 树
st.rerun(手动触发刷新)
用于在状态更新后立即反映到界面,但应该谨慎使用。
st.rerun() 会立即终止当前脚本执行,并从头重新运行整个应用。
它适用于状态已变更但 UI 尚未反映的场景,但在 Agent 聊天应用中通常不需要。
✅ 唯一推荐用法:清空对话
if st.button("🗑️ 清空对话"):
st.session_state.messages = []
st.rerun() # 立即刷新界面,清除所有气泡
❌ 为什么聊天流程中不用?
- Streamlit 是同步执行模型:代码从上到下跑完后才渲染 UI,AI 回复自然会显示;
- 用户输入后,自动触发整页重跑,历史消息通过 st.session_state 正确还原;
- 额外调用 st.rerun() 反而会导致页面闪烁或重复输出。
💡 记住:除“清空对话”等极少数操作外,Agent 应用无需手动刷新。让 Streamlit 的自然执行流接管一切。
下一步:用七种武器,搭建静态骨架
现在,你已掌握构建生产级 Agent 界面所需的全部能力单元。
接下来,我们将先用其中 4 个(sidebar、chat_message、chat_input、status)搭出一个静态 UI 骨架,再逐步注入其余武器,让它真正活起来。
三、实战一:搭建静态的UI骨架
有了前面的装备,我们只需 20 行代码,就能快速搭出一个完整的 Agent 界面骨架——先不管逻辑,只关注布局。
import streamlit as st
st.set_page_config(page_title="智能客服驾驶舱",layout="wide") # 标签页的命名
st.title("✈️ 智能航天客服 Swarm") # 标题
# 侧边栏
with st.sidebar:
st.header("📦 驾驶舱监控") # 侧边栏标题
st.info("当前坐席:前台 TriageAgent") # 侧边栏高亮信息
st.subheader("用户画像") # 侧边栏副标题
st.json({"name":"张三","vip":True})
# 画聊天历史(模拟)
with st.chat_message("user",avatar="👤"): # 用一个小表情代表发言人头像
st.write("我要退票")
with st.chat_message("assistant",avatar="🤖"):
st.write("好的,为您转接退票专员...")
# 画输入框
prompt = st.chat_input("请输入您的问题")
if prompt:
# 当用户输入后,页面会刷新,显示下面的内容
with st.chat_message("user",avatar="👤"):
st.write(prompt)
▶ 运行与验证
在终端执行:
streamlit run app.py
Streamlit 会启动一个本地 Web 服务,并自动打开浏览器。

你会看到:
- 顶部标题 ✈️ 智能航空客服 Swarm
- 左侧 驾驶舱监控面板 显示坐席状态与用户画像
- 中间是模拟的对话历史
- 底部是可输入的聊天框

🔁 重要机制提醒:
Streamlit 会在每次用户交互(如输入、点击)后,从头重新运行整个脚本,并根据st.session_state 和 当前输入 重建 UI。
因此,修改代码后只需刷新网页,即可看到最新效果(无需重启服务)。
下一步:注入“灵魂”
这个界面目前是静态的——它不会调用 Agent,也不会真正处理请求。
但它已经具备了完整的产品形态。
接下来,我们将把 M12 中基于 Agents SDK 构建的 Swarm 引擎接入进来,让这个骨架真正活起来。
四、实战二:接入Agents SDK —— 构建首个真正联通的 Agent 产品
现在,我们把前面搭好的 UI 骨架,真正连上后端智能体。
目标很明确:用最少的代码,验证 Streamlit 能驱动 Agents SDK —— 不搞流式、不搞异步,先跑通再说。
思路
用户输入 → 追加到历史 → 同步调用 Agent(会卡几秒)→ 拿到结果 → 更新界面。
虽然简单,但这一步意味着:你的 Agent 不再只是终端里的脚本,而是一个可交互的产品原型。
完整代码:
import streamlit as st
from agents import Runner, set_tracing_disabled
from agents.agent import Agent
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
from openai import AsyncOpenAI
from config import OPENAI_API_KEY
set_tracing_disabled(True) # 去掉tracing
# 初始化模型
client = AsyncOpenAI(api_key=OPENAI_API_KEY,base_url="https://api.deepseek.com")
model = OpenAIChatCompletionsModel(model="deepseek-chat",openai_client=client)
# 定义一个通用Agent
smart_agent = Agent(
name="SmartAssistant",
instructions="""
你是航空公司智能客服助手,客户姓名:张三(白金会员),航班号:CA1234。
你具备以下能力:
- 用户说“退票”“退款”“取消” → 回复:✅ 退款申请已提交,预计3个工作日内原路返回。
- 用户说“改签”“换航班” → 回复:✅ 明日同航线航班尚有余座,已为您预留,可随时确认改签。
- 其他任何问题 → 礼貌、专业地直接回答
回复要简洁、自然、带表情符号,让用户感到温暖。
""",
model=model
)
# Streamlit UI组件
st.set_page_config(page_title="智能客服驾驶舱",layout="wide") # 标签页命名
st.title("✈️ 智能航天客服 Swarm") # 页面标题
# 侧边栏:驾驶舱监控(先固定不变动)
with st.sidebar:
st.header("🖥️ 驾驶舱监控")
st.success("当前坐席: 智能助理 SmartAssistant 🤖") # success用作高亮块显示
st.subheader("用户画像")
st.json({"user_name": "张三(白金会员)", "flight_no": "CA1234"})
# 会话状态与历史消息
if "messages" not in st.session_state:# 首次运行时,初始化空列表,用于存储聊天消息。
st.session_state["messages"] = []
for msg in st.session_state["messages"]:# 重新渲染历史消息,确保聊天上下文在页面刷新后依然可见
avatar = "👤" if msg['role'] == 'user' else "🤖"
with st.chat_message(msg['role'],avatar=avatar):
st.write(msg["content"])
# 用户输入与核心交互
prompt = st.chat_input("请输入您的问题(试试:我要退票 / 想改签 / 你好)")
if prompt:
# 显示用户信息
st.session_state.messages.append({"role":"user","content":prompt})
with st.chat_message("user",avatar="👤"):
st.write(prompt)
# 调用Agents SDK
with st.spinner("思考中..."): # 执行耗时操作时,显示旋转的加载动画
result = Runner.run_sync( # 同步运行智能体
smart_agent, # 参数:agent
st.session_state.messages # 参数:对话历史
)
# 显示AI回复
reply = result.final_output # 最终AI回复内容
st.session_state.messages.append({"role":"assistant","content":reply})
with st.chat_message("assistant",avatar="🤖"):
st.write(reply)
💡 注意:
- 使用 Runner.run_sync() 做同步调用,便于调试;
- 通过 st.session_state.messages 保持对话上下文;
运行测试:
下一步:扩充能力
这个版本是“能跑就行”的最小闭环。
但它有几个明显短板:
- Agent 是固定的,无法像 M12 那样动态转接;
- 全程阻塞,用户体验卡顿。
- 无法调用任何工具。
下一章,我们就把 M12 的完整 Swarm 引擎(含多 Agent + 工具调用)接入进来,并升级为流式输出 + 动态状态反馈,让这个驾驶舱真正“活”起来。
五、实战三:工程化的Agent产品 —— 打造可交付的Swarm驾驶舱
目标:在上一章同步 MVP 基础上,升级为 支持多 Agent 动态转接 + 工具调用 + 流式输出 的生产级界面。
📚 新增四大能力
- 动态坐席显示:侧边栏随 Agent 切换实时更新
- 流式打字机效果:逐字输出,提升响应感
- 工具调用可视化:显示“正在查座位”“正在退款”等过程
- 会话持久化:对话历史存入数据库,支持多用户隔离
🔧 关键挑战与解法
挑战 1:Streamlit 是同步的,如何跑异步 Agent?
问题:Streamlit 底层基于异步,但用户代码默认是同步执行。若直接调用 async 函数会报错,其本质是异步无法嵌套异步。
✅ 解法:用 nest_asyncio.apply() 允许嵌套异步
import nest_asyncio
nest_asyncio.apply() # ← 加这一行即可
💡 这是 Streamlit + 异步 Agent 的标准搭配,不可省略。
挑战 2:如何让侧边栏“动态变色”?
问题:Streamlit 的 UI 是按执行顺序生成的。一旦某行 st.write("A") 执行完 ,它就“固化”在页面上,无法后续修改。后面再写也只会追加而不是更新原文本。
正确做法:用 `st.empty()` 创建一个**可重复更新的占位符**,并封装渲染逻辑。
✅ 解法:占位符 + 渲染函数
# 1. 创建占位符(只创建一次)
agent_status_placeholder = st.empty()
# 2. 定义渲染函数(统一控制样式和逻辑)
def render_agent_status(placeholder, agent):
if agent.name == "RefundAgent":
placeholder.success("当前坐席: 退票专员 🚨")
# ...其他类型
# 3. 在 Agent 切换时调用
render_agent_status(agent_status_placeholder, new_agent)
为什么必须用函数:
因为 Agent 切换可能发生在多个地方(如流式事件、按钮点击),用函数可以确保所有场景下显示规则一致,避免重复代码。
✨ 原则:静态 UI 直接写,动态 UI 用占位符。
挑战 3:如何监听 Agent 的流式事件?
问题:我们需要同时处理:文本流、Agent 切换、工具调用。
✅ 解法:复用 M12模块 的事件循环逻辑(s03_main.py),但对接 Streamlit UI
async for event in stream.stream_events():
if event.type == "raw_response_event":
# 实时更新打字机效果
reply += delta
message_placeholder.markdown(reply + "▌")
elif event.type == "agent_updated_stream_event":
# 更新侧边栏 + 记录日志
st.session_state.current_agent = new_agent
render_agent_status(agent_status_placeholder, new_agent)
elif event.type == "tool_called":
# 显示工具调用
status.write(f"🔧 调用: {tool_name}")
为什么必须用事件循环:
因为 Agents SDK 的 stream_events() 是一个异步生成器,它逐个发出事件。只有通过 async for 才能逐条处理,实现“边思考边输出”。(这点在12模块已经有所提及)
✨ 核心思想:把 M12 的终端打印,换成 Streamlit 的 UI 更新。
挑战 4:如何持久化多用户会话?
问题:st.session_state 只在单次浏览器会话有效。用户刷新页面、关闭标签或换设备,历史记录就会丢失。
✅ 解法:引入 SQLiteSession ,将对话自动存入本地数据库。
# 每个用户分配唯一 session_id(例如基于时间戳或用户 ID)
if "session_id" not in st.session_state:
st.session_state.session_id = str(uuid.uuid4())
# 初始化持久化会话(首次创建,后续自动加载历史)
if "session" not in st.session_state:
st.session_state.session = SQLiteSession(
session_id=st.session_state.session_id,
db_path="./conversations.db"
)
💡 关键机制:
- SQLiteSession 在初始化时自动从数据库加载该 session_id 的历史消息;
- 每次调用 stream.run(..., session=...) 时,新消息会自动追加保存,无需手动调用 .save()。
- 不同 session_id 对应不同用户,天然实现多用户数据隔离。
注:为保持章节聚焦,本章未展示完整代码。
所有功能均基于 M12 模块的 s01_tools.py 与 s02_agent.py 实现,前端仅负责 UI 集成与事件响应。
完整可运行代码已开源:https://github.com/Annyfee/agent-craft



👍 最终效果:
Agent 能动态切换坐席、调用工具查询酒店/MCP服务,并实时展示调试日志——一个真正可交付的 Swarm 驾驶舱。
⚠️ 已知限制:页面闪烁
由于 Streamlit 的重跑机制,复杂 UI 在异步更新时可能出现轻微闪烁。
这是框架当前限制,不影响实际功能,优先保证逻辑正确性。
✅ 总结:本章交付了什么?
| 能力 | 实现方式 |
|---|---|
| 多 Agent 动态转接 | agent_updated_stream_event + 占位符更新 |
| 工具调用可视化 | tool_called 事件 + st.status |
| 流式输出 | st.empty() + 逐字更新 |
| 会话持久化 | SQLiteSession + session_id |
现在,你拥有了一个接近真实产品的 Swarm 驾驶舱——它不仅能思考,还能协作、调用工具、记住历史。
总结:前端篇收官,全栈能力已就绪:
至此,M13 的三个实战已完整覆盖 Streamlit 与 Agents SDK 的集成方法。
我们不仅能快速搭建可视化界面,更能构建出具备 多 Agent 协作、工具调用、流式交互 能力的智能体产品原型。
更重要的是——
从 LangChain 到 LangGraph,从 RAG 到 MCP,从后端逻辑到前端交互,Agent 全栈技术栈已全部打通。
预告:《14篇 综合实战项目》
🔜 下一篇将是我们的「综合实战」毕业项目:
我们将融合所有已学技术,打造一个贴近真实场景的产品级 Agent 系统。
- 它支持多用户、可持久化、能调用外部服务
- 笔者将部署在线版本,供你体验
- 同时提供一键部署脚本,你可轻松复现并二次开发
这不仅是一次总结,更是一次交付——
属于你的第一个全栈 Agent 产品,即将上线。
更多推荐




所有评论(0)