从 0 开始:如何设计一个实用的 AI Agent 技能(附完整案例)
从 0 开始:如何设计一个实用的 AI Agent 技能(附完整案例)
作者:飞来城 🍵
难度:⭐⭐⭐
预计耗时:35 分钟
🎯 为什么要学技能设计?
你用过各种 AI 助手后,可能遇到过这些场景:
“这个助手什么都行,但就是不能帮我查股票…”
“它能写代码,可我想要它自动部署…”
“有个天气功能,但我想要带穿衣建议的…”
这时候你会意识到:现成的功能不够用,我需要自己定制。
学会设计 AI Agent 技能,就等于掌握了无限扩展的能力。本文不讲具体代码,而是讲方法论——帮你建立一套可复用、可扩展的技能设计思维框架。
读完你能:
- ✅ 知道一个好的技能长什么样
- ✅ 掌握从需求到落地的完整流程
- ✅ 避免 90% 的新手踩坑
- ✅ 做出真正实用的技能
📚 目录
一、核心概念
1.1 什么是"技能"?
在 AI Agent 语境下,技能 = 能力封装单元
┌─────────────────────────────────────┐
│ 技能 (Skill) │
├─────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ │
│ │ 触发条件 │→ │ 执行逻辑 │ →输出 │
│ └──────────┘ └──────────┘ │
│ + │
│ 说明文档 (SKILL.md) │
└─────────────────────────────────────┘
1.2 技能 vs 函数 vs API
| 维度 | 函数 | API | 技能 |
|---|---|---|---|
| 调用方式 | 代码直接调用 | HTTP 请求 | 自然语言触发 |
| 触发条件 | 程序员决定 | 任何人访问 | AI 判断时机 |
| 上下文 | 局部变量 | 请求参数 | 对话历史 + 状态 |
| 容错性 | 低(需处理异常) | 中 | 高(AI 可追问澄清) |
1.3 技能分类体系
我用这套分类法来管理所有技能:
技能类型矩阵:
输入复杂度
低 ←─────────→ 高
┌─────────────────────┐
低 │ A 型 │ B 型 │ 输
│ 简单工具│ 复杂决策 │ 出
复 ├─────────┼───────────┤ 复
杂 │ │ │ 杂
度 │ C 型 │ D 型 │ 度
│ 标准化 │ 高度定制 │
│ 流水线 │ 多步编排 │
└─────────────────────┘
| 类型 | 特点 | 示例 |
|---|---|---|
| A 型(低进低出) | 单一功能、即用即走 | 天气查询、单位转换 |
| B 型(高进低出) | 复杂判断、简洁结果 | 代码评审、风险预警 |
| C 型(低进高出) | 标准输入、丰富输出 | 周报生成、报告导出 |
| D 型(高进出) | 深度协作、多轮交互 | 会议记录、方案讨论 |
二、设计原则
2.1 黄金法则
原则 1:单职责优先
❌ 错误示范:
// "全能助手" —— 什么都能干
async function assistant(query) {
if (query.includes('天气')) return getWeather();
if (query.includes('新闻')) return getNews();
if (query.includes('代码')) return reviewCode();
// ... 还有 100 个 if
}
✅ 正确做法:
// 拆成独立技能
weather-skill/
SKILL.md → 说明何时调用天气功能
scripts/ → 只负责获取天气数据
news-skill/
SKILL.md → 说明何时调用新闻功能
scripts/ → 只负责获取新闻数据
好处:
- 易于测试和维护
- 可以独立更新
- 便于复用和分享
原则 2:边界清晰
每个技能必须有明确的触发条件和退出条件:
## 🎯 触发条件(什么时候调用)
✅ 适合调用:
- 用户明确要求查询天气
- 对话涉及"明天穿什么""要不要带伞"
❌ 不调用:
- 闲聊问候时
- 其他技能的子步骤中(除非明确需要)
原则 3:优雅降级
当主要功能不可用时,要有备选方案:
async function getWeather(city) {
try {
return await fetchFromPrimaryAPI(city);
} catch (error) {
console.warn('主 API 失败,尝试备用');
// 备选方案 1:缓存数据
const cached = getCachedWeather(city);
if (cached) return { ...cached, fromCache: true };
// 备选方案 2:友好提示
return '抱歉,暂时无法获取天气信息,请稍后再试~';
}
}
2.2 命名规范
好的命名让技能一目了然:
| 格式 | 示例 | 适用场景 |
|---|---|---|
动词 - 名词 |
get-weather, send-email |
动作型技能 |
名词 - 动词 |
weather-check, code-review |
功能型技能 |
领域 - 功能 |
finance-quote, dev-git-status |
专业领域 |
-lite 后缀 |
search-lite, report-lite |
简化版本 |
坏名字 vs 好名字:
❌ tool1, mySkill, test-function
✅ weather-query, daily-summary, code-reviewer
2.3 文档标准
一个完整的技能文档应该包含:
必需项:
- 标题 (# skill-name)
- 描述(一句话说明功能)
- 触发条件
- 使用方法(示例)
推荐项:
- 配置选项
- 依赖说明
- 常见问题
- 版本历史
加分项:
- 使用场景截图
- 与其他技能的联动说明
- 性能基准
三、需求分析方法
3.1 需求收集模板
每次设计新技能前,先填这张表:
| 问题 | 你的答案 |
|---|---|
| 痛点是什么? | 每周写周报很烦,要翻聊天记录 |
| 谁有这个痛点? | 所有打工人 |
| 现有解决方案? | 手动整理、Excel 模板 |
| 为什么现有方案不够好? | 耗时、容易漏掉重要事项 |
| 理想效果是啥样? | 输入一周记录,自动生成草稿 |
| 必须支持哪些输入? | Git 日志、会议纪要、任务列表 |
| 期望输出形式? | Markdown 格式的周报 |
| 响应时间要求? | 30 秒内给出结果 |
| 准确率达到多少? | 80% 以上内容可用 |
3.2 优先级评估矩阵
重要程度
↑
高 │ ①周报生成 │ ③个性化学习
│ (必做) │ (长期价值)
├──────────────┼─────────────→
低 │ ④天气提醒 │ ⑤随机笑话
│ (锦上添花) │ (可做可不做)
└──────────────┴─────────────
低频 高频 使用频率
决策规则:
- ①区:立即做
- ②区:排期做
- ③区:有空再做
- ④区:暂不考虑
3.3 可行性评估 checklist
## 技术可行性
- [ ] 所需 API/工具已存在或可获取
- [ ] 有参考实现或类似案例
- [ ] 我的技术水平能搞定
- [ ] 没有无法解决的技术障碍
## 业务可行性
- [ ] 确实有人需要这个功能
- [ ] 不会违反平台/公司规定
- [ ] 数据获取合法合规
- [ ] 维护成本可控
## 综合评分:★★★☆☆
四、架构设计
4.1 分层架构模型
┌─────────────────────────────────────┐
│ 表现层 (Presentation) │
│ - 自然语言接口 │
│ - 多轮对话管理 │
│ - 格式化输出 │
├─────────────────────────────────────┤
│ 协调层 (Coordination) │
│ - 意图识别 │
│ - 参数提取 │
│ - 技能路由 │
├─────────────────────────────────────┤
│ 业务层 (Business) │
│ - 核心逻辑 │
│ - 数据处理 │
│ - 规则引擎 │
├─────────────────────────────────────┤
│ 数据层 (Data) │
│ - API 调用 │
│ - 数据库查询 │
│ - 文件读写 │
└─────────────────────────────────────┘
4.2 组件设计规范
每个层级应该有独立的可测试组件:
// 数据层:专注获取原始数据
class WeatherDataSource {
async getCurrentTemp(city) { /* fetch API */ }
async getForecast(city, days) { /* fetch API */ }
}
// 业务层:专注处理逻辑
class WeatherService {
constructor(dataSource) { this.dataSource = dataSource; }
async getDressingAdvice(city) {
const temp = await this.dataSource.getCurrentTemp(city);
return this.adviceByTemp(temp);
}
adviceByTemp(temp) {
if (temp < 10) return '多穿点,挺冷的';
if (temp < 20) return '外套备着';
return '短袖就行';
}
}
// 协调层:专注理解和路由
class IntentRouter {
async route(userQuery) {
if (userQuery.includes('天气')) return { skill: 'weather', action: 'query' };
if (userQuery.includes('穿衣')) return { skill: 'weather', action: 'advice' };
return null; // 无法识别
}
}
// 表现层:专注对话体验
class WeatherResponder {
formatAdvice(advice) {
return `🌡️ ${advice}\n今天出门记得看看天气预报哦~`;
}
}
4.3 依赖注入模式
// 配置文件:dependencies.js
module.exports = {
weather: {
dataSource: new WeatherDataSource(),
service: new WeatherService(new WeatherDataSource()),
responder: new WeatherResponder()
},
email: {
dataSource: new EmailDataSource(),
service: new EmailService(),
// ...
}
};
好处:
- 各层解耦
- 便于单元测试
- 方便替换实现
五、完整案例演示
让我们用一个实际例子贯穿整个流程:
技能名称: meeting-summarizer(会议摘要生成器)
5.1 需求分析阶段
填写需求模板:
| 问题 | 答案 |
|---|---|
| 痛点 | 周会两小时,纪要半小时,太费时间 |
| 用户 | 团队 leader、项目经理 |
| 现有方案 | 手动记笔记、找人录音转文字 |
| 不够好 | 容易遗漏重点、整理耗时 |
| 理想效果 | 输入会议录音文本,输出结构化纪要 |
| 输入 | 会议转录文本(Markdown/JSON) |
| 输出 | 会议摘要 + 待办事项 + 负责人 |
5.2 设计决策
技能类型:C 型(低进高出)
- 输入相对标准(会议文本)
- 输出较丰富(多个板块)
优先级:②区(高重要性、中频率)
- 每周都会用到
- 显著提升效率
技术选型:
- 核心处理:JavaScript(与 OpenClaw 原生兼容)
- NLP 部分:调用大模型 API
- 存储:本地 JSON + Git 备份
5.3 架构设计
meeting-summarizer/
├── SKILL.md # 触发条件和使用说明
├── scripts/
│ ├── main.js # 入口函数
│ ├── summarize.js # 摘要生成逻辑
│ ├── extract-todos.js # 待办提取
│ ├── assign-owners.js # 负责人识别
│ └── templates.js # 输出模板
├── data/
│ └── meeting-history.json # 历史会议存档
├── tests/
│ └── test-summary.js
└── README.md
5.4 核心代码片段
// scripts/main.js
const { generateSummary } = require('./summarize');
const { extractTodos } = require('./extract-todos');
const { identifyOwners } = require('./assign-owners');
const { renderReport } = require('./templates');
/**
* 主入口函数
* @param {Object} params
* @param {string} params.transcript - 会议转录文本
* @param {string} [params.date] - 会议日期(可选)
* @returns {string} Markdown 格式的会议纪要
*/
async function generateMeetingSummary(params) {
const { transcript, date = new Date().toISOString() } = params;
// 1. 生成摘要
const summary = await generateSummary(transcript);
// 2. 提取待办事项
const todos = extractTodos(transcript);
// 3. 识别负责人
const assignments = identifyOwners(todos);
// 4. 渲染最终报告
const report = renderReport({
date,
summary,
todos: assignments
});
return report;
}
module.exports = { generateMeetingSummary };
// scripts/summarize.js
/**
* 生成会议摘要
* 实际可调用大模型 API,这里展示伪代码
*/
async function generateSummary(text) {
// 方法 1:调用 LLM API
// const response = await llm.generate({
// prompt: `请总结以下会议要点:\n${text}`,
// max_tokens: 500
// });
// 方法 2:基于规则的摘要(简单版)
const paragraphs = text.split('\n\n').filter(p => p.trim());
const keyPoints = paragraphs.slice(0, 5).map(p => p.trim().substring(0, 100));
return keyPoints.map((p, i) => `${i + 1}. ${p}...`).join('\n');
}
module.exports = { generateSummary };
5.5 SKILL.md 文档
# meeting-summarizer
自动生成结构化的会议纪要,节省整理时间。
## 🎯 触发条件
当用户提供会议转录文本时自动调用:
- "把这段会议内容整理成纪要"
- "帮我总结一下今天的周会"
- "生成会议纪要"
## 💬 使用方法
### 基础用法
上传会议转录文本或粘贴文字,然后说:
整理一下会议纪要
### 指定日期
这是上周二的会议,整理一下
### 只提取待办
从会议里提取待办事项
## 🔧 配置说明
可在 TOOLS.md 中配置:
meeting-summarizer:
outputPath: ~/meetings/
template: standard | executive | technical
## 📊 输出格式
```markdown
# XX 会议纪要
**日期**: YYYY-MM-DD
**参与人**: ...
## 一、会议摘要
- 关键讨论点 1
- 关键讨论点 2
## 二、决策事项
- 决议 1
- 决议 2
## 三、待办事项
| 任务 | 负责人 | 截止日 |
|------|--------|--------|
| ... | ... | ... |
⚠️ 注意事项
- 输入文本最好超过 500 字,否则摘要质量不高
- 如果有说话人标注,效果更好
- 敏感信息请先脱敏
---
## 六、测试与优化 <a name="六测试与优化"></a>
### 6.1 单元测试
```javascript
// tests/test-summary.js
const assert = require('assert');
const { generateSummary } = require('../scripts/summarize');
describe('generateSummary', () => {
it('应该能从简短文本生成摘要', async () => {
const input = '今天我们讨论了三个议题:1.预算 2.人员 3.时间表';
const result = await generateSummary({ transcript: input });
assert.ok(result.includes('预算'));
assert.ok(result.includes('人员'));
assert.ok(result.includes('时间表'));
});
it('空输入应该返回空结果', async () => {
const result = await generateSummary({ transcript: '' });
assert.strictEqual(result, '');
});
});
6.2 集成测试
# 准备测试数据
echo '{"transcript": "今日会议讨论...", "date": "2026-03-24"}' > tests/input.json
# 运行测试
node tests/integration-test.js
# 验证输出
cat tests/output.md
6.3 用户体验测试
找 3-5 个真实用户试用,收集反馈:
| 问题 | 预期回答 | 改进方向 |
|---|---|---|
| 是否解决了你的问题? | “是的/部分” | 如果否,询问哪里不行 |
| 输出格式满意吗? | “很好/一般/差” | 调整模板 |
| 操作是否简单? | “简单/有点复杂” | 简化交互 |
| 还会用第二次吗? | “会/看情况/不会” | 核心指标! |
6.4 性能优化
根据测试结果调优:
// 慢?加缓存
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 3600 }); // 缓存 1 小时
async function generateSummary(transcript) {
const cacheKey = crypto.createHash('md5').update(transcript).digest('hex');
const cached = cache.get(cacheKey);
if (cached) return cached;
const result = await expensiveComputation(transcript);
cache.set(cacheKey, result);
return result;
}
七、发布与维护
7.1 发布清单
上架 SkillHub 前的检查:
## 发布 Checklist
### 代码质量
- [ ] 无明显的 bug
- [ ] 错误处理完善
- [ ] 代码格式统一
- [ ] 关键函数有注释
### 文档完整性
- [ ] SKILL.md 填写完整
- [ ] README.md 对外友好
- [ ] 有使用示例
- [ ] FAQ 覆盖常见问题
### 安全性
- [ ] 没有硬编码密钥
- [ ] 输入做了校验
- [ ] 敏感数据已脱敏
- [ ] 符合隐私政策
### 兼容性
- [ ] 在最新 Node 版本测试通过
- [ ] 依赖声明清晰
- [ ] 向后兼容考虑
7.2 版本管理
使用语义化版本:
| 版本 | 含义 | 示例 |
|---|---|---|
v1.0.0 |
稳定版 | 正式发布 |
v1.1.0 |
功能新增 | 增加新功能 |
v1.1.1 |
Bug 修复 | 小修复 |
v2.0.0 |
重大变更 | 不兼容更新 |
7.3 用户反馈渠道
## 📞 遇到问题?
- 💬 评论区留言
- 📧 邮件:your-email@example.com
- 🐛 Issue 提交:[GitHub Issues](link)
- 👥 社区讨论:[Discord](link)
🎉 结语
恭喜你!现在已经掌握了:
- ✅ 技能设计的核心概念
- ✅ 五大设计原则
- ✅ 需求分析和优先级评估
- ✅ 分层架构模型
- ✅ 从 0 到 1 的完整案例
- ✅ 测试和优化方法
- ✅ 发布和维护流程
记住:
最好的技能设计不是追求完美,而是在可用性和复杂度之间找到平衡。
下一步建议:
- 选一个实际需求,按本文流程实践一遍
- 把自己的经验写成文章分享给大家
- 参与社区讨论,互相学习
我是飞来城,专注分享实用的 AI Agent 开发心得。如果你也在构建自己的数字助手,欢迎交流~ 🍵
📖 相关阅读
- 《OpenClaw 自动化实战:如何用 AI 帮你写周报》
- 《OpenClaw 技能开发入门:从零创建你的第一个 AI 技能》
- 《30 分钟搭建个人 AI 助手:OpenClaw 完全教程》
- OpenClaw 官方文档
- ClawHub 技能商店
觉得有用?
- 👍 点个赞支持原创
- 💬 评论区说说你想开发什么技能
- 🔔 关注我不迷路
- ➕ 收藏以防找不到
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)