Day 2: 从 100% 浪费到 95% 产出——效率优化的杠杆在哪里

十天写一个编码 Agent,第二天的主题是:找到浪费,消灭浪费。

回顾 Day 1 的问题

Day 1 我们搭了一个能跑通的框架,在 django__django-11179 上成功生成了正确的 patch。但仔细分析日志后发现了一个扎心的事实:

Agent 59% 的步骤是浪费的。

22 步中只有 5 步在真正解决问题,其余 13 步在做无用功。具体来说:

浪费类型步骤数原因
搜索不存在的测试8 步不知道 FAIL_TO_PASS 测试由评测框架注入
pip install4 步环境应由 harness 提前配置
修改测试文件1 步SWE-bench 明确禁止修改测试

这就是 Day 2 的切入点:不是让模型更聪明,而是不让模型做蠢事。

优化一:告诉 Agent 什么不该做

SWE-bench 有一个反直觉的设计:FAIL_TO_PASS 字段列出了修复后应该通过的测试,但这些测试可能不存在于当前代码库中——它们会在评测阶段由 harness 自动注入。

Day 1 的 Agent 不知道这一点,花了 8 步去找一个 test_fast_delete_instance_set_pk_none 测试,最终还自作主张写了一个。这不仅浪费了步骤,还可能导致评测失败(因为 Agent 修改了测试文件,导致 harness 注入 patch 时冲突)。

修复很简单,在系统提示词中加两句话:

- The test(s) listed above may NOT exist in the repo yet. 
  They will be added by the evaluation harness. 
  Do NOT create or modify any test files.
- The environment is already set up. Do NOT run pip install.

效果立竿见影。修改后 Agent 在遇到测试不存在时,不再死磕,而是直接说"这个测试会由评测框架添加",然后转向跑已有的测试来验证修复。

经验:编码 Agent 的效率瓶颈往往不是推理能力,而是对任务规则的理解。

优化二:把基础设施的活从 Agent 身上拿走

Day 1 的 Agent 花了 4 步在执行 pip install -e .,包括处理权限错误和重试。这完全不应该是 Agent 的工作。

解决方案是在 harness 层自动处理:

python
REPO_INSTALL_COMMANDS = {
    "django/django": ["pip", "install", "-e", ".", "-q", "--break-system-packages"],
    "sympy/sympy": ["pip", "install", "-e", ".", "-q", "--break-system-packages"],
    # ...
}

def setup_repo(instance, workdir):
    # ... git clone, checkout ...
    # 自动安装依赖
    install_cmd = REPO_INSTALL_COMMANDS.get(repo)
    if install_cmd:
        subprocess.run(install_cmd, cwd=repo_dir, ...)

这样 Agent 启动时环境已经就绪,不需要浪费任何步骤在环境配置上。

经验:能确定性完成的事情,就不要交给概率性的 LLM 去做。

优化三:释放上下文空间

Day 1 留下了一个隐患:每个 slot 有 32K token 的上下文窗口,但 Agent 自限于 5.5K token。这意味着 83% 的上下文空间被浪费了。

后果是 Agent 很快就开始"失忆"——旧的工具调用结果被裁掉后,Agent 会重复搜索已经看过的文件。

Day 2 的修改:

  1. 上下文预算 5.5K → 28K,充分利用可用空间
  2. 工具输出截断上限 3K → 8K,让 Agent 能看到更完整的文件内容
  3. 智能压缩替代粗暴删除:旧的工具结果不再直接删掉,而是压缩为一行摘要
python
# 旧方式:直接删除
self.messages = self.messages[:2] + self.messages[-20:]

# 新方式:压缩旧消息
for msg in old_messages:
    if msg["role"] == "tool" and len(msg["content"]) > 200:
        first_line = msg["content"].split("
")[0][:150]
        msg["content"] = f"[compressed] {first_line}"

这样 Agent 至少能记住"我之前读过 deletion.py 的 270-327 行",不会再去重复读取。

优化四:Patch 卫生

SWE-bench 评测只看源代码的修改。如果 Agent 顺手改了测试文件,不仅无用,还可能干扰评测。

python
def extract_patch(repo_path):
    # 排除测试目录的修改
    result = subprocess.run(
        ["git", "diff", "HEAD", "--", ".", ":!tests/", ":!test/"],
        ...
    )

一行改动,确保产出干净的 patch。

优化五:网络韧性

批量跑 20 个实例时发现,本地 LLM 服务器偶尔会重启(加载模型、内存压力等原因)。第一轮有 6 个实例因为 503 错误直接失败。

加了指数退避重试:

python
for attempt in range(5):
    try:
        response = self.client.chat.completions.create(**kwargs)
        break
    except (APIConnectionError, APITimeoutError, InternalServerError) as e:
        wait = min(2 ** attempt, 30)
        time.sleep(wait)

批量评测结果

在 20 个 Django 实例(按 patch 长度排序,取最简单的 20 个)上运行:

指标值
总实例数20
生成 patch19
无 patch(模型能力限制)1
Patch 生成率95%

唯一失败的 django__django-11964 是一个涉及 enum/choices 多文件交互的复杂 bug,Agent 跑满 40 步仍未收敛——在 fields/__init__.py、base.py、query.py 之间反复搜索,始终没有定位到修改点。这是模型推理能力的真实瓶颈。

需要强调:生成 patch ≠ 正确修复。95% 是 patch 生成率,不是通过率。后续需要用 SWE-bench 的正式评测框架来验证这些 patch 是否真的能通过测试。

Day 2 的认知收获

1. 提示词是最高杠杆的优化

两句话的提示词改动("测试可能不存在"、"不要 pip install")比任何架构改动效果都大。在编码 Agent 领域,提示词工程不是"锦上添花",而是"必须做对"。

2. 分层设计:确定性的事不要让 LLM 做

确定性层(Harness):环境安装、repo checkout、patch 提取
概率性层(Agent):理解问题、定位代码、生成修复

把确定性的工作从 Agent 中抽出来,是效率的根本保证。

3. 上下文就是记忆

对 Agent 来说,上下文窗口就是它的工作记忆。限制上下文 = 限制记忆 = 强迫重复劳动。在上下文管理上的投入,回报率极高。

4. 失败案例比成功案例更有价值

19 个成功的实例告诉你"能跑",但那 1 个失败的实例告诉你"瓶颈在哪"。django-11964 的失败模式(探索不收敛)指向了下一步的优化方向:结构化探索策略。

下一步

  • 用 SWE-bench 正式评测验证 patch 正确性
  • 分析 19 个 patch 的质量(是否真的修复了 bug)
  • 针对"探索不收敛"问题设计结构化策略
  • 扩展到 SymPy 等其他仓库

这是「十天开发编码 Agent」系列的第二篇。代码已打 tag day2。

Linked from

Comments (0)

No comments yet

imfht
April 8, 2026