
模型本身不会用工具这应该是所有做过Agent开发的人都撞过的那堵墙。GPT-4也好、DeepSeek也好API拉起来之后它只会回复文本你让它“查一下天气再告诉我”它表面答应但结果还是对着空气瞎编。2025年社区里讨论的harness工程正是为了解决这个断层而涌现出来的一套工程实践——先把模型的原始完成度“套上马鞍”再通过工具调用、技能注册、执行编排把它改造成真正能干活的东西。而比这更进一步的话题是光有马鞍不够还要把整套系统做成一个会记忆、会计划、会反省的认知体也就是从harness工程升级到认知工程。这篇文章我想把这套升级路径完整拆开适合已经被Agent框架反复折磨过、或者正准备把手头Demo级Agent推上真实任务的开发者。1. “模型很聪明但不会干活”harness工程在解决什么任何深入做过Agent的开发都会有同感把LLM当作一个“会说话的大脑”去理解你会很快发现它的原生输出和应用落地之间隔着一条巨大的断层。模型接受提示词后给出文本这份文本可能是合理的、结构完整的但它不可靠格式随机漂移、数值计算会出错、知识截止之后的信息一无所知更不会自动去调用外部系统完成闭环。它本质上是一个概率性文本生成器不是一个任务执行器。这就是harness工程存在的基本理由。harnness这个概念在传统软件工程里指的是测试的“夹具”或“笼头”但在LLM Agent语境下它的含义变成了“给模型装上一整套可受控的外部能力装置”你定义工具清单、设定调用规则、给模型提供可执行的动作空间然后由一段工程代码来保证模型的每一次决策都被稳定接管和严格执行。你可以把它理解成给一匹没受过训练的马配上缰绳和鞍具——马还是那匹马但只有戴上harness它才可能载着人走到指定地点。实际开发里没有harness的Agent是什么状态我见过太多团队把工具列表直接拼进System Prompt就上线了。模型确实在回复里写出了“我调用了数据库查询”但日志显示它只是编了一段输出并没有真的发起请求。再或者模型确实尝试调用工具但因为参数格式不规范、技能名称拼错、返回结果太长导致上下文爆炸等原因任务中断在中间状态。这些问题不是模型智商不够而是缺少一个结构化的“套具层”来约束模型的决策空间、接管工具的输入输出、保证执行链路的确定性。我自己最开始写的Agent只有两步把用户请求交给模型再把模型的回复返回给用户。跑Demo很顺畅一旦接进真实生产环境就崩溃。后来翻了不少harness工程的开源实现才明白真正可用的Agent必须经历一次“去伪存真”的工程转化——模型思考结果先进入一个结构化的动作表示再由外部系统严格解析和执行。这个转化就是harness工程的核心也是从“模型很聪明”到“系统很好用”之间最难补上的一块拼图。对比维度裸调LLM的AgentHarness化后的Agent工具调用依赖模型自觉可能伪造由代码注册、白名单控制强制走接口输出格式自然语言漂移结构化Schema校验失败重试任务中断一步出错即死有状态、可回退、可恢复技能扩展改Prompt字符串以独立Skill模块注册可动态装配可观测性只能看生成文本完整执行轨迹可追溯可审计从这个角度再回看热搜词里“harness和agent区别”之类的问题本质就在这里agent是概念层面的智能体只要它具备感知、决策、行动能力你都可以叫它agent。但harness是把“决策能力”变成“可靠执行能力”的那层工程基础设施。没有这层设施agent只是聊天的有了它agent才是干活的。1.1 为什么“接线”这件事这么重要很多人觉得“给模型加工具”不就是定义个JSON Schema再丢进Prompt吗真实搞过之后才知道这里的地狱细节远超预期。工具的参数怎么从模型回复里准确提取模型输出了一串差不多的JSON但少了个括号怎么办工具执行超时了是否需要终止整个任务工具返回结果中带有非法字符会不会破坏下一次模型调用搜一下社区里“agent execution terminated due to error”这个词频繁出现就知道这种事故普遍到快成为常识了。Harness工程的核心价值不是给模型“增加功能”而是给模型“增加可靠的执行保障”。它把Agent从一次性问答的形式改造成了一个可以循环运转的“决策-执行-反馈”闭环。这也是所有更深层改造的前提——认知工程里要谈的记忆、规划、反思如果没有坚实的harness执行层作为底座一切花哨设计都无从谈起。所以别rst嫌接线工作低级很多认知升级的坑追根溯源都在接线上。2. harness、Agent、Skill很多困惑都是概念打架既然热词区里铺满了“harness和agent区别”“skill和agent的区别”“harness与agent之间的边界”这类问题说明大家真正卡住的不是代码能力而是概念模型没理顺。我用比较朴素的辞令把这三个东西拆开Skill是招式Agent是打架的人Harness是整个格斗馆的规则体系和安全设施。Skill指的是一个具体可复用的能力单元。比如“执行Python代码”“读取CSV文件”“调用某个API”“生成一幅图”。它应当以标准化的输入输出接口封装有清晰的描述说明什么情况下该用、什么情况下不该用。Skill是给模型准备的“技能石”模型在决策时通过读取描述来决定要不要激活它、传什么参数进去。Agent则可以看作一个具备自主目标的运行主体。它有状态、有上下文感知、有规划能力它会在一次任务里决定“这步我应该用Python技能算数据下一步应该用绘图技能出图”然后驱动这些Skill顺序执行。它代表的是“谁会做决策、谁对结果负责”的逻辑层。Harness承载的是整个“打得起来而且不会出乱子”的工程系统。它决定Agent能使用哪些Skill、技能的权限边界是什么、执行的超时上限是多少、调用出错时是重试还是终止、全过程如何记录日志。Harness可以替换模型、替换配置、调整策略但它的职责始终是“约束与控制”。我见过不少团队把这几个概念混着用结果项目一开始就注定踩坑。有人在System Prompt里用几百行文字“描述一个Agent”实际上这只是一段特别长的提示词既没有Skill注册也没有执行环路。还有人把Skill写得非常零碎一个“读取文件”功能拆成十几个子技能结果模型每次决策都要翻菜单迟迟下不了手。其实工程合理性的标准就一条每个Skill应当是模型“看一眼描述就知道该不该用、用了大概发生什么”的原子能力而Harness要保证这些Skill在正确的边界内被组合。层次本质你关心的核心问题Skill能力原子输入输出是什么、什么时候该调用Agent决策主体任务怎么拆、下一步做什么Harness工程约束层边界、安全、重试、追踪、资源控制在我目前的项目实践里最实用的一种组织方式是Skill以单个文件/模块形式存在内部包含运行函数、参数Schema和给模型看的说明文档Agent借助这些Skill的说明来决定路由Harness则负责把Agent的路由结果转成实际执行调用再根据执行结果决定是否把反馈交还给模型继续推理。三层各司其职项目结构清晰了非常多变。2.1 用DeepSeek Harness这类实践理解Skill装配DeepSeek Harness在2025年被社区频繁提起不是偶然。这套实践把“模型-工具-技能”的装配关系展示得很直白通过harness定义模型能访问哪些能力池并通过Skill描述告诉模型在什么样的情况下使用哪种技能。有人问“deepseek harness用skill到底怎么用”其实核心不在代码里装了什么炫酷玩意而是设计Skill描述的方法——描述写得清楚模型路由自然准确描述写得含糊模型就瞎猜。这也是从单纯的“工具调用”迈向“技能管理”的第一步你开始认真写每一个技能的使用说明而不是塞一段接口文档了事。事实上Harness工程的高级形态就是对技能边界、行为策略、反馈回路的一整套结构化治理。3. 一个能跑的harness骨架基于LangGraph的编排实现理论说再多不如直接看代码。目前社区里最主流的一套harness工程底座是LangChain LangGraph的组合LangChain提供了一大堆现成的工具封装和模型接入能力LangGraph则负责把Agent的执行过程变成一个显式的图结构节点、边、状态都可视可控。热搜词里单独挂着“harness架构(langchainlanggraph)智能体开发案例”说明这套组合在社区基本已经成了事实标准。我更喜欢用LangGraph的一个原因是它有状态管理。Agent在执行过程中产生的中间结果、工具调用记录、错误信息都能存进一个全局State对象这让“编排”从抽象概念变成了具体可编程的东西。下面提供一个极简但完整的harness骨架你动手跑一遍就能直观理解Skill、Agent与Harness三层是怎么协作的。from typing import TypedDict, Annotated, Callable from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage import json # 1. 定义全局状态所有工具执行结果和消息历史都沉淀在这里 class AgentState(TypedDict): messages: list last_tool_result: str step_count: int # 2. 定义Skill注册表每个技能都是独立函数 描述文档 SKILLS {} def skill(name: str, description: str): def decorator(func: Callable): func.skill_name name func.skill_description description SKILLS[name] func return func return decorator skill(python_exec, 在沙箱环境中执行Python代码适合做计算、数据处理) def python_exec(code: str) - str: # 真实项目里请接沙箱运行时这里用len模拟 return fexecuted code of {len(code)} chars skill(read_csv, 读取本地CSV文件并返回前5行) def read_csv(path: str) - str: return fcsv preview of {path} # 3. 模型决策节点把技能清单挂给模型让它决定下一步动作 def agent_node(state: AgentState): llm ChatOpenAI(modelgpt-4o-mini, temperature0) skills_desc \n.join( f- {name}: {SKILLS[name].skill_description} for name in SKILLS ) system_prompt f你是被harness约束的agent。 可用技能如下 {skills_desc} 请输出JSON决策格式为 {{skill: 技能名, args: {{...}} }} 如果你的结果已经满足用户需求输出 {{skill: finish, result: 最终答复}} resp llm.invoke([*state[messages], (system, system_prompt)]) return {messages: state[messages] [AIMessage(contentresp.content)]} # 4. 工具执行节点解析模型输出调技能拿结果 def tool_node(state: AgentState): decision_text state[messages][-1].content decision json.loads(decision_text.strip().replace(json, ).replace(, )) skill_name decision.get(skill) if skill_name finish: return {last_tool_result: decision.get(result, ), step_count: state[step_count] 1} fn SKILLS.get(skill_name) if not fn: return {last_tool_result: ferror: skill {skill_name} not found, step_count: state[step_count] 1} result fn(**decision.get(args, {})) return { last_tool_result: result, messages: state[messages] [AIMessage(contentftool result: {result})], step_count: state[step_count] 1, } # 5. 状态流转与结束条件控制 builder StateGraph(AgentState) builder.add_node(agent, agent_node) builder.add_node(tool, tool_node) builder.add_edge(agent, tool) def should_continue(state: AgentState): if state[step_count] 5: return END last state[messages][-1].content if skill: finish in last or finish in last: return END return agent builder.add_conditional_edges(tool, should_continue) builder.set_entry_point(agent) app builder.compile() # 6. 运行示例 result app.invoke({ messages: [HumanMessage(content读取 data.csv 并告诉我前5行长什么样)], last_tool_result: , step_count: 0, }) print(result[messages][-1].content)这个骨架虽然简单但已经把harness工程最关键的几个原则都放进去了技能必须注册且描述清晰模型输出必须经过解析才能转成动作工具结果必须显式反馈给模型执行必须有步数上限以防死循环。实际项目的复杂度会高不少——解析失败要重试、参数校验要严格、工具要跑在沙箱里、并发和持久化要考虑——但骨架不变。3.1 为什么是LangGraph而不是自己写状态机市面上也有很多人说自己写个循环就能实现Agent不需要LangGraph。我不反驳早期我也这么干过。但到了多工具、多分支、需要人工审批节点、需要并行分支的场景手写循环的状态维护会迅速变成一团乱麻。LangGraph的价值在于它把图结构显式化了每一条边、每一个跳转条件都是代码里可见的声明比散落在while循环里的if判断容易维护得多。再加上它自带State的不可变快照、断点重放、人工介入能力几乎天生就是为了“可控Agent执行”设计的。如果你目标就是做一个简单的两层调用自写循环没问题只要你想往认知工程方向走图编排几乎是必选项。4. 从harness到认知工程到底“升级”了什么好现在假设你已经有一个不错的harness工程模型能稳定调用技能、执行链路可靠、日志完整。这时候你再回头审视整个系统会发现一个尴尬的事实——每次新任务来它仍然是一个“失忆的专家”。同一个用户昨天让它生成过图表今天再问同样的事它要从零开始上一轮任务里它已经发现“数据文件里某列全是空值”这种重要情报但它不会把这个经验带到下一轮。Harness工程把执行做扎实了却还没有把“认知”做长进。所以“将harness工程升级到认知工程”这句话我认为准确的含义是从“给模型接上手脚”走向“给agent构建大脑结构”。不是在模型层做什么微调而是在应用架构层引入一套更接近人类认知层次的信息处理机制。拆开来看至少包含四个维度的改造记忆分层、任务规划、反思纠错、安全边界。4.1 记忆分层从“无状态”到“会成长”大家都知道要加记忆但多数人做出来的只是一个“把历史对话拼进Prompt”的劣质方案。真实场景下历史会话记录越长模型注意力越容易被无关信息稀释。好的做法是把记忆拆成工作记忆和长期记忆两层。工作记忆承载当前任务的进行状态用户目标、已经执行完的步骤、上一步的工具返回结果、还没完成的事项。这一层可以理解为Agent的“桌面”需要保持精简通常由harness的State对象来维护每次只把必要信息送回上下文。长期记忆则存储跨任务的结构化知识用户偏好、领域实体、任务结论、踩坑经验。这层一般落库或者进向量数据库在相关任务触发时检索召回。用个最简化的实现感受一下# 长期记忆的最简实现向量库 召回 import sqlite3, json class LongTermMemory: def __init__(self, db_path: str): self.conn sqlite3.connect(db_path) self.conn.execute(CREATE TABLE IF NOT EXISTS memory (id INTEGER PRIMARY KEY AUTOINCREMENT, topic TEXT, content TEXT, keywords TEXT)) def store(self, topic: str, content: str, keywords: list): self.conn.execute( INSERT INTO memory (topic, content, keywords) VALUES (?, ?, ?), (topic, content, json.dumps(keywords)), ) self.conn.commit() def recall(self, keywords: list) - str: # 实际项目应通过向量相似度检索这里用关键词匹配示意 results self.conn.execute( SELECT content FROM memory ORDER BY id DESC LIMIT 20 ).fetchall() return \n.join(r[0] for r in results if any(k in r[0] for k in keywords))如果你有一千个既往任务的经验沉淀下次遇到“用户要分析销售数据报表”时agent可以从长期记忆里直接调出上次的分析结论、用过的代码模板、典型坑位而不是从头摸索。这就是从“工程执行”到“认知积累”的分水岭。4.2 规划与反思把“一步到位”改成“计划-执行-校验”Harness工程版本的Agent每轮都是“读一下任务-决定调哪个技能-执行-再回到模型”。这种模式对单步任务没问题但遇到复杂任务时模型很容易短视想到一步做一步做着做着忘记最初目标或者被中间结果带偏。认知工程里的规划层要求agent在动手之前先把任务拆解成子目标并建立一份显式的执行计划。PLANNER_PROMPT 你是任务规划器。将用户目标拆解为3-5个可执行步骤。 输出JSON数组 [ {{step: 1, goal: 子目标描述, action: 需要的技能名, check: 如何判断这步完成}} ] 注意每步的check必须可验证不能是模糊表述。 # 反思节点通常在一次任务结束后对执行过程做一次复盘总结 REFLECTOR_PROMPT 你是复盘器。基于以下执行轨迹回答 1. 这次任务哪里成功了 2. 哪里失败了/可以改进 3. 总结出一条可复用的经验它以什么关键词被检索最合适 执行轨迹 {trajectory}这两个Prompt看起来简单但它们背后代表的是一个全新的执行流程先规划再按计划执行每走一步检查check条件不满足就回退重来最终对整个轨迹做一次反思并把经验写入长期记忆。这就是所谓“认知回路”的基本形态。如果你在做Agent开发时发现自己从“猜下一个工具调用”变成了“按计划推进、按结果复盘”说明你已经从harness阶段迈进了认知工程阶段。4.3 错误处理升级从“终止”到“能自愈”热搜词里有个高频短语“agent execution terminated due to error”——翻译过来就是“Agent执行因错误终止”。这是所有Agent落地最真实的伤口工具返回异常、参数校验失败、依赖环境崩溃框架的默认行为基本都是一抛异常就结束用户拿到一条莫名其妙的错误信息任务不了了之。认知工程对待错误的态度完全不同——它把错误当作认知过程中正常且重要的输入信号而不是终点。每个错误触发后系统首先判断是否可恢复如果可恢复把错误信息整理成结构化反馈给模型让它换一种方式重试如果不可恢复才优雅降级。这里需要做一层错误分类与反馈翻译的逻辑因为直接甩出原生的堆栈跟踪给模型看很多时候只会把它带偏它需要的是“发生了什么、应怎么调整”不是几十行异常栈。4.4 安全与边界认知能力越强越需要护栏认知工程让agent变得更强同时也让风险变得更大它能记忆、能规划、能自主调用一串工具如果没有边界控制一个小失误可能引发连锁副作用。Harness层的安全策略要靠白名单技能、权限隔离、调用配额过载保护来保证认知层的安全则要更进一步给agent设定“行为准则层”让它学会拒绝执行具有外部副作用的操作在敏感动作前主动请求人工确认。几年前我们觉得这是过度设计现在真实跑过长时间任务后才发现护栏不是束缚而是让agent可以大胆尝试的底气——首先保证不会坏其次才能谈干得好。升级维度Harness工程阶段认知工程阶段记忆无状态或会话内森林工作记忆长期记忆分层规划每步即时响应显式任务拆解可验证check错误处理异常终止分类反馈自愈重试经验复用无反思沉淀检索式召回安全工具白名单行为准则层人工审批闸门5. 升级路上的真实踩坑记录与实操建议说实话从harness工程往认知工程升级的路径并没有一条“照这个文档就能做”的路。每个环节都隐藏着即使看文档也未必能预见的坑。我把亲身踩过的、以及身边团队反复出问题的点整理成清单希望你能绕开。技能描述一定要写给模型看不是写给程序员看。我见过最普遍的错误是开发者用接口文档的语气写技能描述堆了很多术语模型根本不知道怎么用。正确写法是“本技能用于X场景通常在做了Y之后调用传入Z参数输出会包含W信息。如果你不确定是否需要调用不要用。”每一句都在降低模型的路由决策负担。错误反馈要分“可恢复”和“不可恢复”两类处理。可恢复错误应当带着上下文进入重试循环比如参数解析JSON不合法、网络超时。不可恢复错误则应直接终止任务并返回给用户说明比如权限不足、输入数据缺失。把所有错误都重试会把系统拖进死循环热搜词里的“execution terminated due to error”有一部分就是重试策略设置不当导致的。绝对要给Agent设置最大步数和时间预算。大型模型在多轮工具调用中完全可能迷路循环10轮20轮不结束。harness层设置硬性的步数上限之外认知工程还要加上目标一致性校验如果agent发现当前动作已经偏离最初目标应当主动停止并汇报而不是“忠实”地执行到底。长期记忆必须定期清洗或人工确认。模型反思生成的经验并不总是正确的如果错误经验被写进长期记忆并在后续任务中被反复召回相当于把坏习惯变成了默认习惯。我会在记忆写入环节加一道“采纳门槛”只有达到一定置信度的结论才入库部分关键经验需要人工抽查确认。这比事后清理成本低得多。记忆检索要讲究相关性切题不要无脑拼历史。有些人给Agent的System Prompt里塞回去七八次任务的历史结果模型被不相关信息干扰表现反而下降。好做法是回忆时为核心目标和当前步骤限定关键词空间只召回任务真正需要的经验片段。从工程约束到认知结构这个过程没有一蹴而就的银弹。我自己的路径是先把手头已有harness跑稳再加入一层简单的反思节点让Agent每完成一次复杂任务都产出经验短句接着搭建向量检索的长期记忆让经验真正可复用最后才把规划层和校验check纳入执行流。这个顺序的优点是每一步都能独立验证收益不会机制叠太多导致出问题不知道是哪一环。如果你正在做一个被反复吐槽“能力很强但总在最不该出错的地方出错”的Agent项目那很可能是缺了认知这一层。别急着换更大的模型先把反思、记忆、规划这几根骨架装上哪怕是最朴素的实现效果都会立刻不一样。