Agent Harness 技巧初探:Codex CLI 的工程封装,为 Agent 智能贡献了多少?

知与行 2026-10-30T15:57:22.774336

2025 年 coding agent 加速落地,OpenAI 也开源了 Codex CLI 的源码。本文想量化一个常被忽视的问题:Codex CLI 里各种 harness(围绕大模型搭建的工程脚手架)技巧,究竟为整个 agent 的智能加了多少分。作者用 DeepSWE 做了对比评测,结论有些出人意料——这些技巧带来的提升相当有限。

背景

2025 年是 coding agent 快速起步的一年,OpenAI 同时公布了 Codex CLI 的源码。作者初次试用时,感觉像在看科幻电影:Codex 像一个程序员一样自主探索,修改自己写的 JSON 库,还添上了新语法。大模型似乎从聊天对话框里一跃而出,成了真正意义上的智能体。这让人不禁好奇:Codex CLI 到底为整个 agent 的智能贡献了百分之多少?

先厘清术语。这里的 agent 指「大模型 + agent CLI」。大模型只负责文字的输入输出,本身没有读取或操作计算机环境的能力,必须依靠 agent CLI 代劳。而 agent CLI 又分成两块:一是客户端 UI 部分(登录、沙盒、插件等),二是 harness——可以理解为围绕大模型搭建的一层工程脚手架。业界普遍认为 harness 能增强 agent 的智能,让它处理更难的任务、跑得更快,最常见的例子就是上下文压缩。

在 AI 编程、尤其是“氛围编程”这类让模型自主探索的工作流火热的当下,把模型和 CLI 拆开来看,对判断工具链的价值很有参考意义。本文想探索的主题正是:「大模型 + 最小 agent CLI」与「大模型 + 最小 agent CLI + Codex 中的各种 harness 技巧」之间,差距到底有多大?

结论出乎意料:作者从 Codex 中选取的 harness 技巧,对 agent 智能的影响相当有限。如今的大模型只靠极少的 harness 技术就能做很多事。这样一来,agent CLI 本身更像一个 UI 软件,是光鲜的果皮,而整个 agent 的“果肉”仍藏在大模型里。

研究方法

要衡量 agent 的智能度,先得有一个评测基准。作者选择了 DeepSWE。主要考量是:写本文时,GPT-5.6、K3、deepseek 4.1 刚刚发布,它们的评测报告都用了 DeepSWE。此前业界多用 SWE-bench 系列,但 OpenAI 的博客提到这一系列的“泄题率”已经很高——大模型很多时候是在背题。这些任务本身就是公开的 GitHub 数据,很可能已被新一代模型在训练中记下了答案。

DeepSWE 的应对方式是雇人类专家出题:题目程序来自 GitHub 上较流行的开源仓库,由专家编写题目和验证程序,再由团队审核。效果很好,刚发布时各大主流模型的通过率远低于 SWE-bench,区分度很高。值得一提的是,大模型评测很像人类考试,需要在资源约束下完成任务:一是金钱,很多论文会限定单个任务的成本上限;二是时间,DeepSWE 官方给每个任务定的时限是 1.5 小时。

至于任务验证,有些超时的案例经 AI 检测发现是死锁,作者统一判为失败。

模型方面选了 deepseek-v4.1-flash:开源、性价比高,通过率约在 50% 上下。太高就没有 harness 的提升空间,太低的话 harness 可能也补救不了,所以选一个智能度中等的模型最合适。

agent CLI 选了 Codex:它有大规模的 production 使用,而且完全开源。

此外还需要一个极简 agent CLI 来控制变量。极简 CLI 做的事很少:把请求发给大模型、接收响应,再按大模型的指令在操作系统上执行。作者本打算自己写,调研时发现 SWE-bench 团队为了方便做实验,已经开源了 mini-swe-agent(下文简称 mini agent)。它的源码只有几百行,高度可扩展,可以用继承和 Jinja 模板改写各种参数,实验设施也齐全,比如能记录 token 消耗。

不过在这里,作者产生了一种直觉:agent CLI 对智能的影响很有限。因为 DeepSWE 官方榜单本身就是用 mini-swe-agent 跑的,在本文写作时,主流旗舰模型几乎不需要复杂 CLI 就能跑出 70% 以上的成功率。而 DeepSWE 的任务已经相当复杂,所基于的仓库来自多种语言的底层库,例如 Python 的静态检查器。后续的实验结果确实验证了这个直觉。

通读 mini agent 源码后,作者发现它并非完全没有 harness。虽然官方自称只有一个 shell 工具调用,但其中仍有两处 harness 技巧:第一是工具截断,上限 10000 个字符;第二是一套 workflow——在初始化 prompt 里告诉大模型要分解问题、编写测试等,这可以算作 prompt engineering。

衡量智能度的指标,除了最常见的成功率,作者还统计了 token 消耗量和 step。因为成本本身也是智能的一部分,而 step 能反映大模型在路径探索上的效率。

harness 选择

研究的关键在于:到底要选取哪些 harness 技巧?作者从 Codex 中挑出了三个:

作者把 Codex 等产品中已验证的几项 harness 技巧——工具输出截断、结构化编辑、上下文压缩——逐一迁移到极简 mini agent 上,并在 DeepSWE 任务上做 A/B 对比。结果显示:截断阈值调到 1000 或 30000 字符都会让成功率下降,10000 更像是模型训练时的“舒适区”;结构化编辑 apply_patch 在 DeepSeek 模型上同样没有带来收益,反而增加了 token 消耗和交互步数。

接下来要迁移的技巧包括:

作者把这些 harness 技术迁移到 mini agent,再分别与原始 mini agent 在 DeepSWE 任务上的通过表现作对比。

过程和结论

工具截断

工具输出截断在 mini agent 中已经存在,恰好是两项极简 harness 技巧之一。而且 Codex 和 mini agent 都选择了 10000 个字符作为上限。

作者好奇:调大或调低这个上限会怎样?分别调成 1000 和 30000 后,整体智能度都下降了。

作者猜测,大模型厂商训练时可能就把截断上限设成了 10000 字符,因此这里存在一定的“过拟合”。增大工具输出后,成功率虽下降,但模型效率有所提升。

还要注意截断发生的频率。从 baseline 任务看,发生截断的任务有 105 个,总计 675 次,说明截断非常普遍,值得优化。截断下调到 1000 后,任务数量为 113,截断次数为 12,223;上调到 30000 后,任务数量为 37,截断次数为 49。

结构化编辑

这是作者最感兴趣的部分。先看结构化编辑和 mini agent 直接用 shell 编辑的区别。

如果要改程序中的一行,mini agent 会用命令行自带的 sed,它本质上就是字符串替换,命令对人类来说可读性很差。它表达的改动大致是:

  -            aliases=(),
  +            aliases={},

而 Codex 编写了名为 apply_patch 的工具,用自己定制的一套语法来编辑,改动一目了然。

于是作者想:把这套技术迁移到 mini agent 会如何?毕竟按日常使用 chat bot 的经验,人类读起来困难的内容,大模型往往也会觉得困难。

这里有个注意事项:OpenAI 的 ChatGPT 在使用这个工具时,采用了一种叫“约束编码”的技术——现场教会大模型语法,然后约束模型在推理阶段按这种语法生成,但前提是上下文无关文法(Context Free Grammar)。它不是用 prompt 教会大模型后让模型直接输出,因为那样无法保证 100% 语法正确。

但 DeepSeek 并没有这项技术,作者只能用 prompt 的方法教 DeepSeek 使用该工具。不过后续评测中并未发现 DeepSeek 产生 apply_patch 的语法错误。

Codex 中的 apply_patch 作为一个独立库,带有测试用例,可以直接移出来,当作二进制给 mini agent 调用。此外还需要在 mini agent 的 prompt 里标注:不要用命令行编辑文件,要用 apply_patch。

最后结果让作者很意外:成功率下降 15.04%,input token 和步数几乎不变。

作者怀疑还是“过拟合”问题——DeepSeek 自己训练用的 agent 走命令行路线,而 OpenAI 用的是 apply_patch。于是作者引入一个支线任务,加入 ChatGPT 5.6 luna,再研究 apply_patch 的影响。结果验证了这个想法:成功率下降 2.65%,input token 提升 28.11%,步数提升 28.43%。

奇怪的是,成功率可以看作接近(考虑随机性),但效率却下降了。所以这个工具到底能产生多大效益,还需要打一个问号。sed 这种编辑方法虽然对人类很粗暴,对大模型却可以轻松适应。对开发者而言,工具是否漂亮并不是第一位的,模型平时习惯怎么用、调用起来顺不顺手,往往更影响结果。apply_patch 在 Codex 上有效,不代表换个模型也能照搬;sed 看着笨,却可能正好落在大模型熟悉的用法里。所以迁移 harness 技巧时,最好先做小规模对照实验,把成功率、token、步数和截断次数放在一起看,再决定要不要上线。结构化编辑仍然值得继续打磨,但它的收益要结合具体模型和任务来评估,不能只凭命令可读性下结论。

上下文压缩

上下文压缩是 harness 中相当常见的技巧。DeepSWE 并不是长程任务,总的上下文规模一般不会触及 DeepSeek 模型的窗口上限;但我在实际观测中发现,单轮交互中上下文的最大值可以达到 223,852。此前用大模型解读文档时,即便窗口标称 1M,一旦内容超过十万字,注意力涣散、丢三落四的情况就会很明显。所以我推测:虽然上下文没有达到上限,在十万量级中途压缩一次,是否也能减少注意力涣散、带来收益?

于是我把压缩阈值设在 15 万。本来想直接研究 Codex 的上下文压缩实现,结果发现它被藏到了服务端,由专门的一个 API 来做压缩——所谓“开源”在此处并不完整。不过在 Codex 仓库里,我找到了它为其他模型准备的本地压缩 prompt,于是借鉴了其中的逻辑。这个 prompt 的设计颇有意思:它让大模型假装自己是另一个将要接手的模型,要求对当前任务做一份交接摘要,并附上了比较细致的要求:

COMPACTION_PROMPT = """You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.

Include:
- Current progress and key decisions made
- Important context, constraints, or user preferences
- What remains to be done (clear next steps)
- Any critical data, examples, or references needed to continue

实际运行结果是:成功率下降 7.08%,输入 token 下降 15.78%,步数上升 13.48%。看来压缩之后 agent 更容易迷失,和此前把工具输出截断阈值调低时的表现类似。还有一点值得注意:输入 token 虽然降了,成本却略有上升,因为输出 token 增多了。

这说明目前的压缩方式还很难做到无损,也和我使用 coding agent 的体验一致:agent 完成一次上下文压缩后,经常会忘掉某些约束或我先前提供的内容,需要我再讲一遍。

总结

截至本文发布,我认为 agent CLI 并没有给 agent 带来多少智能上的价值,更像是一个供用户交互的 UI。agent 真正的核心仍然掌握在大模型厂商手里。

技术难点

本次研究中的程序都是用 GPT5.6 和 Kimi 2.8 写的。主要难点在于,大模型经常给出一个极度复杂的方案,然后自己陷入其中。比如 mini agent 接入各种 harness 之后,需要在 DeepSWE 指定的 Docker 环境里运行,大模型却建议我给 harness 单开一个仓库、发布源码并提供 URL。最后在我把关下改成直接用 wheels 打包,以更简洁的方式实现了功能。

另一个难点是确认 reasoning effort 这个参数是否成功传递。DeepSWE 的技术栈层次很深,按照我过去的工业界经验,这种结构下参数很容易在传递过程中丢失。后来我亲自做了实验,发现这个参数居然真的丢了——DeepSWE 背后的技术栈依赖 Litellm,而它有一个 bug,会丢弃传递给 DeepSeek 的 reasoning effort。当时该问题尚未修复,只能换用另一种扩展 API 的方式传入。

我使用的是默认的 reasoning effort。如果其他研究者采用不同的强度,又没有检查出这个 bug,并且过于信任 AI,那么整个研究就会失去根基。本质上这还是人机协作的问题:对大模型应该信任到什么程度,仍是一个有待讨论的难题,每个人答案不同。

局限性

按照 DeepSWE 官方的评测方法,每个任务应跑四次,取均值以消除随机性。但本实验预算有限,每个任务只跑了一次。

此外,尝试的大模型数量也有限。而且本文的评测基于 DeepSWE 这类短时任务,真实的开发则是长期的,一个 session 可能要持续一周,因此 skills 这类 harness 技巧无法被评测——这是本文最大的局限。

不过,DeepSWE 本身的难度和工作量已经非常贴近程序员的真实工作,所以我认为这次评测仍有一定启发价值。

附录:技术栈

开发过程:

技术 版本或配置 用途
Python >= 3.12 Harness、配置生成和实验分析
uv 0.12.3 Python 环境、依赖和命令管理
Hatchling >= 1.27 将自定义 Harness 打包成 wheel
PyYAML >= 6.0.3 读取任务和 Harness 配置

评测:

实验环境:固定版本组合

整套评测运行在 Ubuntu 24.04 上,各组件的版本都做了明确锁定,以确保任务环境可以复现。

组件 版本 职责
DeepSWE v1.1,113 个任务 Coding Agent 测试集
DeepSWE commit 435ee89ec2f2e2289f33b0da4f992f0b7b7266b9 固定数据集版本
Pier 0.3.1 创建任务、运行 Agent、执行 verifier、收集结果
mini-swe-agent 2.4.6 基线 Coding Agent
LiteLLM 1.96.2 统一模型 API、usage 和费用数据
Docker / Compose 服务器环境快照为 Docker 29.1.3 隔离任务环境和依赖

其中,Codex 源码也固定在以下版本:

这次改动本身并不复杂:它通过 app-server API 暴露线程来源信息,让外部能够识别一个 Agent 会话由谁、由什么触发。对需要追踪多轮任务来源的 harness 来说,这类元数据是排查问题和复现行为的基础。

对做 AI 编程、氛围编程的读者来说,这份清单最值得记住的一点是:harness 的结论只在锁定的版本组合下成立。模型、Agent 框架、测试集、运行环境,任何一项发生变动,都会让横向对比失去意义。因此在复现或对比技巧之前,先把版本固定下来,是成本最低、也最容易被忽略的一步。

关键要点

查看原文