04 · 技能系统工程化
把 skill 指令注入系统提示词,理解 skill 与 agent 的关系,以及可扩展的技能加载设计。
注入点:系统提示词的动态拼接
回顾 src/agent.ts 中系统提示词的构建方式。第 6 章把固定的字符串模板改成了动态拼接的数组,第 7 章利用这个灵活性注入 skill 指令:
const systemParts: string[] = [
"你是一个代码仓库助手...",
// 工具列表、工作方式、行为准则
];
// 项目规则(第 6 章)
if (options?.projectRules) {
systemParts.push("", "## 项目规则", "", "...", options.projectRules);
}
// skill 指令(第 7 章)
if (options?.skill) {
systemParts.push("", options.skill.instructions);
}
// 会话上下文(第 6 章)
if (contextText) {
systemParts.push("", contextText);
}
systemParts.push("", `工作目录:${state.workingDir}`);skill 的 instructions 直接追加到系统提示词的数组中。由于每个 skill 的 instructions 本身就是完整的 markdown 文本(带标题和分段),它自然地融入系统提示词的结构,不需要额外的包装。
RunAgentOptions 的变化
RunAgentOptions 新增了一个可选的 skill 字段:
export interface RunAgentOptions {
maxIterations?: number;
permissionGuard?: PermissionGuard;
emitter?: AgentEmitter;
contextManager?: ContextManager;
projectRules?: string;
/** 匹配到的 skill 指令(第 7 章新增) */
skill?: Skill;
}和之前新增的 permissionGuard、emitter、contextManager 一样,skill 是可选的。不传的话,agent 的行为和第 6 章完全一样。
Skill 与 Agent 的关系
理解 skill 在 agent 架构中的位置:
main.ts
├── SkillRegistry.match(input) → 选择 skill
├── SkillRegistry.stripSkillPrefix(input) → 剥离前缀
└── runAgent(state, model, tools, { skill })
├── 系统提示词 = 基础指令 + skill.instructions + 项目规则 + 上下文
├── ReAct 循环(不变)
└── 返回结果skill 不改变 agent 的核心逻辑。 ReAct 循环、工具执行、权限检查、事件发射——这些都不受 skill 影响。skill 唯一做的事情是改变系统提示词的内容,让模型用不同的方式来使用同样的工具。
这就是 skill 系统的优雅之处:同一个 agent,不同的系统提示词,就能产生截然不同的工作方式。
可扩展设计
当前的 skill 都是在代码中内置的(builtInSkills)。但 SkillRegistry 的设计支持更灵活的扩展方式:
注册自定义 skill:
const customSkill: Skill = {
name: "test",
description: "编写测试",
keywords: ["test", "测试", "spec"],
instructions: "## 测试技能\n...",
};
registry.register(customSkill);任何实现了 Skill 接口的对象都可以注册到 registry 中。将来可以从配置文件、远程 API 或者 skill 市场加载。
内置 skill + 自定义 skill 共存:
const registry = new SkillRegistry(); // 默认加载内置 skill
registry.register(customSkill); // 追加自定义 skillSkillRegistry 的构造函数接受可选的 skill 数组。不传就使用内置 skill,传了就使用传入的 skill 列表。这样测试时可以注入自定义 skill,不需要依赖内置定义。
测试覆盖
Skill 的测试文件在 test/skills/registry.test.ts 中,覆盖了:
- 显式匹配:
/debug xxx→ debug skill, source = "explicit" - 自动匹配: "帮我修 bug" → debug skill, source = "auto"
- 中文关键词匹配
- 多关键词冲突时选最多的
- 无匹配返回 null
- 前缀剥离
- 帮助文本格式化
测试时使用自定义的测试 skill(通过 makeSkill 辅助函数创建),不依赖内置 skill 的具体内容。
版本更新
main.ts 的版本号从 v0.6.0 升级到 v0.7.0。
本章回顾
第 7 章实现了 skill 系统,让 agent 能根据任务类型切换工作方式:
| 新增 | 文件 | 作用 |
|---|---|---|
| Skill 类型 | src/skills/types.ts | 定义 skill 的数据结构 |
| 内置 skill | src/skills/builtins.ts | debug、review、refactor 三个基础技能 |
| SkillRegistry | src/skills/registry.ts | 注册、匹配、前缀剥离 |
| skill 注入 | src/agent.ts | 把 skill 指令注入系统提示词 |
| skill 集成 | src/main.ts | 匹配 skill 并传入 agent |
加上之前章节的测试,整个项目现在有 155 个测试用例。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。