news 2026/11/2 3:53:49

AI Agent Harness 七个子系统:从能聊到能干活

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent Harness 七个子系统:从能聊到能干活

1. 从"能聊"到"能干活":Harness 到底卡在哪个环节

大多数人第一次搭 AI Agent,都会经历同一个阶段:模型接上了,提示词调通了,对话效果看着还行,但只要让它真正去执行一个多步骤任务,立刻就露馅——要么中途忘了自己干到哪一步,要么工具调用参数拼错,要么循环几轮之后开始胡言乱语。问题往往不在模型本身,而在于模型外面那层"壳"没搭好。

这层壳,业内习惯叫Harness。直译是"马具""挽具",意思很形象:模型是那匹力气很大的马,但光有马跑不起来,你得有一套缰绳、鞍具、轭具把它约束住、引导好,才能让它拉着车往一个方向走。Harness 就是 Agent 里负责"约束和引导模型真正干活"的那套工程结构。

很多人把 Harness 和 Agent 框架混为一谈,其实两者关注点不一样。框架(比如各种编排库)解决的是"怎么把组件拼起来",而 Harness 解决的是"模型每一步该看到什么、该输出什么、输出之后怎么落地、出错怎么兜"。前者是骨架,后者是神经和肌肉。你去看那些真正能跑通复杂任务的 Agent,模型可能换来换去,但 Harness 的设计思路高度相似——基本都能拆成 7 个子系统。

这篇就把这 7 个子系统一个个拆开讲清楚:每个是干什么的、为什么必须有、实际写的时候容易在哪翻车。适合已经能跑通单轮对话、想让 Agent 真正"下地干活"的人。如果你还停留在"调 API 拿回复"的阶段,看完这篇会对整个工程结构有个清晰的地图。

提示:Harness 不是某个具体产品的名字,而是一类工程结构的统称。不同团队叫法不同,但核心职责高度重合。下面这 7 个子系统是我在多个项目里反复验证后收敛出来的划分方式。

2. 子系统一:Agent Loop——整个 Harness 的心跳

2.1 为什么"循环"是第一个要解决的问题

单轮问答不需要循环:输入进去,输出出来,结束。但 Agent 干活天然是多轮的——它要先理解任务,再决定调哪个工具,拿到工具结果后再判断下一步,直到任务完成。这个"判断—执行—观察—再判断"的过程,就是一个循环。

Agent Loop 就是驱动这个循环的引擎。它决定了:什么时候继续循环、什么时候停下来、每一轮把什么信息喂给模型。听起来简单,但这是整个 Harness 里最容易写出死循环、最容易烧钱、最容易让 Agent "鬼打墙"的地方。

我见过太多新手写的 Loop 长这样:把用户问题丢给模型,模型说要调工具,调完把结果拼回对话历史,再丢给模型,如此往复,直到模型不再要求调工具为止。这个逻辑在简单场景能跑,但一旦任务复杂,就会出现三种典型故障。

2.2 三种典型故障与对应的 Loop 设计

第一种是无限循环。模型可能因为工具返回的结果不符合预期,反复调用同一个工具。比如让它查一个不存在的文件,工具每次都返回"文件不存在",模型每次都再查一遍。没有轮次上限,这个循环能跑到天荒地老。

第二种是提前退出。模型在任务只完成一半时就认为"搞定了",直接给出最终答案。这在多步骤任务里特别常见,因为模型看不到全局进度,只看到当前上下文。

第三种是上下文爆炸。每一轮的工具返回结果都往对话历史里塞,几轮之后上下文就撑满了,要么超长被截断,要么成本飙升。

针对这三种故障,Loop 的设计要带上三个机制:最大轮次限制、显式的任务状态跟踪、上下文压缩策略。最大轮次好理解,设个硬上限比如 15 轮,到了就强制收尾。任务状态跟踪则需要你在 Loop 外面维护一个结构化的进度对象,每一轮把"已完成什么、还剩什么"注入到提示里,让模型有全局感。上下文压缩则是当历史超过阈值时,把早期的工具调用结果摘要化,只保留关键结论。

# Agent Loop 的核心骨架(伪代码,突出控制逻辑) MAX_TURNS = 15 state = {"goal": task, "done": [], "pending": []} for turn in range(MAX_TURNS): context = build_context(state, recent_history) action = llm.decide(context) # 模型决定下一步 if action.type == "final": return action.answer # 模型认为完成 result = execute_tool(action) # 落地执行 state = update_state(state, action, result) recent_history = compress_if_needed(recent_history, result) return force_wrap_up(state) # 超轮次强制收尾

2.3 一个容易被忽略的细节:循环的"退出条件"要显式化

很多人依赖"模型自己说完成"作为退出条件,这是最不可靠的做法。更稳的方式是让 Loop 自己判断:任务状态里的 pending 列表空了,才算完成。模型说完成但 pending 还有内容,就继续循环并提示它"还有未完成项"。

这个改动看着小,但实测下来能显著降低"半途而废"的概率。因为模型在每一轮都能看到明确的待办清单,而不是靠自己的记忆去判断进度。

3. 子系统二:LLM Integration——别把模型当成一个黑盒函数

3.1 模型接入不只是"发请求收回复"

LLM Integration 这个子系统,新手往往觉得最简单——不就是调 API 吗?但真正做过生产级 Agent 的人都知道,这里是坑最多的地方之一。原因在于:Agent 对模型的要求和普通对话完全不同。

普通对话里,模型输出一段文字就完事了。但 Agent 里,模型的输出要被解析成结构化动作——它得告诉 Harness "我要调哪个工具、参数是什么"。这就要求模型输出必须是可解析的格式,而且格式要稳定。

3.2 结构化输出的三种实现路径与取舍

目前主流有三种做法,各有取舍。

第一种是提示词约束 + 正则解析。在提示里明确要求模型按 JSON 格式输出,然后用正则或 JSON 解析器提取。优点是通用,任何模型都能用;缺点是模型偶尔会"跑格式",输出带 markdown 代码块包裹的 JSON,或者干脆漏个括号,解析就崩了。

第二种是模型原生的函数调用能力。现在主流模型基本都支持 function calling 或 tool use,模型直接返回结构化的工具调用对象,不用你自己解析。这是最稳的方式,优先推荐。缺点是不同模型的调用格式有差异,切换模型时要适配。

第三种是约束解码。在推理层面限制模型只能输出符合某个语法规则的 token,从根上保证格式正确。效果最好,但需要模型侧支持,不是所有部署方式都能用。

我的建议是:能用原生函数调用就用原生,实在不行再退回提示词约束,并且一定要在解析层加容错和重试。解析失败时,不要把错误直接抛给用户,而是把"你上次输出格式不对,请重新按格式输出"作为一条消息塞回去,让模型自己修。

3.3 模型选型的现实考量

Agent 场景下选模型,不能只看"谁最聪明"。要考虑三个维度:指令遵循能力(能不能稳定按格式输出)、工具调用准确率(参数拼得对不对)、延迟和成本(Agent 是多轮的,单轮成本会被放大十几倍)。

一个反直觉的经验:在 Agent 场景里,一个指令遵循强、工具调用稳的中等模型,往往比一个"最聪明但爱自由发挥"的顶级模型更好用。因为 Harness 需要的是可预测性,而不是单轮的惊艳表现。模型每次都能老老实实按格式输出、按规则调工具,整个系统才稳。

注意:切换模型时,一定要重新跑一遍工具调用的回归测试。不同模型对同一个工具描述的理解可能完全不同,A 模型能正确填的参数,B 模型可能填错。

4. 子系统三:Tool Registry——工具不是越多越好

4.1 工具注册表的核心职责

Tool Registry 管的是"Agent 能用哪些工具、每个工具怎么描述、怎么调用"。听起来像个简单的字典,但它直接决定了模型能不能选对工具。

核心问题在于:模型选工具,靠的是工具的描述文本。描述写得含糊,模型就会选错;工具太多,模型就会挑花眼。所以 Tool Registry 不只是存工具,还要负责工具的描述优化和筛选。

4.2 工具描述的写法直接决定调用准确率

我踩过的一个坑:早期给工具写描述,写的是"查询数据库"。结果模型经常在不需要查库的时候也去调它。后来改成"根据用户提供的订单号,从订单库查询该订单的详细状态,包括发货、物流、签收信息。仅当用户明确询问某个具体订单的状态时使用",调用准确率立刻上去了。

关键是把三件事写清楚:这个工具做什么、什么情况下用、什么情况下不要用。尤其是最后一条,很多人不写,但它是减少误调用的关键。

4.3 工具数量膨胀后的筛选策略

当工具超过 15 到 20 个,模型的选错率会明显上升。这时候有两个策略。

一是分组。把工具按领域分组,先让模型选组,再在组内选工具。相当于把一次大选择拆成两次小选择,准确率会高很多。

二是动态筛选。根据当前任务状态,只把相关的工具暴露给模型。比如任务还在"信息收集"阶段,就只暴露查询类工具,不暴露写入类工具。这需要 Harness 维护一个"当前阶段允许的工具集"。

工具数量推荐策略预期选错率
1-10全量暴露低
10-20全量暴露 + 描述优化中
20-50分组选择中低
50+动态筛选 + 分组可控

4.4 工具执行的安全边界

Tool Registry 还要管一件事:哪些工具是危险的。写文件、删数据、发请求这类有副作用的工具,不能让它随便执行。常见做法是加一层确认机制——危险工具在执行前,要么要求人工确认,要么在沙箱环境里先跑一遍。

我在实际项目里的做法是给每个工具打一个risk_level标签,低风险的直接执行,高风险的走确认流程。这个标签在注册工具时就定好,不要等到运行时再判断。

5. 子系统四:Memory & Context——Agent 的"记性"怎么管

5.1 短期记忆和长期记忆要分开设计

Agent 的"记忆"分两种,混在一起设计必然出问题。

短期记忆是当前任务执行过程中的上下文——这一轮调了什么工具、返回了什么、当前进度到哪。它跟着 Agent Loop 走,任务结束就清空。

长期记忆是跨任务、跨会话的信息——用户的偏好、历史交互的关键结论、领域知识。它需要持久化存储,并且在合适的时候被检索出来注入上下文。

新手最常见的错误是把所有东西都往对话历史里塞,既当短期又当长期,结果就是上下文越来越长,模型越来越糊涂。

5.2 上下文窗口的分配策略

上下文窗口是有限资源,怎么分配直接决定 Agent 的表现。我的经验分配大致是这样:系统提示和工具描述占 20% 到 30%,当前任务状态占 10%,近期对话历史占 30% 到 40%,检索到的长期记忆占 10% 到 20%,剩下留作输出缓冲。

这个比例不是死的,但核心原则是:当前任务状态必须始终可见,因为它决定模型下一步做什么;长期记忆按需检索,不要一股脑全塞进去。

5.3 记忆检索的触发时机

长期记忆什么时候检索?两个时机最有效:任务开始时(拉取相关背景),以及模型显式请求时(模型判断需要历史信息)。

前者是主动注入,后者是被动查询。主动注入要控制量,只拉最相关的几条;被动查询则可以把检索做成一个工具,让模型自己决定要不要查。

提示:记忆检索的相关性排序,不要只靠向量相似度。加上时间衰减(近期记忆权重更高)和重要性标签(标记为关键的记忆优先),效果会好很多。

6. 子系统五:Planning & Decomposition——把大任务拆成能执行的步骤

6.1 为什么 Agent 需要显式的规划层

一个复杂任务,比如"帮我整理这份销售数据并生成周报",直接丢给模型,它很可能东一榔头西一棒子。Planning 子系统的职责,就是把这个大任务拆成有序的小步骤,让 Agent 一步步执行。

规划有两种模式:先规划后执行和边执行边规划。前者在任务开始时一次性生成完整计划,执行时按计划走;后者每一步都重新判断下一步做什么。

先规划的好处是全局感强,不容易跑偏;坏处是计划可能一开始就错了,后面全错。边执行的好处是灵活,能根据中间结果调整;坏处是容易失去全局方向。实际项目里,我通常用混合模式:先出一个粗粒度的计划(3 到 5 个大步骤),每个大步骤内部再边执行边细化。

6.2 任务拆解的粒度控制

拆得太粗,模型执行时还是不知道怎么做;拆得太细,规划本身就成了负担,而且容易过度约束模型。

我的经验粒度是:每个子任务应该是一次工具调用或一次明确的推理能完成的。比如"查询上季度销售数据"是一个合适的粒度,"处理数据"就太粗,"打开文件、读取第 3 行、提取第 2 列"就太细。

6.3 计划执行中的动态调整

计划不是圣旨。执行过程中发现某个步骤不可行,要允许调整。但调整要有约束,不能一遇到困难就推翻整个计划。

我的做法是:计划里的每个步骤有"状态"(待执行、进行中、完成、失败)。失败时,先尝试重试或换方法;连续失败两次,才触发重新规划。这样既保留了灵活性,又避免了频繁推翻计划导致的混乱。

7. 子系统六:Execution & Sandbox——让动作真正落地且不出事

7.1 执行层要解决的核心矛盾

Execution 子系统负责把模型决定的动作真正执行掉——调 API、读写文件、跑代码。这里的核心矛盾是:既要让 Agent 有能力做事,又要防止它做坏事。

模型可能会生成有问题的代码、访问不该访问的资源、执行破坏性操作。Sandbox 就是用来隔离这些风险的。

7.2 沙箱的几种隔离级别

隔离级别从弱到强大致分四档:进程内隔离(同进程跑,只做权限检查)、子进程隔离(独立进程,限制资源)、容器隔离(独立文件系统和网络)、虚拟机隔离(最强,但最重)。

选哪一档,取决于 Agent 要执行什么。如果只是调几个受控的 API,进程内隔离加权限检查就够了。如果要让 Agent 跑任意代码,那必须上容器甚至虚拟机。

隔离级别适用场景开销安全性
进程内受控 API 调用极低低
子进程脚本执行低中
容器任意代码执行中高
虚拟机高风险操作高极高

7.3 执行结果的标准化

工具执行完,返回给模型的结果要标准化。不要直接把原始输出丢回去,而是包装成统一格式:成功还是失败、关键信息是什么、有没有需要模型注意的异常。

这一步做得好,模型对执行结果的理解会准确很多。我见过太多 Agent 因为工具返回了一大坨原始日志,模型抓不住重点,导致后续判断出错。

8. 子系统七:Observability & Guardrails——看不见的 Agent 最危险

8.1 可观测性不是可选项

Agent 是多轮、多工具、有状态的系统,出问题时如果看不到中间过程,排查就是盲人摸象。Observability 子系统要记录:每一轮的输入输出、工具调用详情、状态变化、耗时和成本。

这些数据不只是用来排错的,也是优化 Harness 的依据。比如你发现某个工具被频繁误调用,就能针对性优化它的描述;发现某类任务总是超轮次,就能调整规划策略。

8.2 护栏要拦在哪些位置

Guardrails 是安全网,要在几个关键位置设卡:输入侧拦截明显有害的请求,工具调用侧拦截高风险操作,输出侧过滤不当内容,循环侧检测异常模式(比如反复调用同一工具)。

护栏的设计原则是"宁可误拦,不可漏放",但误拦率也不能太高,否则 Agent 会变得畏手畏脚。我的做法是分级:明确有害的直接拦,疑似有害的走确认,正常的放行。

8.3 成本监控是隐形的护栏

Agent 多轮调用,成本很容易失控。一个跑飞的循环,可能几分钟烧掉几十块。所以成本监控要实时,设一个单任务成本上限,超了就强制终止并告警。

这个上限怎么定?先跑一批典型任务,统计平均成本,然后设成平均值的 3 到 5 倍。既给了复杂任务空间,又能拦住异常。

9. 七个子系统怎么串起来:一次完整任务的流转

把七个子系统串起来看,一次任务的大致流转是这样的:

  1. 用户输入进入,Guardrails 做输入检查。
  2. Planning 子系统把任务拆成粗粒度计划。
  3. Agent Loop 启动,每一轮从 Memory 拉取上下文,从 Tool Registry 拉取可用工具。
  4. LLM Integration 让模型基于当前状态决定下一步动作。
  5. 如果是工具调用,Execution 子系统在 Sandbox 里执行,结果标准化后回填。
  6. 每一轮的状态变化、调用详情写入 Observability。
  7. 循环直到任务完成或触发退出条件,输出经 Guardrails 检查后返回。

这七个部分不是孤立的,它们之间有大量交互。比如 Memory 的上下文分配会影响 LLM 的判断,Tool Registry 的描述质量会影响 Execution 的成功率。所以搭 Harness 不能一个子系统一个子系统孤立地做,要有整体视角。

10. 搭 Harness 时我踩过的几个真实坑

第一个坑是过早优化。一开始就想把七个子系统都做得很完善,结果哪个都没做好。后来改成先跑通最小闭环——Loop 加 LLM 加一个工具,能干活了再逐个补强。这个顺序很重要。

第二个坑是工具描述偷懒。前面提过,工具描述直接决定调用准确率。我早期为了快,描述写得很简略,结果调试工具调用花的时间比写描述多十倍。后来养成习惯,每个工具的描述都当小作文写。

第三个坑是忽略上下文压缩。有个任务跑到第八轮突然开始胡言乱语,排查半天发现是上下文超了被截断,把关键的任务状态截掉了。加了压缩策略后问题消失。

第四个坑是没有成本上限。有次测试一个循环逻辑写错了,Agent 反复调用一个付费 API,半小时烧掉一笔不小的费用。从那以后所有 Agent 都强制加成本监控。

第五个坑是可观测性做得太晚。前期没记录中间过程,出问题只能靠猜。后来补上日志,排查效率提升非常明显。这个投入绝对值得,越早做越好。

11. 关于 Harness 的几个常见误解

第一个误解是"Harness 就是提示词工程"。提示词只是其中一小部分,Harness 更多是工程结构问题——循环怎么控、状态怎么管、工具怎么注册、执行怎么隔离。提示词写得好,但 Harness 结构烂,Agent 照样跑不起来。

第二个误解是"模型够强就不需要 Harness"。恰恰相反,模型越强,能做的事越多,越需要 Harness 来约束和引导。没有 Harness,强模型只会更自由地跑偏。

第三个误解是"Harness 一次搭好就不用管了"。Harness 是要持续迭代的。任务类型变了、工具变了、模型换了,Harness 都要跟着调。它更像一个需要长期维护的系统,而不是一次性工程。

第四个误解是"子系统越多越好"。七个是我收敛出来的必要集合,不是让你无限加。每个子系统都有维护成本,加之前先问:不加它,Agent 会出什么问题?如果答不上来,就不加。

12. 从最小可用 Harness 开始的落地路径

如果你现在就想动手,我的建议是按这个顺序来:

第一步,搭一个带最大轮次限制的 Agent Loop,接一个模型,注册一个工具,跑通"模型决定调工具、工具执行、结果回填、模型给最终答案"这个最小闭环。

第二步,把工具描述写规范,加上结构化输出解析和容错重试。这一步做完,Agent 的稳定性会有质的提升。

第三步,加上任务状态跟踪和上下文压缩,让 Agent 能处理多步骤任务而不跑偏。

第四步,补上执行隔离和可观测性,让 Agent 能安全地做更多事,同时出问题能排查。

第五步,加规划层和长期记忆,让 Agent 能处理更复杂的任务。

这个顺序的核心逻辑是:先让它能干活,再让它干得稳,最后让它干得复杂。反过来做,很容易在还没跑通闭环的时候就陷入细节,最后什么都没搭起来。

Harness 这个东西,说穿了就是把"让模型真正干活"这件事拆成一个个可控的工程问题。七个子系统不是标准答案,而是一张地图。你照着这张地图走,至少不会在搭 Agent 的时候迷路。至于每个子系统做到什么程度,取决于你的任务复杂度和风险容忍度——这个平衡,只能在实际项目里慢慢找。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 3:52:54

VPKTool:纯C99轻量级VPK文件操作工具链

简介:VPKTool 是一个面向游戏开发者的轻量级 C 语言库与命令行工具集,专为高效读写 Valve 游戏(如 CS:GO、《半条命2》)所用的 VPK 资源包而设计,解决开发者在资源打包、解包、分析及资产安全管控中的核心需求。资源包…

作者头像 李华
网站建设 2026/11/2 3:52:39

高防服务器防御能力验证全指南

1. 高防服务器防御能力验证的必要性在当今网络环境中,DDoS攻击已成为企业线上业务面临的主要威胁之一。根据最新行业报告,2023年全球DDoS攻击规模同比增长了37%,单次攻击峰值流量已突破3Tbps。面对这种态势,高防服务器成为众多企业…

作者头像 李华
网站建设 2026/11/2 3:52:39

神经网络与MPC在非线性机器人控制中的融合应用

1. 项目背景与核心挑战在非线性机器人汽车系统和四旋翼无人机的控制领域,传统控制方法面临着两大核心挑战。首先是系统动力学的高度非线性特性:机器人汽车的轮胎与地面接触力呈现复杂的非线性关系,特别是在不同车速和载荷条件下,这…

作者头像 李华
网站建设 2026/11/2 3:51:41

WorkBuddy+WebView+Supabase:六周从零搭建可上线App的实战复盘

1. 为什么我选择用 WorkBuddy 从零搭一个能上线的 App去年年底我接了个私活,帮一个做线下活动策划的团队做一套内部工具。需求很明确:活动执行人员要在现场用手机签到、拍照上传、查看任务清单,管理端要能实时看到进度。预算不高,…

作者头像 李华
网站建设 2026/11/2 3:51:20

Jev、Laya、DeepSeek文档分类实测:准确率、成本与选型指南

1. 三个模型同台竞技,我为什么要做这轮文档分类实测文档分类这件事,听起来像是老生常谈,但真正落到工程里,坑比想象的多。我手头有一批混合型文档——技术手册、产品说明、会议纪要、合同片段、FAQ 问答对,格式从纯文本…

作者头像 李华
网站建设 2026/11/2 3:50:48

Passbolt自托管团队密码库:部署配置与API认证调通实战

团队里共用一套账号密码这件事,几乎每个有点规模的技术团队都绕不开。有人用共享表格,有人直接甩在群里,有人用某个同事的个人网盘,等到人员流动或者要做审计的时候才发现根本理不清谁在什么时候看过哪条凭据。Passbolt 就是冲这个…

作者头像 李华