实战:让 AG2 Agent 直接读取前端 UI 状态)
CopilotKit 共享状态读取Shared State Read实战让 AG2 Agent 直接读取前端 UI 状态【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKitCopilotKit 的 Shared StateReading演示展示了如何在多 Agent 应用中让 AI Agent 直接读取前端维护的共享应用状态——以一份由前端表单掌控的菜谱recipe为例Agent 无需前端将上下文作为提示词发送即可基于实时 UI 数据回答我做的这道菜是什么还差什么配料之类的问题。读完本文你将掌握useAgent().state的读写机制、AgentState类型化 schema 的前后端共享方式以及如何在 AG2通过 AG-UI 协议与 CopilotKit Runtime 的链路中实现前端发布状态、Agent 只读查询的单向数据流。关联文档与演示概览本文核心基于 shared-state-read/README.md。该演示位于 AG2 集成 showcase 中其核心定位是Reading agent state from UIAgent 从前端读取共享状态演示交互方式为向 Copilot 提问例如What tasks are on my todo list?Summarize what I have to doHow many items are pending?Agent 读取共享的应用状态todo 列表并根据当前数据作答。README 同时给出了四点技术要点Shared state让 Agent 通过useAgent().state读取前端管理的同一份状态Agent 的工具访问runtime.state来查询当前应用数据状态被定义为前端与后端共享的类型化 schemaAgentState这一机制使 Agent 能回答关于当前 UI 状态的问题而无需前端把状态作为上下文发送。演示源码位于 shared-state-read/page.tsx类型定义在 types.ts表单组件在 recipe-card.tsx。E2E 测试见 tests/e2e/shared-state-read.spec.ts。演示页面结构从 CopilotKit 挂载到 Recipe 表单SharedStateReadDemo是页面的根组件结构非常简洁export default function SharedStateReadDemo() { return ( CopilotKit runtimeUrl/api/copilotkit agentshared-state-read div classNamemin-h-screen w-full bg-gray-50 div classNamemx-auto max-w-2xl px-4 py-8 md:py-12 Recipe / /div CopilotSidebar defaultOpen labels{{ modalHeaderTitle: AI Recipe Assistant }} / /div /CopilotKit ); }三个关键点runtimeUrl/api/copilotkit前端通过 Next.js 的 API 路由与 CopilotKit Runtime 通信。该路由在 src/app/api/copilotkit/route.ts 中实现它创建一个CopilotRuntime将shared-state-read注册为共享默认 Agent并通过HttpAgentAG-UI 客户端把请求代理到后端 Agent 进程。agentshared-state-read将页面绑定到名为shared-state-read的 Agent 实例。CopilotSidebar提供聊天 UI默认展开标题为 AI Recipe Assistant。页面主体是Recipe组件它通过useAgent拿到 Agent 句柄并用agent.setState把菜谱发布进共享状态。单向共享状态前端是唯一数据源Single Source of TruthRecipe组件是理解整个演示的关键。它用useAgent绑定 Agent并订阅两类更新const { agent } useAgent({ agentId: shared-state-read, updates: [UseAgentUpdate.OnStateChanged, UseAgentUpdate.OnRunStatusChanged], }); const { copilotkit } useCopilotKit();OnStateChanged任何来自 Agent 的状态变更都会触发组件重渲染OnRunStatusChangedAgent 的运行状态如agent.isRunning变化时触发重渲染用于控制加载态。随后组件把初始菜谱种子进 Agent 状态并确保表单的每一次编辑都写入同一份状态useEffect(() { if (!(agent.state as RecipeAgentState | undefined)?.recipe) { agent.setState({ recipe: INITIAL_RECIPE } satisfies RecipeAgentState); } }, []); const recipe (agent.state as RecipeAgentState | undefined)?.recipe ?? INITIAL_RECIPE; const handleChange (next: RecipeData) { agent.setState({ recipe: next } satisfies RecipeAgentState); };这里体现的是纯受控组件设计表单本身不维护任何本地副本agent.state.recipe是唯一事实来源single source of truth。每一次编辑都直接流向agent.setState({...})下一次渲染即反映最新值。页面注释也明确写道The form is a pure controlled component on top of that — every edit flows straight intoagent.setState({...})and the next render reflects it.源码注释还强调了只读的边界page.tsxthe UI publishes a recipe to the agent viaagent.setState; the agent reads that recipe on every turn but does not mutate it (the wired graph is the neutral default agent with no tools)也就是说后端对接的是无工具no tools的默认 Agent因此不存在任何后端工具会改写菜谱——数据流向是严格的前端写 → Agent 读。Improve with AI按钮的完整调用链页面还演示了通过命令式 API 发起一次 Agent 运行const handleImprove () { if (agent.isRunning) return; agent.addMessage({ id: crypto.randomUUID(), role: user, content: Improve the recipe, }); void copilotkit .runAgent({ agent }) .catch((err) console.error([shared-state-read] runAgent failed, err)); };调用链为agent.addMessage先把用户消息加入线程 →copilotkit.runAgent({ agent })触发一次 Agent 运行。由于 Agent 会在每一轮读取共享状态中的菜谱所以这条 Improve the recipe 消息实际上是在对当前state.recipe做改进。agent.isRunning作为保护条件防止并发重复运行同时驱动按钮上的加载态Please Wait... 与 Spinner。建议交互Suggestions页面通过useConfigureSuggestions配置了三条启动建议available: always表示常驻可用useConfigureSuggestions({ suggestions: [ { title: Create Italian recipe, message: Create a delicious Italian pasta recipe. }, { title: Make it healthier, message: Make the recipe healthier with more vegetables. }, { title: Suggest variations, message: Suggest some creative variations of this recipe. }, ], available: always, });类型化共享 SchemaAgentState的工程化定义README 强调状态是前端与后端共享的类型化 schemaAgentState。在这个演示里状态 schema 定义在前端 types.ts 中export enum SkillLevel { BEGINNER Beginner, INTERMEDIATE Intermediate, ADVANCED Advanced, } export enum CookingTime { FiveMin 5 min, FifteenMin 15 min, ThirtyMin 30 min, FortyFiveMin 45 min, SixtyPlusMin 60 min, } export interface Ingredient { icon: string; name: string; amount: string; } export interface RecipeData { title: string; skill_level: SkillLevel; cooking_time: CookingTime; special_preferences: string[]; ingredients: Ingredient[]; instructions: string[]; } export interface RecipeAgentState { recipe: RecipeData; }RecipeAgentState即 README 中所说的AgentState——这里只有一个recipe字段SkillLevel、CookingTime、SpecialPreferences用枚举约束可选值配合cookingTimeValues数组将枚举与数值索引映射供下拉选择器使用RecipeData是一个结构完整、可 JSON 序列化的领域对象包含标题、技能等级、烹饪时长、饮食偏好、配料列表与步骤列表。INITIAL_RECIPE提供了种子数据标题 Make Your Recipe、Intermediate 技能、45 分钟、胡萝卜与面粉配料、一条预热烤箱的指令保证 Agent 在第一轮对话时就有数据可读。这一层 schema 的价值在于前端写入与后端读取共用同一结构Agent 通过 AG-UI 协议拿到的状态天然是类型明确的 JSONLLM 无需猜测字段含义。状态如何从前端流向后端Runtime 的setState链路agent.setState(...)并不是只更新前端内存。在 CopilotKit Runtime 中每次 Agent 运行都会携带状态。见 packages/runtime/src/v2/runtime/handlers/handle-run.tsagent.setMessages(input.messages); agent.setState(input.state); agent.threadId input.threadId;即运行时在处理每次 Run 请求时会解析请求体parseRunRequest把其中携带的state通过agent.setState(input.state)设置到目标 Agent 上随后才进入 SSE 运行流程handleSseRun。这正是 README 所述Agent 的工具访问runtime.state查询当前应用数据的底层支撑状态是随每次运行请求一起从前端传递到后端的后端 Agent 在每一轮都能读到最新的state.recipe。在 React 侧useAgent的订阅机制实现在 packages/react-core/src/v2/hooks/use-agent.tsx 中。UseAgentUpdate.OnStateChanged等更新标志定义于该文件开头OnStateChanged OnStateChanged当updateFlags.includes(UseAgentUpdate.OnStateChanged)时组件会订阅 Agent 的状态变更并触发重渲染。这也解释了为什么表单编辑agent.setState之后页面包括建议列表、加载态能即时刷新。后端接线AG2 默认 Agent 与 AG-UI 协议虽然共享状态读取演示没有专属后端工具但理解它的接线方式对复现至关重要。前端路由注册route.ts 将shared-state-read列入sharedAgentNames统一指向根路径的默认 Agentconst sharedAgentNames [ // ... shared-state-read, // ... ];随后createAgent()返回指向AGENT_URL默认http://localhost:8000的HttpAgent并用createCopilotRuntimeHandler在mode: single-route下处理所有 CopilotKit 请求。这意味着shared-state-read复用同一个后端 Agent与agentic_chat、tool-rendering等共享同一进程——不同之处仅在于前端 UI 的绑定方式。后端 AG2 进程src/agent_server.py 是 FastAPI 服务核心是app.mount(/, default_stream.build_asgi())——把默认 Agent 的 AG-UI 流挂载到根路径。该 Agent 在 src/agents/agent.py 中定义是一个标准的 AG2ConversableAgent通过AGUIStream(agent)暴露为 AG-UI 协议端点。演示注释明确指出 shared-state-read 对接的是中性默认 Agent无工具因此状态只读、不会被子端改写。值得注意的一个对比同目录下的shared-state-read-write演示见 shared-state-read-write/README.md展示了双向读写——后端通过PreferencesInjectorMiddleware读取request.state[preferences]注入系统提示set_notes工具用Command(update{notes: ...})写回状态。这与本演示的只读形成鲜明对照read 演示刻意去掉所有写路径让前端写、Agent 读的单向数据流成为教学焦点。用 E2E 测试验证Agent 读取前端状态仓库为演示提供了完整的 Playwright E2E 测试 tests/e2e/shared-state-read.spec.ts其注释点明了测试契约页面通过agent.setState发布agent.state.recipeAgent 在每轮读取但不修改该菜谱。测试覆盖四个维度初始渲染recipe-card可见、AI Recipe Assistant 侧边栏挂载、配料与步骤容器渲染建议渲染三条启动建议按钮Create Italian recipe / Make it healthier / Suggest variations全部可见表单可编辑点击add-ingredient-button后ingredient-card行数 1状态读取闭环向侧边栏发送 What recipe am I making?断言第一条copilot-assistant-message可见——即 Agent 基于当前菜谱状态给出了回复。其中第 4 条正是 README 所述核心能力的自动化验证Agent 无需前端把菜谱作为上下文发送也能回答关于当前 UI 状态的问题。对应的人工 QA 清单见 qa/shared-state-read.md其中也包含编辑菜谱后询问 What recipe am I making?验证回答引用当前菜谱状态的验收步骤。实战要点总结单向共享状态的适用场景当 UI 维护着一份业务数据表单、清单、配置而你希望 Agent 能围绕它对话、总结、提出建议但又不想让 Agent 拥有修改它的能力时采用前端setState发布 后端只读模式最合适。类型化 schema 是协作基础把共享状态定义成前后端一致的AgentState类型能让 LLM 收到结构清晰的 JSON也便于前端受控组件与后端工具共享同一套字段契约。更新订阅决定渲染时机useAgent({ updates: [OnStateChanged, OnRunStatusChanged] })是让 UI 跟随状态与运行状态刷新的关键配置。复现演示的前置条件需要同时运行 Next.js 前端runtimeUrl指向/api/copilotkit与 FastAPI Agent 进程默认端口 8000AGENT_URL可配置前端路由负责把 AG-UI 协议请求代理到后端。测试保障E2E 用例与 QA 清单覆盖了从初始渲染到询问当前状态的完整用户路径可作为自行实现共享状态读取功能时的验收模板。延伸阅读shared-state-read/README.md本文关联文档shared-state-read/page.tsx页面与useAgent实现shared-state-read/types.ts共享状态类型定义shared-state-read/recipe-card.tsx受控表单组件shared-state-read-write/README.md双向共享状态对照演示shared-state-streaming/README.md状态流式写入对照演示src/app/api/copilotkit/route.tsCopilotKit Runtime 路由与 Agent 注册src/agents/agent.pyAG2ConversableAgent与AGUIStream后端tests/e2e/shared-state-read.spec.tsPlaywright E2E 测试packages/runtime/src/v2/runtime/handlers/handle-run.ts运行时agent.setState链路packages/react-core/src/v2/hooks/use-agent.tsxuseAgent与更新订阅实现【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考