CopilotKit LangGraph Interrupts Starter 版本演进解析:基于 CHANGELOG 的人机协同中断(HITL Interrupt)加固之路

发布时间:2026/9/10 15:27:28
CopilotKit LangGraph Interrupts Starter 版本演进解析:基于 CHANGELOG 的人机协同中断(HITL Interrupt)加固之路 CopilotKit LangGraph Interrupts Starter 版本演进解析基于 CHANGELOG 的人机协同中断HITL Interrupt加固之路【免费下载链接】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 仓库中的examples/v2/interrupts-langgraph是一个演示 人在回路Human-in-the-Loop中断确认流程的 LangGraph Next.js Starter其 CHANGELOG.md 完整记录了 0.1.1 到 0.1.7 共五个阶段的修复与重构。本文以该 CHANGELOG 为主体逐条解读每个版本的变更动机并结合 Agent 图实现、前端页面 与 运行时路由 的源码验证这些变更记录背后对应的真实代码行为帮助你理解一套生产级 HITL 中断系统应当做哪些加固。一、Starter 概览目录结构与运行方式在解读版本记录前先明确这份 CHANGELOG 描述的对象。按 README.md 与根目录 package.json项目是一个 pnpm workspace monorepo由 pnpm-workspace.yaml 声明packages: [apps/*]包含apps/webNext.js 前端包名web-langgraph-interrupt与apps/agentLangGraph Agent包名agent-langgraph-interrupt根脚本pnpm dev / build / lint全部委托给 Turbo见 turbo.json 中的dev、build、start、lint四个 task 定义Agent 通过langchain/langgraph-cli dev --port 8125在8125 端口启动前端运行在 3000 端口langgraph.json 将图注册为default: ./src/agent.ts:graph前置要求Node.js 20、pnpm 9.15.0、OpenAI API Key配置于apps/agent/.env。这一结构说明直接对应了 CHANGELOG 中大量独立提取后仍可运行的修复——因为该 Starter 的发布形态是从 monorepo 中抽出后可独立运行工具链配置必须自洽。二、0.1.72026-04-21面向 OpenAI 不变量的加固与日志/依赖修正CHANGELOG 0.1.7 是条目最多的版本分为 Fixed 与 Changed 两类。2.1 Fixed 条目逐条解析加固emit_unknown_tools_notice与intercept_frontend_tools针对 OpenAI tool_call 不变量违例与 prior-stash 覆盖问题。对应源码在 agent.ts 与 agent.tsemit_unknown_tools_notice只保留携带非空id的未知 tool_call为每个保留项合成status: error的 ToolMessageTool ${call.name} is not available in this environment.并让重建后的 AIMessage 同时保留 known 与 unknown calls——因为 OpenAI 在下一轮会校验每个 ToolMessage 的tool_call_id必须匹配前一条 AIMessage 的tool_call.id任何悬空引用都会毒化整个会话intercept_frontend_tools处理上一轮 stash 未及 flush 时又进入本节点的竞争先按originalAIMessageId在剥离前 flush失败再在剥离后二次 flush两次都失败才发出携带丢失 id 列表的console.warn并写入新 stash源码注释明确说明把两个不同 AIMessage id 合并进同一个 slot 会破坏 originalAIMessageId。useCopilotAction的依赖数组修正。page.tsx 中setThemeColoraction 的依赖为[setThemeColor]第 33 行getWeather的依赖为[themeColor]第 264 行——依赖数组必须与 handler 闭包中实际读取的状态一致否则 handler 捕获的是过期值。Next 16 移除next lint改为直接调用 ESLint。可在 apps/web/package.json 中验证lint: eslint . --max-warnings0不再出现next lint。route.ts的 LANGSMITH 警告按 NODE_ENV 门控。route.ts 中if (!process.env.LANGSMITH_API_KEY process.env.NODE_ENV ! production)与LANGGRAPH_DEPLOYMENT_URL的警告第 25-32 行采用同一策略next build会以NODE_ENVproduction求值路由模块此时 env 尚未注入门控避免 CI 构建时刷屏误报。日志前缀区分runtime 构建失败与dispatch 失败。route.ts 用两个独立的 try/catch[copilotkit/route] runtime construction failed:配置/环境错误与[copilotkit/route] handleRequest dispatch failed:请求内异常两者都返回结构化 500 JSON。README 的 Troubleshooting 一节也明确教用户按这两个前缀排障。parseInterruptPayload单一返回结构日志交给调用方。page.tsx 中解析器只返回{ ok: true; value } | { ok: false; reason }自身不打日志唯一的错误日志行由useInterrupt的 render 回调持有[interrupts-langgraph] Unknown interrupt payload shape:消除了旧版解析器与渲染器双打日志的重复。2.2 Changed 条目LICENSE 版权署名改为2025-2026 CopilotKit原为个人署名README 修正修复 troubleshooting 中失效的pnpm --filter示例把内联echo .env改为cp .env.example .env 手动编辑项目结构图中的注释改为引用pnpm-workspace.yaml与当前 README 第 14 行一致apps/web/tsconfig.json移除无用的.next/dev/types/**includeapps/web/.env.example澄清 LANGSMITH_* 变量语义从 apps/web/.env.example 可见这些变量主要被 agent/LangGraph 部署消费Web 侧仅在route.ts中读取LANGSMITH_API_KEY转发给LangGraphAgent客户端根.gitignore忽略dist/turbo.json增加starttask当前 turbo.json 中start为cache: false, persistent: true, dependsOn: [^build]apps/web/project.json的buildtarget 设置cache: false与 package.json 的 Nx 配置保持一致见 apps/web/package.json 的nx.targets.build.cache: falseapps/agent/tsconfig.json设置noEmit: true使直接tsc调用与脚本驱动构建tsc -p tsconfig.json --noEmit见 apps/agent/package.json行为一致。三、0.1.62026-04-21让 Starter 可独立提取构建0.1.6 的主题是修复 Starter 被从 monorepo 中抽出单独使用时构建失败的问题逐条对照当前仓库文件均可验证根目录补上turbo.json此前根脚本委托 turbo 但缺少配置turbo run dev/build/lint在独立提取时直接失败补上pnpm-workspace.yamlpnpm v9 不再识别根package.json的workspaces数组缺少该文件会导致workspace:*依赖如 agent 的copilotkit/sdk-js: workspace:*、web 的copilotkit/react-core、copilotkit/runtime链接失败Agenttsconfig.json的target从es2016提升到ES2022显式lib: [ES2022]无 DOM对齐已声明的 Node 20 运行时基线apps/agent/package.json补build/lint脚本tsc -p tsconfig.json --noEmit与project.json声明一致使turbo run build/lint与 Nx target 口径统一补全 agent 的空description与author字段当前值为LangGraph agent for the CopilotKit interrupts starter/CopilotKitapps/web/.env.example增加注释掉的LANGSMITH_TRACINGtrue与 agent 侧 .env.example 对齐两侧均含LANGSMITH_API_KEY/LANGSMITH_TRACING/LANGSMITH_PROJECT三个可选项apps/web/tsconfig.json增加baseUrl: .让/*路径别名在各 IDE 与工具链中稳定解析清理apps/agent/.gitignore中 Python 残留项venv/、__pycache__/、*.pyc——该目录 fork 自 Python LangGraph Starter本身是 TypeScript 项目LICENSE 补充版权年份MIT 惯例。Versioning 约定根、apps/agent、apps/web三包版本号从0.1.5同步升到0.1.6。当前仓库三个package.json的version均为0.1.7印证了子包版本跟随根 Starter 版本、changelog 条目与 package.json 读数跨 workspace 保持一致的约定。四、0.1.52026-04-17目录更名与路由/校验加固4.1 Renamed目录从interrupts-langraph更名为interrupts-langgraph拼写修正代码中立。当前仓库目录即为更名后的examples/v2/interrupts-langgraph。4.2 图内路由与 payload 校验对应源码可全部复核类型收紧Agent 图内移除as any改用isAIMessage类型谓词做结构收窄agent.ts 中shouldContinue对末条消息先用isAIMessage判定非 AIMessage 打 warn 后落到END并在chat_node中对model.bindTools加了显式能力守卫第 242-246 行模型不支持 bindTools 时直接 throw。shouldContinue评估全部 tool_callsagent.ts只要批次中任意一个调用指向已注册后端工具就路由到tool_node避免前端 action 后端工具混合批次中后端调用被静默丢弃每个未知工具名单独console.warn含后端工具时保留走tool_nodeToolNode 会对未知名发 error ToolMessage图随后带该错误回到chat_node否则落END含未知名且无后端工具时走emit_unknown_tools_notice。Web 侧parseInterruptPayload校验非法 payload 渲染取消兜底 UI 而非崩溃数组被显式拒绝旧实现中数组能通过typeof object检查并被强转为 Record 查找路径——当前实现第 162 行Array.isArray(value)提前拦截。Agent 侧 zod 校验 resume 值ApprovalResumeSchemaz.object({ approved: z.boolean() })在deleteProverb工具内解析interrupt()返回值带外out-of-band客户端以错误形状 resume 时会在工具边界显式失败返回status: error的 ToolMessage内容说明deletion was NOT performed而不是静默走 cancelled 分支。注意源码只对z.ZodError做降级处理其他异常照常抛出避免掩盖真实 bug。deleteProverb使用函数式setStatepage.tsx 中删除按钮的setState((prev) ...)按值而非捕获的 index 过滤防止渲染与点击之间 Agent 增删条目导致索引漂移React key 采用${index}-${proverb}复合键第 292 行纯proverb在重复内容时冲突纯index在 Agent 侧插入时使行失稳源码注释声明迁移到{id, text}对象是长期正解留待后续需扩展AgentState.proverbs类型移除未使用的starterAgent别名模型名提为MODEL常量agent.tsconst MODEL gpt-4o-mini实现单点替换route.ts为handleRequest包结构化错误响应未处理异常表现为结构化 500 JSON 而非 Next.js 原始错误页见上文 2.1 第 4/5 条README 端口引用统一为 8125占位的 Next metadata 替换为真实 title/description当前 layout.tsx 的metadata即 CopilotKit LangGraph Interrupts Starter。4.3 Dependencies 与 VersioningCHANGELOG 记录 0.1.5 的依赖变更与 apps/agent/package.json、apps/web/package.json 完全吻合依赖变更现状types/node^20 → ^22.19.11agent/web 两侧均为^22.19.11typescript^5 → ^5.9.3两侧均为^5.9.3zod^3.24.4 → ^3.25.76两侧均为^3.25.76langchain/langgraph由根overrides钉 1.0.2 → agent 直接声明1.1.5agent 依赖为精确版本1.1.5langchain/coreagent 提升到^1.1.26agent 依赖^1.1.26同时删除了根overrides中的langchain/core与langchain/langgraph两项前者在 monorepo pnpm workspace 内本就无效若独立提取反而会压低 agent 的^1.1.26需求后者随版本收归 agent 自持。Versioning 部分则把apps/agent0.0.1与apps/web0.1.0同步到 0.1.5确立了与上文相同的 lockstep 约定。五、0.1.1 – 0.1.4CHANGELOG 对 0.1.1 至 0.1.4 的记述仅一行Internal only (dependency sync / tooling bumps)仅限内部依赖同步与工具链升级无对外行为变化。六、结合源码复盘中断Interrupt端到端机制版本记录反复加固的正是同一条 HITL 链路。以删除谚语需用户确认为例端到端流程如下6.1 Agent 侧interrupt()与 resume 校验deleteProverb 工具 的核心序列从ToolRunnableConfig.toolCall.id取toolCallId缺失则直接 throw——因为返回Command会绕过 ToolNode 自动的tool_call_id接线而 OpenAI 拒绝空/不匹配的tool_call_id调用interrupt({ action: delete_proverb, proverb, message })图在此暂停等待前端 resumeresume 值先过ApprovalResumeSchema.parse失败则返回确定性 error ToolMessage批准分支用getCurrentTaskInputAgentState()读取当前图状态按内容匹配过滤proverbs找不到目标时返回 nothing was deleted 的错误 ToolMessage不向模型撒谎无论批准或取消都返回Command包裹带正确tool_call_id的 ToolMessage批准时同时写入proverbs: filtered状态更新——没有这一步UI 读state.proverbs仍会显示已删除的条目。6.2 图结构与混合批次路由workflow 定义 由五个节点组成chat_node、tool_nodeToolNode、intercept_frontend_tools、restore_frontend_tools、emit_unknown_tools_notice固定边intercept → tool_node → chat_node、restore → END、emit_unknown_tools_notice → restore_frontend_tools条件边挂在chat_node上。intercept/restore镜像了copilotkit/sdk-js的copilotkitMiddlewareafterModel/afterAgent 拦截模式可对照 middleware 测试 中copilotkitMiddleware.afterModel产生copilotkit.interceptedToolCalls、afterAgent还原的断言——本 Starter 是原始 StateGraph 而非 createAgentmiddleware因此把该模式内联实现混合批次先把前端 action 的 tool_calls 剥离暂存interceptedToolCallsoriginalAIMessageId让 ToolNode 只跑后端工具图结束前再按 id 挂回原 AIMessage保证前端 runtime 仍能派发这些调用。6.3 前端侧useInterrupt渲染确认 UIpage.tsx 使用来自copilotkit/react-core/v2的useInterrupt其实现位于 use-interrupt.tsx配置支持render、handler、enabled过滤、agentId与renderInChat内外两种渲染模式render回调接收{ event, resolve }先用parseInterruptPayload校验 payload{ action: delete_proverb; proverb: string; message: string }合法则渲染带 Yes, delete it由APPROVE_LABELS按 action 穷举映射新增 action 未扩展映射会直接编译报错与 Cancel 的确认卡片分别resolve({ approved: true/false })恢复 Agent。6.4 运行时路由懒构建与失败门控route.ts 用闭包缓存在首个请求时才构建LangGraphAgentdeploymentUrl缺省回退http://localhost:8125graphId: default与 layout.tsx 的CopilotKit runtimeUrl/api/copilotkit agentdefault对应CopilotRuntimecopilotRuntimeNextJSAppRouterEndpoint。之所以延迟next build以NODE_ENVproduction求值路由模块但生产 env 在构建期尚未注入模块加载期抛错会中断本可成功的构建且会把 localhost 回退地址烘焙进产物。生产环境缺少LANGGRAPH_DEPLOYMENT_URL则在首次请求时 fail-fast第 64-69 行。七、从版本演进中可复用的工程模式通读 CHANGELOG 并结合源码这套 Starter 展示了数条可直接迁移到自身 Agent 项目的实践消息序列合法性是硬不变量每个 tool_call 必须有匹配的 ToolMessage 结果、tool_call_id不得为空或失配——deleteProverb拒绝空 id、emit_unknown_tools_notice保留 unknown 调用、intercept保留 AIMessage 全部元数据usage_metadata等避免破坏追踪与 token 统计都服务于同一目标双向 payload 校验发出的 interrupt payload 由前端parseInterruptPayload校验resume 值由 Agent 侧 zod 校验两端各自兜底防止任一侧 schema 漂移导致静默分支路由函数只路由、不改状态shouldContinue是纯路由函数状态重写全部放在独立节点中完成源码注释明确说明这一点单点日志解析器不写日志、调用方持有唯一日志行按 NODE_ENV 门控构建期警告按失败阶段拆分日志前缀使排障README Troubleshooting 直接引用这些前缀有章可循Starter 级版本管理三包 lockstep 升级 CHANGELOG 每条变更都能在仓库文件中复核使模板可被独立提取后原样构建。八、关键文件索引文件作用CHANGELOG.md本文主体0.1.1–0.1.7 变更全记录README.md目录结构、启动脚本、Troubleshootingapps/agent/src/agent.ts图定义、deleteProverbHITL 工具、拦截/恢复节点apps/agent/langgraph.jsondefault图注册与 env 声明apps/web/src/app/page.tsxuseInterrupt确认 UI、共享状态、parseInterruptPayloadapps/web/src/app/api/copilotkit/route.ts运行时路由、懒构建、结构化 500apps/web/.env.example / apps/agent/.env.example环境变量模板与语义说明turbo.json / pnpm-workspace.yaml独立提取可用的构建工具链packages/react-core/src/v2/hooks/use-interrupt.tsxuseInterruptHook 的 SDK 实现适用前提说明以上分析基于当前仓库中该 Starter 0.1.7 的实际内容要求 Node 20 / pnpm 9.15 环境其中 Agent 依赖langchain/langgraph精确版本 1.1.5 与langchain/core^1.1.26前端使用 Next 16.0.8。CHANGELOG 0.1.1–0.1.4 仅存一行概述更细的中间态细节已不可考。【免费下载链接】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),仅供参考