资讯详情

资讯详情

Learn Claude Code 笔记:Planning Coordination 中 Skills 的配置与验证

1. 从 s04 到 s05为什么 Skills 要按需加载如果你跟着 learn-claude-code 一路写下来到 s04 的时候这个最小 Agent 已经能调工具、写 todo、把局部探索丢给子智能体去跑。但有个前提一直没被戳破模型自己得知道该怎么做。你让它写 commit、做 code review、跑测试分析它得先懂这些流程。问题就出在这。这些领域知识不是通用常识而是一整套具体工作流。比如 code review 不是看代码提意见这么简单它通常要先拉 diff、按文件逐个检查、重点盯 bug/security/style最后按固定格式写 comment。你要是把这些全塞进 system prompt10 个技能每个 2000 tokens就是 20000 tokens 的常驻开销而当前请求里可能一个都用不上。我在本地跑这套工作流时踩过的坑就是一开始图省事把所有 skill 正文直接拼进 SYSTEM 字符串结果每轮请求 token 都爆模型还因为背景设定太臃肿反而抓不住当前任务的重点。s05 给的解法很干净——把知识加载也做成一个工具两层注入第一层是永远存在的技能目录只有名字和描述约 100 tokens/skill第二层是模型主动调load_skill时把完整正文作为tool_result回填进上下文。这一节的核心检索词就是Learn Claude Code Planning Coordination 里的 Skills 按需加载机制。它适合谁适合已经在本地跑 Claude Code 工作流、想让 Agent 掌握多个领域流程、又不想被 system prompt 拖垮的开发者。下面我把目录结构、配置片段、一次可复现的规划任务验证以及怎么把 endpoint 统一到 TaoToken 通道一步步拆开。2. TaoToken 前置把 endpoint 统一到一条 Key 通道在动手配 Skills 之前先把调用通道理顺。learn-claude-code 默认走 Anthropic 官方客户端但如果你同时跑多个 Agent 项目、多个模型Key 散在各处很难管。我的做法是统一走 TaoToken 的 API 通道一个 Key 管所有调用切换模型只改 Model ID。TaoToken 在这里扮演的角色是统一的模型调用入口不是替代你的编辑器或 Agent 框架。你本地该跑的 Claude Code 工作流照跑只是把base_url指过去。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 这个不加 UTM。具体到 learn-claude-code 的 s05 脚本初始化部分原本是这样from anthropic import Anthropic client Anthropic(api_keyos.getenv(ANTHROPIC_API_KEY))改成走 TaoToken 通道只需要补一个base_urlimport os from anthropic import Anthropic client Anthropic( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlhttps://taotoken.net/api )对应的.env文件TAOTOKEN_API_KEYsk-你的统一Key MODELclaude-sonnet-4-20250514 WORKDIR/Users/you/learn-claude-code这里有个关键点Base URL、Key、Model ID 三件套必须对齐。Base URL 是https://taotoken.net/apiKey 从控制台拿Model ID 用你实际要调的模型名。三者任何一个写错后面验证请求就会报 401 或 model not found。如果你还没拿 Key去 API Keys 页面生成https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。生成后直接填进.env别硬编码在脚本里。为什么要在 Skills 这一节强调通道统一因为 Skills 机制会让模型频繁发起load_skill工具调用每一轮都是真实的 API 请求。如果 Key 分散、endpoint 混乱排查技能没加载成功时你根本分不清是 skill 配置问题还是通道问题。统一到一条通道后排障路径就清晰了先确认请求通不通再看 skill 加载逻辑。配好之后跑一个最小连通性测试resp client.messages.create( modelos.getenv(MODEL), max_tokens100, messages[{role: user, content: reply with ok}] ) print(resp.content[0].text)能打印出ok说明通道没问题可以进入 Skills 配置了。3. 可复制配置Skills 目录结构与 SKILL.md 片段s05 最实在的改动是把知识从 Python 代码里外置出来变成一个skills/目录。SkillLoader 会递归扫描所有SKILL.md把每个文件拆成 frontmatter 元信息和正文 body 两部分——这正好对应两层注入元信息进 system prompt 当目录正文按需加载。目录结构长这样learn-claude-code/ ├── agents/ │ └── s05_skill_loading.py ├── skills/ │ ├── code-review/ │ │ └── SKILL.md │ ├── git-commit/ │ │ └── SKILL.md │ └── test-analysis/ │ └── SKILL.md └── .env每个SKILL.md的格式是 frontmatter 正文。以code-review/SKILL.md为例--- name: code-review description: Structured code review workflow covering security, correctness, performance tags: review,security,quality --- # Code Review Skill ## 1. Security (Critical) Check for: - Injection vulnerabilities: SQL, command, XSS - Hardcoded credentials, weak auth - Sensitive data in logs or error messages Quick scan: bash grep -rn password\|secret\|api_key\|token --include*.py .2. CorrectnessEdge cases and boundary conditionsError handling completenessOff-by-one and null checks3. PerformanceUnnecessary loops or repeated I/ON1 query patternsReview Output FormatSummaryCritical IssuesImprovementsPositive NotesVerdictfrontmatter 里的 name 和 description 会被 get_descriptions() 拼进 system prompt形成第一层目录。正文 body 则被 get_content() 包成 skill name....../skill 结构通过 load_skill 工具返回。 SkillLoader 的核心解析逻辑 python import re from pathlib import Path class SkillLoader: def __init__(self, skills_dir: Path): self.skills_dir skills_dir self.skills {} self._load_all() def _load_all(self): for f in sorted(self.skills_dir.rglob(SKILL.md)): text f.read_text() meta, body self._parse_frontmatter(text) name meta.get(name, f.parent.name) self.skills[name] {meta: meta, body: body, path: str(f)} def _parse_frontmatter(self, text): match re.match(r^---\n(.*?)\n---\n(.*), text, re.DOTALL) if not match: return {}, text meta {} for line in match.group(1).strip().splitlines(): if : in line: key, val line.split(:, 1) meta[key.strip()] val.strip() return meta, match.group(2) def get_descriptions(self) - str: if not self.skills: return (no skills available) lines [] for name, skill in self.skills.items(): desc skill[meta].get(description, No description) tags skill[meta].get(tags, ) line f - {name}: {desc} if tags: line f [{tags}] lines.append(line) return \n.join(lines) def get_content(self, name: str) - str: skill self.skills.get(name) if not skill: return fError: Unknown skill {name}. Available: {, .join(self.skills.keys())} return fskill name{name}\n{skill[body]}\n/skill然后把它接进 system prompt 和工具表SKILLS_DIR WORKDIR / skills SKILL_LOADER SkillLoader(SKILLS_DIR) SYSTEM fYou are a coding agent at {WORKDIR}. Use load_skill to access specialized knowledge before tackling unfamiliar topics. Skills available: {SKILL_LOADER.get_descriptions()} TOOL_HANDLERS { bash: lambda **kw: run_bash(kw[command]), read_file: lambda **kw: run_read(kw[path], kw.get(limit)), write_file: lambda **kw: run_write(kw[path], kw[content]), edit_file: lambda **kw: run_edit(kw[path], kw[old_text], kw[new_text]), load_skill: lambda **kw: SKILL_LOADER.get_content(kw[name]), }注意load_skill的 schema 定义{ name: load_skill, description: Load specialized knowledge by name., input_schema: { type: object, properties: { name: {type: string, description: Skill name to load} }, required: [name] } }到这里配置就齐了。system prompt 里只有技能目录轻量正文躺在skills/目录里等模型主动来取。整个改动没有推翻 s02 建立的加工具 加 handler 加 schema结构只是多了一个操作知识库的 handler。4. 验证请求一次可复现的规划任务配置写完得验证它真的能跑通。我设计了一个可复现的规划任务让 Agent 先加载 code-review 技能再对agents/s05_skill_loading.py做一次审查。整个过程能清楚看到两层注入是怎么落地的。启动脚本后第一轮输入I need to do a code review -- load the relevant skill first预期行为模型先从 system prompt 的技能目录里识别出code-review然后发起load_skill调用。调试输出应该看到 load_skill: skill namecode-review # Code Review Skill ## 1. Security (Critical) ... /skill这一步验证了第一层目录起作用了——模型不是凭空知道有 code-review 技能而是从 system prompt 的摘要列表里读到的。同时第二层注入也生效了完整正文被包成skill块作为tool_result回填进上下文。第二轮模型会确认技能已加载然后问你想 review 什么。继续输入I want you to review agents/s05_skill_loading.py预期行为模型调用read_file读取目标文件拿到内容后基于已加载的 code-review 技能正文按结构化流程开始审查。理想情况下它会先做安全检查 bash: grep -n password\|secret\|api_key\|token\|key agents/s05_skill_loading.py这个动作直接对应 SKILL.md 里Security (Critical)的第一项。说明技能正文里的 structured approach 真的在驱动模型的决策顺序——它没有先去看命名风格而是优先做安全扫描。最终输出应该是一份结构化报告包含 Summary、Critical Issues、Improvements、Positive Notes、Verdict而不是一段随意的代码还不错。这验证了技能正文对输出格式的影响。如果你想验证模型对话层面的效果可以到模型对话页面直接测https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。把同样的 prompt 丢进去观察它是否先加载技能再行动。这里有个实测细节我用 deepseek 模型跑的时候出现过模型忘记已经加载过 code-review 技能、又重新去skills/目录找 SKILL.md 的情况。上下文并不长前面明明有完整的load_skill结果但它没沿着那份技能走。换能力更强的模型后这个现象明显减少。所以验证时如果发现模型反复加载同一个技能先别怀疑配置可能是模型本身对长上下文里工具结果的利用能力偏弱。完整的验证链路是system prompt 目录 → 模型识别技能 →load_skill调用 →skill块回填 → 模型按技能正文行动 → 结构化输出。每一步都能在终端输出里看到对应痕迹。5. 本篇常见错排查401、local proxy failed 与技能加载失败配 Skills 的过程中报错基本集中在通道和加载逻辑两块。我把踩过的几个真实报错列出来对照排查。401 Unauthorized。这个最常见通常是 Key 或 Base URL 没对齐。检查.env里的TAOTOKEN_API_KEY是否有效base_url是否写成https://taotoken.net/api注意不是官网首页地址。如果 Key 是从别处复制的确认没有多余空格或换行。三件套里任何一个错位都会 401。local proxy failed / connection error。这类报错说明请求根本没发出去。先确认网络能访问https://taotoken.net/api再检查客户端初始化时base_url有没有被环境变量覆盖。有时候.env里同时存在ANTHROPIC_BASE_URL和代码里的base_url两者冲突会导致请求发到错误地址。reading choices of undefined。这个报错通常出现在响应结构不符合预期时。如果你用的是 OpenAI 兼容格式的客户端去调 Anthropic 格式的接口或者反过来就会读到不存在的字段。确认你用的 SDK 和 endpoint 格式匹配——learn-claude-code 用的是 Anthropic SDK走/api通道时保持 Anthropic 消息格式。OAuth / authentication 相关报错。如果你之前配过 Claude Code 的 OAuth 登录环境里可能残留旧的凭证配置和新的 API Key 冲突。清理掉旧的 auth 配置确保只走 Key 通道。技能加载失败Unknown skill。load_skill返回Error: Unknown skill xxx说明 SkillLoader 没扫描到对应技能。检查三点skills/目录路径是否和SKILLS_DIR一致SKILL.md文件名是否全大写frontmatter 里的name字段是否和模型调用的名字匹配。SkillLoader 用的是rglob(SKILL.md)递归扫描子目录里的文件也能找到但文件名必须精确是SKILL.md。技能加载了但模型不按它行动。这不是报错但很常见。表现是load_skill成功返回了正文模型却忽略它。原因通常是模型能力问题或者技能正文太长导致注意力分散。可以试着精简 SKILL.md 正文把最关键的检查项放前面。Codex auth.json / CC Switch / Cline MCP 场景。如果你在 Codex 或 Cline 里配 Skills同样要保证 Base URL、Key、Model ID 三件套完整。Codex 的auth.json里填base_url和api_keyCline 的 MCP 配置里对应填 endpoint 和 model。任何一处缺失都会导致调用失败。排障的通用思路先确认通道通跑最小请求再确认技能被扫描到打印SKILL_LOADER.skills.keys()最后确认模型行为看调试输出里有没有load_skill调用。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有完整的参数说明。6. 把 Skills 用起来从验证到长期工作流验证跑通之后下一步是把它变成日常能用的东西。Skills 机制真正的价值是让 prompt 从一次性写死的文本变成可组合、可加载、可管理的模块化系统。你可以按项目需要往skills/目录里不断加新技能system prompt 里的目录会自动更新而正文永远按需加载。如果你要长期跑编码任务或 Agent 工作流建议把调用通道固定下来。Coding Plan 适合持续性的编码场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。统一通道的好处是你加再多技能、跑再多轮工具调用Key 和 endpoint 都不用改排障路径也始终清晰。回到 s05 本身它最漂亮的地方是底层 loop 几乎没变。while True没变client.messages.create没变tool_use/tool_result协议没变dispatch map 结构没变。变化只有两处system prompt 里加了一层廉价的技能目录工具层里加了一个load_skill入口。昂贵知识在需要时才通过tool_result回到上下文。这种克制正是这个项目一直整洁的原因——每一节都在加能力但几乎从不推翻前面建立的核心结构。到 s05系统第一次长出了知识管理能力哪些知识永远挂在背景里哪些只在需要时短暂进入。常驻的是技能目录按需出现的是技能正文模型不用永远背着全部知识但它永远知道可以去哪里取。你可以先拿code-review这个技能练手跑通加载技能 → 读取文件 → 结构化审查这条链路再往skills/里加自己的领域流程。每加一个技能就多验证一次load_skill是否被正确触发。跑顺了这套按需加载的规划协调机制就能直接用到你的实际项目里。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →