Agent 循环
单次轮次如何从用户消息流转到最终答案,以及维持整体运作的状态记录机制
Agent 循环是轮次编排器,职责单一:接收用户消息,运行至最终答案,并持久化沿途发生的一切。Minara 中的每项功能,价格查询、交易、深度研究报告,都经由同一个循环处理。它以 AgentRuntime 类的形式,位于 apps/agent/src/agent/runtime.ts。
为何选用 Vercel AI SDK,而非自行实现循环? 一次轮次是有界的短序列:构建上下文、调用模型、执行模型请求的工具、反馈结果、重复直到停止。AI SDK 的
streamText已经精确建模了这一多步工具循环,并提供跨 Anthropic、OpenAI、xAI 和 OpenRouter 的统一 provider 接口。Minara 将策略逻辑(哪些工具可用、哪些闸门触发、哪些内容被缓存、上下文如何压缩)保留在streamText调用的各模块中,由 SDK 负责机械性的"调用工具 → 观察结果"迭代。
实际使用场景:REPL 和 HTTP 网关 中的每次对话轮次都驱动此循环。首次交易 演练即是一次完整的端到端轮次。
轮次流水线
AgentRuntime.run() 是一个轮次形状的流水线,按顺序执行以下阶段,并输出单一的 AsyncGenerator<AgentEvent>。两个表层(网关 SSE 和 REPL)均消费这同一个事件流,而非分散的回调。
1. 轮次前准备
调用模型前,运行时先执行偏好演化和输入扫描,再通过 buildSystemPromptBlocks() 组装系统提示词。提示词由声明式块构建,而非字符串拼接;可缓存的前缀(身份标识与技能目录)在各轮次之间保持字节级一致,从而命中 Anthropic 的提示词缓存。动态尾部(活跃技能、信号上下文、待确认项)每轮重新构建。块顺序是实质性约束:任何改变缓存前缀的操作都会将一次热调用变为缓存未命中。工作区 markdown(SOUL.md、MEMORY.md、HEARTBEAT.md)位于动态块首位,确保操作员维护的基准事实优先于任何推断层(参见工作区)。
活跃技能的决定由路由器优先完成:它按关键词、生命周期阶段、资产类别和协同激活对每项技能打分,活跃集合决定模型被允许查看哪些工具集。
2. 压缩阶梯
对话较长时,运行时在消耗模型调用前,先执行压缩阶梯(边界切片、折叠、自动压缩、Top-N 重注入),以适配上下文窗口。压缩策略优先采用零 LLM 剪枝,再考虑付费摘要。完整约定参见 docs-src/context-management.md。
3. streamText
运行时以活跃技能允许的工具(与本轮允许工具集取交集)调用 streamText。SDK 在内部驱动"调用工具 → 观察结果"循环,并在 stopWhen: stepCountIs(maxSteps) 时停止。每一步:
prepareStep在调用前裁剪累积 token 预算。- 模型输出文本和工具调用;工具调用通过注册表分发(见下节)。
onStepFinish记录用量,并向流中发送步骤事件。
整个 streamText 调用由溢出恢复守卫包裹:若某步超出上下文窗口,则裁剪后重试。
4. 工具分发与闸门
模型发出的每次工具调用通过工具注册表分发,并受两道闸门约束:
- 权限等级。 每个工具携带一个
PermissionTier(READ_ONLY→CONFIRM_ONCE→ALWAYS_CONFIRM→MANUAL_ONLY),该等级强制执行,不可绕过。 - 资金安全栈。 涉及资金的处理程序通过共享的预览-确认辅助函数把关;交易路径还额外通过钩子流水线(token 安全检查、敞口、滑点、风险官上限、审计日志)。被拦截的调用会返回结构化错误,模型将其视为正常工具结果;审计日志对其单独记录。完整的 6 阶段安全栈文档参见资金安全。
轮次状态(来源、运行中的已用工具集、风险上限)通过 ToolCallContext 传递,确保每次工具调用(包括子 Agent 调用和技能执行的序列)读取相同的每轮状态。
5. 轮次结束
streamText 停止后,运行时发出 post_turn 事件,扇出至决策捕获、对话轮次记录、工作区状态更新、仪表盘缓存失效和可观测性上报。这条记录是可观测性工具的读取来源,也是学习系统反思的数据基础。
轮次状态记录
两条不变量确保循环可安全扩展:
- 每轮次一个上下文。 风险上限、信号上下文和已用工具集均存于
ToolCallContext,从不存于模块级状态。并发轮次(REPL 和网关可同时运行)之间的状态记录互不干扰。 - 缓存前缀不可变。 轮次中途激活技能会追加一条说明,而非重建系统提示词,因为重建前缀会破坏提示词缓存。对加载或压缩逻辑的任何修改,都不得触及缓存前缀。
轮次外的确定性执行
并非所有工具调用都经过 streamText。计划和事件驱动的工作流直接通过注册表调用已注册的工具处理程序,无需模型往返。tool_call 工作流步骤运行与循环相同的处理程序,受同等权限等级和资金安全闸门约束,但无需消耗模型调用来做决策。
由此产生两个结论:
- 常规自动化(提醒、简报、监控)成本低廉。仅在显式包含模型节点的步骤时才消耗 token。
- 执行语义取决于工具实现,而非模型对其 schema 的理解。
循环和工作流引擎是同一工具注册表的两个入口,因此无论在何处运行,涉及资金的步骤仍须经过两步确认。