乐于分享
好东西不私藏

AI Agent Skill到底是什么,是如何实现的?

AI Agent Skill到底是什么,是如何实现的?

01

前言

前几天我在司内论坛的一个问答中提到了要写一个拉取网络文章文本的 skill,昨天我实现了之后也就开始好奇起 Skills 的底层原理了——相比起各种花里胡哨的 agrnt 应用,我一直以来都很对大模型在纯粹的 HTTP 交互层面是如何交互的更感兴趣。

我们知道,大模型只会对话,聊天,所谓的工具调用也只不过是特化的聊天功能而已。但是各种天花乱坠的 skills,是如何在底层的 HTTP 中,与大模型——这个只会嘴遁的工具交互的呢?

02

前置知识

本文面向对 OpenAI 兼容协议 有了解的同学,如果不了解的话,可以参考协议文档,或者是我的 两篇老文章 https://cloud.tencent.com/developer/article/2518981 简单了解。

03

核心结论先说:Skills 不是协议层概念

在 OpenAI 兼容协议中,根本不存在 "Skill" 这个字段或角色。 Skills 是一个纯粹的应用层抽象,它最终被 Cursor(或类似的 AI IDE)"编译"成三种协议原语的组合:

  1. System/Developer Message — 把 Skill 的指令文本注入到 system prompt 中

  2. Tools Definition — 把 Skill 需要用到的工具(如 Shell、Read 等)注册为 tools数组

  3. Multi-turn Tool Calling Loop — LLM 根据注入的指令,自主决策发起 tool_calls,宿主执行后把结果喂回去

用一句话总结:Skill = 动态注入的 system prompt 片段 + 预定义的 tool schema + 多轮 tool calling 循环。这里我们用 Cursor 以及我实现的 skill mp-read 来举例,其他工具(OpenClaw)也是一样的——

04

第 0 步:Skill 发现与描述摘要注入

在你打开 Cursor、还没说话的时候,Cursor 就已经扫描了 .cursor/skills/.agents/skills/ 等目录,收集了所有 Skill 的 name + description(来自 YAML frontmatter),然后把它们作为静态上下文塞进 system prompt。

以你的 mp-read 为例,SKILL.md 的 frontmatter 是:

name: mp-readdescription: >-  Extract plain text from Tencent MP (mp.weixin.qq) articles using a headless  Chrome browser. Use when the user wants to read, fetch, extract, summarize,  or reference a MP article, or when a mp.weixin.qq URL appears in conversation.

这段信息会被注入成类似这样的 system prompt 片段(Cursor 真实行为的简化版):

<available_skills><agent_skill fullPath="/path/to/mp-read/SKILL.md">  Extract plain text from Tencent MP (mp.weixin.qq) articles using a headless  Chrome browser. Use when the user wants to read, fetch, extract, summarize,  or reference a MP article, or when a mp.weixin.qq URL appears in conversation.</agent_skill></available_skills>

注意:此时 SKILL.md 的正文还没有被读取。这就是 Cursor 文档里说的 "Progressive Loading"——只先放名字和描述,不浪费 token。

05

第 1 步:用户发问,触发 Skill

假设用户发了一句:

帮我读一下这篇公众号文章:https://mp.weixin.qq.com/s/HHPK6QvclYaxlDg28elN8w

此时 Cursor 作为客户端,构造出的第一次 API 请求大致如下(简化但忠实于 OpenAI 协议):

{  "model""claude-4.6-opus",  "messages": [    {      "role""system",      "content""You are an AI coding assistant...\n\n<available_skills>\n<agent_skill fullPath=\"/Users/123456/.../mp-read/SKILL.md\">\n  Extract plain text from Tencent MP (mp.weixin.qq) articles...\n</agent_skill>\n</available_skills>\n\nWhen a skill is relevant, read and follow it IMMEDIATELY as your first action..."    },    {      "role""user",      "content""帮我读一下这篇公众号文章:https://mp.weixin.qq.com/s/HHPK6QvclYaxlDg28elN8w"    }  ],  "tools": [    {      "type""function",      "function": {        "name""Read",        "description""Reads a file from the local filesystem...",        "parameters": {          "type""object",          "properties": {            "path": { "type""string""description""The absolute path of the file to read." },            "offset": { "type""integer" },            "limit": { "type""integer" }          },          "required": ["path"]        }      }    },    {      "type""function",      "function": {        "name""Shell",        "description""Executes a given command in a shell session...",        "parameters": {          "type""object",          "properties": {            "command": { "type""string" },            "description": { "type""string" },            "working_directory": { "type""string" },            "block_until_ms": { "type""number" }          },          "required": ["command"]        }      }    }  ],  "tool_choice""auto"}

关键点:

  • tools 数组是 Cursor 预定义好的,不是 Skill 定义的。Skill 本身不声明工具——它只是告诉 LLM "你可以用 Read 来读文件,用 Shell 来执行命令"。

  • system prompt 里有 Skill 的描述摘要和一条关键指令:"When a skill is relevant, read and follow it IMMEDIATELY"

06

第 2 步:LLM 响应 — 决定先读 SKILL.md

LLM 看到用户提到了 mp.weixin.qq,匹配到了 system prompt 中 mp-read skill 的描述,于是按照指令"先读 Skill 文件"。它返回的响应是:

{  "choices": [    {      "message": {        "role""assistant",        "content": null,        "tool_calls": [          {            "id""call_abc123",            "type""function",            "function": {              "name""Read",              "arguments""{\"path\"\"/path/to/mp-read/SKILL.md\"}"            }          }        ]      },      "finish_reason""tool_calls"    }  ]}

这就是 Skill 的"加载"——本质上就是 LLM 自己发起了一次 Read tool call,读取 SKILL.md 文件。

07

第 3 步:Cursor 执行 tool call,返回结果

Cursor 在本地执行 Read("/Users/123456/.../mp-read/SKILL.md"),拿到文件内容,然后构造下一轮请求:

{  "messages": [    { "role""system""content""(同上,省略)" },    { "role""user""content""帮我读一下这篇这篇公众号文章:https://mp.weixin.qq.com/s/HHPK6QvclYaxlDg28elN8w" },    {      "role""assistant",      "content": null,      "tool_calls": [        {          "id""call_abc123",          "type""function",          "function": {            "name""Read",            "arguments""{\"path\"\"/Users/123456/.../mp-read/SKILL.md\"}"          }        }      ]    },    {      "role""tool",      "tool_call_id""call_abc123",      "content""---\nname: mp-read\ndescription: >-\n  Extract plain text from MP...\n---\n'\n```\n\n(...完整 SKILL.md 内容...)"    }  ],  "tools": [ "(同上,Shell、Read 等工具定义)" ]}

到这一步,SKILL.md 的全部内容已经通过 role: "tool" 消息进入了 LLM 的上下文窗口。 LLM 现在拥有了完整的"技能说明书"。

08

第 4 步:LLM 按照 Skill 指令行动 — 前置检查

LLM 读完 SKILL.md 后,按照 "Prerequisites Check" 章节的指示(章节中要求用户必须实现准备好一个 cookie.txt 文件),先检查环境。它返回:

{  "choices": [    {      "message": {        "role""assistant",        "content": null,        "tool_calls": [          {            "id""call_def456",            "type""function",            "function": {              "name""Shell",              "arguments""{\"command\"\"which mp-read\"\"description\"\"Check mp-read is installed\"}"            }          },          {            "id""call_ghi789",            "type""function",            "function": {              "name""Read",              "arguments""{\"path\"\".../cookie.txt\"}"            }          }        ]      },      "finish_reason""tool_calls"    }  ]}

注意这里 一次返回了两个 tool_calls——这是 OpenAI 协议支持的并行 tool calling。LLM 判断这两个检查互相独立,所以同时发起。

09

第 5 步:工具结果回传

Cursor 并行执行两个 tool call,然后把结果都塞进 messages:

{  "messages": [    "(...之前的所有消息...)",    {      "role": "assistant",      "tool_calls": [        { "id": "call_def456", "function": { "name": "Shell", "arguments": "..." } },        { "id": "call_ghi789", "function": { "name": "Read", "arguments": "..." } }      ]    },    {      "role": "tool",      "tool_call_id": "call_def456",      "content": "/usr/local/go/bin/mp-read"    },    {      "role": "tool",      "tool_call_id": "call_ghi789",      "content": "skey=xxxxxxx; p_skey=yyyyyyy; RIO_TCOA=zzzzzz..."    }  ]}

10

第 6 步:LLM 执行核心命令

前置检查通过,LLM 按照 SKILL.md 中的 Usage 章节,构造并发起实际的 mp-read 命令:

{  "choices": [    {      "message": {        "role""assistant",        "content": null,        "tool_calls": [          {            "id""call_jkl012",            "type""function",            "function": {              "name""Shell",              "arguments""{\"command\"\"mp-read 2026/0316_mp_read/cookie.txt 'https://mp.weixin.qq.com/s/HHPK6QvclYaxlDg28elN8w'\"\"description\"\"Extract MP article text\"\"block_until_ms\": 120000}"            }          }        ]      },      "finish_reason""tool_calls"    }  ]}

注意 block_until_ms: 120000——这正是 SKILL.md 中明确要求的。LLM 从 Skill 文档中"学到"了这个参数应该设多大。

11

第 7 步:最终响应

Shell 执行完毕,mp-read 的 stdout 输出(文章全文)通过 role: "tool" 消息回传给 LLM。LLM 最终生成一个 role: "assistant" 的纯文本响应,把文章内容整理后呈现给用户:

{  "choices": [    {      "message": {        "role""assistant",        "content""这篇公众号文章的内容如下:\n\n# 文章标题\n\n文章正文内容...",        "tool_calls": null      },      "finish_reason""stop"    }  ]}

12

景图:从协议视角看 Skill 生命周期

把上面 7 步画成一张协议交互时序图:

                Cursor (客户端)                              LLM (服务端)                     │                                          │   ┌─────────────────┤                                          │   │ 启动时扫描 skill │                                          │   │ 目录,提取 name  │                                          │   │ + description   │                                          │   └────────┬────────┘                                          │            │                                                   │   Round 1  │  POST /chat/completions                           │            │  system: "...skills摘要..." + tools: [Shell,Read] │            │  user: "帮我读一下 https://mp.weixin.qq.com/s/HHPK6QvclYaxlDg28elN8w"     │            │ ─────────────────────────────────────────────────> │            │                                                   │            │  assistant.tool_calls: Read(SKILL.md)             │            │ <───────────────────────────────────────────────── │            │                                                   │   ┌────────┤  执行: Read(SKILL.md)                              │   └────────┤                                                   │            │                                                   │   Round 2  │  tool: (SKILL.md 完整内容)                          │            │ ─────────────────────────────────────────────────> │            │                                                   │  ← LLM 现在 "学会" 了这个 Skill            │  assistant.tool_calls:                             │            │    Shell("which mp-read")                         │            │    Read(cookie.txt)                                │            │ <───────────────────────────────────────────────── │            │                                                   │   ┌────────┤  并行执行两个 tool call                              │   └────────┤                                                   │            │                                                   │   Round 3  │  tool: "/usr/local/go/bin/mp-read"                │            │  tool: "skey=xxx;p_skey=yyy..."                   │            │ ─────────────────────────────────────────────────> │            │                                                   │            │  assistant.tool_calls:                             │            │    Shell("mp-read cookie.txt 'URL'",              │            │           block_until_ms=120000)                   │            │ <───────────────────────────────────────────────── │            │                                                   │   ┌────────┤  执行: mp-read(耗时 ~30s)                          │   └────────┤                                                   │            │                                                   │   Round 4  │  tool: (文章全文)                                   │            │ ─────────────────────────────────────────────────> │            │                                                   │            │  assistant.content: "这篇文章的内容如下:..."         │            │  finish_reason: "stop"                             │            │ <───────────────────────────────────────────────── │            ▼                                                   ▼

13

总结:Skill 的协议映射表
Skill 概念
协议映射
Skill 发现(scan directories)
纯客户端行为,不涉及协议
Skill 摘要(name + description)
注入到 messages[0].role = "system" 的文本中
Skill 加载(读取 SKILL.md)
LLM 发起 tool_calls: [Read(SKILL.md)],结果通过 role: "tool" 回传
Skill 指令执行
LLM 按读到的 SKILL.md 内容,自主发起后续 tool_calls
Skill 的 "Progressive Loading"
先在 system prompt 放摘要(省 token),LLM 需要时再 Read 全文
Skill 的 "scripts/" 目录
LLM 通过 Shell tool call 执行脚本
Skill 的 "references/" 目录
LLM 通过 Read tool call 按需读取参考文档

核心洞察:Skill 在协议层面完全不存在。它是一种"给 LLM 写使用手册,让 LLM 通过已有工具自己照着做"的设计模式。 整个过程就是:

  1. 在 system prompt 里告诉 LLM "你有这些技能手册可以查"

  2. LLM 通过 Read 工具自己去读手册

  3. LLM 读完手册后,按手册说的步骤,通过 Shell/Read 等工具一步步执行

这种设计的精妙之处在于:它完全复用了 OpenAI 协议已有的 tool calling 机制,不需要任何协议扩展。 Skill 的全部"魔法"都发生在 system prompt 的措辞和 SKILL.md 文件的编写质量上——本质上是一种 prompt engineering + 文件系统的组合。总结一下:

一个简简单单的对话功能,人类真的是能够玩出花来,语言不愧是高智慧的人类区别于动物的一个重要特征呀!

-End-
欢迎校招和社招同学加入极客星球圈子,让我们在AI时代,加速成长,提升职场认知,快速找到好工作:
  • 提高自己技术(稳固核心:分享多年基础技术深度理解,基础概念深度解析,经典书籍推荐和读书分享,经典源码阅读分享等,不定期直播分享和答疑解惑,打好技术基础;

  • 扩展认知和视野:分享热门技术发展,国内外大厂技术内幕,建立国际化视野,转型, 副业等,提升你对社会认知能力,尽早发现自己特长,做好职业规划;

  • 找到好工作简历优化,职位分析,面试指导,就业指导,职业发展,职位内推等,全面提升面试成功率,校招/社招就业指导;

  • 职场发展:分享各种不同公司宝贵的职场普升经验,技术方向选择, 大厂普升经验,技术专家成长经验,让你少走几年的弯路,让工作三年的你提早拥有高质量10年+工作经验的认知

  • 人脉:专属高质量VIP交流群,最新技术趋势,分享技术热点,分享学习心得,学习工作讨论(群里有在各个大厂工作的的同学),可以相互请教和学习,工作机会内推和推荐,大厂职位内幕等等;

星球有深入理解系列经典PDF资料(进大厂的秘密武器,基础知识大局观,加深理解,帮助你提升学习效率,加快修炼):
  • 深入理解计算机系统(计算,存储,网络)

  • 深入理解操作系统(调度,内存,网络,IO)

  • 深入理解并发技术全景指南

  • 深入理解编程语言

  • 深入理解算法与数据结构

  • 深入理解网络协议

  • 深入理解网络编程

  • 深入理解性能优化  (进大厂或升级高级工程师的核心能力)

  • 深入理解分布式技术(互联网大厂必备核心技能)

现在加入超级优惠,早点加入一起学习成长,早点突破成长瓶颈:

  坚持分享干货内容,专注帮助大家找到offer,欢迎大家关注极客重生 

推荐阅读:

大厂招聘究竟在筛选什么样的人?一张图讲透核心能力体系

大厂编程一夜转型。。。

AI编程未来真的会取代程序员吗?

Notion创始人年终AI思考:清醒而深刻

腾讯员工爆料:10级老兵体面毕业!55k底薪+6个月年终

2025 互联网顶级大厂程序员职级薪资表

《建议收藏 | 我用这份独家“面试心法”,带无数普通人闯进了大厂》

大厂公积金缴纳比例排行榜(2025最新版)

深入理解简历,面试,职场

国内最难入职的 IT 公司排行

大龄牛马接到了腾讯的offer

腾讯员工爆料: "任职5年多,薪资为45k×16,加上股票年入约90万。曾拿到阿里的P8、140万年薪的offer却拒绝了。"

国内 IT 公司时薪排行榜