做智能体开发这段时间,我最大的体会是:模型本身的能力差距大家都看得见,但真正决定一个智能体是“好用”还是“翻车”的,往往是 SKILL 和 RULE 这两个容易被忽略的设计环节。简单来说,SKILL 决定智能体“会做什么”,RULE 决定它“该怎么做、不该怎么做”。这两套东西没设计好,再强的模型也会变成“嘴上什么都答应、手上什么都不会”的失控话痨。
这篇文章写给正在做 AI 应用、智能体开发或技术决策的人。我会从智能体运行原理讲起,说明为什么 SKILL 和 RULE 是所有智能体框架都绕不开的核心抽象,然后结合我实际调过的项目,给出 SKILL 和 RULE 的设计思路、写法和避坑经验。内容不依赖特定框架,你把这些原则拿到任何智能体架构里都能用。
1. 先搞懂智能体的运行原理,再谈最佳实践
1.1 智能体到底是怎么“想”和“做”的
把智能体拆到最底层,它就是一个循环:感知(Perception)→ 决策(Decision)→ 行动(Action)→ 再感知。模型在这个循环里扮演大脑的角色,负责读懂当前状态、判断下一步该做什么;而真正去执行“做事”的,是一堆外部工具、代码函数、知识库查询接口。
这里有个很关键的认知:大模型本身并不“可靠”。它擅长的是在给定上下文里生成合理的下一步动作,但如果你不给它边界,它会在每一步都“自由发挥”。比如你让它“查一下季度数据然后写报告”,它可能真的去查了数据,但在总结时会加入自己的猜测,甚至会编造一个不存在的指标来源。这就是没有对“行动”做约束的典型表现。
所以智能体框架的核心工作,就是给“感知-决策-行动”这个循环加上可控的中间层。这个中间层通常由两部分组成:能力层(让智能体知道有哪些工具/方法可以用)和 规范层(让智能体知道在什么条件下该用哪些能力、怎么用、不能怎么做)。这就是 SKILL 和 RULE 存在的位置。
1.2 为什么 SKILL 和 RULE 是所有框架的公共答案
我见过很多刚入门的开发者,一上来就拿着模型 API 写 prompt,让模型“你自己看着办”。在小 demo 里这没问题,一旦进入真实业务,立刻就崩。原因很简单:真实场景有几个特点,模型靠 prompt 压不住:
- 动作空间巨大:真实系统里可调用的接口可能有几十上百个,模型不知道哪个才是当前任务该用的。
- 上下文有限:你不可能把所有工具说明、业务规则都塞进 prompt,token 根本不够。
- 需要确定性:业务流程中某些环节必须严格按规范来,比如金融场景里的金额计算、法务场景里的合规话术,模型自由发挥就是事故。
SKILL 和 RULE 正是为了同时解决这三件事出现的。SKILL 把“能力”封装成有明确输入输出、有描述、有使用条件的模块,让模型在有限的选项里做选择;RULE 则把“约束”结构化,让模型在决策时无法无视边界。可以这么理解:SKILL 是给模型一份“菜单”,RULE 是给模型一张“禁忌清单和上菜顺序”。菜单越清晰、禁忌越明确,智能体的行为就越可预期。
1.3 从原理推导设计原则
既然原理如此,设计原则就顺理成章了:
- 能力要有边界,不能模糊。一个 SKILL 负责一件事,描述必须让模型一看就知道“什么场景用我、什么时候别用我”。
- 规则要有优先级。多个 RULE 同时存在时,模型得知道先遵守哪条,否则规则之间一冲突,模型就会挑一条“最顺眼”的执行。
- 所有设计都要考虑“模型会误读”。你以为写清楚了,模型不一定理解对了,所以要用示例、反例来校准它的理解。
这三个原则会贯穿下文的所有最佳实践。你后续看每一条具体建议,本质上都是在回应“如何让模型在有限的感知和判断能力下,做出最接近预期的决策”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SKILL 设计的最佳实践:能力不是越多越好,是越准越好
2.1 SKILL 的定义与常见误区
先给 SKILL 下一个可操作的定义:SKILL 是一个可被模型调用、具有明确输入输出契约、内部封装了特定实现逻辑的能力单元。它可以是单个函数、一个 API 调用流程、一段数据处理管线,甚至是另一个智能体的封装。
我在实际项目里见过三种典型的 SKILL 设计误区:
- 误区一:大而全。一个 SKILL 里面塞了“数据分析+生成图表+写结论+发送消息”,看起来方便,但模型在中间某个环节想替换或调整时根本没有操作空间,而且 SKILL 描述越长,模型理解的偏差越大。
- 误区二:描述废话多。SKILL 的描述里全是“该技能用于高效地进行某某操作,帮助用户获得更好体验”这类空话,真正关键的触发条件、输入格式、返回值含义反而没写清楚。
- 误区三:参数设计随意。参数名含义不明、没有默认值、格式约束缺失,模型传参全靠猜,执行成功率自然低。
2.2 一个高质量 SKILL 的组成部分
我在项目中总结出的高质量 SKILL 结构,通常包含六块:
| 组成部分 | 作用 | 说明 |
|---|---|---|
| 技能名称 | 唯一标识 | 名称要直观,能表达“做什么”,不要用项目内部代号 |
| 触发条件 | 让模型判断何时调用 | 描述“什么场景、什么用户意图下使用本技能” |
| 输入参数 | 模型调用时提供的字段 | 每个参数要有类型、含义、取值范围、示例 |
| 执行逻辑 | 具体实现 | 代码或流程编排,必须处理输入异常 |
| 输出结果 | 返回给模型的内容 | 结构化输出更容易被模型理解 |
| 使用示例 | 给模型的参考 | 一个完整调用示例比一大段说明都有效 |
这里最重要的其实是 触发条件和输入参数。模型本质上是在做“阅读理解”,SKILL 描述就是它阅读的材料。你材料写得不清楚,它自然用不对。
2.3 实操模板与案例拆解
拿一个我最近做的“周报智能助手”来举例,其中有两个 SKILL:
第一个是“查询本周项目进度”:
yaml复制name: query_project_progress
description: 查询指定项目在指定时间范围内的进度数据。当用户询问项目进展、完成度、里程碑状态时使用本技能。如果用户没有明确指定项目名称,必须向用户询问确认后再调用。
trigger:
- 用户询问项目进度/完成情况/里程碑状态
- 用户要求查看某个项目的当前进展
parameters:
project_id:
type: string
description: 项目唯一标识,格式如 PRJ-2024-001
required: true
start_date:
type: string
description: 开始日期,格式 YYYY-MM-DD,默认本月第一天
required: false
end_date:
type: string
description: 结束日期,格式 YYYY-MM-DD,默认今天
required: false
execution:
- 校验 project_id 格式
- 从项目数据库查询任务完成情况
- 汇总完成率、延期任务列表、风险项
output:
project_id: string
total_tasks: integer
completed_tasks: integer
completion_rate: string
overdue_tasks: array
risk_list: array
example:
user: 看看 PRJ-2024-001 这个月的进度
assistant_call: query_project_progress(project_id="PRJ-2024-001", start_date="2024-06-01", end_date="2024-06-30")
注意几个设计细节。description 特意写了“如果用户没有明确指定项目名称,必须向用户询问确认后再调用”,这就是在给模型划边界,防止它拿一个空参数去查询然后随便猜个项目。completion_rate 用 string 类型,是为了让后端算好了“85%”直接返回,避免模型在计算百分比时出错。
第二个是“生成周报摘要”:
python复制# 伪代码:实际项目里这里的输入是上面查询到的结构化数据
def generate_report_summary(progress_data: dict, focus: str = "risk") -> str:
"""
根据项目进度数据生成周报摘要。
注意:本函数不自行编造数据,所有数据必须来自 progress_data 参数。
如果 progress_data 中缺少某项数据,直接写“待补充”,禁止推测。
"""
lines = []
lines.append(f"本周重点项目完成率 {progress_data['completion_rate']}")
if focus == "risk" and progress_data["risk_list"]:
lines.append("主要风险项:")
for risk in progress_data["risk_list"]:
lines.append(f"- {risk}")
return "\n".join(lines)
这里我在 SKILL 的实现里也强调了“不编造数据、缺数据就写待补充”。因为模型拿到 SKILL 的返回值后还会做二次加工,如果不提前约束,它很可能把“风险列表为空”自行演绎成“风险可控”,这就失真了。
2.4 SKILL 数量与粒度的平衡
一个常见问题:到底该设计多少个 SKILL?我的经验是按“用户可感知的动作”来划分粒度,而不是按代码函数的粒度。用户说“帮我查天气”,这是一个 SKILL;但“查天气”后面涉及的“获取城市编码”“请求气象接口”“解析响应”这些内部步骤不应该暴露成多个 SKILL,它们应该是一个 SKILL 内部的实现细节。
为什么?因为模型每一步决策都会消耗 token、引入错误概率。SKILL 越多,模型选择错误的可能性越大。我调过的一个项目里,最初团队的 SKILL 数量是 37 个,实际运行中模型经常混淆功能相近的 SKILL;后来我们把功能相近的合并到 16 个,准确率反而提升了。在模型面前,少而准永远优于多而杂。
判断 SKILL 数量是否合理,可以做一个简单测试:随机罗列 20 条用户指令,看你能否在两秒内为每条指令判断出应该用哪个 SKILL。如果连你都犹豫,说明 SKILL 描述或粒度有问题,模型更会犹豫。
3. RULE 设计的最佳实践:规则不是不能有,而是不能模糊
3.1 RULE 的本质与类型
如果说 SKILL 解决的是“能不能做”的问题,RULE 解决的就是“可不可以做、优先怎么做”的问题。RULE 是对智能体行为的约束和引导,它独立于任何具体 SKILL,是全局的。
我在项目里习惯把 RULE 分成三类:
- 硬性约束:绝对不允许做的事,没有商量余地。比如“禁止修改用户身份信息字段”“涉及金额输出时必须保留两位小数”“无法确认信息时必须明说不知道”。
- 软性引导:默认情况下应该怎么做,但当用户明确要求时可以调整。比如“默认用简洁风格回复,除非用户要求详细”。
- 触发式规则:某些条件出现时必须执行的逻辑。比如“当检测到用户情绪负面时,先共情再解决问题”“当数据查询失败时,必须先告知用户而不是重试三次”。
这三种规则对模型的重要性不一样。硬性约束是安全底线,必须描述得极其明确;软性引导是调性一致性的保障;触发式规则则决定了智能体在面对特殊场景时的应变能力。
3.2 编写 RULE 的四个要点
要点一:用“条件+动作”的句式,而不用形容词。
糟糕的写法:“回复要专业。”
好一点的写法:“当用户咨询涉及法律/金融建议时,必须加上‘以上内容仅供参考,不构成专业意见’的说明。”
前者“专业”是模糊形容词,模型不知道怎么执行;后者有明确的触发条件和动作,模型能直接照做。
要点二:明确规则优先级。
规则之间一定会冲突,你在设计时就要提前考虑。我通常会定义一个优先级字段,比如:
yaml复制rules:
- id: R001
priority: 1
type: hard
content: 当用户要求重复执行同一操作超过3次时,先询问用户意图再继续
- id: R002
priority: 2
type: soft
content: 默认情况下应配合用户的重复请求
这里如果 R001 触发,即便 R002 是默认行为,模型也应该优先遵守 R001,先停下来问用户。没有优先级标注的规则集,到了模型那里基本等于“谁都管不住谁”。
要点三:正反结合,给规则配反例。
一条规则如果要描述“禁止做什么”,最好同时说明“正确做法是什么”。比如:
当用户询问的数据不存在时,禁止编造数据,也不应该用“可能”“大概”来含糊带过。正确做法是直接回答“该数据暂未获取到”,并询问是否要换一个查询范围。
反例给的是“不要”,正例给的是“要”,模型两者都看到,才能真正理解边界。
要点四:每条 RULE 必须可验证。
怎么判断一条规则有没有生效?如果它写得太抽象,根本没法验证。我在实践中的最低标准是:规则执行后,你能明确判断模型“有没有做对”。比如“回复不能超过 200 字”可验证,“回复要言简意赅”不可验证。规则在投入运行前,我会自己用测试用例跑一遍,每条规则对应用例通过才算合格。
3.3 规则冲突的预防与消解
规则冲突是最常见的坑。举一个我真实遇到的例子:一个电商客服智能体有一条“回复要简洁,控制在 50 字以内”,另一条是“当用户询问退款条件时,必须完整说明退款的 5 个条件”。两条规则单看都没问题,但模型同时面对时会很矛盾——完整说明 5 个条件基本不可能压缩到 50 字。
我最终的解决办法是:把规则的适用场景写得更具体——第一条改成“回复要简洁,控制在 50 字以内,除非完整说明退款条件等硬性要求时不受此限”;同时给第二条加序号,标注它的优先级高于简洁规则。这里的关键不是“消除所有冲突”,而是在冲突发生时,让模型知道该优先听谁的。
3.4 RULE 的维护与版本管理
很多团队的 RULE 是“一次性写好,上线后就不管了”,这非常危险。模型迭代、业务变化、用户类型的改变,都会让旧规则失效或产生副作用。我采用的做法是:
- 每条 RULE 记录添加日期、负责人(虽然文内不写具体人名,机制上得有)、关联业务场景;
- 每次修改 RULE,至少跑一遍全量回归测试;
- 定期复盘:收集智能体运行日志中“被规则拦下来”和“触发规则异常”的样本,分析规则是否过严或过松。
4. SKILL 与 RULE 的协同设计:从单点能力到完整闭环
4.1 SKILL 与 RULE 的分工边界
很多人分不清 SKILL 和 RULE 的边界。我在项目里的判断标准很简单:
- 如果是“做什么”的问题,放到 SKILL。比如“查天气”“算价格”“生成图表”,这些是可封装的能力命脉。
- 如果是“在什么条件下怎么做、不能怎么做”的问题,放到 RULE。比如“涉及金额必须四舍五入到两位”“用户没确认需求前不要生成最终报告”。
- 如果是 SKILL 内部实现的逻辑,既不要写成 RULE,也不要在描述里堆规则。比如某个数据清洗函数内部怎么处理空值,那是代码逻辑,不该让模型操心。
用一句话概括:SKILL 是硬件能力,RULE 是交通规则。硬件能力决定车能跑多快,交通规则决定在什么路况下该怎么跑。两者缺一不可,而且设计时要一起考虑。
4.2 实战案例:用 SKILL + RULE 搭建一个“合规咨询助手”
我把一个真实项目的设计骨架拿出来拆解(为了便于说明做了一些简化处理)。这个智能体的任务是为内部员工解答合规问题,核心要求是“敢答但不多答、答必有据”。
SKILL 层我设计了三个:
search_policy:检索合规政策库,返回相关条款原文和编号。explain_policy:基于检索到的条款做通俗化解释。这个 SKILL 内部规定:解释不能脱离原文依据,必须附带条款编号。escalate_to_human:当模型判断自己无法给出确定性答复时,转接人工客服。
RULE 层我设计了四条:
- R001(硬性):所有回答必须先调用
search_policy再开始生成内容,禁止凭模型内部知识直接回答。 - R002(硬性):当
search_policy未返回任何结果时,禁止自行推断答案,必须调用escalate_to_human。 - R003(软性):解释性回答中,当用户表现出不理解术语时,可以附加生活化类比,但类比部分必须明确标注是“类比说明”,不能与条款混同。
- R004(触发式):当用户连续追问同一问题超过三次且未得到满意答复时,自动触发
escalate_to_human。
这个设计里,SKILL 与 RULE 是交织的。没有 SKILL,光靠 RULE 模型也不知道去哪找政策;没有 RULE,光靠 SKILL 模型很可能“我随便检索一下就开始长篇大论”。两者合在一起,才能形成一个闭环。
4.3 调优方法论:不看感觉看数据
很多团队调智能体靠“感觉”——工程师自己试几个 case,觉得不错就上线。我的建议是至少要建立两个数据:
- SKILL 触发准确率:在所有该用某个 SKILL 的测试用例里,模型正确触发该 SKILL 的比例。
- RULE 违规率:在所有测试会话里,模型违反硬性约束的次数。
每次改动 SKILL 描述或 RULE 内容,用同一套测试集跑一遍,对比这两个指标。我吃过亏的地方是:之前改了一条 RULE 想让回复更详尽,结果模型的其中一个硬性约束被“冲淡”了,违规率明显上涨。如果没有数据对比,这种回归问题很难发现。
测试集也不需要特别大规模,我常用的是 80~120 条覆盖典型场景的用例,足够发现问题了。关键在于测试集要固定,不能每次随手换一批,否则前后指标没有可比性。
5. 常见问题排查与避坑实录
5.1 SKILL 被模型调用了,但执行结果不对
这类现象特别多。排查时先别怀疑模型,按顺序查三件事:
- 参数传对没有:日志里看模型传给 SKILL 的参数值,经常发现把项目名称写成了路径名,或者日期格式传成了
2024/6/1而不是2024-06-01。参数格式约束没写清楚是最常见原因。 - SKILL 内部是否有异常分支处理:比如查询结果为空时,函数有没有返回合理的空结构,还是直接抛异常。
- 输出有没有被模型二次加工破坏:有时候 SKILL 返回的结构化数据本身是对的,但模型在生成回复时自己“脑补”了几个字段。解决办法是 RULE 里增加一条“引用 SKILL 返回数据时,禁止添加原文中没有的数字”。
5.2 规则之间打架,模型行为“精神分裂”
前面讲过规则优先级的重要性。真遇到冲突,除了调整优先级,还有一个我经常用的调试技巧:把冲突的两条规则同时拉出来,看模型为什么选择了其中一条。很多时候不是因为优先级,而是某条规则里的关键词更容易吸引模型的注意力。比如一条规则有“必须”“禁止”等强语气词,一条是平铺直叙,模型大概率先执行强语气那条。这提醒我们:RULE 的措辞强度本身就是一种“隐式优先级”,这在设计时要有意识地去控制。
5.3 智能体过于死板,处处被规则卡死
规则太多、太死,会让智能体显得很“蠢”。用户问一句“今天天气不错,适合干嘛”,结果模型先触发了一堆流程性规则,非要先确认城市、再调用天气接口,最后才回答。这种问题通常不是规则本身错了,而是规则缺少“前置条件判断”。解决办法是给 RULE 加适用前提,比如“当用户使用闲聊语气且不涉及任务需求时,不进入任务流程”,或者“识别到用户倾向非正式交流时,优先执行软性引导规则”。
另外也要警惕一种反向情况:因为你塞了太多规则,模型在决策时反而“选择性忽略”一部分。我的经验是,硬性约束控制在 8~12 条以内,超过这个数量,就该考虑把部分规则做成“某个 SKILL 内部的前置校验”,而不是全局 RULE。
5.4 排查流程与日志设计
我推荐一个轻量级的排查流程:
- 每次会话保存完整的决策日志,包括模型思考链、SKILL 触发记录、RULE 命中记录、最终回复。
- 发现问题时,先看 RULE 命中记录,确认是“规则未触发”还是“规则触发但被忽略”。
- 如果是“规则未触发”,通常是规则描述里的条件与用户表达不匹配,需要改触发条件的表述方式。
- 如果是“规则触发但被忽略”,多半是规则优先级不够,或与其他规则冲突。
日志里还应该记录 SKILL 的入参和出参,这一点在调试时价值极大。很多问题光看最终回复根本看不出原因,一看出参就真相大白。
最后分享一点个人体会
做了这么多智能体项目,我最大的感受是:SKILL 和 RULE 不是写好就完事的静态配置,而是需要持续迭代的动态设计。模型在变、用户问题在变、业务逻辑在变,你的 SKILL 和 RULE 也要跟着变。每跑一段时间,我都会翻一翻会话日志,看看哪些 SKILL 调用频率低、哪些规则从不触发,然后果断调整。与其不断调模型参数,不如多花时间打磨这两个抽象层——投入产出比真的很高。如果你正准备做一个智能体,我建议把 SKILL/RULE 的设计放在和选模型同等重要的位置,不要等到 demo 跑通了再回头补。那时候返工的成本,可比一开始想清楚要高得多。
