CopilotKit 实战:基于 LangGraph + Tavily 构建带人工在环(Human-in-the-Loop)的研究画布应用 ANA
【免费下载链接】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 仓库中的open-research-ANA演示项目(位于 examples/showcases/research-canvas/final)为核心,讲解如何将 LangGraph 状态机、Tavily 实时搜索与 CopilotKit 的 Agent Native 前端结合起来,构建一款支持"人工审核大纲 → 分节写作 → 实时进度展示"的交互式研究画布应用。读完本文,你将掌握从 LangGraph Agent 到 Next.js 前端的完整搭建链路、interrupt人工在环机制的实现原理,以及 CopilotKit 状态渲染与流式输出 API 的实际用法。
项目概览:什么是 ANA(Agent Native Application)
open-research-ANA是一个研究画布(Research Canvas)演示应用,README 将其定位为"ANA(Agent Native Application)":应用不再是单纯的聊天框,而是把 Agent 的中间状态(搜索进度、大纲提案、章节草稿)直接渲染到页面上的一个结构化工作区。其核心能力组合如下:
- Tavily 实时搜索:为 Agent 提供真实的联网检索与页面内容抽取能力;
- LangGraph 工作流:编排"搜索 → 提大纲 → 人工审核 → 分节写作"的状态机流程;
- CopilotKit Agent 界面:负责 Agent 与前端的通信、状态渲染、中断(interrupt)处理与流式章节输出。
项目目录中同时保留了start/(起始骨架)与final/(完整实现)两份副本,final即本文讲解的成品。Agent 端为 Python(LangGraph + CopilotKit Python SDK),前端为 Next.js(React + CopilotKit React SDK),两者通过 CopilotKit Runtime 桥接。
整体架构:Agent 与前端如何协同
从代码结构看,项目由两个相对独立的部分组成:
- Agent 端(examples/showcases/research-canvas/final/agent):包含状态定义 state.py、模型配置 config.py、工作流图 graph.py,以及
tools/下的四个工具(tavily_search、tavily_extract、outline_writer、section_writer)。 - 前端(examples/showcases/research-canvas/final/frontend):Next.js 15 应用,页面通过 page.tsx 组织成"左侧聊天 + 右侧文档视图"的可拖拽分栏布局,核心组件包括
Chat、DocumentsView、StructureProposalViewer、Progress、SourcesModal等。
前后端之间由 Next.js API 路由 route.ts 承接:它使用@copilotkit/runtime的CopilotRuntime与langGraphPlatformEndpoint指向 LangGraph 平台部署的agent(描述为 "Research assistant"),同时用OpenAIAdapter连接 OpenAI 服务。
Agent 工作流的三节点设计
graph.py 中的ResearchAgent类把研究流程建模为一张三个节点的状态图:
call_model_node:入口与终点节点。动态构建 System Prompt,调用绑定工具的 LLM,若模型决定调用工具则跳转tool_node,否则结束图执行(__end__);tool_node:自定义异步工具节点。依次执行模型选择的工具,把工具返回的新状态通过copilotkit_emit_state推送给前端;其中review_proposal工具是特殊路由——命中它即跳转process_feedback_node;process_feedback_node:人工在环节点。调用interrupt(state.get("proposal", {}))挂起图的执行,等待用户在前端审核大纲后返回结果。
图的边定义非常简洁:call_model_node是入口同时也是出口(set_finish_point),tool_node与process_feedback_node执行完都回到call_model_node,形成循环直到模型不再调用工具为止。
状态的集中管理:ResearchState
state.py 中ResearchState继承自CopilotKitState(后者扩展了 LangGraph 的MessagesState),额外声明了研究任务所需的全部字段:
title:报告标题;proposal:写作前提交给用户审核的提议结构(含各章节的 title / description / approved 标记);outline:用户审核通过后的最终大纲;sections:已写好的章节列表,每项含title、content、idx;footnotes与sources:参考文献与来源数据(URL 到来源对象的映射);tool:当前正在执行的工具名;logs:推送给前端展示的进度日志列表(每项含message与done状态)。
所有关键中间产物都沉淀在状态里,工具通过读写state实现数据共享,这也是 Agent Native 界面能实时渲染"搜索进度、大纲提案、章节草稿"的数据基础。
快速启动:从零跑通 ANA
以下是 README 给出的标准启动流程,分为 Agent 与前端两大部分。
1. 环境准备(Prerequisites)
项目依赖以下工具:
- pnpm 指定
packageManager: pnpm@10.2.1); - Docker:LangGraph 本地开发服务依赖容器运行;
- LangGraph CLI:用于启动本地 Agent 服务(Agent 端 requirements.txt 固定了
langgraph-cli==0.1.71)。
2. 需要准备的 API Key
在本地运行时,需要以下四组密钥(分别配置在 Agent 与前端两个.env文件中):
- OpenAI:驱动 LLM 推理(Agent 端模型配置见 config.py:主流程使用
gpt-4o-mini、温度 0.0,大纲写作等任务用gpt-4/gpt-4o-mini); - Tavily:实时搜索与网页内容抽取;
- LangSmith:LangGraph 平台的追踪与链路观测;
- CopilotKit:云端 Dashboard 提供的
NEXT_PUBLIC_COPILOT_CLOUD_API_KEY,用于前端与 Agent 的安全通信。
3. 启动 Agent
cd agent # Create and populate .env cat << EOF > .env OPENAI_API_KEY=your_key TAVILY_API_KEY=your_key LANGSMITH_API_KEY=your_key EOF ## Start the agent langgraph up # Note the API URL from the output (e.g., http://localhost:8123)langgraph up会读取 langgraph.json,其声明了图的入口"agent": "./graph.py:graph"(即graph = ResearchAgent().graph编译产物)、Python 版本3.12与依赖声明dependencies: ["."]。启动后请记录输出的 API URL(默认形如http://localhost:8123),后续隧道命令与前端环境变量会用到它。
4. 为本地 Agent 打开隧道
npx copilotkit@latest dev --port 8123这条命令通过 CopilotKit CLI 把本地 8123 端口的 LangGraph Agent 暴露为隧道地址,供 CopilotKit Cloud 与前端连接(本地开发模式下由DEPLOYMENT=local与LOCAL_DEPLOYMENT_URL环境变量控制,见 package.json 的dev脚本与 route.ts 中的部署地址选择逻辑)。
5. 启动前端
cd frontend pnpm install # Create and populate .env cat << EOF > .env OPENAI_API_KEY=your_openai_key LANGSMITH_API_KEY=your_langsmith_key NEXT_PUBLIC_COPILOT_CLOUD_API_KEY=your_copilot_cloud_key EOF # Start the app pnpm run devpnpm run dev实际执行DEPLOYMENT=local next dev。若你的 Agent 部署在 LangGraph Cloud 而非本地,可改用remote-lgc-dev(即DEPLOYMENT=remote next dev),此时 route.ts 会改用DEPLOYMENT_URL指向远程部署。
深度解析:人工在环(Human-in-the-Loop)是如何实现的
ANA 最核心的交互体验是"大纲提案 → 用户审核/修改 → 按批准章节写作"。这条链路横跨 Agent 与前端两端:
Agent 端:outline_writer工具基于已收集的sources生成结构化的 JSON 提案(格式见PROPOSAL_FORMAT:每个section含title、description、approved标记),写入state["proposal"]后,主图路由到process_feedback_node;该节点调用interrupt(state.get("proposal", {}))将图执行挂起,等待前端返回。用户提交后,节点解析返回的reviewed_outline:只把approved == True的章节写入outline状态,同时追加一条 SystemMessage 告知 LLM"用户已审核提案,请据此处理反馈",再回到call_model_node继续执行——若用户提出了修改意见,模型会再次调用outline_writer重写提案。
前端端:page.tsx 通过useLangGraphInterrupt钩子监听中断事件,渲染StructureProposalViewer组件,用户确认/修改后调用resolve把{...proposal, approved}序列化回传给 Agent。
从源码可以推断,这套机制把"模型自动生成"与"人类决策"清晰地切分为两个阶段:模型负责起草与迭代,用户负责在关键节点把关,从而避免生成方向性错误的内容,这正是 Agent Native 应用区别于纯自动 Agent 的价值所在。
深度解析:四个工具的职责与状态流
Agent 端 tools 目录下的四个工具对应研究工作流的四个阶段:
1. tavily_search:多路并行搜索
tavily_search.py 采用多子查询设计:TavilySearchInput接收一组可独立回答的sub_queries,每个子查询还带topic(general或news)、days(新闻回溯天数)与domains(限定可信域名)参数。搜索时先向state["logs"]追加"🌐 Searching the web"日志并推送给前端,然后通过asyncio.gather并发执行全部子查询;结果按score > 0.45过滤,去重后合并进state["sources"]并随 ToolMessage 返回给模型。注意它会在查询词后拼接当前月份(%m-%Y),以保证优先拿到最新资料。
2. tavily_extract:深度抽取页面正文
tavily_extract.py 接收 URL 列表,调用 Tavily 的extract接口抓取raw_content,回填到state["sources"][url]["raw_content"],供后续大纲与章节写作使用,同时追加"🚀 Extracting additional content"日志。
3. outline_writer:生成可审核的章节提案
outline_writer.py 用json5解析模型输出,以PROPOSAL_FORMAT作为"单一事实来源"定义提案结构(sections下每个章节含title、description、approved),并强制校验PROPOSAL_KEYS完整性。它还会读取现有proposal:若存在,则把已批准章节与未批准章节分别拼接进提示词,指导模型"保留用户批准的章节、按 remarks 修改、未提及的未批准章节则省略",从而支持多轮迭代。生成的提案会附加timestamp、approved: False、remarks(用户反馈)字段。
4. section_writer:流式分节写作与局部修订
section_writer.py 是产出最终报告的工具,有两个关键设计:
- 流式中间状态:通过
copilotkit_customize_config注册emit_intermediate_state,把WriteSection工具的content与footer参数映射为section_stream.content.{idx}.{section_id}.{section_title}这样的动态 state key,前端据此实现章节内容的实时流式渲染(对应 useStreamingContent.ts 钩子); - 新增与修订双模式:若章节
idx尚不存在则走"全新写作"提示词(要求输出完整 Markdown,支持标题、列表、引用、代码块、表格、LaTeX 公式,以及[^1]脚注并强制将参考文献写入 footer 字段而非正文);若章节已存在则走"修订模式"提示词,只按用户最新请求定位并修改对应位置,其余内容保持不变。
前端如何呈现 Agent 的"思考过程"
ANA 前端把 Agent 的中间状态变成了可视化的研究画布,主要通过两个 React 钩子实现:
- useCoAgentStateRender(page.tsx):监听名为
agent的 Agent 状态,只要state.logs非空就渲染Progress进度组件,把"搜索中 / 思考大纲 / 写作章节"等日志实时展示给用户;页面每次发起新研究前会先清空 logs。 - useLangGraphInterrupt:如上文所述,负责渲染大纲审核弹层并把结果回传。
页面主体由Chat(左侧对话,宽度 30%~50% 可拖拽调节)与DocumentsView(右侧文档视图,展示已写章节、流式写作中的章节、选中章节详情)组成,SourcesModal则聚合展示所有来源链接。整套 UI 依赖 @copilotkit/react-core 的1.5.20版本(见 package.json),组件体系基于 shadcn/ui(components.json)与 Radix UI。
结语与进一步探索
open-research-ANA展示了一条可复制的 Agent Native 应用开发路径:用 LangGraph 编排可中断的工作流,用 Tavily 补足实时信息,用 CopilotKit 把中间状态变成可交互的界面。你可以参考同目录下的 start 骨架版本,从空白的 Agent 与前端逐步实现这套流程,体会每个环节的接入点;也可以深入 graph.py 与tools/目录,把大纲审核、分节写作、来源管理这些模式迁移到你自己的研究、写作或报告类产品中。
【免费下载链接】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),仅供参考