把大模型当成一个确定性函数,很容易高估它。更合适的工程抽象是:模型在当前上下文、参数和工具环境给出的概率空间里,采样出一个看起来最合适的结果。

这意味着同一个模型在同一类任务上的能力并不是一个点,而是一段分布。一个平均能做 70 分的模型,在某个具体任务上可能落到 50 分,也可能冲到 90 分。Harness Engineering 的价值,不是把 70 分模型魔法般变成 95 分模型,而是把它的行为压进一个更小、更可验证的区间,让低分尾部少出现,让高分路径更容易复现。

这个区间可以叫“箱体”。Spec、测试、工具、循环、权限、外部状态、子 Agent、hook,都是箱体的不同面。没有箱体时,模型在荒野里寻路;有箱体时,模型在一条被标出边界和检查点的路线上前进。

flowchart TB
    A[用户目标] --> B[Spec: 目标 / 非目标 / 边界]
    B --> C[Plan / Tasks]
    C --> D[模型生成候选方案]
    D --> E[确定性工具: 编译 / 测试 / schema / 日志]
    E --> F{验证通过}
    F -->|否| G[失败证据写回]
    G --> B
    F -->|是| H[状态持久化 / 提交 / 交接]
    H --> I[下一轮上下文回灌]
    I --> C

模型不是函数,而是概率场

OpenAI 的 reproducible outputs 文档把一个事实说得很直白:Chat Completions 和 Completions API 默认是非确定性的;即使设置 seed、保持参数和 system_fingerprint 一致,也只是“mostly deterministic”,仍然存在输出不同的小概率。这不是实现瑕疵,而是生成式模型的工作形态。

Nature 2024 年的论文《Larger and more instructable language models become less reliable》给了另一个侧面:更大、更听指令的模型能解决更难的问题,但不会自动把低难度区域全部锁死。它们仍会在简单题上犯错,也会因为问题表述细微变化给出不同答案。论文里提到的加法例子很典型:模型可能会让用户误以为“这已经在它的稳定能力范围内”,然后在一个很普通的加法提示上失败。

工程上要接受这个前提:模型能力不是一条确定边界,而是一片概率地形。裸模型的输出像在这片地形上找路,模型越强,越有续航、越会识别地貌,但它仍可能绕圈、误入岔路,或者在看似简单的地方踩空。

这个视角会改变问题定义。问题不再是“模型到底会不会”,而是:

工程问题 真实含义
模型能不能做 分布的均值是否足够高
模型靠不靠谱 分布的方差是否足够小
能不能上线 低分尾部是否被验证和兜底机制拦住
能不能长程执行 跨上下文后是否仍能回到同一个目标分布

Harness 的工作就是移动这个分布:提高均值,压低方差,切掉不可接受的低分尾部。

CoT 是最早的微型 Harness

Chain-of-Thought Prompting 论文证明了一件很重要的事:给模型几个中间推理步骤示例,能显著提升大模型在算术、常识和符号推理任务上的表现。这个结果经常被理解为“模型学会了推理”,但从工程角度看,它更像是第一个微型 Harness。

CoT 没有改变模型权重,也没有给模型接入外部计算器。它只是把模型带进一个更有利的上下文轨道:先分解、再推导、最后回答。原本模型可能直接跳到答案,现在它被要求沿着一条局部可观察的轨迹走。

这正是 Harness 的基本动作:不试图在每次采样时祈祷模型自然选中好路径,而是把好路径的形状注入上下文,让它更容易走到想要的区域。

从这个角度看,CoT、few-shot、system prompt、rubric、checklist 都属于同一个家族。它们不是“让模型变聪明”的咒语,而是改变采样空间的边界条件。边界越贴近任务,模型越少把 token 浪费在无关探索上。

Spec 是任务箱体的边界

Spec-Driven Development 把这件事推进了一层。GitHub Spec Kit 对 SDD 的定义是:在 AI 辅助开发中把 specification 放到中心位置,流程从 Spec 到 Plan,再到 Tasks 和 Implement;每个阶段产生 Markdown artifact,作为下一阶段的结构化上下文。

这套流程的关键不是“多写文档”,而是把任务从自然语言愿望变成可继承的工程资产。

一个有效 spec 至少给模型三类边界:

边界 作用 典型形态
目标边界 哪些结果算完成 user story、验收条件、成功示例
非目标边界 哪些东西明确不做 non-goals、禁止改动范围、兼容性要求
验证边界 怎么判断没有跑偏 单测、E2E、截图、schema、人工 checklist

SWE-bench 的演进很能说明问题。ICLR 2024 的 SWE-bench 把真实 GitHub issue、仓库和测试组合成软件工程评测,但早期模型只能解决很少一部分问题。OpenAI 后来发布 SWE-bench Verified,不是因为模型变了,而是因为原始 benchmark 中存在问题描述欠规格化、测试过窄或环境不稳定等噪声。OpenAI 进一步在 2026 年停止报告 SWE-bench Verified 分数,原因之一仍然是测试可能拒绝功能正确的提交。

这件事反过来证明了 spec 和 test 的地位:它们不是附属物,而是模型行为的坐标系。测试写错,模型会被错误地惩罚;spec 缺失,模型会在多个有效解释之间随机选一个;验收条件太窄,模型可能被训练成迎合实现细节而不是解决问题。

好的 spec 是优势法则。它告诉模型,在当前这片地形里,哪些方向比训练数据里的平均经验更值得走。

小系统是大系统的种子

复杂系统不能靠一句话直接生成。一个排序函数可以由一句话加一个测试说清楚,一个 CRM 系统不行。差别不在于模型是否“理解 CRM”,而在于一句话给出的约束密度远远不够。

在单个上下文窗口里,早期上下文对任务框架有很强的定调作用;但长上下文并不等于所有位置的信息都被同等使用。《Lost in the Middle》发现,模型对长上下文中的信息位置很敏感,相关信息放在开头或结尾时表现通常更好,放在中间时可能显著退化。

所以,长程 Agent 的关键动作不是把所有信息塞满,而是在上下文早期构造一个精确的小系统:

  • 目标是什么
  • 不是目标的东西是什么
  • 现有系统有哪些不可破坏的边界
  • 完成后必须通过哪些验证
  • 如果失败,怎样回滚和继续

这个小系统随后被延长成大系统。Spec 放在外部存储里,随时可以作为 tool result 被重新插入上下文尾部;测试也在早期被设计出来,后面每轮实现都要回到测试面前对账;循环和 hook 把一个有限上下文接到下一个有限上下文上。

这就是“no human in the loop”能成立的最低条件。不是人类完全消失,而是目标、边界和验证不再靠人类实时记忆维持。模型每次偏离时,外部 spec 和测试能把它重新拉回同一个箱体。

注意力预算需要降维

复杂任务还有一个更朴素的问题:模型的注意力会互相稀释。

可以想象一个人站在房间中央,要把四面墙都涂黑。如果他一会儿向左、一会儿向右、一会儿抬头、一会儿低头,运动方向会互相抵消,最后每面墙都只涂了一半。把任务分成四个人,每个人只负责一面墙,单个方向上的预算反而更充分。

Agent teams 的基础思想也是如此。Anthropic 在 multi-agent research system 文章里给出过很清晰的解释:subagents 用各自独立的上下文窗口并行探索问题的不同方面,再把重要 token 压缩回 lead agent。它们带来的不是“更多人格”,而是上下文隔离、职责分离和并行 token 预算。Anthropic 的内部研究评测中,多 Agent 研究系统比单 Agent Claude Opus 4 高 90.2%;同时也承认这种系统 token 消耗很高,普通 Agent 大约是聊天的 4 倍,多 Agent 可到 15 倍。

这说明多 Agent 不是免费午餐。它是一种注意力预算优化:当任务天然可拆、信息超过单一上下文、探索方向相互独立时,多 Agent 值得;当任务强依赖同一上下文、实时协调成本很高时,多 Agent 可能只是更贵的混乱。

工程里常见的两种降维方式可以组合使用:

降维方式 做法 适合场景
阶段降维 先 plan,再 build,再 verify,每阶段屏蔽其他角色 需求清晰但步骤长的任务
模块降维 把系统拆成小模块,每个模块有独立边界和测试 多文件、多子系统、可并行开发

阶段降维让模型在每个阶段只做一种事。模块降维让模型在每个工作单元里只面对一个小世界。二者共同减少“同时向四面墙涂色”的浪费。

上下文换入换出是箱体的供料系统

Harness 不只规定模型怎么做,也规定模型每一轮能看见什么。Spec、测试、外部状态和 session summary 都是上下文供料系统的一部分。更完整的讨论放在 《上下文换入换出:下一代 scaling》;本文只保留控制层结论:如果目标和验证不在外部稳定存在,长程任务就会退回到模型的短期注意力里。

所以,一个可运行的 Harness 至少要同时回答两件事:边界在哪里,下一轮怎样重新拿到这些边界。前者是 spec,后者是 context paging。只有边界,没有回灌,模型会在长任务里忘掉边界;只有回灌,没有边界,模型会把更多噪声带进下一轮。

确定性工作必须交给确定性工具

模型的概率工作模式决定了另一条边界:确定性任务不应该交给裸模型承担最终责任。

这不是说模型一定算不对 1 + 1。关键问题是,模型不是以传统程序的方式执行加法算法。关于 LLM 算术的研究已经反复指出,大模型在复杂算术和精确数值任务上仍会出现不稳定;《Arithmetic Without Algorithms》进一步把部分算术能力解释为一组启发式组合,而不是稳健算法。

OpenAI Structured Outputs、function calling、JSON schema、MCP、Claude Code Skills 指向的都是同一个方向:模型负责理解意图、选择工具、组织上下文;确定性执行交给工具、schema、脚本、解释器、数据库、测试框架和文件格式库。

Claude Code Skills 文档里的 PDF 示例很典型。一个 PDF Processing skill 可以把操作写成 SKILL.md,再配合 pypdfpdfplumber、脚本和参考文档来处理 PDF。实际改变 PDF 的不是模型“想象”二进制格式,而是模型调用了可靠的程序抓手。

这条边界决定了 AI 不会吞掉所有软件本体。计算器、数据库、编译器、PDF 库、浏览器、CAD、CI、权限系统都会继续存在。被吞掉的是入口层:用户不再亲自学习每个软件的按钮、菜单和 API,而是让一个高阶 Agent 把意图翻译成这些软件可以执行的动作。

MCP 把这种趋势标准化了。官方文档把 MCP 定义为连接 AI 应用与外部系统的开放标准,让模型连接数据源、工具和 workflows。因此,未来很多软件会变成 Agent 可观察、可调用、可组合的技能包。LLM 会成为新的胶水语言,但胶水语言不会替代被粘合的系统。

难的是 spec 密度

Harness 最难的部分不是把流程画出来,而是决定 spec 应该多大。

一句话可以写出一个排序函数,因为函数的目标空间很小:输入、输出、复杂度、稳定性、异常情况,再加几条测试就能封住大部分边界。一句话写 CRM 系统则通常会失败,因为任务空间包含用户、权限、客户生命周期、数据模型、导入导出、审计、通知、报表、移动端、国际化、性能和合规。

系统性的问题需要系统性的解。很多个函数组成的系统,不能指望由一句话驱动模型生成;它需要很多句话共同形成约束环境。更重要的是,这些话不能只是散落的愿望清单,而要有强结构的逻辑关联:目标约束住范围,范围约束住模块,模块约束住接口,接口约束住实现,测试再反过来约束每一层是否成立。

所以问题不是“要不要 spec”,而是“每一份目标需要多少有结构关系的话才能被定义良好”。思考和设定这个约束环境,就是 SDD 要处理的问题。它不是替代码写一份长说明,而是先构造一套能驱动模型稳定生成系统的语义骨架。

可以用一个粗糙但好用的密度表来判断:

目标规模 最小 spec 密度 最小验证密度
单函数 签名、输入输出、边界条件 单测覆盖正常值和边界值
单模块 职责、公开 API、状态不变量、依赖边界 单测 + 合约测试
单功能 用户路径、状态流转、失败路径、非目标 E2E + 回归测试
子系统 领域模型、权限模型、数据迁移、可观测性 集成测试 + 冒烟 + 回滚方案
产品级系统 业务边界、组织约束、演进路线、治理规则 分层 CI + 线上指标 + 人工验收点

低质量 spec 不是优势法则,只是更长的噪声。优质 spec 的标志是:它能减少合理解释的数量。读完以后,模型不是“知道了更多背景”,而是少了很多本来可能误走的路。

一个可执行的判断方法是看三件事:

检查项 好 spec 坏 spec
目标 能判断某个输出是否完成 只描述愿望和氛围
边界 明确哪些东西不能碰 什么都想顺手优化
验证 有机器或人工可执行的检查 只能靠作者感觉“差不多”

Harness 的成熟度,最终会落到 spec 密度、测试密度和循环密度这三件事上。

模式速查表

需求关键词 对应模式 工程动作
输出不稳定 缩小采样箱体 加示例、rubric、schema、测试
任务太大 降维 拆阶段、拆模块、拆子 Agent
上下文切换频繁 减少 context refill 外部笔记、状态摘要、检索索引、稳定工作集
上下文变长后跑偏 外部状态回灌 spec 文件化,作为 tool result 反复插入
上下文装不下 context paging 按需 page in 关键材料,page out 噪声和旧轨迹
模型忘记目标 可继承状态 progress、issue、git commit、decision log
结果无法验收 验证优先 先生成测试和验收清单,再实现
需要精确计算 工具化 调计算器、代码、数据库、解析器
多 Agent 互相干扰 上下文隔离 每个 Agent 独立职责、独立输入、汇总输出
长程无人接力 循环和 hook 每轮读取状态、执行、验证、写回、触发下一轮

收束

Harness 的本质,是把概率模型放进一个可验证的工作系统里。

裸模型有能力,但能力以分布形式出现。Spec 给它边界,测试给它目标函数,工具给它确定性执行,循环给它跨上下文寿命,子 Agent 给它注意力隔离。组合起来以后,模型不再只是一次性回答器,而是一个被工程系统托住的任务执行者。

未来的软件不会消失。相反,越确定、越专业、越可验证的软件越重要。变化发生在入口层:人不再直接操作所有软件,而是把意图交给一个能读文本、能调工具、能接工作流、能接受验证的 Agent。AI 改变软件世界的方式,不是把一切程序变成神经网络,而是把一切程序变成它可以调用的外部器官。

这就是 Harness 的位置。它不是提示词的升级版,也不是多 Agent 的包装词。它是概率智能进入确定性工程世界时,需要穿过的那层控制系统。

相关文章

参考资料