ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CopilotKit 共享状态(只读)实战:让 LangGraph Python Agent 读取前端应用状态

CopilotKit 共享状态(只读)实战:让 LangGraph Python Agent 读取前端应用状态 CopilotKit 共享状态只读实战让 LangGraph Python Agent 读取前端应用状态【免费下载链接】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本篇基于 CopilotKit 仓库中 LangGraph Python 集成示例下的shared-state-read演示演示说明讲解只读共享状态这一模式前端把受控组件的表单状态通过agent.setState发布为 Agent 状态后端 Agent 在每一轮对话中都能直接看见并回答关于该状态的问题而不需要前端手动把上下文拼进 prompt。读完你可以掌握该模式的完整前端实现、后端 Agent 注册方式以及用 Playwright 验证 Agent 确实读取了前端状态的测试思路。这个演示解决什么问题原始文档README.md对该模式的定位是Reading agent state from UI——让 Agent 读取前端管理的应用状态。文档给出的典型交互是What tasks are on my todo list?Summarize what I have to doHow many items are pending?Agent 读取的是与前端同一份共享应用状态README 以 todo 列表为例基于当前数据作答。其核心要点原文 Technical Details 四条完整继承如下Shared state让 Agent 通过useAgent().state读取与前端同一份状态Agent 侧通过runtime.state本演示后端为默认 Agent 时则由运行时把状态随对话上下文带入查询当前应用数据状态以带类型的 schema文档中称AgentState本演示中落地为RecipeAgentState在前后端之间共享这使得 Agent 能回答关于当前 UI 状态的问题而无需前端把状态作为 context 发送。需要注意一个仓库演进事实README 用 todo 列表作为概念示例而当前仓库中该演示的实际落地形态是一个菜谱编辑器Recipe Editor。演示的注释里写得很清楚page.tsx 第 1–10 行UI 通过agent.setState向 Agent 发布菜谱Agent 每一轮都读取该菜谱但不做任何变更——它是只读的因为挂接的图是不带工具的中性默认 Agent。前端实现以agent.state为唯一数据源状态定义带类型的 schematypes.ts 定义了前后端共享的状态结构。核心类型是export interface RecipeData { title: string; skill_level: SkillLevel; // Beginner | Intermediate | Advanced cooking_time: CookingTime; // 5 min | 15 min | 30 min | 45 min | 60 min special_preferences: string[]; // High Protein / Low Carb / Spicy / ... ingredients: Ingredient[]; // { icon, name, amount } instructions: string[]; } export interface RecipeAgentState { recipe: RecipeData; }文件头注释点明了只读契约The agent onlyreadsthis — theres no backend tool that mutates it, so the UI is the single source of truth.Agent 只读这份状态——没有后端工具会修改它因此 UI 是唯一数据源。初始状态INITIAL_RECIPE包含标题 Make Your Recipe、技能等级Intermediate、烹饪时长45 min、两条默认食材Carrots、All-Purpose Flour和一条默认步骤 Preheat oven to 350°F (175°C)。页面接线CopilotKit Provider 与 useAgentpage.tsx 的SharedStateReadDemo组件负责把前端接入运行时CopilotKit runtimeUrl/api/copilotkit agentshared-state-read Recipe / CopilotSidebar defaultOpen labels{{ modalHeaderTitle: AI Recipe Assistant }} / /CopilotKitagentshared-state-read把本页面绑定到后端注册的同名 Agent见下文后端注册一节runtimeUrl指向 Next.js 应用内的 CopilotKit 运行时路由。Recipe组件是纯受控组件关键有三处1. 用useAgent订阅状态与运行状态变化第 45–48 行const { agent } useAgent({ agentId: shared-state-read, updates: [UseAgentUpdate.OnStateChanged, UseAgentUpdate.OnRunStatusChanged], });OnStateChanged让组件在 Agent 状态变化时重渲染OnRunStatusChanged驱动运行中UI如按钮上的加载态。2. 首帧播种初始状态第 72–77 行useEffect(() { if (!(agent.state as RecipeAgentState | undefined)?.recipe) { agent.setState({ recipe: INITIAL_RECIPE } satisfies RecipeAgentState); } }, []);这一步保证 Agent 在第一轮对话时就有可读的状态此后所有编辑都经由agent.setState流入。3. 所有编辑直接写入 Agent 状态第 82–84 行const handleChange (next: RecipeData) { agent.setState({ recipe: next } satisfies RecipeAgentState); };读取则统一走agent.stateconst recipe (agent.state as RecipeAgentState | undefined)?.recipe ?? INITIAL_RECIPE;第 79–80 行。这正是 README 所说 the UI publishes a recipe to the agent viaagent.setState; the agent reads that recipe on every turn 的落点——前端不维护第二份本地 stateagent.state.recipe就是唯一数据源。表单组件recipe-card.tsxRecipeCard是纯展示 回调的受控表单内部通过局部更新函数把每次变更合并后交给onChange即上面的agent.setStateconst update (partial: PartialRecipeData) { onChange({ ...recipe, ...partial }); };表单覆盖四类字段标题无边框大标题Inputaria-labelRecipe title元信息下拉烹饪时长与技能等级各一个Select时长通过cookingTimeValues数组做 label/value 映射饮食偏好SpecialPreferences枚举渲染为可切换的Badge胶囊按钮aria-pressed标记选中态食材与步骤可增删的行列表。Add Ingredient 按钮data-testidadd-ingredient-button追加一行空食材 Add Step 追加一条空步骤Improve with AI按钮data-testidimprove-buttonisLoading时禁用并显示 Spinner 与 Please Wait...。页面还通过useConfigureSuggestions提供三个引导建议Create Italian recipe / Make it healthier / Suggest variationsavailable: always供用户一键触发对话。主动触发 AgentImprove with AI 的调用链page.tsx 第 86–98 行展示了程序化发起一轮 Agent 运行的完整写法const handleImprove () { if (agent.isRunning) return; // 防止运行中重复触发 agent.addMessage({ // 以用户消息身份入对话 id: crypto.randomUUID(), role: user, content: Improve the recipe, }); void copilotkit .runAgent({ agent }) // 显式指定 Agent 运行 .catch((err) console.error([shared-state-read] runAgent failed, err)); };要点先addMessage注入用户消息再copilotkit.runAgent({ agent })运行agent.isRunning作为并发闸门与RecipeCard中disabled{isLoading}的按钮禁用形成双保险。Agent 运行期间可读到的agent.state.recipe正是用户刚刚编辑过的最新菜谱——这就是每轮都读当前状态的具体体现。后端注册为什么只读不需要任何后端代码后端路由 route.ts 揭示了该演示与读写演示的本质差异。文件顶部定义了 Agent 工厂第 26–41 行function createAgent( graphId: string sample_agent, options: { recursionLimit?: number } {}, ) { return new LangGraphAgent({ deploymentUrl: LANGGRAPH_URL, // 默认 http://localhost:8123 graphId, langsmithApiKey: process.env.LANGSMITH_API_KEY || , assistantConfig: { recursion_limit: options.recursionLimit ?? 100 }, }); }注释解释了recursion_limit的处理原因LangGraph 的recursion_limit默认为 25且 Python 侧with_config不会经由 langgraph server 的 runs API 传播因此把限额固化进assistantConfig让每个经该路由发起的 run 都带上它。shared-state-read属于中性默认 Agent 组第 43–64 行// Cells that share the neutral default helpful, concise assistant graph. const neutralAssistantCells [ human_in_the_loop, shared-state-read, // ← 本演示 shared-state-write, prebuilt-sidebar, ... ]; const agents: Recordstring, LangGraphAgent {}; for (const name of neutralAssistantCells) { agents[name] createAgent(); // 默认 graphId: sample_agent }也就是说shared-state-read挂接的是名为sample_agent的默认对话图不注册任何后端工具——这与 README 所述the agent reads the shared application state … and responds based on the current data以及 manifest.yaml 中该演示的描述完全一致the agent reads the recipe context but does not mutate it (no backend tool — neutral default agent)。只读能力来自运行时把 Agent 状态随对话上下文提供给 LLM而不是靠工具回调runtime.state。作为对照同一路由里有专用图的演示则显式指定 graphId例如agents[shared-state-read-write] createAgent(shared_state_read_write)第 107 行见 langgraph.json 中shared_state_read_write的图注册。每个 demo 拥有独立注册名的意义也写在注释里Each still gets its own registered name so per-cell frontend tool/component registrations scope correctly.整个路由以createCopilotRuntimeHandler({ runtime: new CopilotRuntime({ agents }), basePath: /api/copilotkit, mode: single-route })组装第 129–147 行GET /api/copilotkit则提供健康探针返回 LangGraph 可达性与OPENAI_API_KEY等环境变量是否配置的状态。补充若需要像读写演示那样在后端主动查询共享状态shared-state-setup 文档给出的模式是前端agent.setState写入、图节点内state.get(...)读取并把CopilotKitMiddleware挂到create_agent调用上使 CopilotKit 专有状态与业务状态一并被拾取。shared-state-read演示作为纯只读形态则省去了这条后端接线。验证方式QA 清单与 Playwright 测试QA 检查清单qa/shared-state-read.md 给出了完整的人工验收项核心预期包括菜谱卡片与侧边栏 3 秒内加载侧边栏默认展开且标题为 AI Recipe Assistant初始状态核对标题 Make Your Recipe、时长默认 45 min、技能等级默认 Intermediate、默认食材与默认步骤逐项匹配与 types.ts 的INITIAL_RECIPE一一对应本地编辑全部即时生效标题、两个下拉、偏好胶囊、增删食材/步骤Agent 读取前端状态的关键用例手动编辑菜谱改标题、加食材后向侧边栏发送 What recipe am I making?验证 Agent 的回答引用的是当前菜谱状态错误处理空消息被优雅处理、Improve with AI 在加载期间禁用、正常操作无 console 报错。Playwright 自动化测试tests/e2e/shared-state-read.spec.ts 把 QA 契约固化为四条用例全部依赖 recipe-card.tsx 暴露的data-testidtest.beforeEach(async ({ page }) { await page.goto(/demos/shared-state-read); }); // 1. 菜谱卡片带默认食材加载侧边栏挂载含 AI Recipe Assistant 标题 // 2. 三条 starter suggestions 均可见 // 3. 点击 Add Ingredient 后 ingredient-card 行数 1 // 4. 在侧边栏发送 What recipe am I making? // 期望 [data-testidcopilot-assistant-message] 在 30s 内可见第 4 条用例就是Agent 读取前端状态的自动化断言Agent 必须基于当前状态作答并产出一条助手消息。测试头注释也明确了映射关系Spec mirrors the QA contract in qa/shared-state-read.md and the testids exposed by recipe-card.tsx.关键文件索引文件作用README.md演示说明模式定位、交互示例、技术要点page.tsxProvider 接线、useAgent订阅、setState写入、runAgent触发types.ts前后端共享的类型化状态 schema 与初始数据recipe-card.tsx纯受控表单变更全部经onChange流入 Agent 状态route.ts后端注册shared-state-read为中性默认 Agent、运行时路由与探针tests/e2e/shared-state-read.spec.tsPlaywright 端到端验收qa/shared-state-read.md人工 QA 清单与预期结果manifest.yaml演示清单路由/demos/shared-state-read、描述与高亮文件小结shared-state-read演示展示了 CopilotKit 共享状态模式中最轻量的一档前端是唯一写者Agent 是每轮的读者。实现上只需要三件事——用带类型的RecipeAgentState约定结构、用agent.setState让每次 UI 编辑直达 Agent 状态、用useAgent的OnStateChanged更新让 UI 与状态保持同步后端则零工具注册直接复用默认图即可回答关于当前状态的问题。当业务需要从只读升级为读写时可参考同一 showcase 下的shared-state-read-write演示在专用 LangGraph 图中以工具返回Command(update...)写回状态两种形态在 manifest.yaml 中并列注册便于对比学习。【免费下载链接】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),仅供参考
返回列表