- 为什么团队需要 Skill,而不是零散 Prompt
很多团队在接入 AI Agent 的初期,都会经历一个共同阶段:先让模型“直接回答”,发现输出不稳定;再把经验写进 Prompt;最后发现 Prompt 到处散落,版本失控、风格不一、合规不可控。
典型现象如下:
| 场景 | 没有 Skill 的问题 | 引入 Skill 后的变化 |
|---|---|---|
| 代码生成 | 每次目录结构、日志规范、异常处理都不同 | 统一脚手架、统一编码约束、统一交付格式 |
| 代码评审 | 只会泛泛而谈,缺少团队规则 | 可注入 Check List、架构红线、发布约束 |
| 故障排查 | 回答“像对的”,但不符合 SRE SOP | 严格按告警确认、影响评估、根因定位、止血回滚执行 |
| 架构设计 | 只会讲通用方案,不结合现网环境 | 可以绑定组织中间件、容量模型、SLA、成本边界 |
| 合规审计 | 无法知道模型依据什么规则输出 | Skill 可审计、可回放、可追责 |
所以,Skill 的核心价值不是“提示词复用”,而是把组织经验从“口口相传”升级为“Agent 可执行的制度化资产”。
一句话概括:
Prompt 面向一次对话,Skill 面向长期治理。
- Skill 的本质:给 Agent 安装组织级“行为约束”
从架构视角看,Skill 可以理解为一种轻量级的 Agent Capability Package。它至少包含三层内容:
┌──────────────────────────────────────────────┐│ 元数据层 Metadata ││ name / description / owner / version / tags │├──────────────────────────────────────────────┤│ 指令层 Instructions ││ 流程、约束、输出模板、决策规则、禁令 │├──────────────────────────────────────────────┤│ 资产层 Assets / References ││ 文档、脚本、Schema、模板、样例、规范 │└──────────────────────────────────────────────┘
这三层分别解决不同问题:
- • 元数据层解决“如何被发现”和“如何被路由”。
- • 指令层解决“模型应该如何做事”。
- • 资产层解决“模型做事时可以参考什么事实依据”。
很多文章把 Skill 讲成一份 Markdown 文件,这种说法不算错,但不够完整。对生产系统来说,Skill 更像“带治理属性的能力包”,它既参与 Prompt 构建,也参与权限控制、缓存策略、审计流程和版本演进。
- Skill 文件语法总览
一个标准 Skill 通常位于如下目录:
.opencode/skills/order-review/SKILL.md
最小可用结构如下:
---name: order-reviewdescription: 审查订单域代码,重点检查事务边界、幂等性、库存一致性和审计日志version: 1.2.0owner: commerce-archtags: - java - spring-boot - review - order-domain---# 角色你是负责电商订单域的资深架构师和 Reviewer。# 工作目标收到代码评审请求时,优先检查:- 事务传播行为- 幂等 Token 使用- 库存扣减一致性- MQ 发送与本地事务顺序# 输出要求必须按以下结构输出:1. 风险摘要2. 严重问题3. 中等级问题4. 建议改进项5. 是否建议合并
从语法上看,Skill 并不复杂,但难点在于“如何把它写成真正能稳定驱动 Agent 的结构化说明书”。后文会从语法、运行时、工程治理三个层面展开。
- Frontmatter 设计规范
Frontmatter 是 Skill 的索引区。它直接影响发现效率、匹配准确率、权限治理粒度和版本演进能力。
4.1 推荐字段
建议至少具备以下字段:
---name: microservice-scaffolddescription: 生成符合团队规范的 Go 微服务脚手架,包含 RPC、配置、日志、缓存和观测埋点version: 2.1.0owner: platform-teamlicense: internaltags: - go - scaffold - backend - microservicecompatibility: - opencode - claude-codemetadata: domain: platform language: go maturity: production risk: medium---
字段说明:
| 字段 | 是否必须 | 说明 |
|---|---|---|
name | 是 | Skill 唯一标识,建议使用 kebab-case |
description | 是 | 给 Agent 做第一轮匹配的短描述 |
version | 否但强烈建议 | 便于灰度、回滚、兼容性判断 |
owner | 否但强烈建议 | 标记责任团队,便于治理 |
tags | 否 | 提高分类与召回准确率 |
compatibility | 否 | 标识适用平台 |
metadata | 否 | 扩展字段,适用于组织自定义治理 |
4.2 name 设计原则
name 不只是文件名,它经常被用于:
- • 路由选择
- • 权限匹配
- • 审计统计
- • 版本兼容判断
- • 运行时缓存键
建议规则:
- • 使用
kebab-case - • 避免使用含义宽泛的名字,如
reviewer、assistant - • 尽量体现“领域 + 动作”,如
k8s-incident-response、java-ddd-review - • 与目录名保持一致,降低发现与加载阶段的不一致风险
示例:
.opencode/skills/java-ddd-review/SKILL.mdname: java-ddd-review
4.3 description 不是摘要,而是“召回提示”
很多人会把 description 写得很文学化,例如:
description: 一个强大而全面的企业级开发助手
这类描述几乎没有路由价值。好的 description 要包含三个信息:
- 处理对象
- 执行动作
- 关键约束或边界
更好的写法:
description: 审查 Spring Boot 订单服务代码,重点检查事务一致性、幂等控制、缓存击穿和 MQ 最终一致性问题
这类描述更利于:
- • Agent 语义匹配
- • 规则引擎做关键词过滤
- • 平台做技能分类
4.4 生产环境扩展字段建议
对于企业内部 Skill 平台,Frontmatter 往往还会扩展以下字段:
metadata: environment: production auth_scope: sre cost_tier: high token_budget: 6000 data_classification: internal review_required: true deprecated: false
这些字段可以接入权限和治理链路,例如:
- •
token_budget决定预加载还是延迟加载 - •
review_required决定是否必须人工确认 - •
deprecated决定是否从路由结果中降权 - •
data_classification决定是否允许在低安全会话加载
- Instructions 指令体怎么写才真正可执行
Skill 的成败,80% 取决于 Instructions 是否可执行。所谓“可执行”,不是语言看起来专业,而是模型拿到后能稳定形成可复现的行为。
5.1 一个高质量 Skill 指令体应该包含什么
推荐采用下面的结构:
# 角色# 适用场景# 输入信息清单# 执行流程# 决策规则# 输出格式# 约束与禁令# 失败处理
每一部分的作用不同:
| 区块 | 作用 |
|---|---|
角色 | 给模型明确身份和视角 |
适用场景 | 避免 Skill 被误用 |
输入信息清单 | 约束用户必须提供哪些上下文 |
执行流程 | 把任务拆成稳定的步骤 |
决策规则 | 处理分支逻辑与优先级冲突 |
输出格式 | 保证结果可消费、可审阅 |
约束与禁令 | 防止模型自由发挥 |
失败处理 | 防止缺信息时胡乱补全 |
5.2 写 Skill 时最重要的原则:流程化,不要散文化
差的写法:
请帮我优雅地检查代码,并尽可能给出高质量建议。
好的写法:
## 执行流程1. 先确认本次评审对象是 Controller、Service、Repository 还是配置变更。2. 如果涉及数据库写操作,必须检查事务边界与幂等性。3. 如果涉及缓存,必须检查缓存更新策略、空值缓存、热点 Key 风险。4. 如果涉及 MQ,必须检查消息发送时机、重试策略和死信处理。5. 最终按严重级别输出问题,不要只输出建议。
区别在于:
- • 前者是“愿望表达”。
- • 后者是“行为编排”。
5.3 决策规则要显式,不能让模型自己猜你更在乎什么
例如代码评审场景,决策规则可以写成:
## 决策优先级发现冲突时,按以下优先级判断:1. 正确性与数据一致性2. 安全性与权限边界3. 性能与资源消耗4. 可维护性与代码风格如果存在 P0/P1 级问题,不要被代码风格优点稀释结论。
这会显著提升输出稳定性。因为模型知道当多个问题同时存在时,应该如何排序。
5.4 输出格式要为“后续系统消费”设计
生产环境下,Skill 输出通常不会只给人看,还可能被:
- • 前端渲染
- • 自动化审核系统读取
- • 审计系统归档
- • 二次 Agent 链路继续消费
所以建议固定输出结构。例如:
## 评审结论- 风险等级: high- 是否建议合并: no## 严重问题1. ...## 中等级问题1. ...## 建议改进1. ...## 需要补充的信息1. ...
如果平台支持结构化输出,甚至可以要求 JSON:
{ "riskLevel": "high", "mergeRecommendation": "reject", "findings": [ { "severity": "critical", "title": "库存扣减与订单落库不在同一事务边界", "reason": "可能出现已扣库存但订单创建失败", "suggestion": "使用本地事务 + Outbox 或事务消息" } ]}
5.5 Skill 中要明确“不会做什么”
这是很多文章容易忽略的点。生产级 Skill 不仅要告诉模型“做什么”,更要约束“不要做什么”。
例如:
## 禁止事项- 禁止凭空假设数据库表结构- 禁止在没有证据时判断根因为代码 Bug- 禁止建议在生产高峰期直接重启核心服务- 禁止输出“看起来可能”但没有命令或日志依据的结论
这类禁令能显著降低幻觉和误操作风险。
- References 与外部资产组织方式
只靠一份 Skill 主文件,通常不足以覆盖复杂生产任务。真正的企业 Skill 往往依赖大量外部资产:
- • 架构图
- • SQL Schema
- • OpenAPI 文档
- • Helm 模板
- • 部署手册
- • 代码模板
- • Runbook
- • 示例输入输出
建议目录结构如下:
.opencode/skills/└── microservice-scaffold/ ├── SKILL.md ├── references/ │ ├── architecture.md │ ├── coding-standard.md │ ├── error-code-spec.md │ └── api-contract.yaml ├── templates/ │ ├── main.go.tmpl │ ├── application.yaml.tmpl │ └── Dockerfile.tmpl └── examples/ ├── input.md └── output.md
6.1 为什么要把参考资产拆出来
原因主要有四个:
- 降低主 Skill 体积,减少 token 成本
- 便于按需加载,避免不相关上下文污染
- 便于不同 Skill 复用同一份规范资产
- 便于单独版本化和审阅
6.2 参考资产的使用原则
- • 主 Skill 只保留决策主流程和必须规则
- • 大篇幅规范放到
references/ - • 模板文件放到
templates/ - • 示例放到
examples/ - • 通过“需要时读取”的方式按需加载,而不是一次性全注入
6.3 示例:在 Skill 中显式指导 Agent 读取外部资产
## 参考资料使用规则如果任务是生成服务代码,优先读取:- references/coding-standard.md- templates/main.go.tmpl- templates/application.yaml.tmpl如果任务涉及错误处理,必须读取:- references/error-code-spec.md如果用户输入信息不足,不要猜测,先列出缺失字段。
这能让 Agent 的行为更加稳定,因为它知道该去哪里找依据。
- Skill 发现、匹配、加载的运行原理
这一部分是很多文章缺失的重点。理解运行原理,才能真正把 Skill 平台做成工程系统,而不是“能跑的 Demo”。
7.1 发现:从文件系统到 Skill Catalog
典型发现路径如下:
当前工作目录 ├── .opencode/skills/<name>/SKILL.md ├── .claude/skills/<name>/SKILL.md ├── .agents/skills/<name>/SKILL.md └── 向上遍历直到 git worktree root全局目录 ├── ~/.config/opencode/skills/<name>/SKILL.md ├── ~/.claude/skills/<name>/SKILL.md └── ~/.agents/skills/<name>/SKILL.md
发现流程可抽象为:
扫描目录 -> 校验结构 -> 解析 frontmatter -> 建立索引 -> 写入 Catalog
示意数据结构:
interface SkillIndexEntry { name: string; path: string; description: string; version?: string; tags?: string[]; source: "workspace" | "global" | "remote"; priority: number; checksum: string;}
7.2 匹配:从用户意图到候选 Skill 集合
Skill 匹配通常分为三层:
- 规则过滤
- 语义召回
- 权限裁剪
流程如下:
用户请求 -> 意图解析 -> 基于 name/description/tags 做候选召回 -> 结合 agent 类型做白名单过滤 -> 根据权限策略做 allow/ask/deny 裁剪 -> 得到最终可加载的 Skill 集
生产环境中,匹配不应只靠 embedding 或 LLM 语义召回。更推荐“规则 + 语义”的混合式:
- • 高频明确场景走规则匹配,快且稳定
- • 长尾复杂场景走语义召回,提高覆盖率
7.3 加载:为什么要坚持懒加载
Skill 不适合启动时全量注入,原因很简单:
- • Token 成本高
- • 上下文污染严重
- • 无关 Skill 会干扰模型决策
- • 大规模 Skill 会拉高冷启动延迟
合理做法是懒加载:
Catalog 只保存摘要 -> 命中候选 Skill -> 按优先级逐个加载正文 -> 必要时再加载 references/templates -> 拼装到最终推理上下文
7.4 注入:Skill 为什么本质上是 Prompt Runtime 的一部分
Skill 最终不是“注册到内存里”的配置项,而是被注入到模型推理上下文中的内容片段。因此它天然受到以下约束:
- • 超长 Skill 会压缩有效上下文窗口
- • Skill 越多,推理路径越复杂
- • 注入顺序会影响模型关注权重
- • 同时加载多个 Skill 时可能发生指令冲突
这也是为什么生产系统必须有:
- • Token 预算
- • 指令冲突检测
- • 按场景分层注入
- • 热点 Skill 摘要化
7.5 一个完整的运行时链路
用户输入 -> Agent 分类当前任务 -> Skill Router 查询 Catalog -> Permission Engine 判定可见性 -> Loader 读取 SKILL.md -> Reference Resolver 按需加载外部资产 -> Prompt Builder 组装上下文 -> LLM 推理 -> Audit Hook 记录本次 Skill 使用情况
- 生产级 Skill 引擎架构设计
当 Skill 数量从 10 个增长到 1000 个,系统设计重点会从“怎么写 Skill”转向“怎么管理 Skill”。
8.1 总体架构
┌──────────────────────────────────────────────────────────┐│ Client Layer ││ CLI / IDE Plugin / Desktop App / Web Console │└──────────────────────────┬───────────────────────────────┘ │┌──────────────────────────▼───────────────────────────────┐│ Agent Runtime ││ Planner Agent / Code Agent / Review Agent / SRE Agent │└──────────────────────────┬───────────────────────────────┘ │┌──────────────────────────▼───────────────────────────────┐│ Skill Control Plane ││ Catalog / Router / Permission / Audit / Policy Engine │└──────────────────────────┬───────────────────────────────┘ │┌──────────────────────────▼───────────────────────────────┐│ Skill Data Plane ││ Loader / Cache / Template Resolver / Reference Reader │└──────────────────────────┬───────────────────────────────┘ │┌──────────────────────────▼───────────────────────────────┐│ Storage Layer ││ Local FS / Git Repo / Object Store / OCI / Registry │└──────────────────────────────────────────────────────────┘
8.2 为什么要分 Control Plane 和 Data Plane
这是工程化升级的关键。
Control Plane 负责:
- • Skill Catalog 管理
- • 权限校验
- • 元数据检索
- • 版本灰度
- • 审计追踪
Data Plane 负责:
- • Skill 正文读取
- • 模板解析
- • 外部资产按需加载
- • 本地缓存
- • Prompt 组装
分层之后的好处:
- • 管理逻辑和加载逻辑解耦
- • 可以单独横向扩容
- • 权限和审计不需要依赖 LLM Runtime
- • 便于做远程 Registry 与本地缓存协同
8.3 核心领域模型
interface SkillMetadata { name: string; description: string; version?: string; owner?: string; tags?: string[]; metadata?: Record<string, string | number | boolean>;}interface SkillDocument { metadata: SkillMetadata; path: string; instructions: string; references: SkillReference[]; checksum: string; tokenCount: number; loadedAt: number;}interface SkillReference { type: "doc" | "template" | "schema" | "example" | "script"; path: string; checksum?: string; optional?: boolean;}interface SkillPermissionRule { subject: string; pattern: string; action: "allow" | "ask" | "deny";}
8.4 一套更接近生产的加载器实现
下面给出一个 Node.js 风格的生产级 Skill Loader 示例,重点展示:
- • Frontmatter 解析
- • 缓存复用
- • 文件变更检测
- • 并发安全
import fs from "node:fs/promises";import path from "node:path";import crypto from "node:crypto";import matter from "gray-matter";type SkillMetadata = { name: string; description: string; version?: string; owner?: string; tags?: string[]; metadata?: Record<string, string | number | boolean>;};type SkillDocument = { metadata: SkillMetadata; path: string; instructions: string; checksum: string; mtimeMs: number; tokenCount: number;};class SkillCache { private readonly docs = new Map<string, SkillDocument>(); private readonly inflight = new Map<string, Promise<SkillDocument>>(); get(key: string): SkillDocument | undefined { return this.docs.get(key); } set(key: string, value: SkillDocument): void { this.docs.set(key, value); } getInflight(key: string): Promise<SkillDocument> | undefined { return this.inflight.get(key); } setInflight(key: string, promise: Promise<SkillDocument>): void { this.inflight.set(key, promise); } clearInflight(key: string): void { this.inflight.delete(key); }}export class SkillLoader { constructor(private readonly cache = new SkillCache()) {} async load(skillFilePath: string): Promise<SkillDocument> { const normalizedPath = path.resolve(skillFilePath); const stat = await fs.stat(normalizedPath); const cacheKey = normalizedPath; const cached = this.cache.get(cacheKey); if (cached && cached.mtimeMs === stat.mtimeMs) { return cached; } const existingInflight = this.cache.getInflight(cacheKey); if (existingInflight) { return existingInflight; } const loadPromise = this.doLoad(normalizedPath, stat.mtimeMs); this.cache.setInflight(cacheKey, loadPromise); try { const loaded = await loadPromise; this.cache.set(cacheKey, loaded); return loaded; } finally { this.cache.clearInflight(cacheKey); } } private async doLoad(skillFilePath: string, mtimeMs: number): Promise<SkillDocument> { const raw = await fs.readFile(skillFilePath, "utf8"); const parsed = matter(raw); const metadata = parsed.data as SkillMetadata; this.validate(metadata, skillFilePath); const checksum = crypto .createHash("sha256") .update(raw) .digest("hex"); return { metadata, path: skillFilePath, instructions: parsed.content.trim(), checksum, mtimeMs, tokenCount: estimateTokens(parsed.content), }; } private validate(metadata: SkillMetadata, skillFilePath: string): void { if (!metadata.name || !metadata.description) { throw new Error(`Invalid skill: missing name/description in ${skillFilePath}`); } }}function estimateTokens(text: string): number { return Math.ceil(text.length / 4);}
这个实现看似简单,但已经体现了生产要点:
- • 基于
mtime做快速缓存失效判断 - • 用
inflight避免并发重复加载同一 Skill - • 对 metadata 做最小校验
- • 预估 token,便于路由器做预算控制
- 工程化升级:高并发、缓存、扩展性与稳定性
这一章重点回答一个问题:
当一个企业内部有数百个 Agent、上千个 Skill、每秒几十到上百次会话请求时,Skill 平台如何不成为瓶颈?
9.1 高并发下的四类核心问题
| 问题 | 表现 | 根因 |
|---|---|---|
| 重复 I/O | 同一热门 Skill 被反复读取 | 没有本地缓存和并发合并 |
| Token 膨胀 | 上下文成本急剧上升 | 技能过多、正文过长、无摘要 |
| 指令冲突 | 多个 Skill 给出相反约束 | 缺少优先级和组合策略 |
| 远程依赖抖动 | Registry 慢导致会话延迟 | 没有本地镜像和降级策略 |
9.2 缓存分层设计
推荐采用三级缓存:
L1: 进程内内存缓存L2: 本地磁盘缓存L3: 远程 Registry / Git / Object Store
加载链路:
请求到来 -> 查 L1 -> miss 后查 L2 -> miss 后从 L3 拉取 -> 回填 L2 / L1
缓存内容建议分层:
- • 元数据 Catalog 缓存
- • Skill 正文缓存
- • Reference 缓存
- • 模板渲染结果缓存
- • Token 统计结果缓存
9.3 热点 Skill 的并发合并
高并发场景下,如果多个请求同时命中同一 Skill,必须避免惊群式加载。
关键思路:
- • 同一个 Skill 同一版本只允许一个加载任务
- • 其他请求等待这次加载完成后复用结果
- • 失败时及时清理 inflight 标记,避免死锁
这就是前面 inflight Map 的意义。
9.4 Skill 组合不是越多越好
很多团队在性能出问题时会只盯着 I/O,但更大的成本常常来自 Prompt 侧。
例如一次请求同时注入:
- • 代码规范 Skill
- • 安全审查 Skill
- • 架构评审 Skill
- • 数据库规范 Skill
- • 可观测性规范 Skill
结果可能是:
- • token 爆炸
- • 指令重叠
- • 模型注意力被稀释
- • 最终输出反而变差
正确做法是“主 Skill + 辅助摘要 + 按需引用”:
主 Skill 决定当前任务主流程辅助 Skill 只注入摘要和关键约束详细规范按引用文件二次加载
9.5 大规模 Skill 的 Pointer 模式
当 Skill 数量达到 500+ 时,建议引入分类指针 Skill。
示例:
---name: backend-category-pointerdescription: 后端开发技能目录入口,包含 Go、Java、Python 服务开发、审查和发布规范---# 使用方式当任务属于后端开发时,先查看以下候选子 Skill:- go-microservice-scaffold- java-spring-review- sql-performance-review- cache-consistency-review只有在任务明确命中后,才继续读取对应子 Skill。
这样做的收益:
- • Catalog 更轻
- • 工具描述更短
- • 召回更聚焦
- • 冷启动更快
9.6 远程 Registry 的降级策略
如果 Skill 已经远程化存储,必须考虑网络异常。
生产建议:
- • 本地保留最近 N 个稳定版本
- • Registry 不可用时优先回退本地缓存
- • 高风险 Skill 必须显式标注“不可离线使用”或“可离线只读”
- • 对远程下载设置超时、校验和、重试上限
9.7 可扩展性设计:不要把 Skill Engine 写死成单体
建议预留以下扩展点:
| 扩展点 | 用途 |
|---|---|
SkillSource | 支持本地、Git、OCI、对象存储等多种来源 |
PermissionProvider | 支持本地配置、RBAC、OPA、策略中心 |
ReferenceResolver | 支持本地引用、HTTP 拉取、模板渲染 |
AuditSink | 支持写文件、Kafka、ES、SIEM |
PromptComposer | 支持不同 Agent 的拼装策略 |
这会让 Skill 平台从“工具实现”升级为“能力基础设施”。
- 案例一:企业级微服务脚手架 Skill
这一节我们把 Skill 真正落到业务场景。
10.1 场景设定
某电商平台技术栈如下:
- • 语言:Go
- • 通信:Kitex / gRPC
- • 注册发现:Nacos
- • 存储:MySQL + Redis
- • 消息:Kafka
- • 观测:OpenTelemetry + Prometheus + Loki
- • 部署:Kubernetes
目标:让 Agent 生成的新微服务从第一天起就满足团队规范,而不是“生成后再人工返工”。
10.2 Skill 定义
创建文件:
.opencode/skills/microservice-scaffold/SKILL.md
完整示例如下:
---name: microservice-scaffolddescription: 生成符合团队规范的 Go 微服务脚手架,包含 RPC、配置中心、日志、缓存、MQ 和可观测性埋点version: 2.1.0owner: platform-teamtags: - go - scaffold - microservice - kitexmetadata: language: go maturity: production risk: medium---# 角色你是负责中后台基础架构的资深 Go 架构师。# 适用场景用户要求生成新的后端微服务,且项目技术栈为 Go + Kitex + MySQL + Redis + Kafka。# 输入信息清单如果用户没有明确提供,必须先确认:- 服务名称- 服务职责- 对外协议类型(HTTP / RPC / MQ Consumer)- 数据表或聚合根- 是否需要缓存- 是否需要事件发布- 是否需要定时任务# 执行流程1. 先确认服务边界,不要把多个领域职责混到同一个服务。2. 生成目录结构时,必须遵循团队标准分层。3. 业务逻辑进入 service 层,禁止写在 handler 中。4. 所有数据库写操作必须考虑事务边界和幂等性。5. 所有跨服务调用必须带超时、重试和 trace 信息。6. 所有关键流程必须预埋日志、指标、链路追踪。7. 最终输出文件清单、启动方式、配置项说明和待人工确认项。# 目录结构约束必须输出以下目录结构:```textcmd/server/main.gointernal/config/internal/handler/internal/service/internal/repository/internal/model/internal/cache/internal/mq/internal/transport/pkg/logx/pkg/errorsx/conf/default.yamlconf/online.yamlMakefileDockerfileREADME.md
工程约束
- • 禁止使用全局变量保存业务依赖
- • 禁止使用 init() 初始化核心组件
- • 依赖注入必须通过构造函数
- • 所有配置必须可通过环境变量或配置中心覆盖
- • 所有外部调用必须设置 timeout
- • 所有错误必须归类,不允许直接向上抛裸错误字符串
输出格式
必须按以下格式输出:
- 服务设计说明
- 目录结构
- 核心代码
- 配置样例
- 启动命令
- 待人工确认项
### 10.3 配套模板文件仅有 Skill 还不够,最好搭配模板文件。例如 `templates/main.go.tmpl`:```gopackage mainimport ( "context" "os" "os/signal" "syscall" "time" "go.uber.org/zap")type App struct { logger *zap.Logger server Server}func NewApp(logger *zap.Logger, server Server) *App { return &App{ logger: logger, server: server, }}func (a *App) Run(ctx context.Context) error { if err := a.server.Start(ctx); err != nil { return err } stopCh := make(chan os.Signal, 1) signal.Notify(stopCh, syscall.SIGINT, syscall.SIGTERM) select { case <-ctx.Done(): case <-stopCh: } shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() return a.server.Stop(shutdownCtx)}
这个模板体现了几个生产约束:
- • 有统一生命周期管理
- • 支持优雅停机
- • 不依赖全局状态
- • 明确 shutdown 超时
10.4 生产级代码补全:统一错误模型
下面给出一个更接近生产的错误定义:
package errorsximport "fmt"type Code stringconst ( CodeInvalidArgument Code = "INVALID_ARGUMENT" CodeNotFound Code = "NOT_FOUND" CodeConflict Code = "CONFLICT" CodeInternal Code = "INTERNAL")type Error struct { Code Code Message string Cause error}func (e *Error) Error() string { if e.Cause == nil { return fmt.Sprintf("%s: %s", e.Code, e.Message) } return fmt.Sprintf("%s: %s: %v", e.Code, e.Message, e.Cause)}func Wrap(code Code, message string, cause error) error { return &Error{ Code: code, Message: message, Cause: cause, }}
为什么要在 Skill 中强制统一错误模型?
- • 便于 API 层映射 HTTP / RPC 状态码
- • 便于日志和告警分类
- • 便于业务错误与系统错误分离
- • 便于审计和可观测平台聚合
10.5 生产级代码补全:带 trace 的 Service 逻辑
package serviceimport ( "context" "time" "go.uber.org/zap")type OrderRepository interface { Create(context.Context, CreateOrderParam) (int64, error)}type InventoryGateway interface { Reserve(context.Context, ReserveInventoryRequest) error}type Publisher interface { Publish(context.Context, string, []byte) error}type OrderService struct { logger *zap.Logger repo OrderRepository inventoryGateway InventoryGateway publisher Publisher}func NewOrderService( logger *zap.Logger, repo OrderRepository, inventoryGateway InventoryGateway, publisher Publisher,) *OrderService { return &OrderService{ logger: logger, repo: repo, inventoryGateway: inventoryGateway, publisher: publisher, }}func (s *OrderService) CreateOrder(ctx context.Context, req CreateOrderRequest) (int64, error) { start := time.Now() log := s.logger.With(zap.String("trace_id", TraceIDFromContext(ctx))) if err := req.Validate(); err != nil { return 0, err } if err := s.inventoryGateway.Reserve(ctx, ReserveInventoryRequest{ SkuID: req.SkuID, Qty: req.Qty, }); err != nil { log.Error("reserve inventory failed", zap.Error(err)) return 0, err } orderID, err := s.repo.Create(ctx, CreateOrderParam{ UserID: req.UserID, SkuID: req.SkuID, Qty: req.Qty, }) if err != nil { log.Error("create order failed", zap.Error(err)) return 0, err } if err := s.publisher.Publish(ctx, "order.created", MarshalOrderCreated(orderID)); err != nil { log.Error("publish order event failed", zap.Error(err)) return 0, err } log.Info("create order success", zap.Int64("order_id", orderID), zap.Duration("cost", time.Since(start)), ) return orderID, nil}
这段代码还不是完整业务系统,但已经体现了 Skill 应该推动 Agent 生成的几个生产特征:
- • 上下文贯穿
- • 依赖可替换
- • 日志可观测
- • 外部调用可封装
- • 关键路径有时延统计
10.6 场景价值
当团队真正使用这种 Skill 后,Agent 生成的不再是“能编译的示例”,而是“符合组织标准的初始可交付版本”。这会明显减少:
- • 架构师重复讲规范
- • Reviewer 重复提相同问题
- • 新人对项目结构理解成本
- • 服务间工程质量差异
- 案例二:Kubernetes 故障排查与自愈 Skill
第二个案例更能体现 Skill 的运行价值,因为它直接关联生产稳定性。
11.1 场景设定
凌晨 2 点,订单服务大量 Pod 进入 CrashLoopBackOff。如果没有 Skill,模型可能只会给出一些泛泛建议;如果有 SRE Skill,它就会按组织 SOP 行动。
11.2 Skill 定义
---name: sre-incident-responsedescription: 按照团队 SRE SOP 处理 Kubernetes 集群故障,覆盖 Pod 异常、节点故障、网络故障和依赖异常version: 3.0.0owner: sre-teamtags: - kubernetes - incident - sre - productionmetadata: environment: production auth_scope: sre review_required: true risk: high---# 角色你是生产值班 SRE,必须优先保障服务恢复,而不是给出泛泛分析。# 适用场景- Pod CrashLoopBackOff- Pod OOMKilled- Node NotReady- Service 无 Endpoint- DNS 或 CNI 异常# 执行流程1. 先确认告警真实性,避免误报。2. 评估影响面,确认是否为单实例、单可用区还是全局故障。3. 根据现象进入对应分支排查。4. 所有结论必须基于命令输出、日志或事件,不允许猜测。5. 如果达到 P0/P1 等级,优先止血,再做根因分析。# 命令规范优先执行:- kubectl get pods -A- kubectl describe pod- kubectl logs --previous- kubectl get events --sort-by=.lastTimestamp- kubectl get endpoints如果需要跨节点排查,再进入节点级命令。# 禁止事项- 禁止直接删除全部 Pod- 禁止在没有确认副本冗余的前提下重启核心服务- 禁止修改生产 Secret- 禁止在没有变更记录的情况下手工改 Deployment 配置# 输出格式必须输出:1. 事故等级2. 影响范围3. 已执行命令与证据4. 根因判断5. 止血动作6. 后续行动项
11.3 运行时如何触发
用户输入:
order-svc 一直重启,看看什么问题
匹配链路可能是:
"重启" + "svc" + "Pod 异常" -> 命中 sre-incident-response
然后 Agent 会按 Skill 指令组织执行,而不是直接“凭经验回答”。
11.4 为什么这种 Skill 特别适合生产场景
因为故障处理最怕三件事:
- • 顺序错
- • 证据弱
- • 动作猛
Skill 恰好可以把这三类风险前置控制:
- • 顺序通过 SOP 固化
- • 证据通过输出格式和禁令约束
- • 动作通过权限和人工确认控制
11.5 进一步升级:把 Skill 接到自动化执行器
如果团队已经具备受控执行环境,可以把 Skill 与自动化工具结合:
interface RemediationPlan { incidentLevel: "P0" | "P1" | "P2"; evidence: string[]; actions: { kind: "scale" | "rollback" | "restart" | "drain-node"; target: string; requiresApproval: boolean; }[];}
然后规定:
- •
P0的只读排查动作可自动执行 - • 写动作必须二次审批
- • 所有执行步骤必须审计留痕
这时 Skill 就从“文本规范”进化成“自动化治理入口”。
- 权限治理、审计与安全边界
如果说前面讨论的是“Skill 能做什么”,这一章讨论的是“Skill 不应该越过什么边界”。
12.1 生产默认策略:默认拒绝
推荐权限配置:
{ "permission": { "skill": { "*": "deny", "microservice-scaffold": "allow", "java-ddd-review": "allow", "sre-incident-response": "ask", "k8s-deploy": "ask", "db-migration-*": "deny" } }}
解释:
- • 默认拒绝所有 Skill
- • 低风险设计类、评审类 Skill 可直接放行
- • 涉及生产执行的 Skill 至少要
ask - • 数据变更类 Skill 默认禁止
12.2 按 Agent 角色隔离
不同 Agent 不应该看到完全一样的 Skill 集合。
{ "agent": { "plan": { "permission": { "skill": { "architecture-*": "allow", "k8s-deploy": "deny" } } }, "code": { "permission": { "skill": { "microservice-*": "allow", "review-*": "allow" } } }, "sre": { "permission": { "skill": { "sre-*": "allow", "db-migration-*": "deny" } } } }}
这样做的收益:
- • Planner 不会误碰执行类技能
- • Code Agent 更聚焦研发场景
- • SRE Agent 拥有故障处理所需能力,但不会拿到无关研发技能
12.3 审计日志必须记录什么
至少记录:
- • 谁加载了 Skill
- • 何时加载
- • 加载了哪个版本
- • 在什么会话、什么任务中加载
- • 是否通过人工确认
- • 后续触发了哪些工具调用
示例:
type SkillAuditEvent = { timestamp: number; sessionId: string; userId: string; agent: string; skillName: string; skillVersion?: string; decision: "allow" | "ask" | "deny"; approvedBy?: string; promptHash: string;};
12.4 一个审计 Hook 示例
export async function onSkillLoaded(event: SkillAuditEvent): Promise<void> { await auditStore.write(event); if (event.skillName.startsWith("sre-") && event.decision !== "deny") { await siemSink.publish({ type: "skill_loaded", severity: "high", payload: event, }); }}
12.5 安全边界的本质
Skill 本身只是文本,但一旦它能引导 Agent 调用工具、修改代码、执行命令,它就进入了操作面。此时必须把它当成“低代码自动化规则”来治理,而不是普通 Markdown 文档。
- Skill 生命周期:版本、测试、灰度、回滚
企业内部 Skill 一旦规模化,就不能再靠人工拷贝目录来管理。
13.1 版本化
建议语义化版本:
- •
MAJOR:指令逻辑或输出格式有破坏性变化 - •
MINOR:新增能力或规则 - •
PATCH:修正文案、样例、小范围约束
例如:
version: 2.3.1
13.2 Skill 也要做测试
最少应包括三类测试:
| 测试类型 | 目标 |
|---|---|
| 语法测试 | frontmatter 是否完整、字段是否合法 |
| 约束测试 | name 与目录名是否一致、输出结构是否存在 |
| 行为测试 | 给定输入时,Agent 是否能稳定遵守关键规则 |
13.3 一个简单的校验脚本
import fs from "node:fs/promises";import path from "node:path";import matter from "gray-matter";async function validateSkill(skillDir: string): Promise<void> { const skillFile = path.join(skillDir, "SKILL.md"); const raw = await fs.readFile(skillFile, "utf8"); const parsed = matter(raw); const dirName = path.basename(skillDir); if (!parsed.data.name) { throw new Error(`${skillDir}: missing name`); } if (parsed.data.name !== dirName) { throw new Error(`${skillDir}: frontmatter name must equal directory name`); } if (!parsed.data.description) { throw new Error(`${skillDir}: missing description`); } if (!parsed.content.includes("# 输出格式")) { throw new Error(`${skillDir}: missing output format section`); }}
13.4 灰度发布
Skill 升级后不要全量立即生效,建议:
- • 先对内部测试用户开放
- • 再对部分团队灰度
- • 观察命中率、满意度、token 消耗、异常率
- • 稳定后再全量切换
13.5 回滚策略
出现以下情况应快速回滚:
- • 命中率骤降
- • 输出格式不兼容下游系统
- • Token 消耗异常升高
- • 高风险场景判断错误率上升
回滚最好做到:
- • 元数据级回滚
- • 版本级 pin
- • 按 Agent 单独回滚
- • 按租户或团队局部回滚
- 常见反模式与踩坑实录
14.1 反模式一:把 Skill 写成超长百科全书
问题:
- • token 成本高
- • 模型抓不住重点
- • 修改一小段规则也要改整篇大文档
更好的做法:
- • 主 Skill 只保留核心流程和硬约束
- • 详细规范拆到 references
- • 热点规范做摘要化
14.2 反模式二:Skill 名字过于宽泛
例如:
name: assistantdescription: 一个帮助开发者工作的技能
这几乎无法用于精确路由,也不利于审计与权限治理。
14.3 反模式三:没有明确“缺信息时怎么办”
如果不写这部分,模型常常会自动补全。
应该显式规定:
如果输入关键信息不足,不要猜测。先输出缺失字段列表,并暂停执行。
14.4 反模式四:多个 Skill 互相打架
例如:
- • 安全 Skill 要求所有接口必须鉴权
- • Demo Skill 说可以省略鉴权便于快速开发
如果没有优先级,模型可能同时遵守,也可能随机偏向其中一个。
解决思路:
- • 引入优先级模型
- • 高风险 Skill 优先
- • 场景冲突时只允许一个主 Skill 生效
14.5 坑一:目录名与 name 不一致
目录: java-reviewname: javaReviewer
这会造成:
- • 扫描能发现
- • 加载或匹配阶段却可能失败
最稳妥的方式仍然是目录名与 name 完全一致。
14.6 坑二:高并发下重复读文件
如果没有并发合并,一个热门 Skill 可能在瞬间被读几十次甚至上百次,放大 I/O 与 GC 压力。
解决方式:
- •
inflightPromise 合并 - • 热点缓存
- • 大文件引用拆分
14.7 坑三:引用资产失效但 Skill 本体没报错
主文件还在,但引用的模板或规范文件已经被删除,模型就会在“引用缺失”时开始自由发挥。
建议:
- • 发布前做引用完整性校验
- • 对关键引用做 checksum
- • 缺失时阻止上线
- 从单机 Skill 到分布式 Skill Registry 的演进路线
这是很多团队最关心的架构问题:Skill 系统如何从“本地目录”成长为“组织级平台”。
15.1 阶段一:本地文件阶段
特点:
- • Skill 存在仓库目录中
- • Git 管理版本
- • 适合 1 到 2 个团队试点
优点:
- • 简单直接
- • 离线可用
- • 开发体验好
缺点:
- • 难统一发布
- • 难全局审计
- • 跨团队共享效率低
15.2 阶段二:Git 中央仓库阶段
特点:
- • Skill 统一托管在平台仓库
- • 通过 Git Submodule、同步脚本或构建流程拉取
优点:
- • 版本清晰
- • 评审流程成熟
- • 易于复用
缺点:
- • 仍偏静态
- • 实时性不够
- • 缺少租户和权限中心能力
15.3 阶段三:Skill Registry 阶段
这时可以引入真正的分布式注册中心。
能力包括:
- • 元数据索引
- • 版本管理
- • 权限下发
- • 灰度发布
- • 审计查询
- • 热点缓存分发
一个 Registry API 示例:
GET /api/v1/skills?tag=review&agent=codeGET /api/v1/skills/java-ddd-review/versions/latestGET /api/v1/skills/java-ddd-review/artifactsPOST /api/v1/skill-audit-events
15.4 阶段四:控制面平台化
此时可以进一步引入:
- • Web 控制台
- • 可视化分类和依赖图
- • 策略中心
- • 命中率与效果分析
- • 用户反馈闭环
15.5 分布式架构的关键设计点
| 能力 | 关键设计 |
|---|---|
| 一致性 | 元数据强一致,正文内容最终一致即可 |
| 高可用 | 本地缓存优先,Registry 可降级 |
| 扩展性 | Source、Policy、Audit 全部插件化 |
| 安全性 | Skill 下载鉴权、签名校验、审计留痕 |
| 成本控制 | 摘要化、Pointer、按需加载 |
15.6 适合大规模组织的一种参考架构
Skill Authoring Repo -> CI 校验 -> 发布到 Skill Registry -> 元数据写入 Catalog DB -> 正文与模板写入 Object Store -> 边缘节点或本地 Agent Runtime 拉取缓存 -> 会话请求按需加载 -> 使用结果回流 Audit / Metrics / Feedback
这条链路一旦打通,Skill 才真正成为企业 AI 能力平台的标准资产。
- 最终结论
如果把本文压缩成几条最重要的结论,我认为有以下几点:
16.1 Skill 的本质不是 Prompt,而是“可治理的行为资产”
它负责把组织知识、约束和流程转译成 Agent 能稳定执行的规则。真正的价值不在语法本身,而在运行时治理。
16.2 写好 Skill 的关键,不是词藻,而是结构化执行能力
高质量 Skill 必须至少具备:
- • 明确元数据
- • 稳定执行流程
- • 清晰决策规则
- • 固定输出结构
- • 显式禁令和失败处理
16.3 生产级 Skill 平台必须同时解决三件事
- • 技术深度:理解发现、匹配、加载、注入和冲突处理原理
- • 工程能力:缓存、并发、降级、扩展、版本、回滚
- • 治理能力:权限、审计、灰度、安全、组织协同
16.4 真正的落地原则
把 Skill 当代码来管理,把 Skill 平台当基础设施来建设,把 Skill 输出当生产行为来审计。
16.5 推荐行动清单
- 梳理团队前 10 个高频 AI 使用场景,优先建设对应 Skill。
- 为每个 Skill 增加
version、owner、tags和metadata字段。 - 把 Skill 主体与 references/templates/examples 拆分管理。
- 为 Skill 平台补上 Catalog、Permission、Audit、Cache 四个核心组件。
- 在高风险场景启用默认拒绝、人工确认和审计留痕。
- 建立 Skill 的 CI 校验、灰度发布和版本回滚机制。
当你完成这六步,Skill 就不再是一篇 Markdown,而会真正成为你们组织 AI Agent 的“制度化能力底座”。
学AI大模型的正确顺序,千万不要搞错了
🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!
有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!
就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇
学习路线:
✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经
以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!
我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

336



被折叠的 条评论
为什么被折叠?



