Skip to content

Skills(技能系统)

Skills 系统让你将 Agent 的能力拆分为具名、自包含的单元。每个 Skill 只负责一个业务域 —— Agent 自动将请求路由到最合适的那个。

为什么需要 Skills?

传统 Agent 将所有能力写在单一 System Prompt 里。随着能力增长,Prompt 越来越长,越来越难维护,路由逻辑散落在 if/else 里。Skills 的解法:

  • 每个能力有自己专属的系统提示词和工具集
  • 非开发者可以通过编辑 Markdown 文件定义新 Skill
  • 两级路由(规则路由 + LLM 路由)自动分发,无需手写分发逻辑

定义 Skill

Markdown Skill(推荐)

创建 SKILL.md,frontmatter 定义路由元数据,正文成为系统提示词:

markdown
---
name: code-reviewer
description: 审查 TypeScript 和 JavaScript 代码,发现 Bug、类型安全问题和性能隐患。
triggerHint: 当用户要求审查、检查或改善代码质量时
---

# 代码审查员

你是一位资深 TypeScript 工程师,正在进行严格的代码审查。

## 审查清单
- 类型安全:无隐式 `any`,返回值类型明确
- 错误处理:无未处理的 Promise rejection
- 性能:不必要的循环、内存泄漏

## 输出格式
1. **总体评价** — 一句话总结
2. **问题列表** — 严重程度 + 修复建议
3. **改进后的代码**
ts
import { SkillLoader, SkillRunner } from "@agenticforge/skills";
import { LLMClient } from "@agenticforge/core";

const llm = new LLMClient({ provider: "openai", model: "gpt-4o" });
const skills = await SkillLoader.fromDirectory("./skills");
const runner = new SkillRunner({ llm, skills });

const result = await runner.run(
  "帮我审查:async function fetchUser(id) { return fetch('/api/' + id).then(r => r.json()); }"
);
console.log(result.output);

TypeScript Skill

ts
import { AgentSkill } from "@agenticforge/skills";
import type { SkillContext, SkillResult } from "@agenticforge/skills";
import type { LLMClient } from "@agenticforge/core";

class StockSkill extends AgentSkill {
  constructor() {
    super({
      name: "stock-query",
      description: "查询任意股票的实时价格和市场数据。",
      triggerHint: "当用户询问股票价格、市值、代码或交易数据时",
    });
  }

  override async execute(ctx: SkillContext, llm: LLMClient): Promise<SkillResult> {
    const price = await fetchStockPrice(extractTicker(ctx.query));
    const output = await llm.think([
      { role: "system", content: "用简洁友好的语言格式化股票数据。" },
      { role: "user",   content: `行情:${JSON.stringify(price)}\n问题:${ctx.query}` },
    ]);
    return { output };
  }
}

两级路由策略

SkillRunnerSkillAgent 使用两级策略,在速度和准确性之间取得平衡:

级别工作方式LLM 调用次数
规则路由(优先)triggerHint 关键词与 query 匹配0
LLM 路由(兜底)把所有 Skill 描述发给 LLM 做意图分类1
ts
const runner = new SkillRunner({
  llm,
  skills: [...mdSkills, new StockSkill(), new CalendarSkill()],
  fallbackPrompt: "你是一个通用助理。",
});

await runner.run("明天柏林天气如何?");         // => 天气 Skill(规则路由命中)
await runner.run("帮我审查一下这段 TS 代码。");  // => code-reviewer Skill
await runner.run("特斯拉现在股价多少?");        // => StockSkill
await runner.run("帮我约一个周五下午三点的会。"); // => CalendarSkill

// 跳过路由,直接调用指定 Skill
await runner.runSkill("stock-query", "AAPL 和 MSFT 本周走势对比");

进阶:SkillDispatcher

如果你需要路由能力但不想用完整的 SkillRunner,可以直接使用 SkillDispatcher

ts
import { SkillDispatcher, SkillRegistry } from "@agenticforge/skills";

const registry = new SkillRegistry();
registry.register(weatherSkill);
registry.register(stockSkill);

const dispatcher = new SkillDispatcher(registry, llm);
const skill = await dispatcher.dispatch("东京明天下雨吗?");
if (skill) {
  const result = await skill.execute({ query }, llm);
}

与 SkillAgent 配合使用

ts
import { SkillAgent } from "@agenticforge/agents";
import { SkillLoader } from "@agenticforge/skills";

const skills = await SkillLoader.fromDirectory("./skills");
const agent = new SkillAgent({ name: "assistant", llm, skills });

// 对话历史自动维护
await agent.run("伦敦今天天气怎么样?");
await agent.run("那东京呢?");         // 知道上一轮在问天气
await agent.run("哪个城市更暖和?");   // 继续路由到天气 Skill

agent.clearHistory();

SkillRunner vs SkillAgent

SkillRunnerSkillAgent
@agenticforge/skills@agenticforge/agents
对话历史手动传入(options.history自动维护
继承 Agent 基类
适用场景脚本、API 服务完整 Agent 工作流

Skill 文件命名

SkillLoader 识别:

  • SKILL.md —— 推荐
  • *.skill.md

其他 .md 文件(README.mdexamples.md)会被忽略。

Released under the CC BY-NC-SA 4.0 License.