☰
Agent Skills实战:让大模型从会聊天到会干活的技能设计
2026/10/14 8:45:47 网站建设 项目流程

这一两年做大模型应用,我听过最多的一句话是:"模型智商挺高,就是不会干活。"这话虽然带点调侃,但确实戳中了很多人的实际感受。把一个大模型接进业务系统,写文案、做总结、日常问答都没什么问题,可一旦让它去查数据库、改电子表格、调第三方接口,它就愣住了。问题通常不在模型本身,而在一个长期以来被低估的概念:Agent Skills,也就是智能体技能。

Agent Skills 可以简单理解成:提前给智能体准备好的一批"可被调用的能力模块"。它不是让模型多背一段知识,而是给模型一双能真正操作外部世界的手。过去大半年,我参与了一个知识管理方向的智能体项目,需要让模型自动阅读会议录音转写、抽取待办、写周报,项目做下来最大的体会是:模型选型和 Prompt 调优只占三成工作量,剩下七成都在打磨技能。这篇文章把这些经验整理出来,重点讲技能体系怎么设计、怎么实现、怎么排查问题。适合正在做智能体应用、准备把大模型接入实际业务的同学参考。

1. 想清楚一个问题:Agent Skills 到底在解决什么

1.1 从"会聊天"到"会干活"

大模型的对话能力大家已经很熟了,但真实业务要的是"行动力"。我让智能体"把上周的会议录音整理成待办"时,它面对的不只是一句话,而是一连串子任务:找到录音文件、做转写、解析文本、识别责任人和时间、生成待办、写入系统。其中每一步都涉及模型自身不擅长的操作——读取文件、调用接口、读写数据库。

Agent Skills 就是把这些操作包装成一个个能被模型感知并主动调用的能力模块。技术上通常借助 Mainstream 大模型都支持的函数调用机制,把技能暴露给模型。模型在规划阶段决定"我要调用哪个技能、传什么参数",然后由执行器执行技能并返回结果,模型根据结果继续下一步规划。所以技能本质上是一座"思考与行动之间的桥"。

用生活里的例子类比:模型是大脑,技能是手。大脑负责想,手负责做。没有手的大脑,只能纸上谈兵。很多项目做到一半发现模型"变傻了",其实不是模型退化,而是它缺少足够好用的技能把手,导致它想做的事永远停在计划里。

1.2 技能、工具、插件的边界到底在哪里

在 Agent 生态里,工具、插件、技能这三个词经常混着用,但边界值得分清。

工具是最底层的一个可调用函数或接口,比如"获取用户信息""发送邮件"。插件通常是一组工具的集合,附带配置、权限和界面,偏向产品化,用户装一个插件就能获得一套完整功能。技能则更强调"完整地完成一个业务动作的能力"。它可能只包一个工具,也可能包含多个工具、一段固定流程、一组规则和提示词。

为什么做 Agent 项目时我更喜欢"技能"这个词?因为在智能体场景里,我们关心的不是"底层有没有这个接口",而是"模型能不能可靠地完成这件事"。技能是面向目标的封装,粒度贴近业务。比如"发送邮件"是一个工具,"向项目成员发送周报并抄送主管"是一个技能,后者还要包含收件人清单怎么获取、邮件模板怎么选、发送失败怎么处理等逻辑。

如果一上来就只列一堆底层工具,模型面对几百个函数会很迷茫,选错、漏调、反复试探的情况会非常多。技能的价值在于把复杂性包起来,让模型看到的是一张清晰的"能力菜单"。

1.3 动手前,先画一张技能清单

我的经验是:画技能清单不要从"现有系统有哪些接口"出发,要从"用户想让 Agent 完成哪些任务"出发。最简单的方法是拿一周内的真实用户请求,把每一条都转成"任务-对象-目的"三元组。

举个例子,用户说"把 Q3 汇报 PPT 转成摘要发给领导",拆出来就是:任务是生成摘要,对象是 PPT,目的是发送。再看"帮我把上周例会的行动项同步到看板",任务是同步行动项,对象是例会记录,目的是更新看板。把这些任务里的动词抽出来:检索、解析、生成、更新、通知、归档,每个动词背后往往就是一个候选技能。

拆技能时有三个原则:高频复用优先,失败影响小的优先,输入输出边界清晰的优先。第一版不要贪多,把覆盖 80% 常用请求的技能做出来就行,冷门场景可以留给模型自由发挥或后续迭代。

清单画完之后,还要为每个技能写一句话描述,这句话将来就是模型选择技能时的"广告词"。这一步最容易被跳过,但恰恰是决定技能能不能被正确使用的关键之一。

2. 技能体系怎么搭:分类、粒度与接口设计

2.1 三种常见的技能划分方式

技能清单有了,下一步是设计体系结构。我见过三种划分方式,各有适用场景。

按功能域划分:信息获取类、内容生成类、任务执行类、决策辅助类。这种划分很直观,适合功能数量多、面向不同业务线的项目,缺点是类别之间偶尔会重叠。

按数据流划分:输入处理、分析加工、输出落地。比如先解析文档、再做摘要、最后写入系统。这种划分适合流程型项目,技能之间的先后关系清晰,方便做编排。

按复杂度划分:原子技能和复合技能。原子技能是基础能力,比如"解析文档""创建任务""发送消息";复合技能负责编排多个原子技能并加入业务规则,比如"处理会议"可能包含解析、提取、建任务、发通知四步。这种划分适合从简到繁迭代。

我在项目里通常用第三种作为主线,再结合功能域做命名和分组。原子技能保证复用性,复合技能保证业务完整性,两边各司其职。

先做一个简单的能力分类表,帮助团队对齐认知:

技能类型典型例子是否可复用是否包含编排
原子技能解析转写文本、创建待办高否
复合技能生成会议纪要、同步看板中是
外部接入技能查询项目系统、发通知低视情况

2.2 技能粒度:太粗和太细都是坑

技能粒度是整个体系里最容易踩坑的地方。

粒度太细的典型表现:一个技能只做"读取文件"或"调用接口",模型要连续调五六个技能才能完成一个用户任务。每多一次调用,就多一次失败概率、多一段延迟和多一笔 Token 开销,而且模型在长链条里丢失参数的概率会指数级上升。

粒度太粗的典型表现:一个技能叫"处理会议",实际内部包含解析转写、生成纪要、发通知、建任务四件事。模型的输入参数根本写不清楚,输出描述也含糊,结果就是误用、漏操作,或者把一堆不相关的事塞进一次调用里。

我给团队定的标准是看"业务可验证的结果":一个技能执行完,你能明确说"这件事做完了",说明粒度合适。例如"生成会议纪要""创建待办""更新看板"都是合适的技能;"处理会议"和"读取文件"都不合适。前者太粗,后者太细。

2.3 接口设计:让Agent真正"用得了"技能

技能最终要交给模型去调用,所以接口设计必须把模型当作一个粗心但聪明的调用者。

第一是技能名。用动词开头的短语,见名知意。search_recent_documents 比 doc_utils_01 好太多。模型在决策时是先扫技能名再读描述的,名字太抽象等于让模型多猜一步。

第二是参数。参数越少越好,尽量给默认值,类型要明确。多一个必填参数,模型就多一次传错的机会。时间日期这类参数要写明格式,比如"日期格式为 YYYY-MM-DD",不要只写一个 date 让模型自己猜。

第三是返回值。尽量返回 JSON,并把执行状态放在最外层,业务数据放 data 里。不要返回一大段自然语言文本让模型自己解析,那样非常不稳定。

第四是错误处理。技能失败时要返回可读的错误码和原因,比如 NOT_FOUND、PERMISSION_DENIED,而不是抛异常直接中断整个链路。模型拿到错误信息后还能自己修正参数重试,这对成功率提升非常明显。

一个接口定义看起来像这样:

# 技能返回的统一结构 def build_response(success: bool, data=None, error=None): return { "success": success, "data": data if success else None, "error": error if not success else None }

2.4 技能描述:最容易被低估的一环

很多人写完技能描述只写一两句话,实际跑起来才发现,模型选错技能十有八九和描述有关。技能描述不是给程序员看的,是给模型看的,它的作用是帮助模型在几十个技能里挑到正确的那一个。

我建议描述按这个模板写:这个技能是干什么的,一句话;什么情况下应该调用,给出明确的触发场景;什么情况下不应该调用,写清楚反例;参数的含义和格式,逐一说明;再附一个典型用法示例。

正反面示例对比一下。反面写法:"解析文档。"太短了,模型不知道什么文档、用什么格式、输入输出长什么样。正面写法:"解析会议录音转写文本,返回包含标题、参会人、议题、结论的结构化 JSON。当用户提到'整理会议记录''解析转写'时调用。如果用户只是要求总结观点,不应调用此技能,应使用 generate_summary 技能。参数 raw_text 为原始转写内容。"这样模型基本不会选错。

在项目里,描述文本的维护要跟代码一起做评审,改功能不改描述是后期故障的一大来源。

3. 实操过程:从零实现一组 Agent Skills

3.1 场景设定:做一个会议纪要自动化工位

理论讲再多,不如动手做一遍。我虚构一个非常常见的场景:某产品团队每周开两次例会,已经有一份语音转写文本,希望智能体自动生成会议纪要、提取行动项、写入项目看板并通知相关人。用户输入一句话:"帮我把今天的例会录音转写整理一下,生成纪要和待办。"

这个场景需要的技能清单可以定为四条:parse_transcript 解析转写文本,extract_action_items 提取行动项,create_todo 创建待办,post_message 发送通知。其中 parse_transcript 是偏原子的技能,它的输出会被其他技能复用;extract_action_items 和 create_todo 是业务技能,负责把自然语言变结构化;post_message 是外部接入技能,负责最后落地。

这个场景选择"显式编排"而不是完全交给模型自由规划,原因是步骤顺序很固定,流程可控远比灵活性重要。用户预期就是从文本到纪要再到待办,顺序错了会产生一堆脏数据。

3.2 技能A:文档解析与关键信息提取

解析转写文本听起来简单,做起来很容易翻车。最忌讳的是用正则去匹配自然语言,比如找"参会人:张三"之类的固定格式,实际转写文本千奇百怪,今天可能是"今天有张三、李四参加",明天可能是"张三和李四都来了",正则写不完的。

我的做法是把这个技能内部也接一次模型调用,但用固定的抽取 Schema 做约束。技能对上层暴露的参数只有一个 raw_text,内部用特定的提示词让模型抽取字段并输出 JSON,然后做一层字段校验。这样上层技能拿到的永远是统一结构,不会因为文本格式变化而崩。

# skills/parse_transcript.py def parse_transcript(raw_text: str) -> dict: """解析会议转写文本为结构化内容。 参数: raw_text: 语音转写的原始文本。 返回: { "success": true, "data": { "title": "例会-2025-Q3", "attendees": ["张三", "李四"], "topics": ["需求评审", "进度同步"], "decisions": ["需求评审通过,采用方案B"] } } """ extracted = extraction_model.run( schema=MEETING_SCHEMA, content=raw_text ) if not is_valid_schema(extracted): return build_response(False, error="SCHEMA_INVALID") return build_response(True, data=extracted)

这类技能的关键在于 Schema 必须稳定。上线后不要轻易加字段,因为上游技能依赖它,模型在编排时也会根据字段名推断后续步骤。改一次 Schema,等于所有下游技能都要重新测试。

3.3 技能B:会议待办生成与任务入库

提取行动项和创建待办是两个技能,最好拆开。提取行动项也是偏"模型抽取"性质的,从结构化文本里找"责任人、截止时间、事项描述",输出为待办列表;创建待办则是纯逻辑加接口调用,把待办写入任务数据库。

创建待办这种技能要做得尽可能"确定",内部不要依赖大模型发挥,因为写入操作一旦出错就很难补救。所有字段进去之前先做校验,非法输入宁可拒绝也不要硬写半个待办进去。实现示例:

# skills/create_todo.py def create_todo(title: str, due_date: str = "2025-12-31", owner: str = "", priority: str = "medium") -> dict: """创建一条待办任务并返回任务ID。 参数: title: 待办标题,不能为空。 due_date: 截止日期,格式 YYYY-MM-DD。 owner: 负责人,可省略。 priority: 优先级,可选 high/medium/low。 返回: {"success": true, "data": {"todo_id": "T-12345"}} """ if not title or len(title.strip()) < 3: return build_response(False, error="TITLE_INVALID") if due_date and not is_valid_date(due_date): return build_response(False, error="DATE_INVALID") if priority not in ("high", "medium", "low"): return build_response(False, error="PRIORITY_INVALID") todo_id = todo_api.create( title=title.strip(), due_date=due_date, owner=owner.strip(), priority=priority ) return build_response(True, data={"todo_id": todo_id})

有人会问,参数校验这么严格,会不会导致模型经常传错被拒?实际情况恰恰相反。校验严格、错误信息明确,模型在第一次被拒后就会根据错误提示调整参数,整体成功率反而上升。最怕的是接口"什么都收",结果写入一堆脏数据,后期清理成本远高于一次重试。

3.4 技能编排:让多个技能按顺序协作

复合技能就是把原子技能按业务顺序串起来。以会议纪要场景为例,编排过程可以简化成下面这样:

# skills/process_meeting.py def process_meeting(raw_text: str) -> dict: # 第1步:解析文本结构 parsed = call_skill("parse_transcript", {"raw_text": raw_text}) if not parsed["success"]: return parsed # 第2步:提取行动项 actions = call_skill("extract_action_items", { "content": parsed["data"] }) if not actions["success"]: return actions # 第3步:逐条创建待办 for item in actions["data"]["items"]: todo = call_skill("create_todo", { "title": item["title"], "due_date": item.get("due_date", ""), "owner": item.get("owner", "") }) if not todo["success"]: return todo # 第4步:发送通知 notify = call_skill("post_message", {...}) return notify

这种显式编排有几个好处。第一,省 Token,模型不需要在所有环节都参与决策。第二,行为可控,步骤顺序完全由代码保证。第三,出错定位快,日志一看就知道卡在哪一步。

但也不是所有场景都该用显式编排。如果用户请求非常开放,比如"帮我处理一下这份会议记录",中间可能包含摘要、待办、周报等多种产出,这时让模型自主规划反而更灵活。我实际采用的策略是:关键业务链路用显式编排,开放需求用模型自主规划,两类模式可以共存。

4. 常见问题与排查技巧实录

4.1 技能注册了,但Agent就是不调用

这大概是群里被问得最多的问题。技能明明写得没问题,但模型就是不调。我的排查顺序一般是这样的:

先查日志里的模型决策轨迹,看模型在生成最终回答前有没有提到技能名。如果完全没提,大概率是描述不清或触发场景没写明白,模型根本没把请求和技能关联起来。如果模型提了技能名却没有真正调用,那就要检查参数的必须项是不是太多,模型可能因为凑不齐参数而放弃。

还有一个很隐蔽的原因:改完技能忘了发布新版 Agent。很多平台里技能和 Agent 之间存在版本绑定,本地测试通过不代表线上生效。遇到"技能就是不调用"的情况,先看一眼线上版本是不是最新的,能省下大量排查时间。

4.2 技能调用参数总是传错

参数传错是模型调用技能时最典型的问题,表现形式也很集中:日期传成"下周二"而不是具体日期,枚举值传中文而不是英文,必填参数直接不传,数组参数结构不对。

解决思路分三层。第一层是描述引导,在参数说明里写死格式,比如"日期格式为 YYYY-MM-DD,如 2025-12-31",别写"传入日期"。第二层是默认值兜底,能不给必填就不给必填,让模型尽量少做选择。第三层是入口校验加清洗,发现参数格式不对时,在技能内部做一次转换或纠正,不要直接拒绝,也别放任脏数据进入业务逻辑。

我见过一个真实案例:一个技能要求传入用户ID列表,模型总是传成逗号分隔的字符串。后来在技能入口把字符串自动转成列表,问题立刻消失。与其要求模型"正确",不如让技能本身更宽容。

4.3 技能返回结果不结构化,解析困难

很多自己实现的技能,返回结果五花八门:有的返回字符串,有的返回字典,有的失败时抛异常,有的成功时却夹杂着大段提示文本。上层技能处理返回值时只能靠猜,稳定性自然差。

解决这个问题只有一条路:所有技能统一返回结构。至少包含 success、data、error 三个字段,成功时 data 是结构化对象,失败时 error 是机器可读的错误码。再加一道返回结果校验器,任何技能返回前都过一遍,结构不对就自动修正或重试。

def validate_and_fix(result): if not isinstance(result, dict): return build_response(False, error="RESULT_NOT_DICT") if "success" not in result: return build_response(False, error="MISSING_SUCCESS_FIELD") return result

这套规则听起来繁琐,但一旦形成习惯,后面加新技能会越来越顺,排查问题的速度也会快很多。

4.4 技能编排死循环或超时

模型自主规划模式下,偶尔会出现循环:反复调用同一个技能,或者在两个技能之间来回跳。原因一般是技能描述之间有歧义,模型不知道自己该结束,或者某个技能返回结果一直不满足退出条件。

防御措施比事后排查更重要。给整个 Agent 加三层限制:最大调用次数、最大 Token 消耗、总超时时间。一旦命中任何一层,立刻终止并返回"需要人工介入"的提示。还要注意,技能之间不要互相调用,如果确实有公共逻辑要复用,应该把它下沉到共享层,否则很容易出现隐式循环,排查起来极其痛苦。

4.5 排查工具与调试方法

最后说几个让我效率翻倍的排查习惯。

首先是完整日志。每次调用都记录五样东西:模型决策轨迹、被调用的技能名、传入参数、返回值、耗时。有了这五样,绝大多数问题都能定位到具体环节。没有日志,就只能靠猜,效率极低。

其次是回放能力。把一次失败的用户请求连同当时的技能调用序列记录下来,在测试环境改掉某个技能返回后重新跑一遍,验证问题能否复现。这个习惯能省掉大量"改了代码不知道有没有用"的无效循环。

最后是技能单元测试。为每个技能准备至少四类测试:成功路径、参数缺失、数据不存在、超时。不用写得特别复杂,能覆盖这四类就能拦住一大半低级问题。配合模拟数据层,每次改动技能代码先跑一遍测试,再让模型真实调用。

我在这套技能体系上前后迭代了三个版本。第一版技能粒度特别细,模型频繁调用一堆小技能,速度慢、成本高;第二版把相似技能合并,结果模型经常误用;直到按"可验证业务结果"来划分技能边界,整体稳定性才真正上来。如果你也在折腾 Agent 技能,我的建议是先挑一个核心场景做小范围测试,把日志和调用轨迹看得滚瓜烂熟再扩大技能范围。另外,技能描述要像写产品说明一样写清楚,宁可啰嗦一点,也好过让模型去猜。

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

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

立即咨询