
标题拆解为两半来看会有意思得多。上面是agent智能体下面是skills技能。市面上大量文章都在讲怎么接大模型、怎么写 prompt、怎么搭框架但真正卡住一线工程师的地方往往是同一个问题你的 Agent 到底会干什么当模型输出一大堆 token、看起来在思考的时候它此刻的行为边界是什么它能调用哪些动作每个动作是不是稳定可靠我做了大半年 Agent 相关项目最深的感触是Agent 的能力上限不在模型而在你喂给它的那一批技能。这也是我做 agent-skills 这个迷你项目的原因——不想再造一个框架只想把如何为 Agent 设计、实现、测试一套高可用技能这件事彻底捋清楚。这篇文章没有高深理论全部来自实际跑通的经验。适合正在用 LangChain、AutoGPT、CrewAI 或自研编排层做 Agent 的开发者也适合那些已经做出原型、但发现 Agent 经常看起来聪明、做起来犯傻的团队。读完后你会对技能设计、调用编排、评估链路有一个可以直接复制到项目里的完整打法。1. agent-skills 解决的核心问题为什么你的 Agent 总在空转1.1 光有模型没有技能Agent 就是一台没有手的计算机先讲一个真实场景。早期我用 GPT-4 写过一个自动整理周报的 Agentprompt 里设置了角色、任务目标、输出格式自以为天衣无缝。结果跑了一周发现 Agent 经常编造数据——它不存在的本周上线功能能写得有模有样原因很简单模型根本不会去查询真实数据源它只能凭训练数据里的蛛丝马迹推算一个看起来合理的答案。这就是没有技能的 Agent的典型症状。模型是大脑但大脑没有手不知道也不应该知道如何拉起数据库接口、执行一段 Python 代码、去搜索、去读取某个特定文件。你必须在它和外部世界之间架起一套标准化的动作层这个动作层就是技能。我跑过的项目里最直接的对比是把同样一个总结本周工单的任务分别交给纯 prompt 型 Agent和带技能型 Agent。前者输出了一份结构完整但带幻觉的总结后者先调用查询工单数据技能拿到真实列表再调用生成 Markdown 报表技能输出结果全程没有一处编造因为每一个数据点都有明确的来源。1.2 技能到底是什么一次标准化的模型-工具交互在 agent-skills 里我对技能的定义是一个可以被模型按固定协议调用、执行具体动作并返回结构化结果的最小功能单元。它比工具多了一层上下文感知比插件更聚焦行为本身。拆开看一个完整的技能包含四个部分技能名与描述模型用来决定什么时候该调用这个技能的依据类似函数签名里的 docstring。输入参数 Schema定义这个技能需要哪些参数、每个参数的类型和约束。执行逻辑真正干活的代码可以是搜索、文件读写、调用内部 API、执行代码等。返回结果模板以结构化格式返回方便模型理解并进入下一步决策。这四部分缺一不可。很多初学者只写执行逻辑不写描述结果模型在关键时刻根本不知道有这号技能可用只写参数不写返回模板模型拿到结果后又得靠猜来继续体感非常差。Lab 现场统计的数据表明技能描述写得好不好直接决定 Agent 在复杂任务中能否选对动作——选对率能从五成提高到八成以上。1.3 为什么说技能库才是 Agent 项目的真正护城河项目做久了你会意识到Model 本身是标准化商品今天能用 A 模型明天就能换 B 模型但技能库是跟着你的业务场景长出来的。换模型不会让这些技能失效反而因为技能标准化迁移成本极低。我们的 agent-skills 项目本质上是在构建一个与业务解耦、可无限复用的技能仓库。每新增一个业务需求先看技能库里有没有可复用的原子技能有就直接组合没有才开发新技能开发完沉淀回库里。这样的好处非常明显项目中期开始Agent 的新功能开发速度会明显加快因为大部分底层能力已经有了剩下的只是新组合。2. 架构设计先把技能从 Agent 主流程里拆干净2.1 我采用的总体架构技能注册表 调度器 执行器直接上架构这是我跑过几版之后收敛出来的方案简单但稳定。架构一共分三层技能注册表Skill Registry负责维护所有技能的定义、参数 Schema、版本号和启用状态。相当于一个字典让调度器能快速检索到某项技能是否存在、如何调用。用 YAML 或 JSON 描述技能元信息代码动态加载。调度器Scheduler这是中枢。接收用户的自然语言任务把它拆解成一系列子任务再为每个子任务匹配合适的技能编排执行顺序。注意调度器本身并不直接调用技能它只负责生成调用计划。执行器Executor真正调用技能的模块。它从注册表读取技能定义校验参数执行代码把结果包装成标准格式返回给模型。为什么要拆三层核心原因是决策和执行必须分离。模型适合做决策但不适合直接控制执行细节执行器负责稳定、可控的调用动作两者分离后任何一层的修改都不会影响另一层。比如你换了一个更强的新模型只需要改调度器里的 prompt 模板技能定义和执行逻辑一行都不用动。2.2 技能注册表设计用 YAML 描述每个技能的能力边界很多项目死在技能多了以后没人说得清每个技能是干嘛的。所以 agent-skills 在注册表设计上花了很大力气每个技能都有一段独立、完整的元信息描述统一用 YAML 格式维护。一个典型的技能注册条目长这样skill: name: web_search version: 1.2.0 description: 在互联网上执行关键词搜索返回网页标题、摘要和链接列表。 当用户询问实时信息、最新事件或不确定的事实时优先使用该技能。 parameters: - name: query type: string required: true description: 搜索关键词建议控制在20个中文字符以内。 - name: max_results type: integer required: false default: 5 description: 返回的搜索结果数量默认5条。 returns: type: list item_type: object fields: - name: title type: string - name: snippet type: string - name: url type: string enabled: true这段描述里最有价值的部分是description和参数约束。调度器拿到任务后会基于这些描述决定调不调用、怎么调用。如果描述含糊Agent 就很容易犹豫或误用把边界写清楚后调度准确率会直线上升。实践里我建议每条技能描述都要包含三句话一是技能能干什么二是典型的调用时机三是不能干什么。不能干什么尤其重要它能有效防止模型在边缘场景下乱用技能。比如一个查询天气的技能描述里要明确仅用于当前实时天气不用于历史气候分析Agent 就不会在遇到某地去年降雨量问题时强行调用它。2.3 为什么我用技能而不是工具来命名整套体系命名这件事看着小实际影响团队协作。刚开始项目组里有人叫函数有人叫工具有人叫插件每周评审会都在争论同一个东西。后来统一叫技能并且定义了一个核心区别工具是被动等待调用技能是主动提供上下文感知的行为单元。工具更像编程里的函数定义好入参出参就完事技能则多了这个技能在什么场景下该被想起这层语义。比如sql_query是一个工具但报表数据查询技能就是一个技能——它背后包含了对数据源连接、SQL 安全校验、结果长度限制、异常处理链路的完整封装。Agent 调用它时不需要也不应该知道这些细节。这个叫法上的差异最终影响了注册表描述怎么写、调度器怎么判断、执行器怎么兜底。整个体系顺着技能这个心智模型走越做越顺。3. 实操拆解我实现的几个典型技能及关键逻辑3.1 搜索技能让 Agent 真正知道实时信息搜索技能是 agent-skills 里最早实现、也最常用的一批。它的逻辑不复杂但细节非常值得抠。执行逻辑大致分四步接收query参数做基础清理去掉非法字符、控制长度。调用搜索 API拿到原始结果列表。对结果做过滤和去重去掉明显无关的广告或低质页面。把结果截断到max_results条并格式化输出。关键点在第三和第四步。搜索 API 返回的数据非常噪直接丢给模型会严重干扰判断。我做过实验不经过滤的搜索结果让 Agent 的最终回答准确率下降了近两成。所以我在技能内部加了简单的质量分过滤——根据域名权重、标题与查询的相关性、更新时间做加权排序把最靠前的几条给模型。这里有一个值得大多数开发者迁移的经验技能内部一定要做结果整形不要让生数据直接裸露给模型。模型对数据的消化能力有限喂得越干净输出越可控。3.2 代码执行技能安全边界与沙箱隔离让 Agent 写代码已经不稀奇但让它直接在你的服务器上执行代码完全是另一件事。agent-skills 里的代码执行技能我一开始只在本地跑后来发现风险太大改成了 Docker 沙箱隔离。核心设计技能接收一段 Python 代码字符串作为输入。在独立的 Docker 容器里执行容器内没有外网权限、只有最小化的标准库和基础第三方库。执行有超时控制默认 10 秒超时强制终止。输出被限定为标准输出和返回值超大输出直接截断。这个技能的价值在于把模型生成代码和代码运行之间的信任边界划清了。你可以放手让 Agent 写一段数据处理的 Python 代码让它在沙箱里跑再把结果拿回来继续推理——一切都在可控范围内。实际测试中模型会经常犯写错文件路径死循环用了不存在的库这类低级错误。沙箱技能因为能反复试错且不会有真实副作用反而让 Agent 的自我纠错能力大幅提升。很多任务它能自己迭代几个版本最终给出能运行的代码这个体验是纯 prompt 方案完全做不到的。3.3 文件读写技能让 Agent 能落地交付物如果 Agent 只能返回文字那它只是一个高级聊天机器人。要让 Agent 真正完成工作流它必须能读写文件。agent-skills 里的文件读写技能设计原则很简单文件路径必须白名单化。技能定义里root_dir参数被固定为一个目录任何文件操作都被限制在这个目录内防止 Agent 通过路径穿越等手段越权。同时写入操作自动生成目录结构避免因为目标目录不存在而失败。这里有个实测教训如果允许 Agent 任意指定路径它的行为会变得不可预测比如把中间文件写到临时目录、把输出文件覆盖到来源文件上。加白名单之后这些问题基本消失了——Agent 只能控制文件内容控制不了物理位置混乱度大幅下降。文件读写技能与代码执行技能组合起来之后让 Agent 自己写脚本、自己保存结果就变成了一条完整链路。我的周报项目最终形态就是Agent 搜索数据 → 用代码做聚合 → 生成 Markdown 文件 → 写入指定目录全自动跑完我只需要事后打开文件确认。4. 让 Agent 学会使用技能编排层的核心策略4.1 从 ReAct 到 Skills-based 编排我经历了什么做 Agent 的人大概率听过 ReAct 模式——交替执行Reasoning推理和Acting行动模型先想一步再动一步循环往复。这套模式在简单任务上非常好用但一旦技能数量多了问题就来了模型会在推理阶段反复纠结该用哪个技能导致 token 消耗巨大、响应延迟变长。我的做法是把 ReAct 从每一轮都全量决策改成预规划 动态修正双层结构预规划阶段调度器先把用户任务拆解成多个子任务每个子任务映射到一个或多个候选技能生成一个初步执行计划。动态修正阶段执行时如果某个技能返回异常或结果不符合预期调度器重新规划后续步骤可选地调用其他技能补救。这有点像一个经验丰富的员工拿到任务后先列待办清单而不是接到一条信息就立刻跑去找人。基于预规划的编排让整体执行更连贯、可解释后续排查问题也有清晰的日志链路可追溯。4.2 技能选择与排序把决策成本压缩到最低当技能库超过二十个时模型每次做技能选择都要面对巨大的决策空间。这里我踩过一个大坑把全部技能描述一次性塞进 prompt结果模型频繁选择错误——不是技能缺失而是选项过载。优化方案是稀疏技能注入。调度器先基于用户任务的语义做一次粗筛选只把最相关的 5~8 个技能描述注入模型上下文其余技能全部隐藏。粗筛选本身的准确率不需要太高因为最终决策权仍在模型手里但筛掉明显无关的选项后模型的选择准确率和响应速度都有明显提升。我统计过一组效果对比全量注入时技能选中准确率约 62%稀疏注入后提升到 84%平均响应时间缩短了约 40%。原因是模型的注意力是稀缺资源少而精的选择空间能让它把推理集中在真正重要的决策上。4.3 动态技能注入不同任务只看到不同的技能菜单顺着稀疏注入的思路继续深挖我又做了一个动态技能菜单。核心逻辑是技能注册表里维护每项技能适用的任务类型标签调度器根据当前任务的意图分类动态组装出当前会话可用的技能列表。比如用户的问题是帮我看看今天的服务器日志有没有报错调度器会认定意图属于运维诊断注入的技能菜单就只包含日志读取、代码执行、关键词搜索这几项用户改为问给我写一份季度总结报告菜单就会切换到文件读写、搜索、数据聚合技能上。这个机制看似简单但对 Agent 的行为影响极大。技能可见范围收窄后模型几乎不会再去尝试那些与任务无关的技能整体行为更加专注。菜单外技能不是不存在而是在当前任务里被主动隐藏避免干扰决策。5. 技能测试与调优我踩过的坑和建立的质量闭环5.1 技能的自测别等 Agent 跑挂了才回头补测试很多人写完技能就直接接入 Agent等任务跑挂了才去查是哪一步出错。这种模式在技能少的时候还能忍技能多了以后定位问题会非常痛苦。agent-skills 里我坚持每个技能都配有独立的自测用例测试内容分三层正常路径给合法参数验证返回结果的结构和内容。边界路径空参数、超长参数、异常格式验证技能是否优雅失败。风险路径恶意路径、超时、外部依赖不可用验证技能是否兜底。自测不是走形式它能帮你提前发现大量看似没问题、实际一用就炸的细节。我印象最深的是一个文件读取技能正常路径测试全过但边界测试发现当文件不存在时错误信息是英文 raw message模型拿到后一头雾水。后来我在技能返回里加了可读性错误文案和备选建议这类问题才彻底解决。5.2 回归测试技能升级时防意外惊喜技能库一旦跑起来迭代是常态。但技能的每次改动都可能影响 Agent 的既有行为——这里说的回归不是指代码层面的 bug而是指同一个任务在技能升级前后的行为差异。我建了一个简单的回归用例集包含二十多个典型任务每次技能库有变更时自动跑一遍这些任务记录 Agent 的最终输出和关键中间步骤然后做人工审查。这个过程不需要完全自动化判定只需能快速暴露改动影响了哪些行为就够。这套回归机制帮我发现过好几次问题。比如升级搜索技能时把过滤逻辑调严了结果搜索召回率下降Agent 回答查不到信息的频率变高如果没跑回归测试这种问题在真实业务里可能要几天后才能暴露出来。5.3 链式调用的稳定性中间失败怎么办真实任务中Agent 很少只调一个技能通常是一串技能串行或并行执行。链式调用最大的风险是中间环节失败导致全链路瘫痪。我的处理策略是分级兜底第一级技能内部兜底。每个技能尽量返回降级但不报错的结果。比如搜索技能如果主搜源超时自动切备用搜索源文件写入失败时尝试写到临时目录并返回警告信息而不是直接抛异常。第二级调度器重试。当技能返回异常时调度器先判断异常类型。如果是临时性故障超时、限流自动重试一次如果是参数错误则尝试基于模型推理修正参数后再试一次。第三级路径替换。如果某个技能连续失败调度器尝试用另一个等价技能替代。比如数据库查询技能失败时可以换文件读取技能去读数据库导出文件虽然时效性差一点但任务能继续往下走。这套三级兜底下来链式任务的整体成功率我从最初的 70% 拉到了 92% 左右。中间失败不再是任务终止的同义词Agent 更接近一个能灵活应变的操作员。6. 一些实测数据与体会技能质量决定 Agent 体验上下限6.1 用同一组任务横向对比了三个配置为了更直观地说明技能的重要性我曾在同一组 50 个任务上对比过三种配置配置技能数量任务完成率平均耗时幻觉率纯 prompt 无技能038%12.4s41%基础技能10个1072%16.8s12%完整技能库23个2391%19.6s4%纯 prompt 配置完成率很低而且幻觉率高——因为它只是看起来在工作实际交付基本靠编。加基础技能后完成率大幅提升幻觉率也降了一大截完整技能库进一步提升代价是平均耗时有所增加因为更多技能意味着有机会做更多真实动作这些动作天然需要时间。这个数据基本验证了我的核心判断Agent 项目的重心不在模型选型、不在 prompt 设计而在技能库的设计、实现与维护上。技能库越完善Agent 的真实可用性越高技能库稀烂再好的模型也救不回来。6.2 交互设计上的一个心得让 Agent 学会说不知道在 agent-skills 项目里我刻意在技能行为中加了能力边界感知当模型判断当前任务没有合适技能时不允许它硬答必须明确说当前能力不足。这个设计一开始觉得是让步实际跑下来反而大大提升了整体体验。原因是用户能接受做不到但不能接受瞎做。当 Agent 明确说需要额外的数据源或权限时用户反而更信任它的其他回答。反过来如果 Agent 总是绕开技能边界强行编答案信任崩塌后即使某些真实能力也会被用户怀疑。6.3 后续我计划继续做的事情当前版本依赖外部大模型 API 的稳定服务后续打算做一次多模型兼容适配让技能库能无缝对接不同模型接入商。然后想重点增强技能间的并行执行能力目前链式执行整体是串行的部分独立子任务其实可以并行跑这能进一步压缩整体耗时。外接经验证明并行化改造预计能把任务耗时的 20%~30% 省下来。不过这些都是锦上添花的部分。回归到最初的问题——你的 Agent 到底会干什么只要技能库这一层做得够扎实Agent 的上限就能真正被顶起来。而如果技能层还在裸奔那任何模型升级、prompt 技巧都只是在给一个没有手的人换更聪明的大脑罢了。