4 结果
对 13 个开源编码智能体脚手架的分析揭示了一套由三个层次组织的分类法:控制架构(智能体如何决定下一步做什么)、工具与环境接口(智能体如何与代码和执行环境交互)、以及资源管理(智能体如何管理上下文、状态和模型)。在每个层次内,架构选择沿连续梯度分布,而非落入离散类别。本节将每个维度呈现为一系列观察到的策略范围,将智能体放置在相应位置上并附以源代码证据,同时识别跨维度的共性模式。Figure 1 提供了完整分类法结构的概览。

Figure 1:分类法概览:12 个维度组织为三个架构层次。每个维度是一个连续频谱,其端点来自 13 个智能体语料库的观察结果。智能体沿这些频谱分布,而非落入离散类别(Section 5.1)。
4.1 第一层:控制架构
控制层决定了智能体如何编排其行动。三个维度捕捉了关键差异:(1) 控制循环的拓扑结构,(2) 驱动循环的主体,(3) 控制循环在代码中的实现方式。
4.1.1 控制循环策略
控制循环的范围从无反馈的固定流水线到具有反向传播的树结构搜索(Table 2),且这些循环类型并非互斥;智能体经常将一种循环类型嵌套在另一种内部。这种可组合性意味着表中低估了实际的控制复杂度:被归类为"分阶段循环"的智能体可能在每个阶段内包含一个完整的 ReAct 循环。例如,AutoCodeRover 在其流水线的每个阶段内运行多轮 LLM 交互(agent_search.py:88--163):一个生成器函数将工具选择结果 yield 给调用方,调用方执行这些操作并将结果返回,这使得它在不同抽象层次上既是分阶段智能体又是迭代式智能体。Moatless Tools 在可组合性方面更进一步,将内部智能体与外部控制流完全解耦:其 ActionAgent(一个单步执行器:一次 LLM 调用生成动作,然后执行)既可以由 AgenticLoop(反复调用它以产生 ReAct 行为)驱动,也可以由 SearchTree 驱动进行基于蒙特卡洛树搜索 (Monte Carlo Tree Search, MCTS) 的探索,且无需修改智能体代码本身。这种分离意味着顺序探索与树搜索探索之间的选择是一个配置决策,而非架构决策。
Table 2:控制循环策略。智能体按探索策略的灵活性从低到高排列。
| 位置 | 智能体 | 机制 |
|---|---|---|
| 固定流水线 | Agentless | 由 10 个独立脚本组成的流水线,通过磁盘上的 JSONL 文件连接。阶段之间无反馈循环。 |
| 用户驱动循环 | Aider | 外部循环由用户发起(每个编辑周期需要用户输入)。内部的生成-测试-修复循环在最多 max_reflections 次迭代内自主运行。 |
| 顺序 ReAct 循环 | SWE-agent, OpenHands, Codex CLI, Gemini CLI, mini-swe-agent, Cline, OpenCode | 标准的思考-工具-观察循环。LLM 选择下一个动作;循环在完成信号或预算耗尽时终止。 |
| 分阶段循环 | AutoCodeRover, Prometheus | [^30] |
| 深度优先树搜索 | DARS-Agent | ReAct 步骤构成搜索树中的节点。在分支点,环境被重置并从根节点重放;一个 LLM 评论者在采样的备选方案中进行选择。 |
| 完整 MCTS | Moatless Tools | 选择-扩展-模拟-反向传播,具有奖励值(-100 到 +100)和访问计数。可插拔的选择器接口;一个判别器从已完成的轨迹中选择最优者。 |
树搜索策略。
三个智能体跨越了从扁平采样到启发式搜索的梯度,展示了探索可能解空间的方法如何逐步精细化。
在最简单的一端,Agentless 使用独立采样:在定位到相关代码后,它提示 LLM 独立生成候选补丁(默认配置生成 20 个;原始论文使用 4 个定位样本 × 每个 10 个补丁,共计 ≈$ 40 个)。每次生成看到相同的上下文,但可能产生不同的修复方案。然后通过对这些候选方案进行多数投票来选择最终补丁。不存在树结构,候选方案之间也没有交互;每个补丁都是独立生成的。
DARS-Agent 在其主执行循环中引入了树结构搜索。与 Agentless 将定位和修复分为不同阶段不同,DARS-Agent 没有阶段分离:搜索命令与编辑和执行命令在整个过程中并行可用。该智能体构建一棵搜索树,其中每个节点代表一个动作(如编辑文件、创建文件或提交补丁)。在每个分支点,智能体生成多个备选动作,然后使用一个 LLM 评论者在其中进行选择:评论者接收这些备选方案作为提示,并以 <best_action_index> 标签响应以指示其选择。然而,与经典树搜索不同,DARS-Agent 没有数值奖励信号,也没有将结果反向传播到较早节点;评论者做出贪心的局部决策,不考虑较早的选择如何影响了后续结果。
Moatless Tools 实现了完整的蒙特卡洛树搜索 (MCTS) [^11],这与 AlphaGo [^49] 等博弈系统使用的算法相同。搜索树中的每个节点接收数值奖励值(范围从 -100 到 +100),算法维护访问计数以平衡对未尝试路径的探索与对有前景路径的利用。在扩展节点后,奖励沿树反向传播以更新祖先节点,使搜索能够从后续结果中学习,并将精力重新导向更有前景的分支(search_tree.py:326--345)。
从扁平采样到完整 MCTS 的演进揭示了一个设计权衡:更丰富的搜索策略需要一种跨分支管理执行状态的机制。Moatless Tools 通过影子模式执行来解决这一问题,即在内存中跟踪文件修改而非写入磁盘;这使得搜索可以在任意点分支,而无需昂贵的文件系统操作。DARS-Agent 采用了另一种方法:在每个分支点,它将 Docker 环境重置为干净状态,并从树的根节点重放所有动作以到达目标分支,这种方法是正确的但在较深的搜索深度下代价高昂。
其余 CLI 智能体(Cline、Codex CLI、Gemini CLI、OpenCode)均实现了标准的顺序 ReAct 循环,不含分阶段结构或树搜索,与 Table 2 中的其他 ReAct 智能体处于同一中间区段。Aider 是一个特例:虽然它出现在该区段中,但其外部循环是用户驱动而非自主式的(Section 4.1.2),LLM 生成文本格式的编辑而非选择工具。然而,Aider 的内部循环(base_coder.py:932)是自主的:在 LLM 生成编辑后,脚手架运行代码检查和测试,如果任一失败,则将错误输出重新提示给 LLM,最多进行 max_reflections 次迭代。这个生成-测试-修复循环是 Aider 中唯一不需要用户输入即可进行多轮 LLM 交互的部分。
4.1.2 循环驱动者
与循环拓扑正交的问题是什么驱动循环(Table 3),这一维度可以说是最根本的架构区分。Aider 位于一个极端:LLM 从不运行 grep,从不打开未被提供的文件,也从不决定"我应该看看模块 Y"。所有导航责任都落在用户身上,PageRank 加权的仓库地图提供被动上下文。在另一个极端,13 个智能体中有 9 个赋予 LLM 对工具选择的完全自主权,Prometheus 占据一个混合位置——LLM 在每个图节点内驱动工具选择,但由脚手架控制的边管理节点间的转换。在这两个极端之间,Agentless 和 AutoCodeRover 占据中间位置,脚手架控制阶段顺序,但 LLM 在每个阶段内做出决策。
Table 3:循环驱动者策略。谁决定下一步做什么?
| 驱动者 | 智能体 |
|---|---|
| 用户驱动 | Aider:LLM 拥有 0 个可调用工具。用户选择文件(/add)、运行搜索并提供上下文。LLM 以文本格式生成编辑,由脚手架解析(base_coder.py:2296--2304)。 |
| 脚手架驱动 | Agentless, AutoCodeRover:脚手架控制顺序并在固定点调用 LLM。在 Agentless 中,每次 LLM 调用都是单轮的,没有对话状态。在 AutoCodeRover 中,脚手架管理跨越最多四个阶段的阶段转换:可选的复现器生成、可选的基于频谱的故障定位 (SBFL) 故障定位、搜索和补丁生成。 |
| LLM 驱动 | SWE-agent, OpenHands, Codex CLI, Gemini CLI, Cline, mini-swe-agent, Moatless Tools, DARS-Agent, OpenCode:LLM 选择工具并控制探索。Prometheus 是一个混合体:在每个图节点内,LLM 通过 ReAct 驱动工具选择,但节点间的转换由脚手架控制(基于状态字段的条件边,如 state["reproduced_bug"])。 |
循环驱动者的影响超越了控制流。用户驱动的智能体回避了先前轨迹分析中识别出的缺陷定位瓶颈:如果用户选择文件,定位不正确是用户错误,而非智能体失败。LLM 驱动的智能体必须将定位作为任务的一部分来解决,这使得检索策略(Section 4.2.4)成为关键的设计选择。
4.1.3 控制流实现
上述语义层面的循环类型通过四种不同的代码级机制来实现(Table 4):(1) 命令式 while 循环,脚手架在 while True 循环中调用 LLM 并在终止信号时跳出(13 个智能体中有 8 个);(2) 递归,每个工具使用轮次触发一次递归函数调用(Cline);(3) 图即控制流,由编译后的状态机定义转换和循环(Prometheus);(4) 基于异常的信号传递,特殊的异常类型在循环体和外部处理器之间传递控制消息(mini-swe-agent)。
Table 4:控制流实现变体。本表按代码级机制对智能体进行分类,这与 Table 2 中的语义循环策略是正交的:按循环策略被归类为"用户驱动"的智能体(如 Aider)在实现层面仍可能使用命令式 while 循环。
| 实现方式 | 智能体 |
|---|---|
| 命令式 while 循环 | SWE-agent, OpenHands, Codex CLI, Gemini CLI, mini-swe-agent, Aider, OpenCode |
| 固定流水线(无循环) | Agentless:顺序脚本;每次 LLM 调用都是单轮的,没有智能体循环。Anthropic 路径包含一个有界 for 循环(最多 10 次迭代,model.py:148--284),但主体架构没有循环。 |
| 递归 | Cline:recursivelyMakeClineRequests(task/index.ts:2268)。调用栈随对话长度线性增长。 |
| 图即控制流 | Prometheus:LangGraph 编译的状态机,具有显式边(issue_graph.py:22--134)。图中的循环创建迭代;递归限制(IssueBugSubgraph 为 30,BugReproductionSubgraph 为 150;动态公式在多候选运行中可扩展至数百步)作为终止保证。 |
| 基于异常的信号传递 | mini-swe-agent:InterruptAgentFlow 层级结构(Submitted、LimitsExceeded、FormatError)将消息作为载荷传递。run() 方法捕获这些异常,将消息注入历史记录,然后继续或跳出(default.py:88--96)。 |
基于图的方法与其他方法有本质区别:控制流可被框架检查、序列化和创建检查点。Prometheus 的子图定义了自己的状态类型,每个子图被包装在一个 SubgraphNode 类中,该类在父图状态和子图状态之间进行转换。例如,父 IssueState 持有 issue_title、issue_body 和 issue_comments;IssueBugSubgraphNode 包装器将这些作为关键字参数传递给 IssueBugSubgraph.invoke()。至少存在四层嵌套:IssueGraph → IssueBugSubgraph → IssueVerifiedBugSubgraph → ContextRetrievalSubgraph。
Cline 的递归实现是语料库中唯一将递归用于主智能体循环的实例。虽然在语义上与迭代等价,但这意味着 JavaScript 调用栈随每次工具使用轮次增长。在实践中,Node.js 的默认栈限制(通常为数千帧)在正常会话中不太可能被触及,但该设计有架构层面的影响:每个递归帧保留局部状态,与迭代方法相比,控制流更难序列化或创建检查点。七个智能体(SWE-agent、OpenHands、Codex CLI、Gemini CLI、mini-swe-agent、Aider、OpenCode)使用命令式 while 循环。Agentless 完全没有智能体循环(其流水线是固定的脚本序列),尽管其 Anthropic 代码路径包含一个小型迭代循环。Codex CLI 的 while 循环明显比其他智能体复杂:它使用了双层事件驱动架构和异步通道,但逻辑模式仍然是标准的 ReAct 循环。在这个群组中,OpenCode 在架构上独具特色,它在 while 循环之上叠加了一个全局的发布-订阅事件总线(packages/opencode/src/bus/)。各组件通过类型化事件而非直接函数调用进行通信。语料库中没有其他 CLI 智能体使用事件总线进行组件间通信;OpenHands 使用事件溯源进行状态管理(Section 4.3.1),但其事件流服务于与 OpenCode 的发布/订阅总线不同的目的(持久化和重放 vs. 解耦的运行时通信)。
4.2 第二层:工具与环境接口
接口层捕捉了智能体如何与代码和执行环境交互。五个维度刻画了该设计空间:(1) 工具集设计,(2) 编辑与补丁格式,(3) 工具发现策略,(4) 上下文检索范式,(5) 执行隔离。
4.2.1 工具集设计
工具数量从 0(Aider)到 37 个动作类(Moatless Tools)不等,但原始计数掩盖了能力类别上的趋同(Table 5)。尽管数量差异悬殊,相同的四个核心能力类别(读取、搜索、编辑、执行)出现在所有 LLM 驱动的智能体中(按 Section 4.1.2 的分类)。第五个类别——验证(专门的测试运行或代码检查工具)——仅出现在 Moatless Tools 中;其他智能体将验证归入其执行能力之下。两个使用 LLM 可调用工具的脚手架驱动智能体(AutoCodeRover、Agentless)有意将工具集限制为这些类别的子集,反映了其分阶段架构。工具较少的智能体通过组合实现覆盖:mini-swe-agent 的单一 bash 工具通过委派给 shell 命令覆盖了全部四个类别。工具较多的智能体则将这些类别分解为更细粒度的操作(仅搜索类别,Moatless Tools 就拥有 FindClass、FindFunction、FindCodeSnippet、SemanticSearch、GrepTool 和 GlobTool 等独立动作)。OpenHands 因包含一个基于 BrowserGym 的无头浏览器 [^31] 作为一等工具而突出,是语料库中唯一一个内置网页浏览工具用于导航和交互网页的智能体。它还提供了一个 think 工具用于记录推理而无副作用,以及一个 request_condensation 工具允许 LLM 请求上下文压缩(Section 4.3.2)。OpenCode 拥有相当的工具数量(18 个内置),并包含其他智能体中未见的独特工具:实验性的 LSP 集成用于符号导航、一个 skill 元工具从文件系统加载用户定义的领域特定指令和工作流、以及一个 batch 工具用于分组多个操作。Codex CLI(≈$ 20+ 个工具)值得注意的是包含了元工具,允许 LLM 在运行时发现更多工具:tool_search 查询已注册的应用工具,tool_suggest 为当前任务推荐工具。它还暴露了一个 request_permissions 工具,允许 LLM 在会话中途请求提升的沙箱访问权限,使智能体自身的权限成为可协商的资源而非固定约束。
Table 5:工具集规模与能力覆盖。工具计数反映 LLM 可调用工具;面向用户的命令(如 Aider 的 ≈$ 38 个斜杠命令)不包含在内。
| 智能体 | 工具数 | 读取 | 搜索 | 编辑 | 执行 | 验证 | 备注 |
|---|---|---|---|---|---|---|---|
| Aider | 0 | ✓ ∗ | ∗ 文本解析编辑,13 种格式 | ||||
| Agentless | 0–1 | ✓ ∗ | ∗ Anthropic 路径中 1 个模拟工具 | ||||
| AutoCodeRover | 8 | ✓ | ✓ | 全部为搜索/读取;无编辑工具 | |||
| OpenHands | 9+ | ✓ | ✓ | ✓ | +MCP;搜索通过 bash 实现 | ||
| Moatless Tools | 15–37 | ✓ | ✓ | ✓ | ✓ | ✓ | 37 个类;每个会话约 ≈$ 15 个 |
| SWE-agent | 3–35 | ✓ | ✓ | ✓ | ✓ | 默认 3 个;15 个工具包中共 35 个 | |
| DARS-Agent | ≈$ 15 | ✓ | ✓ | ✓ | ✓ | 继承自 SWE-agent 分支 | |
| Codex CLI | ≈$ 20+ | ✓ | ✓ | ✓ | ✓ | +MCP;+子智能体生成 | |
| Gemini CLI | 17+ | ✓ | ✓ | ✓ | ✓ | +MCP;+工具发现子进程 | |
| Prometheus | 17 | ✓ | ✓ | ✓ | ✓ | 每个图节点绑定 1–12 个 | |
| OpenCode | 18+ | ✓ | ✓ | ✓ | ✓ | +MCP;+插件;+自定义工具 | |
| Cline | 27+ | ✓ | ✓ | ✓ | ✓ | +MCP;最大的扁平内置工具集 | |
| mini-swe-agent | 1 | ✓ | 所有能力通过 bash 实现 |
按节点工具作用域。
Prometheus 是唯一在不同决策点绑定不同工具子集的智能体。其 EditNode 拥有 5 个工具(文件操作),而 BugReproducingWriteNode 仅拥有 read_file,BugFixVerifyNode 仅拥有 run_command。这种结构性护栏在每一步约束了动作空间。AutoCodeRover 通过阶段分离实现了类似效果:补丁智能体不被提供搜索工具,而是被提示直接从搜索阶段收集的上下文生成补丁。这是一种工作流级别的约束,而非可配置的绑定。
AutoCodeRover 定位阶段的搜索专用工具。
AutoCodeRover 的搜索智能体拥有 8 个 LLM 可调用工具,全部为只读搜索操作;搜索 LLM 无法编辑文件、运行命令或修改状态。这是使用 LLM 可调用工具的所有智能体阶段中最受约束的工具集。AutoCodeRover 确实生成补丁,但这发生在一个单独的补丁智能体阶段,该阶段提示 LLM 直接在其输出中生成补丁,而不调用任何工具。其理念是定位和修复是具有不同工具需求的不同任务:搜索阶段需要结构化的代码导航,而补丁阶段仅需要搜索阶段收集的上下文和 LLM 的代码生成能力。
AutoCodeRover 中用于工具调用的代理智能体。
AutoCodeRover 使用一个辅助 LLM 调用(agent_proxy.py:81--82)将搜索智能体的自然语言工具选择转换为结构化 JSON。搜索智能体"自言自语地思考"要调用哪些工具;代理智能体最多重试 5 次来提取结构化的调用。这为每轮搜索增加一次 LLM 调用(在可能的 15 轮中,最多增加 15 次额外的 LLM 调用),但避免了要求搜索智能体直接生成结构化输出。语料库中没有其他智能体使用辅助 LLM 调用来解析工具调用;所有其他智能体依赖函数调用 API、正则表达式解析或 XML 提取。
4.2.2 编辑与补丁格式
智能体如何将 LLM 输出转换为代码变更揭示了一种向共享接口趋同的趋势(Table 6)。str_replace_editor 工具——接受 old_str 和 new_str 参数进行精确字符串替换——出现在 13 个智能体中的 5 个中(OpenHands、SWE-agent、Codex CLI 自由模式下的 apply_patch、Agentless 作为三种修复输出格式之一、以及 Moatless Tools 的 StringReplace)。这种趋同值得注意,因为这些智能体是独立开发的;共享的接口反映了一个共同发现——对于 LLM 生成的补丁,精确字符串匹配比基于行号或基于统一 diff 的编辑更可靠 [^57]。
Table 6:编辑/补丁格式变体。
| 格式 | 智能体 |
|---|---|
| 字符串替换(函数调用) | OpenHands 和 SWE-agent(str_replace_editor),Codex CLI(apply_patch),OpenCode(edit) |
| 写入工具(函数调用) | Gemini CLI, Cline |
| 文本解析编辑块 | Aider(13 种格式),DARS-Agent |
| 模拟工具使用 | Agentless(Anthropic 路径) |
| Pydantic 模式动作 | Moatless Tools, Prometheus |
在解析方面,SWE-agent 支持 10 种不同的输出解析器(FunctionCallingParser、ThoughtActionParser、XMLThoughtActionParser 等),使相同的工具集能够跨具有不同输出约定的模型工作。结合 Aider 的 13 种模型特定编辑格式,这代表了语料库中观察到的输出接口方面最高程度的模型无关性;然而,两种方法针对不同的层次(SWE-agent 适配工具解析,而 Aider 适配编辑格式本身)。
Aider 以 13 种注册编辑格式成为异类,每种格式作为独立的 coder 子类实现。格式根据模型能力进行选择:某些模型更擅长处理统一 diff,其他模型则更适合 SEARCH/REPLACE 块。将编辑格式视为一等的、模型特定的架构组件,这在语料库中是独特的,尽管 OpenCode 实现了同一思路的简化版本:其工具注册表根据模型能力在 edit(字符串替换)和 apply_patch(统一 diff)之间选择,提供两种格式而非十三种。
Agentless 在其 Anthropic 路径中的"模拟工具使用"在架构上是独特的。当使用 Anthropic 的 API 时,LLM 调用 str_replace_editor 工具,但每次调用都收到相同的硬编码响应:"File is successfully edited",无论输入是什么。LLM 在编辑后从不看到实际的文件状态;工具调用被提取并在事后应用。这将工具调用 API 用作结构化输出提取技术,而非用于实际执行。
其余智能体使用同一方法的变体。AutoCodeRover 使用自定义的类 XML 标签 <original>/<patched>,而 Gemini CLI 和 Cline 将全文件写入工具与功能上类似于 str_replace_editor 的搜索替换工具相结合。mini-swe-agent 是唯一通过 shell 命令直接编辑文件而非生成补丁供脚手架应用的智能体。
4.2.3 工具发现策略
工具发现的范围从完全静态(工具在初始化时固定)到真正动态(工具在会话期间添加)(Table 7)。近半数智能体(13 个中有 6 个)使用完全静态的工具注册:所有工具在初始化时定义,在整个会话期间保持不变。这是基准测试智能体(Agentless、AutoCodeRover、mini-swe-agent、DARS-Agent、Moatless Tools)和 Aider(LLM 没有可调用工具)的默认方法。SWE-agent 和 OpenHands 处于中间地带:其工具集是配置条件化的(不同的工具包根据配置加载),但一旦加载,在给定尝试中工具集是固定的。(在 SWE-agent 的重试循环中,如果 agent_configs 指定了不同的配置,不同的尝试可以加载不同的工具包。)
Table 7:工具发现策略。
| 策略 | 智能体 |
|---|---|
| 静态(全部在初始化时确定) | Aider, Agentless, AutoCodeRover, mini-swe-agent, DARS-Agent, Moatless Tools |
| 按阶段作用域(每个节点静态) | Prometheus, AutoCodeRover |
| 配置条件化 | SWE-agent, OpenHands |
| 每轮动态重建 | Codex CLI(每次采样请求调用 built_tools(),codex.rs:6156--6164) |
| 动态(MCP + 子进程) | Gemini CLI(工具发现子进程,tool-registry.ts:312--439),Cline(MCP 服务器在运行时连接/断开),OpenCode(静态核心工具 + 来自配置目录的动态自定义工具、插件系统和 MCP 集成) |
在动态的一端,Codex CLI 的每轮工具重建是独特的:大多数智能体构建工具集一次(或每个阶段一次),而 Codex CLI 在每次 LLM 采样请求时调用 built_tools(),纳入任何 MCP 服务器变更、新启用的连接器或会话期间添加的动态工具。工具集原则上在每次 LLM 调用时都可能不同。Gemini CLI 的 toolDiscoveryCommand 功能采用了不同的方法:一个外部子进程以 JSON 形式输出 FunctionDeclaration[],允许在不修改智能体代码的情况下使用任意工具源。Cline 和 OpenCode 类似地通过 MCP 服务器连接和插件系统支持运行时工具变更。Prometheus 和 AutoCodeRover 介于静态和动态之间:其工具集在每个阶段或图节点内是固定的,但不同阶段暴露不同的工具子集(如 Section 4.2.1 所述)。
4.2.4 上下文检索范式
上下文检索(智能体如何找到相关代码)显示出显著的架构差异,七种不同的策略类型从简单的关键词搜索到知识图谱遍历(Table 8)。13 个智能体分为两种检索范式,反映了关于代码理解应驻留在何处的根本不同假设。
Table 8:上下文检索策略。智能体可能使用多种策略。
| 策略 | 智能体 | 机制 |
|---|---|---|
| 关键词/正则搜索 | SWE-agent, OpenHands, Codex CLI, Gemini CLI, Cline, mini-swe-agent, DARS-Agent, OpenCode | LLM 调用 grep、find、ripgrep 作为工具。 |
| 仓库地图(静态分析) | Aider | PageRank 加权的 tree-sitter 标签索引。构建 NetworkX 依赖图;对话中提及的标识符获得 10 倍权重提升;加入聊天的文件获得 50 倍提升(repomap.py:365--574)。 |
| 抽象语法树 (AST) 感知搜索 | AutoCodeRover, Moatless Tools, DARS-Agent, Prometheus | search_class、search_method:在预构建的 AST 索引上进行结构感知查询。AutoCodeRover 的 AST 工具仅支持 Python;Prometheus 基于 tree-sitter 的工具覆盖 20 种语言。 |
| 知识图谱遍历 | Prometheus | 从覆盖 20 种语言的 tree-sitter AST 构建的 Neo4j 图。11 个工具(10 个图遍历加 read_file)查询 FileNode、ASTNode、TextNode 实体(graph_traversal.py:93--586)。 |
| 基于嵌入的语义搜索 | Moatless Tools | [^28] |
| 层次化定位 | Agentless | 文件 → 类/函数 → 跨流水线阶段的行级缩窄。每一层仅看到前一层识别的内容(FL.py:313--681)。 |
| 经典故障定位 | AutoCodeRover | 使用 Ochiai 评分的 SBFL(analysis/sbfl.py)。语料库中独此一例。 |
第一种范式被八个智能体采用(SWE-agent、OpenHands、Codex CLI、Gemini CLI、Cline、mini-swe-agent、DARS-Agent、OpenCode),将 LLM 视为导航者:智能体提供通用 shell 工具(grep、find、ripgrep),依赖 LLM 制定查询、解释结果并决定下一步查看位置。脚手架本身不提供代码理解能力;它只是执行 LLM 请求的命令并返回输出。
第二种范式投资于脚手架侧的代码理解,在任务之前或期间构建代码库的结构化表示。Aider 从解析后的源代码构建依赖图,使用 PageRank 对文件相关性进行排名(下文讨论)。Agentless 在连续的 LLM 调用中从文件缩窄到类再到行,每次调用仅看到前一阶段识别的内容。AutoCodeRover 和 Moatless Tools 将源代码解析为抽象语法树 (AST),支持结构感知查询(如"查找所有名为 process 的方法"),而非文本模式匹配。Prometheus 走得最远,从覆盖 20 种语言的 AST 构建 Neo4j [^36] 图数据库,并提供 11 个工具(10 个图遍历加 read_file)用于查询代码实体间的关系。
范式选择与循环驱动者(Section 4.1.2)相关:脚手架驱动的智能体倾向于投资检索基础设施,而 LLM 驱动的智能体倾向于信任 LLM 使用通用工具进行导航。这种相关性并不令人意外:如果脚手架控制顺序,它就有机会(也有必要)对仓库进行预处理;如果 LLM 控制探索,它可以按需发出搜索命令。
Aider 的 PageRank 仓库地图。
Aider 的检索机制将 Google 的 PageRank 算法 [^10] 应用于源代码结构。tree-sitter [^12] 解析每个文件以提取符号定义和跨文件引用,形成有向依赖图(repomap.py:365--574)。PageRank 分数按结构中心性对文件进行排名,并具有上下文感知的权重提升:对话中提及的标识符获得 10 倍权重,加入聊天的文件获得 50 倍权重,二分搜索按排名顺序填充 Token 预算。语料库中没有其他智能体使用图论相关性排名。该方法以启动成本(解析整个仓库)换取上下文质量:Aider 不依赖 LLM 导航代码库,而是从仓库的实际依赖结构预计算相关性。
AutoCodeRover 的 SBFL。
AutoCodeRover 是唯一结合了经典故障定位 [^53] 的智能体。当存在失败测试时,它运行基于频谱的故障定位 (SBFL),使用 Ochiai 可疑度评分 [^1]:被失败测试频繁执行而被通过测试很少执行的方法排名最高(analysis/sbfl.py)。可疑度最高的 5 个方法作为建议性输入呈现给 LLM,补充其基于搜索的探索。这在两个原本互不关联的社区(自动故障定位与基于 LLM 的修复)之间架起了桥梁 [^60];语料库中没有其他智能体使用基于测试执行的定位。
4.2.5 执行隔离
执行隔离的范围从无沙箱到推测性的内存中执行(Table 9)。对于树搜索智能体,执行隔离与搜索成本直接相关。DARS-Agent 的环境重置执行完整的 Docker 重置,并从根节点到分支点重放所有动作。在深度 N 处,这需要重新执行 N 条命令。DARS 通过将分支限制为特定动作类型(edit、create、append、submit)来降低这一成本,具体通过 action_expansion_limit 实现(default_dars.yaml:179--184)。Moatless Tools 完全避免了重放:其影子模式在 FileContext 对象中跟踪文件修改而不写入磁盘,每个节点克隆其父节点的文件上下文。这使得在任意步骤分支而无环境成本成为可能。
Table 9:执行隔离策略。
| 隔离级别 | 智能体 |
|---|---|
| 无(本地 shell) | Gemini CLI, Aider, OpenCode |
| 无状态子 shell | mini-swe-agent(subprocess.run(),local.py:28--39) |
| 平台级沙箱 | Codex CLI(Linux 上使用 Bubblewrap+Landlock,macOS 上使用 Seatbelt) |
| Docker 容器 | SWE-agent, OpenHands, DARS-Agent, AutoCodeRover, Prometheus |
| 影子 Git 检查点 | Cline(隔离的 Git 仓库在每次工具执行后跟踪状态,CheckpointTracker.ts) |
| 影子模式(内存中) | Moatless Tools(shadow_mode 标志,agent.py:57) |
| 不适用 | Agentless:LLM 从不执行任意命令;Docker 仅用于通过 SWE-bench harness 执行测试 |
Cline 的影子 Git。
Cline 的 CheckpointTracker 为每个工作区创建一个隔离的 Git 仓库,在每次工具执行后记录文件系统状态。这实现了基于 diff 的回滚,而不触及用户的真实 Git 历史,也不需要 Docker。它通过临时禁用嵌套 Git 仓库来处理嵌套情况,并对敏感目录进行验证。这是在无隔离和容器化之间的一种中间方案,特定于 Cline 所运行的 IDE 上下文。
安全策略的分化。
未使用容器隔离的智能体采取了截然不同的安全策略,这表明在交互式智能体的隔离标准方面,生态系统尚未形成共识。
Gemini CLI 采用基于规则的策略引擎,为每个工具分配审批要求。在执行工具调用之前,引擎会检查该工具是否需要用户确认、是否自动允许、还是完全禁止。这些规则是可配置的,允许用户根据自身工作流调整安全边界。
Codex CLI 结合了两种机制。在操作系统层面,它使用平台特定的沙箱技术(Linux 上的 Bubblewrap [^19] 和 Landlock [^45],macOS 上的 Seatbelt)来限制文件系统和网络访问。在此之上,一个 Guardian 安全子智能体——一个独立的 LLM (gpt-5.4) 2——通过 0-100 分的结构化评分来评估每个工具调用的风险,阻止得分超过 80 分阈值的调用 (guardian.rs)。这是语料库中唯一一个使用 LLM 来评估另一个 LLM 行为安全性的智能体。
Aider 采取了最简单的方式:依赖用户在场监督。由于用户手动选择要编辑的文件,并在所有提议的更改应用之前进行审查,因此人类充当了安全边界。
Cline 提供了语料库中最细粒度的审批系统:按工具和按范围的审批设置,配合一个 CommandPermissionController 来阻止危险的 shell 操作符。设置范围从完全自主模式("YOLO")到按命令模式审批,为用户提供了对信任边界的精细控制。OpenCode 使用了类似于 Gemini CLI 的基于策略的权限系统:工具可以通过各自工具实现中的权限回调请求运行时用户审批,提供三个选项(允许一次、始终允许、拒绝),但不提供操作系统级别的沙箱。mini-swe-agent 使用无状态子 shell,在不使用容器化的情况下提供进程级隔离。
五个基于 Docker 的智能体(SWE-agent、OpenHands、DARS-Agent、AutoCodeRover、Prometheus)依赖容器边界作为其主要安全机制:所有命令在容器内执行,宿主文件系统永远不会被直接暴露。OpenHands 的 Docker 实现在架构上具有独特性:一个 FastAPI 动作服务器运行在容器内部,宿主端的智能体控制器通过 HTTP 与之通信。这在智能体和执行环境之间创建了一个干净的 API 边界,不同于其他直接在容器中执行命令的 Docker 智能体。Agentless 处于独特的位置:由于 LLM 从不执行任意命令(它只生成文本,由脚手架进行解析),其隔离需求与智能体方法有根本性的不同。Docker 仅用于通过 SWE-bench harness 执行测试,而非用于智能体安全。
从人工监督到基于 LLM 的安全评估,这一分布反映了一个开放的设计问题:随着智能体获得更多的自主权(Section 4.1.2),安全机制必须相应地扩展,但目前尚未出现标准的方法。
4.3 第三层: 资源管理
资源管理层关注智能体如何处理有限上下文窗口、API 成本和会话边界等约束。四个维度刻画了其中的变异:(1) 状态管理,(2) 上下文压缩,(3) 多模型路由,(4) 持久化记忆。
4.3.1 状态管理
智能体表示和维护对话状态的方式,从简单的破坏性覆写到完整的事件溯源 [^20],跨度极大(Table 10)。在一个极端,Aider 的双列表设计(cur_messages 和 done_messages)简单但具有破坏性:摘要化会替换 done_messages 的内容。在另一个极端,OpenHands 的事件溯源架构存储不可变事件,并通过 View 类计算视图;压缩操作插入标记而非删除事件,从而保留完整的审计轨迹。在这两个极端之间,OpenCode 基于 SQLite 的层级结构使用仅追加的消息和 12 种类型化的部件变体,是语料库中继 OpenHands 之后最细粒度的状态表示,也是唯一一个由关系数据库而非内存结构支撑的状态表示。Agentless 位于频谱的另一端:它完全没有对话状态,因为每次 LLM 调用都是单轮的。流水线各阶段之间的状态以不可变的 JSONL 文件表示,存储在磁盘上,每行对应一个问题实例的一个 JSON 对象。这种基于文件的状态总线使流水线可以被轻松恢复(--skip_existing 检查输出中的实例是否存在)和并行化,但这也意味着不存在需要管理的对话历史,因为根本没有对话。Codex CLI 在扁平列表类智能体中脱颖而出,它添加了双重持久化:一个仅追加的 JSONL 回放文件用于人类可读的重放,另有一个 SQLite 数据库用于可查询的状态和会话恢复。它也是唯一一个支持撤销(Op::Undo)和线程回滚(Op::ThreadRollback)的扁平列表类智能体。Cline 维护两个并行的消息列表,一个用于 LLM API,另一个用于 UI,通过互斥锁保护的并发访问进行同步;这种双列表架构反映了其 IDE 集成的特点,即 UI 需要比 API 更丰富的表示。
Table 10: 状态管理策略。
| 策略 | 智能体 |
|---|---|
| 破坏性 | Aider: 摘要化覆写 done_messages (base_coder.py:1024--1034) |
| 扁平列表,保留原始数据 | SWE-agent、Codex CLI、Gemini CLI: 保留原始历史;为 LLM 创建过滤视图。mini-swe-agent: 保留原始历史且不进行过滤(消息按原样发送给 LLM) |
| 类型化事件日志 | OpenCode: 基于 SQLite 的消息/部件层级结构,包含 12 种部件类型(Drizzle ORM)。仅追加的消息,部件状态可变 (message-v2.ts) |
| 图作用域 | Prometheus: 每个图节点拥有独立的消息列表 (edit_messages、analyzer_messages、context_provider_messages),在重试边界处重置 |
| 树结构 (MCTS) | Moatless Tools: 树中的节点,每个节点包含文件上下文快照、访问计数和奖励值 |
| 树结构(贪心) | DARS-Agent: 树中的节点,每个节点包含扩展候选和评判者响应 (dars_agent.py:294--297)。无 MCTS 统计信息;分支使用贪心 LLM 评判者选择,状态通过 Docker 重置和动作重放来恢复,而非文件上下文快照。 |
| 事件溯源 | OpenHands: 不可变的 EventStream;视图通过压缩标记计算 (memory/view.py:13--96) |
Prometheus 的图作用域状态在结构上具有独特性。它并非维护一个持续增长的单一对话,而是图中每个 LLM 节点维护各自的消息列表。当图循环回来进行重试时,ResetMessagesNode 清除特定的消息列表,无需任何 Token 计数逻辑即可防止无界累积。
树结构状态存储了扁平列表无法表示的逐节点元数据,但两个树搜索智能体对其的使用方式不同。Moatless Tools 维护 MCTS 统计信息(访问计数和奖励值),并在每个分支点克隆文件上下文快照。DARS-Agent 存储扩展候选和评判者响应,但没有 MCTS 统计信息:它使用贪心 LLM 评判者选择,并通过重置 Docker 环境并从根节点重放动作来恢复分支状态,而非维护逐节点的文件快照。
4.3.2 上下文压缩
所有智能体都面临有限上下文窗口的约束,压缩策略从不进行任何管理到 LLM 主动发起压缩不等(Table 11)。
Table 11: 上下文压缩策略。
| 策略 | 智能体 | 机制 |
|---|---|---|
| 无(溢出时崩溃) | mini-swe-agent | 无界增长;智能体在 ContextWindowExceededError 时崩溃。 |
| 基于规则的截断 | SWE-agent、DARS-Agent | SWE-agent: 7 个可组合的处理器;保留前 N 个和后 N 个观测,省略其余部分。用于提示缓存保留的 polling 参数。DARS-Agent: 在其分支中添加了 Last5Observations。 |
| 结构化隔离 | Prometheus、AutoCodeRover | Prometheus: 逐节点的消息作用域 + 在重试边界处重置。AutoCodeRover: 轮次限制 (15) + 结果截断。 |
| 基于 Token 的选择性包含 | Moatless Tools | 在 Token 预算内进行贪心的近期优先选择;逐观测摘要作为回退。 |
| LLM 摘要化(脚手架触发) | Aider、OpenHands、Gemini CLI、Codex CLI、OpenCode | 在 Token 阈值处自动触发。Aider: 递归层级式摘要化。Codex CLI: 轮次前和轮次中两种模式。OpenCode: 两阶段(先修剪旧输出,再进行 LLM 摘要化)。 |
| LLM 摘要化 + 验证 | Gemini CLI | 先摘要化,然后进行"Probe"验证轮次以检查信息是否丢失。 |
| LLM 主动发起的压缩 | Cline | condense 工具: LLM 决定何时进行压缩。同时也支持在 Token 阈值处脚手架触发的压缩。 |
语料库揭示了两种截然不同的理念。"预防型"智能体从结构上约束上下文增长:Prometheus 将消息限定在图节点作用域内,并在重试边界处重置;AutoCodeRover 将搜索轮次上限设为 15,每次查询最多展示 3 个完整结果;Moatless Tools 通过树结构限制轨迹深度。"治疗型"智能体则让上下文自由增长,在需要时进行压缩:Aider、OpenHands、Gemini CLI 和 Codex CLI 都在 Token 阈值处触发基于 LLM 的摘要化。预防方法避免了摘要化的成本和信息丢失,但要求脚手架预先估计上下文增长模式。Agentless 则完全绕开了压缩问题:由于每次 LLM 调用都是无对话历史的单轮调用,"压缩"简化为将代码装入单个提示。当提示超过 128K Token 限制时,Agentless 从排序列表末尾逐步丢弃文件,并通过 libcst 将函数体压缩为签名。这种预计算方法通过从不累积对话状态,消除了运行时压缩的需要。在"治疗型"智能体中,OpenCode 的两阶段策略最为精准:它首先修剪冗长的旧工具输出,保持消息结构但将最近 40,000 Token 之前的输出替换为截断标记。只有在此之后,它才通过一个可使用更廉价模型的专用压缩智能体触发基于 LLM 的摘要化。与纯截断相比,这种方法保留了更多的对话上下文;与全面摘要化相比,则更具针对性。Codex CLI 区分了轮次前压缩和轮次中压缩:轮次前压缩在每个用户轮次之前运行,清除引用上下文,以便下一轮次能干净地重新注入初始上下文;轮次中压缩在工具执行期间达到 Token 限制时运行,将初始上下文注入到最后一条用户消息之上,以匹配模型对上下文出现位置的训练预期。这种对压缩时机与对话结构关系的感知在语料库中是独一无二的。
SWE-agent 的 polling 参数。
SWE-agent 的 LastNObservations 处理器包含一个 polling 参数,揭示了压缩与 API 成本之间的一个微妙交互。许多 LLM 提供商提供提示缓存,即共享相同消息前缀的连续调用可以跳过重复处理。如果不使用 polling,每个新观测都会改变包含哪些消息,从而使缓存失效。使用 polling 后,截断变化仅以每步 1/polling 的速率发生,使前缀在连续调用之间保持稳定。这种成本优化处于两个本来相互独立的关注点的交汇处,在此前对 SWE-agent 的分析中未被记录。
Gemini CLI 的验证探测。
Gemini CLI 是唯一一个验证自身上下文压缩结果的智能体。在 LLM 摘要化之后,它运行一个"Probe"轮次,让模型检查关键信息是否丢失。这种自我纠正机制以每次压缩事件额外消耗一次 LLM 调用为代价,解决了 LLM 摘要化的一个已知失效模式(技术细节的有损压缩)。
Cline 的 LLM 主动发起的压缩。
Cline 的 condense 工具赋予了 LLM 对自身上下文管理的能动性。如果 LLM 判断上下文已变得难以处理,它可以主动请求摘要化。语料库中没有其他智能体将压缩决策委托给 LLM。OpenHands 提供了一个概念上类似的 CondensationRequestAction,但压缩也可以在历史记录超过压缩器阈值时自动触发。OpenHands 的压缩器架构是语料库中最具可扩展性的:九个可插拔的实现通过注册表模式组合成流水线。由于压缩操作在视图层面进行(插入 CondensationAction 标记而非删除事件),原始事件流永远不会被修改,即使在积极压缩之后也能实现会话重放。
4.3.3 多模型路由
多模型路由(为不同子任务使用不同的 LLM)从单模型的简洁性到多策略分类器链不等(Table 12)。两个智能体自始至终使用单一模型:mini-swe-agent 和 Agentless。OpenHands 提供了可扩展的路由基础设施,但默认采用单模型运行;其唯一已实现的路由器仅根据图像是否存在和 Token 限制做出有限的决策。其余 10 个智能体路由到多个模型,但出于不同的原因。
Table 12: 多模型路由策略。
| 策略 | 智能体 | 机制 |
|---|---|---|
| 单模型 | mini-swe-agent、Agentless(按路径) | 全程使用一个模型。 |
| 路由器抽象(默认单模型) | OpenHands | RouterLLM 基类,配合 MultimodalRouter: 根据图像是否存在和 Token 限制进行路由 (llm/router/rule_based/impl.py:16--81)。默认: 通过 noop_router 使用单模型。 |
| 基于角色 | Aider、OpenCode | 为不同子任务配置主模型/弱模型/编辑器模型。Aider: 弱模型用于摘要化和提交消息 (models.py:607--608);编辑器模型用于架构师模式 (architect_coder.py:22--25)。OpenCode: 为构建、计划、探索和压缩智能体配置逐智能体的模型覆盖 (agent/agent.ts:78--233)。 |
| 基于计划/执行模式 | Cline | 每种模式使用独立的模型 (api/index.ts:76--149)。LLM 通过工具调用切换模式。 |
| 逐次尝试轮换 | SWE-agent、AutoCodeRover | 在重试时使用不同的模型。SWE-agent: 在 agent_configs 中轮询 (agents.py:303--319)。AutoCodeRover: 在 model_names 中轮询 (inference.py:98--114)。 |
| 安全导向 (Guardian) | Codex CLI | 独立模型 (gpt-5.4) 评估工具调用的风险 (guardian.rs)。 |
| 基于任务的双模型 | Prometheus | 高级模型用于推理(分析、编辑、补丁选择);基础模型用于机械性任务(检索、验证)(llm_service.py:23--38)。按图节点硬编码。 |
| Actor-Critic | Moatless Tools | 价值函数(可能使用不同模型)为节点评分 (value_function/base.py)。 |
| 分类器链 | Gemini CLI | 7 层优先级路由: 回退 → 覆盖 → 审批模式 → Gemma 分类器 → LLM 分类器 → 数值分类器 → 默认 (modelRouterService.ts:39--67)。可选的本地 Gemma 模型用于客户端路由。 |
成本优化是主要驱动力。
在使用多模型的智能体中,主要动机是成本:将机械性任务路由到更廉价的模型,同时将昂贵的模型留给推理任务。Aider 的"弱模型"处理摘要化和提交消息;在架构师模式下,第三个"编辑器模型"接收计划并生成编辑。OpenCode 通过逐子智能体的模型覆盖扩展了这种基于角色的方法。
Prometheus 以更细的粒度应用了同样的原则。其 LangGraph 状态机中的每个节点都被硬编码为使用"高级"或"基础"模型。推理密集型节点(分析、编辑和补丁选择——最后一项进行 10 次多数投票 LLM 调用)使用高级模型,而机械性节点(知识图谱遍历、测试执行)使用基础模型。由于路由是按节点而非按角色进行的,成本节约随图中机械性步骤占比的增加而扩大。
Gemini CLI 的分类器链。
Gemini CLI 的 7 层路由策略是观察到的最复杂的路由机制。每一层实现不同的策略,第一个产生决策的层胜出,因此简单的情况以低成本解决,而模糊的情况则传递给更复杂的分类器。最具特色的层是可选的 GemmaClassifierStrategy,它在本地运行一个轻量级的 Gemma 模型 [^24] 进行客户端路由决策,避免了仅为选择模型而发出 API 调用。没有其他智能体执行客户端模型选择。
树搜索中的 Actor-Critic。
Moatless Tools 的价值函数 (value_function/base.py) 为搜索树节点分配数值奖励。当配置为使用与动作智能体不同的模型时,结果是一种 Actor-Critic 架构:一个模型生成动作,另一个模型评估动作。没有其他智能体使用不同的模型分别进行生成和评估;DARS-Agent 的 LLM 评判者扮演类似角色,但生成和评估使用同一模型,这意味着评判者共享了生成者的偏见。
其他路由策略。
两个智能体使用逐次尝试的模型轮换:SWE-agent 和 AutoCodeRover 都在重试时轮换不同的模型配置,押注在一次尝试中失败的模型,在由不同模型从零开始尝试同一任务时可能会成功。Cline 按模式而非按角色进行路由:其计划和执行模式各使用一个独立配置的模型,LLM 通过工具调用在模式之间切换。Codex CLI 是语料库中使用模型数量最多的智能体:用于代码生成的主模型,用于工具调用安全评估的 Guardian 模型 (gpt-5.4),以及其记忆提取流水线的两个专用模型(gpt-5.1-codex-mini 用于逐回放提取,gpt-5.3-codex 用于整合;Section 4.3.4)。Guardian 是语料库中唯一一个出于安全而非成本或能力原因进行多模型路由的实例。
4.3.4 持久化记忆
持久化记忆(跨会话留存的知识)从完全不存在到多层提取流水线不等(Table 13)。基准测试评估类智能体和交互式使用类智能体之间存在明显的分界。五个没有持久化记忆的智能体(SWE-agent、OpenHands、AutoCodeRover、mini-swe-agent、DARS-Agent)将每个任务视为独立的,没有跨任务学习。对于纯基准测试智能体(SWE-agent、AutoCodeRover、mini-swe-agent、DARS-Agent),这是预期之中的;而对于同时广泛用于交互式开发的 OpenHands(53k star,语料库中第二高),缺乏持久化记忆值得关注,尽管其 microagent 系统加载的静态项目指令部分填补了这一角色。Agentless 也缺乏跨任务学习,但通过缓存输出和嵌入索引支持流水线可恢复性,介于上述两组之间。五个具有持久化记忆的 CLI 智能体(Aider、Cline、Gemini CLI、Codex CLI、OpenCode)面向交互式开发,在这种场景中记住项目规范和过往决策具有直接价值。Prometheus 是一个异类:尽管它是一个 SWE-bench 智能体(Table 1),却实现了更具交互式工具特征的多层持久化(Neo4j、PostgreSQL、Athena),这暗示着超越基准测试评估的架构抱负。在这些智能体中,"记忆"的含义差异显著:Cline 和 Gemini CLI 持久化学习到的规则,Codex CLI 从过往会话中提取和整合记忆,而 OpenCode 则在 SQLite 中持久化完整的会话状态,包括所有消息、工具输出、Token 使用量和成本,使得中断的会话可以在完整上下文下恢复。
Table 13: 持久化记忆策略。
| 策略 | 智能体 | 机制 |
|---|---|---|
| 无 | SWE-agent、OpenHands、AutoCodeRover、mini-swe-agent、DARS-Agent | 无跨会话持久化。每次运行从零开始。轨迹文件是输出制品,不被未来的运行消费。 |
| 流水线可恢复性 | Agentless | 无跨任务学习,但 JSONL 输出支持流水线可恢复性 (--skip_existing),嵌入索引通过 --persist_dir 持久化,预计算的仓库结构通过 PROJECT_FILE_LOC 缓存。这些被同一流水线的未来运行消费,而非跨任务知识。 |
| 配置文件加载 | Aider (.aider.conf.yml) | 静态的、用户编写的配置。标签缓存 (repomap.py:43, 217--265) 将 AST 分析跨会话持久化,作为性能优化。 |
| LLM 可写的规则/记忆 | Cline (.clinerules/)、Gemini CLI (GEMINI.md) | LLM 主动编写持久化指令。Cline: new_rule 工具 (tools.ts:31)。Gemini CLI: save_memory 工具将内容追加到 GEMINI.md 的"Gemini Added Memories"部分 (memoryTool.ts)。 |
| 完整会话持久化 | OpenCode | 基于 SQLite 的会话历史,支持恢复能力。所有消息、工具输出、Token 使用量和成本均被持久化 (session/session.sql.ts:14--76)。 |
| 后台提取流水线 | Codex CLI | 两阶段: 第一阶段从近期回放中提取记忆(并行,gpt-5.1-codex-mini);第二阶段通过子智能体整合 (gpt-5.3-codex)。按使用频率排序,过时记忆被修剪 (memories/README.md)。 |
| 多层持久化 | Prometheus | Athena(语义记忆服务,HTTP API)+ Neo4j(知识图谱,20 种语言的 AST)+ PostgreSQL(LangGraph 检查点)。记忆优先检索,知识图谱作为回退 (context_retrieval_subgraph.py:159--163)。 |
静态项目指令。
"无"类别中的若干智能体确实会加载跨会话持久化的静态、用户编写的项目指令。OpenHands 通过其 microagent 系统从工作区读取 .openhands_instructions 和 .cursorrules,类似于 Aider 的 .aider.conf.yml。这些未被归类为持久化记忆,因为智能体从不写入或更新它们;它们是静态配置而非学习到的知识。
LLM 作为记忆的作者。
Cline 和 Gemini CLI 共享一种模式,即 LLM 编写自己的持久化指令。Cline 的 new_rule 工具创建 .clinerules 文件;Gemini CLI 的 save_memory 工具向 GEMINI.md 追加内容,后者还支持 @path/to/file 引用以跨多个文件组合指令。这些记忆持久化在项目仓库中,并在未来会话的系统提示中被加载。Codex CLI 采取了不同的方法:一个后台流水线提取和整合记忆,而无需 LLM 明确决定要记住什么。
跨工具兼容性。
Cline 不仅读取自己的 .clinerules/,还读取 .cursorrules、.windsurfrules 和 AGENTS.md。这种务实的互操作性反映了一个正在形成的生态系统,在该生态系统中开发者使用多个 AI 编码工具并共享项目级指令 [^21]。
4.4 跨维度主题
若干发现横跨多个分类法维度,无法简化为单一轴线。这些跨维度主题源自分析模板的开放编码部分(Section 3.2),代表了在不同维度上以不同方式呈现的架构模式或权衡取舍。之所以单独呈现,是因为将它们强行纳入维度框架会遮蔽其多维本质。
4.4.1 采样与迭代
当 LLM 生成的补丁失败时,有两种根本不同的重试方式:生成另一个独立的尝试(采样),或利用失败的反馈来改进失败的尝试(迭代)。这一区分横跨控制循环分类法,因为它描述的是智能体如何处理解决方案尝试的总体,而非任何单次尝试的结构。
Agentless 是采样的最纯粹示例:它独立生成多个补丁,并通过多数投票进行选择(Section 4.1.1)。每个补丁都从相同的上下文生成;没有任何补丁因知道另一个失败而受益。
九个 LLM 驱动的智能体中有六个(OpenHands、Codex CLI、Gemini CLI、Cline、mini-swe-agent、OpenCode)采取了相反的方式:纯迭代。单次尝试通过反馈循环不断精化,每一步都能看到前一步的结果。如果测试失败,智能体会看到错误消息并进行调整。这种深度优先策略押注于反馈比独立性更有价值,且单条有引导的轨迹比多条无引导的轨迹更可能收敛到正确的解决方案。
多数投票也出现在 Prometheus 中,但处于不同的层面。Prometheus 并非独立生成补丁,而是在同一提示上调用高级模型 10 次,以在已生成的候选补丁中进行选择,当票数领先超过剩余票数时提前终止。在这里,投票运作在决策层(选择提交哪个补丁),而非生成层(创建补丁)。
SWE-agent 的 RetryAgent 介于采样和迭代之间。它生成多个完整的尝试——每个都是一条拥有自身反馈循环的完整深度优先轨迹——并通过一个审阅模型选出最佳者。每次尝试可以使用不同的模型配置。其结果将每次尝试内的迭代(反馈驱动的精化)与跨尝试的采样(事后评估的独立轨迹)结合在一起。
4.4.2 子智能体委托
五个智能体支持子智能体生成,即主智能体创建一个辅助智能体实例来处理子任务。这一能力之所以重要,是因为它支持并行性(同时处理多个文件)和专业化(委托给具有不同工具权限或系统提示的智能体)。然而,这五个智能体通过根本不同的机制实现委托,揭示了关于谁应控制委托决策的不同假设。
Codex CLI 通过将委托作为一套工具暴露给 LLM,赋予其完全的委托控制权:spawn_agent、send_input、resume_agent、wait 和 close_agent。LLM 决定何时生成子智能体、分配什么任务以及何时收集结果。深度受 agent_max_depth 限制,协作工具在最大深度时被禁用,以防止无界递归。
OpenCode 采取基于角色的方法:其 task 工具生成具有不同专长的子智能体(build、plan、explore、general),每个都有脚手架强制的工具权限。plan 智能体对大多数路径禁用文件编辑工具(edit、write),但保留 bash 访问;explore 智能体启用面向读取的工具加 bash,同时默认拒绝面向写入的工具。LLM 选择调用哪个专家,但可用的专长及其能力由脚手架定义。这是一种结构性约束,不同于 Cline 的计划/执行模式切换——后者由 LLM 自身通过工具调用决定何时转换模式。
OpenHands 将委托集成到其事件溯源架构中。父 AgentController 通过 AgentDelegateAction 创建子控制器,并将事件转发给委托者。由于委托通过与所有其他动作相同的事件流进行,它自动被捕获在智能体的历史中,并受到与其他动作相同的压缩和重放机制的约束。
Cline 通过 new_task 和 use_subagents 提供了更简单的基于工具的委托。Gemini CLI 通过其 LocalAgentExecutor 支持子智能体,后者运行一个独立的 ReAct 循环,拥有自己的轮次限制和截止时间计时器;其独特之处在于包含一个恢复阶段,当截止时间到达时给予子智能体最后一轮以产生输出。Prometheus 的图结构通过子图嵌套隐式地进行委托,而非显式的生成。
4.4.3 在线选择与离线选择
树搜索智能体面临两个不同的选择问题:在搜索过程中下一步探索哪个分支(在线引导),以及在搜索完成后返回哪个已完成的解决方案(离线选择)。这两个问题可以由相同的机制解决,也可以由不同的机制解决,各有不同的权衡。
DARS-Agent 将两者清晰地分离。在搜索过程中,LLM 评判者在每个分支点的候选动作之间进行选择;这是塑造搜索树哪些部分被探索的在线引导。搜索完成后,一个单独训练的审阅者评估已完成的补丁;这是选择最终输出的离线选择。这种分离意味着每个组件可以独立优化:在线评判者需要快速(它在每个分支点运行),而离线审阅者可以更加深入(它只在最后运行一次)。
Moatless Tools 也将两个组件分离。价值函数在在线 MCTS 模拟期间分配数值奖励;一个独立的判别器离线评估并选择最佳已完成轨迹。与 DARS-Agent 独立训练的审阅者不同,两个组件可以配置为使用同一模型,使判别器能够应用与搜索引导一致的评估标准。
两者在如何提取最终答案上的对比进一步延伸。DARS-Agent 的最左路径提取总是取 children[0],完全依赖在线评判者已将搜索引导向好的解决方案。Moatless Tools 的判别器则主动重新评估所有已完成的轨迹,有可能选择一个在搜索过程中并非被访问最多的轨迹。
4.4.4 生态系统成熟度
DARS-Agent 与 SWE-agent 之间的关系说明了当前生态系统的成熟度状况。当 DARS-Agent 需要在 SWE-agent 的 ReAct 循环之上添加树搜索能力时,它复制并修改了整个代码库而非扩展它:agents.py 是原始 SWE-agent Agent 类的 700 行副本,dars_agent.py 是一个 1382 行的并行重新实现,加入了树搜索逻辑。这种基于分叉的复用意味着任一项目中的缺陷修复和改进都不会传播到另一个项目。
mini-swe-agent 采取了相反的方法,复用 SWE-agent 的执行环境(包括其 SWE-ReX Docker 和 Modal 后端),同时在其之上定义自己的抽象。它将 agent、model 和 environment 指定为 Python Protocols——一种结构化类型 [^32],即任何拥有正确方法的对象自动符合该接口。这使得在不修改 mini-swe-agent 代码的情况下替换为其他实现成为可能。
对同一上游项目同时存在基于分叉和基于依赖的复用,表明生态系统尚未围绕干净的扩展点稳定下来。Moatless Tools 的双流架构(Section 4.1.1)提供了这种稳定化的一种预示:逐步逻辑与编排策略之间的干净分离,使得在顺序模式和树搜索模式之间切换成为一个配置选择。
4.4.5 IDE 作为架构
Cline 是语料库中唯一一个作为 IDE 扩展而非独立 CLI 或服务器运行的智能体 [^43]。这一架构选择使其能够获取 CLI 智能体无法获得的一类上下文:IDE 自身对项目的理解。
例如,@problems 提及调用 VS Code 的诊断 API,使智能体能够访问与开发者在编辑器"Problems"面板中看到的相同的类型错误、lint 警告和构建失败。@terminal 提及访问集成终端输出,命令在可见的终端面板中通过 VS Code 终端 API 执行,因此用户可以实时观察命令运行。FileContextTracker 监控模型在各轮次中已查看、读取或修改的文件,检测外部修改以防止差异编辑时的上下文过时。
其权衡是平台锁定。这些能力依赖于 VS Code 的扩展 API,Cline 的核心功能(诊断集成、文件监控、检查点 Git 集成)无法在 VS Code 之外运行。代码库显示出持续解耦的迹象(一个独立的终端管理器、一个 CLI 模式),但最丰富的上下文来源仍然依赖于 VS Code。