Agent 运行时:一次生成的完整生命周期
30 秒导读: VoltAgent 里,你
new Agent({...})得到一个对象,然后调它的generateText("...")。这一章讲的就是从你按下这个调用,到拿回结果的中间发生的一切:框架怎么把系统提示、历史记忆、你的输入拼成一串消息,交给底层模型,再在"模型说话 → 调工具 → 再说话"的循环里推进,最后把每一步落库、收尾返回。这是全库的主干,后面每一章(记忆、工具、护栏、子代理)都是往这条主干上挂的分支。
1. 这是什么(零基础也能懂)
-
一句话定义:
Agent是 VoltAgent 的中枢类——你给它模型、指令、工具、记忆,它负责跑完一次"和模型对话并可能调工具"的完整流程,把杂事(拼提示、存历史、追踪、重试)都替你办了。 -
它替你解决什么: 直接用底层 AI SDK,你得自己拼 system prompt、自己塞历史消息、自己写工具循环、自己存对话、自己做可观测。
Agent把这些固化成一条标准流水线,你只管配置。 -
一个最小例子: 感受一下调用有多轻。
// 示意,非源码:一次最普通的生成
const agent = new Agent({
name: "assistant",
instructions: "你是一个乐于助人的助手。", // 会变成 system 消息
model: openai("gpt-4o-mini"),
tools: [weatherTool], // 可选:给模型装"手脚"
});
const result = await agent.generateText("北京今天天气怎么样?");
console.log(result.text);
- 一句话直觉/类比: 把
Agent想成一个餐厅后厨的传菜流程。你(顾客)点一句话,后厨要先备料(拼消息)、下锅(调模型)、按菜谱可能多道工序(工具循环)、记账(落库),最后上菜(返回)。这一章讲的就是这条传菜线,不讲某道菜(记忆、工具)具体怎么做。
本节到此不碰代码细节。记住一句话就够:Agent = 一次生成的流水线管家。
2. 顶层全景(它大概怎么转)
2.1 四个对外入口
Agent 对外只有四个"发起一次生成"的方法,内部走的是同一条主干,只是最后交给底层 SDK 的动作不同。
| 入口 | 定义位置 | 干什么 | 返回 |
|---|---|---|---|
generateText | agent.ts:1198 | 一次性生成文本(可带工具循环) | 完整结果对象(.text) |
streamText | agent.ts:1729 | 流式生成文本,边生成边吐 | 可迭代的流(.textStream / .fullStream) |
generateObject | agent.ts:2848 | 生成符合 schema 的结构化对象 | .object |
streamObject | agent.ts:3188 | 流式结构化对象(已废弃,建议改用带 output 的 streamText) | 对象流 |
四者开头一模一样:都先 createOperationContext(agent.ts:1206、1734、2857、3197),再进同一套"中间件 → 护栏 → prepareExecution → 调模型"的骨架。本章以 generateText 为主线讲透,其余三个只点出差异。
2.2 一次 generateText 的骨架图
怎么读这张图: 从上到下是时间顺序。左侧竖线是贯穿全程的
OperationContext(下一节讲)。中间的"工具循环"是可能重复多次的部分,由stopWhen决定何时停。
你调用 agent.generateText("...")
│
▼
┌───────────────────────────┐
│ 建"随身背包" OperationContext │ createOperationContext (agent.ts:4119)
│ · operationId / logger │ ← userId、conversationId、abort、trace
│ · context / systemContext │ 都塞进这个背包,后面到处传它
└───────────────────────────┘
│
▼
┌───────────────┐
│ 输入中间件+输入护栏 │ runInputMiddlewares → executeInputGuardrails
└───────────────┘ (改写/拦截你的输入)
│
▼
┌────────────────────────────────┐
│ prepareExecution (agent.ts:3760) │ ← 组装"发给模型的一切"
│ 1. prepareMessages 拼消息 │
│ 2. getSystemMessage 拼系统提示 │
│ 3. convertToModelMessages │
│ 4. prepareTools 准备工具 │
│ 5. maxSteps 算步数上限 │
└────────────────────────────────┘
│ messages / tools / maxSteps
▼
┌────────────────────────────────┐
│ 调底层 SDK generateText │ agent.ts:1384
│ ┌───── 工具循环(≤ maxSteps)──┐│
│ │ 模型说话 → 想调工具? ─是→ 执行 ││
│ │ ↑ │ ││ 每步触发
│ │ └── stopWhen 未满足 ──┘ ││ onStepFinish
│ └──────────────────────────────┘│ (createStepHandler)
└────────────────────────────────┘
│ result.text / steps
▼
┌───────────────────────────────┐
│ 输出中间件 → 落库 → 输出护栏 → 收尾 │ runOutputMiddlewares (1469)
│ · recordStepResults 存每步 │ executeOutputGuardrails (1489)
│ · onEnd 钩子 / 结束 trace span │
└───────────────────────────────┘
│
▼
返回 result
2.3 主要部件一句话职责
| 部件 | 干什么 | 在哪 |
|---|---|---|
Agent 构造 | 把 AgentOptions 存成实例字段,建 memoryManager / toolManager / subAgentManager | agent.ts:1068 |
createOperationContext | 为这一次调用造一个隔离的"背包" | agent.ts:4119 |
prepareExecution | 把消息、工具、步数上限一次性备齐 | agent.ts:3760 |
prepareMessages | 拉记忆 + 拼系统消息 + 拼输入,产出 UIMessage[] | agent.ts:4969 |
getSystemMessage | 组装系统提示(指令 + 检索 + 工作记忆 + 工具包说明) | agent.ts:5299 |
createStepHandler | 每个模型步骤结束时的回调:记步、增量落库、bail 检测 | agent.ts:7390 |
OperationContext | 一次调用的全部运行时状态 | 类型见 types.ts:1316 |