1. 从“调工具”到“具备技能”Agent 可靠性的关键转折我最早做 Agent 项目的时候踩过一个特别典型的坑模型明明调用了正确的工具参数也没传错但结果就是不对。有一次我让 Agent 去统计某个目录下所有的 Python 文件数量它调了list_files然后自己心算了一个答案回来——错的。问题出在哪不是模型不行也不是工具不行而是我给了它一堆“工具”却没有给它“技能”。这个区别非常关键。工具是死的它只提供一个动作入口比如“读取文件”“发送请求”“执行命令”。而技能是活的它包含完整的执行路径、边界条件、预期输出甚至包含这个动作在什么场景下该用、什么场景下不该用。agent-skills 做的事情就是把后者规范化、结构化、系统化让 Agent 真正“会做事”而不是“能调接口”。我第一次意识到需要这么一套东西是在一个自动化数据采集的项目里。Agent 需要自己去查资料、解析网页、整理成结构化数据。如果只是把 requests、BeautifulSoup 这类工具丢给它模型每次调用都要重新“现想”怎么用不仅 token 消耗大而且很多边缘情况根本处理不好。后来我把整个流程腌制成一个技能它有明确的输入 schema、标准化的执行步骤、预置的错误处理出口Agent 每次只需要传三个参数正确率直线上升从原来的六七成直接干到九成以上。如果有人问 agent-skills 到底解决什么问题我的回答很简单它解决的是 Agent 的“无头苍蝇”问题。没有技能库的 Agent每次任务都像第一次进厨房的新手连刀怎么握都要想半天有了技能库它就是一个熟手厨师看到食材就知道该走哪个流程。这篇文章适合正在做 Agent 应用、或者准备把 LLM 接入实际业务流程的工程师我会把整套东西怎么设计、怎么写、怎么用、怎么踩坑从头到尾说一遍。2. 技能与工具的本质区别为什么 Agent 会“选中”但“做错”要理解 agent-skills 的价值得先理解一个核心问题为什么现在的模型调用工具的时候经常会出现“动作对了但结果错了”的情况。这不是偶然失误而是架构层面的缺陷。2.1 工具描述是“名词解释”技能描述是“使用手册”大部分工具调用框架里工具通过一个 JSON Schema 来描述自身——名字、功能描述、参数类型、必填项。模型读出这段描述决定要不要调用。这个机制的问题在于给模型的指令颗粒度太粗。拿“发送 HTTP 请求”这个工具来举例。如果工具描述只写“向指定 URL 发送请求支持 GET/POST/PUT/DELETE”模型确实知道它能发请求但不知道什么时候该用 GET、请求超时该等多久、返回 403 是重试还是放弃、遇到重定向要不要跟进。这些都是实际操作中必然遇到的分支判断而模型每次调用都要临时推理一遍。技能不一样技能把这段操作里 80% 的判断逻辑预先封装好了。Agent 只需要表达意图技能负责执行细节。判断什么时候该用这个技能、参数怎么填、返回结果怎么解释都是技能设计者事先想清楚的事情。2.2 把“尝试”的负担从模型身上移走模型调用工具的另一个大问题是“反复试错”。第一次调用失败它会换一种参数重新尝试再失败再尝试……在简单场景下这个还能容忍但在真实业务里试错成本很高。一个请求重试 5 次每次都是完整的一轮 LLM 推理这笔 token 开销和延迟是很多项目无法接受的。技能体系解决这个问题的方式是把容错逻辑固化成代码。请求失败了一次技能内部自动换重试策略页面结构变了技能内部自动走备用解析方案。模型根本不需要“看到”这个失败过程因为它只对接技能的输出。2.3 可测试性带来的稳定保障工具调用的行为像黑盒模型这次是以一种方式用工具下次可能是另一种方式。你没法为“模型随机发挥”写测试用例。技能就不一样既然技能是固化的代码路径那就可以做单元测试、集成测试、回归测试。组件有一个很直白的矛盾模型技术栈在飞速迭代但你的业务逻辑应该稳定。技能这个设计天然地画了一条分界线——模型负责理解和决策技能负责执行和交付。决策可以换模型执行不能随便换因为执行是要保证稳定的。这条分界线划清楚之后Agent 项目的工程质量才真正有保障。3. 技能的边界与架构设计原子性拆分、元数据、依赖管理设计一套 agent-skills最大的难点不是写技能代码本身而是怎么把大任务拆成一个一个边界清晰的原子技能。拆分得不好技能之间互相重叠、互相依赖Agent 反而会被技能列表搞晕。3.1 原子性一个技能只做一件事我见过有人把“数据分析”做成一个技能里面有 20 个参数涵盖了从读文件到画图表的全部功能。这种“全能技能”实际上是变回了一堆工具的大杂烩模型使用起来依然迷茫。原子技能的正确拆分标准很简单一个技能应该对应一个不可再分的业务操作。可以按下面四个特征来评估一个技能是否原子输入参数少于 8 个超过 8 个说明职责不单一只有一个主要返回结果不会一次返回 5 种不同类型的数据有明确的失败模式和重试策略失败不会连带其他技能挂掉技能的描述能在 50 字以内说清楚“什么场景下用它”我在实际项目中会把技能分成三类基础技能、组合技能、业务技能。基础技能是“打开文件”“发起请求”这种最底层操作组合技能是把几个基础技能串成一个流程业务技能则是绑定具体业务逻辑的高级操作。层级清晰之后Agent 的选择空间并不乱日常任务用业务技能有特殊需求时可以自主组合低层技能。3.2 元数据设计让模型“一看就懂”的功夫技能描述是模型选择技能时的唯一天线描述写得差再实现得好的技能也是摆设。我的经验是技能描述不能只写“这个技能做什么”还必须写“什么时候用它、什么时候别用它、跟相邻技能有什么区别”。一个成熟的技能描述模板是这样技能名称web_page_extractor 技能用途抓取指定 URL 的正文内容过滤导航、广告等无关信息 适用场景需要获取网页正文、文章内容或页面主要信息时 不适用场景需要完整的原始 HTML、需要执行页面 JavaScript 后才渲染的页面 相邻区分与 url_downloader 的区别是本技能返回清洗后的文本内容url_downloader 返回原始文件尤其是“相邻区分”这一项很多技能库都会忽略。但模型最容易困惑的恰恰是两个相似技能该选哪个。你把这层窗户纸捅破了模型就不会犹豫。3.3 依赖关系的显式声明技能之间天然存在依赖关系高级技能往往要调用低级技能。这个依赖关系必须显式声明否则 Agent 在使用技能时会出现两个问题一是模型不知道某个技能需要前置环境直接用导致失败二是组合调用时层级混乱模型既要管流程又要管细节负担很大。我在每个技能的元数据里都加了requires字段声明它依赖哪些前置技能或环境条件。如果条件不满足Agent 应该先去执行前置技能或者直接提示用户环境未就绪而不是徒劳地调用。4. 构建一套 agent-skills 的实操记录从需求分析到测试完成光说不练没意义这一节分享一下我在一个真实项目里构建技能库的完整过程。项目背景是开发一个内部知识库问答机器人Agent 需要检索内部文档、提取关键信息、生成答案。4.1 需求盘点画出“业务流程脑图”第一步不是写代码而是把 Agent 要干的活完整列出来然后逐层拆解。拿知识库问答机器人来说拆解之后大概是接收用户的自然语言问题识别问题的类型事实型、流程型、操作型根据类型选择检索策略全文检索、标题检索、语义检索从检索结果中提取相关段落将段落组织为回答草稿对回答进行格式化和引用标注这六步里哪些是模型天然擅长的哪些是必须固化的类型识别和回答组织可以交给模型但检索策略、段落提取这些环节有明确的规则可循适合做成技能。4.2 技能清单与优先级排优先级有个原则别追求一次性把技能库做全先把出现频率最高、失败代价最大的技能做出来跑通后再扩展。第一版技能清单我定了五个优先级最高的优先级技能名称功能描述配套工具P0doc_retriever根据关键词/语义检索内部文档库向量数据库、ES 全文索引P0content_extractor从检索到的文档中提取指定主题的关键段落PDF 解析器、HTML 解析器P1citation_formatter为回答内容自动生成引用标注自研格式化函数P1query_expander对用户自然语言问题做同义扩展LLM 二次调用P2doc_summarizer对长文档生成层级摘要LLM 调用 分段策略P0 的技能必须在第一天就稳定因为它们直接影响核心流程。P1 是体验增强P2 放到后期迭代。4.3 技能实现的结构规范每个技能我都要求统一结构方便后续维护和模型理解。一个完整的技能定义文件长这样{ name: doc_retriever, description: 在内部文档库中检索与查询最相关的文档片段支持语义检索与关键词检索混合模式, when_to_use: 用户提问涉及内部规范、流程文件、产品文档等场景, when_not_to_use: 用户询问的是常识性问题或代码调试问题, similar_skills: [web_searcher, codebase_searcher], input_schema: { type: object, properties: { query: {type: string, description: 检索查询内容}, top_k: {type: integer, description: 返回文档片段数量, default: 5}, search_mode: {type: string, enum: [hybrid, semantic, keyword], default: hybrid} }, required: [query] }, output_schema: { type: object, properties: { fragments: {type: array, items: {type: object}}, total_found: {type: integer} } }, execution_plan: [ 1. 解析查询内容提取核心关键词, 2. 使用语义检索获取向量相似度最高的候选集, 3. 使用关键词检索获取命中候选集, 4. 合并候选集并去重按综合相关性排序, 5. 截断超过窗口长度的内容返回前 top_k 个结果 ], error_handling: { retry_strategy: 首次查询失败后降低语义检索阈值重试一次, fallback: 检索结果为空时返回提示信息并建议用户更换关键词 }, requires: [vector_db_client, es_client] }这个结构其实就是一个“技能的技能说明”——不只是给代码调用方看的更是给 Agent 的模型看的。执行计划这一项很多人会忽略觉得模型反正是要自己推理的你写不写它都会做。其实不是模型在读取技能元数据时如果你把执行步骤写清楚了它的决策负担会大幅降低同时也降低了它自由发挥跑偏的概率。4.4 技能测试比工具调用多一层验证技能测试不能只看“调通了没有”还要看“在不同输入下表现是否稳定”。我会为每个技能编写三组测试用例正常场景、边界场景、异常场景。正常场景输入标准参数验证返回结果符合预期。边界场景比如空字符串查询、超长文本、不存在的文件路径。异常场景比如下游服务超时、返回数据格式异常。这三组用例跑完之后再加一组和模型搭配的端到端测试。因为技能最终是给模型用的模型对技能的描述理解得对不对、参数填得准不准都要通过实测来验证。端到端测试里经常发现的问题是模型的参数格式与技能预期的 schema 对不上。这种问题只有实际跑一遍才能暴露出来静态检查根本找不到。5. 将技能库接入 Agent 主循环路由、选择与错误传播技能库建好只是第一步真正决定成败的是怎么把它接入 Agent 的主循环。这一节分享我在接入过程中的踩坑和经验。5.1 挂载方式的选择接入技能库有三种常见方式方式一把技能当作普通工具挂载所有技能平铺在工具列表里。简单直接但技能数量一多模型选择时注意力会被稀释。方式二引入一个“技能路由器”模型先看到分类列表选完类目再选具体技能。路径变长但是每层可选项少准确率会提升。方式三动态挂载根据任务上下文提前用检索方式召回相关的 3~5 个技能只把这几个技能暴露给模型。这个方式我目前最推荐。方式三本质上是用一个技能检索器来决定本次对话给模型看哪些技能。用户输入问题后系统先用 embedding 做一次相似度检索把候选技能列表缩小到 5 个以内再连同用户的原始问题一起传给模型让它在这些技能中做选择。路由的粒度可以调节技能少的项目用方式一就行超出 20 个技能就开始考虑方式三。这个临界值没有严格标准但 20 个之后模型在长列表里选对技能的概率会显著下降。5.2 技能选择的“拒答路径”技能选择问题有一个经常被忽略的细节如果在路由阶段检索不到相关技能Agent 应该怎么办很多实现会强迫模型随便选一个结果就是答非所问。我的做法是引入一个 reject 出口。技能候选列表为空或者相关性分数低于阈值时Agent 会直接告知用户“当前能力范围内无法处理该请求”并附带建议。这个设计一开始做会觉得是在“浪费机会”但实际使用中避免了很多不该发生的幻觉输出。5.3 错误传播的边界技能内部处理了大部分异常但免不了有异常需要向上层传播。传播时需要记住一个原则传给模型的是结构化错误码而不是裸异常信息。裸异常信息经常包含堆栈追踪、内部路径、SQL 语句等细节模型翻译成用户能看懂的话时会添油加醋。结构化错误码就好得多比如ERROR_404_DOC_NOT_FOUND对应“未找到请求的文档”模型只需要把这个原因翻译给用户即可不需要了解底层的技术细节。6. 技能召回与存储优化技能库大了之后怎么办技能数量从十几个涨到七八十个的时候一个新的问题浮出水面Agent 怎么在这么多技能里找到正确的那一个这就像图书馆里的书多了之后怎么快速找到需要的那本一样需要索引和分类体系。6.1 技能描述的检索友好化技能描述不仅影响模型阅读还影响检索。因为技能选择的核心机制是 embedding 相似度匹配描述的措辞直接决定了匹配效果。一个技巧是给技能配置多条“唤起语”。例如一个负责 PDF 转文本的技能描述里除了写“PDF 解析”还可以写上“读取 PDF 文件”“提取 PDF 内容”“把 PDF 变成文本”这些用户可能使用的表述。模型不会在乎你写得啰嗦它只在乎能不能搜得到。6.2 聚类与层级管理技能数量多了以后平铺的效果一定不好。我开始按业务域对技能做聚类比如“文档处理域”“网络请求域”“数据处理域”“系统交互域”每个域有一个域描述。用户在提问时系统先匹配域再在域内匹配具体技能。这个两段式匹配跟前面说的方式二类似但在技能量大时是必需品。每个域的技术支持也要维护一个使用统计某个域的技能完用率长期低于阈值就要反思是技能本身设计问题还是描述问题是否应该下线或合并。6.3 反馈闭环让技能库越用越顺技能库不是上线之后就冻结的它需要根据 Agent 的表现持续迭代。我在项目中建立了一个最简单有效的反馈机制给每次技能调用附加两个指标——成功还是失败、模型是否需要矫正后手动重试。周会后统计一次发现某类技能失败率偏高就优先排查。比如有一次我发现content_extractor的失败率一周内从 5% 涨到 25%排查后发现是上游文档系统的页面结构改了。这类问题如果没反馈闭环可能要等到用户投诉才知道。技能库的优化方向很多时候不是加新技能而是调整已有技能的边界和容错。特别是当你发现模型反复选择一个技能但执行结果不理想时问题大概率不在模型而在技能本身的设计。7. 实测中的意外情况与我的最终建议项目上线之后我记录了三个月里踩过的所有坑再回头看最值得提醒后来者的其实不是技术上的难题而是一些很容易被低估的细节。7.1 两个最容易被忽略的坑第一个坑是技能描述里的“不适用场景”写得太含糊或者漏写。模型把技能用错场景的情况一半以上就是因为描述里没写清楚边界。写“不适用场景”不是走过场它切实地帮模型节省了在错误方向上试探的时间。第二个坑是技能的执行计划写得过于笼统。执行计划千万别只写“调用外部 API 获取数据”这种废话要把关键决策点写清楚比如超时时间、重试策略、什么情况下中断执行。模型在调用技能时确实会读取这段信息它知道得越具体自主发挥的余地就越小稳定性就越高。7.2 给小团队的建议如果你的团队只有一两个人不用一口气建一个几十技能的库。先认真梳理核心业务链路挑两三个最高频、最有重复价值的技能建好跑通之后再慢慢扩展。技能库是活的东西随着业务和模型能力的演进它需要不断维护和重构。最后一点千万别把技能做成“一次性脚手架”。技能和模型的边界要划清楚模型是会变的今天用 GPT-4明天可能换国产模型技能体系如果绑定在特定模型的能力假设上换模型时就要全部重写。做技能的时候一定要默认模型是个“笨但听话的执行者”把逻辑都放在技能里而不是期待模型能自己兜底。
企业数字化 ERP 产品动态
相关推荐
Vue 插件推荐:用 TaoToken 统一 Key 打通 AI 辅助开发链路 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 9:59:28
客户端接入实战:在 LangChain 中集成 MCP 工具调用与 TaoToken 统一 Key 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 9:59:22
DeepSeek Harness 安装与初体验:用 TaoToken 统一 Key 打通 Node 工作区 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 9:59:22
AI自动写代码:GitHub Copilot插件在Idea的安装和使用教程(TaoToken统一Key接入版) /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 10:27:50
【数据处理】UltraEdit处理超大文件的扩容方法:用TaoToken统一Key打通AI辅助配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 10:27:44
Suricata入侵检测毕设全解析:从架构原理到iptables联动封禁 简介:网络入侵检测系统(IDS)是安全防御的基础组件,其核心价值不止于被动告警,更在于形成从检测到响应的闭环。Suricata作为高性能IDS引擎,通过多线程抓包、协议解析与规则匹配,将原始流量转化为… · 2026/9/25 10:27:37
Log4j JSON日志反序列化漏洞CVE-2026-49844深度解析 1. 这不是又一个“Log4j漏洞”,而是日志设施底层逻辑的崩塌点最近在几个金融和政务系统的安全巡检群里,突然炸出一条消息:“线上审计服务凌晨告警,JSON日志里混进了JNDI lookup字符串,触发了WAF拦截规则。”我第一反应… · 2026/9/25 10:27:37
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37