ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CopilotKit × LangGraph Python:以 Todo 协作清单为例的 Agent 状态同步模式深度解析

2026/9/10 6:28:28 拓冰建站 浏览量
CopilotKit × LangGraph Python:以 Todo 协作清单为例的 Agent 状态同步模式深度解析 CopilotKit × LangGraph Python以 Todo 协作清单为例的 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本文基于 langgraph-python 集成示例 编写聚焦其中演示的CopilotKit v2 代理状态模式agent state pattern状态定义在 LangGraphPythonAgent 中通过双向同步驱动 Next.js 前端的交互式 Todo 应用。读完后你将掌握如何在自己的项目中让 AI Agent 与用户共同操作同一份结构化应用状态——而不只是停留在聊天框里。这个示例的定位Showcase 兼模板CLAUDE.md 明确说明examples/integrations/langgraph-python这个仓库目录同时承担两个角色Showcase演示展示 CopilotKit 如何驱动超越聊天的交互 UI主要载体是一个协作式 Todo 清单Template模板面向正在评估 CopilotKit 或准备启动 AI Agent 新项目的开发者代码被设计为可直接 fork 后扩展。目标受众是开发者——它演示的核心命题是agent-driven UI代理驱动的 UIAgent 可以操作应用状态添加 todo、更新状态、整理任务用户可以操作同一份状态编辑标题、勾选任务、删除 todo双方的修改更新的是同一个共享状态UI 会基于 Agent 的状态变化做出响应式更新。实现这一命题的机制就是 CopilotKit 的v2 agent state pattern状态住在 Agent 里并同步到前端。核心概念Agent 与用户共享同一份状态传统做法里前端有一份 React state后端有一份数据库两边靠 API 手动同步。而这个模式把真相来源直接放在 Agent 的 graph state 里用户点击复选框 ──→ agent.setState({todos}) ──→ Agent graph state Agent 调用 manage_todos 工具 ──────────────→ Agent graph state ──→ 前端重新渲染前端既不持有独立的业务状态也不手写同步逻辑只通过useAgent()钩子对agent.state进行读写。这一模式在项目中的四个关键步骤如下文详解。项目架构与目录结构CLAUDE.md 描述这是一套扁平的 npm 项目flat npm projectNext.js 前端位于根目录Python Agent 位于agent/子目录。文档给出的结构树与实际仓库基本一致实际目录结合 README.md 的结构说明如下examples/integrations/langgraph-python/ ├── src/ │ ├── app/ │ │ ├── page.tsx # 主页面装配所有组件 │ │ └── api/copilotkit/ # CopilotKit API 路由 │ ├── components/ │ │ ├── example-canvas/ # Todo 清单 UIindex / todo-list / todo-column / todo-card │ │ ├── example-layout/ # 布局聊天 画布并排 │ │ ├── generative-ui/ # 生成式 UI 示例组件 │ │ └── ui/ # 基础 UI 组件button、checkbox 等 │ ├── hooks/ │ │ ├── use-generative-ui-examples.tsx # CopilotKit 模式示例 │ │ └── use-example-suggestions.tsx # 聊天建议 │ └── agent.ts # LangGraphAgent 客户端封装 ├── agent/ # LangGraph Python Agent │ ├── main.py # Agent 入口 │ └── src/ │ ├── todos.py # Todo 工具与状态 schema │ ├── query.py # 示例数据查询工具 │ └── a2ui*/ # A2UI 固定/动态 schema 工具 ├── scripts/ │ ├── setup-agent.sh / .bat # 安装 Python 依赖uv sync │ └── run-agent.sh / .bat # 启动 LangGraph dev server ├── package.json # 根项目配置npm concurrently └── next.config.ts注意一个路径细节文档结构树中写的是src/components/canvas/而仓库中实际的 Todo UI 目录名为 src/components/example-canvas/两者指向同一套组件。关键模式CopilotKit v2 Agent State这是整个示例的灵魂。状态定义在 Agent 后端并与前端双向同步。下面按文档脉络的四个步骤展开并在每一步附上仓库中的真实源码。第 1 步Agent 端定义状态 schema 和工具Python文档给出的模式示意节选自 CLAUDE.md# agent/src/todos.py class Todo(TypedDict): id: str title: str description: str emoji: str status: Literal[pending, completed] class AgentState(TypedDict): todos: list[Todo] tool def manage_todos(todos: list[Todo], runtime: ToolRuntime) - Command: Manage the current todos. return Command(update{todos: todos, ...})对照仓库真实实现 agent/src/todos.py有一个值得注意的细节AgentState并不是凭空定义一个全新的TypedDict而是继承自langchain.agents的AgentState在其上追加todos字段from langchain.agents import AgentState as BaseAgentState from langchain.tools import ToolRuntime, tool from langchain.messages import ToolMessage from langgraph.types import Command from typing import TypedDict, Literal import uuid class Todo(TypedDict): id: str title: str description: str emoji: str status: Literal[pending, completed] class AgentState(BaseAgentState): todos: list[Todo]这样做的好处是状态 schema 在保留 LangChain Agent 原有消息通道messages的同时把业务字段todos注册进 graph stateCopilotKit 后续才能将其同步到前端。第 2 步前端从 Agent 状态读取数据文档给出的前端读取模式节选自 CLAUDE.md// Canvas 组件 const { agent } useAgent(); return ( TodoList todos{agent.state?.todos || []} onUpdate{(updatedTodos) agent.setState({ todos: updatedTodos })} isAgentRunning{agent.isRunning} / );仓库真实实现位于 src/components/example-canvas/index.tsx与文档完全一致useAgent从copilotkit/react-core/v2导入use client; import { useAgent } from copilotkit/react-core/v2; import { TodoList } from ./todo-list; export function ExampleCanvas() { const { agent } useAgent(); return ( div classNameh-full overflow-y-auto bg-[--background] div classNamemax-w-4xl mx-auto px-8 py-10 h-full TodoList todos{agent.state?.todos || []} onUpdate{(updatedTodos) agent.setState({ todos: updatedTodos })} isAgentRunning{agent.isRunning} / /div /div ); }三个要点agent.state?.todos || []—— 状态直接来自 Agent前端没有第二份副本|| []兜底初始为空的状态agent.setState({ todos: updatedTodos })—— 用户的每一次点击都通过这行写回 Agentagent.isRunning—— 把Agent 正在执行暴露给 UI用于在执行期间禁用按钮避免并发写入见下文TodoList中disabled{isAgentRunning}的用法。第 3 步用户交互更新 Agent 状态文档给出的用户交互模式// 用户点击复选框 → 前端调用 agent.setState() const toggleStatus (todo) { const updated todos.map((t) t.id todo.id ? { ...t, status: t.status completed ? pending : completed } : t, ); agent.setState({ todos: updated }); };真实实现 src/components/example-canvas/todo-list.tsx 中toggleStatus通过onUpdate(updated)间接调用agent.setState()onUpdate就是 Canvas 传入的agent.setState包装。除了勾选该组件还完整实现了删除、改标题、改描述、改 emoji、新建crypto.randomUUID()生成 id等操作全部走同一条onUpdate → agent.setState通道const toggleStatus (todo: Todo) { const updated todos.map((t) t.id todo.id ? { ...t, status: (t.status completed ? pending : completed) as | pending | completed, } : t, ); onUpdate(updated); }; const deleteTodo (todo: Todo) { onUpdate(todos.filter((t) t.id ! todo.id)); }; const addTodo () { const newTodo: Todo { id: crypto.randomUUID(), title: New Todo, description: Add a description, emoji: , status: pending, }; onUpdate([...todos, newTodo]); };布局上TodoList将todos按status过滤为两列To Do/Done分别渲染为TodoColumn对应 todo-column.tsx 与 todo-card.tsx。第 4 步Agent 通过工具操作状态文档说明Agent 调用manage_todos工具更新 todo 列表用户和 Agent 的修改落在同一个agent.state.todos上前端在状态变化时自动重新渲染。仓库真实实现 agent/src/todos.pytool def manage_todos(todos: list[Todo], runtime: ToolRuntime) - Command: Manage the current todos. # Ensure all todos have IDs that are unique for todo in todos: if id not in todo or not todo[id]: todo[id] str(uuid.uuid4()) # Update the state return Command( update{ todos: todos, messages: [ ToolMessage( contentSuccessfully updated todos, tool_call_idruntime.tool_call_id, ) ], } ) tool def get_todos(runtime: ToolRuntime): Get the current todos. return runtime.state.get(todos, []) todo_tools [manage_todos, get_todos]两个实现细节值得关注Command(update{...})工具不是返回普通值而是返回 LangGraph 的Command一次性更新todos状态并附带一条ToolMessage携带tool_call_id保证状态更新与消息流在同一步提交id 补全Agent 生成的 todo 如果没有 id工具会用uuid4兜底避免前端按 id 匹配/更新时出错。为什么选这个模式文档给出了四条理由与源码表现一致Single source of truth单一真相来源状态住在 Agent不在前端重复一份Bidirectional sync双向同步用户变更 → Agent 状态Agent 变更 → UI 更新Simple简单不需要独立的前端状态管理方案Observable可观测Agent 对状态变化有完整可见性get_todos可直接读取runtime.state。文档的**关键洞察Key insight**一句话概括状态住在 Agent前端只是通过 CopilotKit 钩子对它进行读写。Agent 后端入口真实配置与中间件文档中的 Agent 定义示意节选自 CLAUDE.mdfrom langchain.agents import create_agent from copilotkit import CopilotKitMiddleware from src.todos import todo_tools, AgentState agent create_agent( modelgpt-5.2, tools[*todo_tools, ...], # manage_todos, get_todos middleware[CopilotKitMiddleware()], state_schemaAgentState, system_promptYou are a helpful assistant... )仓库当前的 agent/main.py 在此基础上有所演进完整代码如下from copilotkit import CopilotKitMiddleware, StateStreamingMiddleware, StateItem from langchain.agents import create_agent from src.query import query_data from src.todos import AgentState, todo_tools from src.a2ui_dynamic_schema import generate_a2ui from src.a2ui_fixed_schema import search_flights from langchain_openai import ChatOpenAI model ChatOpenAI(modelgpt-5.4-mini, model_kwargs{parallel_tool_calls: False}) agent create_agent( modelmodel, tools[query_data, *todo_tools, generate_a2ui, search_flights], middleware[ CopilotKitMiddleware(), StateStreamingMiddleware( StateItem(state_keytodos, toolmanage_todos, tool_argumenttodos) ), ], state_schemaAgentState, system_promptSYSTEM_PROMPT, )与文档示意相比有三处增量信息模型实例化文档示意写modelgpt-5.2当前仓库实际使用ChatOpenAI(modelgpt-5.4-mini, model_kwargs{parallel_tool_calls: False})即通过ChatOpenAI显式关闭并行工具调用——对 Todo 这类整表替换状态的工具来说可以避免两个manage_todos并发执行互相覆盖StateStreamingMiddleware注册了一个StateItem(state_keytodos, toolmanage_todos, tool_argumenttodos)把manage_todos工具的todos参数与状态键todos绑定。从源码结构看它的作用是在工具调用阶段就把参数增量流式推送到前端而不是等工具执行完才整体更新——这是Agent 修改 UI 实时可见体验的关键工具集扩展create_agent还挂载了query_data数据查询见 agent/src/query.py与两个 A2UI 工具search_flights、generate_a2ui。系统提示词中明确指示 Todos: enable app mode first, then manage todos即 Todo 画布功能与聊天/图表等模式共存于同一 Agent。CopilotKitMiddleware本身是 sdk-python 中实现的 LangGraph Agent 中间件其模块 docstring 明确说明 Works with any agent (prebuilt or custom)即无论create_agent预构建还是自定义 graph 都可挂载。前端接线线程模型与 LangGraphAgentCLAUDE.md 主要聚焦状态模式本身而仓库源码还揭示了前端与 Agent 之间的完整接线方式值得作为补充理解Agent 客户端定义src/agent.tsimport { LangGraphAgent } from copilotkit/runtime/langgraph; export function createDefaultAgent(): LangGraphAgent { return new LangGraphAgent({ deploymentUrl: process.env.AGENT_URL || process.env.LANGGRAPH_DEPLOYMENT_URL || http://localhost:8123, graphId: sample_agent, langsmithApiKey: process.env.LANGSMITH_API_KEY || , }); }deploymentUrl默认指向本地http://localhost:8123与下文开发脚本中的 Agent 端口一致graphId: sample_agent与 agent/pyproject.toml 中name sample-agent对应连字符转下划线源码注释说明每次调用返回全新实例因为 channel host 会为每个会话设置threadId共享实例会跨线程泄漏状态。页面装配src/app/page.tsx页面使用未受控的CopilotChatConfigurationProvideragentIddefault持有活跃线程CopilotChat聊天面板与ExampleCanvasTodo 画布挂载在ExampleLayout的并排布局中读取同一个活跃线程下的 Agent 状态。从源码结构看这就是聊天与画布共享同一份agent.state的装配点。状态如何流动文档给出的六步状态流State Flow用户添加/编辑 todo→ 前端调用agent.setState({ todos: [...] })Agent 状态更新→ CopilotKit 同步到后端Agent 感知变化→ 可通过manage_todos工具响应Agent 修改 todos→ 调用manage_todos工具状态同步回前端→agent.state.todos更新UI 重新渲染→ React 感知新状态并更新展示结合 agent/main.py 中的StateStreamingMiddleware第 4→5 步在工具参数阶段即可开始流式推送前端因此能在 Agent边想边改时逐步看到 todo 列表变化。技术栈与版本文档声明的技术栈CLAUDE.md与仓库配置一致层文档声明仓库实证前端Next.js 16, React 19, TailwindCSS 4package.jsonnext 16.1.6、react ^19.2.4、tailwindcss ^4CopilotKitReact hooks for agent integration (v2)copilotkit/react-core、copilotkit/runtime、copilotkit/a2ui-renderer均为1.70.2useAgent来自copilotkit/react-core/v2AgentLangGraph (Python) OpenAIagent/pyproject.tomllangchain1.2.15、langgraph1.1.6、copilotkit0.1.96、ag-ui-protocol0.1.19、langgraph-cli[inmem]0.4.21模型当前为gpt-5.4-mini构建npm concurrently 并行开发进程dev脚本用concurrently同时拉起 UI 与 Agent--kill-others保证同生共死其他Recharts生成式 UI 示例recharts ^3.7.0此外 package.json 通过overrides将ag-ui/client、ag-ui/core、ag-ui/encoder、ag-ui/proto锁定在0.0.59保证 AG-UI 协议组件版本一致CopilotKit 即 AG-UI 协议的发起方。Python 侧依赖版本被精确锁定如copilotkit0.1.96要求requires-python 3.12这也是文档Development一节适用前提的一部分。本地开发与运行前置条件结合 README.mdNode.js 18、Python 3.12、uv 包管理器仓库内通过uv sync安装 Python 依赖、任一 JS 包管理器npm 为默认、OpenAI API Key。环境配置# 设置 OpenAI API key cp .env.example .env # 编辑 .env加入 OPENAI_API_KEYyour-openai-api-key-here开发命令文档给出的命令与 package.json 脚本一致# 安装依赖postinstall 会同时通过 setup-agent.sh 执行 uv sync 装好 Agent npm install # 同时启动前端和 Agent npm run dev # 单独启动 npm run dev:ui # Next.js 前端next dev --turbopack端口 3000 npm run dev:agent # LangGraph Agent端口 8123 # 构建 npm run build底层脚本的实现值得看一眼scripts/run-agent.shcd agent npx langchain/langgraph-cli dev --port 8123 --no-browser——即dev:agent实际是用 LangGraph CLI 以 dev 模式在 8123 端口启动 Agentscripts/setup-agent.shcd agent uv sync——即postinstall/install:agent用 uv 按 agent/pyproject.toml 同步 Python 环境。.bat版本提供 Windows 等价实现。故障排查README.md 补充了文档未展开的排障要点若 Agent 侧提示 Im having trouble connecting to my tools请确认 ① LangGraph Agent 运行在 8123 端口② OpenAI API key 配置正确③ 两个服务都成功启动。Python 导入错误时运行npm run install:agent重建虚拟环境。设计原则文档总结了四条设计原则可作为扩展这个模板的行为准则Simple over complex简单优先——Todo 清单刻意保持简单、聚焦CopilotKit v2 patterns使用现代模式——采用 v2 的 Agent 状态管理Template-first模板优先——代码就是为被 fork 和扩展而写的Showcasing agent-driven UI展示代理驱动 UI——演示 AI 在聊天之外操作应用状态的能力。开发者要点如何扩展这个模板文档最后的 Key Takeaways 给出了扩展清单本文按仓库实证补全为可执行步骤状态管理模式回顾状态定义在 Agent 后端PythonTypedDict继承langchain.agents.AgentState前端通过agent.state.todos读取前端通过agent.setState({ todos: ... })写入Agent 通过工具manage_todos修改状态变更自动双向同步。扩展模板时的四步定义状态 schema在 agent/src/todos.py 风格的AgentState上追加你的业务字段如contacts: list[Contact]创建操纵状态的工具返回Command(update{...})参考manage_todos的整表替换写法并注意为缺少 id 的实体补uuid4前端用useAgent()读写在画布组件里todos{agent.state?.xxx || []}读、agent.setState({ xxx: ... })写并把agent.isRunning传给 UI 做执行期禁用让 CopilotKit 处理同步不需要手写任何状态管理。若希望工具参数阶段就流式更新 UI参照 agent/main.py 追加StateStreamingMiddleware(StateItem(state_key..., tool..., tool_argument...))。这个模式适用于一类场景AI 需要操作结构化应用状态、而不只是回消息的 agent-driven 应用——表单、看板、画布、配置面板等都同构于此。小结CLAUDE.md 用一份 Todo 清单把 CopilotKit v2 LangGraph Python 的核心协作范式讲清楚了TypedDict状态 schema Command工具 useAgent()前端读写 中间件同步四者拼出双向共享状态的闭环。配合仓库中 agent/main.py、agent/src/todos.py、src/components/example-canvas/index.tsx 和 src/agent.ts 的真实实现可以直接作为自己项目里 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/CopilotKit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考