如果你正在做 Agent 应用最近一定被“Agent Skills”这个词包围了。但打开各个平台的教程要么是纯概念讲解看完还是不知道代码怎么写要么直接甩一个框架 Demo换一个场景就不会用了。这篇文章想解决的就是这两个问题Agent Skills 到底是什么以及它在真实项目中到底怎么落地。先说结论Agent Skills 不是新的 AI 模型也不是新的编程语言它是 Agent 开发中的一种能力组织方式。它解决的核心痛点是“同一个能力在不同 Agent 之间复用太难”。过去我们把这些能力写成 Function、写成 Tool、写成 MCP 服务各有各的缺点Function 和业务代码耦合太重Tool 的描述信息往往不够MCP 服务又偏重和外部系统对接。Agent Skills 的思路是把一个完整能力封装成“可独立安装、可移植、可被 LLM 自动识别和调用”的模块并且带上一份模型能看懂的使用说明书。这篇文章会按照“概念 → 原理 → 实操 → 常见问题 → 最佳实践”的顺序展开。你会看到一个 Skill 从零到一怎么写怎么把它接到 Agent 上以及多 Agent 协作时 Skill 为什么是关键底座。文中所有代码都基于通用思路不绑定某个特定框架你可以在 Claude、DeepSeek、自研 Agent 或者其他支持工具调用的环境里做迁移实践。1. 为什么 Agent Skills 值得单独学过去一年Agent 开发基本走完了“从能聊到能干活”的阶段。但真正做生产级 Agent 的人都知道目前最大的瓶颈不是模型推理能力而是能力封装和复用。先看一个具体场景。假设你要做一个客服 Agent它需要查订单、查物流、处理退款、生成工单。没有 Skills 的时候通常的做法是写一堆函数每个函数对应一个能力然后在系统提示词里写清楚函数怎么用。一开始只有 5 个函数还好维护。等到函数变成 50 个你会发现几个问题第一提示词越来越长模型对函数描述的注意力会被稀释经常选错工具。第二函数和主程序强耦合牵一发而动全身。第三这些函数只能在这个 Agent 里用换一个项目就得复制粘贴改起来极其痛苦。Agent Skills 的设计思路就是把“函数”升级为“可独立组织、独立描述、独立调用的能力单元”。每个 Skill 自带使用说明模型读到说明就知道这个 Skill 能干什么、在什么条件下调用、输入输出是什么格式。这样一来能力本身和 Agent 的主逻辑解耦了你可以在项目 A 里开发一个 Skill在项目 B 里直接引用甚至通过配置文件动态装配。这个变化对开发者的意义在于Agent 的架构从“一个巨大的提示词 一堆散装函数”变成了“一个轻量核心 一组标准化的 Skill 集合”。开发和维护的心智负担会显著下降。所以不要以为 Agent Skills 只是又一个包装概念。它是 Agent 应用走向工程化、产品化过程中非常关键的一个抽象层。理解并掌握它你写的不再是“能跑的 Demo”而是“能维护的系统”。2. Agent Skills 的核心概念与适用场景2.1 什么是 Agent Skills从实现层面看一个 Agent Skill 通常包含三个部分一是元信息描述这个 Skill 的名称、版本、用途、作者、依赖等。它相当于能力的“身份证”。在很多实现里元信息用一个 JSON 或 YAML 文件表示例如skill.json或SKILL.yaml。二是说明书也就是模型的引导文档常见命名是SKILL.md。这份文档是给 LLM 看的而不是给人看的。它需要写清楚这个 Skill 用来解决什么问题、什么时候该调用、不该调用、输入参数怎么传、输出格式长什么样、有没有边界条件和注意事项。三是实现代码也就是真正执行任务的程序可以是 Python 脚本、Shell 脚本甚至是可执行文件。模型通过函数调用或工具调用触发这段代码。以 JSON 处理场景为例一个名为json-processing-skill的 Skill其核心文件结构可能是这样的json-processing-skill/ ├── SKILL.md ├── skill.json ├── scripts/ │ ├── clean_json.py │ └── merge_json.py └── examples/ └── sample_input.json其中SKILL.md是模型要读的说明书skill.json是元数据scripts/下面是实际执行的代码examples/存放示例输入输出方便模型理解用法。2.2 Skill、Tool、Function、MCP 的区别很多初学者会把 Skill 和 Tool、Function、MCP 混为一谈这里先做一个对比。维度Function/ToolMCPModel Context ProtocolAgent Skills粒度单一函数通常一个动作一组服务能力往往对应外部系统完整任务能力包含说明和实现描述方式函数签名 简短描述服务端声明工具列表说明书式引导文档 元数据复用性低与代码强耦合中跨应用但需服务端支持高独立安装和迁移学习成本低中高涉及协议和服务部署中掌握结构规范即可适用阶段快速原型系统对接、跨应用共享能力Agent 能力沉淀、多 Agent 协作通俗解释就是Function/Tool 是“胳膊腿”MCP 是“API 网关 工具实现”而 Skill 是“一个带使用手册的完整岗位”。模型读到SKILL.md不仅知道该调用什么还知道什么时候不该调用、调用前要做什么准备、调用后结果怎么解析。这一点在很多真实场景里非常关键因为模型出错往往不是“不会用工具”而是“在错误的场景下用了工具”。2.3 适用场景判断Agent Skills 适合以下场景第一你正在构建面向业务领域的 Agent且业务能力可以被拆成多个可复用模块比如数据清洗、文档解析、内容审核、代码检查。第二你需要多个 Agent 协作完成复杂任务每个 Agent 负责一个领域Skill 是它们之间交换能力的标准载体。第三你的团队有多个项目都需要调用同一套内部能力你希望能力可以沉淀、维护和升级而不是复制粘贴。反过来如果你的场景只是调用一两个公开 API或者做一次性脚本那直接用 Function 或 Tool 就够了不需要引入 Skill 的复杂度。2.4 一个容易被忽视的点Skill 的本体是“说明”不是“代码”新手最容易误解的地方是以为 Skill 的重点是写代码。其实真正难点在于写SKILL.md。因为代码是给人确定的逻辑而SKILL.md是给模型不确定的“理解空间”。说明书写得好模型才知道这个 Skill 该怎么用、什么时候用、边界在哪里。举个例子同一个 JSON 清理函数你可以把它封装成一个“通用 JSON 格式化工具”也可以封装成一个“针对用户上传的 JSON 数据进行敏感字段脱敏和格式规范化的处理器”。前者模型可能在各种场景乱调后者模型只在需要清洗 JSON 时触发。差异不在函数里在说明书里。所以开发一个 Skill一半时间在写代码另一半时间要花在教育模型“怎么正确使用”这件事上。3. 环境准备与前置条件接下来进入实操部分。为了让你能跟着跑通我们先准备一个最小环境。本文的示例基于 Python 3不依赖任何特定的 Agent 框架核心逻辑就是“一个被 LLM 调用的工具函数 一个说明书”。后续你可以把这段逻辑迁移到任意 Agent 框架中。需要准备的工具和依赖如下操作系统Windows 10/11、macOS 或 Linux 均可。Python 版本3.9 及以上如果你本机没有安装可以从 Python 官网下载稳定版本。虚拟环境建议使用venv或conda避免污染全局环境。一个支持工具调用/函数调用的 LLM 接口例如 OpenAI 兼容接口或 DeepSeek 等国产模型接口也可以先使用本地 Ollama 部署的模型做测试。核心依赖requests用于调用 LLM APIpydantic用于参数校验可选但推荐。这里有一个重要的提醒你不需要一开始就搭建一个完整的 Agent 框架。很多人学 Agent Skills 学不下去就是因为先把 LangChain、LlamaIndex、Dify 这些重框架装上结果还没碰到 Skill 本身就被框架的抽象绕晕了。建议先用最朴素的方式把“Skill 的骨架”跑通再考虑引入框架。环境准备完成后建议统一在一个工作目录下操作。下面所有示例的根目录假设为agent-skills-demo/。你可以按自己的习惯命名。4. 从一个 JSON 处理 Skill 开始动手目录结构与核心文件为了讲清楚 Skill 的组成部分我们用一个贴近日常开发的场景来做示例开发一个“JSON 数据处理 Skill”。这个 Skill 可以实现两个功能清理 JSON 数据去重、删空值、统一键名风格以及合并两个 JSON 文件。选择这个场景是因为 JSON 处理在 Agent 应用中几乎无处不在而且逻辑足够简单方便你把注意力集中在 Skill 的结构上。4.1 创建项目目录先创建目录结构mkdir -p agent-skills-demo/json-processing-skill/{scripts,examples} cd agent-skills-demo创建完成后目录结构如下agent-skills-demo/ └── json-processing-skill/ ├── scripts/ └── examples/接下来依次创建skill.json、SKILL.md和两个 Python 脚本。4.2 编写 skill.json 元信息文件文件路径agent-skills-demo/json-processing-skill/skill.json{ name: json-processing-skill, description: 提供 JSON 数据清理、格式校验、字段合并等常用数据预处理能力, version: 0.1.0, author: agent-team, license: MIT, language: python, entry: scripts/clean_json.py, parameters: [ { name: input_file, type: string, description: 输入 JSON 文件路径, required: true }, { name: output_file, type: string, description: 输出 JSON 文件路径, required: false } ], tags: [json, data-cleaning, preprocessing] }这个文件的作用是给框架或人工提供索引信息。注意description字段不只是给人看的也会在很多 Agent 框架中作为“选择哪个 Skill”的参考依据。所以描述要精炼、包含关键词、说清楚能力边界。不要写空话比如“这是一个 JSON 工具”应该写“清理 JSON 数据中的空值和重复项统一键名风格”。4.3 编写 SKILL.md 使用说明书文件路径agent-skills-demo/json-processing-skill/SKILL.md# JSON Processing Skill ## Purpose 在处理用户提供的 JSON 数据之前使用本技能完成清理和预处理。适用于数据导入、数据转换、接口调试等场景。 ## When to Use - 用户上传了 JSON 文件需要去除空值、重复项或统一键名格式。 - Agent 从多个来源获取 JSON 片段需要合并后再做后续分析。 - 需要对 JSON 格式进行校验确认字段类型是否符合预期。 ## When NOT to Use - 用户只要求查询 JSON 中的某个值不需要修改原始数据。 - 数据格式不是 JSON而是 CSV、XML 或其他格式。 - 用户明确要求不做任何数据清洗保留原始内容。 ## Input Parameters - input_file需要处理的 JSON 文件路径。 - output_file处理结果的输出路径。如果为空则在原文件基础上覆盖并备份原始文件。 - mode处理模式可选值为 clean清理、merge合并、validate校验默认 clean。 - merge_with合并模式下第二个 JSON 文件路径。 ## Output Format 输出为 JSON 格式包含 - statussuccess 或 error - message处理结果描述 - data处理后的 JSON 数据或校验结果 ## Examples ### Example 1: Clean Input: json {name: Alice, age: null, tags: [a, b, a]}Output:{name: Alice, tags: [a, b]}Example 2: ValidateInput:{id: 1, email: invalid-email}Output:{valid: false, issues: [email field format invalid]}Notes清理逻辑仅对根级键有效嵌套对象需要先展开。如果输入文件超过 10MB建议先做文件分块。合并操作不会覆盖原始文件而是生成新文件。SKILL.md 的写作原则是**像教一个新同事一样教模型**。你要告诉它什么时候用、什么时候不要用、输入输出长什么样、有哪些坑。描述得越具体模型乱调用的概率就越低。 ### 4.4 编写 Python 实现代码 接下来实现真正的逻辑。先写清理脚本 clean_json.py。 文件路径agent-skills-demo/json-processing-skill/scripts/clean_json.py python #!/usr/bin/env python3 JSON Processing Skill 核心实现。 import json import sys import argparse from pathlib import Path def clean_json_data(data): 清理 JSON 数据删除值为 None 的字段数组去重。 if isinstance(data, dict): cleaned {} for key, value in data.items(): cleaned_value clean_json_data(value) if cleaned_value is not None: cleaned[key] cleaned_value return cleaned elif isinstance(data, list): cleaned_list [clean_json_data(item) for item in data] # 对不可变元素去重保持顺序 seen set() result [] for item in cleaned_list: if isinstance(item, (dict, list)): result.append(item) elif item not in seen: seen.add(item) result.append(item) return result else: return data def validate_json(data): 校验 JSON 数据基本格式返回 (is_valid, issues)。 issues [] if isinstance(data, dict): for key, value in data.items(): if value is None: issues.append(f字段 {key} 值为空) return (len(issues) 0), issues def merge_json_files(input_file, merge_with_file): 合并两个 JSON 文件。基于 dict 的键合并或 list 的拼接。 with open(input_file, r, encodingutf-8) as f: data1 json.load(f) with open(merge_with_file, r, encodingutf-8) as f: data2 json.load(f) if isinstance(data1, dict) and isinstance(data2, dict): merged {**data1, **data2} return merged elif isinstance(data1, list) and isinstance(data2, list): return data1 data2 else: raise ValueError(合并的两个 JSON 顶层结构必须一致都是 dict 或都是 list) def main(): parser argparse.ArgumentParser(descriptionJSON Processing Skill) parser.add_argument(--input_file, requiredTrue, help输入 JSON 文件路径) parser.add_argument(--output_file, help输出 JSON 文件路径) parser.add_argument(--mode, defaultclean, choices[clean, merge, validate], help处理模式) parser.add_argument(--merge_with, help合并模式下第二个 JSON 文件路径) args parser.parse_args() input_path Path(args.input_file) if not input_path.exists(): print(json.dumps({status: error, message: f文件不存在: {input_path}})) sys.exit(1) try: with open(input_path, r, encodingutf-8) as f: data json.load(f) if args.mode clean: result_data clean_json_data(data) message 清理完成 elif args.mode merge: if not args.merge_with: print(json.dumps({status: error, message: 合并模式需要指定 merge_with 参数})) sys.exit(1) result_data merge_json_files(input_path, args.merge_with) message 合并完成 else: valid, issues validate_json(data) output {status: success, data: {valid: valid, issues: issues}} print(json.dumps(output, ensure_asciiFalse, indent2)) return output {status: success, message: message, data: result_data} if args.output_file: with open(args.output_file, w, encodingutf-8) as f: json.dump(result_data, f, ensure_asciiFalse, indent2) else: print(json.dumps(output, ensure_asciiFalse, indent2)) except json.JSONDecodeError as e: print(json.dumps({status: error, message: fJSON 解析错误: {e}})) sys.exit(1) except Exception as e: print(json.dumps({status: error, message: f处理异常: {e}})) sys.exit(1) if __name__ __main__: main()这段代码并不复杂但它体现了 Skill 实现层的重要原则输入输出必须采用标准 JSON 结构并且要清晰区分成功和失败状态。因为调用方是 LLM它需要通过输出来决定下一步动作。如果脚本输出一堆不可解析的日志模型就会“迷茫”。4.5 准备测试数据创建两个示例 JSON 文件用于后续验证。文件路径agent-skills-demo/json-processing-skill/examples/sample_input.json{ name: Alice, age: null, email: aliceexample.com, tags: [admin, user, admin], address: { city: Hangzhou, zip: null } }文件路径agent-skills-demo/json-processing-skill/examples/merge_input.json{ role: admin, permissions: [read, write] }4.6 本阶段小结到这里你已经看到了一个完整 Skill 的骨架。它包含元信息、说明书和实现代码三部分。其中元信息和说明书是 Skill 与普通脚本的本质区别。把同样的代码复制到脚本里它只是一个脚本配上SKILL.md和skill.json它才具备被模型正确使用的基础。5. 把 Skill 接进 Agent两种典型接入方式写好了 Skill下一步是让它被 Agent 调用。根据项目的复杂程度不同有两种接入方式可以选。5.1 方式一轻量级 “说明书注入 命令执行”这种方式适合实验阶段或轻量场景。核心思路是把 Skill 的信息作为系统提示词的一部分注入给 LLM模型在需要时返回一个要执行的命令主程序解析命令并调用脚本。下面是一个最小接入示例。文件路径agent-skills-demo/basic_agent.py#!/usr/bin/env python3 轻量级 Agent 接入 Skill 的示例。 import json import subprocess import sys from pathlib import Path # 读取 SKILL.md 内容注入系统提示词 SKILL_MD_PATH Path(json-processing-skill/SKILL.md) SKILL_DOC SKILL_MD_PATH.read_text(encodingutf-8) SYSTEM_PROMPT f你是一个数据处理助手。你可以使用以下技能 {SKILL_DOC} 当你需要调用技能时请严格输出以下 JSON 格式的命令不要输出其他内容 {{command: python3 scripts/clean_json.py --input_file 路径 --mode 模式}} 如果你认为不需要调用技能直接回答用户问题。 def parse_model_output(output_text): 解析模型输出。这里简化处理仅提取 JSON 块。 start output_text.find({) end output_text.rfind(}) 1 if start -1 or end 0: return None try: return json.loads(output_text[start:end]) except json.JSONDecodeError: return None def run_command(cmd): 执行命令并返回输出。 result subprocess.run(cmd, shellTrue, capture_outputTrue, textTrue, cwdPath(__file__).parent) return result.stdout, result.stderr def main(): # 这里假设你已经通过 requests 或 openai 库调用 LLM简化起见直接接收一个手动输入作为模拟 print(请输入你的请求例如清理 sample_input.json 中的空值) user_input input().strip() # 真实项目中你会将 SYSTEM_PROMPT 和 user_input 一起发送给 LLM。 # 这里做演示我们跳过 LLM 调用直接构造命令。 # 你可以把这段替换为 openai.ChatCompletion 调用。 cmd python3 json-processing-skill/scripts/clean_json.py --input_file json-processing-skill/examples/sample_input.json --mode clean stdout, stderr run_command(cmd) if stderr: print(执行出错, stderr) sys.exit(1) try: result json.loads(stdout) if result.get(status) success: print(处理成功) print(json.dumps(result.get(data), ensure_asciiFalse, indent2)) else: print(处理失败, result.get(message)) except json.JSONDecodeError: print(无法解析技能输出, stdout) if __name__ __main__: main()这个示例把“模型决策”部分简化了但结构是完整可运行的。你只需要把 main 函数里的调用替换成真实的 LLM API 调用即可。5.2 方式二框架级 “工具注册” 接入在生产项目中更推荐使用框架级的工具注册机制。以常见的工具调用实现为例一个 Skill 可以封装为SkillExecutor类按模块化方式注册到 Agent 运行时中。文件路径agent-skills-demo/skill_executor.py#!/usr/bin/env python3 Skill 执行器把 Skill 包装成工具供 Agent 框架调用。 import json import subprocess from pathlib import Path class SkillExecutor: 通用 Skill 执行器。 def __init__(self, skill_dir: str): self.skill_dir Path(skill_dir) self.skill_config self._load_config() self.entry_script self.skill_dir / self.skill_config.get(entry, ) def _load_config(self): config_path self.skill_dir / skill.json with open(config_path, r, encodingutf-8) as f: return json.load(f) def get_skill_definition(self): 返回给模型看的工具定义类似 OpenAI Function Calling 的 function 定义。 params self.skill_config.get(parameters, []) properties {} required [] for p in params: properties[p[name]] { type: p.get(type, string), description: p.get(description, ), } if p.get(required): required.append(p[name]) return { type: function, function: { name: self.skill_config[name], description: self.skill_config[description], parameters: { type: object, properties: properties, required: required, }, }, } def execute(self, **kwargs): 执行 Skill 脚本并解析输出。 cmd [python3, str(self.entry_script)] for key, value in kwargs.items(): cmd.append(f--{key}) cmd.append(str(value)) result subprocess.run(cmd, capture_outputTrue, textTrue, cwdself.skill_dir) if result.returncode ! 0: return {status: error, message: result.stderr} try: return json.loads(result.stdout) except json.JSONDecodeError: return {status: error, message: f输出解析失败: {result.stdout}}这个SkillExecutor类做的事情包括加载 skill 配置、生成模型视角的工具定义、执行命令并规范输出。你可以把它非常容易地接入到支持 Function Calling 的 Agent 中只需要在调用模型时把get_skill_definition()的返回值传给tools参数然后根据模型的tool_calls参数调用execute即可。5.3 如何验证接入是否正确无论用哪种方式接入都要做三层验证第一层脚本本身能否独立运行。如果脚本直接执行报错说明问题在 Skill 实现本身先不要谈接入。第二层传参能否被正确映射。模拟一个 LLM 可能生成的不规则参数看你的执行器能否容错和处理。第三层端到端调用。给定一个真实用户问题看模型是否会主动调用 Skill、传参是否正确、输出格式是否符合后续处理预期。如果在端到端测试中发现模型不会调用 Skill大概率不是模型的问题而是SKILL.md的触发条件描述不够清晰。此时不应该调大“模型温度”之类的参数而是回头修改说明书。6. 多 Agent 协作Skill 是协作的关键底座很多人在学 Agent 时会遇到一个概念迷雾单 Agent 都还没搞明白为什么要学多 Agent 协作其实答案很简单一旦 Agent 要承担真实业务涉及的领域知识往往超过单个 Agent 能承载的范围。比如一个“电商运营分析 Agent”既要知道怎么从数据库查订单又要懂 RFM 模型还要能生成图表。如果所有这些能力都塞进一个 Agent 的提示词里提示词会变得极其臃肿模型出错率也会上升。更合理的做法是拆成三个 Agent数据查询 Agent、分析 Agent、可视化 Agent每个 Agent 专注于一个方向。这时候就出现了一个关键问题三个 Agent 之间如何共享能力各自拥有的技能如何被团队统一管理这就是 Agent Skills 在多 Agent 协作中的价值。6.1 多 Agent 协作的三种典型编排模式从工程实践看多 Agent 协作通常有三种模式。第一种是顺序编排模式。Agent A 处理完把结果交给 Agent BAgent B 交给 Agent C。这种模式适合流程图清晰的场景比如数据采集 → 数据清洗 → 数据分析。在顺序编排中每个 Agent 需要知道“上游给我什么、我输出什么”Skill 的输入输出规范化能力正好发挥作用。第二种是层级编排模式。有一个主控 Agent或者叫 Orchestrator负责拆解任务然后把子任务分发给不同的 Worker Agent。这种模式适合任务比较复杂、需要动态决定分工的场景。主控 Agent 需要了解每个 Worker 能干什么这时候skill.json中的description和SKILL.md的When to Use就成了主控做任务派发的重要依据。第三种是协作群组模式。多个 Agent 围绕一个共同目标并行工作通过消息机制同步状态。这种模式实现难度最高一般在真正复杂的生产系统中用到。在这种模式里Skill 是“能力的最小共识单元”——你不需要关心别的 Agent 内部怎么实现只需要调用它暴露的 Skill。6.2 一个简单协作案例数据流水线假设我们要构建一个简单的双 Agent 协作系统Agent A 负责从外部获取 JSON 数据并做清洗Agent B 负责对清洗后的数据做统计汇总。两个 Agent 通过共享的 Skill 进行衔接。文件路径agent-skills-demo/multi_agent_demo.py#!/usr/bin/env python3 多 Agent 协作示例数据清洗 Agent - 统计 Agent。 import json from pathlib import Path from skill_executor import SkillExecutor class DataCleaningAgent: 只负责数据清洗不关心统计逻辑。 def __init__(self): self.skill SkillExecutor(json-processing-skill) def process(self, raw_json_path: str) - dict: # 在真实项目中这里会根据模型决策动态传参。 # 这里简化直接调用清洁能力。 result self.skill.execute( input_fileraw_json_path, modeclean ) return result class StatisticsAgent: 只负责统计不关心数据如何清洗。 def __init__(self): # 假设统计也封装为一个 skill self.skill SkillExecutor(statistics-skill) def process(self, cleaned_data: dict) - dict: # 统计 tags 中出现次数最多的项实际项目里这里可以调用统计技能 tags cleaned_data.get(tags, []) counter {} for tag in tags: counter[tag] counter.get(tag, 0) 1 most_common max(counter, keycounter.get) if counter else None return {most_common_tag: most_common, tag_count: counter} class Orchestrator: 调度中心负责调用 Agent并串联流程。 def __init__(self): self.cleaner DataCleaningAgent() self.statistician StatisticsAgent() def run(self, raw_json_path: str): clean_result self.cleaner.process(raw_json_path) if clean_result.get(status) ! success: return {status: error, message: clean_result.get(message)} cleaned_data clean_result[data] stats_result self.statistician.process(cleaned_data) return { status: success, cleaned_data: cleaned_data, statistics: stats_result, } if __name__ __main__: # 使用 examples 下的原始数据做演示 sample_file Path(json-processing-skill/examples/sample_input.json) orchestrator Orchestrator() result orchestrator.run(str(sample_file)) print(json.dumps(result, ensure_asciiFalse, indent2))注意这个示例为了便于演示跳过了 LLM 决策部分直接用 Python 串起两个 Agent。但在真实项目中Orchestrator 里会有 LLM 参与决策它会根据用户需求决定调用哪些 Skill、按什么顺序调用。Skill 的规范化让这种自动编排成为可能。6.3 协作中最容易踩的坑技能边界模糊在真实的多 Agent 协作开发里最容易出的问题不是代码 bug而是技能边界模糊。比如“数据清洗”和“数据校验”听起来很像如果两个 Skill 的说明书写得含糊主控 Agent 就会不知道该派发给谁。解决办法是在编写 SKILL.md 时明确写下“When NOT to Use”。给一个能力写“什么时候不该用”往往比写“什么时候该用”更能帮模型做正确决策。比如json-processing-skill的When NOT to Use中写了“用户只要求查询 JSON 中的某个值不需要修改原始数据”。这句话就是给主控 Agent 的“排除信号”帮助它把这个 Skill 从候选列表中剔除。7. 从“会写”到“写好”Skill 开发的常见问题与排查方法在实践 Skill 开发时大家几乎都会遇到下面几类问题。这里整理成一张排查表覆盖了从编写到接入、再到多 Agent 协作的完整链路。问题现象可能原因排查方式解决方案模型从不调用 SkillSKILL.md 中“When to Use”描述太泛模型无法匹配触发条件检查说明书看描述是否与用户问题的常见表达一致增加具体场景示例和关键词补充“When NOT to Use”模型总是乱调用 Skill说明书没有写清边界条件或 Skill 的 description 过于通用回看模型实际触发场景找到误触发条目在说明书中增加禁用场景缩小 description 范围调用成功但输出无法解析脚本输出混入了日志信息不是纯 JSON手工执行脚本检查 stdout日志输出到 stderrstdout 只保留标准 JSON 结果参数传递错误skill.json 中参数类型或描述与脚本不一致对照 skill.json 的 parameters 和 argparse 参数统一参数名和类型重要参数必须标 required中文路径导致脚本报错部分系统上 subprocess 处理中文路径的编码问题检查报错堆栈是否涉及路径编码使用 Path 对象处理路径或对路径做编码统一多 Agent 协作时任务分给了错误 Agent各 Skill 的 description 区分度不够检查两个 Skill 的 description 和 When to Use 是否有重叠用关键词边界把职责区分到互斥Skill 在 A 项目可用在 B 项目不可用缺少相对路径处理依赖全局路径检查代码是否使用了绝对路径所有文件操作都基于 Skill 目录做相对定位7.1 一个高频问题的详细排查模型不调用 Skill模型不调用 Skill是新手最容易遇到且最难定位的问题。建议按以下顺序排查第一步确认 Skill 是否真的被注入到模型的上下文里。很多框架中Skill 不是默认注入的需要在代码里显式加载。可以打印系统提示词确认里面是否包含 SKILL.md 的内容。第二步确认 Skill 的描述是否包含用户可能使用的关键词。举个例子如果你的 Skill 是用来做“情感分析”的但描述里永远只写“情绪识别”模型面对“你觉得这段文本是正面还是负面”时可能匹配不上。第三步用简单直接的指令做测试。不要一上来就做复杂任务先用最标准的说法触发一次调用比如“请执行 json-processing-skill 清理 sample_input.json”如果这样都不调用说明接入有问题如果能调用只是复杂场景不调用说明是描述匹配问题。第四步检查模型本身的工具调用能力。部分轻量模型在 Function Calling 场景下表现不稳定可以换一个强一些的模型再次测试。7.2 输出格式不一致的处理思路当 Skill 脚本被直接执行时输出完全正确但被 Agent 调用后结果却“变量不对”问题往往出在参数映射上。例如模型返回的工具调用参数是{input_file: xxx, mode: clean}而你的执行器错误地将参数名改写成了--input-file而不是--input_file脚本就会报错。解决思路是在 SkillExecutor 中增加参数名映射层把模型可能生成的多种参数写法统一为标准形式。在真实项目中模型返回的参数名可能和skill.json中定义的不完全一致这需要用代码来兜底而不是依赖模型“准守规则”。8. Skill 开发与落地的最佳实践这一部分会跳出具体代码谈一谈在生产项目中沉淀 Skill 的工程建议。这些建议来自常见项目的共性经验希望帮你少走弯路。8.1 命名规范Skill 命名要遵循“领域 动作 对象”的模式例如json-cleaner、code-reviewer、image-resizer。避免使用过于抽象的命名比如utils、helper、common。抽象命名会让模型和人都无法快速判断这个 Skill 的职责最终沦为“垃圾桶 Skill”。8.2 版本管理Skill 一定要有版本号而且升级时遵循语义化版本规则。因为 Skill 会被多个 Agent 引用你在 Skill A 里改了输出格式如果调用方没同步升级协作流程就会断裂。建议在 skill.json 中维护version字段在关键脚本中通过命令行参数支持--version输出。8.3 SKILL.md 的维护节奏SKILL.md 不是写一次就完事的。建议每次迭代都做一次“模型行为回归测试”准备一组标准用户请求记录模型是否正确调用 Skill、调用后是否得到预期结果。如果发现某一类请求频繁误触发或漏触发就要修改 SKILL.md 中的触发条件描述而不是去改模型参数。8.4 安全边界Skill 的本质是让模型决定何时执行一段代码。这带来一个安全问题如果 Skill 被恶意构造或者模型被注入攻击者控制的指令可能会触发危险操作。有几个基本要求要守住第一Skill 执行环境必须隔离。不要让 Skill 脚本直接运行在宿主机上建议使用容器、沙箱或受限权限账号。第二Skill 参数必须做白名单校验。无论模型传什么参数都要在代码里再次校验不合法就拒绝。第三涉及网络请求、文件删除、数据修改的 Skill必须增加人工确认机制。第四Skill 的代码同样要做 Code Review不能因为是“给 AI 用的工具”就降低质量要求。8.5 日志与可观测性生产环境中运行 Skill必须有日志和监控。日志建议至少包含调用时间、调用模型、输入参数摘要、输出结果摘要、执行耗时、错误堆栈。有了这些日志你才能在模型行为异常时复盘定位。还可以为每个 Skill 设置执行阈值和失败率告警一旦失败率超过阈值及时处理。8.6 测试策略Skill 至少需要三层测试单元测试脚本逻辑是否正确、接口测试模型调用参数能否正确映射、端到端测试真实业务场景是否能完成任务。在 CI/CD 中加入 Skill 的回归测试非常值得因为 Skill 是会被多个项目复用的一次改动可能影响面很大。9. 总结与后续学习方向到这里Agent Skills 的完整链路已经走了一遍。我们从“为什么需要它”说起讲清楚了 Skill 与 Tool、MCP 的区别然后亲手搭建了一个 JSON 处理 Skill把它接进了最小 Agent并通过一个双 Agent 协作示例展示了 Skill 如何在多 Agent 场景中作为能力底座。如果你希望继续深入可以考虑以下方向一是研究你正在使用的 Agent 框架对 Skill 的底层支持比如微软 Agent Framework 等二是研究复杂多 Agent 任务编排特别是动态任务规划三是关注社区中各类 Skill 的实现方式多从别人的 SKILL.md 中学习“如何给模型写说明”。四是在团队中尝试建设内部 Skill 仓库把高频业务能力逐步沉淀下来。建议收藏本文在你第一次从零搭建 Skill 时把它当作对照清单使用。真正的学习曲线不在概念而在你动手写完第一个能被模型稳定调用的 Skill 的那一刻。