
1. 从skills这个模糊词说起它到底指什么第一次看到skills这个标题我脑子里冒出来的第一个念头是这词太泛了。技能、能力、技巧什么都能往里装。但结合热搜词里那一串Agent Skillsclaude agent skillscodex skillsskills开发skills安装包下载方向就清楚了——这里说的 skills指的是给 AI Agent 挂载的能力模块也就是让智能体在特定场景下调用特定工具、执行特定流程的一套封装机制。说白了大模型本身是个光杆司令它能理解你的话但没法直接读你本地的文件、查你的数据库、调你的接口。skills 就是给它配的手脚和工具箱。一个 skill 通常包含三样东西一段描述这个能力干什么的说明文本、一套调用逻辑可能是脚本、可能是 API 封装、以及触发条件什么时候该用这个 skill。Agent 拿到用户请求后先判断该不该调 skill调哪个然后把参数传进去拿到结果再组织成自然语言回给用户。这套东西为什么最近火因为大家发现光靠提示词工程已经卷到头了。你把 prompt 写得再花哨模型也没法凭空变出实时数据、没法操作外部系统。skills 补的正是这块短板。它把模型能力和真实世界操作之间的那道墙给拆了。适合谁看这篇三类人一是想给自己搭的 Agent 加功能但不知道从哪下手的开发者二是被各种 skills 安装包、下载平台搞晕了的新手三是想理解这套机制底层逻辑、方便做技术选型的老手。我会从概念讲到实操从选型讲到踩坑尽量把我知道的都倒出来。2. Agent Skills 的运行机制模型怎么知道该调哪个 skill2.1 触发判断不是所有请求都会走 skill很多人以为 Agent 是无脑调 skill其实不是。模型在收到请求后会先做一轮意图判断。这个判断依赖的是 skill 的描述文本——也就是你写在 skill 定义里的那段这个能力是干什么用的。举个例子你定义了一个叫query_weather的 skill描述写的是查询指定城市的实时天气。用户问今天北京热不热模型会把这个请求和所有可用 skill 的描述做语义匹配发现query_weather最相关于是决定调用它并把北京作为参数传进去。这里有个关键点描述文本的质量直接决定触发准确率。我见过太多人把描述写得含糊比如处理数据结果模型根本不知道什么时候该用它。好的描述应该包含三要素能力边界能做什么、不能做什么、典型输入用户可能怎么问、输出形式返回什么。2.2 参数提取从自然语言到结构化输入模型决定调 skill 之后下一步是把用户的自然语言请求转成 skill 能接受的参数格式。这一步最容易出问题。假设你的 skill 需要两个参数city城市名和date日期。用户说帮我看看后天上海的天气模型需要提取出city上海、date后天对应的日期。如果用户说上海天气那date就得用默认值通常是今天。我实测下来参数提取的准确率和几个因素强相关影响因素说明优化建议参数命名用city比用loc更容易被正确理解参数名用完整英文单词避免缩写参数描述每个参数都要写清楚含义和格式在 skill 定义里给每个参数加 description默认值设置没给默认值的参数用户不提就报错非必填参数一定要设默认值枚举约束参数只能取固定值时要明确列出用 enum 类型约束取值范围2.3 执行与回传skill 跑完之后发生什么skill 执行完结果会以结构化数据的形式返回给模型。模型拿到结果后不是直接甩给用户而是会再组织一遍语言。比如 skill 返回{temp: 28, condition: 晴}模型可能会说上海后天晴天气温 28 度挺适合出门的。这个再组织的过程很关键。如果你希望输出格式固定比如必须是 JSON那就在 skill 的返回说明里写清楚或者在系统提示词里约束。否则模型会自由发挥有时候加一堆废话有时候漏掉关键信息。提示skill 返回的数据量要控制。返回一大坨 JSON模型可能抓不住重点。建议在 skill 内部先做一轮筛选只返回最相关的字段。3. 自己动手写一个 skill从零到跑通的完整流程3.1 先想清楚这个 skill 解决什么问题动手之前先回答三个问题这个能力模型自己能做吗如果模型靠推理就能完成比如把这段话翻译成英文那不需要 skill。skill 是给模型补它做不到的事——查实时数据、操作外部系统、执行精确计算。输入输出是什么用户会怎么触发它它返回什么格式的数据失败怎么办接口超时、参数缺失、权限不足这些情况都要有兜底逻辑。我见过有人上来就写代码结果写到一半发现这个功能模型本来就能做白忙活。先想清楚再动手能省一半时间。3.2 定义 skill 的描述文件不同平台的 skill 定义格式不一样但核心结构大同小异。以常见的 JSON 格式为例{ name: query_weather, description: 查询指定城市的实时天气和未来三天预报。当用户询问天气、气温、是否下雨等问题时使用。, parameters: { type: object, properties: { city: { type: string, description: 城市名称如北京、上海 }, date: { type: string, description: 日期格式为 YYYY-MM-DD默认为今天, default: today } }, required: [city] } }这段定义里description是给模型看的决定了它什么时候调这个 skill。parameters是给模型填的决定了它怎么传参。两个部分都要写清楚。3.3 实现 skill 的执行逻辑执行逻辑可以用任何语言写Python 最常见。核心是接收参数、执行操作、返回结果。import requests from datetime import datetime, timedelta def query_weather(city: str, date: str today): if date today: target_date datetime.now().strftime(%Y-%m-%d) else: target_date date # 调用天气 API这里用示例接口 api_url fhttps://api.example.com/weather params {city: city, date: target_date} try: resp requests.get(api_url, paramsparams, timeout5) resp.raise_for_status() data resp.json() return { city: city, date: target_date, temp: data[temperature], condition: data[weather], humidity: data[humidity] } except requests.Timeout: return {error: 天气服务超时请稍后重试} except Exception as e: return {error: f查询失败{str(e)}}几个实操要点超时一定要设。不设超时接口卡住会把整个 Agent 拖死。我一般设 5 秒天气这种实时性要求不高的可以放宽到 10 秒。异常要捕获。网络请求、数据解析、API 限流都可能抛异常。不捕获的话Agent 会直接崩。返回结构要稳定。不管成功失败都返回一个 dict让模型能统一处理。3.4 注册与测试写完执行逻辑把它注册到 Agent 的 skill 列表里。注册方式取决于你用的框架——有的用配置文件有的用代码注册有的用平台界面。注册完之后一定要做触发测试。测试用例至少覆盖这几种测试场景输入示例预期行为明确触发北京今天天气怎么样调用 skill返回天气模糊触发出门要不要带伞可能触发取决于描述质量不该触发帮我写首诗不调用 skill参数缺失查天气追问城市或返回错误提示接口异常断网状态下查询返回友好错误信息我踩过的坑描述写得太宽泛结果用户问今天吃什么模型也去调天气 skill。后来把描述改成查询指定城市的天气状况包括温度、天气现象、湿度误触发就少多了。4. skills 的获取渠道与选型别在下载平台上浪费时间4.1 官方市场 vs 第三方平台热搜词里有一堆skills下载平台skills大全skills安装包下载说明很多人卡在去哪找现成的 skill这一步。我的建议是优先用官方渠道第三方平台只做参考。官方渠道比如各 Agent 框架自带的 skill 市场的好处是版本可控、安全有保障、和框架兼容性好。第三方平台的问题是质量参差不齐、可能夹带私货、更新不及时。我见过有人从某平台下了个 skill结果里面藏了恶意代码把本地文件读了个遍。如果你确实需要某个第三方 skill先看源码。Python 脚本直接读混淆过的就别用了。看它有没有网络请求、有没有文件操作、有没有执行系统命令。有可疑行为的一律不用。4.2 选型时看什么拿到一个 skill怎么判断它靠不靠谱我一般看这几个维度描述是否清晰描述含糊的触发准确率大概率不行。参数设计是否合理必填参数太多、参数名用缩写、没有默认值的用起来会很累。错误处理是否完善有没有超时、有没有异常捕获、失败返回什么。依赖是否干净依赖一大堆第三方库的部署起来麻烦还容易出安全问题。更新频率半年没更新的大概率有兼容性问题。4.3 自己写 vs 用现成的这个问题我被问过很多次。我的判断标准是通用能力天气查询、网页抓取、文件读写用现成的没必要重复造轮子。业务相关查你公司的数据库、调你内部的 API自己写现成的 skill 不可能适配你的业务。逻辑复杂多步骤、有条件分支、需要状态管理自己写现成的 skill 通常只做单一功能。自己写的好处是可控。你知道每一行代码在干什么出了问题能定位要改逻辑随时改。用现成的 skill出问题只能等作者更新或者自己 fork 一份改。5. 实际部署中的坑我踩过的和见过的5.1 描述文本的语义漂移这是最常见的问题。你写描述的时候觉得这个说法够清楚了但模型的理解可能和你想的不一样。我做过一个实验同一个 skill描述写查询订单状态触发准确率大概 70%改成根据订单号查询订单的当前状态包括待付款、已发货、已完成、已取消准确率提到 92%。差别就在于是否列出了具体的状态值。模型是靠语义匹配来选 skill 的。你给的信息越具体它匹配得越准。所以描述文本要啰嗦一点把用户可能用的各种说法都覆盖到。5.2 参数类型不匹配模型有时候会把数字传成字符串把字符串传成数组。比如你的 skill 需要count参数是整数模型传了个5过来代码里直接range(count)就报错了。解决办法是在 skill 执行逻辑里做类型转换和校验def process(count): try: count int(count) except (ValueError, TypeError): return {error: count 必须是整数} if count 1 or count 100: return {error: count 必须在 1-100 之间} # 继续处理别嫌麻烦这一步能省掉后面一堆调试时间。5.3 并发调用时的状态冲突如果你的 Agent 会同时处理多个请求而 skill 内部有共享状态比如写同一个文件、操作同一个数据库连接就可能出问题。我遇到过一次两个请求同时调同一个 skill 写日志文件结果日志内容交错在一起完全没法看。后来改成每个请求写独立文件或者加锁问题才解决。注意skill 设计时尽量做成无状态的。每次调用都是独立的不依赖上一次调用的结果。这样并发安全也方便水平扩展。5.4 超时和重试的平衡超时设太短正常请求也被掐断设太长卡住的请求会拖垮整个系统。我的经验值是本地操作读文件、算数1-2 秒外部 API天气、搜索5-10 秒复杂查询数据库、大数据量15-30 秒重试的话只对幂等操作重试。查询可以重试写入不要重试可能重复写入。重试次数一般 2-3 次每次间隔递增1 秒、2 秒、4 秒。6. 进阶玩法把多个 skill 串起来6.1 链式调用单个 skill 能力有限但多个 skill 串起来就能完成复杂任务。比如帮我查一下明天北京的天气如果下雨就提醒我带伞顺便看看有没有合适的室内活动——这需要天气 skill、提醒 skill、活动推荐 skill 协同工作。链式调用的关键是上下文传递。第一个 skill 的输出要能作为第二个 skill 的输入。这要求 skill 的返回结构设计得合理字段命名清晰方便后续 skill 引用。6.2 条件分支有时候需要根据 skill 的返回结果决定下一步调哪个 skill。比如查天气返回下雨就调推荐室内活动返回晴天就调推荐户外活动。这种逻辑一般写在 Agent 的编排层而不是 skill 内部。skill 只负责单一功能编排层负责决定调用顺序和条件分支。6.3 错误降级链式调用中如果某个 skill 失败了整个链条不能直接崩。要有降级策略天气 skill 失败跳过天气相关逻辑继续执行其他部分提醒 skill 失败记录日志稍后重试活动推荐 skill 失败返回通用建议降级策略要在编排层实现skill 本身只负责返回错误信息。7. 关于 skills 开发的一些个人体会写了这么多 skill我最大的感受是难的不是写代码是写描述。代码逻辑再复杂调试几次总能跑通。但描述文本写不好模型就是不用你的 skill或者用错地方你连问题出在哪都找不到。我的做法是每写一个 skill先写描述然后拿十几个不同的用户问法去测。测到触发准确率 90% 以上再开始写执行逻辑。这样能避免代码写完了发现触发有问题回头改描述又要重新测的尴尬。另一个体会是skill 要小而专。一个 skill 只做一件事做精做透。我见过有人把查天气、查快递、查汇率塞进一个 skill结果描述怎么写都不对触发准确率一塌糊涂。拆成三个独立 skill每个描述都清晰问题就解决了。最后说个实际的日志一定要打。skill 被调用了没有、传了什么参数、返回了什么结果、耗时多少这些都要记下来。出问题的时候日志是唯一的线索。我一般用结构化日志JSON 格式方便后续检索和分析。这套东西还在快速演进今天好用的方案明天可能就过时了。但底层的逻辑——描述决定触发、参数决定执行、错误处理决定稳定性——这些不会变。把这几块吃透换什么框架都能快速上手。