案例研究:Open SWE
"最好的内部工具是由每天使用它们的团队构建的。" — LangChain 团队
Open SWE(Open Source Software Engineer,开源软件工程师)是 LangChain 用于构建内部编码代理的开源框架。基于 LangGraph 和 Deep Agents 构建,它提供了一个生产就绪的架构,反映了 Stripe、Ramp 和 Coinbase 等精英工程组织使用的内部编码代理。
项目: langchain-ai/open-swe 技术栈: Python, LangGraph, Deep Agents, Modal/Daytona 沙箱 许可证: MIT
1. 项目概述与重要性
什么是 Open SWE?
Open SWE 是一个异步、云原生的编码代理框架,它能够:
- 接收来自 Slack、Linear 或 GitHub 提及的任务
- 为每个任务生成隔离的沙箱
- 编排多代理工作流来规划、实现和审查代码更改
- 自动创建与原始工单链接的拉取请求
它代表了内部工程工具的民主化——使任何开发团队都能使用万亿美元公司使用的相同架构模式。
为什么这很重要
问题: 精英工程组织(Stripe、Ramp、Coinbase)已经构建了强大的内部编码代理,但它们的实现是专有的。行业缺乏开源的参考架构。
Open SWE 的影响:
- 参考架构: 为内部编码代理提供生产蓝图
- 组合优于分叉: 基于 Deep Agents 框架构建,支持升级和定制
- 可插拔设计: 可以交换沙箱、模型、工具和触发器
- 社区创新: 为特定于组织的扩展提供开放基础
与专有系统的关系
| 公司 | 内部工具 | Open SWE 等效方案 |
|---|---|---|
| Stripe | Minions | 多代理编排,规则文件 → AGENTS.md |
| Ramp | Inspect | 基于 OpenCode 构建 → Deep Agents |
| Coinbase | Cloudbot | Slack 原生,Linear 优先集成 |
2. 代理架构(核心重点)
这是 Open SWE 的核心——一个基于 LangGraph 状态机架构构建的复杂多代理系统。
高级架构
四代理系统
Open SWE 实现了一个专门的多代理架构,其中每个代理都有明确的职责:
1. 管理代理
角色: 入口点和协调器
# 高级概念(不是实际代码)
manager_agent = Agent(
name="manager",
system_prompt="路由任务和协调工作流",
decisions=[
"route_to_planner", # 需要研究的新任务
"route_to_programmer", # 简单直接的修复
"respond_complete", # 任务成功完成
"respond_error" # 任务失败
]
)
职责:
- 从 Slack/Linear/GitHub 接收初始任务
- 解析上下文(工单描述、线程历史)
- 决定是否路由到规划代理或程序员代理
- 协调代理之间的交接
- 将最终响应发送回触发源
2. 规划代理
角色: 编码前的研究和规划
# 概念:规划代理的工作流
planner_agent = Agent(
name="planner",
tools=[ls, grep, read_file, glob, fetch_url],
system_prompt="分析代码库并创建逐步计划",
output="structured_todos"
)
职责:
- 研究代码库使用文件操作
- 分析 GitHub 问题或 Linear 工单
- 创建使用
write_todos工具的结构化计划 - 识别需要修改的文件
- 提出逐步执行策略
使用的关键工具:
| 工具 | 用途 |
|---|---|
ls | 列出目录内容 |
grep | 搜索代码模式 |
read_file | 读取文件内容 |
glob | 按模式查找文件 |
fetch_url | 获取文档 |
3. 程序员代理
角色: 实现计划好的更改
# 概念:程序员代理的工作流
programmer_agent = Agent(
name="programmer",
tools=[write_file, edit_file, execute, http_request],
system_prompt="根据计划实现更改",
constraints=["run_linters", "run_tests", "ensure_tests_pass"]
)
职责:
- 执行规划代理创建 的计划
- 写入/编辑沙箱中的文件
- 运行代码检查器和格式化工具
- 执行测试以验证更改
- 迭代直到测试通过
使用的关键工具:
| 工具 | 用途 |
|---|---|
write_file | 创建新文件 |
edit_file | 修改现有文件 |
execute | 运行 shell 命令(npm test、black 等) |
http_request | 发出 API 调用 |
4. 审查代理
角色: 发布前验证
# 概念:审查代理的工作流
reviewer_agent = Agent(
name="reviewer",
tools=[execute, read_file, git_diff],
system_prompt="审查更改并确保质量",
checks=["code_quality", "test_coverage", "documentation"]
)
职责:
- 审查所有代码更改
- 运行最终验证测试
- 检查边界情况
- 确保代码检查器和格式化工具通过
- 减少构建失败
LangGraph 状态机
代理使用 LangGraph 进行编排,它提供:
为什么使用 LangGraph?
- 确定性转换: 代理之间清晰的交接
- 状态持久化: 长时间运行的任务保持内存
- 循环预防: 防止无限代理循环
- 人工监督: 可以注入人工审查的检查点
- 表达力: 不限于单一认知架构
工具系统
Open SWE 遵循 Stripe 的见解:工具的精选比数量更重要。
核心工具
| 工具 | 类别 | 用途 |
|---|---|---|
execute | Shell | 在沙箱中运行命令(bash、python、npm) |
fetch_url | Web | 将网页作为 markdown 获取 |
http_request | API | 发出 HTTP 请求(GET、POST 等) |
commit_and_open_pr | Git | 提交更改 + 创建 GitHub 草稿 PR |
linear_comment | 通信 | 在 Linear 工单中发布更新 |
slack_thread_reply | 通信 | 在 Slack 线程中回复 |
Deep Agents 内置工具
| 工具 | 类别 | 用途 |
|---|---|---|
read_file | 文件系统 | 读取文件内容 |
write_file | 文件系统 | 创建新文件 |
edit_file | 文件系统 | 修改现有文件(基于差异) |
ls | 文件系统 | 列出目录内容 |
glob | 文件系统 | 按模式查找文件 |
grep | 文件系统 | 搜索文件内容 |
write_todos | 规划 | 创建结构化任务列表 |
task | 编排 | 生成子代理 |
工具设计原则
内存与上下文管理
AGENTS.md
Open SWE 读取存储在仓库根目录的 AGENTS.md 文件(如果存在)并将其注入到系统提示中。这是仓库级别的规则手册:
# AGENTS.md 示例
## 代码风格
- 使用 4 个空格进行缩进
- Python 遵循 PEP 8
- 提交前运行 `black` 和 `isort`
## 测试要求
- 所有新功能都需要单元测试
- 测试覆盖率不得下降
- 提交前运行 `pytest`
## 架构规则
- 使用依赖注入
- 没 有循环导入
- 数据库查询通过 repository 层进行
类比: 这是 Stripe 的"规则文件"概念——编码每个代理运行必须遵循的约定。
源上下文
Open SWE 在代理开始前组装丰富的上下文:
- Linear 工单: 标题、描述、所有评论
- Slack 线程: 完整的对话历史
- GitHub PR: 描述 + 审查评论
这可以防止代理"通过工具调用发现所有内容",并实现更快、更准确的响应。
基于文件的内存
对于大型代码库,Open SWE 使用基于文件的内存:
优势:
- 防止上下文溢出: 大型代码库不会耗尽令牌限制
- 持久化: 在代理重启和崩溃后存活
- 可查询: 代理可以搜索过去的交互
中间件系统
中间件在代理循环周围提供确 定性钩子:
关键中间件
# 概念:中间件链
middleware_chain = [
ToolErrorMiddleware(), # 优雅地捕获工具错误
check_message_queue_before_model, # 注入后续消息
open_pr_if_needed, # 自动提交安全网
]
1. ToolErrorMiddleware
目的: 防止级联故障
# 概念:错误处理
try:
result = tool.execute(**args)
except ToolError as e:
# 优雅地处理错误
return f"工具 {tool.name} 失败: {e}。请尝试替代方法。"
2. check_message_queue_before_model
目的: 启用实时人工引导
创新: 你可以在代理工作时向它发送消息,它将在下一步获取你的输入。
3. open_pr_if_needed
目的: PR 创建的安全网
# 概念:代理后钩子
if agent_finished and no_pr_created:
# 代理忘记打开 PR — 自动执行
commit_changes()
open_draft_pr()
notify_user("作为安全网打开了 PR")
设计理念: Stripe 确定性节点的轻量级版本——确保关键步骤发生,无论 LLM 行为如何。
子代理生成
task 工具支持并行子代理委托:
每个子代理都有:
- 自己的中间件栈
- 独立的待办列表
- 隔离的文件操作
- 单独的沙箱(如果需要)
用例: 在独立的子任务上并行工作(例如,前端 + 后端 + 测试)。