- 人工智能
- AI Agent
- Agent 框架
- 后端
- 多智能体
- RAG
- 工具调用
- Agent 记忆
【免费下载链接】voltagent
AI Agent Engineering Platform built on an Open Source TypeScript AI Agent Framework
本文以仓库中的官方配方文档 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 }; }, })工作流程:
data即工作流输入,解构出topic;- 调用 Assistant Agent 生成 3 条多样化搜索查询,
temperature设为 1 以获得更高多样性; - 以
{ 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 签名进一步确认):
- 增强 Agent:加入更复杂的 instructions 或额外工具;
- 扩展工作流:追加事实核查(fact-checking)、排版、翻译等步骤;
- 条件分支:使用
.andWhen()实现条件路由; - 并行处理:使用
.andAll()同时执行多条研究查询; - 错误处理:利用步骤配置中的
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
相关推荐
使用 VoltAgent 构建多智能体研究助手:Workflow Chain 与 Exa MCP 集成实战
使用 VoltAgent 构建多智能体研究助手:Workflow Chain 与 Exa MCP 集成实战 VoltAgent 是一个开源的 TypeScrip
人工智能AI AgentAgent 框架后端多智能体RAG工具调用Agent 记忆Agent 工作流AI 评测MCP 服务MCP Clients语音AI Agent 框架调研报告:hello-agents 第十章多智能体 MCP 协作生成实战
AI Agent 框架调研报告:hello agents 第十章多智能体 MCP 协作生成实战 本篇以 hello agents 仓库第十章产出的《AI Age
教程人工智能大模型AI AgentDeep Search 全栈研究 Agent 实战:基于 ADK 构建带人工审核与内联引用的多智能体研究流程
Deep Search 全栈研究 Agent 实战:基于 ADK 构建带人工审核与内联引用的多智能体研究流程 导读 本文以仓库 core/python/deep
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考