• Skill 机制解析:从定义、触发到调用外部工具


    转发请注明出处:

    一、什么是 Skill

    Skill 是一套 “AI 调度 + 脚本执行”的分工协作机制。它的核心思想是关注点分离:AI 大模型擅长理解意图、做判断和调度,但不擅长精确计算和复杂文件操作;因此,Skill 让 AI 专注于“什么时候调用什么工具”的决策,而把“重型”的实际执行工作交给封装好的专用脚本。

    一个 Skill 通常由以下部分构成:

    • 指令文件(如 SKILL.md):写给 AI 看的“操作指南”,用自然语言描述这个 Skill 能做什么、在什么场景下触发、具体执行步骤是什么。
    • 脚本目录:存放实际干活的代码,比如处理 Excel 的 Python 脚本、生成 PPT 的程序等。
    • 参考文档:存放该领域的知识文档,供 AI 在需要时查阅。
    • 资源目录:存放模板、图片等输出时需要的素材。

    二、Skill 如何产生作用:触发与执行逻辑

    Skill 的触发并非魔法,而是基于一套精心设计的调度机制,核心在于解决“AI 怎么知道该用哪个 Skill”的问题。

    1. 三层渐进式加载,管理上下文

    AI 的“记忆容量”(上下文窗口)有限,因此采用分层策略:

    • 第一层(始终在线):只有 Skill 的名称和描述这一小段元数据会一直待在 AI 的“记忆”里。AI 根据对话内容判断是否匹配某个 Skill 的描述,来决定“要不要触发它”。
    • 第二层(触发后加载):一旦 AI 决定触发某个 Skill,才会加载完整的指令正文,了解具体执行步骤。
    • 第三层(按需加载):执行过程中,如果指令要求查阅参考文档或调用脚本,AI 才会按需加载对应的脚本或参考资料。

    2. 触发匹配

    AI 根据对话内容和用户输入的关键词,自动匹配最合适的 Skill。为了让匹配更精准,Skill 的描述需要写得非常清晰,明确告知“我能处理什么意图”。

    3. 主动发现与边界管理

    为解决“装了 Skill 但 AI 想不起来用”的问题,一些进阶机制也被引入,比如在对话开始时主动扫描意图方向,列出当前可用的相关 Skill;当需求超出当前 Skill 的能力范围时,主动告警并建议调用其他 Skill。

    三、Skill 如何调用外部工具

    Skill 可以调用外部工具,这是它从“告诉 AI 怎么想”进化到“帮 AI 真的去做”的关键一步。

    调用外部工具通常通过“连接器”这座桥梁来实现。可以把连接器想象成给 AI 装的“USB 接口”,专门用来对接外部的各种软件和服务。

    整个调用流程:

    1. 配置连接器:在连接器市场里找到需要的服务,手动点击“信任”并完成授权。这一步的核心是安全,遵循“最小权限”原则。
    2. Skill 声明依赖:在写 Skill 指令时,明确告诉 AI 这个 Skill 需要用到哪个连接器里的哪个工具,相当于列出它“被允许”使用的工具箱。
    3. AI 调度执行:用户下达任务后,AI 理解意图,自动匹配并加载对应的 Skill,再按照 Skill 里写的流程,通过配置好的连接器去调用外部工具完成具体操作。

    四、Skill 与 Function Calling 的区别

    Function Calling 是模型“能调用函数”的原生能力,而 Skill 是“如何用好工具”的完整说明书和流程编排。

    对比维度 Function Calling(函数调用) Skill(技能)
    核心定义 一种底层机制,让大模型能输出结构化的 JSON,表示“我要调用哪个函数,参数是什么”。 一个上层封装,是包含指令、脚本、资源的完整模块,用来指导 AI 完成一个复杂任务。
    所在层次 执行层:解决“怎么调用”的问题,是模型和外部代码之间的桥梁。 能力层/调度层:解决“为什么调用、何时调用、按什么流程调用”的问题。
    主要形态 通常是 JSON Schema,定义了函数的名称、参数和类型。 通常是一个指令文件,用自然语言写明任务目标、操作步骤、触发条件和示例。
    核心职责 让 AI 能生成代码可以理解的、格式化的调用指令。 封装领域知识、标准操作流程(SOP)、多步骤编排和异常处理,让 AI 像有经验的专家那样工作。
    两者关系 是 Skill 的基础。Skill 最终还是要通过 Function Calling 来触发对具体工具的调用。 是 Function Calling 的指挥官。它告诉 AI 在什么场景下,按什么顺序,去调用哪些 Function Calling。

    简单说,Function Calling 给了 AI “手”去操作工具,而 Skill 给了 AI 一张“施工图纸”,告诉它什么时候该动手,第一步做什么,第二步做什么,以及做到什么标准才算合格。

    五、如何定义一个 Skill

    定义一个 Skill,核心是写好一个指令文件,它由两部分组成:

    1. YAML Frontmatter(元数据)

    文件顶部的元信息,必须包含 name 和 description,它们决定了 Skill 的触发时机:

    • name:技能的唯一标识,需与文件夹名一致。命名规则严格,只能用小写字母、数字和连字符(-),且不能以连字符开头或结尾。
    • description:最关键的一行。它需要清晰地告诉 AI “这个技能能做什么”以及“什么时候该用它”。写得好的 description 应包含核心功能和具体的触发关键词。
    • agent_created:如果 Skill 是通过自动生成方式创建的,需要加上 agent_created: true,否则后续可能无法修改。

    2. Markdown 正文(指令)

    这是 Skill 的“灵魂”,指导 AI 如何执行任务。建议包含以下结构:

    • 角色设定:给 AI 一个专业身份,比如“你是一名资深后端工程师”。
    • 工作流(SOP):分步骤描述执行流程,比如“先通读 diff,再分模块检查,最后输出报告”。
    • 约束与边界:设定必须遵守的规则或要避免的坑点,比如“必须考虑生产环境影响”。

    3. 一个简单示例

    ---
    name: code-review-expert
    description: 专业后端代码审查技能。当用户提交代码 diff、PR 链接,或提到“代码审查”、“PR Review”时触发。按安全性、性能、规范三个维度输出 Markdown 格式报告。
    agent_created: true
    ---
    
    # 角色设定
    你现在是拥有 10 年经验的 Senior Backend Engineer。
    
    # 标准操作流程(SOP)
    1. 通读 diff,理解变更意图。
    2. 分模块检查:安全性、性能、规范。
    3. 输出 Markdown 格式报告。
    
    # 常见坑点
    - 必须考虑生产环境影响
    - 拒绝模糊结论
    

    六、定义 Skill 时需要注意的关键点

    1. 描述决定成败

    Description 是整个 Skill 体系中最关键的一行文字,直接影响 Token 消耗和响应速度。写得不好会导致“该用时不用”(under-triggering)或“不该用时乱用”(over-triggering)。好的 description 应同时回答三个问题:能做什么、核心能力有哪些、什么情况下触发。

    2. 保持单一职责

    一个 Skill 只做一件事。不要把多个不相关的功能塞进同一个 Skill,因为规则之间容易冲突,导致 AI 执行混乱。如果需要多个能力协同,可以把它们拆成独立的 Skill,再通过流程编排组合使用。

    3. 从高频场景开始

    首个自定义 Skill 建议只解决一个明确且高频的问题,比如“整理会议记录”或“生成周报”。越高频的重复操作,越值得沉淀成 Skill。

    4. 注意边界与安全

    • 明确边界:在 Skill 中写清楚哪些事情不能做,比如“不评价年龄、婚育等合规敏感项”。
    • 注意安全:Skill 可以调用本地文件或外部 API,安装第三方 Skill 时需要检查其权限和脚本内容,优先选择可信来源。

    5. 多 Skill 协作与共享

    复杂任务可以被拆解,由多个 Skill 接力完成。例如,“收集信息 → 生成报告 → 发送邮件”这个流程,可以分别调用网页搜索 Skill、PDF 生成 Skill 和邮件发送 Skill。它们之间通过共享知识池传递上下文,比如上一个 Skill 生成的文件路径、关键结论等,确保信息不断链。

    此外,自定义 Skill 还可以共享给团队成员,统一团队的工作方式。

    七、总结

    Skill 体系是一个精密的“AI 调度系统”,它通过标准化的封装,让 AI 能够按需调用各类专业能力。这既解决了大模型“会聊不会做”的痛点,也让用户能通过创建和组合 Skill,把经验固化成可复用的自动化工具。

    它与 Function Calling 的关系可以概括为:Function Calling 是底层执行机制,Skill 是上层能力封装与流程编排。两者配合,才能让 AI 从“能说”真正走向“能做”。

    再附一个我在开发过程中使用的一个skill:

    ---
    name: deep-root-cause-analysis
    description: Systematically trace and debug complex data consistency issues in distributed systems with caching, async messaging, and multi-instance scenarios. Use when API returns incomplete or inconsistent data, when cache rebuild logic fails after restart, when data is lost across process/Kafka boundaries, or when multi-instance merge logic has field gaps.
    ---
    
    # Deep Root Cause Analysis
    
    ## 适用场景
    
    当遇到以下类型的问题时使用:
    - API 返回数据不完整或与预期不一致
    - 程序重启后缓存数据丢失
    - 异步消息(Kafka/RabbitMQ)链路中数据被截断
    - 多实例场景下数据合并不完整
    - 双模式采集(MIN/FULL)策略下数据一致性断裂
    - 序列化/反序列化后字段丢失
    
    ## 分析范式:八步定位法
    
    ### Step 1: 端到端数据流追踪
    
    **目标**:画出从数据产生到 API 响应的完整数据流图。
    
    **操作**:
    1. 找到数据**产生入口**(定时调度器、事件触发器)
    2. 找到**消息发送点**(Kafka producer、HTTP client)
    3. 找到**消息消费点**(Kafka consumer、消息处理器)
    4. 找到**实际处理逻辑**(数据解析器、转换器)
    5. 找到**缓存写入点**(内存缓存、数据库)
    6. 找到 **API 读取点**(HTTP handler、GraphQL resolver)
    7. 确认每个节点间的数据传递方式(指针引用 / 值拷贝 / JSON 序列化)
    
    **关键检查点**:
    - 数据是指针传递还是值拷贝?值拷贝后是否写回?
    - API 读取的字段与 parser 写入的字段是否一致(切片 vs Map)?
    - 数据在哪些节点可能被过滤或丢弃?
    
    ### Step 2: 序列化边界检查
    
    **目标**:识别数据在跨进程/Kafka 边界时是否丢失字段。
    
    **常见陷阱**:
    
    | 语言/框架 | 陷阱 |
    |-----------|------|
    | Go `json.Marshal` | 不序列化未导出字段(小写开头) |
    | Go 值拷贝 | 结构体值拷贝后修改不会反映到原值 |
    | Go Map vs Slice | Map 是引用类型,Slice header 是值拷贝 |
    | Python `pickle` | 自定义类需要 `__getstate__` |
    | Java Serializable | transient 字段不序列化 |
    | Protobuf | 未知字段被丢弃 |
    
    **检查清单**:
    - [ ] 所有通过 JSON 传递的结构体,字段是否都有正确的 tag?
    - [ ] 接收端反序列化后,未导出/未标记字段是否必然为零值?
    - [ ] 合并逻辑中是否依赖了这些可能为零的字段?
    
    ### Step 3: 缓存生命周期分析
    
    **目标**:分析缓存在重启后、重建时、合并时的行为。
    
    **生命周期阶段检查**:
    
    | 阶段 | 检查项 |
    |------|--------|
    | 重启后 | 缓存初始化为空,首次请求是否有强制刷新机制? |
    | 重建 | 重建函数是否从旧缓存保留了必要字段(特别是静态字段)? |
    | 合并 | MergeFrom 是否同步了所有字段类型(切片 + Map + 结构体)? |
    | 覆盖 | else 分支是否用空数据覆盖了缓存中的有效数据? |
    
    ### Step 4: 时序竞态分析
    
    **目标**:分析启动时序和消息消费时序是否导致消息丢失。
    
    **操作**:
    1. 绘制启动时间线:`T+0s: 程序启动 → T+Xs: consumer 就绪 → T+Ys: producer 启动`
    2. 确认 consumer 在 producer 之前就绪
    3. 检查消息 offset 策略(OffsetNewest vs OffsetOldest)
    4. 确认首条消息不会被 consumer 遗漏
    
    **关键问题**:
    - consumer 和 producer 是否在同一进程?
    - producer 是否等待 consumer 完成(如 chDone channel)?
    - 多个 goroutine 是否会竞争同一资源?
    
    ### Step 5: 分支条件验证
    
    **目标**:逐一验证每个条件分支,特别是 else 分支的副作用。
    
    **检查每个 if/else**:
    1. **if 分支**:预期的正常路径,数据如何处理?
    2. **else 分支**:
       - 是否用空值/默认值覆盖了有效数据?
       - 是否跳过了必要的处理步骤?
       - 是否有副作用(如重建切片导致 Map 数据丢失)?
    3. **early return**:是否跳过了关键的"写回"操作?
    
    ### Step 6: 多实例合并分析
    
    **目标**:确认多实例场景下,结果回传合并是否完整。
    
    **检查项**:
    1. sendResultMessage 是否包含完整数据?
    2. JSON 序列化是否丢失字段?(回到 Step 2)
    3. MergeFrom 是否同步所有字段?
    4. `SenderId == self` 的判断逻辑是否正确?
    5. 同一进程内直接写缓存 vs 跨进程走 MergeFrom 的路径是否一致?
    
    ### Step 7: 诊断日志注入
    
    **目标**:在关键节点注入日志,确认实际执行路径和数据状态。
    
    **日志注入点**:
    1. **调度入口**:输出模式、缓存长度
    2. **处理返回**:输出数据数量
    3. **分支判断**:输出走了哪个分支
    4. **缓存读取**:输出各字段大小(切片长度 + Map 长度)
    5. **合并函数**:输入和输出的字段大小对比
    
    **诊断决策树**:
    - 如果 `fieldA=0` 但 `fieldAMap>0` → 切片未被重建
    - 如果所有字段都为 0 → 数据采集从未成功
    - 如果 `mapA>0` 但 `sliceA=0` → Map 到切片的转换逻辑有缺陷
    
    ### Step 8: 渐进式修复与验证
    
    **原则**:一次修复一个问题,编译验证,逐步推进。
    
    **修复优先级**:
    | 优先级 | 类型 | 示例 |
    |--------|------|------|
    | P0 | 数据完全丢失 | 序列化丢字段、缓存未初始化 |
    | P1 | 数据部分残缺 | 合并遗漏字段、else 覆盖 |
    | P2 | 数据值错误 | 字段映射错误、类型转换 |
    | P3 | 诊断增强 | 添加日志 |
    | P4 | 防御性编程 | 增加空检查、边界保护 |
    
    **每次修复后**:
    1. 编译验证
    2. 确认修复逻辑不引入新问题
    3. 如果问题仍在,回到 Step 1 重新追踪
    
    ## 详细参考
    
    - 完整检查清单和代码示例,参见 [reference.md](reference.md)
    zengjian@Mac ~ %```
    
  • 相关阅读:
    【推导】线性变换的矩阵表达式
    【VUE3】--创建vue-cli项目,setup+ref+reactive+vue2/vue3响应式原理【练习代码已上传至Gitee】
    C语言笔记第15篇:文件操作
    114页5万字字智能交通大数据综合服务平台建设方案
    【自校正控制】递推最小二乘法
    这种测试用例编写方法,你怕是都没用过...
    【C++/STL】位图和布隆过滤器
    5个免费样机素材网站,设计必备,赶紧马住!
    《动手学深度学习 Pytorch版》 10.5 多头注意力
    CentOS7 安装docker
  • 原文地址:https://www.cnblogs.com/zjdxr-up/p/22936825