
最近在给项目接 AI Agent 时总有一种“模型懂很多但干不了细活”的感觉。让它生成代码可以让它批量处理表格、调用本地脚本、按业务规则做判断结果往往不稳定。后来接触到 Agent Skills 这个概念才意识到问题出在“能力边界”上——模型本身具备的是推理能力而真正要落地到具体任务还需要一套明确的“工作技能包”。这篇文章我们彻底拆解 Agent Skills 的完整链路它是什么、和 AI Skills 有什么区别、怎么把现成技能装进自己的 Agent、以及最关键的一步——如何从零造一个能用、好维护的 Agent Skills。全文采用小白友好的讲解方式尽量不用难懂的黑话最终目标是让你 1 小时内理解原理、能操作、能自己动手开发一个小技能。如果你之前对 Agent、Function Calling 这些概念似懂非懂这篇文章刚好适合你。1. Agent Skills 是什么先建立一个直观印象1.1 一个能听懂人话的“工具箱”如果你用过各类 AI Agent大概率遇到过这种尴尬大模型聊天很流畅论文、代码都能写但让它去统计本地文件夹里的 Markdown 标题数、批量给文件重命名、把 CSV 转成 JSON它经常“避而不答”或者生成一段不完整的内容让你自己动手。为什么因为模型本身的知识和推理能力再强也“触碰不到”你本地的文件、数据库、命令行工具。它需要一种机制把“模型会推理”和“程序能执行”这两件事连起来。Agent Skills 解决的正是这个问题。你可以把它理解为“给 AI 助手额外安装的插件包”每个 Skills 对应一个具体能力比如“批量处理 Markdown 文档”“生成接口文档”“查询数据库表结构”。每个 Skills 都自带了“说明书”告诉模型我这个能力是干什么的、什么时候该调用、怎么调用。每个 Skills 还自带了可执行脚本模型不需要重写代码直接调用这个脚本就能完成任务。这样Agent 就从一个“只会聊天的助手”变成“装备齐全的团队”。1.2 更严谨一点的定义如果要用专业一点的话来描述Agent Skills 可以定义为一段可复用的能力封装通常由描述文件、可选依赖清单和可执行脚本组成能够被 AI Agent 在推理过程中自动识别、加载和调用。它和传统的 API、SDK 有一个本质区别API 需要开发者通过写代码来调用而 Agent Skills 的调用者不是人是模型本身。模型根据用户的任务描述自行判断“该使用哪个 Skills”然后按 Skills 里的使用说明来执行。这也决定了 Agent Skills 的设计重点设计重点说明明确描述模型要靠描述判断是否调用含糊等于没用接口简单脚本的入参、出参要简单可控输出规范模型需要根据标准输出来回答用户最小依赖依赖越多Agent 环境越容易崩1.3 它解决了哪些实际问题在真实项目中我们使用 Agent Skills 通常是为了解决下面几类问题操作本地资源读取文件、批量修改、整理目录结构等。访问外部数据调用内部接口、查询数据库、抓取公开网页等需要授权。完成确定性的计算比如格式转换、数据清洗、数据校验这类任务用模型硬写容易翻车用脚本一次搞定。复用团队经验一个团队沉淀好的 Skill可以被多个 Agent、多个项目反复使用。2. Agent Skills 与 AI Skills、Function Calling 的区别2.1 AI Skills 与 Agent Skills 的关系“AI Skills”和“Agent Skills”经常被混着用但严格来说它们不完全是一个层次的概念。AI Skills 是一个更宽泛的说法指“大模型具备的某种能力”可以是通过提示词实现也可以是通过工具实现。Agent Skills 更强调“面向 Agent 的可调用技能”它必须满足三个特征描述化、模块化、可执行。换句话说Agent Skills 是一种具体实现形式而 AI Skills 更像一个能力总称。当网上很多文章讨论“Agent Skills 赋能人文社科混合研究方法论文写作”时本质上是在说研究者把文献整理、数据清洗、摘要提取等步骤封装成可复用的 Skills让 Agent 在论文写作流程中自动调用。它让跨学科的研究方法不再停留在“提问-回答”层面而是真正变成一套可执行、可复现的分析流程。2.2 Agent Skills 与 Function Calling 的区别Function Calling函数调用是很多 Agent 框架的基础能力模型按照协议输出一个结构化调用指令然后由程序执行对应函数。两者最直观的区别对比项Function CallingAgent Skills定位一次函数调用一个完整技能包包含内容函数定义 参数描述文件 脚本 依赖 示例复用程度往往需要逐个注册可整体复制、分发、安装开发成本低中等适合场景简单、单个功能复杂、可沉淀、可复用举一个例子Function CallingAgent 调用get_weather(city北京)。Agent Skills包含一个SKILL.md描述文件说明何时使用、入参规则还带一个scripts/get_weather.py实现天气查询、结果格式化、异常兜底。Skills 不只是“一段函数”它是一个自包含的、携带说明的能力包。2.3 Agent Skills 与 Prompt 工程的边界还有一部分人会把 Agent Skills 理解成“更长的提示词”。实际上两者也有明显差别Prompt 只能引导模型“怎么回答”。Skills 可以让 Agent“真正去执行”。例如你可以在提示词里写“请帮我统计文件里有多少个标题”但如果文件不在模型上下文中它无法完成。而一个负责读取文件的 Skills 可以主动读取一个文件夹统计完再把结果返回给模型。所以在复杂 Agent 应用中推荐组合使用Prompt 负责定义 Agent 的人设、决策边界Agent Skills 负责具体执行、计算、访问数据。3. 环境准备与版本说明3.1 本地开发环境开发一个 Agent Skills 本身并不需要特别复杂的工具链。本文示例以 Python 为主推荐环境如下操作系统Windows 10/11、macOS、Linux 均可Python 版本建议 3.9 及以上依赖管理pip后面会用requirements.txt文本编辑器VS Code、PyCharm 或者其他你顺手的编辑器支持 Agent Skills 的 Agent 客户端或平台。关于 Agent 客户端目前不同产品对 Skills 的规范和支持程度还有差异建议先确认你使用的 Agent 是否支持“加载本地 Skills 目录”的能力。本文会把重点放在技能本身的设计和编写上平台差异不会影响你理解核心逻辑。如果你在某个平台上的具体配置有差异以官方文档为准。3.2 本文目录规划为了演示清晰我们约定一个工作目录agent-skills-demo/ ├── skills/ │ ├── text_assistant/ │ │ ├── SKILL.md │ │ ├── requirements.txt │ │ ├── scripts/ │ │ │ └── process_markdown.py │ │ └── examples/ │ │ └── demo.md └── playground/ └── test.mdskills/放所有技能的地方playground/用来放测试文件模拟用户要处理的数据。4. 拆解 Agent Skills 的标准结构4.1 描述文件SKILL.md每个 Skills 里最关键的文件是SKILL.md。它有两个作用给 Agent 看模型通过读取这个文件决定“这个技能适不适合当前任务”给人看开发者也能快速了解技能用途。一个典型的SKILL.md可以这样写--- name: markdown_text_assistant description: 提供 Markdown 文档的统计与整理能力例如统计标题数量、生成长度摘要、检查重复标题。 --- # Markdown 文本助手 ## 使用时机 当用户希望分析 Markdown 文档或者需要对 Markdown 文档做基础体检时使用。 ## 输入参数 - file_path: Markdown 文件路径必填。 - action: 要执行的动作可选值包括 summary、headings、check_duplicates。 ## 输出格式 脚本输出 JSON 格式结果字段包括 action、file_path、result。 ## 示例 bash python scripts/process_markdown.py --file_path playground/test.md --action summary注意几点 - description 越具体Agent 越容易判断何时调用 - 参数说明要写清楚类型和是否必填 - 建议附带一个可运行的示例命令帮助 Agent 理解调用方式。 ### 4.2 依赖文件 requirements.txt 如果脚本里用到了第三方库需要把依赖写进 requirements.txt。让 Agent 或平台在安装 Skills 时自动安装。 txt # 本文示例没有任何第三方依赖保留作为依赖管理示例示例脚本只用 Python 标准库就够了所以依赖文件可以为空。但保留这个文件仍然有价值后续新增第三方库时不用调整结构。4.3 主体脚本 scripts/process_markdown.py脚本是 Skills 的执行核心。你需要保证输入参数能通过命令行解析推荐用argparse输出格式稳定推荐 JSON要做好异常处理避免因为文件名不对、文件不存在直接崩溃加上必要的日志方便排查。4.4 examples 示例目录examples/不是强制要求但在真实项目中非常推荐。示例文件的作用是方便开发者快速测试帮助 Agent 理解“这个技能跑起来的输出长什么样”。5. 实战一先把一个现成的 Skills 用起来5.1 准备测试数据在playground/test.md下创建一个简单的 Markdown 文件# 项目周报 本周主要完成了三个任务。 ## 任务一完成接口开发 接口已上线待联调。 ## 任务二修复登录 Bug 已修复超时问题。 ## 任务三补充单元测试 覆盖率提升到 80%。 ## 待办事项 - 联调 - 回归测试5.2 编写 Skills 描述文件现在我们在skills/text_assistant/下建立文件。先写SKILL.md--- name: markdown_text_assistant description: 分析 Markdown 文档支持统计标题数量、生成摘要、检查重复标题。当用户给出 Markdown 文件并要求分析时使用。 --- # Markdown 文本助手 ## 使用时机 当用户希望分析 Markdown 文档或者需要对 Markdown 文档做基础体检时使用。 ## 输入参数 - file_path: Markdown 文件路径必填。 - action: 要执行的动作可选值包括 summary、headings、check_duplicates。 ## 输出格式 脚本输出 JSON 格式结果字段包括 action、file_path、result。 ## 示例 bash python scripts/process_markdown.py --file_path playground/test.md --action summary### 5.3 编写核心脚本 创建 scripts/process_markdown.py python #!/usr/bin/env python3 # -*- coding: utf-8 -*- Markdown 文档处理脚本 - summary: 统计文档总行数、标题数、估算字数 - headings: 提取文档标题结构 - check_duplicates: 检查重复标题 import argparse import json import re import sys from pathlib import Path def read_markdown(file_path: Path) - str: if not file_path.exists(): raise FileNotFoundError(f文件不存在: {file_path}) return file_path.read_text(encodingutf-8, errorsignore) def parse_headings(content: str): 提取所有标题及其级别。 返回 (level, title) 列表。 headings [] lines content.splitlines() for line in lines: line line.strip() match re.match(r^(#{1,6})\s(.*), line) if match: level len(match.group(1)) title match.group(2).strip() headings.append({level: level, title: title}) return headings def action_summary(content: str): headings parse_headings(content) total_chars len(re.sub(r\s, , content)) return { total_lines: len(content.splitlines()), headings_count: len(headings), estimated_chars: total_chars, } def action_headings(content: str): return {headings: parse_headings(content)} def action_check_duplicates(content: str): headings parse_headings(content) seen {} for item in headings: key item[title] seen.setdefault(key, []).append(item[level]) duplicates {k: v for k, v in seen.items() if len(v) 1} return {duplicates: duplicates} def main(): parser argparse.ArgumentParser(descriptionMarkdown 文本助手) parser.add_argument(--file_path, requiredTrue, helpMarkdown 文件路径) parser.add_argument( --action, requiredTrue, choices[summary, headings, check_duplicates], help要执行的动作 ) args parser.parse_args() file_path Path(args.file_path) output {action: args.action, file_path: str(file_path.resolve())} try: content read_markdown(file_path) if args.action summary: output[result] action_summary(content) elif args.action headings: output[result] action_headings(content) else: output[result] action_check_duplicates(content) print(json.dumps(output, ensure_asciiFalse, indent2)) except Exception as exc: output[error] str(exc) print(json.dumps(output, ensure_asciiFalse, indent2)) sys.exit(1) if __name__ __main__: main()5.4 命令行验证在项目根目录执行python skills/text_assistant/scripts/process_markdown.py \ --file_path playground/test.md \ --action summary预期输出{ action: summary, file_path: .../playground/test.md, result: { total_lines: 24, headings_count: 5, estimated_chars: 72 } }这说明一个 Skills 已经可以被直接执行。接下来就是把这样一个包含描述文件和脚本的目录告诉 Agent让它学会在合适的时机调用。5.5 让 Agent 调用这个 Skills不同 Agent 平台的加载方式不太一样但底层逻辑基本一致把skills/text_assistant/整个目录注册到 Agent 的技能列表中。通常只需要两步在 Agent 配置里指定 Skills 存放路径并启动扫描给 Agent 发一条指令例如“分析 playground/test.md 这份 Markdown 文档帮我提取标题结构”。此时 Agent 会先读取SKILL.md理解技能用途然后根据用户需求构造命令执行脚本最后把脚本返回的 JSON 以自然语言总结给用户。记得先单独测试脚本能不能跑通再接入 Agent。脚本本身稳定Agent 端排查问题会简单很多。6. 实战二从零开发一个自己的 Agent Skills6.1 选主题与需求分析软件开发里最忌讳一上来就写代码。开发 Agent Skills 也一样先想清楚三件事这个技能解决什么问题模型什么时候该调用它它的输入和输出是什么下面我们给这个例子定义需求技能名称csv_to_json_converter解决什么问题把 CSV 文件转换为 JSON 文件并支持字段筛选。调用时机当用户上传或指定了一个 CSV 文件希望转成 JSON或提取部分列时。输入input_file: CSV 文件路径output_file: 输出 JSON 文件路径可选默认同目录生成selected_columns: 逗号分隔的字段名列表可选输出标准 JSON 统计信息例如转换成功、行数、列名。6.2 创建目录结构skills/csv_to_json_converter/ ├── SKILL.md ├── requirements.txt └── scripts/ └── convert_csv.py6.3 编写 SKILL.md--- name: csv_to_json_converter description: 将 CSV 文件转换为 JSON 文件支持按列筛选。当用户希望处理 CSV 数据格式转换时使用。 --- # CSV 转 JSON 转换器 ## 使用时机 当用户提供 CSV 文件路径希望转换为 JSON 或提取部分字段时使用。 ## 输入参数 - input_file: 必填CSV 文件路径。 - output_file: 可选输出 JSON 文件路径。不填则默认在输入文件同目录生成同名 .json 文件。 - selected_columns: 可选逗号分隔的字段名列表只保留指定列。 ## 输出格式 返回 JSON 统计信息包括 success、row_count、columns、output_file。 ## 示例 bash python scripts/convert_csv.py \ --input_file data.csv \ --output_file data.json \ --selected_columns name,age,email### 6.4 编写转换脚本 python #!/usr/bin/env python3 # -*- coding: utf-8 -*- CSV 转 JSON 转换器 - 读取 CSV 文件 - 可指定输出路径 - 可筛选指定列 - 输出转换统计结果 import argparse import csv import json from pathlib import Path def load_csv(file_path: Path, selected_columnsNone): if not file_path.exists(): raise FileNotFoundError(f输入文件不存在: {file_path}) with open(file_path, r, encodingutf-8-sig, newline) as f: reader csv.DictReader(f) if reader.fieldnames is None: raise ValueError(CSV 文件为空或格式不正确) all_columns list(reader.fieldnames) # 校验用户选择的列是否都存在 if selected_columns: missing set(selected_columns) - set(all_columns) if missing: raise ValueError(f以下列不存在: {, .join(sorted(missing))}) data [] for row in reader: if selected_columns: row {col: row.get(col, ) for col in selected_columns} data.append(row) return data, all_columns def save_json(data, output_file: Path): output_file.parent.mkdir(parentsTrue, exist_okTrue) with open(output_file, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) def main(): parser argparse.ArgumentParser(descriptionCSV 转 JSON 转换器) parser.add_argument(--input_file, requiredTrue, helpCSV 输入文件路径) parser.add_argument(--output_file, helpJSON 输出文件路径) parser.add_argument(--selected_columns, help逗号分隔的列名列表可选) args parser.parse_args() input_path Path(args.input_file) selected None if args.selected_columns: selected [col.strip() for col in args.selected_columns.split(,) if col.strip()] if args.output_file: output_path Path(args.output_file) else: output_path input_path.with_suffix(.json) try: data, all_columns load_csv(input_path, selected) save_json(data, output_path) result { success: True, row_count: len(data), columns: list(data[0].keys()) if data else all_columns, output_file: str(output_path.resolve()), } print(json.dumps(result, ensure_asciiFalse, indent2)) except Exception as exc: result { success: False, error: str(exc), } print(json.dumps(result, ensure_asciiFalse, indent2)) raise SystemExit(1) if __name__ __main__: main()6.5 准备测试数据与运行创建playground/sample.csvname,age,email,department 张三,28,zhangsanexample.com,研发部 李四,31,lisiexample.com,产品部 王五,25,wangwuexample.com,市场部运行转换python skills/csv_to_json_converter/scripts/convert_csv.py \ --input_file playground/sample.csv \ --output_file playground/sample.json \ --selected_columns name,age,department预期输出{ success: true, row_count: 3, columns: [name, age, department], output_file: .../playground/sample.json }打开playground/sample.json[ { name: 张三, age: 28, department: 研发部 }, { name: 李四, age: 31, department: 产品部 }, { name: 王五, age: 25, department: 市场部 } ]这样一个完整可用的 Agent Skills 就做出来了。从“会用到会造”的整个过程其实只涉及描述文件、脚本、依赖管理、测试数据这几个要素。7. 常见问题与排查思路即使是一个简单的 Agent Skills在真实环境中也可能遇到各种问题。下面按优先级整理一份排查清单。问题现象常见原因解决思路Agent 从不调用这个技能SKILL.md 里的描述太模糊Agent 无法判断何时使用打开描述文件补充“使用时机”和“示例”脚本在终端能跑但 Agent 调用时报错Agent 工作目录与脚本预期目录不一致脚本内统一使用相对路径并先打印当前工作目录中文内容输出乱码控制台编码问题脚本输出统一使用 UTF-8Windows 可设置PYTHONIOENCODINGutf-8文件路径找不到传入的是相对路径或路径中包含特殊字符在SKILL.md里写明路径要求脚本层做resolve()依赖安装失败版本冲突或网络超时锁关键依赖版本减少第三方依赖数量输出格式不稳定脚本内直接print中文描述没有统一 JSON全部改成 JSON 输出字段固定大量数据内存溢出一次性读取完整大文件改为分批读取或流式处理下面挑两个高频问题详细说。7.1 Agent 不调用 Skills这是最容易遇到也最让人头疼的问题。排查顺序建议如下检查SKILL.md的description是否写清楚了适用场景确认 Agent 配置里 Skills 目录路径是否正确确认用户指令与技能描述有较高相关性比如你写的是“Markdown 分析”用户说“帮我看看这个文件”Agent 确实很难判断在描述文件中增加典型示例模型看到示例后识别准确率会明显提升。7.2 脚本工作目录不对很多脚本在命令行直接执行没问题但被 Agent 调用后运行目录是 Agent 进程的工作目录不是脚本所在目录。这时候就会触发“找不到文件”的报错。在脚本里最好加一个调试信息import os import sys print(os.getcwd(), filesys.stderr)先确认实际运行目录再决定路径如何拼接。更稳妥的做法是在SKILL.md中传入绝对路径或者让脚本基于入参路径的父目录推导文件位置。8. 最佳实践与工程建议8.1 描述文件要“把事情说清楚”写SKILL.md时不要只写“这是一个文本处理工具”要具体到什么时候使用什么时候不要使用参数怎么传输出长什么样。模型没有耐心去猜测一个模糊的描述。很多时候Agent 调用不准就是因为描述文件写得太抽象。8.2 脚本做到单一职责、稳定输出一个技能只解决一个问题。如果脚本又负责解析、又负责发送网络请求、又负责写数据库一旦出错很难定位。强烈建议脚本统一输出 JSON并且包含固定字段。这样无论脚本怎么改Agent 都能稳定解析结果。至少包含success是否成功result或error结果或者错误信息。8.3 加入日志与异常处理脚本要记录足够的日志输入参数关键步骤异常堆栈。日志建议写到stderr标准输出只保留供 Agent 读取的结果避免日志和结果混在一起。8.4 安全与权限边界要提前设计Agent Skills 能够帮 Agent 执行真实操作意味着它可能带来安全风险。需要注意最小权限原则技能只授予完成当前任务所需的最小权限比如只允许读取指定目录不允许删除文件操作前确认涉及删除、覆盖、修改生产数据时脚本应该先输出影响范围并确认后再执行路径校验对传入路径做白名单或前缀校验避免任意文件访问敏感信息保护不要在技能脚本中硬编码数据库密码、Token日志脱敏打印日志时不要输出完整密钥、手机号、身份证号等敏感字段。8.5 版本管理与可维护性把 Skills 当成代码工程来维护使用 Git 管理每个技能的独立仓库或目录在SKILL.md中维护变更记录每个技能都带上requirements.txt锁定关键依赖版本提供基本测试用例至少要有一个最小可运行示例。8.6 从使用到创造的成长路径学习 Agent Skills 时不要只停留在“会调用现成技能”。一个比较有效的路径是第一周克隆别人的 Skills逐行读懂脚本第二周给现有技能增加一个新参数、新动作第三周结合自己工作里的重复任务写一个 50 行以内的技能第四周尝试把多个小而简单的技能组合成一套更复杂的流程。9. 总结与学习路线这篇文章从零拆解了 Agent Skills 的完整链路重点包括Agent Skills 的定义以及它和 AI Skills、Function Calling 的区别一个标准技能包的基本结构SKILL.md、依赖文件、核心脚本、示例目录如何引入并验证现成技能如何从需求分析、目录搭建、代码编写、测试验证四个步骤完成自己的第一个技能开发常见调用问题的排查思路以及工程化落地时的安全与维护建议。如果你是第一次接触 Agent Skills建议先不要急着写复杂技能。把本章的两个示例复制到本地分别跑一遍观察脚本输出格式的变化再尝试修改描述文件和参数。这个过程会帮你建立对“模型如何理解技能”的直觉。接下来可以继续学习的方向包括Agent 多技能编排、技能间的依赖传递、本地工具与外部 API 的混合调用、技能测试自动化以及如何在团队内部建立统一的技能仓库。实战中优先关注技能描述质量和异常处理能力它们往往决定 Agent 在实际任务中的可用性。如果这篇文章对你有帮助可以收藏备用后续遇到 Agent 调用技能不准、脚本写好了却无法被识别这些问题时翻出排查清单对照一遍通常能省下不少时间。动手才是最好的学习方式建议现在就找一个小任务试试。