☰
智能体技能体系设计:从提示词到可复用能力单元
2026/10/21 5:30:53 网站建设 项目流程

1. 从"技能"这个词说起:为什么智能体需要一套技能体系

第一次看到"agent-skills"这个命名,我脑子里冒出来的第一个念头是:这不就是把智能体当成一个"新员工"来培养吗?你招一个人进来,他光有通用智力不够,还得会你们公司内部的报销流程、会用你们那套CRM、知道遇到客诉先查哪个工单系统。智能体也一样,底层模型再强,它不知道你的业务规则、不会调用你的工具、不理解你的输出格式要求,那它就是个"高智商但啥也不会干"的实习生。

所以"agent-skills"这个项目,我理解它的核心命题就一句话:把智能体从"能聊天"变成"能干活",靠的不是换更贵的模型,而是给它装配一套可复用、可组合、可版本管理的技能包。这套技能包,就是智能体的"岗位说明书 + 操作手册 + 工具箱"三合一。

我在过去一年多的时间里,陆陆续续给好几个不同场景搭过智能体,从客服问答到数据处理,从文档生成到流程自动化。踩过的坑告诉我一件事:大多数人做智能体失败,不是因为模型不行,而是因为把"提示词"当成了"技能"。提示词是一段话,技能是一个有输入、有输出、有边界、有失败处理的完整单元。这两者的差距,就像"你跟新人说了一句注意点"和"你给新人写了一份带SOP的操作手册"之间的差距。

这篇文章我想把"agent-skills"这件事彻底讲透。不管你是刚接触智能体开发的新手,还是已经写过一堆提示词但总觉得不够稳的老手,我都会从设计理念、技能拆解、实现方式、组合编排、调试排错这几个角度,把我自己趟出来的经验完整分享一遍。文章里会涉及不少代码和配置,但我会尽量用"为什么这么设计"来解释每一步,而不是甩一堆代码让你自己猜。

提示:本文讨论的"技能"是智能体工程中的通用概念,不绑定任何特定厂商或框架。你可以把它套用到你手头正在用的任何智能体平台上。

2. 技能到底是什么:拆开一个技能包看内部结构

2.1 技能不是提示词,而是"能力单元"

我见过太多人把技能理解成"一段精心写的提示词"。比如写一段"你是一个专业的翻译助手,请把用户输入翻译成英文",然后管这叫"翻译技能"。这没错,但它太薄了。一个真正能用的技能,至少包含五个部分:

  • 触发条件:什么情况下该用这个技能?是用户明确要求,还是智能体自己判断?
  • 输入契约:这个技能需要哪些参数?参数是什么类型?必填还是选填?
  • 执行逻辑:核心的处理步骤是什么?是调用模型,还是调用外部API,还是两者结合?
  • 输出契约:返回什么格式?是纯文本、JSON,还是结构化对象?
  • 失败处理:参数缺失怎么办?外部调用超时怎么办?结果不符合预期怎么办?

把这五部分补齐,一个技能才算"能上岗"。我打个比方:提示词像是你口头交代给同事的一句话,技能像是你写进公司知识库的一份标准作业流程。前者靠对方悟性,后者靠制度保障。

2.2 一个技能包的目录长什么样

我习惯把每个技能做成一个独立目录,这样便于版本管理和复用。一个典型的技能目录结构大概是这样:

skills/ translate/ skill.yaml # 技能元信息:名称、描述、触发条件 prompt.md # 核心提示词模板 schema.json # 输入输出契约定义 handler.py # 执行逻辑(可选,复杂技能才需要) examples/ # 少样本示例 case1.json case2.json

这个结构的好处是:元信息、提示词、契约、逻辑、示例各归各位,改哪部分就动哪个文件,不会牵一发动全身。我早期把所有东西塞在一个大配置文件里,结果改一个技能的触发词,不小心影响了另一个技能,排查了半天才发现是配置串了。分开之后,这种问题基本绝迹。

skill.yaml里最关键的是触发条件。我一般会写三类触发:显式触发(用户直接点名)、语义触发(用户意图匹配)、以及前置技能触发(上一个技能的输出指向这个技能)。这三类触发叠加,能大幅降低"该用技能时没用、不该用时乱用"的概率。

2.3 输入输出契约:被最多人忽略、却最要命的部分

如果让我只强调一件事,那就是输入输出契约。我踩过最大的坑,就是早期技能没有严格定义输出格式,导致下游技能拿到上游的输出后解析失败,整个链路崩掉。

举个真实场景:我做过一个"会议纪要生成"的技能链,第一个技能负责从录音转写文本里抽取"待办事项",第二个技能负责把待办事项分配给对应负责人。第一个技能我一开始让它"输出待办事项列表",结果它有时候输出带序号的列表,有时候输出带项目符号的列表,有时候还夹带一句"以下是待办事项:"。第二个技能按固定格式解析,直接崩了。

后来我给第一个技能加了严格的输出契约:

{ "type": "object", "properties": { "todos": { "type": "array", "items": { "type": "object", "properties": { "content": {"type": "string"}, "owner": {"type": "string"}, "deadline": {"type": "string", "format": "date"} }, "required": ["content"] } } }, "required": ["todos"] }

并且在提示词里明确要求"只输出JSON,不要任何额外文字"。加上这层约束后,链路稳定性从"三天两头出问题"变成了"基本不用管"。

注意:契约不只是给下游看的,也是给模型看的。把schema直接写进提示词,模型对输出格式的遵守程度会明显提升。这是我在多个项目里反复验证过的经验。

3. 技能怎么拆:颗粒度拿捏是门手艺

3.1 拆太细和拆太粗,都是灾难

技能拆分的颗粒度,是我觉得最考验设计者功力的地方。拆太细,技能之间调用开销大,一个简单任务要串七八个技能,延迟高、出错点还多;拆太粗,一个技能啥都干,提示词臃肿,模型容易顾此失彼,改一处影响一大片。

我的经验法则是:一个技能只做一件"能用一句话说清楚"的事,且这件事的输入输出能明确定义。比如"从文本中抽取邮箱地址"是一个合格技能,"处理用户请求"就不是,因为它太模糊了。

再给个判断标准:如果你发现某个技能的提示词超过800字还说不清楚,那大概率是它承担了太多职责,该拆了。反过来,如果两个技能总是成对出现、从不单独使用,那它们可能该合并。

3.2 按"能力维度"拆,而不是按"业务场景"拆

这是我很想强调的一点。新手容易按业务场景拆技能,比如"订单查询技能""退款处理技能""物流跟踪技能"。这样拆的问题是:技能和具体业务绑死了,换个业务就得重写。

更好的做法是按能力维度拆,比如:

能力维度技能示例可复用场景
信息抽取抽取实体、抽取日期、抽取金额订单、合同、邮件都能用
格式转换转JSON、转表格、转Markdown几乎所有输出场景
外部调用查数据库、调API、发通知所有需要外部数据的场景
校验判断校验格式、判断意图、风险识别所有需要决策的场景
内容生成写摘要、写回复、写报告所有需要产出的场景

按这个维度拆出来的技能,是"原子能力",可以像积木一样组合。我做过一个项目,前期按业务拆了二十多个技能,后期业务一变全废了;另一个项目按能力拆了十来个原子技能,后面接了三个不同业务,几乎没改技能本身,只是重新编排了组合顺序。

3.3 技能之间的依赖关系要画清楚

技能多了之后,依赖关系会变得复杂。我习惯在项目初期就画一张依赖图(用文字描述也行),标明哪些技能是"叶子技能"(不依赖其他技能),哪些是"组合技能"(依赖其他技能)。

叶子技能是基础,要优先保证它们的稳定性和测试覆盖。组合技能是编排层,要重点保证它们的容错和降级逻辑。我一般会要求:叶子技能的单元测试覆盖率尽量高,组合技能则重点测异常路径。

这里有个反直觉的经验:组合技能出问题,往往不是因为它自己逻辑错,而是因为它假设了叶子技能"一定成功"。所以组合技能里必须显式处理"上游技能失败"的情况,比如重试、降级、或者返回一个明确的错误让上层决定怎么办。

4. 让技能真正跑起来:执行层的几种实现方式

4.1 纯提示词技能:最轻,但边界要清楚

最简单的技能就是纯提示词,不需要写代码,只需要一个模板加几个示例。这类技能适合"模型本身就能做好"的任务,比如改写、翻译、分类、摘要。

但即便是纯提示词技能,我也有几个固定动作:

  • 固定输出格式:在提示词末尾明确要求输出结构,最好给一个示例。
  • 限制输出长度:避免模型啰嗦,影响下游解析。
  • 给出拒绝条件:明确告诉模型"如果输入不满足X条件,直接返回Y",避免它硬编。

我见过有人写纯提示词技能,提示词里全是"请你尽量""你可以考虑"这种软性表述,结果模型行为极不稳定。对模型说话要像对程序下指令,而不是像对朋友提建议。该强硬的地方必须强硬。

4.2 带代码的技能:什么时候必须写handler

当技能需要访问外部资源时,就必须写代码了。典型场景包括:查数据库、调第三方接口、读写文件、做复杂计算。

写handler的时候,我强烈建议遵守一个原则:handler只负责"取数据"和"存数据",不负责"做决策"。决策交给模型,数据操作交给代码。这样职责清晰,也便于测试。

比如一个"查询用户订单"的技能,handler的职责是:接收用户ID,调用订单服务,返回订单列表。至于"这个订单该不该退款",那是模型该判断的事,不该塞进handler。

handler里必须有的东西:

def handle(inputs: dict) -> dict: # 1. 参数校验 user_id = inputs.get("user_id") if not user_id: return {"error": "missing_user_id", "message": "用户ID不能为空"} # 2. 超时控制 try: result = call_order_service(user_id, timeout=5) except TimeoutError: return {"error": "timeout", "message": "订单服务超时,请稍后重试"} except Exception as e: return {"error": "unknown", "message": str(e)} # 3. 结果裁剪(避免返回过大) return {"orders": result[:20]}

注意这里的错误返回是结构化的,不是抛异常。技能之间靠结构化错误通信,而不是靠异常,这样上层才能优雅处理。这是我踩过坑之后的血泪教训——早期我让handler直接抛异常,结果一个技能挂了整个链路就崩了,连个友好的错误提示都给不出来。

4.3 混合技能:模型和代码各干各的

最实用的往往是混合技能:代码负责取数据,模型负责理解和生成,代码再负责校验和落库。

举个例子,"智能回复邮件"这个技能:

  1. 代码:拉取邮件原文和用户历史
  2. 模型:理解邮件意图,生成回复草稿
  3. 代码:校验草稿长度、敏感词、格式
  4. 模型:如果校验不通过,根据反馈重写
  5. 代码:返回最终结果

这种"代码-模型-代码"的交替模式,比纯模型或纯代码都稳。因为代码负责确定性的事,模型负责需要理解的事,各展所长。

提示:混合技能里,模型调用次数要控制。我一般限制单个技能内模型调用不超过3次,超过就说明这个技能该拆了,或者该重新设计流程了。

5. 技能编排:从单兵作战到协同配合

5.1 编排的本质是"路由 + 串联 + 并联"

技能有了,怎么让它们协同工作?这就是编排层的事。我总结编排就三种基本模式:

  • 路由:根据输入决定用哪个技能。比如用户问天气走天气技能,问订单走订单技能。
  • 串联:技能A的输出作为技能B的输入,形成流水线。
  • 并联:多个技能同时执行,结果汇总。比如同时查三个数据源,合并结果。

复杂的编排都是这三种模式的嵌套组合。我建议新手先把这三种模式吃透,别一上来就搞什么动态规划、自我反思,那些是锦上添花,基础编排没做好,花活都是空中楼阁。

5.2 路由的准确性决定用户体验

路由是编排里最容易出问题的地方。用户说一句话,系统要判断该走哪个技能,判断错了,后面全错。

我提升路由准确率的几个手段:

  1. 显式关键词优先:用户明确说了"翻译",就直接走翻译技能,不要犹豫。
  2. 语义相似度兜底:把技能描述向量化,用户输入也向量化,算相似度,超过阈值就走对应技能。
  3. 模型判断补充:前两步都不确定时,让模型在候选技能里选一个,并给出理由。
  4. 兜底技能:实在判断不出来,走一个"澄清技能",反问用户想干什么。

这四层下来,路由准确率能到95%以上。剩下的5%,靠兜底技能兜住,用户体验也不会太差。

5.3 串联时的数据传递要"显式化"

串联最大的坑是数据在技能之间"隐式传递"。比如技能A的输出里有个字段叫result,技能B默认去读result,但技能A某次输出里没有result,技能B就崩了。

我的做法是:技能之间的数据传递必须显式声明。在编排配置里写清楚"技能B的输入来自技能A输出的哪个字段",而不是让技能B自己去猜。

pipeline: - skill: extract_todos output_key: todos - skill: assign_owner input: todo_list: "{{ extract_todos.todos }}" output_key: assigned

这样写,数据流一目了然,出问题也好定位。我早期用隐式传递,排查一个数据丢失问题花了一整天,后来全部改成显式声明,类似问题再没出现过。

6. 调试与排错:技能体系跑不稳时怎么查

6.1 先分清是"技能问题"还是"编排问题"

技能体系出问题,第一件事是定位问题层级。我的排查顺序是:

  1. 单技能测试:把出问题的技能单独拎出来,喂固定输入,看输出对不对。如果单技能就不对,那是技能本身的问题。
  2. 链路追踪:如果单技能没问题,那就是编排的问题。看数据在哪个环节丢了或变形了。
  3. 模型波动排查:如果时好时坏,可能是模型输出的随机性导致的。这时候要检查提示词是否足够约束,契约是否足够严格。

我见过太多人一上来就怀疑模型不行,其实八成问题出在技能设计或编排逻辑上。模型是最后才该怀疑的对象,不是第一个。

6.2 日志要记"输入-输出-耗时"三件套

调试技能体系,日志是命根子。我要求每个技能执行时都记录三样东西:输入是什么、输出是什么、耗时多少。

  • 输入输出用于复现问题。
  • 耗时用于发现性能瓶颈。

有了这三样,大部分问题都能快速定位。我还会给每次链路执行分配一个trace_id,把所有相关技能的日志串起来,这样看一条完整链路就像看一个故事,哪里卡住一目了然。

6.3 常见问题速查表

现象可能原因排查方向
技能不被触发触发条件太严/太松检查触发词和相似度阈值
输出格式错乱提示词约束不够加强格式要求,加示例
链路中途断掉上游技能失败未处理检查错误处理和降级逻辑
结果时好时坏模型随机性降低温度参数,加强约束
响应特别慢技能串太多/外部调用慢看耗时日志,考虑并联或缓存
数据丢失隐式传递字段名不匹配改成显式声明数据流

这张表是我自己排错时最常翻的,基本覆盖了八成以上的问题。

7. 技能体系的版本管理与复用

7.1 技能要像代码一样做版本管理

技能是会迭代的。今天改个提示词,明天加个参数,后天换个模型。如果没有版本管理,改出问题想回滚都回不去。

我的做法是:每个技能目录用git管理,每次修改打tag。技能元信息里记录版本号,编排配置里引用技能时指定版本。这样某个技能升级了,不会影响正在用旧版本的链路。

skills: - name: translate version: 1.2.0 - name: summarize version: 2.0.1

这看起来有点繁琐,但当你同时维护多条链路、每条链路对技能版本要求不同时,这套机制能救命。

7.2 技能复用的关键是"去业务化"

想让技能被多个业务复用,就得把业务相关的部分抽出去。比如"抽取日期"这个技能,不应该内置"订单日期""发货日期"这种业务字段,而应该只负责"从文本里找出所有日期表达并标准化"。

业务相关的映射,放在编排层做。这样技能保持通用,业务变化时只改编排,不动技能。我做过一个统计:去业务化做得好的技能,平均能被4到5个不同场景复用;做得差的,基本一个技能只服务一个场景,维护成本极高。

7.3 建立技能库,别重复造轮子

当技能积累到一定数量,就该建技能库了。技能库要有的东西:

  • 技能清单:每个技能的名称、描述、输入输出、版本。
  • 使用示例:每个技能至少一个可运行的示例。
  • 测试用例:每个技能的标准测试输入输出。
  • 变更记录:每个版本改了什么。

有了技能库,新项目启动时先翻库,能复用的直接拿,不能复用的再新建。我现在的习惯是:新建技能前先搜库,十次有六次能找到能用的或改改就能用的。这省下来的时间,够我多调好几个链路了。

8. 我踩过的几个典型坑和对应的解法

8.1 坑一:技能描述写得太"文学"

早期我写技能描述,喜欢写得漂亮,比如"本技能致力于为用户提供优雅流畅的翻译体验"。结果模型判断该不该用这个技能时,经常判断错。后来我把描述改成大白话:"把中文翻译成英文,输入中文文本,输出英文文本。"准确率立刻上去了。

技能描述是给模型看的,不是给人看的。要具体、直白、包含触发关键词,别整虚的。

8.2 坑二:一个技能里塞了太多"如果"

我曾经写过一个技能,提示词里全是"如果用户问X就做A,如果用户问Y就做B,如果用户问Z就做C"。结果模型经常搞混,该做A的时候做了B。后来我把这个技能拆成三个独立技能,每个只做一件事,问题消失。

技能里的"如果"超过三个,就该考虑拆分了。这是我现在的一条硬性标准。

8.3 坑三:忽略了技能的"冷启动"

新技能上线,没有历史数据,模型对它不熟,表现往往不稳定。我的解法是:新技能上线前,先准备20到30个典型示例放进技能目录,让模型有参考。上线后持续收集badcase,补充进示例库。一般迭代两三轮,技能就稳了。

8.4 坑四:编排层没有超时和熔断

有一次一个外部接口挂了,导致调用它的技能一直等,整个链路卡死。后来我在编排层加了超时和熔断:单个技能超过N秒没返回就跳过,连续失败M次就暂时禁用该技能。加上之后,单个技能出问题不再拖垮整条链路。

注意:超时时间要根据技能类型设。纯模型技能可以设长点,外部调用技能要设短点。我一般纯模型设15秒,外部调用设5秒。

9. 从零搭一套技能体系的实操路线

如果你现在想动手搭一套自己的技能体系,我建议按这个顺序来:

第一步,梳理场景。把你希望智能体能干的活列出来,越具体越好。别写"处理客服问题",写"回答退货政策""查询订单状态""转接人工"。

第二步,抽原子能力。把场景里重复出现的能力抽出来,形成原子技能清单。比如多个场景都要"抽取订单号",那就抽一个"抽取订单号"技能。

第三步,定义契约。给每个技能写清楚输入输出,用JSON Schema最好,不用也得用文字写明白。

第四步,写技能。从最简单的纯提示词技能开始,跑通了再加代码技能。

第五步,编排链路。先用最简单的串联,跑通一条完整链路,再逐步加路由和并联。

第六步,加监控和日志。这一步别省,越早加越好,后面调试全靠它。

第七步,迭代。收集badcase,补示例,调提示词,升版本。

这套流程我自己走过好几遍,每遍都能在一两周内搭出一个可用的技能体系。关键不是一次做完美,而是先跑起来,再迭代。

10. 关于技能体系,我最后想说的几点体会

做智能体技能体系这件事,最忌讳的是"想太多、做太少"。我见过不少人花大量时间设计完美的技能架构,结果一个技能都没落地。我的建议永远是:先做一个最小的技能,跑通它,再慢慢加。

另一个体会是:技能体系的价值不在技能本身,而在技能之间的组合。单个技能再强,也就解决一个问题;技能组合起来,才能解决复杂问题。所以设计技能时,要多想"这个技能能和谁组合",而不是"这个技能能解决什么"。

还有一点:别追求一步到位。我现在的技能体系,和一年前比已经面目全非了。技能拆了又合,合了又拆,契约改了又改。这很正常,因为你对业务的理解在加深,对模型能力的认知也在更新。技能体系是长出来的,不是设计出来的。

最后分享一个我最近在用的技巧:给每个技能加一个"自检"步骤。技能执行完,让模型自己检查一遍输出是否符合契约,不符合就重试一次。这个简单的自检,把很多低级错误挡在了下游之前,链路稳定性又上了一个台阶。你可以试试,成本很低,效果很明显。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询