SWE-agent
一句话定位
SWE-agent 是 Princeton NLP 团队提出的、以「Agent-Computer Interface (ACI)」为核心设计理念的自动化软件工程 harness(论文 arXiv:2405.15793),核心贡献是定制化的文件查看/编辑/搜索工具而非通用 shell access;仓库当前(分析时点)README 明确声明开发重心已转移到姊妹项目 SWE-agent/mini-swe-agent,本文分析的是 SWE-agent 1.0(本体仓库)架构,非 mini-swe-agent。
核心架构总览(目录结构关键路径 + 引用的 commit)
分析基于 commit 0363b9ef787a667d96120e132e8d3d59a692adcd(2026-07-06 docs fix,depth-1 clone)。仓库 MIT 协议,文档站 https://swe-agent.com/latest/ 。
关键目录:
sweagent/agent/—agents.py(DefaultAgent/RetryAgent主循环,1294 行)、models.py(LiteLLMModel/HumanModel/ReplayModel,903 行)、history_processors.py(上下文压缩,399 行)、reviewer.py(best-of-N 评审/重试,664 行)、action_sampler.py(单步集成采样,317 行)、hooks/abstract.py(生命周期 hook 接口)sweagent/tools/—tools.py(工具安装/黑名单/状态获取,430 行)、parsing.py(多种 parser,621 行)、commands.py(Command/Argumentschema,223 行)、bundle.py(插件/bundle 机制)sweagent/environment/—swe_env.py(276 行,SWE-ReX 的薄封装)、repo.py(仓库重置逻辑)sweagent/run/—run_single.py(单实例入口)、run_batch.py(442 行,多实例并行)sweagent/inspector/server.py— 本地轨迹查看 HTTP servertools/— ~14 个一手 bundle(registry、edit_anthropic、windowed*、search、submit、forfeit、review_on_submit_m等)config/default.yaml— 系统/实例 prompt 模板、parser 配置、工具 bundle 装配的规范样例
姊妹仓库:SWE-agent/mini-swe-agent(当前开发重心)、SWE-agent/SWE-ReX(实际沙箱执行后端,本仓库只是其薄封装)、SWE-bench/SWE-bench、SWE-bench/SWE-smith、SWE-bench/sb-cli。
Agent Loop(主循环 / 何时继续何时停)
主循环入口 DefaultAgent.run()(agents.py:1265-1294):while not step_output.done: step_output = self.step()。
step()(agents.py:1235-1263)调用forward_with_handling(),写轨迹、更新info(submission/exit_status/model_stats)。forward_with_handling()(agents.py:1062-1218)是带重试的包装层,max_requeries默认 3(DefaultAgentConfig.max_requeries,agents.py:158)。可恢复错误(格式错误、动作被拦截、bash 语法错误)会把错误信息追加进历史后重新询问模型(不永久污染历史,只记入轨迹);不可恢复错误(超预算、超上下文窗口、环境死亡、运行时错误、重试耗尽)触发attempt_autosubmission_after_error(),尝试抽取 git diff 并强制step.done = True。forward()(agents.py:1006-1060):self.model.query(history)→self.tools.parse_actions(output)解析 thought/action →handle_action(step)。handle_action()(agents.py:936-1004):检查should_block_action(黑名单)、处理字面"exit"动作、通过self._env.communicate(...)在持久 shell 会话中执行真实 bash 命令、处理CommandTimeoutError(连续超时达到max_consecutive_execution_timeouts默认 3 次后杀死 agent,tools.py:150)、最后handle_submission()检测提交信号。- 停止条件:
submit工具运行(写/root/model.patch,通过魔法字符串<<SWE_AGENT_SUBMISSION>>识别,来自tools/submit/bin/submit,已核实脚本内容:git add -A && git diff --cached > /root/model.patch && echo "<<SWE_AGENT_SUBMISSION>>");字面exit动作;exit_forfeit工具(tools/forfeit,魔法字符串###SWE-AGENT-EXIT-FORFEIT###,agents.py:221);超预算(CostLimitExceededError/TotalCostLimitExceededError);超上下文窗口;连续超时过多;总执行时间超限(total_execution_timeout默认 1800s,tools.py:145);不可恢复的运行时/API 错误。 RetryAgent(agents.py:257-441)是包裹DefaultAgent的元循环:可在总cost_limit下重启整个 agent(_next_attempt→env.hard_reset()+ 全新DefaultAgent)多次,再用评审机制挑选最佳尝试(见「自进化能力」)。
记忆与上下文管理(压缩、长期记忆、会话持久化)
历史结构是 role/content 字典的扁平列表(sweagent/types.py: History/HistoryItem);DefaultAgent.messages 属性(agents.py:539-551)在发给模型前应用一条 history_processors 处理链——这是压缩层所在。
history_processors.py 实现的可插拔判别联合类型(discriminated union,history_processors.py:390-399):
DefaultHistoryProcessor— 无操作直通。LastNObservations(85-176)— 经典 0.7 版策略:只保留最近 n 条 observation,旧的替换为"Old environment output: (n lines omitted)";支持polling(批量改变省略窗口,利于 prompt caching)与按 tag 覆盖(always_keep_output_for_tags/always_remove_output_for_tags)。ClosedWindowHistoryProcessor(215-258)— 针对窗口化文件查看工具:同一文件的历史 view 只保留最后一次展示,其余替换为占位符,避免大文件重复出现在多轮上下文里。CacheControlHistoryProcessor(261-302)— 给最近 N 条 user/tool 消息加 Anthropic prompt-caching 的cache_control: {"type": "ephemeral"}标记;这是config/default.yaml的默认处理器(last_n_messages: 2)。RemoveRegex(305-337)— 对除最后 N 条外的历史剥离任意正则模式(默认剥离<diff>...</diff>)。ImageParsingHistoryProcessor(340-387)— 把嵌入的 base64 markdown 图片转成规范的多模态image_urlcontent block。TagToolCallObservations(179-212)— 给特定工具调用 observation 打 tag,供上面的”always keep”逻辑使用。
未发现跨会话/长期记忆存储——记忆管理完全是单个 problem instance 内的事。会话持久化 = 每步后写入的 .traj JSON 文件(agents.py:779-787, save_trajectory()),是磁盘持久化状态,但不会自动回灌进活跃 agent 的上下文,只用于事后分析/重放(ReplayModel, models.py:464-526,逐字重放历史 .traj 的动作)。
环境侧的小型持久状态:tools/registry/lib/registry.py 的 EnvRegistry——一个位于 /root/.swe-agent-env 的 JSON 文件,工具脚本可读写以在同一容器会话的多次工具调用间持久化状态(因为每次工具调用都是独立子进程,环境变量不传播)。
templates.max_observation_length(默认 100,000 字符,agents.py:79)截断单条 observation,附带模板化警告(next_step_truncated_observation_template, agents.py:69-77)告诉模型改用 head/tail/grep 而非整体输出。
上下文窗口溢出是一等异常:ContextWindowExceededError 触发立即强制自动提交(agents.py:1175-1179),而非进一步压缩——即 SWE-agent 的压缩是静态/配置时确定的(history processor 提前选好),不是溢出触发的自适应压缩。
工具体系(定义/调用协议/注册/权限)
工具是 Command 对象(sweagent/tools/commands.py):name、docstring、arguments: list[Argument](每个含 type/description/required/enum/argument_format——渲染成 shell 调用的 Jinja 模板),可选 signature 覆盖,可选 end_name(标记多行/heredoc 命令)。
Command.get_function_calling_tool()(commands.py:133-165)把 Command 转成 OpenAI 风格的 function-calling JSON schema——当 parse_function.type == function_calling 时这就是发给模型的内容。
工具注册:ToolConfig.bundles: list[Bundle](tools.py:83)+ 内置的 BASH_COMMAND(除非 enable_bash_tool=False 始终可用)。Bundle(sweagent/tools/bundle.py,已读取源码确认)是一个目录:config.yaml(BundleConfig:tools: dict[str, dict] + 可选 state_command)+ bin/ 可执行脚本 + 可选 install.sh。跨 bundle 重名工具在配置构建期直接抛 ValueError(tools.py:178-187)。
工具安装入沙箱:ToolHandler.install() → _install_commands()(tools.py:292-312)把每个 bundle 目录上传到容器(/root/tools/<bundle_name>/)、chmod +x、运行 bundle 的 install.sh(如有)、把 bin/ 加入 $PATH 前部,然后用 which 验证每个声明的命令确实可解析(_check_available_commands)——这发生在容器启动阶段,非每次调用。
调用协议取决于配置的 parser(见 Prompt 设计一节):解析出的 thought+action 通过 Command.invoke_format 变成字面 bash 命令字符串,在持久 shell 会话中直接执行(SWEEnv.communicate)——即没有独立的结构化”工具调用”RPC 送到沙箱;function-calling 只用在模型 API 边界,之后还是被翻译回普通 shell 命令。多行命令(设置了 end_name)通过 _guard_multiline_input(tools.py:382-409)转成 heredoc。
权限:ToolFilterConfig(tools.py:29-72)是静态黑名单,不是动态审批门:blocklist(前缀匹配,如 vim/emacs/nano/gdb/less/tail -f/make)、blocklist_standalone(精确匹配,如裸 python/bash/su)、block_unless_regex(如 radare2/r2 仅在带 -c ... 调用时放行)。被拦截动作抛 _BlockedActionError → 走 requery 循环并附 blocklist_error_template(默认:“Operation ‘{{action}}’ is not supported by this environment.“)。该代码库没有面向工具调用的交互式人工审批门——唯一的人在环路径是独立的 HumanModel/human 模型类型,由人(非模型)直接输入动作(models.py:344-443)。
submit 工具与 exit_forfeit 工具按名字特殊处理(ToolConfig.submit_command 默认 "submit",通过 check_for_submission_cmd 中的魔法字符串 <<SWE_AGENT_SUBMISSION>> 检测,tools.py:372-376)。
Prompt 设计(系统提示结构、动态组装)
全部 prompt 都是 Jinja2 模板(jinja2.Template),逐步渲染,非静态字符串。TemplateConfig(agents.py:60-146)定义:system_template、instance_template(首个 user turn,即问题陈述)、next_step_template("Observation: {{observation}}")、next_step_truncated_observation_template、next_step_no_output_template、shell_check_error_template、command_cancelled_timeout_template,可选 strategy_template、可选 demonstration_template。
动态组装发生在 _get_format_dict()(agents.py:658-673):合并 tools.config.command_docs(自动生成的工具文档字符串)、tools.config.env_variables、问题陈述文本、仓库名,以及问题陈述对象的任意额外字段——全部作为 Jinja 变量注入每个模板。
具体地,config/default.yaml 的系统提示很简短(“You are a helpful assistant that can interact with a computer to solve tasks.“)——多数任务特定指导在 instance_template 里,是一个嵌在 YAML 配置(非 Python)中的 5 步流程(定位相关代码 → 复现 bug 脚本 → 改源码 → 重跑复现 → 考虑边界情况)。
function-calling 模式下模型实际看到的是工具 schema(而非自然语言文档);非 function-calling 的 parser(thought_action、xml_thought_action 等)需要在系统/实例模板里显式包含 {{command_docs}},模型才能纯靠文本发现可用工具(tools/parsing.py 模块 docstring, 29-33 行)。
Demonstration(few-shot 轨迹)可作为单条格式化消息注入(demonstration_template)或逐步重放进历史(put_demos_in_history=True)——agents.py:617-656。
错误恢复提示也是模板:format_error_template 默认取当前 parser 自身的 error_message,后者本身按 Jinja {% if error_code == ... %} 分支处理不同的 function-calling 失败模式(缺工具调用、多个工具调用、意外参数——见 parsing.py:236-252 XMLFunctionCallingParser.error_message 和 374-392 FunctionCallingParser.error_message)。
Router / 编排(任务分解、多 agent、子 agent)
未发现”planner 把任务拆成子任务、路由给专家 agent”的通用架构。实际存在的是:
RetryAgent(agents.py:257-441):串行多次尝试编排——跑完一个完整DefaultAgent,评审打分,可选再开一次全新尝试(带环境hard_reset()),直到cost_limit/max_attempts耗尽,再选出胜者。这是时间维度上的尝试级并行,不是单实例上的并发多 agent 协作。ActionSampler(action_sampler.py):单步(非单集)级别的集成机制。AskColleagues(49-93 行):对当前步骤从同一模型采样n_samples个补全,拼成”你的同事们有以下想法”提示,让模型挑选/综合出最终动作——本质是套着”同事”多智能体外皮的轻量自一致性机制,仍是单模型实例串行调用,不是独立自治 agent。BinaryTrajectoryComparison(96-314 行):采样min_n_samples..max_n_samples个候选动作,过滤解析失败与重复项,再做成对锦标赛比较(“两位初级开发者建议…“)由 LM 评审选胜者。同样是单模型,无独立 agent 进程。
Chooser/Preselector(reviewer.py:242-372):作用于(来自RetryAgent的)整条尝试,而非单次尝试内的子 agent——LM 评审在若干独立跑完的尝试中挑最优轨迹,候选多时可先跑一遍更便宜的预筛选(PreselectorConfig)。run_batch.py的ThreadPoolExecutor并行(main_multi_worker, 268-289 行)是跨独立问题实例的编排(例如并行跑很多 SWE-bench 任务),不是单任务内的子 agent 分解。
结论:SWE-agent 实现的是 best-of-N / 重试选优编排模式(对同一 agent 架构做时间维度和采样维度的 ensembling),而非层级化的 planner→子agent 任务分解。sweagent/agent/ 或 sweagent/run/ 中未发现”spawn 子 agent 处理 X”的原语。
Skill / 插件体系
Bundle 机制(sweagent/tools/bundle.py)就是 skill/插件体系:每个 bundle 是自包含目录(config.yaml + bin/ 可执行文件 + 可选 lib/ + 可选 install.sh),在 agent 配置中通过 tools.bundles: [{path: tools/registry}, {path: tools/edit_anthropic}, ...] 声明(参见 config/default.yaml:41-44)。
Bundle 可声明 state_command(BundleConfig.state_command, bundle.py:14)——每次动作后运行的 shell 命令,抽取结构化状态(如当前打开文件、工作目录)到 /root/state.json,由 ToolHandler.get_state()(tools.py:337-348)读回并合并进下一条 observation 的模板变量。
Bundle 可通过 hidden_tools 对模型隐藏特定工具,同时仍供内部使用(bundle.py:19,37-40,52-57)——用于不打算被 LM 直接调用的辅助脚本。
仓库自带约 14 个一手 bundle,位于 tools/:registry(状态持久化库,始终加载)、edit_anthropic(Anthropic 风格文件编辑器)、windowed/windowed_edit_linting/windowed_edit_replace/windowed_edit_rewrite(窗口化文件查看/编辑器家族——ACI 论文的定制文件查看器,本次未深入读实现)、search(search_dir/find_file/search_file——ACI 论文的定制搜索工具)、submit、forfeit、review_on_submit_m、diff_state、filemap、web_browser、image_tools、multilingual_setup。每个都可按配置独立插拔——是真正的插件架构,非硬编码工具列表。
未发现动态/运行时插件发现机制(如扫描 marketplace 或从 URL 加载)——bundle 在 agent 构建时通过本地文件系统路径在 YAML 配置中静态引用。
自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)
未发现在线学习/权重更新/持久化跨集学习记忆——这明确超出该代码库的范围(SWE-agent 是推理时 harness,不是训练循环)。
存在的是单个问题实例内的 eval 驱动重试/自我纠错,机制在 reviewer.py:
Reviewer.review()(375-449 行):LM-as-judge 对已完成轨迹采样n_sample(默认 5,ReviewerConfig.n_sample)次独立打分,取平均(可选按方差惩罚reduce_by_std),并在尝试未干净submit时施加failure_score_penalty。ScoreRetryLoop(559-658 行):每次尝试后调用评审;若得分 <accept_score且预算/次数尚有余量,触发下一次完整尝试(RetryAgent._next_attempt,agents.py:321-326,做环境硬重置 + 全新 agent)。最终get_best()选出评审分最高的轨迹(同分按 API 调用数最少/最便宜打破平局)。ChooserRetryLoop(499-556 行):更简单的变体——不做每次尝试打分,收集 N 次尝试后让 LMChooser在最后一次性挑出最优(候选多时可选先跑Preselector缩小范围)。
这是”通过重采样 + LM 评审做自我纠错”,即推理时 eval 驱动纠错,不是跨不同问题实例持久化的学习/适应机制。该代码库中未发现微调、梯度更新或跨运行持久化的技能/策略记忆。
轨迹可转换为未来运行的 few-shot demonstration(docs/config/demonstrations.md,本次仅引用未精读;另有 sweagent/run/run_traj_to_demo.py 存在但本次未打开)——这是”从过去运行中学习”最接近的形态,但属于人工/离线策展步骤(人挑一条好轨迹转成 demo),非自动。
可观测性(日志 / trace 格式)
通过 Python logging 做结构化日志,每个子系统有 emoji 前缀的具名 logger(get_logger("swea-agent", emoji="🤠")、"swea-tools"、"swea-env"、"swea-lm"、"swea-run"、"reviewer"、"chooser_loop" 等),定义在 sweagent/utils/log.py(本次未精读,但使用遍布全代码库)。
每实例多级别日志文件:<instance_id>.trace.log、.debug.log、.info.log(run_batch.py:411-420, _add_instance_log_file_handlers),外加共享的 run_batch.log。
轨迹格式:.traj 文件为 JSON,每步后写入(DefaultAgent.save_trajectory,agents.py:779-787)。顶层字段:trajectory(TrajectoryStep 列表:action、observation、response(LM 原始输出)、thought、execution_time、state(环境状态字典)、query(发给 LM 的完整消息列表,自 SWE-agent 1.1.0 起替代旧的 message 字段,见 docs/usage/trajectories.md:27-30)、extra_info)、history(整个episode的完整原始消息列表)、info(AgentInfo:submission、exit_status、model_stats、编辑文件上下文片段)、replay_config、environment 名。
sweagent/inspector/server.py — 本地 HTTP server(http.server/socketserver),读取 .traj 文件供人类浏览的静态 Web UI(sweagent/inspector/static.py),通过 sweagent inspector CLI 子命令启动(sweagent/run/inspector_cli.py,本次未打开)。
成本/用量跟踪本身也是一种可观测性:InstanceStats(models.py:292-308:instance_cost、tokens_sent、tokens_received、api_calls)按 agent 记录,外加进程级 GlobalStats/GLOBAL_STATS 单例(线程锁保护,models.py:273-289)跟踪一次 run-batch 调用中所有并发实例的 total_cost 与 last_query_timestamp。
run_batch.py 的 RunBatchProgressManager(来自 sweagent/run/_progress.py,未打开)配合 rich.live.Live 渲染跨并行 worker 的终端实时进度表,并写出 run_batch_exit_statuses.yaml 汇总每实例退出状态。
安全与权限(审批门、密钥管理)
不存在面向自治工具执行的交互式人工审批门——模型提出的每个动作(一旦解析且未被黑名单拦截)都立即在沙箱中执行。唯一的”人在环”模式是 HumanModel/human_thought 模型类型,由人直接替代 LM输入动作(models.py:344-461)——这是调试/手动驾驶模式,不是叠加在 LM agent 上的审批层。
安全由「工具体系」一节所述的静态 ToolFilterConfig 黑名单实现(拦截已知危险/交互式命令:编辑器、gdb、nohup、make、裸 shell/python 调用等),并对 radare2 等工具设正则门控例外。
密钥管理(GenericAPIModelConfig, models.py:66-201,及 docs/installation/keys.md):
- 密钥可通过环境变量、
.env文件(load_environment_variables()加载)或--agent.model.api_keyCLI flag 解析。 api_key: SecretStr | None—— 用 pydanticSecretStr避免原始值意外出现在 repr/日志中。- 支持用
:::分隔符拼接多个密钥并按线程轮转(choose_api_key_by_thread,models.py:119-190),使并行run-batchworker 获得缓存友好的一致密钥或随机分散的密钥。 propagate_env_variables: list[str](tools.py:86-92)明确警示:“the value of the environment variables can be read in debug log files, so be careful with your API keys”——代码库自身标记了一条真实的密钥泄露风险路径(把宿主密钥透传进沙箱化工具环境时)。- 仓库根目录
.env.example只文档化了GITHUB_TOKEN(用于克隆仓库/开 PR);模型 provider 密钥(OPENAI_API_KEY、ANTHROPIC_API_KEY等)在docs/installation/keys.md中说明,但未在.env.example里硬编码/模板化。
内容策略处理:litellm 抛出的 ContentPolicyViolationError 被当作值得重采样的软失败捕获(agents.py:1130-1134),非硬停止——agent 只是重新查询。
沙箱与执行隔离
SWE-agent 1.0 的环境层(sweagent/environment/swe_env.py)官方文档明确说是”如今只是我们 SWE-ReX 包的薄封装”(docs/background/architecture.md:8)——真正的沙箱化/进程隔离逻辑在独立的 SWE-agent/SWE-ReX 仓库(https://swe-rex.com),**不在本仓库内**。这是本 dossier 的重要范围边界:命名空间/cgroup/进程隔离的具体细节不在 SWE-agent 仓库本身。
SWE-agent 确实控制的部分:EnvironmentConfig.deployment: DeploymentConfig(swe_env.py:24-49),默认 DockerDeploymentConfig(image="python:3.11")——即默认隔离单元是 Docker 容器。部署抽象(swerex.deployment.abstract.AbstractDeployment)也支持远程后端(文档提及 modal、aws;docs/background/architecture.md:9 明确把 Docker vs. Modal/AWS 等远程系统列为可互换的 Deployment 后端)。
容器内,SWE-ReX 启动一个持久 bash 会话(CreateBashSessionRequest(startup_source=["/root/.bashrc"], ...), swe_env.py:184-188),所有 agent 动作都通过 communicate()(swe_env.py:197-232)在其中执行,后者封装 deployment.runtime.run_in_session(BashAction(...))。这意味着状态(cwd、环境变量、打开的 shell 变量)在一个实例的多轮间自然持久——shell 会话本身就是状态/隔离单元。
尝试间的仓库/代码库隔离:_reset_repository()(swe_env.py:149-166)运行 git fetch && git status && git restore . && git reset --hard && git checkout <base_commit> && git clean -fdq 把仓库恢复到干净状态——这是 RetryAgent 多次尝试之间避免互相污染而不用重建整个容器的方式(相对更昂贵的 hard_reset() 会停止+重启整个 deployment)。
执行超时按命令强制(execution_timeout,默认 30s,tools.py:139),并按 episode 累计强制(total_execution_timeout,默认 1800s,tools.py:145),加上连续超时达 max_consecutive_execution_timeouts(默认 3)后的硬性截断(tools.py:150-152,在 agents.py:968-982 强制执行)。
本仓库中未发现”直接在宿主机无隔离运行工具调用”的模式——Docker(或远程沙箱化 deployment)是贯穿全文档的默认与隐含假设。
与模型的协同设计
Provider 抽象层是 litellm(sweagent/agent/models.py 引入 litellm),即 SWE-agent 设计上是显式多模型/多 provider 的,而非为单一特定模型家族协同设计——但代码中有若干值得注意的 provider 特定特殊处理,这是”模型协同设计”最接近的证据:
- Anthropic 特定:
CacheControlHistoryProcessor(prompt caching 标记)是config/default.yaml中的默认历史处理器,docstring 明说”Use this when running with anthropic claude”(history_processors.py:261-264)。 - Claude 3.7/Sonnet-4 的最大输出 token 特殊处理:
models.py:608-620—— 检测模型名中的claude-3-7-sonnet/claude-sonnet-4,默认把max_output_tokens设为 64000,除非设置了anthropic-beta: output-128k-2025-02-19额外 header,并给出明确警告日志告诉用户如何解锁 128k 输出。 anthropic_beta/thinking_blocks支持:StepOutput/历史项携带thinking_blocks字段(agents.py:1046;history_processors.py不处理它,但models.py:774-778,861-864会透传)——即扩展思维/推理轨迹的保留对能产出它的模型(Claude extended thinking/推理模型)端到端打通。- o1 模型适配:
convert_system_to_user: bool配置项(models.py:98-101)——“useful for models that do not support system messages like o1”。 - Function-calling 能力检查:
LiteLLMModel.__init__(models.py:587-594)调用litellm.utils.supports_function_calling(model=...),若配置模型不支持 function-calling 而parse_function设为该类型,则警告(非硬失败)。 - 多种 parser 策略专门用于适配指令遵循较弱或不支持 function-calling 的模型(
thought_action、xml_thought_action、xml_function_calling面向输出 XML 风格工具调用的开放权重模型、json、all_bash_code_blocks)——tools/parsing.py模块 docstring 明确把FunctionCallingParser定为能力较强模型的推荐路径,其余作为兜底。 - 模型-分词器协同设计:
custom_tokenizer配置项(models.py:146-150)允许覆盖用于 token 计数/上下文窗口检查的分词器——对不在 litellm 默认注册表里的本地/开放权重模型有用。
未发现 SWE-agent 是”为某个特定前沿模型量身打造”的证据(不同于作为某模型自有产品一部分发布的 harness);它是模型无关的,叠加了务实的按 provider 适配。
轨迹利用(session/trajectory 是否反哺训练/评测)
直接证据表明轨迹反馈进评测:sweagent/run/hooks/swe_bench_evaluate.py(在 run_batch.py:223-233 中被引用,本次未精读)——一个 RunHook,作为 run-batch 的一部分触发 SWE-bench 评测(continuous_submission_every=30),直接把轨迹产出(preds.json,由 sweagent/run/merge_predictions.py 生成)接入 SWE-bench 评测 harness(sb-cli,README 中引用)。
直接证据表明轨迹反馈进训练相关数据产品:sweagent/run/run_traj_to_demo.py(文件名强烈暗示”轨迹→demonstration”转换,文档中引用但本次未打开该文件)与 docs/config/demonstrations.md(本次未精读)——轨迹可以变成 few-shot demonstration,通过 TemplateConfig.demonstrations(agents.py:90-93,617-656)反馈进未来的 agent 运行。
README 链接了 SWE-bench/SWE-smith(生成 SWE-bench 风格训练数据/任务的姊妹项目)并引用了 SWE-agent-LM-32b(一个开放权重模型,README.md:42)——强烈的旁证表明 SWE-agent 的轨迹/环境被用于上游训练专用代码 agent 模型,但实际训练流水线在本仓库之外(在 SWE-smith / SWE-agent-LM 训练代码里),本次未检视。
单次运行内,轨迹也被 reviewer/chooser(见「自进化能力」)消费用于推理时 best-of-N 选择——这是一种”轨迹复用”,但停留在单个问题求解 episode 内,不是跨 episode 学习。
本仓库内未发现从 .traj 文件自动反馈进持久化记忆或微调循环的机制——所有此类利用(SWE-smith、SWE-agent-LM、demo 策展)依据 README/文档引用来看,都是手动/离线/仓库外发生的,本仓库代码中没有对应实现。
与同类 harness 的关键差异(1-3 条,可以先留一句概述,后续 synthesis 阶段会做跨 harness 对比)
- ACI(Agent-Computer Interface)是其立身之本:不像很多 harness 直接给模型裸 shell 或通用 file-edit 工具,SWE-agent 的核心论文贡献就是定制化的窗口化文件查看器(
tools/windowed*)与搜索工具(tools/search),刻意约束/塑造模型与环境的交互面,而非追求最大自由度。 - 编排策略是”同架构多次采样选优”而非”层级化子 agent 分解”:
RetryAgent/ActionSampler/Reviewer/Chooser一整套机制都是在单一DefaultAgent架构上做时间维度(多次尝试)和采样维度(单步多候选)的 ensembling,与规划器→专家子agent 的路由范式明显不同,值得在跨 harness 对比中重点标注。 - 执行隔离层完全外包给独立项目(SWE-ReX):本仓库只声明 Deployment 配置(Docker/Modal/AWS),真正的沙箱机制不在本仓库源码内,这与一些”隔离逻辑与 agent 逻辑同仓库耦合”的 harness 形成对比,调研时需注意这个仓库边界。
(后续跨 harness synthesis 阶段再做系统对比)
原始源码定位
- repo: https://github.com/SWE-agent/SWE-agent
- commit/version analyzed:
0363b9ef787a667d96120e132e8d3d59a692adcd(depth-1 clone,2026-07-07;HEAD commit message: “docs: fix multimodal disable-image-processing flag hierarchy (#1445)“,日期 2026-07-06) - 关键文件列表(相对路径):
sweagent/agent/agents.pysweagent/agent/models.pysweagent/agent/history_processors.pysweagent/agent/reviewer.pysweagent/agent/action_sampler.pysweagent/agent/hooks/abstract.pysweagent/exceptions.pysweagent/tools/tools.pysweagent/tools/parsing.pysweagent/tools/commands.pysweagent/tools/bundle.pysweagent/environment/swe_env.pysweagent/environment/repo.py(部分读取)sweagent/run/run_single.pysweagent/run/run_batch.pysweagent/inspector/server.py(部分读取)tools/registry/lib/registry.pytools/forfeit/config.yaml+tools/forfeit/bin/exit_forfeittools/submit/bin/submitconfig/default.yamldocs/background/architecture.mddocs/background/aci.mddocs/installation/keys.mddocs/usage/trajectories.mddocs/config/environments.md.env.exampleREADME.md- 未深入读取(下阶段可跟进):
sweagent/agent/problem_statement.py、sweagent/agent/extra/shell_agent.py、sweagent/run/hooks/open_pr.py、sweagent/run/hooks/swe_bench_evaluate.py(完整版)、sweagent/run/run_traj_to_demo.py、docs/config/demonstrations.md、tools/windowed/*完整实现
一手源存档(sources/)
/Users/zhao/projects/self-wiki/ai-research/sources/harness/swe-agent/ 下:
NOTES.md— 完整 Stage 1 调研笔记(本文所有引用均核实自此文件及以下源文件)key-files/agents.py、key-files/models.py、key-files/history_processors.py、key-files/reviewer.py、key-files/action_sampler.py、key-files/agent_hooks_abstract.py、key-files/exceptions.pykey-files/tools.py、key-files/parsing.py、key-files/commands.py、key-files/bundle.pykey-files/swe_env.pykey-files/config_default.yamlkey-files/tools_registry_lib.py、key-files/tools_forfeit_config.yaml、key-files/tools_forfeit_exit_forfeit.sh、key-files/tools_submit_bin.shkey-files/docs_aci.md、key-files/docs_architecture.md、key-files/docs_environments.md、key-files/docs_keys.md、key-files/docs_trajectories.md