Cursor 官方博客:Continually improving our agent harness。
这篇文章很值得细看,因为它没有停留在"模型又变强了"这种表层叙事,而是把 Cursor 如何持续优化 Agent 体验的工程方法摊开讲了一遍。
其中最重要的一句话是:
Agent = Model + Harness。
模型当然重要,但真正决定一个 Agent 产品是否好用的,不只是底层模型本身,还有围绕模型搭建的一整套 Harness:提示词、工具、上下文管理、评估系统、错误处理、模型适配、缓存策略,以及未来的多 Agent 编排。
换句话说,模型是发动机,Harness 是整辆车。
发动机再强,如果变速箱、方向盘、刹车和仪表盘没调好,用户依然开不顺。
Cursor 不是在"调用模型",而是在打磨一个软件产品
Cursor 在文章开头说,他们构建 Agent Harness 的方式,和构建一个有野心的软件产品没有本质区别。
他们不是简单地接入新模型,然后把用户请求转发过去。而是先形成一个关于理想 Agent 体验的判断,再围绕这个判断提出假设、做实验、看线上和线下指标,最后不断迭代。
有些优化可能带来阶段性跃迁,但更多时候,Harness 的进步来自大量小优化的叠加。
这也解释了为什么同一个模型,放在不同产品里,体验会差很多。
模型能力决定上限,Harness 工程决定你能不能稳定接近这个上限。
1. 上下文窗口:从"静态灌入"走向"动态获取"
Agent 和大模型交互的核心,是上下文窗口。
当你让 Agent 构建一个功能时,上下文窗口里通常会包含系统提示词、工具描述、当前对话状态,最后才是你的用户请求。
早期的 Cursor Agent 会放入大量静态上下文,也会设置很多护栏。
比如每次编辑后自动把 lint 和类型错误暴露给 Agent;当 Agent 读取的文件行数太少时,系统会重写它的读取请求;甚至还会限制单轮对话里最多能调用多少工具。
这些做法在当时是合理的。因为 2024 年末的模型还不太擅长自己选择上下文。
但随着模型能力提升,Cursor 的方向变了。
现在他们保留少量有用的静态上下文,比如操作系统、Git 状态、当前和最近查看的文件;同时把更多上下文改成动态获取。
也就是说,不再试图提前告诉 Agent 一切,而是给它更多方式,让它在工作过程中自己拉取信息、读取历史、查看终端、调用工具。
这和 Cursor 之前提出的 Dynamic Context Discovery (可以看我上一篇文章)是同一条路线。
好的上下文工程,不是把所有信息塞进 Prompt,而是让 Agent 知道该去哪里找。
2. 评估 Harness:不能只看跑分,还要看真实用户是否接受
既然 Agent 是模型和 Harness 的组合,那要判断 Harness 有没有变好,就不能只看模型榜单。
Cursor 使用了两类评估信号。
第一类是离线评估,比如公开 benchmark 和他们自己的 CursorBench。离线评估的好处是快、标准化,能帮助团队跨时间比较质量变化。
但离线评估只能近似真实使用场景。
真实开发里,用户会提出含糊的需求,会中途改主意,会在复杂代码库里让 Agent 修一个"看起来简单"的问题。这些东西很难被 benchmark 完全覆盖。
所以 Cursor 还会做线上 A/B 测试,把不同 Harness 版本放到真实使用中比较。
他们会看一些直接指标:延迟、token 效率、工具调用次数、缓存命中率。
但这些指标仍然不能回答最重要的问题:Agent 到底有没有把事情做好?
Cursor 提了两个更贴近真实价值的指标。
第一个叫 Keep Rate,也就是 Agent 生成的代码在一段时间后有多少仍然留在用户代码库里。
如果用户很快手动改掉了 Agent 的输出,或者反复让 Agent 修补,就说明初始输出质量可能不够好。
第二个方式,是让模型读取用户对 Agent 初始输出的回应,判断用户是否满意。
用户继续做下一个功能,通常说明 Agent 完成得不错;用户贴出一段报错堆栈,往往说明它没做好。
真正的 Agent 质量,不是看它生成了多少代码,而是看用户最后保留了多少代码。
3. 性能退化:工具调用错误会制造"上下文腐坏"
随着 Cursor 支持更多模型和能力,Harness 本身也会变复杂。
复杂系统一定会有更多状态,也会有更多 Bug。
文章里特别强调了一个风险:Agent 的工具调用,是 Bug 最多、也最容易伤害用户体验的地方。
工具调用失败之后,Agent 有时能自我纠正。但失败记录仍然会留在上下文里,继续消耗 token,并污染后续推理。
Cursor 把这种现象称为 context rot,上下文腐坏。
一次错误可能只是一个小问题,但错误累积在上下文里,就会慢慢降低模型后续决策的质量。
有时工具失败甚至会让 Agent 卡住,或者开始失控。
所以 Cursor 会把未知错误都当作 Harness Bug 处理。同时,他们也会分类那些"预期内错误",比如模型给出错误编辑、读取不存在的文件、第三方服务故障、用户中止、超时等。
他们还会按工具和模型分别建立基线,再用异常检测发现错误率是否突然偏离正常水平。
文章里提到,今年早些时候的一次专项冲刺中,他们把意外工具调用错误降低了一个数量级。
这说明 Agent 产品不是只有 prompt engineering。
它更像一个需要监控、告警、归因、修复和持续运营的软件系统。
4. 不同模型,需要不同 Harness
Cursor 的抽象尽量保持模型无关,但他们会为每个模型深度定制 Harness。
一个很具体的例子是文件编辑方式。
OpenAI 的模型更熟悉基于 patch 的编辑格式,而 Anthropic 的模型更熟悉字符串替换。
理论上,任何模型都可以使用任何编辑工具。但如果让模型使用它不熟悉的工具格式,就会带来额外的推理 token,也更容易出错。
所以 Cursor 会给每个模型配置更贴近其训练分布的工具形态。
定制还包括提示词。
文章里提到,OpenAI 的模型在指令遵循上往往更字面、更精确;Claude 则更直觉化,也更能容忍模糊指令。
这意味着同一套提示词,不一定适合所有模型。
当 Cursor 提前拿到新模型访问权限时,他们会从最接近的现有模型 Harness 出发,跑离线评估,让团队真实使用,找到模型困惑的地方,再不断调整。
有些模型还会出现很有意思的"性格"。
比如某个模型随着上下文窗口逐渐填满,会开始拒绝任务,表现得像是觉得任务规模太大。Cursor 把这种现象称为 context anxiety。他们最终通过调整提示词,降低了这种行为发生的频率。
这再次说明一个事实:
模型不是一个标准零件。每个模型都有自己的习惯、偏好和脾气,Harness 必须顺着它的纹理设计。
5. 对话中途切模型,其实很难
用户经常会有一个自然想法:这轮先用一个模型,下一轮换另一个更强或更便宜的模型。
但从 Harness 角度看,中途切换模型并不简单。
因为不同模型有不同的行为习惯、提示词结构和工具形态。用户切换模型后,Cursor 会自动切换到对应 Harness,加载该模型定制过的提示词和工具。
问题是,新模型接手的对话历史,是另一个模型生成的。
这对它来说是分布外输入。
为了解决这个问题,Cursor 会加入自定义指令,告诉模型:你正在从另一个模型手里接管这段对话。同时提醒它,不要调用历史里出现过、但不属于自己工具集的工具。
另一个问题是缓存。
缓存通常和提供商、模型强绑定。切换模型意味着缓存命中率下降,第一轮响应会更慢,也更贵。
Cursor 尝试过在切换时总结对话,用干净的摘要降低缓存惩罚。但如果用户正在处理一个复杂任务,摘要又可能丢掉关键细节。
所以他们的建议很克制:除非有明确理由,否则尽量在同一段对话里坚持使用一个模型。
还有一种绕开方式,是用 subagent。
子 Agent 从新的上下文窗口开始,不必背负完整历史,也更适合指定某个模型去完成一个独立子任务。
6. 多 Agent 的未来,本质上还是 Harness 问题
文章最后谈到 AI 辅助软件开发的未来:它会越来越像一个多 Agent 系统。
不是所有任务都交给同一个 Agent 从头做到尾,而是把工作委派给不同专长的 Agent:
一个负责规划。
一个负责快速编辑。
一个负责调试。
每个 Agent 都在自己最擅长的范围内工作。
但这件事能不能做好,关键仍然在 Harness。
系统要知道什么时候该派哪个 Agent,如何把任务描述成适合它的输入,如何控制边界,如何整合多个 Agent 的产出,如何避免它们互相踩脚。
所以未来的竞争点,不只是哪个模型最强,而是谁能把这些模型组织成一个可靠的软件开发系统。
单个 Agent 的能力属于模型,多 Agent 的协作能力属于 Harness。
写在最后
读完这篇文章,我最大的感受是:Agent 产品的差距,正在从"有没有接入强模型",转向"能不能持续改进 Harness"。
模型会越来越强,也会越来越接近。
但产品体验不会自动变好。
上下文怎么组织,工具怎么暴露,错误怎么分类,退化怎么监控,不同模型怎么适配,中途切换怎么处理,多 Agent 怎么编排,这些都不是模型自己能完全解决的问题。
这也是 Cursor 这篇文章最有价值的地方。
它提醒我们:AI 编程工具不是一个套壳模型,而是一个复杂的软件系统。
真正优秀的 Agent,不只靠模型能力强,而是靠一套工程扎实的 Harness 来驾驭它、约束它、让它可靠地完成真实任务。