详解:拒绝“盲盒开盲打”,手把手教你用 Harness 节奏驱动 AI Agent

阅读提示:这是主文《 用真实项目讲透:如何通过 Harness Engineering 从 0 到 1 开发 AI Agent 》的配套实操教学版。如果主文解决的是“什么是 Harness、为什么重要、整体架构怎么搭”,这篇文章只解决一件事:当我不再亲手写所有代码,而是开始把执行权放给一个强但非确定性的模型后,在真实项目里,我到底是怎么敲下每一行输入、怎么判断 Codex 回得对不对、以及怎么把它死死拉回正确轨道的。

0. 为什么要单独拆这一篇实操指南?

在主文中,我尽量把 Harness 的理念讲透,但为了保证文章的阅读节奏,隐藏了大量枯燥的交互细节。

这会带来一个天然的断层:看理念觉得“醍醐灌顶”,回工位一敲键盘依然是“让模型自己看着办”。

所以更好的做法,是把这部分单独剥离出来,写成一份实施手册。这一篇不再追求流畅的“文章感”,而是追求极致的“可操作性”。我会直接把 Aegis 项目里最真实的推进方式,提炼成可复用的输入节奏和判断框架。

也可以把它理解成:如果主文讲的是“为什么程序员必须从执行者迁移成控盘者”,那这篇讲的就是“当你真的开始放权以后,具体该怎么控盘”。

:warning: 高亮排雷:关于 sdd-riper 的误区开始前必须澄清:我这里使用的 sdd-riper(或 sdd-riper-one-light),绝对不是业界主流那种要求写大而全的 Spec、有着繁重 Phase 切换、充满仪式感的传统 SDD。在我的实战中,它更像是一套极简的实施层通信协议,只用来卡死下面这五个关键动作。总结一下层级关系:Harness 是架构理念,负责回答"为什么要这样设计系统";而 sdd-riper-one-light 是实施协议,负责回答"我敲键盘时具体怎么把它控稳"。

0.5 先把视角拉回 Harness:我真正控制的到底是什么?

如果只把下面这些做法理解成“我很会跟模型说话”,那还是低估了 Harness。

我后来回头翻 Aegis 项目的本地资料,包括交接文档、分析笔记、以及 Codex 基目录下的一批原始 jsonl,越来越确定一件事:我真正反复在控制的,不是几句话术,而是一个面向非确定性执行的架构控制面。

Aegis 里最有代表性的真实 case,几乎都能按下面这 6 个控制面归类:

  1. 目标建模与轨道定义:项目刚起步时,我不是说“你先写一个 Agent 出来”,而是让它先读架构设计、再读参考项目、再复述主线。真实对话里一开始讨论的就是 reference_spikebackend detach对话层迁移 这些轨道,而不是“先写个接口试试”。

  2. 外部记忆与真相源:跨线程时,真实起手式经常只剩一句“阅读某份 handoff / spec 恢复任务”。这不是文档洁癖,而是在给系统提供一个可回读、可校验、可恢复的任务状态基座。

  3. 运行时 guardrail 与诊断能力:真正把项目拉开差距的,不是“能聊”,而是遇到 chat 接口直接空结束、改完后频繁 504 gateway timeout、更新后接口全是 403 这类问题时,系统有没有日志链路、事件链路和恢复路径。

  4. 执行回路与资产装配:很多看起来像 prompt 的问题,最后都会落到执行回路。比如 configkey 查询到底是先召回再喂模型,还是整包直喂;two_stagefull_prompt 怎么切;examplescases 到底会不会被加载、入口在哪里。

  5. 能力边界与业务骨架:项目往后走,问题不再是“模型会不会回答”,而是一个 skill 能不能从“查一个配置”长成“按组织批量检查管控项”,能不能被真实业务接口消费。

  6. 验证、发布、恢复闭环:真实收尾不是“代码写完了”,而是已经提到测试环境、跑过回归、看过日志、合过分支、确认能恢复。很多轮最关键的输入甚至不是“继续开发”,而是“我已经发布到 pre 环境了,接下来该怎么测试这些 case?”

你会发现,“反复复述核心目标”其实只是其中一个控制动作。它重要,但它服务的不是礼貌确认,而是整个 Harness 控制面的第一层:防止目标漂移。真正完整的 Harness,是把目标建模、状态恢复、执行门禁、运行时证据、验证闭环这些东西一起串起来。

1. 核心心法与全景 SOP 表

如果要把我带 Codex 干活的精髓浓缩成一句话,它绝对不是目前网上最流行的那句:

:cross_mark: “这是一个需求,请你作为资深工程师,帮我把功能完整写出来并测试通过。”

而是极其克制的:

:white_check_mark: “我在每一个阶段只给你一个带边界的输入;你必须先给我一个中间产物;我用 Harness 控制点核对无误后,才允许你进入下一步。”

为了方便大家抄作业,我把整套方法的 8 个阶段浓缩成了下面这张 SOP 总览表

建议把这张表保存在手边,接下来我们进入每一个阶段的拆解。

1.5 我真正盯的不是一句需求,而是“三层目标”

如果只把任务理解成一句大需求,你很容易在长链路里被骗。因为模型会显得很积极,也会不断产出东西,但它有可能已经偏离了你真正要收敛的主线。

我在真实项目里,真正盯的是三层目标:

  1. 总核心目标:整个项目或这一大阶段到底要完成什么,这是北极星,轻易不能变。

  2. 阶段性核心目标:当前这几轮对话,只允许收敛哪一个主问题。

  3. 本轮动作目标:这一轮具体只允许它做哪 1 到 3 个动作。

这三层不能混着用。真正危险的,不是模型不会做,而是它会绕过阶段目标,直接朝着自己理解的“总目标”乱冲,于是表面上很努力,实际上不断偏航。

Aegis 里有一个特别典型的真实例子。我们当时在交接文档里写得很清楚:

  • 总目标:将对话层切到 LangGraph,执行层保持不变,并保留可回滚能力。

  • 阶段目标:先恢复 handoff 和 spec,确认当前代码与开关状态;再跑 case 回归;最后按失败类型修复。

  • 本轮动作目标:先定位为什么 chat 接口会出现 RUN_STARTED -> TEXT_MESSAGE_START/END -> RUN_FINISHED 这种“直接空结束”的现象。

换句话说,总目标从来不是“把整个系统一口气做完”。总目标只负责指北;真正驱动你这一轮输入和判断的,是阶段性核心目标。

在另一个更贴近“手把手带模型干活”的案例里,这种分层会更明显。Aegis 某轮权限边界治理时,我最后给出的完成判断不是简单一句“做完了”,而是明确区分了两层:

“如果你问的是‘这次最小收敛任务是否完成’,答案是完成了。 如果你问的是‘整个项目所有类似权限边界是否彻底治理完’,那还没有,当前只是把这条 security policy 主链先收住了。”

这句话非常重要。因为它准确体现了 Harness 的一个核心动作:把‘阶段完成’和‘全局完成’严格分开。

2. 为什么这套“笨”方法反而最高效?

很多人在尝试 Agent 项目时感到挫败,并不是因为底层大模型智商不够,而是默认采用了极其随意的协作姿势

  • 一上来不给边界,直接甩需求让它梭哈。

  • 做到一半,不要求它做状态沉淀。

  • 遇到长链路任务,不强制它做拆分。

  • 动手改关键代码前,不做 Checkpoint 确认。

  • 收尾时,凭模型自己的一句“我已经完成了”就信以为真。

这种“放养模式”的致命缺陷是:模型每一轮的回复看起来都很积极、代码写得飞快,但整个系统正在加速腐烂,最终不可用。

我最终在实战中收敛出来的,不是某一段“能让 AI 顿悟”的魔法 Prompt,而是一套铁血纪律的输入节奏

  1. 先让模型解释,不让模型马上实现。

  2. 先拿中间产物,不让模型直接声称完成。

  3. 先看外部证据,绝对不相信模型的自我评价。

  4. 每一轮都强制回写,为下一轮准备干净的恢复点。

从 Harness 架构的角度看,这套方法精准狙击了四个绝症:防止目标漂移、防止状态蒸发、防止长链路偏航、防止质量失真。

2.1 为什么我会不断逼它复述核心目标?

这是我在真实项目里最常做、也最有效的动作之一。

很多人听到“复述”会以为这只是礼貌确认,或者是为了显得流程更完整。但在真实工程里,复述不是客套,而是反漂移装置。我不是为了听模型说漂亮话,而是为了确认:

  1. 它理解的总目标是不是还对。

  2. 它当前盯的阶段目标是不是还对。

  3. 它这一轮准备做的动作,是不是还在服务这个阶段目标。

我一般不会让它每一轮都机械重复一遍,而是只在四个节点强制复述:

  1. 阶段开始时:先复述总目标和当前阶段目标,确认没有理解偏差。

  2. 执行前 checkpoint:先复述当前理解、核心目标、下一步动作和验证方式。

  3. 日志/测试反馈回来后:先复述“当前目标是否还成立、剩余差距是什么”,而不是直接继续乱修。

  4. 阶段收尾时:先复述“这次最小收敛是否完成、还有什么没完成、下一轮目标是什么”。

真正有效的不是“让模型记住一次”,而是在关键节点反复把它拉回同一个锚点

2.2 这件事在真实对话里长什么样?

下面这些都不是我事后编的模板,而是 Aegis 项目里真实出现过的输入风格。

项目刚开始时,我不是让它直接做,而是先让它复述方向:

用户: “此项目是一个空的 python 项目,然后阅读架构设计文档,大体上了解一下我想做什么,然后向我复述需求并和我讨论。”

Agent: “我会先阅读你给的架构文档,然后用我的话复述需求并和你讨论实现方向。”

跨线程恢复任务时,我不是让它‘接着写’,而是先恢复目标:

用户: “阅读 2026-03-07_Chat_Handoff_FullLangGraph.md 恢复任务。”

这句看起来很短,但背后其实已经隐含了一个 Harness 动作:先恢复任务锚点,再决定下一步。

真正执行前,我会卡 checkpoint,而不是让它直接冲:

“先别改代码。你先总结当前理解、核心目标、下一步动作、风险和验证方式;我确认后你再执行。”

日志回来以后,我最关心的也不是‘修没修’,而是‘目标是不是还对’:

“不要主观判断是否完成。去看测试、日志和接口的实际回包,基于事实再告诉我现在是什么状态。”

如果你把这几句连起来看,你会发现我真正反复在做的,是同一个动作:不断把模型从“自由发挥”拉回“围绕当前核心目标办事”。

2.3 模型一旦开始偏,我怎么判断?又怎么拉回来?

这一点我觉得特别值得单独写,因为很多人以为 Harness 的价值只在于“让模型一开始别跑偏”。但真实工程里,更常见的情况是:它不是一开始就错,而是做着做着慢慢偏。

我自己最常盯的,其实是下面这 4 个偏航信号:

  1. 它开始绕过阶段目标,直接谈总目标。 比如这一轮明明只该定位 chat 空结束,它却开始讨论“整个 LangGraph 迁移怎么一次补齐”。

  2. 它开始跳过中间产物,直接声称要改代码。 这通常意味着它已经不想被 checkpoint 约束了。

  3. 它开始用主观语气替代客观证据。 比如“我认为应该已经解决了”“看起来没问题了”,但没有日志、没有测试、没有回包。

  4. 它开始混淆阶段完成和全局完成。 明明只是收住了一条主链,却很容易在话术上制造“整个问题已经解决”的错觉。

一旦出现这几种信号,我一般不会和它争论,而是直接改成更硬的输入,把它重新压回当前阶段目标。我的真实句式通常就是这几类:

“先停,不要继续展开。你先复述:这轮阶段性核心目标到底是什么,不要谈总目标。”

“先不要改代码。把当前理解、下一步动作、风险和验证方式重新写一遍,我确认后你再动。”

“不要主观判断。去看日志、测试结果和接口实际回包,基于证据再回答。”

“不要把这次最小收敛和全局完成混为一谈。你明确告诉我:这轮到底完成了什么,还没完成什么,下一轮最小目标是什么。”

你会发现,我几乎从不靠“提醒它聪明一点”来纠偏,而是靠重新设门禁、重新压目标、重新要求证据来纠偏。 这就是为什么我一直说,Harness 不是说服模型,而是约束模型

3. 分阶段详解:我是怎么一步步操纵 Codex 的

3.1 阶段一:先让 Codex 理解项目,不让它立刻写代码

这个阶段的核心绝不是“马上出活”,而是先排雷。我要确认它理解的目标对不对?它抓到的主线对不对?它会不会一开始就猛踩油门冲进死胡同?

:light_bulb: 我的真实输入格式:

“请先阅读架构设计文档,理解这个项目我要做什么。注意:不要急着实现任何功能。 先用你自己的话复述你的理解,并告诉我你认为当前的项目主线应该怎么收敛。”

:bullseye: 我期待它返回: 任务目标的复述、主线路径的判断、它嗅到的技术边界和疑问。如果不对,就在这一步骂回去重来。

这不是一个“演示用模板”,而是 Aegis 起步时真实出现过的输入方式。更原始的一句是:

“此项目是一个空的 python 项目,然后阅读架构设计文档,大体上了解一下我想做什么,然后向我复述需求并和我讨论。”

注意这里最重要的不是“阅读文档”四个字,而是后半句:“向我复述需求并和我讨论。” 这决定了项目的起手式不是“先写点什么”,而是“先让目标不漂移”。

3.2 阶段二:把任务从聊天窗口搬到“外部真相源”

当任务跨天、或者对话轮次过长时,聊天窗口的 Context 已经成了糊涂账。这时候绝对不能让 Codex “凭印象接着干”。

:light_bulb: 我的真实输入格式:

“先阅读这份 Spec / Handoff 文档。读完后告诉我:现在任务整体做到哪里了?还剩什么没做?你准备从哪一段接着推进?”

:bullseye: 我期待它返回: 已完成项、未完成项、当前的真实进度判断、它的接续点建议。这一步的本质,是让系统状态强行恢复。

Aegis 里这一步经常短到只剩一句话:

“阅读 2026-03-07_Chat_Handoff_FullLangGraph.md 恢复任务。”

但这个动作的工程含义非常重。因为 handoff 里不是流水账,而是明确写了:

  • 本次总目标是什么

  • 已完成什么

  • 关键配置开关是什么

  • 下一轮建议先做什么

像那份真实 handoff 里,下一轮建议就直接写成了:

  1. 先确认 pre 环境的 AGENT_GRAPH_*NL2OPS_GRAPH_ENABLED 开关。

  2. 35 case 的 contract-only 回归。

  3. 汇总失败分布,优先修复命中率问题。

这就是为什么我一直强调:Spec / Handoff 不是文档负担,而是 Agent 项目的外部记忆系统。

3.3 阶段三:让它自己点菜,拒绝上下文“整包投喂”

很多团队一遇到报错,就本能地把几万字的文档全贴进去。真正稳定的做法是给入口、给索引,让它自己说需要看什么,保护宝贵的 Context Window。

:light_bulb: 我的真实输入格式:

“当前先以这份 Spec 为主,你可以按需查阅 Handoff 和这组 Examples要求:不要整包吞全部文档。 先评估一下,为了完成下一步,你当前最需要我提供哪几块具体的上下文?”

3.4 阶段四:强制拆动作,严禁“一口吃成胖子”

进入实现阶段前,坚决打断模型试图一次性写完几百行代码的冲动。

:light_bulb: 我的真实输入格式:

“先不要试图把整条链路一次做完。这一轮我们只处理 reference spike 的主链迁移。请把它拆成 1 到 3 个最小可推进的编码动作,然后逐一说明每个动作你要怎么验证。”

3.5 阶段五:设计执行链路,而不是无脑改 Prompt

遇到卡壳,很多人的第一反应是“是不是 Prompt 没写好?”但在真实工程里,往往是底层的调用链路(Pipeline)选错了。必须要让 Agent 明白:这里的链路,不是让它换种语气说话,而是在代码库里真实存在的、不同的执行图或脚本分支

:light_bulb: 我的真实输入格式:

“针对这个问题,先分析这一步的物理执行流应该路由给哪个确定的管道:是走 two_stage(先检索再生成的预设脚本)还是 full_prompt(全量投喂脚本)?ExamplesCases 应该以什么机制装配进当前的物理链路里?如果需要优化该链路下的子 Prompt,你需要我提供哪些真实的回放数据(Replay)支持?”

这一类问题在 Aegis 里出现得非常频繁。真实对话甚至会更口语一些:

“我们刚才做了一版重构,把 skill 进行了拆分,examples 和 cases 可以加载吗,如何加载?”

还有一轮更能说明“这不是 prompt 文案问题,而是执行回路问题”:

用户: “我们在做 configkey 查询的时候,是先召回再喂大模型,还是一次性把所有东西都喂给大模型?”

Agent: “关键分界是:先用本地规则和配置目录做候选召回,只有多个候选还歧义时,才调用一次小范围 LLM 选择,不是把全量 catalog 直接扔给模型。”

而 Agent 的第一反应不是“我给你编一个说法”,而是:

“我先按 sdd-riper-one-light 的方式收敛一下:这次先不改代码,我会快速确认当前 refactor 后 skill 的加载链路,重点看 examplescases 这两类内容现在是否会被扫描、入口在哪、实际该怎么触发。”

这才是我想强调的“手把手”细节:很多所谓的 prompt 问题,本质上其实是在问‘这类资产有没有进入执行回路、是自动注入还是按需读取、入口到底在哪里’。

3.6 阶段六:执行前 Checkpoint(极其重要!)

这是整个协议里含金量最高的一个动作。当它准备好一切要动手改代码前,强行踩一脚刹车。

:light_bulb: 我的真实输入格式:

“**先别改代码!**在动手前,请做一次 Checkpoint,向我总结:1. 当前理解 2. 核心目标 3. 下一步具体动作 4. 潜在风险 5. 你的验证方式。只有我回复确认后,你才可以进入执行。”

3.7 阶段七:看外部证据,拒绝模型的“主观滤镜”

到了验证阶段,大模型最喜欢当理中客:“代码已修改,我认为问题已经解决。”——这时候必须打断它的自我陶醉。

:light_bulb: 我的真实输入格式:

“不要主观判断是否完成!去看最新的单测结果、看运行 Log、看 SSE 链路的断点、看接口的实际回包。基于这些客观事实,再告诉我现在哪些结论是真的,哪里还在报错。”

Aegis 里这一步经常不是“跑个测试”这么简单,而是要根据问题类型换证据源。

如果是运行时异常,我会直接让它盯链路证据:

用户: “阅读代码,告诉我为什么 chat 接口直接结束任务了:RUN_STARTED -> TEXT_MESSAGE_START/END -> RUN_FINISHED

Agent: “我先按现有代码把 chat 接口这条 SSE 链路找出来,重点看 RUN_STARTED -> TEXT_MESSAGE_START/END -> RUN_FINISHED 之间哪里会在没有文本输出时直接收尾;这次先做定位和原因分析,不改代码。”

同一类运行时 guardrail 问题,后面还连续出现过:

  • “此项目在昨天改动之后,就经常会报错 504 gateway timeout,这是为什么?”

  • “为什么更新之后所有接口都是 403?”

这些都不是“再改一版 prompt 看看”的问题,而是已经进入了真实运行链路的故障诊断。到了这一步,你有没有日志、有没有链路视角、有没有分阶段恢复能力,决定了这个 Agent 项目到底是工程系统,还是聊天演示。

如果是常规验证,我也不会让它直接乱跑,而是先缩小验证范围:

用户: “运行单测。”

Agent: “我来先确认这个仓库的测试入口和构建方式,然后只跑最合适的单测命令,尽量避免做高开销的额外动作。”

后面它还会继续自己做一次小 checkpoint:

“当前理解:你要我在这个仓库里执行 Python 单测,而不是编译、打包或跑前后端全量链路。 核心目标:优先跑 tests/unit。 下一步:执行最小范围的 pytest。 验证方式:以 pytest 的退出码、通过/失败/报错统计为准。”

这一段特别能说明我的方法:我不是让模型“去验证一下”,而是让它先定义清楚‘这次验证到底验证什么、验证到什么粒度、什么算证据’。

3.8 阶段八:强制回写,防止经验蒸发

任务不是死在“做不完”,而是死在“今天做完了,明天全忘了”。

:light_bulb: 我的真实输入格式:

“任务暂停。请把这一轮我们具体做了什么、用什么客观手段验证了什么结论、以及还剩哪些 Bug/待办没做,全部规范地回写到 Spec / Handoff 文档里,保证下一轮能直接无损接着干。”

3.9 阶段九:阶段完成不等于结束,要把真实环境反馈再喂回模型

很多人做到这里就停了:本地单测过了、代码看起来也顺眼,于是宣布“这一阶段完成”。但在真实项目里,这通常还远远不够。阶段性核心目标真正完成的标志,不是模型说它做完了,而是它已经在真实链路里经受过 Review、测试环境验证、人工操作和日志回放。

我实际采用的节奏通常是这样的:

  1. 先 Review:确认这一轮改动有没有偏离最初的阶段目标,有没有为了修一个点顺手污染主架构。

  2. 再提测试环境:把模型认为“已经完成”的结果放到更接近真实运行时的环境里接受检验。

  3. 做手动测试:用真实的操作路径去点、去试、去复现,而不是只看模型挑过的那几个 happy path。

  4. 回收运行日志:把接口回包、报错堆栈、链路日志、异常现场整理出来,不靠印象判断。

  5. 把日志重新喂回模型:让它基于真实证据解释“问题到底解决到哪一步了、还差哪一步、下一轮最小核心目标是什么”。

这不是我事后总结出来的漂亮流程,Aegis 里真实就有过这种输入:

“查看此分支的提交,特别是最近的提交。我已经把代码发布、部署到了 pre 环境,我该如何测试这几个 case?”

注意这句的重心已经完全不是“继续写代码”,而是把代码推进到真实环境以后,如何把测试路径、验证证据和下一轮修复入口重新组织起来。

这一步非常关键,因为它把“模型执行”变成了“证据驱动的再收敛”。也正是在这个意义上,我理解的 Harness,不是放任模型一路做下去,而是不断设定阶段性核心目标,不断检查是否真的完成,不断把真实世界的反馈重新灌回这个闭环里。

这里我再放一个我非常喜欢的真实收尾句子,因为它最能体现“总目标”和“阶段目标”的区别:

“从这次约定的范围看,完成了。 …… 所以如果你问的是‘这次最小收敛任务是否完成’,答案是完成了。 如果你问的是‘整个项目所有类似权限边界是否彻底治理完’,那还没有,当前只是把这条 security policy 主链先收住了。”

这段话表面上像总结,实际上是 Harness 里非常硬的一步:把“阶段完成”明确说清,把“尚未完成的总目标”也明确说清。

如果你不逼模型做到这一点,它就会特别容易在阶段性交付时制造一种错觉:看起来好像一切都完成了,实际上只是某条主链暂时被收住,系统层面还有大量剩余工作没有被重新定义。

4. Mini Walkthrough:一轮真实的推进与纠偏推演

为了让大家感受这套节奏的连贯性,我把上述步骤串成一次提炼过的完整实战推演。

【起点】我绝不这样开场: “帮我把这个 Agent 的后端全写出来。”

【我的起手式】: “先读架构设计文档,理解我要做什么;不要急着实现,先复述你的理解,并告诉我你认为项目主线应该怎么收敛。”

【收敛后】我绝不说: “好的,开始写吧。”

【我的追问】: “好,既然对齐了,现在先把这轮任务压成一份最小 Spec,写清目标、范围和边界;没有我的允许,不要展开具体的实现细节。”

【第二天恢复】我不说: “接着昨天那个接口继续写。”

【我的强制拉起】: “先读昨天落盘的 Spec 和 Handoff 记录,告诉我现在做到哪里了、还剩什么、你建议从哪一段接着起手。”

【真正动手前】我不说: “那就按你的建议改吧。”

【我的门禁 Checkpoint】: “先别改代码。做一次 Checkpoint,总结当前理解、核心目标、下一步动作、风险和验证方式;我确认无误后你再执行。”

【改完代码后】我不接受: “我觉得已经修好了。”

【我的客观验证】: “不要用主观判断。去看测试、日志和接口的实际回包,基于事实再告诉我现在是什么状态。”

【阶段验收】我也不直接说: “那这轮就结束了。”

【我的真实闭环】: “先过一遍 Review,再提到测试环境做手动验证;把新的日志和现场现象再带回来,让模型基于真实证据重新判断:这一阶段的核心目标到底是不是已经真正完成了?如果没有,下一轮最小目标是什么?”

【准备下班】我不直接关网页。

【我的闭环约束】: “把这一轮实际做了什么、验证了什么、留了什么坑,全部回写到 Spec/Handoff 里去。”

5. 真实回合里最关键的不是顺利,而是纠偏

如果你去翻我在 Aegis 里的很多真实记录,会发现最有价值的部分往往不是“模型一路做对了什么”,而是它开始偏的时候,我怎么把它拽回来。

一个非常典型的真实链路,大致就是这样:

  1. 我先让它读 handoff 恢复任务。 这一步的目标不是“赶紧继续干”,而是先把总目标、阶段目标和当前状态重新对齐。

  2. 它开始想直接推进实现。 这时候我不会顺着它走,而是先卡一个 checkpoint,让它重新说清当前理解、下一步动作和验证方式。

  3. 跑到运行时,真实日志开始反咬。 例如 RUN_STARTED -> TEXT_MESSAGE_START/END -> RUN_FINISHED 这种空结束,或者改完以后出现 504403

  4. 我不会让它继续“顺手多修几个点”,而是重新压缩阶段目标。 原来更大的阶段目标可能是“收敛 LangGraph 对话层”;但在这一刻,本轮最小目标会被重新定义成“先定位 chat 为什么直接收尾”。

  5. 它定位完、修一轮以后,我也不会立刻认定完成。 我会把它推进到测试、日志、pre 环境和手动验证上,看这次最小目标是不是真的收住了。

  6. 最后我再逼它明确区分两件事。 这次最小收敛是否完成?整个系统性的总问题是否完成?如果没有,下一轮最小目标是什么?

这整条链路里,最关键的变化其实只有一句:

阶段目标不是一开始定完就不动了,而是要随着真实证据不断重新对齐。

所以我后来越来越不把 Harness 理解成“严格按预设流程走完”,而是更像一种动态控盘能力

  • 大方向靠总目标锚住

  • 当前轮次靠阶段目标收束

  • 一旦证据变了,就马上重定义这一轮的最小目标

这才是为什么我会不断让模型复述、不断让它 checkpoint、不断让它看日志、不断让它重新说“现在到底做到哪一步了”。 表面上看是在重复,实际上是在持续把非确定性的执行重新压回可控轨道。

6. 一个更完整的真实 session 拆解

如果前面的内容还是偏“抽象总结”,那我这里再给一版更接近真实工位现场的拆解。 这不是逐字稿,但节奏、判断点和 Aegis 里的真实推进方式是一致的。

Round 1:先收敛,不实现

我的输入:

“先读架构设计文档,不要实现;先复述你理解的目标,并告诉我当前项目主线应该怎么收敛。”

我想拿到的不是代码,而是这三样:

  1. 它理解的总目标

  2. 它看到的阶段主线

  3. 它识别出来的边界和疑问

这一轮如果它开始主动谈实现,我会立刻打断:

“先别实现。你先把目标和边界说清楚。”

Round 2:压成最小 spec

我的输入:

“现在把这轮压成一份最小 spec,写清目标、范围、约束和暂不处理项;没有批准不要进入实现。”

我真正想确认的是:

  • 它是不是知道这轮只做 spec

  • 它是不是已经把“先不做什么”说清楚

  • 它有没有偷偷把总目标混进本轮范围

如果它范围开始变胖,我会这样压:

“只保留这轮最小范围,其他都放到暂不处理。”

Round 3:跨线程恢复

我的输入:

“阅读 handoff / spec 恢复任务,先告诉我现在做到哪里了、还剩什么、你建议从哪一段接着推进。”

我最在意的是两件事:

  1. 它能不能基于外部真相源恢复,而不是靠印象

  2. 它有没有把下一步建议压成当前阶段目标,而不是重新开大坑

这也是为什么 Aegis 里会反复出现这种非常短的起手式:

“阅读 2026-03-07_Chat_Handoff_FullLangGraph.md 恢复任务。”

Round 4:执行前 checkpoint

我的输入:

“先别改代码。你先总结当前理解、核心目标、下一步动作、风险和验证方式;我确认后你再执行。”

这一轮我实际在检查 5 件事:

  1. 目标是不是还对

  2. 动作是不是够小

  3. 风险有没有被提前看见

  4. 验证方式是不是客观

  5. 它是不是又开始偷跑实现了

如果这一步说不清,后面执行越快,偏得越远。

Round 5:运行时反咬,重新定义阶段目标

执行以后,真实工程最常见的不是“顺利完成”,而是日志开始反咬。 比如 Aegis 里最典型的一轮,就是链路直接出现:

RUN_STARTED -> TEXT_MESSAGE_START/END -> RUN_FINISHED

这时候我不会顺着原来的大目标继续推进,而是立刻改写本轮目标:

“先不要扩展修复范围。当前阶段目标改成:只定位 chat 为什么直接结束。先做原因分析,不改代码。”

这一步非常像驾驶: 原本你在走大路线,但真实证据告诉你前面路塌了,那你现在的阶段目标就不能还是“开到终点”,而必须改成“先判断路为什么塌、还能不能走”。

Round 6:基于证据做阶段验收

定位和修一轮以后,我也不会直接接受“应该好了”这种说法。

我的输入:

“不要主观判断。去看测试结果、日志、接口回包和测试环境现象,基于证据回答:这次最小目标是否完成?如果没有,还差什么?”

这一轮我只认三类东西:

  1. 测试结果

  2. 日志和链路现象

  3. 测试环境或手动验证的现场证据

这时如果它回答:

“这次最小收敛任务完成了,但全局同类问题还没有彻底治理完。”

我会认为它终于真正进入了 Harness 的节奏。

7. 可直接照抄的 Harness 句式清单

如果你只想把这篇文章变成可以立即上手的东西,那这一节最适合直接拿去用。 这些句式不是为了“写得像 prompt 大师”,而是为了在关键节点稳定地卡住控制点。

7.1 起手收敛

先读架构设计文档,不要实现。先用你的话复述你理解的目标,并告诉我你认为当前项目主线应该怎么收敛。
先不要写代码。你先说清楚:总目标是什么,当前阶段目标是什么,你看到的边界和疑问是什么。

7.2 压最小 spec

先把这轮任务压成最小 spec,写清目标、范围、约束、暂不处理项;没有我的批准,不要进入实现。
这轮只允许收敛一个阶段性核心目标,不要把总目标里的其他事情一起带进来。

7.3 恢复任务

先读这份 spec / handoff 恢复任务。告诉我现在做到哪里了、还剩什么、你建议从哪一段接着推进。
不要凭印象续写。先以 handoff 为准,恢复当前状态,再说下一步。

7.4 执行前 checkpoint

先别改代码。做一次 checkpoint:总结当前理解、核心目标、下一步动作、风险和验证方式;我确认后你再执行。
进入执行前,你先重新复述这轮阶段性核心目标,不要谈总目标。

7.5 发现偏航时

先停,不要继续展开。你先复述:这轮阶段性核心目标到底是什么,不要谈总目标。
你现在开始超出本轮范围了。把范围重新压回当前阶段目标,只保留这轮必须收敛的部分。
先不要改代码。重新写一遍当前理解、下一步动作、风险和验证方式。

7.6 基于证据验证

不要主观判断是否完成。去看测试、日志、SSE 链路、接口回包和现场现象,基于事实再回答。
先定义清楚:这次验证到底验证什么、验证到什么粒度、什么算完成证据。

7.7 阶段验收

不要把这次最小收敛和全局完成混为一谈。明确告诉我:这轮完成了什么,还没完成什么,下一轮最小目标是什么。
先过 Review,再提测试环境做手动验证;把新的日志和现场现象带回来,再判断这轮阶段目标是否真正完成。

7.8 收尾回写

任务暂停。把这一轮实际做了什么、验证了什么、还剩哪些问题没做,全部回写到 spec / handoff,保证下一轮能直接接着干。
请把本轮的完成项、未完成项、真实偏差、残留风险和建议的下一轮目标写回外部文档。

8. 总结:只要记住这三句话就够了

如果你看完整篇教程,只能带走三样东西,我希望是下面这三句话:

  1. 改变输入习惯:我不再是“给大模型提一个大需求”,而是在系统推进的每一个阶段,给它一个“带极强边界和约束条件的输入”。

  2. 拿回控制权:我坚决不让模型一路黑盒做到底。它必须先交出中间产物,由我通过 Harness 控制点判断能不能放行到下一步。

  3. 理清层级Harness 是我做大工程的底层理念,而 sdd-riper(一轻量版)是我用来把这套理念变成肌肉记忆的实施协议。

把这篇实战指南压缩成最后一句:

真正高段位的 AI Agent 开发,不是在赌“模型能不能自己奇迹般地做完”,而是用 Harness 设计出一套连续的轨道节奏,再用极其克制的通信协议把这套节奏卡死。

5 个赞

太干货了啊佬!收藏!我将周末全职研究这个harness

太干货了

赶紧放到iflow 2.0心流助手里逐帧学习

1 个赞

心流助手直接前情摘要

1 个赞