SKILL.md:用Markdown为AI智能体编写“说明书”,实现技能即文档 📅 2026/8/15 5:45:37 1. 项目概述当AI学会“阅读说明书”最近在折腾一个叫OpenClaw的开源AI智能体框架时我遇到了一个挺有意思的瓶颈。框架本身很强大能调用各种工具比如查询天气、发送邮件、执行代码但每次想让它学会一个新技能比如调用一个特定的内部API或者操作一个复杂的本地软件过程都相当繁琐。要么得写一堆胶水代码去封装要么得在配置文件里大动干戈调试起来更是让人头大。这让我思考有没有一种更自然、更“人话”的方式让AI能快速理解并掌握一个新工具的使用方法直到我遇到了SKILL.md这个概念。简单来说它就是一个用Markdown格式编写的“工具说明书”。你不需要是个专业的程序员只需要像写一份清晰的操作指南一样在Markdown文件里描述清楚这个工具是干什么的、怎么用、输入输出是什么OpenClaw就能“读懂”它并动态地将这个工具注册为自己的新技能。这听起来有点像让AI拥有了“即插即用”学习新工具的能力而学习的教材就是我们最熟悉的Markdown文档。这个思路彻底改变了我和OpenClaw的协作方式。我不再是和一堆抽象的代码、配置项搏斗而是在撰写一份份面向AI的“产品说明书”。整个过程变得直观且高效。接下来我就结合自己的踩坑经验详细拆解一下如何利用SKILL.md让你的OpenClaw智能体真正实现“技能即文档”的自主学习。2. SKILL.md的核心设计哲学为什么是Markdown在深入实操之前我们得先弄明白为什么SKILL.md选择Markdown作为载体而不是JSON、YAML或者更结构化的Schema如OpenAPI Spec。这背后其实有非常务实的考量。2.1 降低技能描述的门槛JSON或YAML对格式要求极其严格一个多余的逗号、缩进错误都可能导致解析失败。这对于快速编写和迭代一个工具描述来说体验并不友好。而Markdown的语法宽容度更高核心是文本内容结构通过简单的标记如#、-、来体现即使格式不那么完美人类和AI都相对容易理解其意图。这让非技术背景的领域专家比如业务分析师、产品经理也能参与到技能描述的工作中他们只需要关注“这个工具该怎么用”而不是“这个JSON该怎么写”。2.2 兼顾人机可读性一份SKILL.md文档首先是一份给人看的说明书。开发者、测试者、使用者都可以通过阅读这份Markdown文档清晰地了解工具的功能、参数和示例。同时OpenClaw的解析引擎通常基于大语言模型的函数调用能力可以“阅读”同一份文档从中提取出结构化的信息如函数名、参数列表、返回值。这种“一份文档两种用途”的特性极大地减少了维护成本。你不需要同时维护一份给人看的Wiki和一份给机器读的API定义。2.3 利用大语言模型的自然语言理解优势现代的大语言模型LLM在理解和生成自然语言、以及从非结构化文本中提取结构化信息方面表现出色。SKILL.md本质上是在用自然语言“教”AI。当我们写下“这个函数用于查询用户余额需要传入用户ID字符串类型返回一个包含余额浮点数和货币单位字符串的JSON对象”时LLM能够很好地理解这段描述并将其映射为内部可执行的函数调用逻辑。这比直接让LLM去理解一个复杂的、充满技术术语的JSON Schema要更自然。2.4 灵活性与可扩展性Markdown的灵活性允许我们在技能描述中嵌入丰富的上下文信息。比如我们可以在文档中加入“注意事项”章节提醒AI在某些边界条件下的处理逻辑可以加入“常见错误”章节让AI在调用失败时能更好地诊断问题。这些非结构化的补充信息对于提升AI智能体使用工具的鲁棒性至关重要而这些在严格的JSON Schema中是很难优雅表达的。注意选择Markdown并不意味着放弃结构化。一个设计良好的SKILL.md解析器会在后台将Markdown中的关键信息函数签名、参数类型提取并转换为内部的结构化表示例如Pydantic模型或JSON Schema以确保调用的类型安全和可靠性。这是一个“前端自由后端严谨”的折中方案。3. 手把手编写你的第一个SKILL.md理论说再多不如动手写一个。我们以一个实际场景为例为OpenClaw添加一个“工作日计算器”技能用于计算两个日期之间的工作日天数排除周末和指定节假日。3.1 SKILL.md的标准结构模板虽然SKILL.md强调灵活性但一个清晰的结构能帮助AI更准确地理解。下面是一个我总结的、在实践中效果不错的模板# 技能名称CalculateWorkingDays **功能描述**计算两个给定日期之间的工作日周一至周五天数支持排除用户自定义的节假日列表。 ## 函数签名 python def calculate_working_days(start_date: str, end_date: str, holidays: List[str] None) - int: **参数说明** - start_date (字符串): 开始日期格式必须为 YYYY-MM-DD例如 2024-01-01。 - end_date (字符串): 结束日期格式必须为 YYYY-MM-DD。结束日期应晚于或等于开始日期。 - holidays (字符串列表可选): 一个可选的节假日列表列表中的每个日期字符串格式也应为 YYYY-MM-DD。这些日期将被视为非工作日。如果不提供则仅排除周末。 **返回值** - int: 从开始日期到结束日期包含开始和结束日期之间的工作日天数。 ## 调用示例 **示例1计算不含节假日的普通工作日** python days calculate_working_days(2024-05-01, 2024-05-10) # 假设5月1日和10日都是工作日期间包含两个周末4日-5日11日-12日但12日不在区间内实际需要计算。 # 返回值可能为 8 具体取决于日历 **示例2计算包含自定义节假日的工作日** python days calculate_working_days(2024-10-01, 2024-10-07, holidays[2024-10-01, 2024-10-02, 2024-10-03]) # 假设10月1-3日为法定节假日即使它们是周二到周四也应被排除。 # 返回值需要排除10月1-3日以及周末10月5-6日。 ## 实现逻辑与边界条件 1. **日期解析**使用 datetime.strptime(date_str, “%Y-%m-%d”) 解析日期字符串格式错误应抛出明确异常。 2. **周末判断**date.weekday() 返回0-6对应周一到周日通常认为5周六和6周日为周末。 3. **节假日处理**将holidays列表中的日期转换为datetime.date对象并与遍历的日期进行比较。节假日即使落在周一到周五也应跳过。 4. **包含性**计算包含开始和结束日期。例如start_date和end_date是同一天且为工作日则返回1。 5. **错误处理** - 如果 start_date end_date应返回错误或0具体根据业务逻辑。建议返回0并给出警告。 ## 注意事项 - 日期格式必须严格遵守YYYY-MM-DD这是国际标准格式避免歧义。 - 节假日的排除优先级高于周末。即一个日期既是节假日又是周末只排除一次。 - 该函数不处理调休上班的情况即周末变为工作日。如需此功能需要更复杂的逻辑或额外的“特殊工作日”参数。3.2 编写要点与避坑指南这份SKILL.md看起来简单但每个部分都有其作用编写时需要注意以下几点技能名称要具体且唯一CalculateWorkingDays比DateHelper或Calculator好得多。它直接反映了核心功能避免了AI在多个相似技能间的混淆。功能描述用一句话概括开头的描述要让AI和人类都能在5秒内明白这个工具是干什么的。避免使用“这是一个用于…的工具”这样的套话直接说“计算…的工作日”。函数签名是核心必须提供准确的函数名、参数名、类型提示和返回值类型。Python风格的类型提示str,List[str],int是目前LLM最易理解的格式之一。参数名本身应具有描述性比如start_date而非s_date。参数说明要详尽除了类型必须说明格式YYYY-MM-DD、约束end_date应晚于start_date、默认值holidays None以及可选/必填。这是AI正确调用不出错的关键。调用示例是“教学黄金标准”示例是最好的老师。提供至少两个示例一个最简单的主流用例一个包含边缘情况的复杂用例。在示例注释中解释预期的行为和结果这能极大地提升AI的推理准确性。我强烈建议把示例注释写得像给实习生看的教程一样详细。实现逻辑是“保险丝”这部分不是给AI执行用的而是帮助AI理解工具的内部运作机制和边界。当AI遇到模糊或边缘的请求时比如用户说“从下周一算起”这部分知识能辅助它进行参数转换或提前预判问题。注意事项是“经验之谈”这里放的是你在真实开发、测试和使用中踩过的坑。比如日期格式问题、节假日优先级、调休难题。把这些写进去相当于给了AI一个“避坑手册”能显著减少低级错误。实操心得一开始我写的SKILL.md很简陋只有函数签名和一句话描述。结果AI调用时经常格式错误或逻辑混乱。后来我把“参数说明”和“调用示例”部分写得极其详细甚至加入了“如果用户输入‘明天’你应该如何将其转换为YYYY-MM-DD格式”这样的引导性文字AI的调用准确率提升了90%以上。记住你是在教一个超级聪明但缺乏常识的新手事无巨细总没错。4. 在OpenClaw中动态注册与使用SKILL.md编写好SKILL.md只是第一步接下来需要让OpenClaw能够加载并理解它最终将其转化为一个可调用的技能。这里涉及到OpenClaw的插件或技能加载机制。虽然不同版本的OpenClaw实现可能略有差异但核心流程是相通的。4.1 技能文件的放置与组织通常OpenClaw会有一个固定的目录如skills/、plugins/或tools/来存放技能定义。你需要将写好的CalculateWorkingDays.md文件放入这个目录。为了便于管理我建议采用以下结构openclaw_home/ ├── config.yaml ├── skills/ │ ├── system/ # 系统内置核心技能 │ ├── third_party/ # 第三方服务技能如天气、邮件 │ └── custom/ # 我们自定义的技能 │ └── CalculateWorkingDays.md └── ...在OpenClaw的配置文件如config.yaml中你需要指向这个自定义技能目录skill_directories: - “./skills/system” - “./skills/third_party” - “./skills/custom” # 添加自定义目录4.2 技能加载与解析流程当OpenClaw启动或收到重载指令时它会扫描配置的目录寻找技能定义文件。对于.md文件它会触发SKILL.md解析器。这个过程大致如下文件读取与解析解析器读取Markdown文件内容。关键信息提取利用大语言模型LLM或基于规则的解析器或两者结合从文档中提取出技能名、函数签名、参数描述和功能描述。高级的解析器还会尝试理解“实现逻辑”和“注意事项”来丰富工具的元信息。结构化转换将提取的信息转换为OpenClaw内部统一的工具定义格式。这个格式通常包含name: 工具唯一标识如calculate_working_days。description: 工具的自然语言描述来自“功能描述”。parameters: 符合JSON Schema规范的参数定义从“函数签名”和“参数说明”转换而来。examples: 可选的调用示例用于few-shot prompting。动态注册将转换后的工具定义注册到OpenClaw的技能注册中心。此时这个技能就对AI智能体可见、可用了。4.3 在对话中触发技能注册成功后你就可以在与OpenClaw的对话中使用了。对话模式取决于你的前端如命令行、Web UI、接入飞书/钉钉等。示例对话你“请帮我计算一下从2024年国庆节到节后第一周周五的工作日有多少天记得排除国庆假期。”OpenClaw思考过程用户需要计算工作日。我有一个calculate_working_days技能。需要提取开始日期、结束日期和节假日列表。开始日期2024年国庆节是10月1日即2024-10-01。结束日期“节后第一周周五”需要推算。10月1日周二节后是10月8日周一那一周的周五是10月11日即2024-10-11。节假日根据中国法定假日国庆假期通常为10月1日至7日。所以节假日列表是[“2024-10-01”, “2024-10-02”, “2024-10-03”, “2024-10-04”, “2024-10-05”, “2024-10-06”, “2024-10-07”]。调用技能calculate_working_days(“2024-10-01”, “2024-10-11”, holidays[…])。OpenClaw“从2024年10月1日到2024年10月11日扣除国庆假期10月1-7日和周末10月5-6日已在假期中10月12-13日不在区间内实际的工作日是10月8日周一、9日周二、10日周三、11日周四共4个工作日。”这个过程展示了AI如何理解你的自然语言请求将其映射到技能参数并最终执行计算。SKILL.md中详细的参数说明和示例在这里起到了关键的指导作用。5. 高级技巧让SKILL.md更“智能”基础的SKILL.md能让AI调用工具但一个优秀的SKILL.md能让AI“聪明地”调用工具。以下是我在实践中总结的几个进阶技巧。5.1 嵌入Few-Shot示例引导AI推理在SKILL.md中除了标准的函数调用示例可以增加一个“自然语言查询示例”章节。这部分直接展示用户可能怎么说以及对应的技能调用应该是什么样。这相当于给AI做了个“对话模板”的few-shot训练。## 自然语言查询与技能调用映射 当用户提出以下类型请求时你可以使用本技能 1. **查询型**“从{开始日期}到{结束日期}有几天工作日” - **思考**需要提取两个日期。用户未提及节假日使用默认值holidaysNone。 - **调用**calculate_working_days(start_date“提取的日期1”, end_date“提取的日期2”) 2. **包含节假日的查询**“算一下{日期范围}的工作日不包括{节假日列表}。” - **思考**需要提取日期范围和节假日列表。注意节假日可能以“国庆假期”、“元旦”等名称出现需要将其转换为具体日期列表。 - **调用**calculate_working_days(start_date“…”, end_date“…”, holidays[“转换后的日期1”, …]) 3. **模糊日期查询**“从下周一开始未来三周有多少个工作日” - **思考**需要解析“下周一”和“未来三周”为具体日期。先计算“下周一”的日期再计算三周后的日期作为结束日期。 - **调用**calculate_working_days(start_date“计算出的下周一”, end_date“计算出的三周后日期”)这样当AI遇到类似的自然语言时就能更准确地进行意图识别和参数填充。5.2 定义错误处理与回退策略在“注意事项”或新增的“错误处理”章节明确告诉AI当技能调用失败或返回意外结果时该怎么办。## 错误处理与用户反馈 - **日期格式错误**如果输入的日期字符串无法被解析技能会抛出 ValueError。此时你应该向用户友好地提示“您输入的日期格式有误请使用 YYYY-MM-DD 格式例如 2024-05-20。” - **开始日期晚于结束日期**根据我们的实现逻辑这可能返回0。你应该向用户确认“您输入的结束日期早于开始日期请问是否需要交换日期计算” - **网络或服务不可用**如果是调用远程API的技能如果技能调用超时或返回5xx错误你应该告知用户“当前服务暂时不可用请稍后再试。” 并尝试是否有替代方案或缓存数据。这赋予了AI基本的异常流程处理能力让对话更健壮。5.3 技能组合与流程提示一个复杂的任务可能需要按顺序调用多个技能。你可以在SKILL.md的末尾添加“与其他技能协作”的提示。## 常见协作场景 本技能常与以下技能组合使用 1. **date_parser**当用户输入“明天”、“下个月底”等相对日期时可先调用 date_parser 技能将其转换为绝对日期 YYYY-MM-DD 格式再作为本技能的输入。 2. **send_email** 或 report_generator计算出的工作日数可以作为生成报告或发送邮件通知的一部分内容。 这样AI在规划任务时就能意识到技能之间的依赖和协作关系做出更合理的规划。 ## 6. 实战排查SKILL.md常见问题与解决方案 即便按照最佳实践编写在实际集成和使用中仍会遇到各种问题。下面是我遇到的一些典型问题及其解决方法。 ### 6.1 技能加载失败解析错误 **问题现象**OpenClaw启动日志报错提示无法解析某个.md文件或者该技能未出现在可用技能列表中。 **排查步骤** 1. **检查文件路径与配置**确认SKILL.md文件是否放在正确的skill_directories配置的路径下并且OpenClaw有读取权限。 2. **检查Markdown语法**虽然Markdown宽容但某些解析器可能对特定语法敏感。确保文件是UTF-8编码并且没有不可见字符。可以尝试在最简单的文本编辑器中重新保存。 3. **检查核心章节**确认“函数签名”代码块存在且语言标记正确如 \\\python。参数说明是否完整。**一个常见的坑是函数签名中的参数名与参数说明中的名称不匹配**。 4. **查看解析器日志**如果OpenClaw提供了更详细的调试日志查看解析器在解析你的文件时具体在哪一步出错。可能是LLM在提取信息时遇到了歧义。 **解决方案**简化初始的SKILL.md文件只保留最核心的“函数签名”和“参数说明”确保能成功加载。然后再逐步添加其他章节以定位问题所在。 ### 6.2 技能调用失败参数错误或类型不匹配 **问题现象**AI尝试调用技能但日志显示调用失败错误信息可能是参数验证错误、类型错误或函数执行异常。 **排查步骤** 1. **核对参数类型**检查AI传递的参数值是否与SKILL.md中定义的参数类型一致。例如定义是List[str]但AI传递了一个用逗号分隔的字符串。 2. **核对参数格式**对于日期、URL等有格式要求的参数检查AI传递的值是否符合约定的格式如YYYY-MM-DD。通常问题出在AI对用户自然语言的日期解析上。 3. **检查默认值处理**如果参数是可选的且有默认值检查SKILL.md中是否明确写明了 None或 []并且AI在用户未提供该信息时是否正确使用了默认值而不是传递了一个空字符串或null。 4. **查看函数实现**SKILL.md描述的是接口最终调用的是背后真实的Python函数。确保后台实现的函数其参数名、类型、默认值与SKILL.md的描述**完全一致**。这是最容易出错的环节。 **解决方案**在SKILL.md的“调用示例”中提供极其精确的示例。并在“注意事项”中强调常见的参数转换陷阱。例如明确写道“holidays参数需要是一个Python列表格式如 [“2024-01-01”]。如果从用户输入中获取的是用‘、’或‘’分隔的字符串需要先进行分割和转换。” ### 6.3 AI不理解或错误使用技能 **问题现象**AI在应该使用该技能时没有使用或者在不该使用时错误调用。 **排查步骤** 1. **审查“功能描述”**描述是否足够清晰、无歧义是否涵盖了技能的主要应用场景用一两个关键词测试看AI能否关联到该技能。 2. **审查“自然语言查询示例”**如果你写了这个章节检查其中的示例是否覆盖了用户真实的提问方式。AI的意图识别能力依赖于这些示例。 3. **检查技能冲突**是否有其他技能的功能描述与当前技能过于相似导致AI混淆例如同时存在calculate_days和calculate_working_days。 4. **观察AI的思考过程**如果OpenClaw支持输出Chain-of-Thought查看AI在决定是否调用该技能时的推理逻辑。它可能因为对某个参数不确定比如无法确定用户说的“假期”具体指哪些天而放弃了调用。 **解决方案**优化技能描述使其更具区分度。增加更多、更贴近真实场景的自然语言示例。在技能描述中可以加入“**适用场景**”和“**不适用场景**”的说明主动引导AI。 ### 6.4 性能问题技能加载或调用缓慢 **问题现象**添加大量SKILL.md文件后OpenClaw启动变慢或者调用技能时响应延迟。 **排查步骤** 1. **SKILL.md文件过大**是否在文档中嵌入了大量与工具调用无关的文本如冗长的实现源码、公司背景介绍这会给解析器尤其是基于LLM的解析器带来不必要的负担。 2. **解析器模式**确认OpenClaw使用的是基于规则的轻量级解析器还是每次加载都调用LLM进行解析。后者在技能数量多时会导致启动缓慢。 3. **缓存机制**OpenClaw是否对解析后的技能定义进行了缓存首次加载后后续启动应直接读取缓存而不是重新解析所有Markdown文件。 **解决方案**保持SKILL.md的精炼只保留对AI调用和理解必需的信息。将详细的实现代码、设计文档等链接到外部资源。如果可能推动OpenClaw项目增加技能定义缓存功能。 ## 7. 从SKILL.md到技能生态的展望 SKILL.md模式的价值远不止于方便个人开发者。它开启了一种构建和共享AI技能的新范式。 **对内成为团队的知识沉淀工具**。每个业务系统、数据接口、内部工具都可以对应一个SKILL.md文件。新成员加入团队阅读这些文档就能知道AI能做什么、怎么做。业务逻辑变更时更新SKILL.md就能同步更新AI的能力实现了文档与能力的统一。 **对外可能催生技能市场**。想象一个开源社区开发者可以将写好的、用于调用各种公共API如机票查询、法律条文检索、学术论文搜索的SKILL.md文件提交上来。其他OpenClaw用户只需下载这些.md文件放到指定目录就立刻获得了这些能力。技能的分享变得像复制粘贴一样简单极大地丰富了AI智能体的能力边界。 当然这需要社区形成一些共识比如SKILL.md的标准化模板、版本管理、安全审核机制防止恶意技能等。但无论如何“技能即文档”的理念无疑让AI智能体的功能扩展变得更加民主化、人性化。它降低了人机协作的门槛让我们可以用最自然的方式——写作来赋予AI新的力量。