卷五协议验证日期:2026-05-17,基于 Claude Code Skills 系统和 Prompt 管理模式
工具给 Agent 能力(能做什么),Skill 给 Agent 专长(怎么做得好)。Skill 是封装了提示词模板、工具集和执行策略的可复用能力单元。
路线图 1 2 3 4 5 6 7 graph LR CH64["← 第 64 章<br/>工具的路由与调度"] --> CH65["📖 第 65 章<br/>技能的编织"] CH65 --> CH66["第 66 章<br/>你的Agent框架"] style CH64 fill:#e8f5e9,stroke:#333 style CH65 fill:#FF8F00,color:#fff,stroke:#333 style CH66 fill:#e1f5fe,stroke:#333
Skill 的形式化定义 1 Skill = PromptTemplate + ToolSet + Strategy + Validator
组件 作用 示例 PromptTemplate 定义行为边界 “你是一个代码审查专家…” ToolSet 专属工具 read_file, run_linterStrategy 执行策略 先审查再测试 Validator 验证规则 所有测试必须通过
Skill 定义格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 name: code-review description: 审查代码的 bug、安全问题和风格 version: 1.0 .0 author: agent-team triggers: - pattern: "审查|review|code review" - command: "/review" system_prompt: | 你是一个资深代码审查专家。审查代码时: 1. 先理解代码的意图 2. 检查逻辑错误和边界条件 3. 检查安全漏洞(注入、XSS、敏感信息泄露) 4. 检查代码风格和可读性 5. 给出具体的修改建议(含代码示例) tools: - read_file - grep_search - run_linter disallowed_tools: - write_file - delete_file - run_command validation: - type: output_check rule: must_contain_suggestions message: "审查结果必须包含具体的修改建议"
实现 SkillLoader 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import { readFile, readdir } from "node:fs/promises" ;import { join, extname } from "node:path" ;import { parse as parseYaml } from "yaml" ;export interface SkillDefinition { name : string ; description : string ; version : string ; author?: string ; triggers : { pattern?: string ; command?: string ; }[]; system_prompt : string ; tools?: string []; disallowed_tools?: string []; validation?: { type : string ; rule : string ; message : string ; }[]; dependencies?: string []; } export class SkillLoader { private skills = new Map <string , SkillDefinition >(); async loadFromDirectory (dir : string ): Promise <void > { const entries = await readdir (dir, { withFileTypes : true }); for (const entry of entries) { if (entry.isDirectory ()) { await this .loadFromDirectory (join (dir, entry.name )); } else if (entry.name .endsWith (".yaml" ) || entry.name .endsWith (".yml" )) { const content = await readFile (join (dir, entry.name ), "utf-8" ); const skill = parseYaml (content) as SkillDefinition ; this .skills .set (skill.name , skill); } } } get (name : string ): SkillDefinition | undefined { return this .skills .get (name); } getAll (): SkillDefinition [] { return Array .from (this .skills .values ()); } matchByInput (userInput : string ): SkillDefinition [] { const matches : SkillDefinition [] = []; for (const skill of this .skills .values ()) { for (const trigger of skill.triggers ) { if (trigger.pattern ) { const regex = new RegExp (trigger.pattern , "i" ); if (regex.test (userInput)) { matches.push (skill); break ; } } } } return matches; } }
实现 SkillInjector 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 export class SkillInjector { constructor (private loader : SkillLoader ) {} buildSystemPrompt ( baseSystemPrompt : string , activeSkills : SkillDefinition [] ): string { if (activeSkills.length === 0 ) return baseSystemPrompt; const skillPrompts = activeSkills .map (s => `## Skill: ${s.name} \n${s.system_prompt} ` ) .join ("\n\n---\n\n" ); return [ baseSystemPrompt, "---" , "## 当前激活的技能" , skillPrompts, ].join ("\n" ); } filterTools ( allTools : ToolDefinition [], activeSkills : SkillDefinition [] ): ToolDefinition [] { if (activeSkills.length === 0 ) return allTools; const allowed = new Set <string >(); const disallowed = new Set <string >(); let hasAllowList = false ; for (const skill of activeSkills) { if (skill.tools ) { hasAllowList = true ; for (const t of skill.tools ) allowed.add (t); } if (skill.disallowed_tools ) { for (const t of skill.disallowed_tools ) disallowed.add (t); } } return allTools.filter (t => { if (disallowed.has (t.name )) return false ; if (hasAllowList && !allowed.has (t.name )) return false ; return true ; }); } validateOutput ( response : MessageResponse , activeSkills : SkillDefinition [] ): ValidationResult [] { const results : ValidationResult [] = []; for (const skill of activeSkills) { if (!skill.validation ) continue ; for (const rule of skill.validation ) { results.push (this .checkRule (rule, response)); } } return results; } private checkRule ( rule : SkillDefinition ["validation" ][number ], response : MessageResponse ): ValidationResult { const text = response.content .filter (b => b.type === "text" ) .map (b => b.text ) .join ("" ); switch (rule.rule ) { case "must_contain_suggestions" : return { skill : rule.message , passed : /建议|修改|改进|修复/ .test (text), message : rule.message , }; case "must_be_json" : return { skill : rule.message , passed : (() => { try { JSON .parse (text); return true ; } catch { return false ; } })(), message : rule.message , }; default : return { skill : rule.message , passed : true , message : rule.message }; } } }
Skill 组合 多个 Skill 可以同时激活,但需要处理冲突:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 export class SkillComposer { compose (skills : SkillDefinition []): ComposedSkill { const sorted = this .topologicalSort (skills); return { systemPrompt : sorted.map (s => s.system_prompt ).join ("\n\n" ), tools : this .mergeTools (sorted), validation : sorted.flatMap (s => s.validation ?? []), }; } private topologicalSort (skills : SkillDefinition []): SkillDefinition [] { const sorted : SkillDefinition [] = []; const visited = new Set <string >(); const visit = (skill : SkillDefinition ) => { if (visited.has (skill.name )) return ; visited.add (skill.name ); if (skill.dependencies ) { for (const depName of skill.dependencies ) { const dep = skills.find (s => s.name === depName); if (dep) visit (dep); } } sorted.push (skill); }; for (const skill of skills) visit (skill); return sorted; } private mergeTools (skills : SkillDefinition []): string [] { const allowed = new Set <string >(); const disallowed = new Set <string >(); let hasAllowList = false ; for (const skill of skills) { if (skill.tools ) { hasAllowList = true ; for (const t of skill.tools ) allowed.add (t); } if (skill.disallowed_tools ) { for (const t of skill.disallowed_tools ) disallowed.add (t); } } for (const t of disallowed) allowed.delete (t); return hasAllowList ? Array .from (allowed) : []; } }
与 Agent Loop 集成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 export class SkillAwareAgent { private agent : AgentLoop ; private injector : SkillInjector ; async *run (userInput : string ): AsyncGenerator <TurnEvent > { const matched = this .injector .loader .matchByInput (userInput); if (matched.length > 0 ) { this .agent .updateSystemPrompt ( this .injector .buildSystemPrompt ( this .agent .getBaseSystemPrompt (), matched ) ); this .agent .restrictTools ( this .injector .filterTools ( this .agent .getAllTools (), matched ) ); } for await (const event of this .agent .run (userInput)) { if (event.type === "response" && matched.length > 0 ) { const validation = this .injector .validateOutput ( (event.data as { response : MessageResponse }).response , matched ); yield { ...event, validation }; } else { yield event; } } } }
试试看 任务 1 :创建三个 Skill——code-review(审查代码)、write-tests(编写测试)、document(写文档)。为每个写 YAML 定义和 prompt。
任务 2 :组合两个 Skill(如审查 + 安全审计),验证工具集合并是否正确。
任务 3 :实现 Skill 的热加载——在 Agent 运行时添加新 Skill,下一个请求生效。
常见错误 现象 原因 解法 Skill 不触发 pattern 正则不匹配 测试正则,调低匹配阈值 工具过多/过少 Skill 的 tools 配置错误 检查 allow/deny 逻辑 Skill 间冲突 两个 Skill 对同一操作有不同要求 用优先级排序 循环依赖 Skill A 依赖 B,B 依赖 A 拓扑排序检测循环
检查点 ← 上一章:第 64 章 工具的路由与调度 | 下一章:第 66 章 你的 Agent 框架 →