编码 Agent 跑长任务,为什么越来越慢?一篇 harness 论文讲清取舍

跑长时任务的编码 Agent(Claude Code、Codex、各种开源 harness)几乎都碰到过同一个问题:会话越长,模型越”笨”,最后卡在某个上下文溢出上。一篇今年 9 月发在 arXiv 的论文《An Empirical Study of Harness Design for Coding Agents》(论文摘要)把这件事拆开看了——它把 harness 当成可拆组件,固定执行循环,只变化 planning、action space、context management 三件,分别测了 176 个组合,覆盖 4 个模型 × SWE-Bench Verified + Terminal-Bench 2.1。本文挑出”上下文管理”这块的发现,并把它翻译成可执行的工程取舍。

论文关键发现(一句话总结)

上下文管理的真正价值不是”省 token”,而是”避免上下文溢出失败”。换句话说:当窗口预算紧的时候,做不做上下文压缩,模型能不能跑完长任务的差别,远比”省了多少 token”大。

五种策略里,谁最强

论文摘要里写明:在五种上下文管理策略里,先把规则性省略(rule-based elision)放在 LLM 摘要之前,综合效率最强。同时它明确指出,”把被裁掉的内容做成可恢复索引”这件事模型很少回头用,也没带来精度增益。

这个结论反直觉的地方是:直觉上”可恢复”听起来更稳——万一模型要回头查呢?但论文的实测说明模型并不查。可恢复索引是典型的”为人写的安全网”,不是”为模型写的安全网”。

五种策略的工程取舍(这张表是本文按工程经验补的,不是论文给的)

再次强调:论文摘要里没有给出五种上下文管理策略的具体名称,也没给每个策略的具体分值。下表是本文按摘要的描述 + 工程经验划分的五条互不重叠的策略线,不是论文给出的对照表,不应被当作论文结论。具体分值、消融数据、置信区间在 arXiv 摘要页里没有披露——论文 HTML 全文版 虽然公开可读,但本文这次没有逐节对照,要看完整结论的读者可以自行翻。

策略 主要做法 适合场景 风险点
全量保留 不压缩,全程塞进上下文 窗口足够大、任务短 预算紧时直接溢出
仅 LLM 摘要 触发阈值后整段让 LLM 摘要 历史冗长但窗口较松 摘要可能固化错误中间态
仅规则裁剪 按规则删低密度内容 日志/构建输出占主体 删过头会丢失败堆栈
规则裁剪 → LLM 摘要(论文发现) 先规则,再触发 LLM 多种密度混杂的历史 摘要触发的时机需要精细
可恢复省略 删原文 + 索引入库 怕返工、要求可回看 模型很少回查,没有精度收益

工程含义其实很直观:先用廉价、确定性的规则去掉低密度内容(重复构建日志、旧命令回显、长输出尾部、可重现的中间文件列表)。规则裁剪完如果已经低于预算,就不调用 LLM。只有当规则裁剪后仍然超预算时,才让 LLM 对剩余内容做摘要。这种”先规则、再触发模型”的取舍在 remote agent 的工程实践里也能看到,比如 Mistral 官方对 Vibe remote agents 的设计介绍 也是把高确定性的过滤放在前面,把昂贵的模型调用留给真正需要的判断(这是工程做法对照,不是论文结论的佐证)。

可落地的伪代码与一个预算推算

下面是本文采用的一种上下文压缩流程示意,不是论文给出的代码,也不是某个官方库的 API:

# 上下文预算控制:本文采用的做法
def compact(history, budget):
    # 第 1 步:规则裁剪,不可恢复地删除低密度内容
    history = rule_elide(history)

    if token_estimate(history) <= budget:
        return history

    # 第 2 步:仅当仍超预算时,才对剩余内容做 LLM 摘要
    history = llm_summarize(history)

    # 第 3 步:如果摘要后仍超预算,再按固定规则截断最旧帧
    return truncate_oldest(history, budget)

配一个按工程习惯的预算推算(论文摘要里没有给出这些数字,仅作示例):假设窗口是 128k token,固定开销预留 8k,则留给上下文的预算是 120k。如果原始历史约 180k token,就要先靠规则裁剪去掉至少 60k;如果规则裁剪后还在 120k 以上,再调用 LLM 摘要把剩余内容压进去。

失败边界:什么不能裁

论文说上下文管理主要避免的是溢出失败,但裁剪本身会引入新的失败模式。下面这几条边界是从论文结论 + 工程经验里抽出来的,不分先后:

  • 失败堆栈不能裁。一条堆栈可能只出现一次,却是定位问题的关键。裁掉它,agent 可能在同一个错误上反复打转。
  • 最近几轮命令的原始输出要保留。远历史的日志可以省,但当前决策依赖的退出码、stderr 尾部必须留原文,否则 LLM 在错误中间态上继续执行。
  • 不要给”可恢复索引”投入太多。论文明确说模型很少回查、没精度收益。先省下这套机制。
  • 预算越紧,越要把规则裁剪前置。论文发现上下文管理在预算紧时价值更大;当窗口明显不够时,应提高规则裁剪的比例,而不是一开始就全量摘要。

一个反方观点

业内对”上下文压缩”有一种乐观假设:只要不丢信息,模型不会变笨。但这篇论文的发现间接否定了这一点——可恢复索引”理论上有信息”,但模型不回查。这说明模型对”看不到”的信息的处理能力比想象中差,给模型留一条能看到的、可执行的提示,比给它留一份”理论上可恢复但需要它主动查询”的数据更可靠。

这条反方对工程上的含义是:如果你的 harness 设计是”全量保存 + 按需查询”,可以重新评估一下模型实际查询的频率——很可能远低于你的预期。

FAQ

Q:什么时候不要做上下文压缩?
任务短、窗口够用、token 不值钱时不要做。压缩是有成本的:规则裁剪要写规则、要调阈值、要处理误删;LLM 摘要要额外调用、要承担摘要错误的风险。如果任务短到 2~3 轮交互就能做完,做压缩是负优化。

Q:规则裁剪的”规则”怎么写?
按低密度 + 高重复的维度写。比如 kubectl apply -f 的成功回显、构建工具的进度条、pip install 的下载百分比,这些都可以被安全裁掉。例外:失败的 stack trace、错误码、文件路径、commit hash 这些不能裁,因为它们是后续决策的直接依据。

Q:LLM 摘要应该怎么触发?
一种工程做法是按预算剩余比例触发,比如规则裁剪后仍超预算 30% 时才触发摘要。这样可以避免”窗口还够用就开始摘要”的过早优化。论文摘要没给具体阈值,所以这条是工程经验,不是论文结论。

参考来源

评论区

0 条评论

登录后可评论。

大熊 2118 阅读