SWE-agent — 架构与原理
核对基准:克隆源
/Users/taiyou/Dev/OpenSource/ai-frontier-reference/aiRef/repos/swe-agent。 下文所有path:line引用均针对该克隆源核对。
SWE-agent 是什么 / 解决什么问题
SWE-agent 让你选定的语言模型(如 GPT-4o、Claude Sonnet)自主调用工具去
修复真实 GitHub 仓库里的 issue、查找安全漏洞,或执行自定义任务
(README.md:28-31)。它在 SWE-bench 上是开源项目中的 SOTA,设计哲学是
"把最大自主权留给 LM"、"全部行为由单个 YAML 文件统辖"
(README.md:33-36)。
它要解决的核心问题:LM 不是人,直接把人类用的 shell/编辑器丢给它,效果很差。 SWE-agent 的关键贡献是 ACI(Agent-Computer Interface)——一套专为 LM 设计的、反馈紧凑、出错可恢复的命令界面。换句话说,SWE-agent ≈ "一个把 LM 输出解析成命令、在沙箱里执行、再把结果喂回 LM 的循环" + "这套 ACI"。
注:克隆源
README.md:19-25标注当前主要开发已转向更精简的 mini-swe-agent,SWE-agent 仍是理解 ACI 与 agent 主循环的完整参考实现。
架构总览图
一次 run(env, problem_statement)
│
┌─────────────────────────▼──────────────────────────┐
│ DefaultAgent │
│ sweagent/agent/agents.py:443 │
│ │
│ run() ──loop──► step() ──► forward_with_handling │
│ :1265 :1235 :1062 (错误→重查) │
│ │ │
│ forward() :1006 │
│ │ │
│ ┌──────────────┐ thought+action ┌───────────┐ │
│ │ AbstractModel│◄──────────────────►│ToolHandler│ │
│ │ models.py:311│ model.query() │ tools.py │ │
│ │ (LM 推理) │ :320 │ :227 │ │
│ └──────┬───────┘ └─────┬─────┘ │
└──────────┼─────────────────────────────────┼────────┘
│ HTTP (LiteLLM) │ parse_actions :378
▼ ▼ 解析出的 shell 命令
┌─────────────────┐ ┌──────────────────────┐
│ LM API 端点 │ │ SWEEnv │
│ (OpenAI/Claude…) │ │ environment/swe_env.py:51│
└─────────────────┘ │ communicate() :197 │
└───────────┬──────────┘
│ run_in_session
▼ (SWE-ReX 运行时)
┌──────────────────────┐
│ 沙箱容器 + 目标 Repo │
│ + 注入的 ACI 工具 │
└──────────────────────┘
数据流一句话:LM 产出文本 → Parser 抽出 action → ToolHandler 转成 shell 命令 → SWEEnv 在沙箱执行 → observation 回灌进 history → 下一轮 LM 推理, 直到提交补丁或触发退出条件。
ACI — Agent-Computer Interface 核心理念
ACI 的落地形态是工具 Bundle:每个工具目录(克隆源 tools/ 下,如
search/、edit_anthropic/、submit/)包含一个 config.yaml 声明命令的
signature / docstring / arguments,外加 bin/ 下的可执行实现与
install.sh(见 tools/search/config.yaml:1-30、目录 tools/search/)。
- 一个
Bundle就是"一个带config.yaml的工具目录"(sweagent/tools/bundle.py:17), 其commands属性把 YAML 里的每条工具读成Command对象(sweagent/tools/bundle.py:52)。 - 这些 bundle 在 agent 启动时被安装进沙箱:
ToolHandler.install()(sweagent/tools/tools.py:252)调用_install_commands()(:292)把命令拷进环境。
设计要点(为 LM 而非人优化):命令签名精简、文档随命令一起暴露给 LM、
执行后由 _get_state() 抽取结构化状态(如当前打开文件、行号)回灌
(sweagent/tools/tools.py:317 的 _get_state,:337 的 get_state)。
主控制循环
主循环全部在 DefaultAgent(sweagent/agent/agents.py:443)中:
| 方法 | 位置 | 职责 |
|---|---|---|
run() | agents.py:1265 | 顶层入口;setup 后进入 while not step_output.done 循环,每步存轨迹(:1284-1286) |
step() | agents.py:1235 | 单步包装:调 forward_with_handling,更新 history、trajectory、info(:1252-1260) |
forward_with_handling() | agents.py:1062 | 包裹 forward,捕获异常并按需重查模型(bash 语法错等可恢复错误) |
forward() | agents.py:1006 | 不处理错误的核心:model.query(history) → parse_actions 得到 thought/action → handle_action 执行(:1042-1052) |
add_step_to_history() | agents.py:714 | 把动作与 observation 追加进消息历史 |
attempt_autosubmission_after_error() | agents.py:823 | 出错时尝试自动提交已有改动,避免白跑 |
循环终止条件:step_output.done 为真(agents.py:1284),由提交命令、退出状态
或执行超时(_TotalExecutionTimeExceeded,agents.py:215、触发点 :1018-1019)决定。
forward() 内的解析委托给工具层:step.thought, step.action = self.tools.parse_actions(output)
(agents.py:1045),对应 ToolHandler.parse_actions(sweagent/tools/tools.py:378)。
工具与命令
解析路径(LM 文本 → 可执行命令)由 sweagent/tools/parsing.py 的一族
parser 承担,均实现 AbstractParseFunction.__call__(parsing.py:52,61):
| Parser | 位置 | 适用 |
|---|---|---|
ThoughtActionParser | parsing.py:109 | 思考+代码块格式(默认家族) |
XMLThoughtActionParser | parsing.py:168 | XML 包裹的思考/动作 |
FunctionCallingParser | parsing.py:371 | 原生 tool-calling API |
JsonParser | parsing.py:455 | JSON 动作 |
Identity | parsing.py:354 | 直通,不解析 |
ToolConfig(sweagent/tools/tools.py:75)声明工具集与解析方式,其
use_function_calling(:155)、commands(:168)、tools(:194)等属性
把 bundle 汇总成模型可见的命令清单。ToolHandler(:227)则负责安装、复位
(reset :256)、阻断危险动作(should_block_action :353)、检测提交命令
(check_for_submission_cmd :372)。
模型抽象
所有模型实现统一接口 AbstractModel(sweagent/agent/models.py:311),核心方法
query(history, ...)(:320)。具体实现:
| 实现 | 位置 | 用途 |
|---|---|---|
LiteLLMModel | models.py:578 | 经 LiteLLM 接 OpenAI/Anthropic 等多家 API(生产路径) |
HumanModel | models.py:344 | 人在回路,手动输入动作 |
HumanThoughtModel | models.py:446 | 人类输入思考+动作 |
ReplayModel | models.py:464 | 回放已有轨迹 |
InstantEmptySubmitTestModel | models.py:551 | 测试用,立即空提交 |
LiteLLMModel 内部 _single_query(models.py:679)、_query(:783)、
query(:794)负责真正的 API 调用、重试与成本统计(_update_stats :632、
InstanceStats :292)。工厂函数 get_model(models.py:875)按配置选实现。
配置与运行入口
单个 YAML 统辖全部行为。 克隆源 config/default.yaml 定义了
agent.templates(系统/实例提示词,config/default.yaml:4-25)等。配置目录还含
bash_only.yaml、coding_challenge.yaml、benchmarks/、human/ 等多套预设。
运行入口:
| 入口 | 位置 | 说明 |
|---|---|---|
sweagent CLI | sweagent/run/run.py:37 (get_cli)、:70 (main) | 顶层命令分发 |
| 单实例运行 | sweagent/run/run_single.py:125 (RunSingle)、:188 (run) | 跑一个 problem |
| 批量运行 | sweagent/run/run_batch.py | 跑数据集(如 SWE-bench) |
| 入口模块 | sweagent/__main__.py | python -m sweagent |
RunSingle.run()(run_single.py:188)最终调用 agent.run(env, problem_statement, output_dir),
即上文的主循环;run_from_config / run_from_cli(run_single.py:210,214)为薄封装。
环境侧 SWEEnv(sweagent/environment/swe_env.py:51)管理沙箱生命周期:
start()(:109)、reset()(:135)、communicate()(:197,经 SWE-ReX 运行时
run_in_session 执行命令)、read_file/write_file(:234,252)、close()(:168)。
代码地图
| 模块 | 关键符号 | 引用 |
|---|---|---|
sweagent/agent/agents.py | DefaultAgent、run、step、forward、forward_with_handling | :443,1265,1235,1006,1062 |
sweagent/agent/agents.py | RetryAgent、AbstractAgent | :257,224 |
sweagent/agent/models.py | AbstractModel、LiteLLMModel、get_model | :311,578,875 |
sweagent/tools/tools.py | ToolConfig、ToolHandler、parse_actions、install | :75,227,378,252 |
sweagent/tools/parsing.py | AbstractParseFunction 及各 parser | :52,109,168,371,455 |
sweagent/tools/bundle.py | Bundle、commands | :17,52 |
sweagent/environment/swe_env.py | SWEEnv、communicate、reset、start | :51,197,135,109 |
sweagent/run/run.py | get_cli、main | :37,70 |
sweagent/run/run_single.py | RunSingle、run、run_from_cli | :125,188,214 |
config/default.yaml | 默认 agent 模板与配置 | :4-25 |
tools/ | 工具 Bundle 目录(search、edit_anthropic、submit…) | tools/search/config.yaml:1-30 |