1. 从工具调用到协作伙伴Agent范式的本质变化过去两年我参与过不少Agent相关的项目从最早的给LLM挂几个API到后来做完整的任务编排系统踩过的坑比写过的代码还多。这篇总结想聊的核心是一个我反复在项目里验证过的判断Agent正在从工具调用器变成协作伙伴而这个转变的关键不在于模型本身有多强而在于Harness这一层工程做得好不好。先把几个概念摆清楚因为热词里混着harness和agent区别agent框架llm框架这些搜索说明很多人对边界是模糊的。我的理解是LLM是大脑Tool是手脚Skill是肌肉记忆而Harness是把这些串起来、让Agent能稳定跑完一个长任务的骨架神经系统。Agent则是最终呈现出来的那个能自主决策、能纠错、能和人协作的整体。这四者不是并列关系是层层包裹的关系。为什么说这是范式跃迁而不是版本升级因为工具调用时代的核心指标是单次调用成功率而Agent时代的核心指标变成了多轮任务完成率。前者你只要把参数拼对就行后者你要考虑上下文怎么管理、失败怎么回滚、记忆怎么沉淀、多个Skill怎么协同。这是两个完全不同的工程问题。我见过太多团队模型选的是顶配Tool接了几十个结果跑一个稍微复杂点的任务就崩问题几乎都出在Harness层——没有状态管理、没有错误恢复、没有Skill之间的调度逻辑。所以这篇总结的重点会放在工程实现上而不是模型选型上。2. 核心概念拆解LLM、Tool、Skill、Harness到底怎么分工2.1 LLM的角色不是万能大脑而是决策中枢很多人对LLM在Agent里的定位有误解觉得它应该什么都懂、什么都能干。实际项目里LLM最擅长的是意图理解、任务分解、工具选择这三件事而不是执行具体操作。我常用的一个类比LLM就像一个刚入职的聪明项目经理他知道大概要做什么但具体每个环节怎么落地他需要问专家Tool、查手册知识库、或者调用现成的流程Skill。你让他直接去写一个复杂的SQL他可能写错但你让他判断这个需求该不该查数据库、该查哪张表他判断得比规则引擎准得多。这里有个关键点LLM的token机制决定了它的能力边界。热词里有个很有意思的说法——key我是谁、query我在找什么、value我能提供什么这其实就是注意力机制的本质。LLM在处理长上下文时会不自觉地给不同信息分配不同的注意力权重。这意味着如果你把Tool的描述、Skill的说明、历史对话全塞进prompt里LLM很可能看漏关键信息。我的做法是给LLM的上下文做分层。系统指令我是谁放最前面当前任务我在找什么放中间可用的Tool和Skill列表我能提供什么放最后并且用清晰的分隔符隔开。实测下来这样能让工具选择的准确率提升不少。2.2 Tool与Skill的区别一个是原子操作一个是组合拳这两个概念经常被混用但在工程上必须分清。Tool是原子操作比如查询天气发送邮件读取文件。它是最小的执行单元输入输出都很明确通常对应一个API或者一个函数。Skill是组合能力比如处理客户投诉这个Skill内部可能包含查询订单Tool→判断问题类型→调用退款Tool→发送安抚邮件Tool这一整套流程。Skill是有状态的、有分支逻辑的、可以复用的。热词里skill编码247skill编码193skill插件codex skill这些搜索说明大家已经在关注Skill的标准化问题了。我的经验是Skill一定要有明确的输入契约和输出契约否则多个Skill串联时会出现上一个Skill的输出格式下一个Skill读不懂的问题。举个我实际踩过的坑早期我们做了一个生成周报的Skill输出是纯文本后来又做了一个发送周报的Skill期望输入是结构化的JSON。结果两个Skill串起来直接报错。后来我们定了个规矩所有Skill的中间产物必须是结构化数据只有最终面向用户的输出才转成自然语言。2.3 Harness被严重低估的工程骨架Harness这个词在热词里出现频率极高——deepseek harnessharness工程harness engineeringharness anything。但很多人还是把它理解成一个调度器这就太小看它了。我的定义是Harness是Agent的运行时环境负责状态管理、上下文组装、错误处理、Skill调度、记忆读写、安全边界控制。它不参与具体决策但决定了Agent能不能稳定跑完一个长任务。打个比方LLM是司机Tool是车上的各种按钮Skill是驾驶技巧Harness就是整辆车的底盘、电路、油路系统。司机再厉害底盘散了也开不动。Harness要解决的核心问题有三个状态持久化Agent跑一个任务可能要几十轮中间如果进程重启状态不能丢。上下文窗口管理LLM的上下文有限Harness要决定哪些历史信息保留、哪些压缩、哪些丢弃。失败恢复某个Tool调用失败了是重试、换方案、还是上报给用户这个决策逻辑在Harness里。我见过一个团队Agent跑得好好的结果服务器一重启所有进行中的任务全丢了因为状态全在内存里。这就是Harness没做好的典型表现。3. 工业界实战一个Agent系统的完整搭建过程3.1 需求拆解先想清楚谁用、干什么、干到什么程度任何Agent项目第一步都不是写代码而是把需求拆清楚。我习惯用三个问题来框定范围谁用是内部员工用还是终端用户用这决定了容错率。内部工具可以容忍偶尔报错面向用户的必须做到优雅降级。干什么是单轮问答还是多轮任务是确定性流程还是需要自主决策这决定了Harness的复杂度。干到什么程度是辅助人做决策还是直接替人执行这决定了安全边界。我做过一个合同审核Agent需求是辅助法务人员快速定位风险条款。这个场景下Agent不需要做最终决策只需要把可疑条款标出来并给出理由。所以我们的Harness设计得很轻——不需要复杂的回滚机制因为Agent不会真的修改合同。但后来做自动退款Agent时情况完全不同。这个Agent会真的调用退款接口一旦出错就是真金白银的损失。所以Harness里加了大量的校验层金额超过阈值要人工确认、同一用户短时间内多次退款要拦截、退款前必须二次查询订单状态。提示需求阶段一定要把Agent能做什么和Agent绝对不能做什么写清楚后者往往比前者更重要。3.2 工具层设计Tool的粒度怎么把握Tool的粒度是个很微妙的问题。太粗LLM不好选太细LLM要调很多次token消耗大且容易出错。我的经验法则是一个Tool应该对应一个人类会一次性完成的动作。比如查询订单是一个Tool但查询订单并计算退款金额就不该是一个Tool因为后者包含了两步逻辑应该拆开。具体到实现我通常会给每个Tool定义这几个字段{ name: query_order, description: 根据订单号查询订单详情返回订单状态、金额、下单时间, parameters: { order_id: { type: string, description: 订单号通常是16位数字, required: true } }, returns: { status: 订单状态枚举值pending/paid/shipped/completed/cancelled, amount: 订单金额单位元, created_at: 下单时间ISO8601格式 } }注意description和returns这两个字段。很多团队只写parameters结果LLM不知道这个Tool返回什么就不会在合适的时机调用它。Tool的description要写什么时候用returns要写用了能得到什么这两句话直接决定了LLM的选择准确率。还有个细节参数描述里要给出格式示例。订单号通常是16位数字比订单号要好得多因为LLM会据此判断用户输入是否合法。3.3 Skill编排把多个Tool串成一条稳定的流水线Skill的本质是预定义的任务流程。它和让LLM自由发挥是两种不同的思路各有适用场景。LLM自由发挥适合开放式任务比如帮我分析这份报告。优点是灵活缺点是结果不稳定。Skill编排适合确定性任务比如处理退款申请。优点是稳定可复现缺点是遇到流程外的情况就卡住。我的做法是混合使用主流程用Skill编排保证稳定性每个Skill内部的判断节点让LLM来做遇到Skill覆盖不了的情况再交给LLM自由发挥。一个退款Skill的伪代码大概长这样def refund_skill(order_id, reason): # 第一步查询订单 order call_tool(query_order, order_idorder_id) if order.status cancelled: return {result: fail, msg: 订单已取消无需退款} # 第二步LLM判断是否符合退款条件 judgment llm_decide( contextf订单状态{order.status}金额{order.amount}退款原因{reason}, question是否符合退款条件返回yes或no及理由 ) if judgment.answer no: return {result: reject, msg: judgment.reason} # 第三步执行退款 refund_result call_tool(execute_refund, order_idorder_id, amountorder.amount) # 第四步通知用户 call_tool(send_notification, user_idorder.user_id, content退款已处理) return {result: success, refund_id: refund_result.id}这个Skill里第一步和第三步是确定性的Tool调用第二步是LLM判断。这样既保证了流程稳定又保留了灵活性。注意Skill里的LLM判断节点一定要设置超时和兜底逻辑。我遇到过LLM返回格式不对导致整个Skill卡死的情况后来加了如果LLM返回无法解析默认走人工审核的兜底。3.4 Harness实现状态、上下文、错误处理三件套Harness是整篇文章的重点我拆成三块来讲。状态管理Agent的每一轮对话、每一次Tool调用、每一个中间结果都要持久化。我用的是事件溯源的思路——不存最终状态而是存所有发生的事件需要时重放。这样即使进程崩溃重启后重放事件就能恢复。存储选型上轻量场景用SQLite就够了重场景上PostgreSQL。关键是每个事件要有唯一ID和时间戳方便排查问题。上下文组装这是Harness里最考验工程能力的地方。LLM的上下文窗口有限你不能把所有历史都塞进去。我的策略是分层压缩最近3轮对话完整保留一字不改。3-10轮之前的对话只保留用户意图Agent动作结果摘要。10轮之前只保留关键结论比如用户已确认退款金额。这样能把上下文控制在合理范围内同时不丢失关键信息。错误处理Tool调用失败是常态Harness要有一套完整的处理策略。我总结了一个决策树错误类型处理策略重试次数网络超时自动重试3次指数退避参数错误让LLM修正参数后重试2次权限不足上报用户请求授权0次业务规则拒绝直接返回失败原因0次未知错误记录日志降级处理1次这张表是我们踩了无数坑之后总结出来的。比如参数错误让LLM修正是因为很多时候是LLM自己拼错了参数格式让它看一眼错误信息就能改对。而权限不足绝对不能自动重试否则会触发风控。4. 常见问题与排查技巧实录4.1 Agent跑偏了怎么办上下文污染的排查最常见的现象是Agent跑着跑着突然开始做和任务无关的事情。这通常是上下文污染导致的。排查思路打印完整的上下文看有没有无关信息混进去。检查Tool的返回值有没有把整个数据库记录都塞进去了。检查Skill的中间产物有没有把调试信息也传下去了。我遇到过一个案例Agent在查订单时Tool返回了完整的订单对象包含了几十个字段其中有个字段叫internal_notes里面是客服的内部备注。LLM看到这些备注后开始脑补用户的情绪然后自作主张地改变了回复策略。后来我们在Tool层做了字段过滤只返回必要的字段问题就解决了。提示Tool的返回值一定要做白名单过滤不要图省事直接返回整个对象。4.2 Skill串联时的格式不兼容问题前面提过多个Skill串联时格式不兼容是高频问题。我的解决方案是定义统一的中间数据格式。我们内部定了一个叫AgentMessage的结构{ type: tool_result | llm_output | user_input, source: skill_name or tool_name, timestamp: 2024-01-01T00:00:00Z, payload: {}, meta: { confidence: 0.95, need_human_review: false } }所有Skill的输入输出都用这个结构包裹。这样不管上游是哪个Skill下游都能统一解析。meta字段里的confidence和need_human_review特别有用——当LLM判断的置信度低于阈值时自动触发人工审核。4.3 并发场景下的状态冲突热词里有个ai agent 怎么扛并发这是个真问题。多个用户同时用Agent如果状态管理没做好会出现A用户的操作影响了B用户的任务。我的做法是每个会话独立的状态空间。会话ID作为命名空间所有状态读写都带上会话ID。数据库层面用session_id做分区键避免跨会话查询。另外对于共享资源比如同一个订单被两个Agent同时操作要加乐观锁。具体做法是读取时记录版本号写入时检查版本号是否变化变了就重试。UPDATE orders SET status refunding, version version 1 WHERE order_id ? AND version ?如果影响行数为0说明版本号变了说明有别的Agent在操作这时候要重新读取最新状态再决策。4.4 LLM幻觉导致Tool调用错误LLM会编造不存在的参数值这是幻觉的典型表现。比如用户说帮我查一下昨天的订单LLM可能编一个订单号出来。防御手段有三层参数校验Tool层对参数做格式校验订单号必须是16位数字不符合直接拒绝。Prompt约束在系统指令里明确写如果用户没有提供必要参数必须先询问用户不得编造。二次确认对于关键操作如退款执行前让LLM复述一遍参数确认无误再执行。第三层特别有效。我们让LLM在调用退款Tool前先生成一句我将为订单XXX退款YYY元请确认用户确认后才真正执行。这个简单的机制拦住了不少幻觉导致的错误。4.5 排查速查表现象可能原因排查方法解决方案Agent不调用ToolTool描述不清打印Tool列表看LLM是否理解优化description加使用场景调用错误的ToolTool之间描述重叠对比相似Tool的描述合并或明确区分边界参数格式错误缺少格式示例看LLM生成的参数在参数描述里加示例任务中途卡死缺少超时机制看日志最后一步加超时和兜底逻辑结果不稳定上下文污染打印完整上下文做上下文分层和过滤并发冲突状态未隔离检查session_id加会话隔离和乐观锁5. 从工具到伙伴Agent演进的几个观察5.1 记忆机制是伙伴感的来源工具和伙伴的区别是什么工具用完就忘伙伴会记得你上次说过什么。Agent要产生伙伴感必须有长期记忆。这个记忆不是简单的对话历史而是结构化的用户画像和偏好。比如这个用户喜欢简洁的回复这个用户上次退款是因为物流太慢。实现上我用的是记忆提取记忆检索两段式。每轮对话结束后让LLM提取值得记住的信息存到向量数据库下一轮对话开始时根据当前任务检索相关记忆注入上下文。关键是记忆要有衰减机制。不是所有记忆都永久保留时间久远的、重要性低的记忆要逐渐淡化否则记忆库会越来越臃肿检索质量下降。5.2 Skill的复用与组合是规模化的关键单个Agent能做的事有限真正有价值的是Skill的复用。我们内部建了一个Skill库每个Skill都有标准化的输入输出契约新项目可以直接引用。比如发送通知这个Skill在退款Agent、客服Agent、营销Agent里都能用。这样新项目启动时不用从零开始直接组合现有Skill就行。热词里book to skillworkbuddy skill这些搜索说明大家已经在探索Skill的标准化和复用问题了。我的建议是从第一个项目开始就按标准格式写Skill哪怕当时只有你一个人用。等到Skill多了标准化带来的收益会非常明显。5.3 安全边界Agent越强边界越重要Agent能力越强越需要明确的安全边界。我的原则是**最小权限关键操作人工确认**。最小权限是指Agent只能访问完成任务必需的资源。查订单的Agent不应该有修改用户的权限发邮件的Agent不应该有读取财务数据的权限。关键操作人工确认是指涉及资金、隐私、不可逆操作时必须有人工确认环节。这个确认不是简单的是/否而是要让用户看到Agent的决策依据比如我将退款100元因为订单状态是已支付且用户提供了合理的退款理由。注意安全边界不是限制Agent能力而是让Agent的能力可以被信任地使用。没有边界的Agent没人敢用。5.4 评估体系怎么知道Agent做得好不好Agent的评估比传统软件难得多因为它的输出不是确定性的。我的做法是分层评估Tool层调用成功率、平均耗时、错误率。这些是硬指标和传统API监控一样。Skill层任务完成率、平均轮次、人工介入率。这些反映流程的稳定性。Agent层用户满意度、任务一次通过率、异常处理能力。这些需要人工标注或用户反馈。我特别看重人工介入率这个指标。它直接反映了Agent的自主程度。如果人工介入率很高说明Agent要么能力不足要么边界太保守需要针对性优化。6. 一些实操心得和踩坑记录6.1 不要过早追求全自主我见过不少团队一上来就想做完全自主的Agent结果做出来的东西没人敢用。我的建议是从人机协作开始逐步提升自主度。具体路径是先做Agent建议人执行再做Agent执行人确认最后做Agent自主执行异常上报。每一步都要积累足够的信任和数据再进入下一步。6.2 日志要记全但不要全塞进上下文日志和上下文是两回事。日志要记全方便排查问题上下文要精简只放LLM需要的信息。我见过把完整日志塞进上下文的做法结果LLM被无关信息干扰表现大幅下降。正确的做法是日志存到独立的存储系统上下文只放经过筛选的关键信息。需要排查问题时从日志系统查而不是从上下文里翻。6.3 Prompt版本管理很重要Agent的Prompt会频繁调整每次调整都可能影响效果。如果没有版本管理出了问题都不知道是哪个版本导致的。我的做法是Prompt和代码一样纳入版本控制。每次修改都记录修改原因、修改内容、效果对比。这样出问题时可以快速回滚到上一个稳定版本。6.4 测试用例要覆盖边界情况Agent的测试不能只测正常流程更要测边界情况。我通常会准备这几类测试用例正常流程用户提供完整信息Agent顺利完成。信息缺失用户没提供必要参数Agent应该主动询问。参数错误用户提供了格式错误的参数Agent应该识别并纠正。Tool失败模拟Tool调用失败Agent应该优雅处理。恶意输入用户试图诱导Agent做越权操作Agent应该拒绝。这些测试用例要定期跑确保每次修改后Agent的行为都符合预期。6.5 性能优化的几个关键点Agent的性能瓶颈通常在三个地方LLM调用、Tool调用、上下文组装。LLM调用能用小模型的地方就用小模型。比如意图识别用7B模型就够了不需要上70B。Tool调用能并行就并行。比如同时查询订单和用户信息不要串行。上下文组装能缓存就缓存。系统指令、Tool列表这些不变的部分缓存起来避免重复组装。我实测下来做好这三点Agent的响应时间能降低一半以上。7. 关于未来演进的一点个人判断Agent从工具到伙伴的转变本质上是从执行指令到理解意图的转变。工具时代用户要告诉Agent每一步怎么做伙伴时代用户只需要说想要什么Agent自己规划路径。这个转变对工程的要求更高了。因为工具时代出错最多是没执行伙伴时代出错可能是执行错了。所以Harness层的状态管理、错误恢复、安全边界会越来越重要。我个人的判断是未来Agent的竞争力不在模型而在Harness工程。模型大家都能用但怎么把模型、Tool、Skill、记忆、安全这些组件稳定地组装起来是每个团队要自己解决的问题。这也是为什么我花这么多篇幅讲Harness而不是讲模型选型。最后分享一个我一直在用的原则Agent的每一个决策都要能解释清楚为什么。如果Agent做了一个决定你无法从日志和上下文中还原出它的推理过程那这个Agent就是不可信的。可解释性不是锦上添花是Agent能被真正用起来的前提。