加载技能到会话上下文
学完你能做什么
- 使用
use_skill工具加载技能到当前会话 - 理解技能内容如何以 XML 格式注入到上下文
- 掌握 Synthetic Message Injection 机制(synthetic 消息注入)
- 理解技能元数据结构(来源、目录、脚本、文件)
- 了解技能在会话压缩后如何保持可用
你现在的困境
你创建了一个技能,但 AI 似乎无法访问它的内容。或者在长对话中,技能指导突然消失了,AI 忘记了之前的规则。这些都与技能加载机制有关。
什么时候用这一招
- 手动加载技能:AI 自动推荐不合适时,直接指定需要的技能
- 长会话保持:确保技能内容在上下文压缩后仍可访问
- Claude Code 兼容:加载 Claude 格式的技能,获得工具映射
- 精确控制:需要加载特定版本的技能(通过命名空间)
核心思路
use_skill 工具将技能的 SKILL.md 内容注入到会话上下文中,让 AI 能够遵循技能中定义的规则和工作流。
XML 内容注入
技能内容以结构化的 XML 格式注入,包含三个部分:
<skill name="skill-name">
<metadata>
<source>技能来源标签</source>
<directory>技能目录路径</directory>
<scripts>
<script>tools/script1.sh</script>
</scripts>
<files>
<file>docs/guide.md</file>
</files>
</metadata>
<tool-mapping>
<!-- Claude Code 工具映射 -->
</tool-mapping>
<content>
SKILL.md 的完整内容
</content>
</skill>Synthetic Message Injection
插件使用 OpenCode SDK 的 session.prompt() 方法注入技能内容,并设置两个关键标志:
Synthetic Message Injection
noReply: true- AI 不会响应这个注入本身synthetic: true- 标记消息为系统生成(对用户隐藏,不计入用户输入)
这意味着:
- 对用户不可见:技能注入不会显示在对话历史中
- 不消耗输入:不计入用户消息计数
- 持久可用:即使会话压缩,技能内容仍在上下文中
会话生命周期
- 首次消息时:插件自动注入
<available-skills>列表,展示所有可用技能 - 使用
use_skill:将选定技能的 XML 内容注入到上下文 - 会话压缩后:插件监听
session.compacted事件,重新注入技能列表
跟我做
第 1 步:加载基本技能
在 OpenCode 中让 AI 加载一个技能:
用户输入:
加载 brainstorming 技能
系统回复:
Skill "brainstorming" loaded.你应该看到:AI 返回加载成功的提示,技能内容已注入到上下文。
现在你可以测试 AI 是否遵循技能规则:
用户输入:
帮我写一段产品描述
系统回复:
(AI 会根据 brainstorming 技能的规则生成内容,遵循其中的技巧和流程)第 2 步:查看加载后的可用资源
加载技能时,系统会返回可用的脚本和文件列表:
用户输入:
加载 git-helper
系统回复:
Skill "git-helper" loaded.
Available scripts: tools/branch.sh, tools/commit.sh
Available files: docs/usage.md, examples/workflow.md这些信息告诉你技能目录下有哪些可用的资源:
- 脚本:可以用
run_skill_script工具执行 - 文件:可以用
read_skill_file工具读取
你应该看到:加载成功的消息,后面跟着可选的脚本和文件列表。
第 3 步:使用命名空间加载同名技能
假设项目级和用户级都有 build-helper 技能:
用户输入:
加载 build-helper
系统回复:
Skill "build-helper" loaded.
Available scripts: build.sh, optimize.sh
用户输入:
(检查加载的是哪个版本的 build-helper)根据技能发现优先级,默认加载项目级技能。如果你需要用户级的:
用户输入:
加载 user:build-helper
系统回复:
Skill "build-helper" loaded.
Available scripts: ci.sh, test.sh
Available files: README.md你应该看到:通过 namespace:skill-name 格式加载不同来源的同名技能。
第 4 步:体验技能指导效果
加载技能后,AI 的行为应该遵循技能定义的规则。以 brainstorming 技能为例:
用户输入:
加载 brainstorming
帮我构思一个智能家居产品的核心卖点
系统回复:
(AI 会使用 brainstorming 技能中定义的技巧,如:
- 先列出可能的方向,再深入探索
- 避免过早评判想法
- 使用"是的,而且..."扩展思路
- 记录所有想法后再筛选)
让我们先列出可能的方向:
1. 便利性控制
2. 能源管理
3. 安全防护
...你应该看到:AI 的回答风格和流程与技能中定义的一致。
第 5 步:理解技能在长会话中的持久性
进行长时间的对话,观察技能是否保持有效:
用户输入:
加载 docker-helper
(进行多轮对话,涉及构建、部署等操作)
...
(假设对话很长,触发了 OpenCode 的上下文压缩)
用户输入:
继续之前的 Docker 部署
系统回复:
(AI 仍然能够访问 docker-helper 的内容,
因为插件在压缩后重新注入了技能列表)压缩恢复机制
插件监听 session.compacted 事件,当会话压缩时会重新注入技能列表,确保已加载的技能在压缩后仍可访问。
你应该看到:即使对话很长、上下文被压缩,AI 仍能访问技能内容。
第 6 步:加载 Claude Code 格式的技能
如果你有 Claude Code 技能,它们会被自动发现:
用户输入:
列出所有可用技能
系统回复:
...
claude-code-superpowers (claude-plugins)
完整的软件开发工作流
用户输入:
加载 claude-code-superpowers
系统回复:
Skill "claude-code-superpowers" loaded.加载 Claude 格式技能时,会自动注入工具映射(toolTranslation),将 Claude 的工具名称映射到 OpenCode 的工具:
工具映射示例
- Claude 的
TodoWrite→ OpenCode 的todowrite - Claude 的
Task→ OpenCode 的task(子代理) - Claude 的
Bash→ OpenCode 的bash
你应该看到:技能加载成功,AI 可以理解并使用 Claude 格式的工作流。
检查点 ✅
- [ ] 你能使用
use_skill加载技能吗? - [ ] 你能理解技能内容以 XML 格式注入的机制吗?
- [ ] 你能说出 synthetic 消息的两个关键标志吗?
- [ ] 你能解释为什么技能在会话压缩后仍可用吗?
- [ ] 你能使用命名空间加载同名技能的不同版本吗?
踩坑提醒
陷阱 1:技能名称拼写错误
如果输入了错误的技能名称:
用户输入:
加载 brainstormig
系统回复:
Skill "brainstormig" not found. Did you mean "brainstorming"?插件会基于编辑距离提供模糊匹配建议。
解决:检查拼写或使用 get_available_skills 查看正确的名称。
陷阱 2:同名技能的混淆
如果项目级和用户级有同名技能,你可能会加载到错误的版本:
用户输入:
加载 build-helper
系统回复:
Skill "build-helper" loaded.
Available scripts: build.sh, optimize.sh # 这是项目级的
用户期望加载用户级的,但默认加载的是项目级解决:使用命名空间明确指定,如 user:build-helper。
陷阱 3:技能内容未生效
有时候你加载了技能,但 AI 似乎没有遵循规则:
用户输入:
加载 my-conventions
(期望 AI 遵循代码规范)
用户输入:
写一个函数
系统回复:
(AI 写的代码不符合预期规范)可能原因:
- 技能 SKILL.md 的内容不够明确
- 技能描述不够详细,AI 理解有偏差
- 长对话中上下文被压缩,技能列表需要重新注入
解决:
- 检查技能的 frontmatter 和内容是否清晰
- 明确告诉 AI 使用特定规则:"请使用 my-conventions 技能中的规则"
- 在压缩后重新加载技能
陷阱 4:Claude 技能的工具映射问题
加载 Claude Code 技能后,AI 可能仍然使用错误的工具名称:
用户输入:
加载 claude-code-superpowers
使用 TodoWrite 工具
系统回复:
(AI 可能尝试使用错误的工具名称,因为没有正确映射)原因:技能加载时会自动注入工具映射,但 AI 可能需要明确提示。
解决:在加载技能后,明确告诉 AI 使用映射后的工具:
用户输入:
加载 claude-code-superpowers
注意使用 todowrite 工具(而不是 TodoWrite)本课小结
use_skill 工具将技能内容以 XML 格式注入到会话上下文中,通过 Synthetic Message Injection 机制实现:
- XML 结构化注入:包含元数据、工具映射和技能内容
- Synthetic 消息:
noReply: true和synthetic: true确保消息对用户隐藏 - 持久可用:即使上下文压缩,技能内容仍可访问
- 命名空间支持:
namespace:skill-name格式精确指定技能来源 - Claude 兼容:自动注入工具映射,支持 Claude Code 技能
技能加载是让 AI 遵循特定工作流和规则的关键机制,通过内容注入,AI 可以在整个对话过程中保持一致的行为风格。
下一课预告
下一课我们学习 自动技能推荐:语义匹配原理。
你会学到:
- 理解插件如何基于语义相似度自动推荐相关技能
- 掌握 embedding 模型和余弦相似度计算的基本原理
- 了解技能描述优化技巧以获得更好的推荐效果
- 理解 embedding 缓存机制如何提升性能
附录:源码参考
点击展开查看源码位置
更新时间:2026-01-24
| 功能 | 文件路径 | 行号 |
|---|---|---|
| UseSkill 工具定义 | src/tools.ts | 200-267 |
| injectSyntheticContent 函数 | src/utils.ts | 147-162 |
| injectSkillsList 函数 | src/skills.ts | 345-370 |
| resolveSkill 函数 | src/skills.ts | 269-283 |
| listSkillFiles 函数 | src/skills.ts | 289-316 |
关键常量:
- 无
关键函数:
UseSkill():接受skill参数,构建 XML 格式的技能内容并注入到会话injectSyntheticContent(client, sessionID, text, context):通过client.session.prompt()注入 synthetic 消息,设置noReply: true和synthetic: trueinjectSkillsList():在首次消息时注入<available-skills>列表resolveSkill(skillName: string, skillsByName: Map<string, Skill>):支持namespace:skill-name格式的技能解析listSkillFiles(skillPath: string, maxDepth: number):递归列出技能目录下的所有文件(排除 SKILL.md)
业务规则:
- 技能内容以 XML 格式注入,包含元数据、工具映射和内容(
tools.ts:238-249) - 注入消息标记为 synthetic,不计入用户输入(
utils.ts:159) - 已加载的技能在当前会话中不再推荐(
plugin.ts:128-132) - 技能列表在首次消息时自动注入(
plugin.ts:70-105) - 会话压缩后重新注入技能列表(
plugin.ts:145-151)
XML 内容格式:
<skill name="${skill.name}">
<metadata>
<source>${skill.label}</source>
<directory>${skill.path}</directory>
<scripts>
<script>${script.relativePath}</script>
</scripts>
<files>
<file>${file}</file>
</files>
</metadata>
${toolTranslation}
<content>
${skill.template}
</content>
</skill>