2026/9/30 22:39:07

Agent Skill 工程化指南(一):定义与架构 — 建立统一认知

Agent Skill 工程化指南(一):定义与架构 — 建立统一认知 1. 从一条“帮我看看流水线”说起Agent Skill 到底是什么如果你正在搭多 Agent 协作体系大概率遇到过这种场面研发同学在群里丢一句“master 上的流水线又挂了帮我看看”你希望 Agent 能真的去拉日志、分类故障、定位根因、给出修复动作而不是回一段“建议检查构建日志、确认依赖版本”的通用废话。Agent Skill 就是解决这个落差的东西——它把意图理解、执行逻辑、工具调用、异常处理和安全约束打包成一个可独立开发、测试、部署和治理的能力单元。适合谁适合正在从“写提示词”过渡到“搭能力资产”的团队尤其是 DevOps、平台工程、内部工具链方向的开发者。我先把结论摆出来Skill 不是更长的 Prompt也不是 Tool 的别名。它是 Agent 和工程系统之间的标准能力接口。一个 Agent 可以掌握多个 Skill一个 Skill 可以被多个 Agent 复用。你把它理解成“员工掌握的技能”最贴切Agent 是雇主Skill 是员工Tool 是员工手里的工具。雇主不会因为要修水管就成立一家修水管公司而是雇一个会修水管的工人让他去不同公司干活。这篇是系列第一篇目标只有一个建立统一认知基线。读完你应该能回答三个问题——Skill 由哪些要素构成、它在 Agent 架构里处于哪一层、它和 Tool/Prompt/Workflow/Agent 的边界在哪。同时我会给出一份可复制的 SKILL.md 目录结构模板并用 TaoToken 统一 Key/API 通道跑通一次 Skill 调用让你不只是“看懂”而是“跑通”。先看一个最小可运行的 Skill 长什么样它决定了后面所有工程化讨论的起点--- name: roll-dice description: Roll dice using a random number generator. Use when asked to roll a die (d6, d20, etc.), roll dice, or generate a random dice roll. --- To roll a die, use the following command that generates a random number from 1 to the given number of sides: bash echo $((RANDOM % sides 1))Replacesideswith the number of sides on the die (e.g., 6 for a standard die, 20 for a d20).就这么点内容但它已经是一个合法 Skillfront matter 里的 name 是唯一标识description 决定它会不会被 Agent 召回正文是 Agent 被触发后逐步执行的指令。复杂 Skill 只是把正文写得更结构化格式本身不变。这就是 SKILL.md 的设计精髓——一个文件同时满足机器解析front matter和 Agent 执行正文的双重需求。 ## 2. Skill 六要素与 SKILL.md 目录结构模板Agent Skill 工程化落地 ### 2.1 六大构成要素Skill 的解剖图 任何 Skill无论简单还是复杂都能拆成六个固定要素。这套框架是后面三篇的主线骨架先记住名字和职责 | 要素 | 职责 | 在 SKILL.md 中的位置 | | --- | --- | --- | | ① Identity 身份标识 | 名称、版本、描述、标签、Owner | front matter 的 name description | | ② Intent 意图定义 | 触发条件、意图槽位、置信度要求 | description 描述触发场景 Step 1 参数定义 | | ③ Contract 输入输出契约 | Input Schema、Output Schema、对话契约 | Step 1 输入参数 Step 5 输出结构 | | ④ Logic 执行逻辑 | Prompt 策略、推理链、流程编排、条件分支 | 正文核心步骤 | | ⑤ Bindings 工具绑定 | 依赖的 Tool/API、超时、重试、降级 | 正文中的命令调用 | | ⑥ Guardrails 安全护栏 | 权限、限流、熔断、人机协同、审计 | 嵌入各步骤的安全约束 | 这六个要素不需要额外配置文件承载。front matter 提供 Identity 和 Intent 的元数据入口正文的分步指令依次覆盖 Contract、Logic、Bindings 和 Guardrails。下面这份目录结构模板可以直接复制到你的仓库里用 text skills/ └── pipeline-diagnosis/ # 每个 Skill 一个独立目录kebab-case ├── SKILL.md # ★ 必须front matter注册检索 正文执行指令 ├── prompts/ # 可选外部 Prompt 模板 │ ├── system.md │ └── few_shots/ │ ├── dependency.md │ └── test_failure.md ├── scripts/ # 可选可执行脚本 │ └── check_flaky.py ├── references/ # 可选参考资料 │ └── failure_patterns.md └── assets/ # 可选其他资源 └── report_template.md关键原则只有一条所有支撑目录的存在都是因为 SKILL.md 里引用了它们。如果 SKILL.md 不引用任何外部文件整个目录里只有一个 SKILL.md这完全合法。别为了“看起来工程化”而堆空目录。2.2 一个复杂 Skill 的 front matter 与正文骨架以贯穿系列的“流水线故障诊断 Skill”为例front matter 必须包含两个字段name用 kebab-casedescription是决定召回的关键--- name: pipeline-diagnosis description: When a CI/CD pipeline build fails, fetch the build logs, diagnose the failure type (dependency conflict, compile error, test failure, or deploy timeout), locate the root cause, and attempt auto-fix or provide fix suggestions. --- When this skill is triggered, follow these steps in order. ## Step 1: Obtain pipeline information Confirm you have the following parameters. If any required parameter is missing, ask the user before proceeding. - pipeline_id (required): the pipeline run ID, e.g. pl-20260706-a3f7 - service_name (optional): the microservice name - branch (optional, defaults to master): the git branch If pipeline_id is missing, ask: What is the pipeline ID or build link? Maximum 2 rounds of clarification. After that, use the fallback strategy. ## Step 2: Fetch build logs Call the CI/CD platform API to retrieve the full build log: bash cicd-cli logs --pipeline-id pipeline_id --format jsonIf the CI/CD API times out, retry up to 2 times. If the log exceeds 500KB, stop and return an error asking the user to download the log manually.Step 3: Diagnose failure typeClassify the failure into: dependency / compile / test / deploy / unknown. Use the diagnostic prompt atprompts/system.mdfor structured analysis.Step 4: Execute fix based on failure typeIf dependency:Identify the conflicting package and versions from the log.Roll back to the last stable version:dependency-cli rollback --package pkg_name --to-version last_stableSTOP and ask for user confirmation before executing the rollback.If compile:Do NOT modify code automatically. Only provide suggestions.Step 5: Generate reportOutput both a human-readable report and a structured JSON object:{ diagnosis: { failure_type: dependency|compile|test|deploy|unknown, root_cause: string, affected_files: [path] }, fix_action: { action_taken: string, fix_result: success|partial|failed } }对照六要素看name/description 是 Identity 和 IntentStep 1 的参数定义和追问策略是 Contract 的输入侧和对话契约Step 5 的报告模板和 JSON 是 Contract 的输出侧Step 2~4 是 Logic命令调用是 BindingsMaximum 2 rounds、log exceeds 500KB, stop、STOP and ask for user confirmation、Do NOT modify code automatically 是 Guardrails。一个文件六要素齐全。 ### 2.3 边界辨析别把 Tool 当 Skill 团队沟通里最容易混的是 Skill、Tool、Prompt、Workflow、Agent 这几个词。混了就会在设计时做错抽象层级。用一张表划清 | 维度 | Agent | Skill | Tool | Prompt | Workflow | | --- | --- | --- | --- | --- | --- | | 本质 | 运行中的角色系统 | 可调用的能力模块 | 原子操作接口 | 一次推理的指令文本 | 预定义流程 | | 粒度 | 系统级 | 能力级 | 操作级 | 指令级 | 流程级 | | 含 LLM 决策 | 是核心 | 是核心 | 否 | 是全部 | 通常无 | | 执行路径 | 运行时选 Skill | 运行时动态决策 | 固定 | 单次推理 | 设计时确定 | | 可独立测试 | 需启动整个系统 | 是轻量级 | 是 | 否 | 是 | | 可复用 | 困难 | 容易 | 容易 | 不适用 | 通常不跨系统 | 一句话记忆Tool 是万用表Skill 是整个故障排查服务Prompt 是 Skill 内部 Logic 的一个组件Workflow 的流程设计时写死Skill 的路径运行时由 LLM 动态决定Agent 是调度者Skill 是它掌握的一项能力。什么时候该做成 Agent 而不是 Skill当这个能力有自己的完整交互流程、需要独立 7×24 运行、不打算被复用、价值在于“持续运行的智能体”时。流水线故障诊断不满足这些条件所以它应该是 Skill。 ## 3. 用 TaoToken 统一 Key/API 通道Skill 注册与加载的可复制配置 ### 3.1 为什么 Skill 工程化需要一个统一通道 Skill 的 Bindings 会调用各种 API如果每个 Skill 各自管一套 Key治理会立刻失控轮换 Key 要改 N 处限流策略无法统一审计日志散落各处。工程化的做法是把模型调用收敛到一个统一通道Skill 只声明“我需要一个模型”不关心 Key 从哪来。TaoToken 在这里扮演的就是这个统一入口——一个 Key、一个 Base URL覆盖对话、编码、Agent 场景。 先把接入信息固定下来后面所有配置都引用它 - 官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content - API Base URLhttps://taotoken.net/api - 模型对话https://taotoken.net/api/chat - Coding Planhttps://taotoken.net/coding-plan - 控制台https://taotoken.net/console - API Keyshttps://taotoken.net/api-keys - 接入文档https://taotoken.net/doc - Claude Code 接入https://taotoken.net/claude-code-anthropic ### 3.2 可复制的 Skill 注册配置JSON / TOML / settings Skill 注册的本质是让 Agent 平台知道“有哪些 Skill、怎么加载、用哪个模型通道”。下面这份 skills.registry.json 可以直接放进项目根目录路径与字段按你的平台微调即可 json { registry_version: 1.0, model_gateway: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, default_model: claude-sonnet-4-5, timeout_ms: 60000, max_retries: 2 }, skills: [ { name: pipeline-diagnosis, path: skills/pipeline-diagnosis/SKILL.md, enabled: true, owner: platform-team, version: 1.0.0, tags: [devops, ci-cd, diagnosis] }, { name: roll-dice, path: skills/roll-dice/SKILL.md, enabled: true, owner: demo, version: 0.1.0, tags: [demo] } ] }如果你用的是 TOML 风格的工具链比如某些 Agent 框架的config.toml等价写法如下[model_gateway] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY default_model claude-sonnet-4-5 timeout_ms 60000 max_retries 2 [[skills]] name pipeline-diagnosis path skills/pipeline-diagnosis/SKILL.md enabled true owner platform-team version 1.0.0 tags [devops, ci-cd, diagnosis]如果你在 Claude Code 这类工具里做接入settings.json的关键三件套是 Base URL、Key、Model ID缺一不可{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的TaoTokenKey, ANTHROPIC_MODEL: claude-sonnet-4-5 } }注意ANTHROPIC_API_KEY建议从环境变量注入不要硬编码进仓库。Key 在控制台的 API Keys 页面创建https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite3.3 Skill 加载器的伪代码注册表有了加载器要做的事很固定读注册表 → 解析每个 SKILL.md 的 front matter → 校验必填字段 → 建立 name 到正文的映射。下面是一段可运行的 Python 骨架import os import re import json import yaml def load_registry(pathskills.registry.json): with open(path, r, encodingutf-8) as f: return json.load(f) def parse_skill_md(skill_path): with open(skill_path, r, encodingutf-8) as f: content f.read() match re.match(r^---\n(.*?)\n---\n(.*)$, content, re.DOTALL) if not match: raise ValueError(fSKILL.md 缺少 front matter: {skill_path}) meta yaml.safe_load(match.group(1)) body match.group(2).strip() if name not in meta or description not in meta: raise ValueError(ffront matter 缺少 name/description: {skill_path}) return meta, body def load_all_skills(registry): skills {} for item in registry[skills]: if not item.get(enabled, True): continue meta, body parse_skill_md(item[path]) skills[meta[name]] { meta: meta, body: body, owner: item.get(owner), version: item.get(version), } return skills if __name__ __main__: reg load_registry() all_skills load_all_skills(reg) print(f已加载 {len(all_skills)} 个 Skill: {list(all_skills.keys())})跑通后你会看到类似输出已加载 2 个 Skill: [pipeline-diagnosis, roll-dice]这一步验证的是“注册与加载”链路还没到模型调用。加载器把 front matter 和正文分离正是为了后续做语义召回时只拿description去匹配执行时才注入正文。4. 验证请求用统一通道跑通一次 Skill 调用4.1 构造一次最小调用加载完 Skill下一步是验证模型通道能通。用 curl 直接打 TaoToken 的对话接口确认 Key 和 Base URL 正确export TAOTOKEN_API_KEYsk-你的TaoTokenKey curl -s https://taotoken.net/api/chat \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [ {role: system, content: You are a skill router. Given a user request, decide which skill to trigger.}, {role: user, content: master 上的流水线又挂了帮我看看 pl-20260706-a3f7} ], max_tokens: 512 }预期返回结构里会有choices[0].message.content内容应该指向pipeline-diagnosis这个 Skill。如果返回 401说明 Key 没生效如果返回local proxy failed说明 Base URL 写错了或网络出口有问题如果报reading choices相关错误通常是响应体不是标准 JSON检查是不是把 Base URL 写成了带路径的完整地址。4.2 把 Skill 正文注入执行验证通道通了之后把 Skill 正文作为 system 指令注入模拟一次真实执行import os import requests BASE_URL https://taotoken.net/api API_KEY os.environ[TAOTOKEN_API_KEY] def run_skill(skill_body, user_input, modelclaude-sonnet-4-5): resp requests.post( f{BASE_URL}/chat, headers{ Authorization: fBearer {API_KEY}, Content-Type: application/json, }, json{ model: model, messages: [ {role: system, content: skill_body}, {role: user, content: user_input}, ], max_tokens: 1024, }, timeout60, ) resp.raise_for_status() return resp.json()[choices][0][message][content] if __name__ __main__: from loader import load_registry, load_all_skills skills load_all_skills(load_registry()) body skills[pipeline-diagnosis][body] result run_skill(body, pl-20260706-a3f7 构建失败帮我诊断) print(result)成功时你会看到模型按 Step 1~5 的结构输出先确认参数再给出诊断分类和修复建议。这一步跑通说明“注册 → 加载 → 调用”整条链路是通的。如果你更想先在网页里验证模型本身可以直接用模型对话页面https://taotoken.net/api/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite4.3 长期编码场景的通道选择如果你不只是验证单次调用而是要把 Skill 挂到长期运行的编码 Agent 上建议走 Coding Plan配额和稳定性更适合持续调用https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite5. 本篇常见错排查401、local proxy failed、reading choices、OAuth排障时先分清是“通道问题”还是“Skill 问题”。下面这几类报错我按出现频率排了序对照着查。401 Unauthorized最常见。原因通常是 Key 没注入、Key 拼错、或者环境变量名和代码里读的不一致。检查echo $TAOTOKEN_API_KEY是否有值再确认请求头是Authorization: Bearer key。如果用的是 Claude Code 的settings.json确认ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL同时存在只配一个会失败。local proxy failed这个报错通常指向 Base URL 配置错误。检查是不是把https://taotoken.net/api写成了别的路径或者多加了/v1。三件套里 Base URL、Key、Model ID 必须同时正确缺一个都会以不同形式报错。reading choices 相关错误模型返回体不是预期 JSON 时出现。常见原因是请求打到了非 API 端点或者响应被中间层改写。用 curl 加-v看原始响应确认返回的是标准{choices: [...]}结构。OAuth 相关报错如果你在 Claude Code 里看到 OAuth 提示说明工具在走账号登录流程而不是 API Key 流程。检查settings.json是否被正确加载环境变量是否覆盖了默认登录态。必要时清掉旧的凭据缓存再重试。Skill 加载报错如果加载器抛SKILL.md 缺少 front matter检查文件开头是不是---且 front matter 和正文之间有空行。如果抛缺少 name/description检查 YAML 缩进name和description必须是顶层键。召回不准Skill 明明注册了却不触发九成是description写得太泛。description要同时说清“做什么”和“什么时候触发”比如When a CI/CD pipeline build fails, fetch the build logs...就比Diagnose pipeline issues召回率高得多。6. 建立认知基线之后把 Skill 当成工程资产到这里你应该能对着一个 SKILL.md 说出它的六要素分别在哪、它在四层架构里处于哪一层、它和 Tool/Prompt/Workflow/Agent 的边界在哪。这套认知基线是后面三篇的前提第二篇讲怎么把六要素组装成高质量 SKILL.md第三篇讲 Skill 怎么被选中、加载、执行第四篇讲上线后的治理与演进。给你一个可以直接落地的动作把团队现有的提示词资产盘一遍凡是“需要调工具 有分支逻辑 要复用”的都按本篇的目录模板改造成 Skill注册表统一走一个模型通道。改造过程中如果卡在接入配置接入文档里有各工具的完整示例https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite下一篇我们会拿description开刀——它是召回率的命门也是最多人写错的地方。