工作原理
了解 AggRoot 的核心工作机制,帮助你更高效地使用和调试。
Agent Loop(代理循环)
AggRoot 的核心是 Agent Loop —— 一个迭代式执行循环,不断交替调用 LLM 和工具,直到任务完成。
循环流程
用户输入 → LLM 推理 → 工具调用 → 工具结果 → LLM 推理 → ... → 最终回答
每一轮循环(iteration)包含以下步骤:
- 消息准备:将对话历史、系统提示词、附件信息组装成消息列表
- 上下文裁剪:如果消息超出 Token 限制,自动压缩旧消息
- LLM 调用:将消息发送给 AI 模型,流式接收响应
- 工具解析:从 LLM 响应中提取工具调用(function calling 或文本解析)
- 工具执行:执行工具调用,返回结果
- 循环判断:如果 LLM 仍在调用工具,继续下一轮;如果 LLM 给出了最终回答,循环结束
循环控制
{
"max_iterations": 100,
"on_error": "retry"
}
- max_iterations:最大循环次数,防止无限循环。
code之神默认 100 次,内容创作助手默认 50 次 - on_error:错误处理策略。
retry表示遇到错误会重试;abort表示遇到错误立即终止 - 连续 API 错误保护:连续 2 次 API 错误后自动终止循环,避免无限重试
Tips: 如果任务特别复杂需要更多迭代,可以在代理配置中调整
max_iterations。
上下文窗口
LLM 的上下文窗口是有限的。AggRoot 会智能管理 Token 消耗,确保对话始终在窗口内进行。
Token 预算分配
上下文窗口 = 系统提示词 + 对话历史 + 工具结果 + 预留输出空间
各部分的 Token 消耗:
- 系统提示词:包含代理身份、行为准则、工具列表等,通常占几千 Token
- 对话历史:用户消息和 LLM 回复
- 工具结果:工具执行后返回的内容
- 预留输出空间:为 LLM 的回复预留 Token
自动裁剪
当对话历史接近 Token 限制时,AggRoot 会自动裁剪旧消息:
- 消息链修复:移除孤立的 tool 消息和缺少响应的 tool_calls
- 占位符插入:为仍缺少响应的 tool_calls 插入占位结果
- 旧消息压缩:将早期的对话轮次压缩为摘要
Tips: 长对话中如果发现 AggRoot "忘记"了之前的内容,这通常是因为上下文裁剪。重要的上下文信息应该放在 AGGROOT.md 或项目记忆中。
工具调用
Function Calling
当 LLM 决定需要使用工具时,会通过 function calling 机制发起调用:
LLM 响应 → tool_calls: [{name: "Read", arguments: {file_path: "src/main.ts"}}]
→ 执行 Read 工具
→ 返回文件内容
→ 下一轮 LLM 推理
文本解析降级
对于不支持 function calling 的模型(如某些推理模型),AggRoot 会从 LLM 的文本输出中解析 <TOOL_CALL> 标签:
<TOOL_CALL>
{"name": "Read", "arguments": {"file_path": "src/main.ts"}}
</TOOL_CALL>
工具依赖编排
AggRoot 会自动分析工具之间的依赖关系:
- 无依赖的工具:并行执行(如同时读取多个文件)
- 有依赖的工具:串行执行(如先读取文件再编辑)
Tips: AggRoot 支持最多 10 个工具并行执行。多文件读取等操作会自动并行化,无需手动指定。
子代理(Sub-agent)
子代理是 AggRoot 的核心能力之一,允许主代理创建独立的子代理来执行子任务。
工作原理
主代理 LLM → 调用 SubagentExecutor → 创建子代理 → 子代理独立运行 → 返回结果
- ForkSubagentService 创建子代理,继承父代理的工具实例
- 子代理拥有独立的 AgentLoop,自主运行
- 子代理的输出缓存与父代理共享,避免重复读取
- 子代理完成后,将完整结果返回给主代理
关键特性
- 工具继承:子代理自动继承父代理的工具实例,无需重复注册
- 缓存共享:子代理的 OutputCache 与父代理共享,相同的 Read 操作直接走缓存
- 文件追踪:子代理读取的文件会被追踪,主代理可据此避免重复读取
- 独立输出:子代理的输出独立于主代理,不污染主对话流
子代理结果处理
如果子代理在所有轮次中只调用了工具但没有输出文字总结(常见于 explore agent),AggRoot 会自动注入一个总结提示,让子代理输出分析报告。
// 自动注入总结提示
'你现在必须输出你的分析总结。基于你刚才读取的所有文件和代码,给出完整的项目分析报告。'
Tips: 子代理的结果是精简摘要(文件列表 + 关键发现),完整代码内容已缓存。主代理可以直接使用摘要,需要查看细节时通过缓存读取。
系统提示词构建
系统提示词是 AggRoot 行为的核心驱动。它由多个部分按顺序组装:
系统提示词 = 代理身份(identity)
+ 核心规则(behavior_guidelines)
+ 个性设置(personality)
+ 说话风格(speaking_style)
+ 工具列表(tools)
+ 环境信息(platform, cwd, etc.)
+ 记忆上下文(memories)
+ AGGROOT.md 内容
+ 附件信息(skills, etc.)
关键组成部分
| 部分 | 来源 | 说明 |
|---|---|---|
| identity | 代理配置 | 代理的核心身份描述 |
| behavior_guidelines | 代理配置 | 行为准则列表 |
| personality | 代理配置 | 性格特征 |
| tools | 代理配置 + 运行时注册 | 可用工具列表及参数定义 |
| 记忆上下文 | ProjectMemoryStore | 跨会话的项目记忆 |
| AGGROOT.md | 项目根目录文件 | 项目级自定义规则 |
Tips: 如果你需要自定义 AggRoot 的行为,最直接的方式是编辑 AGGROOT.md 文件或创建自定义代理配置。
Hooks 机制
Hooks 是 Agent Loop 生命周期中的钩子函数,用于在特定时机执行自定义逻辑:
| Hook | 触发时机 | 用途 |
|---|---|---|
before_loop |
循环开始前 | 初始化上下文 |
after_loop |
循环结束后 | 经验提取、记忆保存 |
before_iteration |
每轮迭代前 | 注入上下文 |
after_iteration |
每轮迭代后 | 统计、日志 |
before_tool_call |
工具调用前 | 审批、拦截 |
after_tool_call |
工具调用后 | 日志、追踪 |
Fire-and-Forget 模式
after_loop hook 采用 Fire-and-Forget + Coalescing 模式执行:
- 不阻塞主循环:after_loop hook(如经验提取)在后台执行,不等待完成
- 合并策略:如果上一次提取还在执行,新的请求会被合并,完成后用最新数据重跑一次
- Drain 机制:进程退出前会等待进行中的 hook 完成(最多 60 秒)
这种设计确保了 UI 响应不会因为后台 LLM 调用而卡顿。
输出截断续写
当 LLM 的输出被截断(finish_reason: "length")时,AggRoot 会自动续写:
- 保存当前的 assistant 消息
- 注入续写提示:"你的上次输出被中断了。请继续完成你的回答或工具调用。"
- 下一轮 LLM 调用会从截断处继续
这确保了即使上下文窗口有限,长输出也不会丢失。