从 Prompt 到 Harness:我对 Agent 工程的理解
刚开始使用大模型时,我最关心的是:怎么把话说清楚,让模型给出更好的回答?
后来,我开始做 Agent,发现问题逐渐变了。模型不只是回答问题,它还要读取文件、调用工具、处理结果,甚至跨越多轮对话和多次运行,持续完成一项任务。
这时候,光把提示词写好已经不够了。我还需要考虑:模型每一步能看到什么?工具出了问题怎么办?任务进行到一半被中断,下一次怎么继续?最终又凭什么判断它真的完成了?
一、Prompt Engineering:先把任务说清楚
刚接触 ChatGPT 的时候,面对一个空白输入框,很多人都不知道该怎么提问。
于是,我们开始学习写提示词:交代背景,描述目标,说明限制,给出示例,再指定希望得到的输出形式。
比如,我想让模型解释一段代码。如果只说“解释一下”,它可能逐行翻译代码,却没有回答我真正困惑的问题。
如果我补充:“我是初学者,请结合一次请求的执行过程,解释这几个对象如何配合,以及异常会传递到哪里”,模型就更容易理解我需要什么。
提示词工程解决的,首先是如何把意图传达给模型。

延伸阅读:Prompt Engineering:我会怎样把任务交给模型
它并没有因为后来出现上下文工程或 Harness 工程而过时。任务没说清楚,后面的工具再多,也可能只是把错误的目标执行得更加彻底。
但随着任务变复杂,我发现模型能否做好一件事,不仅取决于我怎么提问,还取决于它能看到哪些信息。
二、Context Engineering:让模型在合适的时候看到合适的信息
普通聊天里,上下文可能主要是我和模型之前说过的话。
但在 Agent 中,上下文的来源多得多:系统指令、用户任务、历史消息、工具定义、工具返回、检索结果,以及任务执行过程中产生的状态。
比如,我让一个 Coding Agent 修复登录问题。它可能需要读取相关文件、搜索报错日志、运行测试,再根据测试结果继续修改。
每执行一次工具调用,就会产生新的信息。如果所有内容都不断追加到对话中,上下文会越来越长,真正重要的线索也可能被大量无关内容淹没。
这时候,我需要考虑的不只是“能塞下多少内容”,而是:
当前步骤需要哪些信息?
哪些历史记录应该保留,哪些可以压缩?
工具返回太长时,如何保留关键信息?
需要原始细节时,能否重新查到?
这就是我对上下文工程的理解:围绕当前任务,组织模型做决定时所需的信息。
好的上下文不是越长越好,也不是永远压得越短越好。它要让模型在有限的信息空间里,既能看到必要事实,又不会轻易丢掉关键约束。
但当我继续思考长时间运行的 Agent 时,又发现了另一个问题:即使模型看到了正确的信息,任务仍然可能因为执行过程中的各种问题而失败。
三、Harness Engineering:让整个工作过程具备完成任务的条件
假设我让 Agent 修改一个项目,并要求它确保原有功能没有被破坏。
如果我只是告诉它“修改完成后记得测试”,它也许会照做,也可能遗漏;它也许能读懂测试结果,也可能误判;运行中断后,它还可能忘记哪些工作已经完成。
于是,我开始把视线从模型的一次回答,转向模型周围的整个工作环境。
我可以给它提供读取和修改文件的工具,让它运行测试,把测试结果返回给它;我也可以记录当前任务状态,让它在中断后知道做到哪里;对于危险操作,还可以设置权限判断和人工审批。
这些东西没有直接改变模型本身,却改变了模型完成任务的方式。
为了方便理解,我暂时把 Agent 看成两部分:一部分是模型,负责理解、推理和生成;另一部分是围绕模型组织起来的执行环境,包括工具、上下文、状态、权限、验证和反馈。
我把后者理解为 Harness。

这是一种便于思考的简化。不同团队对 Harness 的边界可能有不同划分,但我更在意的是它背后的思路:当模型不能稳定完成任务时,不只想着换一个模型,还可以改进它工作的环境。
人解题时,有纸笔、计算器和检查方法,结果通常会比完全依靠心算更可靠。Agent 也是如此。模型负责做判断,工程系统则为它提供行动、观察和修正的条件。
Harness 的目标不是让模型从此不犯错,而是尽量减少整个任务对“模型每一步都恰好正确”的依赖。
四、为什么长任务尤其需要 Harness?
短任务往往可以在一次回答中完成。即使出了错,我也能直接看见,并重新提问。
但长任务不同。它可能要运行很久,调用很多次工具,还可能跨越多个上下文窗口。时间一长,问题就会累积:
做过的事情和没做完的事情混在一起。
模型认为功能已经完成,但实际缺少验收。
工具调用失败或超时,模型不知道下一步该怎么办。
任务中断后,新的运行不知道之前发生了什么。
这时,压缩上下文有帮助,但摘要本身不能解决所有问题。Agent 还需要能够查看任务进度、确认产物状态,并在新的运行中重新找到工作的起点。
例如,一个跨多次运行的开发任务,可以保存功能清单、进度记录和代码版本。下一次开始时,Agent 先查看当前状态,再选择下一步工作,而不是单纯依赖它“记得”之前的对话。
但我也不认为所有任务都需要这一整套东西。一次简单的文件查询,也许不需要跨会话恢复;一个不会产生外部副作用的只读工具,也不一定需要复杂的审批流程。
需要什么机制,应该由任务和失败方式决定。
五、Agent 出错时,我应该先看什么?
以前,我看到 Agent 做错事,第一反应往往是修改提示词:把要求写得更明确,再提醒它一次。
现在我更愿意先回看它的工作过程:它读到了什么?调用了什么?工具返回了什么?最后是在哪一步偏离目标的?
如果它不知道结果对不对,可能需要的不是更多提醒,而是一个能运行的检查方法,比如测试或静态检查。
如果它做着做着忘了进度,可能需要的是外部状态记录,让后续运行能够找到未完成的工作。
如果它拿不到必要的信息,可能需要补充工具、改善检索,或者重新组织上下文。
当然,也有可能是任务本身没有定义清楚,或者当前模型确实难以胜任。提示词仍然是可以尝试的改进方式,只是不应该成为不看原因的默认答案。
我觉得这里最重要的变化是:把一次失败当成线索,去寻找系统缺少了什么条件。
比如,加了一轮自动检查,确实发现了更多错误,但也可能让每次任务运行时间翻倍。它是否值得保留,要看这项检查解决的问题是否足够重要。
六、通用 Harness 和领域 Harness
继续往下想,我发现不同 Agent 之间,有些需求是共同的,有些则来自具体领域。
模型调用、工具执行、上下文管理、状态记录,这些能力很多项目都需要。我可以把它们理解为比较通用的基础能力。
但一个 Agent 到底要完成什么工作、允许做什么、怎样才算成功,则常常取决于具体场景。
例如,同样是生成一份报告,一个普通资料整理任务可能重点检查来源是否可靠;一个财务场景的报告,还需要核对数据口径、计算方法、时间范围,以及是否经过必要审批。
模型和基础工具可以相似,真正决定结果能不能使用的,却是这些具体规则和验收标准。
这也是我觉得领域 Harness 有价值的地方:把领域里的知识、工具、流程和判断标准,变成 Agent 工作时真正能够使用的条件。
不过,领域知识不是简单地往提示词里堆文档。更重要的是搞清楚:哪些信息需要在什么时候提供?哪些规则可以变成检查?哪些结果必须由人确认?
至于通用 Harness 未来会不会被模型厂商自己的产品挤压,我觉得这仍然是一个开放问题。模型厂商更了解自己的模型,也有动力优化配套环境;但第三方系统也可能因为跨模型支持、可控性或特殊场景而有自己的价值。
对我来说,眼下更实际的问题不是预测谁会赢,而是先区分:哪些能力可以复用,哪些判断必须结合我自己的任务来设计。
七、从哪里开始实践?
如果我已经有一个能够调用模型和工具的 Agent,不需要为了追求 Harness Engineering,立刻给它加上所有机制。
我可以先选一个具体任务,明确什么结果算完成,再让 Agent 实际跑一遍。出现失败时,查看过程,找出最关键的原因,然后只做一项有针对性的改进。
例如,Agent 经常声称“修改完成”,但没有检查原问题是否解决。我可以先补一组针对原问题的测试,再观察它是否会运行这些测试、能否根据结果继续修复。
做完之后,用相同的任务重新验证。如果结果没有改善,就继续分析,而不是默认这个新机制一定有用。
慢慢积累下来的,不只是某一版提示词,还有任务样本、失败轨迹、检查方法,以及对系统边界越来越清楚的认识。
这就是我目前对这三个概念的理解:Prompt Engineering 帮我把任务说清楚;Context Engineering 帮我组织模型需要的信息;Harness Engineering 则让我进一步思考,怎样让模型在一个能够行动、获得反馈、处理错误并持续推进的环境里完成任务。
三者不是互相替代的关系。提示词仍然重要,上下文仍然重要,而工具、状态、验证和恢复让它们能够在更长、更复杂的任务中发挥作用。