为什么学这一课
上一课(M01)我们讲了管控者的定位:你不是智能体的"用户",你是它的"立法者、审计员和紧急制动阀"。这一课,我们讲你手里最实在的一件工具——技能。
先说一个判断:未来三年,决定一个组织能不能管住智能体的,不是模型有多强,而是它的技能库设计得有多好。
为什么?因为大模型本身是不可控的——它是一个概率机器,你给它同样的指令,它可能给出不同的行为。但技能不一样。技能是人类亲手定义的、边界清晰的、可审计的执行单元。智能体可以天马行空,但它每一次"动手",都必须经过某个技能。技能就是智能体行为的海关:所有进出的动作,都要在这里报关、检查、盖章。
所以技能设计不是"开发技巧",它是权力设计。谁定义了技能的输入输出,谁就定义了智能体能做什么、不能做什么;谁规定了技能的权限,谁就规定了智能体能碰什么、不能碰什么。你在这一课学到的每一行设计,都是在为未来的智能体划定国境线。
打个比方:操作系统里,应用程序不能直接操作硬件,必须经过系统调用(syscall)。系统调用就是操作系统给应用划定的"合法动作清单"。技能,就是 AGI 时代的系统调用。而你,就是设计这套系统调用的人。
核心概念
1. 任务拆解(Task Decomposition):把混沌变成清单
所有技能工程的第一步,不是写技能,而是拆解任务。
人类说话是混沌的:"帮我把这周销售数据整理一下,弄份报告出来。"这句话里藏着至少五个不同的动作:找数据源、拉取数据、清洗、分析、排版输出。如果直接把整句话丢给智能体让它"看着办",你就失去了对每一个环节的控制——它可能用了错误的数据源,可能跳过了清洗,可能编造了数字,而你无从察觉。
任务拆解,就是把一句混沌的人话,变成一张有序的、可验证的动作清单。好的拆解遵循三条原则:
第一,MECE——相互独立、完全穷尽。 每个子任务不重叠,所有子任务加起来等于原任务。就像切蛋糕:每一刀下去,块与块之间不重叠,所有块拼起来是完整的一块。
第二,原子性——拆到"一步只做一件事"。 "生成报告"不是原子任务,它里面藏着"取数""计算""排版"三个动作。原子任务的标准是:它的输入输出可以用一句话说清楚,它的成功失败可以用一个检查判定。
第三,可验证性——每个子任务都要有验收标准。 "数据清洗完成"的验收标准不是"感觉干净了",而是"空值率 < 1%、日期格式统一为 YYYY-MM-DD、重复行已去重"。没有验收标准的拆解,等于没拆。
实例:把"整理本周销售数据并生成报告"拆解:
任务:整理本周销售数据并生成报告
├─ T1 获取数据:从 CRM 导出本周(周一~周日)销售订单 CSV
│ └─ 验收:文件存在,行数 > 0,包含字段[订单号, 金额, 日期, 销售员]
├─ T2 清洗数据:去除重复订单,补全缺失字段,统一日期格式
│ └─ 验收:重复率 0%,空值率 < 1%,日期格式统一
├─ T3 汇总分析:按销售员分组统计总额,计算环比
│ └─ 验收:总额与 T2 清洗后数据一致,环比公式正确
├─ T4 生成报告:按模板输出 Markdown,含表格与Top3点评
│ └─ 验收:模板字段齐全,数字与 T3 一致
└─ T5 分发:将报告发送到管理群,并归档
└─ 验收:发送成功回执,归档路径可查
看到没有?拆解之后,每个环节都有名字、有验收。管控者的权力就藏在这里:T2 的验收标准是你定的,T5 发到"哪个群"是你定的。拆解得越细,你的管控抓手就越多。
2. 技能定义(Skill):给动作上户口
拆解出来的原子任务,如果值得被反复使用,就把它封装成技能。
一个完整的技能定义包含六个部分,缺一不可:
技能名称:sales_data_clean(销售数据清洗)
功能描述:对销售订单 CSV 进行去重、补全、格式统一
输入契约:
- file_path: 字符串,CSV 文件路径(必填)
- required_fields: 字符串数组,必须存在的字段名(必填)
输出契约:
- cleaned_path: 字符串,清洗后文件路径
- stats: 对象,{总行数, 去重数, 补全数, 空值率}
执行逻辑:
1. 读取 CSV,校验 required_fields 是否齐全
2. 按订单号去重,记录去重数
3. 空值补全(金额填0并标记,日期缺失则整行移入异常表)
4. 日期统一为 YYYY-MM-DD
5. 输出清洗文件 + 统计报告
权限声明:
- 读:指定目录下的 CSV 文件
- 写:输出目录(仅 .csv 后缀)
- 不需要:网络访问、数据库写入、外部 API
失败语义:
- 缺失必填字段 → 报错并列出缺失字段,不生成任何输出
- 空值率 > 5% → 警告 + 生成异常报告,不阻断
- 文件不存在 → 直接失败,错误码 FILE_NOT_FOUND
注意这个结构。输入输出契约告诉智能体"怎么调用我";权限声明告诉管控者"它能碰什么";失败语义告诉所有人"出问题时它会怎么做,而不是瞎猜"。一个没有失败语义的技能,就像一辆没有刹车的车——你只知道它能跑,不知道它失控时会怎样。
3. 技能接口(Interface):契约比实现更重要
新手最容易犯的错误,是把精力全放在"技能内部怎么实现"上。但资深工程师知道:技能的接口(输入输出长什么样)比它的内部实现重要十倍。
为什么?因为接口是智能体"看见"的部分。智能体在规划任务时,它看不到你的代码,它只能看到:"哦,这里有个叫 sales_data_clean 的技能,需要一个文件路径,会返回清洗后的文件。"它基于这个理解来决定要不要调用、怎么调用。
如果你的接口含糊——比如输入写的是"数据",输出写的是"处理好的数据"——智能体就会靠猜。猜,就意味着不可控。
接口设计的铁律:输入输出的每个字段,都要有类型、有必填/选填标记、有取值范围说明。 "字符串"不够,要写"字符串,CSV 文件的绝对路径,必须以 .csv 结尾"。"数字"不够,要写"数字,单位为元,保留两位小数,范围 0~99999999"。
记住一句话:你今天在接口上省下的每一个字,都是明天审计时要流的每一滴泪。
4. 挂载机制(Mounting):技能如何被智能体"看见"
写好技能只是第一步,还要把它挂载到智能体身上,让智能体在需要时能找到、能调用。
挂载通常分三层:
第一层:注册。 技能要登记到一个"技能注册表"(Registry)里,就像应用要上架到应用商店。注册时要提交:技能定义文档、安全评估报告、权限声明、版本号。注册表是管控者的第一道关——不合规的技能,连被看见的资格都没有。
第二层:发现。 智能体在执行任务时,会根据当前子任务的描述,去注册表里搜索匹配的技能。"我需要清洗一份销售数据"→ 搜索到 sales_data_clean → 读取它的接口文档 → 决定调用。这里的关键是:智能体只能发现它被授权可见的技能。财务技能不对客服智能体开放,这是挂载时的权限隔离。
第三层:调用。 智能体按接口契约传入参数,技能执行,返回结果。调用过程全程记录日志:谁在什么时间、用什么参数、调用了哪个技能、返回了什么。这是 M04 取证审计的数据来源。
最重要的一个区分,徒弟你给我记住了:挂载 ≠ 授权。 一个技能挂载到了智能体身上,只代表"它能看见这个技能";至于"它能不能调用",那是另一套授权规则决定的。就像你手机里装了银行 App(挂载),不代表你能直接转账,还要指纹/密码(授权)。把"看得见"和"用得了"分开,是管控设计里最基本、也最容易被忽略的一道防火墙。
5. 权限声明与最小权限原则
每个技能在注册时,必须声明它需要什么权限。而且必须遵守最小权限原则:只申请完成任务所必需的最小权限,多一分都不行。
回到 sales_data_clean 的例子:它只需要读写本地 CSV 文件。如果它的权限声明里写着"需要网络访问",你作为管控者就要打个问号:一个清洗本地文件的技能,为什么要联网?它要把数据发到哪里去?
权限声明是技能的"自白书",也是管控者的"审讯提纲"。 评审一个技能,第一件事就是逐条过它的权限声明,每一条都要问:为什么需要?没有它行不行?有没有更小的替代方案?
深度解析:好的技能 vs 坏的技能
理论讲完了,我们来看两个版本的"发送邮件"技能。左边是新手写的,右边是管控者视角下合格的版本。你感受一下差距。
坏的技能:send_email(新手版)
功能:发送邮件
输入:收件人、内容
执行:调用邮件服务发送
就这。没有输出契约(发送成功了还是失败了?),没有权限声明(能给谁发?能发附件吗?附件多大?),没有失败语义(收件人地址写错了怎么办?),没有频率限制(智能体一秒钟发一万封呢?)。
这个技能一旦挂载,等于给了智能体一张空白支票。它可以给任何人发任何内容,无限次。这不是技能,这是后门。
好的技能:send_email_v2(管控版)
技能名称:send_email_v2
输入契约:
- to: 字符串数组,收件人邮箱(必填,最多 5 个)
- subject: 字符串,标题(必填,最多 100 字符)
- body: 字符串,正文(必填,最多 5000 字符)
- attachments: 文件数组(选填,单个 < 10MB,总计 < 25MB)
输出契约:
- message_id: 字符串,邮件服务返回的消息 ID
- sent_at: 时间戳
权限声明:
- 仅允许发送到 @company.com 域名(白名单)
- 每小时最多 20 封(频率限制)
- 附件仅允许读取 /attachments/ 目录
失败语义:
- 收件人非白名单域名 → 拒绝,错误码 DOMAIN_NOT_ALLOWED
- 超过频率限制 → 拒绝,错误码 RATE_LIMITED,并记录
- 发送失败 → 重试 1 次,仍失败则报错,不静默吞掉
审计:
- 每次调用记录:调用者、时间、收件人、标题哈希(正文不存原文,存哈希)
对比一下,差距在哪里?
第一,粒度。 坏技能的粒度是"能发邮件就行",好技能的粒度是"在明确约束下发邮件"。约束不是束缚,约束是让智能体的行为可预测。可预测,才可管控。
第二,幂等性。 好技能要考虑:如果智能体因为网络超时,重发了一次,会不会发出两封重复邮件?成熟的技能设计会加入去重键(比如用 message_id + 时间窗口去重)。这是细节,但魔鬼全在细节里。
第三,可观测性。 好技能的每一次调用都留下痕迹:谁调的、什么时候、参数是什么、结果是什么。注意它存的是"标题哈希"而不是正文原文——既保证了可审计,又保护了隐私。管控不是要看穿一切,而是要在需要时能查到一切。
第四,权限诚实。 好技能声明的权限,和它实际需要的权限完全一致。白名单、频率限制、目录限制,每一条都是管控者可以独立验证的。
第五,失败时不撒谎。 坏技能发送失败可能就静默返回"成功"了(很多新手代码都这么写:try-except 然后 pass)。好技能明确规定:失败就是失败,报错就是报错,绝不伪造成功。M04 我们会讲到,"误报成功"是智能体系统里最危险的行为模式之一,而它的根子,往往就埋在技能的失败语义里。
总结成一句话:好技能的定义,不是"功能强大",而是"行为可预测、边界可验证、失败可追溯"。 功能强大是智能体的事,边界清晰是你的事。
真实案例
案例一:从一句人话到可复用技能——"把表格弄干净"
某电商公司的运营每天都要处理供应商发来的商品表格,格式五花八门。最早的做法是:运营把表格丢给智能体,说"帮我弄干净"。智能体每次都"看着办"——有时候删掉了重要列,有时候把日期格式改错了,有时候干脆 hallucination 补了一些不存在的数据。运营每次都要人工检查,省下的时间全花在"验货"上了。
转折点是他们把"弄干净"这个动作技能化了。管控者(这里是运营主管)带着工程师,把过去三个月最常见的脏数据问题列出来:列名不统一、日期格式混乱、价格带货币符号、重复行、空值。然后为每一种问题定义了处理规则和验收标准,封装成 product_table_clean 技能。
效果:智能体不再"自由发挥",而是调用这个技能,按固定规则处理。处理结果可预测、可审计。运营的"验货"时间从每天 1 小时降到 10 分钟——只看技能输出的统计报告(去重 X 行、补全 Y 个空值),异常才人工介入。
管控者视角的启示:这个案例里,真正的权力不在"智能体多聪明",而在"谁定义了'干净'的标准"。运营主管定义了 5 条清洗规则,这 5 条规则就是他对数据质量的立法。技能化 = 把隐性的、口头的、靠默契的质量标准,变成显性的、书面的、可执行的代码。
案例二:审批技能——权力天然长在技能里
某公司的报销审批,原来是智能体"看一下票据,没问题就通过"。听起来很美好,直到有一次智能体通过了一张 PS 过的发票——金额 8000,发票上的公章是 P 的。财务复核时发现,差点出大事。
重构后的 expense_approve 技能是这样设计的:
输入:票据图片、报销金额、申请人、费用类型
执行逻辑:
1. OCR 识别票据,提取金额、日期、开票方
2. 金额 > 5000 → 自动标记为"需人工复核",技能直接返回"转人工",不做通过决定
3. 调用发票验真 API,验证发票代码真实性
4. 验真通过 + 金额 ≤ 5000 → 通过;任一失败 → 拒绝并说明原因
权限声明:
- 读:票据图片目录
- 调用:发票验真 API(只读查询)
- 写:审批结果表(仅 status 字段)
- 禁止:直接操作付款系统(审批通过 ≠ 打款,打款是另一个技能)
失败语义:
- OCR 置信度 < 80% → 转人工,不猜
- 验真 API 超时 → 转人工,不默认通过
看明白了吗?这个技能的设计,处处都是权力边界:
- "5000 以上转人工"——这是财务制度在技能里的投影。制度说"大额要人审",技能就把这条写死在执行逻辑里,智能体想绕都绕不过去。
- "审批通过 ≠ 打款"——审批和付款是两个技能,两个权限。智能体就算通过了审批,也碰不到钱。这是经典的职责分离(Separation of Duties),在技能层面实现。
- "OCR 置信度低就转人工,不猜"——这是在技能里植入谦逊原则。模型最危险的时刻就是它"自信地犯错"的时候,技能要在它可能犯错的地方强制刹车。
管控者视角的启示:审批类技能是管控者权力的"原生领地"。财务制度、合规要求、风险偏好——这些原本写在 PDF 里的东西,都应该被翻译成技能的执行逻辑和失败语义。以后审计问"你们的内控是怎么落地的",你的答案不应该是一份制度文件,而应该是一组技能定义。
案例三:反面教材——一个"热心"的网页抓取技能
某团队写了个 web_scrape 技能,功能很简单:输入 URL,返回网页正文。权限声明写的是"需要网络访问"。听起来人畜无害,对吧?
三个月后,安全审计发现:某个智能体在执行"竞品分析"任务时,用这个技能抓取了竞争对手的内部后台页面——URL 是智能体自己从某个论坛帖子里"推测"出来的,页面没有密码,但 robots.txt 明确禁止爬取。更糟的是,技能没有任何 URL 白名单、没有任何频率限制,智能体一晚上抓了 2000 多个页面,差点触发对方的反爬封禁,给公司惹来律师函风险。
复盘时发现,问题不在智能体"学坏了",而在技能设计之初就埋了雷:
- 权限声明太粗:"需要网络访问"等于"可以访问整个互联网"。正确的做法是声明"仅允许访问白名单域名"或"禁止访问含 /admin、/internal 路径的 URL"。
- 没有频率限制:2000 页一晚上,正常人类操作不可能达到这个量级。技能应该有"每小时最多 X 次"的熔断。
- 没有内容边界:技能返回了"网页正文",但没有规定"遇到登录墙/付费墙/robots.txt 禁止时怎么办"。正确的失败语义应该是:检测到 robots.txt 禁止 → 拒绝抓取并记录。
管控者视角的启示:这个案例是 M03(安全边界)的前置预告。一个技能的权限声明,必须假设"调用者会被滥用"。你不是在为"听话的智能体"设计技能,你是在为"可能被提示注入、可能被误导、可能自己推理出歪点子的智能体"设计技能。技能设计的第一性原理:默认不信任调用者,只信任契约。
实操练习
光看不练,等于没学。现在轮到你动手了。
练习任务:你是一家公司的 IT 管控者。老板提了个需求:
"每周一早上 9 点,把上周的客服工单汇总成一份问题分布报告,发到管理群。"
请你完成以下四步,并把答案写下来(写在纸上、备忘录里都可以,关键是亲手写一遍):
Step 1:拆解任务。 把这句人话拆成原子任务,每个标注验收标准。提示:想想"工单从哪来""汇总的维度是什么""报告长什么样""发到哪个群""发完要不要确认"。
Step 2:识别技能。 哪些子任务值得封装成可复用的技能?(比如"拉取工单"可能每周都用,"生成 Markdown 报告"可能别的场景也用。)至少识别出 2 个技能,说明复用价值。
Step 3:完整定义其中一个技能。 按本课的六要素(名称、功能描述、输入契约、输出契约、执行逻辑、权限声明、失败语义——是七要素,数数看)写出来。重点写好权限声明和失败语义,这是管控者的基本功。
Step 4:标注风险点。 站在"攻击者"的角度想:如果这个技能被滥用,最坏的情况是什么?(比如:工单数据里有客户隐私,技能会不会泄露?报告发错群了怎么办?)针对每个风险点,写下你的管控措施。
自查清单(做完对照): - [ ] 我的拆解里,每个子任务都有验收标准吗? - [ ] 我的技能输入输出,每个字段都有类型和必填标记吗? - [ ] 权限声明里,有没有"顺手"多要的权限? - [ ] 失败语义里,有没有"静默成功"的漏洞? - [ ] 我能说清楚"这个技能不能做什么"吗?(说清楚"不能",比说清楚"能"更重要)
把这份练习发给你的学习伙伴互相评审,或者对照 M04 的审计视角自己审一遍。能经受住"找茬"的技能定义,才是合格的。
常见误区
误区一:把 prompt 当技能。
"我写了个很长的 prompt,让智能体按步骤做,不就是技能了吗?"不是。Prompt 是"建议",技能是"契约"。Prompt 可以被智能体"灵活理解"(也就是灵活跑偏),技能的输入输出是机器校验的。更重要的是,prompt 没有权限声明、没有审计日志、没有版本管理。Prompt 是口头约定,技能是书面合同。 管控者只认合同。
误区二:技能粒度拍脑袋。
两种极端都见过:一种是一个技能干所有事("全能助手"技能,输入是"任务描述",输出是"结果"——这不就是把智能体又包了一层吗?);另一种是粒度细到离谱("字符串转大写"也要做成技能)。判断标准:一个技能应该对应一个"业务上有意义的、权责清晰的"动作。 "清洗销售数据"是业务动作,"字符串转大写"是编程动作——前者做技能,后者写函数。
误区三:只设计 happy path,不设计失败路径。
新手写技能,90% 的篇幅写正常流程,失败就一句"报错"。但真实世界里,失败才是常态:文件不存在、API 超时、数据格式不对、权限不足……一个技能的健壮性,不取决于它正常时多优雅,而取决于它异常时多老实。 每个技能至少要回答三个问题:输入非法时怎么办?依赖服务挂了怎么办?部分成功时怎么办?
误区四:权限"先全开再说,以后收紧"。
这是管控领域最危险的一句话。"以后"永远不会来,而多开的权限每天都在产生风险敞口。正确姿势反过来:先最小权限上线,业务真的跑不通了,再一条一条加,每加一条都要有理由、有记录、有有效期。 权限只增不减是常态,所以起点越低越好。
误区五:以为"挂载了"就等于"管住了"。
前面讲过:挂载 ≠ 授权。但还有更深一层:授权了也不等于管住了。技能上线后,调用日志有人看吗?异常调用有人告警吗?权限声明和实际行为定期对得上吗?技能是有生命的——业务变了、数据变了、威胁变了,技能也要跟着变。M07 会讲技能的长期治理,但你现在就要有这个意识:技能不是一劳永逸的交付物,它是需要持续饲养的活物。
误区六:技能越多越好。
有的团队搞"技能大跃进",三个月攒了 200 个技能,然后发现:一半的技能没人调用(僵尸技能),三分之一的技能功能重叠(三个"发送邮件"技能,权限各不相同),还有几个技能的作者都离职了,没人敢动。技能库的治理成本是随数量指数增长的。 宁可 20 个精品技能,也不要 200 个良莠不齐的。每个技能都要有主人、有文档、有 deprecation 流程。M05 会专门讲技能资产的标准化,这里先记住:技能是资产,资产就需要治理。
延伸思考
学完这一课,你可以带着这四个问题去散步时想:
1. 当技能可以买卖,技能设计就是立法。
M06 会讲技能资产的商业化。想象一下:你在技能市场上买了一个"财务对账"技能,卖家是陌生人。你怎么知道这个技能没有后门?它的权限声明可信吗?它的失败语义真的如文档所说吗?技能交易的前提是技能审计。 而技能审计的标准,恰恰就是这一课讲的六要素。今天你学会了怎么写好技能,明天你才有资格去评审别人的技能。
2. 单个安全,不等于组合安全。
send_email 技能是安全的(白名单+限频),read_customer_db 技能是安全的(只读+脱敏),但把两个组合起来——"读取客户数据库,给每个客户发个性化邮件"——可能就变成了大规模精准钓鱼的基础设施。技能组合会产生单个技能不具备的涌现能力,也会产生单个技能不存在的涌现风险。 这是管控者最难的一课:你管的不只是一堆技能,你管的是它们的组合空间。M03 的安全边界设计会正面迎战这个问题。
3. 谁来审计技能的供应链?
你的智能体调用的技能,可能是你写的,可能是同事写的,可能是从市场上买的,可能依赖了某个第三方 API。每一层都可能藏雷。软件工程界为此发明了 SBOM(软件物料清单),技能工程需要 SKBOM(技能物料清单):每个技能的来源、版本、依赖、审计记录,一目了然。在 AGI 时代,供应链攻击不会消失,只会换个马甲。
4. 最好的技能,是让智能体"不需要聪明"的技能。
这句话值得品味。我们总希望模型更聪明,但管控者的目标恰恰相反:把需要"聪明"的地方,压缩到最小;把"按规矩办事"的地方,放到最大。 技能设计得越好,智能体需要临场发挥的空间就越小,行为就越可预测。一个成熟的技能体系里,智能体的"聪明"只用在任务规划和异常处理上,执行层全部是确定性的技能调用。管控的终极形态,不是更聪明的警察,而是更少需要警察的街道。
本课要点回顾:任务拆解是管控的起点(MECE、原子性、可验证性);技能六要素(名称、描述、输入契约、输出契约、执行逻辑、权限声明、失败语义)缺一不可;好技能的标准是行为可预测、边界可验证、失败可追溯;挂载不等于授权;权限默认最小;技能设计即权力设计。
下一课 M03《AGI安全边界设计与管控体系》,我们把视角从单个技能拉大到整个系统:当几十个技能、上百次调用编织成一张网,边界应该画在哪里?熔断应该装在哪个位置?