☰
从harness工程到认知工程:Agent架构升级实战与复杂任务优化
2026/9/24 23:55:13 网站建设 项目流程

1. 从 harness 工程到认知工程:一次 Agent 架构的认知跃迁

过去大半年,我一直在折腾 Agent 相关的东西。从最早的 prompt 拼接,到后来的工具调用编排,再到最近把整套 harness 工程重构了一遍,踩的坑比写的代码还多。今天想聊的这个话题,是我最近思考比较多的一个方向:把 harness 工程升级到认知工程。这不是一个简单的技术升级,而是整个 Agent 系统设计思路的转变。

先说清楚我在说什么。harness 工程,简单理解就是围绕 Agent 的“执行外壳”做工程化——工具注册、调用编排、上下文管理、错误重试、输出解析,这些都属于 harness 的范畴。你去看现在市面上大部分 Agent 框架,本质上都在解决 harness 层面的问题:怎么让模型稳定地调用工具、怎么管理多轮对话的上下文、怎么处理工具返回的异常。这些工作很重要,但它们解决的是“Agent 能不能跑起来”的问题,而不是“Agent 能不能想明白”的问题。

认知工程则是往上一层走。它关心的不是工具怎么调,而是 Agent 在调用工具之前,脑子里发生了什么:它怎么理解当前任务、怎么判断自己知不知道、怎么决定要不要拆解、怎么评估自己的方案靠不靠谱。换句话说,harness 工程管的是“手脚”,认知工程管的是“脑子”。我最近把手上一个 Agent 项目从纯 harness 架构改造成带认知层的架构,效果提升非常明显,尤其是在复杂任务上的表现,跟之前完全不是一个量级。

这篇文章适合谁看?如果你正在做 Agent 开发,已经过了“跑通 demo”的阶段,开始遇到“任务一复杂就翻车”的问题,那这篇内容应该对你有用。如果你还在学习 Agent 开发的基础知识,也可以看看,至少能知道后面要往哪个方向走。我会从架构设计、核心模块、实操步骤、踩坑经验几个方面展开,尽量把“为什么这么设计”讲清楚,而不只是丢一堆代码。

2. 为什么 harness 工程不够用了

2.1 harness 工程的本质与边界

先给 harness 工程画个像。一个典型的 harness 架构大概包含这些东西:工具注册表(tool registry)、调用解析器(call parser)、执行器(executor)、结果处理器(result handler)、上下文管理器(context manager)。模型输出一段文本,harness 负责解析出工具调用意图,执行工具,把结果塞回上下文,再让模型继续。这个循环就是 ReAct 那套东西的工程化实现。

我最早做 Agent 的时候,觉得这套东西已经很完整了。工具能调、上下文能管、错误能重试,还要啥自行车?但跑了一段时间真实任务之后,问题就暴露出来了。最典型的一个场景:我让 Agent 帮我分析一份数据报告,它上来就开始调工具,读文件、算统计、画图表,一套操作猛如虎,最后输出一个完全跑偏的结论。问题出在哪?出在它根本没想清楚“这个任务到底要什么”,就开始动手了。

harness 工程的边界就在这里:它能保证工具调用的正确性,但保证不了任务理解的正确性。模型说调 A 工具,harness 就调 A 工具,至于该不该调 A、调完 A 之后该干嘛,harness 不管。这就好比一个执行力很强的实习生,你说啥他干啥,但他不会问你“你确定要这么干吗”。

2.2 复杂任务暴露的三个核心缺陷

我复盘了一下过去半年 Agent 翻车的案例,发现大部分问题可以归到三类。

第一类是任务理解偏差。用户说“帮我优化一下这段代码的性能”,Agent 直接开始改代码,但它没搞清楚用户说的“性能”是指运行速度、内存占用还是可读性。这种偏差在 harness 层面是看不出来的,因为工具调用本身没问题,问题在于调用之前的理解环节缺失。

第二类是自我评估缺失。Agent 调完一个工具,拿到结果,它不会判断这个结果是否合理。比如它调了一个搜索工具,返回的结果明显不相关,但它照样把结果塞进上下文继续往下走。harness 工程里通常只有“调用成功/失败”的判断,没有“结果质量”的判断。

第三类是策略僵化。harness 工程里的执行流程通常是固定的:解析、调用、处理、循环。但真实任务需要动态策略——简单任务直接答,复杂任务先拆解,不确定的任务先澄清。固定流程应对不了这种变化。

这三个缺陷的共同点是:它们都发生在“工具调用之前”或“工具调用之间”,属于认知层面的问题,不是执行层面的问题。这就是为什么我说 harness 工程不够用了——不是它做得不好,而是它管不到这些地方。

2.3 认知工程要解决的核心问题

认知工程的目标,是在 harness 之上加一层“思考层”。这层要解决的核心问题包括:Agent 怎么知道自己知不知道(元认知)、怎么把复杂任务拆成可执行的子任务(任务分解)、怎么判断自己的方案是否靠谱(自我评估)、怎么根据反馈调整策略(策略调整)。

我打个比方。harness 工程像是给 Agent 装了一双手,让它能操作工具。认知工程是给这双手配一个大脑,让它在动手之前先想一想:我要干什么、我能不能干、我该怎么干、干完之后对不对。没有大脑的手,只能做机械重复的动作;有了大脑的手,才能做需要判断和调整的复杂工作。

这个升级不是把 harness 推翻重来,而是在它上面叠加一层。harness 依然是基础设施,认知层是决策层。两者配合,才能让 Agent 从“能跑”变成“能想”。

3. 认知工程的核心模块拆解

3.1 元认知模块:让 Agent 知道自己不知道

元认知这个词听起来很学术,说白了就是“对自己认知状态的认知”。放到 Agent 场景里,就是让 Agent 能判断:这个问题我能不能答、这个任务我能不能做、我现在的信息够不够。

我实现元认知模块的方式,是在每次任务开始前加一个“能力评估”步骤。具体做法是让模型先输出一个自评,格式大概是这样的:

{ "task_understanding": "用户想要...", "confidence": 0.7, "known_unknowns": ["缺少XX信息", "不确定YY的含义"], "suggested_action": "clarify | proceed | decompose" }

这个自评不是让模型随便说说,而是有明确的判断标准。confidence 低于某个阈值(我一般设 0.6),就触发澄清流程;known_unknowns 非空且影响核心决策,也触发澄清;如果任务明显复杂,suggested_action 就是 decompose。

实测下来,这个模块最大的价值是减少了“自信地犯错”。以前 Agent 遇到不懂的问题,它会硬答,答得还特别自信。现在它会说“我不确定这个,需要你补充一下”,虽然多了一轮交互,但整体成功率提升了很多。

注意:元认知模块的 prompt 设计很关键。如果你只是问“你确定吗”,模型大概率会说“确定”。要用结构化的方式逼它列出“已知”和“未知”,它才会认真思考。

3.2 任务分解模块:从“一把梭”到“分步走”

任务分解是认知工程里最实用的模块。harness 工程里的 Agent 通常是“一把梭”——拿到任务直接开干。但复杂任务需要先拆解,再逐步执行。

我的做法是加一个 planner 层。用户输入任务后,planner 先输出一个执行计划,格式是子任务列表,每个子任务包含:目标、所需工具、依赖关系、完成标准。然后 executor 按计划逐步执行,每完成一步就更新计划状态。

这里有个关键设计:计划不是一次性的,而是动态调整的。每执行完一个子任务,planner 会重新评估剩余计划是否还合理。如果发现前面的结果改变了任务理解,就重新规划。这个机制我称之为“滚动规划”,比一次性规划灵活很多。

举个例子。我让 Agent 分析一份销售数据,planner 初始计划是:读取数据、清洗数据、计算统计、生成报告。执行到“清洗数据”时发现数据格式跟预期不一样,planner 就动态插入一个“格式转换”子任务,再继续往下走。如果是 harness 工程,遇到这种情况大概率是报错或者硬着头皮往下走。

3.3 自我评估模块:给 Agent 装一个“检查器”

自我评估模块解决的是“结果质量”问题。harness 工程只判断工具调用是否成功,不判断结果是否合理。认知工程要加一层质量检查。

我的实现方式是在每个子任务完成后,加一个 evaluator 步骤。evaluator 拿到子任务目标和实际结果,输出一个评估:

{ "goal_achieved": true, "quality_score": 0.8, "issues": ["结果缺少XX维度"], "suggested_fix": "补充XX分析" }

如果 quality_score 低于阈值,或者 goal_achieved 为 false,就触发修复流程。修复流程可以是重新执行、调整方案、或者向用户求助。

这个模块最明显的效果是减少了“垃圾进垃圾出”。以前 Agent 拿到一个不相关的搜索结果,照样往下走,最后输出一堆废话。现在它会判断“这个结果不相关”,然后重新搜索或者换策略。

3.4 策略调整模块:让 Agent 学会“随机应变”

策略调整模块是认知工程的“自适应层”。它根据执行过程中的反馈,动态调整 Agent 的行为策略。

我实现的策略调整逻辑大概是这样的:维护一个策略状态机,包含几种策略模式——直接回答、澄清提问、分解执行、求助用户。每次任务开始或子任务完成后,根据元认知评估、执行结果、历史成功率,决定切换到哪种策略。

比如,如果连续两个子任务都执行失败,策略就从“分解执行”切换到“求助用户”。如果元认知评估显示 confidence 很高且任务简单,策略就是“直接回答”。这个状态机让 Agent 的行为不再是固定的,而是根据实际情况动态变化。

4. 实操:从 harness 到认知工程的改造步骤

4.1 改造前的准备工作

在动手改造之前,有几件事要先想清楚。

第一,确认你的 harness 工程是稳定的。认知工程是叠加层,如果底层 harness 本身就不稳定,叠上去只会更乱。先确保工具调用、上下文管理、错误重试这些基础功能没问题。

第二,定义清楚认知层的输入输出接口。认知层和 harness 层之间要有清晰的边界。我的做法是定义两个接口:cognitive_pre_process(task)和cognitive_post_process(result)。前者在 harness 执行前调用,返回执行计划;后者在执行后调用,返回评估结果。

第三,准备好评估数据。认知工程的效果需要量化评估,不然你不知道改造有没有用。我准备了一组测试任务,涵盖简单问答、中等复杂度分析、复杂多步任务三类,每类 10 个,用来对比改造前后的成功率。

4.2 第一步:搭建元认知评估层

元认知评估层是认知工程的入口。每次任务进来,先过这一层。

具体实现上,我写了一个MetaCognition类,核心方法是assess(task)。它调用模型输出结构化自评,然后根据自评结果决定下一步动作。代码大概长这样:

class MetaCognition: def assess(self, task): prompt = self._build_assessment_prompt(task) response = self.llm.generate(prompt) assessment = self._parse_response(response) if assessment["confidence"] < 0.6: return {"action": "clarify", "questions": assessment["known_unknowns"]} if assessment["complexity"] == "high": return {"action": "decompose", "task": task} return {"action": "proceed", "task": task}

这里有个细节:_build_assessment_prompt的设计很关键。我试过几种 prompt 结构,最后发现最有效的是“先让模型复述任务,再让它列已知未知,最后让它给建议”。复述任务这一步能逼模型认真理解,减少理解偏差。

4.3 第二步:接入任务分解与规划

任务分解层的核心是 planner。我实现了一个Planner类,核心方法是plan(task)和replan(task, executed_steps, current_state)。

plan方法输出初始计划,格式是子任务列表。每个子任务包含:id、goal、tools、dependencies、success_criteria。replan方法在每步执行后调用,判断是否需要调整计划。

这里有个实操心得:子任务的粒度很重要。太粗了跟没拆一样,太细了执行开销大。我的经验是每个子任务对应 1-3 次工具调用比较合适。如果某个子任务需要 5 次以上工具调用,说明拆得不够细。

另外,success_criteria要写得具体可判断。比如“获取到数据”就不够具体,“获取到包含日期、金额、类别的结构化数据”就比较好判断。这个字段直接影响后续的自我评估模块。

4.4 第三步:实现自我评估与修复循环

自我评估层的核心是 evaluator。我实现了一个Evaluator类,核心方法是evaluate(subtask, result)。

评估的逻辑分两步:先判断目标是否达成,再判断质量是否达标。目标达成判断用规则+模型结合的方式——能用规则判断的用规则(比如“是否返回了数据”),不能用规则的用模型判断(比如“分析是否合理”)。质量判断主要靠模型,给一个 0-1 的分数。

如果评估不通过,触发修复循环。修复策略有三种:retry(重试)、adjust(调整方案)、escalate(上报用户)。选择哪种策略根据失败原因决定:如果是工具调用失败,retry;如果是方案不对,adjust;如果是信息不足,escalate。

注意:修复循环要设最大次数限制,不然可能陷入死循环。我一般设 3 次,超过就 escalate。

4.5 第四步:串联策略调整状态机

策略调整层是认知工程的“调度中心”。我实现了一个StrategyManager类,维护一个状态机。

状态机的状态包括:DIRECT_ANSWER、CLARIFY、DECOMPOSE、EXECUTE、EVALUATE、REPAIR、ESCALATE。转移条件根据元认知评估、执行结果、评估分数、重试次数等决定。

这个状态机的实现不复杂,但设计转移条件需要仔细。我的经验是:转移条件要尽量简单明确,不要搞太复杂的组合条件。比如“confidence < 0.6 就 CLARIFY”比“confidence < 0.6 且 complexity > 0.5 且 history_success_rate < 0.7 就 CLARIFY”好维护得多。

4.6 改造后的效果对比

改造完成后,我用之前准备的测试任务跑了一轮对比。结果如下:

任务类型harness 工程成功率认知工程成功率提升幅度
简单问答92%94%+2%
中等复杂度分析68%85%+17%
复杂多步任务41%73%+32%

简单任务提升不大,因为简单任务本来就不需要太多认知。但复杂任务提升非常明显,成功率从 41% 提到 73%,翻了将近一倍。这个结果验证了我的判断:认知工程的价值在复杂任务上体现得最明显。

5. 踩坑记录与常见问题排查

5.1 元认知评估的“过度自信”问题

刚开始做元认知评估的时候,我发现模型的自评分数普遍偏高。明明任务很复杂,它给自己打 0.9 的 confidence。后来我调整了 prompt,加了“请列出你不确定的地方”这个要求,分数才降下来。

这个问题的本质是:模型倾向于“表现得自信”。你要用结构化的方式逼它暴露不确定性,不能直接问“你确定吗”。我现在的做法是要求它必须列出至少一个“已知未知”,如果确实没有,就写“无”。这个强制列出的机制,让模型不得不认真审视自己的知识边界。

5.2 任务分解的“粒度失控”

任务分解最容易出的问题是粒度失控。要么拆得太粗,子任务还是太大;要么拆得太细,执行开销爆炸。

我试过几种控制粒度的方法。最有效的是在 planner 的 prompt 里加一个约束:“每个子任务应该对应 1-3 次工具调用”。这个约束很具体,模型能理解。另外,我会在 replan 的时候检查子任务数量,如果超过 10 个,就提示 planner 合并一些子任务。

还有一个坑是子任务之间的依赖关系处理。有些子任务可以并行,有些必须串行。我一开始没处理这个,所有子任务都串行执行,效率很低。后来加了依赖关系字段,能并行的就并行,效率提升了不少。

5.3 自我评估的“标准漂移”

自我评估模块跑一段时间后,我发现评估标准会“漂移”。同样的结果,有时候评 0.8,有时候评 0.6。这是因为模型评估本身有随机性,加上上下文变化,标准就不稳定了。

解决方法是把评估标准显式化。我在 evaluator 的 prompt 里加了一个评分标准表,明确什么情况打什么分。比如“结果完整且准确:0.9-1.0;结果基本准确但缺少细节:0.7-0.8;结果有错误:0.4-0.6;结果不相关:0-0.3”。有了这个标准表,评分稳定性好了很多。

5.4 策略状态机的“死循环”风险

策略状态机最怕的是死循环。比如 EXECUTE 失败进 REPAIR,REPAIR 失败又回 EXECUTE,来回转。

我的解决方案是加两个机制:一是重试计数器,每个子任务的重试次数单独计数,超过 3 次就强制 ESCALATE;二是状态转移历史,如果发现最近 5 次状态转移在重复同样的模式,就强制跳出。这两个机制加上之后,死循环问题基本解决了。

5.5 常见问题速查表

问题现象可能原因排查方法解决方案
元认知评分普遍偏高prompt 缺少强制暴露不确定性的要求检查 assessment prompt加“必须列出已知未知”约束
子任务粒度过粗planner prompt 缺少粒度约束检查子任务对应的工具调用次数加“1-3次工具调用”约束
评估分数不稳定评估标准未显式化对比同一结果的多次评分加评分标准表
状态机死循环缺少重试计数和转移历史检查检查状态转移日志加重试计数器和转移历史检查
修复循环不收敛修复策略选择不当检查失败原因和修复策略的匹配度按失败原因选择修复策略
并行子任务未并行依赖关系未正确解析检查子任务依赖字段完善依赖关系解析逻辑

5.6 几个实操心得

第一个心得:认知层不要做太重。我一开始想把认知层做得特别完善,加了很多评估维度和策略分支,结果执行开销很大,简单任务也要跑好几秒。后来精简了,只保留核心的元认知、分解、评估、策略四个模块,效果好很多。认知层是“够用就好”,不是“越多越好”。

第二个心得:评估数据要持续积累。我维护了一个评估数据集,每次改造或调参后都跑一遍,对比效果。这个数据集不用很大,但要有代表性。我的数据集是 30 个任务,覆盖三类复杂度,跑一轮大概 10 分钟,很实用。

第三个心得:认知层的 prompt 要版本管理。认知层的效果很大程度上取决于 prompt 设计,而 prompt 调优是个反复迭代的过程。我用 git 管理 prompt 文件,每次改动都记录效果变化,这样能追溯哪个改动带来了提升。

6. 认知工程的扩展方向

6.1 记忆机制与认知工程的结合

认知工程目前主要处理“当前任务”的认知,但 Agent 的认知能力还可以扩展到“跨任务”的记忆。我最近在尝试把长期记忆机制接入认知层,让 Agent 能记住之前处理类似任务的经验。

具体做法是:每次任务完成后,把任务特征、执行计划、评估结果存到记忆库。下次遇到类似任务时,元认知模块先检索记忆库,看看有没有可参考的经验。这个机制在重复性任务上效果很好,能显著减少规划开销。

6.2 多 Agent 协作中的认知分工

单 Agent 的认知工程做完了,下一步自然是多 Agent 协作。我的想法是让不同 Agent 承担不同的认知角色:一个负责元认知评估,一个负责规划,一个负责执行,一个负责评估。这种分工能让每个 Agent 的认知模块更专注,整体效果可能更好。

不过多 Agent 协作的复杂度也高很多,通信开销、一致性、冲突处理都是问题。我目前还在实验阶段,等有稳定结果了再分享。

6.3 认知工程的可观测性建设

认知工程比 harness 工程更难调试,因为“思考过程”是隐性的。我最近在建设认知层的可观测性,把每个认知步骤的输入输出都记录下来,形成一个“认知轨迹”。这个轨迹能帮我定位问题:是元认知评估错了,还是规划错了,还是评估错了。

可观测性建设是个长期工作,但对认知工程的迭代很重要。没有可观测性,调优就是盲调。

6.4 从认知工程到元认知工程

最后聊一个更远的方向。认知工程是让 Agent“会想”,元认知工程是让 Agent“知道自己怎么想”。前者是认知能力,后者是对认知能力的认知和调控。

我目前只在元认知评估这个点上做了一些尝试,离完整的元认知工程还很远。但我觉得这个方向值得投入,因为 Agent 要真正可靠,不仅要知道自己在干什么,还要知道自己为什么这么干、这么干对不对。这是从“工具”到“伙伴”的关键一步。

我在实际项目中的体会是,认知工程的投入产出比在复杂任务场景下非常高。如果你的 Agent 主要处理简单任务,可能不需要认知层;但如果你的 Agent 要处理需要判断、拆解、调整的复杂任务,认知层几乎是必需的。改造的过程不轻松,但效果值得。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询