深入解析 Gemini CLI 的 `activate_skill` 工具:按需激活 Agent Skills 的原理与实践
本文围绕 gemini-cli 的 activate_skill 工具展开,系统讲解它如何让 Gemini 智能体按需加载面向特定工程任务的专家技能(Agent Skills)。结合原文档 docs/tools/activate-skill.md 与仓库源码,你将理解 Skill 从“发现”到“激活”再到“指令注入”的完整生命周期、name 参数为何是运行时动态生成的枚举、激活前后发生了哪些底层行为,以及如何在会话中配合 /skills 命令使用这一机制。
一、activate_skill 是什么
activate_skill 是 gemini-cli 内置工具(对应的工具名常量 ACTIVATE_SKILL_TOOL_NAME = 'activate_skill' 定义于 base-declarations.ts)。它的作用是让 Gemini CLI 在与任务相关时加载“专门的程序化专业知识与资源”。
Skills(技能)本质上是为特定工程任务量身定制的“指令 + 工具”包,例如代码审查(code-reviewer)、创建 Pull Request(pr-creator)、撰写文档(docs-writer)等。activate_skill 即 Gemini 智能体用来“激活”这样一个技能包、从而获得细粒度准则与专用工具的入口。
与持续注入会话上下文的 GEMINI.md(见 GEMINI.md 机制文档)不同,Skill 代表按需调用的专长(on-demand expertise)。这种“渐进式披露(progressive disclosure)”设计,使终端 Agent 可以维护一个庞大的专用能力库(安全审计、云部署、代码库迁移等),却不必在模型上下文中常驻全部细节,从而节省大量 token。关于 Agent Skills 的整体概念与背景,可参阅 Agent Skills 指南。
二、工具参数:name
activate_skill 只接受一个参数:
| 参数 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
name |
enum(字符串枚举) | 是 | 要激活的技能名称,例如 code-reviewer、pr-creator、docs-writer |
这个枚举不是写死的,而是在运行时根据当前会话已发现的全部技能动态生成的。在 dynamic-declaration-helpers.ts 中,getActivateSkillDeclaration(skillNames) 会做两件事:
- 把发现的技能名拼成一个 Zod
z.enum(skillNames)校验器,再转换为 JSON Schema 作为工具参数声明; - 在工具描述中追加当前可用的技能清单提示,例如
(Available: 'code-reviewer', 'docs-writer'),并明确指示模型“ONLY use names exactly as they appear in the<available_skills>section”,即只能使用出现在可用技能清单中的确切名称,防止模型凭空捏造技能名。
值得注意的边界情况:当某次会话没有任何可用技能(skillNames.length === 0)时,name 会退化为一个普通字符串,描述为“No skills are currently available.”,从根本上杜绝模型发起注定失败的激活请求。
工具注册层同样遵循动态构造策略:ActivateSkillTool 构造函数以及其 getSchema(modelId?) 方法都会调用 config.getSkillManager().getSkills() 重新拉取技能列表,并通过 getActivateSkillDefinition(skillNames) 生成定义(见 coreTools.ts)。这意味着一旦技能发现结果发生变化,模型看到的工具声明也会同步更新。
三、一个纯粹由 Agent 驱动的工具
activate_skill 的一个关键约束是:它仅由 Gemini 智能体内部调用,用户无法手动触发。也就是说,你不会在交互界面中直接输入命令去“运行”它,而是通过 /skills 会话命令管理技能(/skills list 查看、/skills enable|disable 启用与禁用),再把任务交给 Agent,由 Agent 自行判断何时需要调用本工具。
完整的激活生命周期可以划分为五个阶段(详细流程参见 Agent Skills 指南 的 “How it works” 一节):
- 发现(Discovery):会话启动时,Gemini CLI 扫描若干技能发现层级,把所有已启用技能的名称与描述注入系统提示词;
- 激活(Activation):当 Gemini 判断任务与某个技能描述匹配时,调用
activate_skill工具; - 征询(Consent):界面弹出确认提示,说明技能的名称、用途以及它将要获得访问权的目录路径,等待用户批准;
- 注入(Injection):经用户同意后,
SKILL.md正文与目录结构加入对话历史,技能所在目录被加入 Agent 允许访问的路径集合,从而可以读取捆绑资源; - 执行(Execution):模型在“激活态”下继续完成任务,并被要求合理遵循该技能的程序化指导。
一旦技能被激活,Agent 的行为会在任务完成之前持续受到该技能指令的约束与引导,而不是一次性“用完即弃”。
四、激活后的三类行为特征
原文档从三个维度概括了 activate_skill 对 Agent 能力的增强,理解它们有助于设计高质量技能:
- 专门的逻辑(Specialized logic):技能内包含专家级、面向复杂工作流的操作流程。激活后,
SKILL.md正文中的分步指引会进入模型上下文,将模糊的“帮我审查代码”转化为可重复、有校验标准的步骤链。 - 动态能力(Dynamic capability):激活技能可能为 Agent 授予新的、任务专用的工具访问权限。这是通过将技能目录加入工作区上下文(workspace context)实现的(详见下文源码解析)。
- 上下文感知(Contextual awareness):技能帮助 Agent 聚焦特定任务中最相关的标准与约定,例如某个团队的 PR 评审规范,避免把无关的通用准则混入当前任务。
需要澄清的是,“动态授予新工具”的实现在当前仓库中体现为:激活时技能目录被加入允许读取的文件路径,使 Agent 能访问技能捆绑的脚本、模板与示例数据——也就是“资源层面的能力扩展”。而激活状态本身由 SkillManager 中的 activeSkillNames: Set<string> 追踪,activateSkill(name) 与 isSkillActive(name) 分别用于登记与查询(见 skillManager.ts)。
五、源码级的激活实现解析
activate_skill 的核心实现位于 packages/core/src/tools/activate-skill.ts,其中 ActivateSkillToolInvocation 定义了实际的调用行为,主要包含四个关键步骤:
1. 校验技能存在性并回传描述
执行前会先通过 config.getSkillManager().getSkill(name) 查找技能(大小写不敏感):
- 若技能存在,
getDescription()返回"<skillName>": <description>形式的增强描述; - 若技能不存在,描述为
"<skillName>" (?) unknown skill,模型由此得知目标不可用。
2. 生成征询确认信息
非内建(non-builtin)技能的激活会触发一次 UI 确认。确认详情中包含三块信息:技能名称标题、技能描述,以及将向模型共享的目录资源结构(通过 getFolderStructure() 对 SKILL.md 所在目录生成树状清单)。用户确认后才允许继续。activate-skill.test.ts 中的 should return enhanced confirmation details 用例断言了标题为 Activate Skill: <name> 且 prompt 必须包含技能描述与目录结构。
需要特别指出的是内建技能(built-in skills)会跳过确认。这一点在 activate-skill.test.ts 中由 should skip confirmation for built-in skills 用例验证,因为内建技能随 CLI 发布、可信度较高。
3. 执行激活并注入指令
execute() 的核心逻辑(activate-skill.ts)依次完成:
- 再次校验技能;若查找失败,返回错误
Skill "<name>" not found. Available skills are: <列表>,错误类型为INVALID_TOOL_PARAMS,且不会调用激活方法(测试should return an error if skill content cannot be read验证了这一点); - 调用
skillManager.activateSkill(name)登记激活状态; - 调用
config.getWorkspaceContext().addDirectory(path.dirname(skill.location)),把技能所在目录加入工作区上下文,从而让 Agent 获得读取该目录下捆绑资源的权限; - 返回一段结构化 XML 作为
llmContent:
<activated_skill name="code-reviewer">
<instructions>
SKILL.md 中的正文指令
</instructions>
<available_resources>
技能目录的文件夹结构清单
</available_resources>
</activated_skill>
同时 returnDisplay 会向终端用户展示 Skill **code-reviewer** activated. Resources loaded from <目录> 与资源树。测试 should activate a valid skill and return its content in XML tags(activate-skill.test.ts)逐一断言了 activateSkill 被正确调用、目录被加入工作区上下文、且输出包含 <activated_skill>、<instructions>、<available_resources> 全部标签。
这种“结构化 XML + 目录清单”的输出格式,让模型既能读取技能的程序化指令,又能一眼看清自己现在可以读取哪些辅助资源——这正是“动态能力”在底层的数据形态。
六、技能从哪来:发现机制与优先级
activate_skill 的可用枚举完全取决于会话前的技能发现结果。SkillManager.discoverSkills()(skillManager.ts)按如下优先级(低→高)加载技能,同名时高优先级覆盖低优先级:
- 内建技能(Built-in):随 CLI 分发的标准技能,加载后被标记
isBuiltin = true; - 扩展技能(Extensions):由已安装并激活的扩展(extension)提供;
- 用户技能(User):位于用户级目录
~/.gemini/skills/或别名目录~/.agents/skills/; - 工作区技能(Workspace):位于项目内
.gemini/skills/或.agents/skills/别名目录,可随版本库共享给团队。
一个需要留意的细节:工作区技能仅在文件夹被标记为可信(trusted)时才会加载。若当前工作目录未被信任,discoverSkills 会提前返回并打印调试日志 “Workspace skills disabled because folder is not trusted.”,防止恶意仓库注入不受信任的技能。
每个技能的物理形态是一个目录 + SKILL.md 文件。skillLoader.ts(packages/core/src/skills/skillLoader.ts)把目录解析为 SkillDefinition:
| 字段 | 含义 |
|---|---|
name |
技能唯一名称 |
description |
一句话说明技能用途(注入提示词、用于匹配) |
location |
技能源文件(SKILL.md)的绝对路径 |
body |
技能正文(核心逻辑/指令) |
disabled |
是否被 /skills disable 禁用 |
isBuiltin |
是否为内建技能(激活时免确认) |
extensionName |
提供该技能的扩展名(若有) |
其中 name 与 description 通过解析 SKILL.md 顶部的 YAML frontmatter 获得;解析器在 YAML 失败时会回退到简单的键值解析器(见 skillLoader.ts),以兼容描述文本含冒号等特殊字符的情况。
此外,activate_skill 被列入 Plan Mode 可用的只读工具清单 PLAN_MODE_TOOLS(见 tool-names.ts),即规划模式下 Agent 同样可以浏览、激活技能以增强规划质量。
七、实战建议与延伸阅读
使用 activate_skill 前,最重要的是先保证目标技能已被发现并可用:
- 在交互会话中执行
/skills list查看当前已发现的技能及其描述;技能说明写得越贴合实际能力,Agent 的“任务匹配”就越准确; - 若技能未出现,检查它是否放置于正确的发现目录(用户级或工作区级),以及当前目录是否被信任;
- 由于激活需要用户在 UI 中确认(内建技能除外),请在对话中留意确认弹窗中对“将向模型共享的资源目录”的描述——它直接决定了技能捆绑资源是否会暴露给模型。
深入掌握这一机制,建议继续阅读仓库内配套资料:
- Agent Skills 使用指南:技能完整生命周期、发现层级、
/skills命令用法; - 构建 Agent 技能:如何编写
SKILL.mdfrontmatter、组织指令与捆绑资源; - Skills 快速上手教程:从零创建一个技能并激活的动手练习;
- 工具总览:
activate_skill与其他内置工具在整体工具矩阵中的位置。
若希望从测试层面反推工具的契约行为,activate-skill.test.ts 是最直接的“行为规格说明书”;若希望深入技能解析细节,则可以从 skillLoader.ts 与 skillManager.ts 继续追踪。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00