主题
10. 技能系统:可复用的专业能力
渐进式披露——让代理按需加载专业知识
引言
想象一个场景:你的代理需要掌握 100 种不同的编程框架知识。如果把所有知识都塞进系统提示词,会导致:
- 上下文窗口被占满
- 无关信息干扰判断
- Token 成本急剧上升
技能系统解决了这个问题——通过渐进式披露(Progressive Disclosure),让代理只在需要时加载相关知识。

┌─────────────────────────────────────────────────────────────┐
│ 代理上下文 │
│ │
│ 系统提示词(精简) │
│ + 当前对话 │
│ + 按需加载的技能 ←─────────────────────┐ │
│ │ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ 技能库 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ React │ │ Vue │ │ Python │ │ Go │ │
│ │ SKILL │ │ SKILL │ │ SKILL │ │ SKILL │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 用户问 React 问题 → 只加载 React 技能 │
│ │
└─────────────────────────────────────────────────────────────┘核心概念
什么是技能?
技能是一种特殊的 Markdown 文件(SKILL.md),包含:
- 元数据(Frontmatter):描述技能的属性
- 正文:具体的知识、指南、模板
渐进式披露
传统方式:
┌─────────────────────────────────────────┐
│ 系统提示词 │
│ + 所有框架知识(100个) │ ← 上下文爆炸
│ + 当前对话 │
└─────────────────────────────────────────┘
技能系统:
┌─────────────────────────────────────────┐
│ 系统提示词 │
│ + 技能目录(100行描述) │ ← 轻量级
│ + 当前对话 │
│ + 按需加载的技能(1-2个) │ ← 只在需要时加载
└─────────────────────────────────────────┘生活类比
技能系统就像图书馆:
- 代理知道图书馆里有哪些书(技能目录)
- 但不会把所有书都搬到桌上
- 需要时才去借阅相关的书(加载技能)
SKILL.md 文件格式
基础结构
markdown
---
name: react-component-generator
description: 生成 React 组件的技能
---
# React 组件生成技能
## 使用方法
当用户要求创建 React 组件时,遵循以下步骤:
1. 确认组件类型(函数组件/类组件)
2. 确认是否需要 TypeScript
3. 生成组件代码
## 代码模板
### 函数组件模板
\`\`\`tsx
interface ${ComponentName}Props {
// props
}
export const ${ComponentName}: React.FC<${ComponentName}Props> = (props) => {
return (
<div>
{/* content */}
</div>
);
};
\`\`\`Frontmatter 字段详解
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | ✅ | 技能唯一标识符 |
description | string | ✅ | 技能描述(用于判断是否加载) |
license | string | ❌ | 许可证 |
compatibility | string[] | ❌ | 兼容的框架/环境 |
metadata | object | ❌ | 自定义元数据 |
allowed-tools | string[] | ❌ | 技能允许使用的工具 |

完整示例
markdown
---
name: nextjs-app-router
description: Next.js 14 App Router 开发指南,包含路由、布局、数据获取等最佳实践
license: MIT
compatibility:
- Next.js 14+
- React 18+
- TypeScript
metadata:
version: "1.0.0"
author: "DeepAgents Team"
updated: "2024-01-15"
allowed-tools:
- read_file
- write_file
- edit_file
---
# Next.js App Router 开发指南
## 概述
Next.js 14 的 App Router 是基于 React Server Components 的全新路由系统。
## 目录结构
\`\`\`
app/
├── layout.tsx # 根布局
├── page.tsx # 首页
├── loading.tsx # 加载状态
├── error.tsx # 错误边界
├── not-found.tsx # 404 页面
├── api/
│ └── route.ts # API 路由
└── [dynamic]/
└── page.tsx # 动态路由
\`\`\`
## 路由约定
### 页面文件
- `page.tsx` - 路由的 UI
- `layout.tsx` - 共享布局
- `loading.tsx` - 加载 UI
- `error.tsx` - 错误 UI
- `not-found.tsx` - 404 UI
### 代码示例
\`\`\`tsx
// app/blog/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: { slug: string };
}) {
const post = await getPost(params.slug);
return <article>{post.content}</article>;
}
\`\`\`
## 数据获取
### Server Components
\`\`\`tsx
// 直接在组件中 async/await
async function ProductList() {
const products = await fetch('https://api.example.com/products');
return <ul>{/* render products */}</ul>;
}
\`\`\`
### Client Components
\`\`\`tsx
'use client';
import { useState, useEffect } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
\`\`\`
## 最佳实践
1. 优先使用 Server Components
2. 只在需要交互时使用 'use client'
3. 使用 loading.tsx 提供加载状态
4. 使用 error.tsx 处理错误边界配置技能
方式一:指定技能目录
typescript
import { createDeepAgent } from "deepagents";
import { MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const agent = createDeepAgent({
skills: ["/skills/"], // 技能目录路径
checkpointer,
systemPrompt: "你是一个编码助手,可以使用各种框架技能。"
});方式二:指定具体技能文件
typescript
const agent = createDeepAgent({
skills: [
"/skills/react/SKILL.md",
"/skills/vue/SKILL.md",
"/skills/typescript/SKILL.md",
],
checkpointer,
});传入技能文件
调用时需要提供技能文件的实际内容:
typescript
import { createFileData } from "deepagents";
const reactSkill = `---
name: react-basics
description: React 基础知识
---
# React 基础
...技能内容...
`;
const result = await agent.invoke({
messages: [{ role: "user", content: "帮我创建一个 React 组件" }],
files: {
"/skills/react/SKILL.md": createFileData(reactSkill),
},
}, { configurable: { thread_id: "thread-1" } });技能加载时机
SkillsMiddleware 会在以下时机决定是否加载技能:
自动加载
当代理发送消息时,中间件会:
- 分析当前对话上下文
- 检查技能目录中的技能描述
- 判断哪些技能与当前任务相关
- 自动加载相关技能到上下文
手动触发
代理也可以主动请求加载技能:
typescript
// 在系统提示词中指导代理
systemPrompt: `...
## 技能使用
你有以下技能可用:
- react-basics: React 基础知识
- nextjs-app-router: Next.js App Router 指南
- typescript-tips: TypeScript 高级技巧
当需要特定框架知识时,相关技能会自动加载到上下文中。
`
技能 vs 记忆
| 特性 | 技能 (Skills) | 记忆 (Memory) |
|---|---|---|
| 来源 | 开发者预定义 | 代理从交互中学习 |
| 内容 | 操作指南、模板、知识 | 用户偏好、事实、历史 |
| 可修改 | ❌ 通常只读 | ✅ 代理可读写 |
| 作用域 | 全局共享 | 特定用户/线程 |
| 加载时机 | 按需加载(渐进式披露) | 对话开始时 |
| 存储 | 文件系统 | StoreBackend (持久化) |
使用场景对比
用户问:"我喜欢什么风格的代码?"
→ 记忆(用户偏好)
用户问:"Next.js 的 App Router 怎么用?"
→ 技能(框架知识)
用户问:"上次我们讨论的项目架构是什么?"
→ 记忆(历史交互)
用户问:"React 组件的最佳实践是什么?"
→ 技能(通用知识)
技能与子代理
继承规则
| 子代理类型 | 技能继承 |
|---|---|
| 通用子代理 (general-purpose) | ✅ 自动继承主代理技能 |
| 自定义子代理 | ❌ 不继承,需显式配置 |
为子代理配置技能
typescript
const codeReviewer = {
name: "code-reviewer",
description: "代码审查专家",
systemPrompt: "你是一位资深代码审查专家。",
tools: [readFileTool],
skills: ["/skills/code-review/", "/skills/security/"], // 子代理专属技能
};
const agent = createDeepAgent({
skills: ["/skills/general/"], // 主代理技能
subagents: [codeReviewer],
});技能隔离
技能状态在主代理和子代理之间完全隔离:
- 主代理的技能对子代理不可见
- 子代理的技能对主代理不可见
- 每个代理有独立的 SkillsMiddleware 实例

创建自定义技能
步骤 1:规划技能结构
/skills/
├── react/
│ ├── SKILL.md # React 基础
│ └── hooks/
│ └── SKILL.md # React Hooks 专题
├── vue/
│ └── SKILL.md # Vue 基础
├── typescript/
│ ├── SKILL.md # TypeScript 基础
│ └── advanced/
│ └── SKILL.md # TypeScript 高级
└── testing/
└── SKILL.md # 测试技能步骤 2:编写技能文件
markdown
---
name: react-hooks
description: React Hooks 完全指南,包含 useState、useEffect、useContext 等所有内置 Hook 的使用方法和最佳实践
compatibility:
- React 16.8+
allowed-tools:
- read_file
- write_file
- edit_file
---
# React Hooks 完全指南
## useState
### 基础用法
\`\`\`tsx
const [count, setCount] = useState(0);
\`\`\`
### 函数式更新
\`\`\`tsx
setCount(prev => prev + 1);
\`\`\`
## useEffect
### 基础用法
\`\`\`tsx
useEffect(() => {
// 副作用逻辑
return () => {
// 清理函数
};
}, [dependencies]);
\`\`\`
### 常见模式
#### 只在挂载时执行
\`\`\`tsx
useEffect(() => {
// 只执行一次
}, []);
\`\`\`
#### 监听特定依赖
\`\`\`tsx
useEffect(() => {
// 当 userId 变化时执行
}, [userId]);
\`\`\`
## useContext
### 创建 Context
\`\`\`tsx
const ThemeContext = createContext<Theme>('light');
\`\`\`
### 使用 Context
\`\`\`tsx
const theme = useContext(ThemeContext);
\`\`\`
## 自定义 Hook
### 模板
\`\`\`tsx
function useCustomHook(params) {
const [state, setState] = useState(initialValue);
useEffect(() => {
// 副作用逻辑
}, [params]);
return { state, ...actions };
}
\`\`\`
### 示例:useLocalStorage
\`\`\`tsx
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
\`\`\`
## 最佳实践
1. **依赖数组要完整**:包含所有在 effect 中使用的响应式值
2. **避免无限循环**:注意对象和数组的引用稳定性
3. **合理拆分 Hook**:一个 Hook 只做一件事
4. **使用 ESLint 插件**:eslint-plugin-react-hooks步骤 3:组织技能目录
typescript
const agent = createDeepAgent({
skills: ["/skills/"], // 包含所有技能的根目录
checkpointer,
systemPrompt: `你是一个全栈开发助手。
## 可用技能
你有以下技能库可用(会按需自动加载):
### 前端框架
- react-basics: React 基础知识
- react-hooks: React Hooks 完全指南
- vue-basics: Vue 3 基础知识
- nextjs-app-router: Next.js App Router 指南
### 后端开发
- nodejs-basics: Node.js 基础
- express-guide: Express.js 指南
- prisma-orm: Prisma ORM 使用
### 测试
- testing-basics: 测试基础
- vitest-guide: Vitest 使用指南
当用户询问相关问题时,对应的技能会自动加载到上下文中。
`
});实践示例
多框架编码助手
typescript
import { createDeepAgent } from "deepagents";
import { MemorySaver } from "@langchain/langgraph";
import { createFileData } from "deepagents";
const checkpointer = new MemorySaver();
const skills = {
"/skills/react/SKILL.md": createFileData(`---
name: react-basics
description: React 组件开发基础
---
# React 基础
...
`),
"/skills/vue/SKILL.md": createFileData(`---
name: vue-basics
description: Vue 3 组件开发基础
---
# Vue 3 基础
...
`),
"/skills/typescript/SKILL.md": createFileData(`---
name: typescript-tips
description: TypeScript 高级技巧
---
# TypeScript 技巧
...
`),
};
const codingAssistant = createDeepAgent({
skills: ["/skills/"],
checkpointer,
systemPrompt: `你是一个全栈开发助手,精通多种前端框架。
## 技能库
你有以下技能可用:
- react-basics: React 组件开发
- vue-basics: Vue 3 组件开发
- typescript-tips: TypeScript 高级技巧
当用户询问特定框架问题时,相关技能会自动加载。
## 工作方式
1. 理解用户需求
2. 判断需要哪种框架知识
3. 使用对应技能提供解答
4. 给出可运行的代码示例
`
});
async function main() {
const result = await codingAssistant.invoke({
messages: [{ role: "user", content: "帮我用 React 写一个计数器组件" }],
files: skills,
}, { configurable: { thread_id: "thread-1" } });
console.log(result.messages[result.messages.length - 1].content);
}
main();最佳实践
1. 技能粒度适中
✅ 好:一个技能聚焦一个主题
/skills/react-hooks/SKILL.md
/skills/react-context/SKILL.md
/skills/react-performance/SKILL.md
❌ 差:一个技能包含太多内容
/skills/react-everything/SKILL.md // 太大,加载时占用过多上下文2. 描述要精准
markdown
---
name: nextjs-app-router
description: Next.js 14 App Router 开发指南,包含路由、布局、数据获取、Server Components 等最佳实践
---
// ✅ 好:描述清晰,包含关键词,便于 LLM 判断是否加载markdown
---
name: nextjs
description: Next.js 相关
---
// ❌ 差:描述太模糊,LLM 难以判断3. 代码示例要完整
markdown
## 代码示例
### 完整的组件实现
\`\`\`tsx
// ✅ 好:完整、可运行的代码
import { useState } from 'react';
interface CounterProps {
initialValue?: number;
}
export function Counter({ initialValue = 0 }: CounterProps) {
const [count, setCount] = useState(initialValue);
return (
<div>
<span>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
\`\`\`
// ❌ 差:片段代码,缺少上下文
\`\`\`tsx
const [count, setCount] = useState(0);
\`\`\`4. 版本兼容性标注
markdown
---
name: react-server-components
compatibility:
- React 18+
- Next.js 13+
---
// 明确标注版本要求,避免用于不兼容的环境
小结
本文介绍了 DeepAgents 技能系统的核心概念和使用方法:
| 概念 | 说明 |
|---|---|
| 渐进式披露 | 按需加载,避免上下文爆炸 |
| SKILL.md | 技能文件格式 |
| Frontmatter | 技能元数据 |
| SkillsMiddleware | 自动判断和加载技能 |
SKILL.md 结构:
- Frontmatter:name、description、compatibility、allowed-tools
- 正文:知识、指南、代码模板
与记忆的区别:
- 技能 = 开发者预定义的通用知识
- 记忆 = 代理学习的用户特定信息
最佳实践:
- ✅ 技能粒度适中
- ✅ 描述精准、包含关键词
- ✅ 代码示例完整可运行
- ✅ 标注版本兼容性

下一步
恭喜你完成了高级功能篇的学习!在接下来的教程中,我们将探索:
- 安全执行篇:沙盒系统
- 流式处理篇:实时输出
- CLI 工具篇:终端编码助手
- 项目实战篇:完整项目开发
实践任务
- 为你常用的框架创建一个 SKILL.md 文件
- 测试技能的自动加载:让代理根据问题自动选择技能
- 比较使用技能和不使用技能时的回答质量