AggRoot
文档目录

工作原理

了解 AggRoot 的核心工作机制,帮助你更高效地使用和调试。

Agent Loop(代理循环)

AggRoot 的核心是 Agent Loop —— 一个迭代式执行循环,不断交替调用 LLM 和工具,直到任务完成。

循环流程

用户输入 → LLM 推理 → 工具调用 → 工具结果 → LLM 推理 → ... → 最终回答

每一轮循环(iteration)包含以下步骤:

  1. 消息准备:将对话历史、系统提示词、附件信息组装成消息列表
  2. 上下文裁剪:如果消息超出 Token 限制,自动压缩旧消息
  3. LLM 调用:将消息发送给 AI 模型,流式接收响应
  4. 工具解析:从 LLM 响应中提取工具调用(function calling 或文本解析)
  5. 工具执行:执行工具调用,返回结果
  6. 循环判断:如果 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 会自动裁剪旧消息:

  1. 消息链修复:移除孤立的 tool 消息和缺少响应的 tool_calls
  2. 占位符插入:为仍缺少响应的 tool_calls 插入占位结果
  3. 旧消息压缩:将早期的对话轮次压缩为摘要

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 → 创建子代理 → 子代理独立运行 → 返回结果
  1. ForkSubagentService 创建子代理,继承父代理的工具实例
  2. 子代理拥有独立的 AgentLoop,自主运行
  3. 子代理的输出缓存与父代理共享,避免重复读取
  4. 子代理完成后,将完整结果返回给主代理

关键特性

  • 工具继承:子代理自动继承父代理的工具实例,无需重复注册
  • 缓存共享:子代理的 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 会自动续写:

  1. 保存当前的 assistant 消息
  2. 注入续写提示:"你的上次输出被中断了。请继续完成你的回答或工具调用。"
  3. 下一轮 LLM 调用会从截断处继续

这确保了即使上下文窗口有限,长输出也不会丢失。