news 2026/9/25 5:00:27

VoltAgent 多智能体研究助手实战:用 Workflow Chain 与 MCP 构建类型安全的调研报告生成流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VoltAgent 多智能体研究助手实战:用 Workflow Chain 与 MCP 构建类型安全的调研报告生成流程
  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 多智能体
  • RAG
  • 工具调用
  • Agent 记忆

【免费下载链接】voltagent

AI Agent Engineering Platform built on an Open Source TypeScript AI Agent Framework

项目地址:https://gitcode.com/gh_mirrors/vo/voltagent
点击查看免费下载

本文以仓库中的官方配方文档 research-assistant.md 与配套示例 with-research-assistant 为主体,讲解如何用 VoltAgent 的 workflow 系统构建一个"研究助手"多智能体应用:一个 Assistant Agent 负责生成多样化搜索查询,一个 Writer Agent 负责基于 Exa(通过 MCP 接入)检索结果撰写带引用脚注的调研报告。读完本文,你将掌握createWorkflowChain的链式编排、Zod 输入/输出 Schema 的类型安全数据流、getStepData()跨步骤取数,以及通过MCPConfiguration将外部搜索工具注入 Agent 的完整工程方法,并可对照 packages/core 的源码理解底层实现。

一、研究助手整体架构

该示例构建的是一个两阶段多智能体研究流水线:

  • 接收一个研究主题(topic)作为输入;
  • 由 Assistant Agent 生成用于深度检索的多样化搜索查询;
  • 由 Writer Agent 综合研究素材,撰写一份带脚注引用([#])与 References 列表的专业报告;
  • 全程通过 Zod Schema 管理 Agent 间的数据流,保证类型安全;
  • 通过 MCP(Model Context Protocol)接入 Exa 搜索服务作为外部数据源。

对应的示例仓库结构为:

  • examples/with-research-assistant/src/index.ts:完整实现代码;
  • examples/with-research-assistant/package.json:依赖与启动脚本;
  • examples/with-research-assistant/.env.example:环境变量模板。

二、项目搭建与运行环境

2.1 创建项目

使用官方脚手架基于该示例初始化项目:

npm create voltagent-app@latest -- --example with-research-assistant cd my-agent-app

示例的 package.json 中,核心依赖包括:

  • @voltagent/core(^2.9.2):Agent、Workflow、MCP 编排能力;
  • @voltagent/server-hono(^2.0.14):HTTP 服务;
  • @voltagent/logger(^2.0.2):Pino 日志;
  • @voltagent/libsql(^2.1.2):本地存储;
  • zod(^3.25.76):运行时校验;
  • 开发脚本dev为tsx watch --env-file=.env ./src,即由 tsx 热加载并自动注入.env。

2.2 配置环境变量

需要准备两个 API Key:OpenAI 与 Exa(Exa 提供研究搜索 API,注册后在其控制台获取密钥)。创建.env文件:

OPENAI_API_KEY=your-openai-api-key EXA_API_KEY=your-exa-api-key

这与仓库中的 .env.example 保持一致。前置条件为 Node.js(推荐 v18+)与 npm/pnpm。

2.3 启动开发服务器

npm run dev

服务器成功启动后,终端将输出:

════════════════════════════════════════════ VOLTAGENT SERVER STARTED SUCCESSFULLY ════════════════════════════════════════════ ✓ HTTP Server: http://localhost:3141 VoltOps Platform: https://console.voltagent.dev ════════════════════════════════════════════ [VoltAgent] All packages are up to date

随后 VoltOps 平台会在浏览器中自动打开,用于与 Agent/Workflow 交互、查看执行轨迹与调试。

三、完整实现代码

下面是配方文档给出的完整实现(后续将逐步拆解):

import { openai } from "@ai-sdk/openai"; import { Agent, MCPConfiguration, VoltAgent, createWorkflowChain } from "@voltagent/core"; import { createPinoLogger } from "@voltagent/logger"; import { z } from "zod"; (async () => { const mcpConfig = new MCPConfiguration({ servers: { exa: { type: "stdio", command: "npx", args: ["-y", "mcp-remote", `https://mcp.exa.ai/mcp?exaApiKey=${process.env.EXA_API_KEY}`], }, }, }); const assistantAgent = new Agent({ id: "assistant", name: "Assistant", instructions: "The user will ask you to help generate some search queries. " + "Respond with only the suggested queries in plain text " + "with no extra formatting, each on its own line. Use exa tools.", model: openai("gpt-4o-mini"), tools: await mcpConfig.getTools(), }); const writerAgent = new Agent({ id: "writer", name: "Writer", instructions: "Write a report according to the user's instructions.", model: openai("gpt-4o"), tools: await mcpConfig.getTools(), markdown: true, maxSteps: 50, }); // Define the workflow's shape: its inputs and final output const workflow = createWorkflowChain({ id: "research-assistant", name: "Research Assistant Workflow", // A detailed description for VoltOps or team clarity purpose: "A simple workflow to assist with research on a given topic.", input: z.object({ topic: z.string() }), result: z.object({ text: z.string() }), }) .andThen({ id: "research", execute: async ({ data }) => { const { topic } = data; const result = await assistantAgent.generateText( `I'm writing a research report on ${topic} and need help coming up with diverse search queries. Please generate a list of 3 search queries that would be useful for writing a research report on ${topic}. These queries can be in various formats, from simple keywords to more complex phrases. Do not add any formatting or numbering to the queries.`, { provider: { temperature: 1 } } ); return { text: result.text }; }, }) .andThen({ id: "writing", execute: async ({ data, getStepData }) => { const { text } = data; const stepData = getStepData("research"); const result = await writerAgent.generateText( `Input Data: ${text} Write a two paragraph research report about ${stepData?.input} based on the provided information. Include as many sources as possible. Provide citations in the text using footnote notation ([#]). First provide the report, followed by a single "References" section that lists all the URLs used, in the format [#] <url>.` ); return { text: result.text }; }, }); // Create logger const logger = createPinoLogger({ name: "with-mcp", level: "info", }); // Register with VoltOps new VoltAgent({ agents: { assistant: assistantAgent, writer: writerAgent, }, workflows: { assistant: workflow, }, logger, }); })();

版本说明:当前仓库的示例实现 src/index.ts 与上述代码高度一致,有两处细节差异值得注意:其一,模型以字符串形式书写(model: "openai/gpt-4o-mini"),与@ai-sdk/openai的openai(...)写法等价;其二,当前版本在new VoltAgent({...})中显式传入server: honoServer()(来自@voltagent/server-hono,见 index.ts 第 91 行)。按当前仓库代码为准即可。

四、分步解析

4.1 配置 MCP 接入 Exa 搜索

const mcpConfig = new MCPConfiguration({ servers: { exa: { type: "stdio", command: "npx", args: ["-y", "mcp-remote", `https://mcp.exa.ai/mcp?exaApiKey=${process.env.EXA_API_KEY}`], }, }, });

这段配置的作用:

  • 创建一个 MCP 配置,连接 Exa 的研究搜索 API;
  • 使用stdio类型,即通过npx -y mcp-remote拉起一个本地子进程,再以标准输入/输出与远程 Exa MCP 服务通信;
  • Exa API Key 从环境变量EXA_API_KEY注入 URL 查询参数,避免硬编码;
  • 调用await mcpConfig.getTools()后,Exa 的搜索能力即被转换为 VoltAgent 工具列表,供 Agent 使用。

从源码看,MCPConfiguration定义在 packages/core/src/mcp/registry/index.ts,其getTools(authContext?)方法(见该文件 第 101 行)负责从已注册的 MCP Server 拉取工具并返回Tool<any>[],这正是Agent的tools字段所接受的类型。

4.2 创建 Assistant(研究助手)Agent

const assistantAgent = new Agent({ id: "assistant", name: "Assistant", instructions: "The user will ask you to help generate some search queries. " + "Respond with only the suggested queries in plain text " + "with no extra formatting, each on its own line. Use exa tools.", model: openai("gpt-4o-mini"), tools: await mcpConfig.getTools(), });

关键配置项:

  • id:Agent 的唯一标识,也是后续在VoltAgent中注册与观测时的键;
  • instructions:约束输出格式——纯文本、每条查询独占一行、无编号与多余格式,并提示"使用 exa 工具",降低模型"自由发挥"的概率;
  • model:选用gpt-4o-mini承担查询生成这类轻量任务,控制成本;
  • tools:继承 MCP 配置的全部工具(Exa 搜索能力)。

4.3 创建 Writer(写作)Agent

const writerAgent = new Agent({ id: "writer", name: "Writer", instructions: "Write a report according to the user's instructions.", model: openai("gpt-4o"), tools: await mcpConfig.getTools(), markdown: true, maxSteps: 50, });

设计取舍:

  • 使用更强的gpt-4o模型保证成文质量——写作是对质量敏感的任务,与查询生成(对成本敏感)分而治之;
  • markdown: true:开启 Markdown 输出格式化,报告天然具备标题、列表等结构;
  • maxSteps: 50:允许 Agent 在 agentic 循环中执行较多轮工具调用与推理(例如多轮检索、补漏),支撑复杂的多步研究写作;
  • 同样挂载 MCP 工具,写作阶段若发现素材不足仍可主动追加检索。

4.4 定义 Workflow 结构与 Schema

const workflow = createWorkflowChain({ id: "research-assistant", name: "Research Assistant Workflow", purpose: "A simple workflow to assist with research on a given topic.", input: z.object({ topic: z.string() }), result: z.object({ text: z.string() }), });

Schema 定义:

  • input:工作流输入为包含topic字符串的对象;
  • result:最终输出为包含text字符串的对象;
  • 使用 Zod 做运行时类型校验,同时推导 TypeScript 类型,IDE 中有完整补全。

purpose字段面向 VoltOps 平台与团队成员提供可读的用途说明,便于在控制台识别工作流。

从源码看,createWorkflowChain的导出位于 packages/core/src/workflow/chain.ts 第 1089 行,它接受INPUT_SCHEMA、RESULT_SCHEMA等泛型约束,返回WorkflowChain实例;链上每一步都会把数据流类型从"当前步输出"推进到"下一步输入",这正是整条链保持端到端类型推断的原因。

4.5 第一步:生成搜索查询(research)

.andThen({ id: "research", execute: async ({ data }) => { const { topic } = data; const result = await assistantAgent.generateText( `I'm writing a research report on ${topic} and need help coming up with diverse search queries. Please generate a list of 3 search queries that would be useful for writing a research report on ${topic}. These queries can be in various formats, from simple keywords to more complex phrases. Do not add any formatting or numbering to the queries.`, { provider: { temperature: 1 } } ); return { text: result.text }; }, })

工作流程:

  1. data即工作流输入,解构出topic;
  2. 调用 Assistant Agent 生成 3 条多样化搜索查询,temperature设为 1 以获得更高多样性;
  3. 以{ text: result.text }返回,该返回值自动成为下一步的data。

4.6 第二步:撰写报告(writing)

.andThen({ id: "writing", execute: async ({ data, getStepData }) => { const { text } = data; const stepData = getStepData("research"); const result = await writerAgent.generateText( `Input Data: ${text} Write a two paragraph research report about ${stepData?.input} based on the provided information. Include as many sources as possible. Provide citations in the text using footnote notation ([#]). First provide the report, followed by a single "References" section that lists all the URLs used, in the format [#] <url>.` ); return { text: result.text }; }, })

进阶能力点:

  • data:包含上一步(research)的输出,即搜索查询文本;
  • getStepData("research"):按步骤 id 访问任意历史步骤的数据。注意此处访问的是stepData?.input——该步骤的输入侧数据(包含原始topic),而非仅输出。这样写作提示词中可以同时拿到"查询素材(text)+ 原始主题(topic)";
  • 提示词强制要求脚注引用([#])与文末 References 列表([#] <url>格式),保证报告可溯源;
  • 返回最终报告文本,类型由工作流的resultSchema({ text: z.string() })约束。

从源码看,andThen的执行上下文在 chain.ts 第 406 行 的函数签名中定义,除data与getStepData外,还暴露state、workflowState、setWorkflowState、suspend/resumeData、retries、logger、writer等成员——也就是说同一套链式 API 还支持工作流状态持久化、暂停/恢复与重试等更复杂的能力,本示例只用了其中最基础的部分。

4.7 注册到 VoltAgent(接入 VoltOps)

const logger = createPinoLogger({ name: "with-mcp", level: "info", }); new VoltAgent({ agents: { assistant: assistantAgent, writer: writerAgent, }, workflows: { assistant: workflow, }, logger, });

注册后的收益:

  • Agent 与 Workflow 在 VoltOps Console 中可见、可交互;
  • 每次运行生成执行轨迹(trace),支持实时监控与调试;
  • Workflow 可通过 REST API 触发。

五、运行工作流与交互方式

一切就绪后,可在 VoltOps Console 中直接操作名为Research Assistant Workflow的工作流,输入研究主题。推荐尝试的提示(来自配方文档):

  • "Research the latest developments in quantum computing"
  • "Analyze the impact of AI on healthcare in 2024"
  • "Investigate sustainable energy storage solutions"

README 中还补充了一个:"Future of remote work technologies"。

执行时工作流依次完成:生成相关搜索查询 → 基于查询检索信息(经 MCP/Exa 工具)→ 综合成文,产出带引用与 References 的完整报告。

六、核心概念小结

6.1 Workflow 链式编排(Chaining)

.andThen()构建顺序执行的链:每一步的输出成为下一步的输入。从 chain.ts 的签名可以看到,每个andThen返回一条新的WorkflowChain(NEW_DATA泛型替换当前数据类型),从而在编译期锁定数据流形状,同时保留运行期的 Zod 校验。

6.2 Zod 类型安全

流经工作流的每份数据都会对照 Zod Schema 校验:错误在运行早期被捕获,且 TypeScript 获得完整的类型推导与补全体验。input/result/ 各步骤输入输出三者共同构成一条可验证的数据契约。

6.3 步骤上下文访问

getStepData(stepId)允许访问任意前序步骤(而非仅直接上一步)的数据,包括该步骤的输入与输出,使"第 N 步引用第 1 步的原始主题"这类跨步依赖可以用干净的代码表达。

6.4 多 Agent 协作的收益

按任务拆分 Agent(研究 vs. 写作)之后:可以为每个任务选择最合适的模型(成本/质量权衡,本例即gpt-4o-mini+gpt-4o);可以为每个角色提供专门化的 instructions;工作流各部分可独立扩展与替换。

七、下一步扩展方向

配方文档给出的演进路径(均对应框架已有能力,可结合 chain.ts 中的 API 签名进一步确认):

  1. 增强 Agent:加入更复杂的 instructions 或额外工具;
  2. 扩展工作流:追加事实核查(fact-checking)、排版、翻译等步骤;
  3. 条件分支:使用.andWhen()实现条件路由;
  4. 并行处理:使用.andAll()同时执行多条研究查询;
  5. 错误处理:利用步骤配置中的retries(chain.ts 第 422 行 可见retries?: number字段)实现重试与回退策略。

八、参考路径索引

  • 配方文档:website/recipes/research-assistant.md
  • 示例源码:examples/with-research-assistant/src/index.ts
  • 示例说明与运行步骤:examples/with-research-assistant/README.md
  • 依赖与脚本:examples/with-research-assistant/package.json
  • 环境变量模板:examples/with-research-assistant/.env.example
  • 工作流链实现:packages/core/src/workflow/chain.ts
  • MCP 配置与工具拉取:packages/core/src/mcp/registry/index.ts
  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 多智能体
  • RAG
  • 工具调用
  • Agent 记忆

【免费下载链接】voltagent

AI Agent Engineering Platform built on an Open Source TypeScript AI Agent Framework

项目地址:https://gitcode.com/gh_mirrors/vo/voltagent
点击查看免费下载

相关推荐

上一篇:LTX-Video技术解析:从文本到电影级视频的300%质量提升指南
下一篇:CANN/driver设备芯片信息API

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 4:59:12

Atlas 300V 24G推理加速卡部署YOLO:从ONNX到OM的完整指南

最近后台高频出现两个关于 atlas 的问题&#xff0c;一个是"atlas 部署 yolo"&#xff0c;另一个是"atlas 300v 24g 是运算加速卡吗"。两个问题放到一起看&#xff0c;其实指向同一件事&#xff1a;很多人拿到一张 Atlas 300V 24G&#xff0c;想用它把 YOL…

作者头像 李华
网站建设 2026/9/25 4:55:57

小喵V2电机驱动快速入门:简单积木实现4路电机调速与正反转控制

小喵V2电机驱动快速入门&#xff1a;简单积木实现4路电机调速与正反转控制 【免费下载链接】miaow-v2 源师兄扩展项目: 小喵V2 | 由源师兄组织创建 项目地址: https://gitcode.com/yuanshixiong/miaow-v2 小喵V2是源师兄推出的 KittenBot 开源扩展项目&#xff0c;通过配…

作者头像 李华
网站建设 2026/9/25 4:55:31

网盘搜索引擎原理与实战:找资源不再靠运气

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:55:30

Innovus分段长时钟树:5种特殊sink type选型与实战技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:54:21

AS2258固态硬盘量产开卡全攻略:从掉固件到修复

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:54:02

LabVIEW例程全集真相:版本匹配、依赖修复与串口改造实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华