第 21 章

前端概览

构建能够实时展示子 Agent 流、任务进度和沙箱的 UI

从"纯后端 Agent"到"可视化交互体验"的关键一步

为什么需要它

你有没有试过在前端展示 Deep Agent 的工作过程?

裸用 Agent API 的困境

  • 用户只能看到最终结果,中间过程全黑盒
  • 多个子 Agent 同时运行时,不知道谁在干什么
  • 任务规划散落在对话历史中,没有结构化的进度展示
  • 代码执行结果只返回文本,无法呈现文件变更和差异
  • 流式输出全靠手写 SSE 解析,没有统一的连接管理

Deep Agent 前端的解法

  • useStream 统一管理流式连接,消息实时到达
  • stream.subagents 追踪每个子 Agent 状态,进度一目了然
  • stream.values.todos 同步待办列表,任务规划可视化
  • 沙箱模式提供文件浏览器 + 代码查看器 + diff 面板
  • 基于 LangGraph 运行时,API 完全一致,学习成本为零
问题核心:当你的 Agent 从"回答问题"进化到"完成项目"——规划、搜索、编码、测试——用户需要的不只是最终结果,而是实时了解 Agent 在做什么、做到了哪一步、遇到了什么。前端模式就是解决"可见性"和"交互性"的方案。

文档索引

获取完整的文档索引,发现所有可用页面

文档索引地址

https://docs.langchain.com/llms.txt

在进一步探索之前,使用此文件发现所有可用页面。

使用方式

将文档索引通过 MCP 连接到 Claude、VSCode 等工具,获取实时解答。

索引文件包含了所有可用文档页面的完整列表,是探索 API 的起点。

建议:开始开发前先查阅文档索引,了解所有可用的 API 和工具,避免重复造轮子。

协调者-工作者

Deep Agent 采用 coordinator-worker 架构——主 Agent 规划,子 Agent 执行

说白了,协调者负责拆任务,工作者负责干活。在前端,useStream 同时展示协调者的消息和每个子 Agent 的流式状态。

数据流说明

  • stream:后端 createDeepAgent() 将流式事件推送给前端 useStream(),包含协调者消息和子 Agent 状态
  • submit:前端 useStream() 将用户输入提交给后端 createDeepAgent(),触发新一轮任务规划
  • delegate:后端协调者将任务委派给子 Agent A 和 B,两者在隔离环境中并行执行
  • result:子 Agent A 和 B 将执行结果返回给协调者,由协调者汇总后流式推送给前端

前端(useStream)

蓝色节点 — 负责渲染消息、子 Agent 状态、待办列表和沙箱内容。

接收 stream 事件

后端(createDeepAgent)

绿色节点 — 协调者,负责任务规划、委派子 Agent、汇总结果。

核心调度引擎

子 Agent(Subagent)

紫色节点 — 工作者,在隔离环境中执行具体任务,返回结果。

隔离执行单元

关键认知:前端只跟 useStream 打交道。不管是协调者消息还是子 Agent 状态,都通过 useStream 的扩展属性获取。你不需要额外建立 WebSocket 连接。
图:coordinator-worker 数据流架构

创建 Deep Agent

后端只需一行 createDeepAgent,即可启用子 Agent 机制

创建方式与普通 Agent 类似,但多了一个 subagents 配置项,用于声明可用的子 Agent 类型。

import { createDeepAgent } from "deepagents";

const agent = createDeepAgent({
  tools: [getWeather],          // 主 Agent 可用的工具列表
  systemPrompt: "You are a helpful assistant",  // 主 Agent 的系统指令
  subagents: [
    {
      name: "researcher",       // 子 Agent 类型名称
      description: "Research assistant",  // 描述什么任务应该委派给它
    },
  ],
});

createAgent(普通)

  • 单一 Agent,自己完成所有工作
  • 上下文会随任务增长越来越大
  • 适合简单的一问一答场景

createDeepAgent(深度)

  • 协调者 + 多个子 Agent 协作
  • 每个子 Agent 上下文隔离,不会互相干扰
  • 适合多步骤、多任务的复杂场景
注意:subagents 只声明子 Agent 的名称和描述,不需要传具体的实现。子 Agent 由运行时根据任务自动创建和管理。

连接前端

使用 useStream 连接后端,获取完整的 Deep Agent 状态

前端用 useStream 与后端通信,方式和 createAgent 完全一致。但 Deep Agent 提供了额外的状态属性。

import { useStream } from "@langchain/react";

function App() {
  const stream = useStream(typeof agent === "undefined" ? {} : {
    apiUrl: "http://localhost:2024",   // LangGraph Server 地址
    assistantId: "agent",              // Agent 的唯一标识
  });

  // Deep Agent 特有状态(普通 Agent 没有)
  const todos = stream.values?.todos;       // 待办任务列表,由 write_todos 工具驱动
  const subagents = stream.subagents;       // 所有子 Agent 的实时状态 Map

  return (
    <div>
      {/* 渲染协调者消息 */}
      {stream.messages.map(msg => <Message key={msg.id} data={msg} />)}

      {/* 渲染子 Agent 卡片 */}
      {subagents?.map(sub => <SubagentCard key={sub.id} data={sub} />)}

      {/* 渲染待办列表 */}
      {todos && <TodoList items={todos} />}
    </div>
  );
}
三个核心属性:stream.messages(协调者消息)、stream.subagents(子 Agent 状态)、stream.values.todos(待办列表)。这三个属性覆盖了 Deep Agent 前端 90% 的渲染需求。

子 Agent 流式

实时展示每个子 Agent 的执行内容、进度和结果

当协调者委派任务给子 Agent 时,stream.subagents 会实时更新。每个子 Agent 包含名称、状态和流式输出内容。

// 子 Agent 状态结构示例
const subagent = {
  id: "sub_001",
  name: "researcher",          // 子 Agent 类型名称
  status: "running",           // running | completed | error
  taskId: "task_003",          // 关联的任务 ID
  messages: [                  // 该子 Agent 的流式消息
    { role: "assistant", content: "正在搜索相关文档..." },
    { role: "assistant", content: "找到 3 篇相关论文,正在分析..." },
  ],
};

可折叠卡片模式

每个子 Agent 渲染为一张可折叠的卡片,点击展开查看详细输出。折叠时只显示名称和状态。

推荐 UI 模式

进度追踪

通过 status 字段显示运行/完成/错误三种状态,配合动画让用户感知实时性。

状态驱动渲染

内容过滤

在 useStream 中开启 filterSubagentMessages 选项,让 stream.messages 自动过滤出特定子 Agent 的消息,避免混入协调者消息。

消息隔离

待办列表

通过与 Agent 状态同步的实时待办列表跟踪任务进度

协调者使用内置的 write_todos 工具来规划任务。前端通过 stream.values.todos 获取这些待办事项并实时渲染。

// 待办列表数据结构示例
const todos = [
  { id: "todo_1", content: "搜索用户相关资料", status: "completed" },
  { id: "todo_2", content: "分析搜索结果并整理要点", status: "in_progress" },
  { id: "todo_3", content: "编写最终报告", status: "pending" },
];

// 在 React 组件中渲染
// 渲染待办列表,状态驱动图标
function TodoList({ items }) {
  return (
    <div className="todo-list">
      <h3>任务规划</h3>
      {items.map(todo => (
        <div key={todo.id} className={`todo-item ${todo.status}`}>
          {todo.status === "completed" && <span>✓</span>}
          {todo.status === "in_progress" && <span>⟳</span>}
          {todo.status === "pending" && <span>○</span>}
          <span>{todo.content}</span>
        </div>
      ))}
    </div>
  );
}
数据驱动 UI:待办列表完全由后端 Agent 状态驱动。Agent 每次调用 write_todos 更新规划时,前端自动重新渲染。你不需要手动管理状态同步。

沙箱模式

构建类 IDE 的 UI,包含文件浏览器、代码查看器和差异面板

当子 Agent 在沙箱中执行代码时,前端可以渲染一个完整的 IDE 体验,让用户看到文件变更和代码差异。

文件浏览器

以树形结构展示沙箱中的所有文件和目录,支持点击查看文件内容。

// 文件树数据结构
const fileTree = [
  { type: "dir", name: "src",
    children: [
      { type: "file", name: "index.ts" },
      { type: "file", name: "utils.ts" },
    ]
  },
  { type: "file", name: "package.json" },
];

差异面板

展示文件的新增、修改和删除,用红绿色标注增删行,类似 Git diff。

// 差异数据结构
const diff = {
  file: "src/index.ts",
  changes: [
    { type: "add", line: 5,
      content: "import { serve } from './server';" },
    { type: "remove", line: 3,
      content: "const port = 3000;" },
  ],
};
注意:沙箱模式需要后端配置沙箱后端(如 E2B 或 Docker)。如果未配置沙箱,子 Agent 的文件操作会在本地文件系统执行,此时文件浏览器和差异面板将无法展示实时变更。

消息过滤

使用 filterSubagentMessages 选项自动隔离各子 Agent 的消息

在复杂场景中,协调者和多个子 Agent 的消息混合在一起。在 useStream 配置中开启 filterSubagentMessages: true,stream.messages 就会自动按子 Agent 过滤,实现消息隔离渲染。

import { useStream } from "@langchain/react";

function SubagentPanel({ subagentId }) {
  const stream = useStream({
    apiUrl: "http://localhost:2024",
    assistantId: "agent",
    filterSubagentMessages: true,  // 自动按子 Agent 隔离消息
  });

  // stream.messages 已自动按当前子 Agent 过滤
  const messages = stream.messages;

  return (
    <div className="subagent-panel">
      {messages.map(msg => (
        <div key={msg.id} className="message">
          {msg.content}
        </div>
      ))}
    </div>
  );
}

为什么需要过滤

  • 协调者的规划消息 vs 子 Agent 的执行消息,语义不同
  • 不同子 Agent 的消息需要分别渲染在各自的卡片中
  • 避免所有消息堆叠在一起,用户看不清谁在说什么

典型渲染策略

  • 协调者消息 → 主聊天窗口
  • 子 Agent 消息 → 折叠卡片内流式展示
  • 待办列表 → 侧边栏或顶部固定区域
  • 文件变更 → 底部 diff 面板

完整示例

把所有前端模式组合起来——消息 + 子 Agent + 待办 + 沙箱

import { useStream } from "@langchain/react";
import { createDeepAgent } from "deepagents";

// 1. 后端创建 Deep Agent
const agent = createDeepAgent({
  tools: [searchTool, codeTool],  // 主 Agent 可用的工具
  subagents: [
    { name: "researcher", description: "搜索和分析" },
    { name: "coder", description: "编写和执行代码" },
  ],
});

// 2. 前端组件:通过 useStream 获取 Deep Agent 的完整状态
function DeepAgentUI() {
  const stream = useStream({
    apiUrl: "http://localhost:2024",
    assistantId: "agent",
    filterSubagentMessages: true,  // 自动按子 Agent 隔离消息
  });

  const todos = stream.values?.todos;
  const subagents = stream.subagents ?? [];

  return (
    <div className="deep-agent-ui">
      {/* 主消息区 */}
      <ChatPanel messages={stream.messages} />

      {/* 子 Agent 卡片区 */}
      {subagents.map(sub => (
        <SubagentCard key={sub.id} subagent={sub}
          messages={stream.messages}
        />
      ))}

      {/* 待办列表侧边栏 */}
      {todos && <TodoListSidebar items={todos} />}
    </div>
  );
}
组合而非堆叠:四个前端模式不是孤立的,而是可以灵活组合。最小实现只需要 stream.messages,然后根据需求逐步添加子 Agent 卡片、待办列表和沙箱面板。

三大模式总览

Deep Agent 前端提供三个核心模式,覆盖从简单到复杂的所有场景

子 Agent 流式传输

展示专门的子 Agent,支持流式内容、进度跟踪和可折叠卡片。

  • 实时渲染每个子 Agent 的输出
  • 可折叠/展开的卡片 UI
  • 状态驱动:running / completed / error

详见第 22 章

待办列表

通过与 Agent 状态同步的实时待办列表跟踪 Agent 进度。

  • 自动同步 stream.values.todos
  • completed / in_progress / pending 三种状态
  • 用户可见 Agent 的规划思路

详见第 23 章

沙箱

构建类 IDE 的 UI,包含文件浏览器、代码查看器和差异面板。

  • 树形文件浏览器
  • 语法高亮的代码查看器
  • 红绿 diff 面板

详见第 24 章

渐进式采用:你可以从最简单的消息渲染开始,逐步添加子 Agent 卡片,再加待办列表,最后上沙箱。不需要一次性实现所有模式。
图:前端三大模式渐进式定位

生态兼容性

Deep Agent 构建在 LangGraph 运行时之上,与 LangChain 前端模式完全兼容

LangChain 前端模式——包括 Markdown 消息渲染、工具调用展示、人在回路(Human-in-the-Loop)——同样适用于 Deep Agent。

LangChain 前端模式

  • Markdown 消息:格式化渲染 AI 回复中的代码块、列表、链接
  • 工具调用:展示 Agent 调用了哪些工具、传了什么参数
  • 人在回路:Agent 请求用户确认时,前端展示确认按钮

Deep Agent 扩展

  • 子 Agent 状态:stream.subagents 追踪多个并行 Agent
  • 待办列表:stream.values.todos 实时同步任务规划
  • 沙箱内容:文件树 + diff 面板展示代码变更
// useStream 的核心 API 对比
// LangChain 模式                    // Deep Agent 扩展
stream.messages                  → stream.subagents
stream.values                    → stream.values.todos
stream.submit(input)             → filterSubagentMessages: true(配置选项)
零额外学习成本:因为 Deep Agent 构建在相同的 LangGraph 运行时之上,useStream 提供了相同的核心 API。你已经会用的 LangChain 前端知识,全部可以直接复用。

动手练习

构建一个最小化的 Deep Agent 前端

现在轮到你了。停下来,用刚学的知识构建一个最小可用的 Deep Agent 前端界面。

// 练习目标:
// 1. 创建一个 Deep Agent(后端)
// 2. 用 useStream 连接它(前端)
// 3. 渲染协调者消息
// 4. 渲染子 Agent 卡片(可折叠)
// 5. 渲染待办列表(显示任务进度)

// 后端模板
import { createDeepAgent } from "deepagents";

const agent = createDeepAgent({
  tools: [],                      // 添加你的工具
  subagents: [
    { name: "helper", description: "通用助手" },
  ],
});

任务 1:最小前端

  • 用 useStream 连接后端,渲染 stream.messages
  • 实现一个简单的消息列表组件

任务 2:子 Agent 卡片

  • 遍历 stream.subagents,为每个子 Agent 渲染卡片
  • 实现折叠/展开交互

任务 3:待办列表

  • 从 stream.values.todos 读取待办事项
  • 根据 status 显示不同的图标和样式
提示:先实现任务 1 确保消息能正常渲染,再逐步添加子 Agent 卡片和待办列表。渐进式开发比一次性写完所有功能更高效。

本章回顾

到这里,你已经掌握了 Deep Agent 前端的全貌

你学到了什么

  • Deep Agent 采用协调者-工作者架构,主 Agent 规划,子 Agent 执行
  • 前端使用 useStream 统一管理流式连接
  • 三个核心属性:messages、subagents、todos
  • 三大前端模式:子 Agent 流式、待办列表、沙箱
  • 在 useStream 中开启 filterSubagentMessages 实现消息隔离渲染
  • 与 LangChain 前端模式完全兼容,零额外学习成本

后续章节预告

  • 第 22 章:子 Agent 流式传输——详细实现可折叠卡片和进度追踪
  • 第 23 章:待办列表——实时同步 Agent 任务规划的完整方案
  • 第 24 章:沙箱——类 IDE 的文件浏览器、代码查看器和 diff 面板
核心结论:Deep Agent 前端的核心思想是"数据驱动 UI"。后端 Agent 的状态变化通过 useStream 自动同步到前端,你只需要声明式地渲染数据,不需要手动管理任何状态同步逻辑。

延伸阅读

继续本课程

前置章节回顾

官方文档