Agent = Model + Harness,那 Harness 能让模型更聪明吗?

假设你让 AI 整理上个月的 14 张发票,做成一张人民币报销表,写清每一笔花了多少钱、在哪儿花的、属于哪一类。

AI 很快交出了一张整齐的表格,列出了 14 笔明细和合计金额。你抽查到其中一笔香港酒店的费用,发现发票写的是港币,AI 却直接把票面数字加进了人民币总额,没有换算。

你不知道其他 13 笔里还有没有类似的错误,只好从头核对一遍。AI 省下了填表的时间,但你仍然需要检查每笔记录,才能放心把表交出去。

在这个假设里,AI 读完了所有发票,填全了明细,也没有算错加法。问题出在它没有把「这笔费用是港币」和「这张表要用人民币报销」联系起来。

这类错误让人困惑,因为 AI 看起来已经把事情做完了。它有工具,能读文件,也能生成表格,为什么还是不够可靠?增加检查步骤、操作说明和工作流程,能不能减少这种错误?

什么是 Harness

你在聊天窗口里说「把这些发票整理成报销表」,过一会儿就收到了文件。这个过程看起来像是模型读完发票,再把表格写出来,但从你提出要求到拿到文件,中间还有许多工作需要模型之外的系统完成。

以这次报销任务为例,假设助手需要调用工具读取发票、汇总金额,再生成表格。我们先看它怎样读取一张发票。

系统先把文件列表和读取工具的说明交给模型,让它知道有哪些文件、可以怎样读取。模型据此提出请求,比如「读取第二张发票」,读取工具便打开文件、提取内容,系统再把结果交回模型。模型看到内容之后,才能决定记录哪些信息、还要不要查看其他文件。

工具就是供模型调用的具体功能。 读取文件、搜索邮件、运行计算、生成表格,都可以做成工具。每个工具都接收特定的输入,并返回结果。例如,读取工具根据文件路径找到文件,返回文件内容或读取失败的原因;计算工具接收算式,返回计算结果。模型负责提出调用请求,实际操作由工具执行。

但有了工具,这件事也不会自动完成。哪些工具现在可以使用?模型有没有权限读取指定的文件?读取失败后,系统怎样告诉模型失败原因?任务做了一半,系统怎样让模型在后续处理中记得哪些发票已经处理过?生成表格后,是继续检查,还是把文件交给用户?这些都需要系统组织和管理。

围绕模型安排这些工作的系统,就是这里说的 Harness。 它把用户要求、任务材料和可用工具的说明交给模型,执行模型发出的工具调用,再把结果交回模型,让模型继续处理任务。你收到最终回答之前,模型可能已经多次调用工具,并根据每次返回的结果决定下一步。

工具可以由产品团队实现,也可以连接外部服务。例如,邮件工具连接邮箱服务,完成保存草稿或发送邮件的操作。Harness 提供工具说明、检查调用权限,并把结果交回模型,但不需要自己实现整个邮箱服务。

指令和技能文档也参与这个过程,但它们的作用不同。「报销金额统一用人民币」是在说明任务要求;「遇到外币时,先确认汇率来源和日期,再换算」是在提供处理方法。计算工具负责执行模型提交的算式。系统在什么时候提供哪条指令、哪份文档和哪些工具,会影响模型接下来做什么。

现在回头看那张报销表,就能看出问题出在哪里。读取工具可以准确返回港币金额,计算工具可以正确加总模型提交的数字,表格工具也可以正常生成文件,但如果模型没有意识到需要先换算,最后的报销金额仍然会算错。Harness 让这些操作得以完成,模型则需要理解金额该怎样处理。

即使只聊天,不调用工具,系统也要为模型准备信息。它会把相关的历史对话和默认指令一起交给模型,对话太长时,还可能删减或概括旧记录。你觉得助手「记得前面说过什么」,往往是因为系统再次提供了那些信息。所以,聊天助手的表现从来不只取决于选了哪个模型,也取决于模型每次实际收到什么,以及它的输出怎样被处理。

DeepSeek 在介绍自己的 Harness 时,用「Agent = Model + Harness」这个等式说明两者的关系:一个 Agent 由模型和 Harness 共同组成。这里可以先把 Agent 理解为能够为完成任务调用工具,并根据结果继续行动的 AI 助手。这个等式解释了 Agent 由什么组成,至于模型和 Harness 分别怎样影响它的表现,我想进一步谈谈自己的理解。

我的看法是,模型的能力对应一个分数范围。Harness 能让模型的发挥更稳定,提高下限,也让它更有机会发挥出较高的水平。至于最高能达到什么水平,我认为主要由模型决定。

举个例子,假设一个模型的表现最低可以是 0 分,最高可以是 100 分。这些数字只是为了方便说明我的理解,不是实测分数。没有合适的 Harness,它可能缺少必要材料,或者在执行中途出了问题,最后得到一个低分结果。好的 Harness 把这些可以避免的问题处理好,它的日常表现就可能从经常不及格,变成大多能达到 60 分以上。我说的提高下限,是让低分结果更少出现,并不意味着每次都能保证达到 60 分。

90 分、100 分的结果也是如此,模型有能力做到,不代表每次都能做到。同一个任务让它重复尝试多次,也就是多次采样,可能才会出现一次特别好的结果。好的 Harness 还能提高这类高分结果出现的概率,让模型更经常地发挥出它原本就能达到的水平。

继续用这个分数例子:原来多次尝试才出现一次的 90 分,现在更经常出现了;原来经常不及格,现在大多能达到 60 分以上。两种变化都让 Agent 更好用,但不意味着模型的最高分从 100 分变成了 120 分。

Harness 能带来什么

没读过文件,就拒绝修改。 假设你让 AI 修改一段代码,它根据之前的对话猜测文件里有什么,直接提交了修改请求。如果编辑工具直接执行,它就可能改错位置,甚至覆盖原有内容。

一种做法是在指令里写「修改前必须先读文件」,让模型记住并遵守。另一种做法是让编辑工具检查模型在当前任务中有没有读取过这个文件,如果没有,就拒绝修改,返回「请先读取文件,再提交修改」。模型收到错误提示后,可以先调用读取工具,再根据文件的实际内容修改。

两种做法的差别是,前者要求模型不要跳过这一步,后者让它跳不过去。模型没有因此变聪明,但它凭猜测直接修改文件的机会减少了。这就是我理解的 Harness 提高下限的一种方式。

读过之后,文件变了,也不能直接覆盖。 模型读取文件时,系统可以记下文件的版本。假设模型还在准备修改,另一个人已经保存了新内容,编辑工具就应该检查出版本变化,拒绝按旧内容修改,并要求重新读取。

这条错误提示能让模型知道,文件已经变化,需要先读到最新内容再修改。如果没有这个检查,修改可能显示成功,却覆盖了别人刚保存的内容。程序不需要理解代码的业务含义,也能通过比较版本阻止这次操作。

没有用户确认,就不能发送。 你让 AI 起草邮件,要求「先给我看,确认后再发」。Harness 可以把发送工具设成必须经过用户确认才能执行。模型即使提前发起发送请求,系统也会暂停操作,等待用户授权,而不是把模型自己写的「用户已同意」当作确认。

这个机制可以阻止未经确认的发送,但不能保证草稿内容正确,也不能替用户判断邮件该不该发。系统在这里检查的是用户有没有确认发送。

这些设计都可以由 Harness 实现,但并非所有 Agent 都具备。程序在操作前检查必要条件,确认条件满足后才允许工具执行。程序可以检查模型有没有读过文件、文件版本有没有变化、用户有没有确认,不必每次都依赖模型记住要求。

除了限制操作,Harness 还需要让任务能够正常进行。邮件工具一次只返回 20 封,就要说明是否还有下一页;任务要求明天早上发送邮件,就需要真正保存并触发定时任务;修改 3 个文件时有一个失败,就要把错误交回模型,并保留另外两个的执行记录。否则,模型即使理解了任务,也可能因为信息不全、功能缺失或执行中断而失败。

技能文档则可以提供一些具体方法,比如怎样翻到下一页、怎样运行项目的测试、怎样确认文件保存成功。模型可以参考这些方法完成任务。但文档里的提醒和程序中的检查有区别:写着「修改前先读文件」,不代表编辑工具已经禁止跳过读取。了解一个 Harness 时,需要分清哪些要求依赖模型遵守,哪些由程序检查并执行。

判断仍然要靠模型

编辑工具要求先读文件,可以防止模型没看内容就动手。但模型读完以后,可能误解某个函数的作用,改错计算逻辑,或者删掉用户原本想保留的功能。读取记录能证明它调用过读取工具,不能证明它理解了代码。

报销表也是一样,AI 读到了港币金额,也知道用户要人民币报销表,但还需要把这两条信息联系起来,得出「先换算,再汇总」的结论。Harness 可以要求它先读取发票,模型却仍然可能没有注意到币种。

真实工作里的材料经常混着旧版本、相似的名字和互相矛盾的说法。把材料找齐之后,模型仍然需要判断哪些相关、哪些有效,以及该按哪一条执行。

下面三个任务都是假设例子,其中的公司、文件和规则用于说明模型可能在哪些地方判断错。

第一类,两家公司名字相近,业务却不同。

你让 AI 整理这次采购的供应商邮件,把报价、交货安排和付款资料放进「包装采购」文件夹。

收件箱里有一家「青禾包装」,邮件谈的是纸箱报价和交货日期;还有一家「青禾传媒」,发来一封广告设计服务的推销邮件。你之前和供应商往来时,常把「青禾包装」简称为「青禾」,所以搜索「青禾」会把两家的邮件都找出来。

正确的做法是把青禾包装的采购邮件移入文件夹,不移动青禾传媒的推销邮件。AI 需要结合业务内容判断,不能因为两封邮件都出现了「青禾」,就把它们当成同一家公司的往来。

搜索工具把两家邮件都找出来,并没有出错。归档工具按照 AI 的选择移动邮件,也可以正常完成。容易出错的是模型选择邮件的那一步,它需要分清哪家公司参与这次采购,哪家公司只是在推销。

第二类,新通知只改了部分要求。

你让 AI 按最新要求设置老客户优惠。原方案写着:「优惠码叫『老客七五折』,用户输入后按原价的 75% 付款。」两天后,负责人发来更正:「折扣调整为八折。优惠码已经发给客户,名称不要改。」

正确的设置应该保留「老客七五折」这个名称,但实际按八折计算。原价 100 元,输入这个优惠码后应付 80 元。

模型可能犯两种错:看到优惠码叫「七五折」,就继续让客户付 75 元;或者读懂了要改八折,顺手把优惠码改成「老客八折」,导致客户手里已经收到的旧码不能用。

模型需要读懂这封通知的两项要求:折扣要改,优惠码名称不改。模型不能只找最新的数字,也不能为了让文字看起来一致,就自行修改所有相关内容。

模型把优惠码名称和折扣作为参数传给设置工具,八折和七五折都在工具允许的范围内,因此工具都能接受。工具返回成功,说明它已经按模型传入的参数完成设置,但这个折扣不一定符合用户要求。

第三类,费用超过普通标准,却不一定违规。

你让 AI 按公司差旅制度检查报销单。为了方便说明,假设制度规定:普通出差的住宿费上限为每晚 500 元;会展期间,入住公司指定的酒店,可以凭行政部门的确认邮件报销,最高每晚 800 元。

现在有三笔住宿费:第一笔每晚 680 元,住的是会展期间公司指定的酒店,附有行政确认邮件;第二笔每晚 580 元,是普通出差,没有特殊批准;第三笔每晚 760 元,备注写着「参加会展」,却没有提供指定酒店的确认材料。

这三笔都超过 500 元,但处理方式不能一样。第一笔符合例外规定,可以通过;第二笔超过普通标准,需要按制度处理;第三笔还缺少判断依据,应该要求补充材料,不能仅凭「参加会展」四个字就通过,也不该直接断定它一定违规。

如果 AI 把所有超过 500 元的记录都列为违规,就会误报第一笔;如果只要备注里写了「参加会展」就允许报销,又会在第三笔缺少证明时直接通过。

工具可以筛出超过 500 元的住宿费,但能不能报销,还需要结合出差事由和确认邮件判断。

在这些任务里,工具都可能正常工作,AI 却仍然把事情做错。归档工具移动了邮件,但模型选中了推销邮件;设置工具按模型提交的参数修改了折扣,但模型传入的是七五折,用户要的却是八折;报销工具筛出了超额费用,但模型没看确认邮件,就把可以报销的住宿费判成了违规。

这几个例子里,工具执行了模型的要求,模型却没有正确理解用户的要求。

拿优惠码的例子来说,如果模型只读了旧方案,没有读到后来那封「改成八折,名称不变」的通知,Harness 可以在提交设置之前要求它查找并读取后续通知。模型因此发现新要求,就有机会把折扣改对。

但如果模型已经读到了这封通知,却仍然认为「既然改成八折,优惠码也应该改名」,即使程序确认它读过通知,也没能阻止它改错名称。程序能检查模型有没有调用工具读取通知,却不能仅凭这条记录知道它有没有读懂「名称不变」。修改文件前要求先读取文件,也是同样的道理。Harness 可以阻止模型跳过读取,但读完以后有没有理解正确,仍然取决于模型。

技能文档可以提醒模型核对供应商、查看新旧方案或检查报销证明,帮助它减少遗漏。但模型还要判断什么时候需要这些检查,以及怎样使用检查得到的信息。

固定业务可以逐项增加检查,通用 Agent 面对的任务却不断变化。

Harness 可以提供方法、执行明确的限制,但当前任务该用什么方法,以及材料到底意味着什么,仍然需要模型判断。

对构建 Harness 的启发

理解这些区别之后,构建 Harness 就有了一些具体的依据。能够由程序检查的要求,不必每次都交给模型记住。

修改前有没有读取文件、文件版本有没有变化、用户有没有确认,都可以在调用工具时检查。把这些事情交给程序,既能减少遗漏,也让模型少处理一些不需要临时判断的问题。

模型调用工具之后,Harness 还要把实际发生的事情告诉它。比如,模型要修改折扣,工具除了返回「修改成功」,还可以返回改的是哪个优惠码、现在的折扣是多少。模型有了这些信息,才有机会发现自己改错了优惠码,或者把八折填成了七五折。如果工具只说「成功」,模型就可能直接把任务标成完成,继续下一步。

但也不能每出一次错,就给所有任务多加一道检查。比如,AI 漏看了一份文件,我们就要求它以后每次都读完所有文件。这样也许能少漏一些内容,但下次用户只想改一个文件名,它也得先把所有文件读一遍。用户等得更久,token 也花得更多。所以,加规则时还得想一想:这次确实用得上,换个任务还需要吗?

渐进式披露是这里一个重要的设计方法:先让模型知道有哪些信息和能力,需要时再提供详细内容。 比如,先提供技能名称、用途和读取位置,任务涉及报销时,再读取报销方法;方法里涉及外币处理时,再查相关规定。不必在每次对话开始时,把报销、采购、合同审查的全部说明都交给模型。

渐进式披露也有前提。模型需要从简短说明里判断什么时候该读哪份内容,并且有明确的读取方式。如果说明太模糊,模型根本不知道还有一份相关规则,少用的 token 就可能变成遗漏。必须遵守的权限限制也不能只藏在按需读取的文档里,仍应由系统检查。这里要减少的是无关内容,不能让模型拿不到完成任务所需的信息。

信息怎样提供,还会影响缓存命中率。如果多次请求的开头相同,一些模型服务可以复用之前处理过的内容,降低重复输入的费用和处理时间,这就是这里说的 Prompt 缓存。对于依赖相同前缀的 Prompt 缓存,稳定的指令和常用工具说明可以保持内容、顺序不变,任务材料和后续读取的内容再按需追加。这样既不必一开始提供全部信息,也有机会复用已经处理过的输入。具体效果取决于 API 的缓存机制,不能为了追求更短的单次请求,就每轮重排整段上下文。

因此,少用 token、提高缓存命中率,都要以完成任务为前提,并看整个任务的消耗。一次少给了关键信息,导致模型反复查找,最终可能更贵;缓存命中了大量无关内容,模型仍然需要在这些内容里判断哪些有用。增加一条规则、一次读取或一次复核,都需要看它减少了什么错误,以及带来了多少额外处理。

对我来说,构建 Harness 需要不断回答一个问题:这一步真的有必要吗?删掉它,任务会不会更容易出错;保留它,多花的时间和 token 又解决了什么问题?这些取舍,需要随着任务和模型的变化重新判断。

← 返回