
1. 项目概述与核心思路1.1 从工具调用到技能体系agent 开发到底缺什么这两年做大模型应用尤其是搞 Agent智能体方向的朋友应该都有同感模型本身的智商天花板已经不明显了真正卡住项目进度的往往是模型能不能稳定地调用外部能力完成一整条任务链路。换句话说模型再聪明没有一套可靠的执行工具它也就是个会聊天但干不了活的嘴强王者。agent-skills这个词指的就是给智能体配备的一组可复用、可编排、可管理的技能集合。它解决的核心问题有三个第一把模型从只会生成文本变成能操作真实系统第二把零散的 API 调用整理成有语义边界的原子能力第三让这些能力能够被多个 Agent 场景复用而不是每个项目从零造轮子。我最初接触这个概念时还停留在给模型接几个函数的原始阶段后来在实际项目里被反复教育工具和技能是两回事。工具是单个函数、单个接口技能则是围绕一个业务目标封装好的完整能力单元。举一个直观的例子单个搜索网页API 调用是工具但调研一个竞品并输出结构化报告就是技能因为后者需要规划搜索关键词、多次检索、筛选有效信息、按模板整理输出。这个封装层才是 agent-skills 真正有价值的地方。1.2 谁需要关注这套东西如果你是下面几类人这篇文章应该能帮到你做大模型应用开发正在纠结怎么让 Agent 稳定调用工具的工程师。负责企业内部 AI 中台想把各业务线的 Agent 能力统一管理起来的技术负责人。做 RAG、自动化工作流、数字员工方向的开发者需要一套可复用的技能注册与调度机制。刚入门 Agent 开发被 function calling、prompt 工程、工具链路搞得一头雾水的新手。这篇文章不会停留在概念层面我会把 agent-skills 的设计思路、核心实现环节、生产环境落地的问题排查都拆开讲尽量把那些文档里不会写的实操细节一并补齐。整个项目我是在一个真实的内部知识库问答 自动化运维场景里做落地的后面所有代码和踩坑记录都来自这个项目可参考性比较强。2. 技能体系设计的关键决策2.1 为什么不能把技能做成一堆函数列表很多团队第一次做 Agent 工具化时最自然的做法是把所有需要的能力都定义成 function一股脑塞进 system prompt 或 tools 参数里。我见过有项目一次性塞了 40 多个 function 定义结果模型在每次对话里都要对所有工具做一轮评估推理时间明显变长而且工具一多是会出现选择困难的——明明该用 A 工具模型偏偏调了语义相近的 B 工具定位问题会花掉大量时间。agent-skills 的第一个设计原则是分层。技能注册中心维护一个全局技能清单每个技能包含描述、参数 schema、调用入口、依赖条件和适用场景。但在实际请求里我们会先做一个技能路由skill router根据用户的意图和上下文从全局清单里召回一小批相关技能再交给模型做最终选择。打个比方一个大型餐厅有 200 道菜你不可能把整本菜单都摆在客人面前让他选那样客人会懵。合理做法是服务员先根据客人的口味偏好推荐 8~10 道菜客人再从中选择。技能路由就是那个服务员。我在项目里实测30 个技能的环境下加了路由层之后工具选择准确率从 78% 提升到了 94%效果非常显著。第二个原则是技能内部可以编排子任务。一个技能不一定直接对应一个 API 调用它可能是多个子步骤的组合。比如生成数据报表技能内部包含查询数据库、处理缺失值、生成图表、输出 Markdown 表格四个子任务。对外暴露的时候它是一个整体技能但内部实现是一个有向调用链。这种封装方式让上层业务逻辑保持干净也让每个技能可以被单独测试和优化。2.2 技能描述的质量决定成败在 agent-skills 体系里最容易被低估的就是技能描述description的撰写质量。很多开发者把描述写得含糊比如查询用户信息模型根本不知道这个技能接收什么参数、在什么场景下调用、返回什么结构。于是模型要么不调用要么调用了却传错参。我给团队定的规矩是每个技能描述至少要包含四个维度——功能边界这个技能做什么、不做什么、适用场景什么情况下应该选择它、参数含义每个参数的业务含义和格式要求、返回说明调用后能拿到什么。这四个维度写清楚模型的调用准确率会大幅提升。这里还有一个容易被忽略的小技巧描述里要写明不应该在什么情况下使用。负例往往比正例更能帮助模型做排除。比如查询用户信息这个技能描述里加一句注意此技能仅用于查询单用户详情获取用户列表请使用 list_users 技能模型犯迷糊的概率就低得多。2.3 确定技术栈与运行时方案agent-skills 的底层依托什么运行时我试过两种路线路线 A基于大模型平台原生的 function calling如 OpenAI function call、通义千问的 tool call 等所有技能以 JSON Schema 方式注册模型自己决策调用哪个函数。实现快但调度逻辑被平台锁死复杂编排不方便。路线 B自建技能执行引擎技能注册到本地 registry 里由引擎负责意图解析、技能路由、参数校验、执行和结果回填。灵活性高但工程量大很多。我采用的是折中路线技能定义使用标准 JSON Schema保证可移植性技能路由和调度用自研的轻量引擎最终调用模型时只把当前会话相关的技能子集注入到 tools 参数里。这样既享受了平台 function calling 的稳定性又保留了自建体系的灵活性。如果你是在一个已有的大模型应用里做增量改造我建议也从这条折中路线起步不要一上来就全自研。先跑通最小闭环再逐步把技能执行从平台函数调用迁移到自建引擎风险会小很多。3. 核心细节解析与实操要点3.1 技能注册表的数据结构设计技能注册表是整个 agent-skills 体系的心脏。我的设计是每个技能对应一份结构化描述核心字段如下字段说明示例skill_id技能唯一标识query_user_detailname技能名称查询用户详情version技能版本号1.2.0description功能描述包含正例和负例查询指定用户的账户详情信息仅限单用户查询批量查询请用 list_usersparametersJSON Schema 参数定义{userId: {type: string, description: 用户ID}}required必填参数列表[userId]handler技能执行入口的引用skills/user_detail/handler.pytags技能标签[user, query, crm]timeout_ms技能执行超时上限5000dependencies依赖的其他技能或服务[auth_service]enabled是否启用true这里我想多说一下 version 字段。技能是会持续迭代的同一个 skill_id 在不同时间可能有不同版本。生产环境里已经在跑的会话可能还在用旧版技能新会话已经开始用新版如果版本管理做得不到位会出现同一个动作两种行为的情况。我的做法是技能变更必须升版本且每次变更都生成一条变更记录便于回溯。参数校验这块我踩过一个很深的坑早期没有在技能层做参数强校验完全依赖模型生成的参数。结果模型偶尔会把日期格式传成2024年1月1日这种自然语言格式导致后端解析直接报错。后来我在技能入口处增加了一层参数规范化逻辑先按 schema 做格式校验不符合的尝试自动转换转换不成功再请求模型补充或修正参数。这一步看起来不起眼但能把工具调用的整体成功率提升至少 10 个百分点。3.2 技能路由模块的实现思路技能路由模块承担从全局技能池里召回当前会话最相关技能的职责。我实现的第一版用的是简单的关键词匹配规则简单但召回效果一般例如用户说帮我看看这个用户最近有没有异常关键词匹配很难把用户和异常检测技能关联起来。第二版换成了 embedding 向量召回。做法是把每个技能的 description 离线向量化存到向量数据库里线上来了一条用户消息先把消息向量化然后做相似度检索取 top-N 个技能作为候选集。这个方案效果就好很多原因是 embedding 天然能捕捉语义相关性哪怕用户原话里没有技能名也能召回正确技能。在具体参数上我用的 embedding 模型是 text-embedding-v2 级别的通用模型向量维度 1024检索时采用余弦相似度。技能池 30 个技能时每个请求做一次检索的延迟在 30ms 左右可以忽略不计。候选集大小 N 我取 5~8太少了会漏太多了会增加模型的选择负担。需要提醒的是向量召回只是候选生成最终决定权还是要交给大模型。召回的目的是缩小范围不是替代模型判断。把语义接近但实际不适用的技能混进候选集没关系模型通常能根据技能的详细描述做正确排除。3.3 技能执行链与上下文设计单个技能执行是简单的真正的复杂度在于多个技能按顺序协作。比如用户问帮我查一下这个项目的整体健康度如果发现风险就通知相关负责人。这条指令至少涉及三个技能查项目状态、判断风险等级、查负责人联系方式、发通知。技能之间是有关联的后一个技能的入参依赖前一个技能的出参。我的做法是引入一个执行上下文缓冲池。每个 Agent 会话维护一个全局 JSON 对象多个技能执行过程中产生的关键输出都写入这个缓冲池。后续技能在生成参数时可以引用缓冲池里已有的值。相当于给技能体系加了一个工作台上一个技能放上去的工件下一个技能可以直接取用。这个设计在实践里最大的难点是确定什么信息值得写入缓冲池。写太多上下文会冗余模型容易受噪声干扰写太少后续技能拿不到必要参数。我最后定的标准是跨技能使用概率高、且获取成本高的信息才写入。比如查询到的用户ID这类主键信息要写一次性展示用的中间状态就不要写。上下文管理方面每个技能的调用记录我都会保留一份结构化日志包含入参、出参、耗时、状态。这个日志不仅是排障工具也是后续优化技能编排的原始数据来源。我在项目里会定期导出日志做分析看哪些技能被调用次数最多、哪些技能失败率最高用数据指导迭代方向。4. 实操过程与核心环节实现4.1 最小闭环从注册一个技能到跑通一次调用下面用一个最简单的查询天气技能来演示 agent-skills 的完整链路。这个例子虽然简单但每个环节都是通用的。第一步定义技能描述文件。我使用的技能定义格式是标准 JSON方便和各家平台工具对接{ skill_id: query_weather, name: 查询天气, version: 1.0.0, description: 根据城市名查询当前天气情况。适用于用户询问某地天气的场景。注意本技能仅支持国内主要城市如无法匹配城市名请返回错误。, tags: [weather, query], parameters: { type: object, properties: { city: { type: string, description: 城市名称如北京、上海、广州 } }, required: [city] }, handler: skills.weather.handler:run, timeout_ms: 3000 }第二步实现技能执行函数。这里我用 Python 示例实际项目中你可以换成任何语言# skills/weather/handler.py import requests def run(params: dict) - dict: city params[city] # 这里接入实际天气服务商API resp requests.get(https://api.example.com/weather, params{city: city}, timeout2) data resp.json() return { city: city, temperature: data[temp], condition: data[condition], humidity: data[humidity] }第三步注册并测试。技能引擎会自动读取技能定义把 handler 加载到执行环境中。我习惯在注册后立刻做一次单元测试直接构造参数调用 handler确认执行函数本身是通的。这一步能避免把技能定义错误和handler 逻辑错误混在一起排查。第四步将技能接入模型的 tools 参数。这里以 OpenAI 兼容接口为例import json with open(skill_definition.json) as f: skill_def json.load(f) tools [{ type: function, function: { name: skill_def[skill_id], description: skill_def[description], parameters: skill_def[parameters] } }] messages [{role: user, content: 北京今天天气怎么样}] resp client.chat.completions.create( modelqwen-plus, messagesmessages, toolstools, tool_choiceauto )模型返回的内容里如果包含 tool_calls引擎就提取技能名和参数执行 handler再把执行结果以 tool 消息回传给模型模型根据结果生成最终回答。这个闭环跑通之后后续扩展新技能就是重复这个流程工作量集中在技能实现本身框架部分基本不用动。4.2 技能编排实现一个多技能协作的复杂场景单技能跑通之后我们来看一个真实的复杂场景。在运维自动化项目里有一个高频需求是检查服务器异常并通知负责人。这个场景涉及三个技能get_server_status查服务器状态、check_anomaly判断是否有异常、notify_owner通知负责人。这三个技能的编排逻辑是先执行前两个技能如果 check_anomaly 返回有异常再执行 notify_owner。为了让模型能完成这个编排关键是在每个技能的 description 里写清楚触发条件。我实际使用的描述片段如下get_server_status 的描述中有该技能返回指定服务器的原始状态指标是检查服务器健康度的前提步骤通常与 check_anomaly 技能配合使用。check_anomaly 的描述中有该技能基于 get_server_status 返回的指标判断是否存在异常。只有已经获取到服务器状态指标时才能调用。如果用户直接询问服务器是否正常请先调用 get_server_status 获取指标。notify_owner 的描述中有该技能用于向服务器负责人发送异常通知仅在 check_anomaly 判定存在异常时必须调用正常情况下不要调用。大家可以看到我在描述里刻意写明技能之间的调用时机和依赖关系。这样做之后模型基本能按照预期顺序执行。实测下来一次标准的异常检查流程模型会连续调用三次工具总耗时约 8 秒其中大部分时间是三个 API 的实际执行耗时模型自身的工具决策时间占比很小。如果遇到更复杂的编排需求比如条件分支或循环我建议不要只靠模型自由发挥而是在技能引擎里引入工作流定义。也就是说把高层流程写死成 DAG技能是节点引擎负责按序执行和条件判断模型只在需要动态决策的地方介入。Agent 的自由度应该被约束在流程中的灵活节点里而不是让整个流程都在不确定性中游走。这是我在生产项目里最深的体会之一。4.3 技能执行引擎的并发与超时控制技能执行引擎上线后遇到的第一个性能问题是并发控制。早期的引擎对技能调用没有任何并发限制某个技能是慢 API多个会话同时执行时会把后端服务打挂。后来我引入了简单的信号量机制每个技能配置最大并发数超过阈值就排队等待。超时控制同样关键。每个技能定义里都有 timeout_ms 字段引擎在调用 handler 时会启动超时计时超时后直接判定失败并返回错误信息给模型。模型收到错误信息后可以选择换一种方式处理或者告知用户当前系统暂时不可用。这里有一个细节超时返回的错误文案会影响模型的后续行为。我曾经把错误文案写成技能执行失败模型会盲目重试浪费更多时间改成技能执行超时请改用备用方案或告知用户稍后重试之后模型的行为就从无脑重试变成了理性降级。还有一点值得注意技能执行的失败重试策略。我的做法是不做自动重试只在特定条件下重试一次。原因是大多数技能失败是参数或上游服务的稳定性问题自动重试的成功率并不高反而会增加延迟。唯一例外是偶发超时重试一次的成功率还不错。我后来实现了一个简单的策略如果错误码标记为可重试比如 5xx最多重试一次其他错误一律直接返回。4.4 技能效果评估与迭代闭环做 agent-skills光是能跑起来远远不够关键是持续优化模型选对技能、传对参数、产出正确结果的比例。我建立了一套离线评估集包含 200 条真实用户请求每条标注了期望调用的技能序列和期望的最终答案。每次技能体系有变更都会跑一遍评估集观察几个关键指标技能召回率正确技能是否出现在候选集里技能选择准确率模型是否选中期望技能参数正确率传给技能的参数值是否准确任务完成率最终结果是否满足用户意图这套评估机制帮我发现了很多隐蔽问题。举个例子有一次我们发现某个技能的参数正确率特别低排查了半天发现是技能描述里的参数格式写得太含糊模型总是把日期格式传错。修正描述之后参数正确率直接提升了 20 个百分点。没有评估集的迭代基本就是盲人摸象。我强烈建议大家从第一天就建立评估集。哪怕只有 50 条问题也比什么评估都没有强。迭代的方向感、优先级判断都依赖这套数据。5. 常见问题与排查技巧实录5.1 模型死活不调用技能怎么办这是 agent-skills 落地里最让人抓狂的问题——技能定义得清清楚楚但模型就是不用。我排查这类问题时按以下顺序逐步检查技能描述是否指向了用户真实意图有时模型不调用是因为 description 写得太接口化模型没意识到这个技能能解决用户的问题。建议把描述写成用户说 XX 场景时使用的形式。当前模型版本是否支持 function calling有些轻量级模型对工具调用的支持比较弱换一个工具能力强的模型往往立竿见影。是否同时在 tools 里塞了太多技能候选技能超过 15 个时模型的选择准确率会明显下降。优先做技能路由召回缩小候选集。模型是否需要示例引导在 system prompt 里补充少量用户问什么 → 调用什么技能的 few-shot 示例能有效提高调用率。5.2 技能被调用但参数总传错怎么办参数错误是高频问题尤其是多参数字段。我的经验是先从这几个角度找原因参数描述是否采用了业务语言比如字段名是 user_id描述里写用户唯一标识格式为 8 位数字模型传参时要容易得多。参数来源是否清晰如果参数需要从用户对话里提取明确的描述是从对话中提取城市名若未提及请询问用户能帮助模型判断是该提取还是该追问。是否存在同名歧义字段多个技能里相似的参数容易相互干扰可以把参数名设计得更具区分度比如 order_count 和 total_orders。我见过最典型的案例是一个技能期望日期格式为 YYYY-MM-DD而用户在对话里说的是星期六。模型拿不准时就会原样传星期六。后来我在参数的 description 里加了一句如果用户提供的日期是自然语言如明天、星期六请先换算成 YYYY-MM-DD 格式再传入问题就解决了。这也是我在前文提到过的参数规范化在描述层的配合手段。5.3 多技能协作时顺序混乱怎么处理模型在多技能场景下打乱执行顺序本质原因是技能间的依赖关系没有被显式表达。我的解决办法有三层第一层在技能描述里写清前置条件如必须先获取 A 才能调用本技能。第二层在引擎层面做依赖检查当模型选择了一个前置条件未满足的技能时引擎不是直接执行而是返回一个前置技能未执行的错误提示引导模型先执行前置技能。第三层在 prompt 里写明编排规则比如多技能场景下请按顺序执行前一个技能的输出是后一个技能参数的数据来源。这三层叠加的效果非常明显我项目里的多技能流程顺序正确率从 62% 提升到了 88%。特别是第二层引擎主动检查依赖本质上是把容错机制从靠模型自觉变成了靠系统兜底这是工程化落地的关键思路。5.4 技能结果回传后模型理解错乱有个奇怪的现象工具返回的结果明明很完整但模型在生成最终回答时出现幻觉编造一些工具没返回的数据。排查后发现问题出在工具结果的格式上。当工具返回的是 JSON 字符串时如果嵌套层级过深或者字段名没有语义模型的阅读理解容易出偏差。我的建议是工具返回给模型的结果要尽量扁平化、语义化。比如把 {data: {a: {b: 1}}} 拍平为 {用户数量: 1} 这种形式模型理解起来轻松得多。另外如果工具结果太长比如一份完整报表全部塞给模型既不经济也容易干扰判断。我会在技能层做一个结果摘要只把关键指标写入回传内容明细数据另外存库供必要时查询。这个做法在 token 成本和理解准确率上都有明显收益。5.5 技能运行时的安全与权限控制技能意味着模型可以操作真实系统安全边界必须提前设好。我在项目里主要做了几件事技能权限分级只读类技能查询、检索默认开放写入类技能发送通知、修改配置需要额外授权边车模型只有在会话中明确获得用户授权后才允许调用。敏感参数脱敏技能入参和出参中的手机号、邮箱等信息做脱敏处理避免模型在对话中复述敏感信息。操作审计所有技能调用记录全量入日志包含调用者会话、入参、出参、时间戳。这既是为了安全追溯也是评估集构建的数据来源。这些安全机制看起来费功夫但对生产系统来说是不可省的部分。特别是当你的 Agent 技能涉及财务、运维、客户数据时一次越权操作可能带来巨大的业务风险。6. 从项目到平台的延展建议agent-skills 跑完单点项目之后下一步往往是平台化的需求。随着技能数量从十几个增长到上百个会出现几个新问题技能权限怎么管理技能质量怎么保证不同业务线怎么共享技能我的建议是往技能市场方向演进。每个技能像一个应用有发布、审核、上下线流程技能之间有评分和调用量统计帮助开发团队识别高价值技能和低效技能跨业务线共享技能时通过统一的权限体系控制访问范围。这个方向做的事情本质上是把 agent-skills 从工程组件提升到组织能力中台。落到具体执行上其实是三件事一是技能定义标准化所有团队都按同一套 schema 注册二是技能生命周期管理从开发到退役都有清晰流程三是技能数据回流让调用数据反哺技能优化。如果你是在企业内部做这个方向千万不要一上来就追求大而全的平台。先把三五个核心场景的技能做扎实跑通注册、调用、评估、迭代这个闭环用实际效果说服团队和业务方再逐步扩展。技术平台最忌讳的是空转没有业务价值的技能市场只会变成一个没人用的摆设。在我自己的项目里正因为先在一个运维场景里验证了整套体系的稳定性后续才能顺利复制到知识库问答、工单处理、数据分析等其他场景。每一个新场景的接入成本都在下降因为技能注册、路由、评估这些基础设施已经就绪新场景需要做的只是定义技能和实现 handler。这种基础能力沉淀 场景快速复制的模式应该就是 agent-skills 真正值钱的地方。最后分享一个我在日常开发里的小习惯每次新增一个技能我都会在评估集里补 5~10 条相关测试请求并且把技能描述打印出来亲自读一遍读的时候问自己如果我是模型看到这段描述能准确判断何时调用吗能正确生成参数吗这两个问题想明白了技能的调用效果基本就有保障了。希望这套实践对你也有用。