资讯动态

从零搭建Agent技能库:大模型执行力进阶的实战指南

发布时间:2026/10/8 4:55:34 来源:尧图企业网站定制
做AI Agent开发的这半年我踩过最大的坑往往不是模型能力不够而是模型明明什么都会一让Agent真正干活就抓瞎。后来我反复复盘才明白问题出在少了一套扎实的agent-skills技能体系。所谓agent-skills可以理解为给大模型配的手和脚让模型不再只是给建议、说结论而是能真正调用技能、执行动作、完成一件具体的事。这篇文章不是理论科普是我自己从零搭Agent技能库的完整沉淀。内容覆盖技能设计思路、任务拆解方法、参数Schema规范、技能注册与调用链路、多技能编排、常见坑点以及一个可以直接跑通的最小代码示例。无论你用的是LangChain、CrewAI还是自研框架这套方法论基本通用。适合正在做Agent开发、准备把大模型接进真实业务流程的朋友参考。1. 为什么说Agent技能是会干活的分水岭1.1 从会聊天到会干活技能到底指什么Agent技能本质上就是一个稳定的能力接口 一段模型能读懂的能力说明 一套可验证的执行逻辑。这三者缺一不可。拿查天气举例如果只是让模型凭记忆说今天可能下雨那是对话但如果你让模型调用天气API拿到实时数据之后再组织语言回答这就变成了技能调用。技能让Agent从被动应答跨到了主动完成任务这一侧。很多人把技能理解成普通的函数封装觉得我写个Python函数不就完了。但函数是给程序员看的技能是给模型看的。模型不像程序员那样知道你的函数内部逻辑它只能通过你提供的描述和参数Schema来理解这个技能是干什么的、什么时候该用它、怎么填参数。这正是Agent技能和普通工具函数的核心区别技能是给模型配的一件带使用说明书的手套模型得先读懂说明书才能正确地把手伸进去操作。我自己的习惯是把技能当作一个小型产品来设计它有使用场景、有输入约束、有输出格式、有失败反馈。写技能之前先问自己三个问题——用户模型在什么情况下会找到它它能给用户模型返回什么它做不了什么这三个问题想清楚了技能才算是设计到位。1.2 技能、工具、工作流先把概念边界理清楚在动手之前我建议先把三个高频词拆开工具Tool、技能Skill、工作流Workflow。它们经常被混着叫但工程上的角色完全不一样。工具是最底层的能力提供者通常是单个API封装、单个数据库查询函数本身不参与决策也不关心业务场景。技能是面向任务的、带使用说明的能力单元它通常会包装一个或多个工具并且和模型的决策行为绑定。比如查询今日天气是一个技能它内部可以调用某个天气API工具也可以顺带调用一个地理编码工具做城市名转换。工作流则是多个技能按固定或半固定顺序编排起来用来走完一条完整的业务链路比如生成周报并发送到群聊。早期我犯过一个典型错误直接给模型暴露一堆裸工具函数没有做技能层包装。结果模型经常把工具名当闲聊内容该调用的时候不调用调用的时候又因为参数语义不清而传错。后来我把层级改成底层工具 - 中层技能 - 上层工作流每个技能都带完整的调用说明模型的选择准确率一下就上来了。1.3 技能设计为什么决定Agent的上限模型的能力决定Agent有多聪明技能体系则决定Agent能触达多广的边界。一个再聪明的模型如果技能列表乱成一团、描述含糊、参数互相打架它也不可能稳定地完成复杂业务任务。我常打一个比方Agent就像一个刚到岗的实习生脑子很灵光但完全不知道公司有哪些系统、每个系统的入口在哪、什么场景该用哪个系统。这时候你给他的操作手册——也就是技能描述和参数Schema——写得清不清楚直接决定他能不能把活干漂亮。手册写得好实习生不用什么都问手册写得烂他要么瞎猜要么瞎干。更重要的是技能体系的质量是可以通过工程化手段持续迭代的。每次失败都能归因到描述不清接口不稳编排错误某一个具体环节上然后针对性修复。这比发现效果不行就换模型、调Prompt要可控得多。我做过多个Agent项目后最深的体会就是换模型调Prompt是短期手段沉淀一套靠谱的技能库才是长期基本盘。2. 技能设计的第一步把任务拆成技能模块2.1 任务拆解从一个目标到一组技能设计技能之前先别急着写代码先把任务拆清楚。我的拆解方法分为四步。第一步用一句话描述目标任务的最终产物。比如每周五自动生成一份周报并发送给直属领导。第二步列出达成这个产物所需的所有中间步骤包括数据收集、内容生成、格式处理、消息推送等。第三步标记每个步骤是否需要与外部世界交互——凡是需要真实数据、真实操作、真实反馈的步骤都值得拆成一个技能如果某一步只是模型内部推理就不需要技能。第四步把能合并的步骤合并减少模型做决策的次数。拿周报生成来举例目标产物是一份周报文档 一封已发送的邮件。中间步骤可以拆成从项目管理平台拉取本周任务数据读取上周周报模板渲染周报内容校验格式完整性发送邮件。其中拉取任务数据渲染内容发送邮件这三个环节涉及外部系统交互至少要拆成三个技能校验格式步骤可以放进渲染技能内部不必单独暴露给模型。有一个判断粒度是否合适的经验标准一个技能做完的事情口头上一句话能说清楚。如果说三句话还说不清这个技能到底干了什么它就不够原子应该继续拆。2.2 技能粒度怎么选粗技能与细技能的平衡技能粒度没有绝对标准只有场景匹配。粗技能比如生成周报这个技能内部把数据收集、模板渲染、发送邮件全流程包好模型只需要调用一次。细技能则拆成查询任务列表渲染Markdown模板发送电子邮件三个独立技能模型按需组合。粗技能的优势是模型决策少、执行路径固定、不容易出错劣势是灵活性低一旦流程里某个环节需要单独调整就得整个改。细技能的优势是灵活模型可以根据不同用户请求自由组合技能劣势是决策点多每一步都有选错的可能成功率会随着步骤增加而下降。我的建议是新项目起步阶段先用细技能跑通链路之后再针对高频且稳定的任务做技能合并封装成粗技能。比如业务上发现周报生成这个任务每周都要跑而且流程完全固定那就值得合并成一个粗技能。反过来如果任务经常有变化比如用户临时想只查数据不生成周报那就保留细技能组合。千万别一上来就全用粗技能一旦边界封错后面想拆开会非常痛苦。2.3 技能描述的写作比写代码更该花时间如果让我排技能设计的优先级技能描述的质量排第一参数Schema排第二实现代码反而排第三。因为代码只决定技能能不能执行而描述决定模型会不会在正确的时机选中它。后者直接决定了Agent的整体准确率。一个合格的技能描述应该包含三块内容这个技能做了什么、在什么场景下该用它、它有什么限制和副作用。我见过大量失败的技能描述只写了第一块比如该技能用于查询天气。这种描述信息量极低模型根本不知道什么时候触发它。给大家一个可以直接套用的模板根据城市名称查询实时天气状况返回温度、湿度、风力、天气现象等结构化信息。当用户询问天气、出行是否需要带伞、明天适不适合跑步等场景时优先使用本技能。注意本技能仅支持国内主要城市如果用户所在地不在支持列表请先提示用户手动选择城市。这个描述把触发条件、输入方式、边界限制都讲清楚了。我还会习惯在描述末尾加一句不要用于什么场景比如不要在本技能中处理历史天气查询历史天气请走历史数据技能。这个负面约束极其有用能显著减少模型对相似技能的混淆。实际测试中加了这个约束之后两个相似技能的误触发率至少降了一半。2.4 参数Schema设计让模型把参数填对参数Schema是模型填参数时的填空题模板。模板出得好模型能填对模板出得烂填错是必然的。我的参数设计原则有五条。第一参数名要语义化time_range比time好business_date比date好。第二类型要严格能枚举就枚举穷举可选值。第三每个参数都要配一段自然语言描述说明它是什么、取值范围、不传时默认什么行为。第四尽量给出示例值示例不是让模型照抄而是帮它理解这个参数长什么样。第五必填参数和可选参数分清楚不要把所有参数都设为必填也不要全设为可选。常见的反面案例是这样一个函数定义成get_history_data(code: str, date_range: str)模型拿到之后完全懵——code是股票代码还是城市代码date_range是7d这种相对时间还是2024-01-01至2024-01-07这种绝对时间这种参数Schema模型不填错才怪。工程上我建议用Pydantic或者JSON Schema来定义参数不要只靠Python类型注解。模型读到的是JSON Schema字符串Python注解会被转译、折叠、丢失语义。用Pydantic的好处是可以直接生成模型友好的Schema同时还能在运行时做数据校验一举两得。3. 从零搭一个Agent技能库完整实操记录3.1 认清选型的本质框架不是越重越好搭技能库之前要先面对选型。市面上有LangChain、CrewAI、Semantic Kernel等成熟框架也完全可以自研一套轻量机制。我的建议是如果你刚开始做Agent并且没有必须用某个框架的硬性约束先自研一个最小闭环跑通比直接上框架更容易理解本质。原因很简单框架会把很多关键细节藏起来模型是在什么时候看到技能列表的模型返回的工具调用是如何被解析的参数校验失败之后发生了什么事这些恰恰是实战中踩坑最多的地方。如果一开始就被框架封装住出了问题会陷入黑盒调试的困境。自研技能注册机制其实并不复杂。核心就四件事定义技能函数、生成参数Schema、把技能列表注入Prompt、解析模型输出并执行。这个最小闭环一旦跑通你对Agent技能机制的理解会非常扎实之后再去用框架也更容易看懂它的封装逻辑。3.2 技能注册与调用的完整链路技能库的调用链路拆开看就七个环节定义技能函数实现具体业务逻辑。通过装饰器或注册表把函数登记为技能并生成JSON Schema。把技能Schema列表注入系统Prompt让模型知道现在有哪些能力可用。模型根据用户请求在回答中返回一个工具调用指令。解析模型输出用Schema做参数校验。校验通过后执行技能函数把执行结果返回给模型。模型根据技能返回的结果生成最终答复给用户。这个链路上最容易出问题的是第5步也就是参数校验。我的经验是永远假设模型会填出你Schema之外的参数。哪怕你写了枚举它也可能传一个不在枚举里的值哪怕你标了必填它也可能漏掉。所以在执行前必须做一次Schema校验非法参数宁可拒绝执行也不要强行去跑这是上线事故换来的教训别嫌麻烦。3.3 写一个真实的技能并跑通它下面给一个最简可运行的技能库骨架你们可以直接照着改。先用一个Skill类封装技能的基本信息from typing import Any, Callable import json class Skill: def __init__( self, name: str, description: str, parameters: dict | None, func: Callable ): self.name name self.description description self.parameters parameters self.func func def to_schema(self) - dict: return { type: function, function: { name: self.name, description: self.description, parameters: self.parameters or {type: object, properties: {}, required: []}, }, } def run(self, **kwargs): return self.func(**kwargs)然后定义一个真实的技能函数。这里用天气查询做演示真实场景里换成你的API调用逻辑def get_weather(city: str, date: str today): # 真实项目中这里替换为天气API调用 mock_data { 上海: {city: 上海, date: date, weather: 晴, temp: 26}, 北京: {city: 北京, date: date, weather: 多云, temp: 22}, } return mock_data.get(city, {city: city, date: date, weather: 未知, temp: None})接着把技能注册成列表并生成模型能读到的Schemaskills [ Skill( nameget_weather, description根据城市名查询实时天气当用户询问天气、穿衣建议、出行是否带伞时使用。仅支持国内主要城市。, parameters{ type: object, properties: { city: { type: string, description: 城市名称例如上海、北京, }, date: { type: string, description: 日期格式YYYY-MM-DD不传默认今天, }, }, required: [city], }, funcget_weather, ) ] schema_list [s.to_schema() for s in skills] print(json.dumps(schema_list, ensure_asciiFalse, indent2))最后模拟一次模型返回工具调用并执行# 模拟模型返回的function call function_call {name: get_weather, arguments: {city: 上海}} skill_map {s.name: s for s in skills} skill skill_map[function_call[name]] result skill.run(**function_call[arguments]) print(result)这个闭环就是Agent技能调用的最小骨架。真实项目中你只需要把模拟function call替换成真实大模型接口的返回解析就行。不同厂商的模型返回格式不一样OpenAI有tool_calls字段Claude有tool_use块本地模型可能用自定义格式。建议写一个适配层把不同格式统一解析成上面这种{name: ..., arguments: ...}结构技能执行层就不用关心上层模型差异了。3.4 多技能协同当任务不再只有一个步骤单技能跑通之后下一个问题是如何让多个技能协作完成一个复杂任务。多技能协同有两种编排方式。一种是自动编排把多个技能全部暴露给模型由模型自己决定按什么顺序调用。这种模式适合开放性任务比如帮我安排周末行程模型需要自行判断查景点、查天气、查交通。另一种是固定流程用代码把技能按固定顺序串联中间再让模型在关键节点做决策。这种模式适合重复性高、步骤明确的业务比如周报生成流程。我个人强烈建议能用固定流程固化下来的步骤尽量不要让模型自由编排。纯自动编排有一个概率叠加问题假设每一步技能选择准确率都是90%三步任务串下来成功率只有72.9%五步就只剩59%。这一步一个偏差累计下来Agent的表现非常不稳定。所以对关键业务场景要尽可能减少中间决策点把稳定步骤直接写死在编排器里。在固定流程中每个步骤之间需要传数据。我习惯用一个统一的上下文对象在步骤之间传而不是靠参数层层传递class TaskContext: def __init__(self): self.data {} self.trace []每一步执行完把输出写入context.data同时把调用了哪个技能、传了什么参数、结果摘要是什么追加到context.trace。这样既方便调试又为后面的日志归因分析打了基础。后面排查问题的时候只要翻一下trace就能还原整个任务的执行过程。3.5 技能质量和效果的验证方法技能库不是写完就能上线的起码要做三层验证。第一层是单技能测试。给每个技能准备一组固定测试用例覆盖常规输入、边界输入、非法输入。比如查天气技能要测正常城市名、不支持的城市、缺参数的情况。这一层验证的是技能函数本身对不对。第二层是技能选择测试。构造一批用户请求看模型在正确场景下是否选中了正确技能。这一层本质上是测试技能描述的质量。如果某个请求模型选错了技能优先去改描述而不是改模型参数。第三层是端到端任务测试。跑完整的Agent任务看最终产物是否正确。比如周报生成Agent要真的跑一遍拉数据-渲染-发送整个流程看输出邮件是否完整。这三层我都建议做成自动化回归脚本每次改技能描述、新增技能、调整编排逻辑之后都跑一遍。我见过太多项目死在demo能跑、一改就坏的阶段就是因为没有这套回归保障。别觉得写自动化脚本麻烦这是技能库从能用走向好用的关键一步。4. Agent技能实战中的常见问题与排查4.1 模型就是不调用技能怎么办这是我被问得最多的问题技能列表明明已经放进Prompt了模型却视而不见还在那儿硬编答案。常见的诱因有三个。第一个是技能列表太长被Prompt里其他内容淹没了。模型对位于Prompt边缘的列表注意力会下降尤其是几十个技能堆在一起的时候。解决办法是控制单次暴露的技能数量一次别超过20个。超过这个数就该做分组路由比如先让模型选择一个分组再在该分组内选择具体技能。第二个是技能描述写得太静态只写了技能是什么没写什么时候触发。模型本质上在做选择它需要的是行动指令。在描述里直接写当用户请求包含天气信息时请调用get_weather获取实时数据比只说该技能用于查询天气有效得多。第三个是系统Prompt里缺少显式的工具调用指令。我通常会在系统Prompt里加一句如果你需要获取实时数据或执行具体操作请直接使用工具调用不要基于记忆推测。这句话看着简单实测下来对工具调用率的提升非常明显。它相当于给模型一个明确的行动许可很多模型会因为缺少这个许可而只输出文字建议。另外再分享一个兜底技巧当模型连续两轮不调用技能却还在编造数字或时间时可以在生成之后加一道程序化检查检测回答中是否出现了具体数字、时间、地点等断言如果存在且对应任务的目标技能没有被调用过就强制返回请先调用技能后再回答。这个手段比较粗暴但能兜住很多漏网之鱼。4.2 参数总是填错怎么兜底参数填错的排查方向我建议按顺序查三件事。第一件参数名是不是和业务语义对应。我之前有个技能参数名叫query模型总是把一整段话塞进去。后来我把参数名改成keywords并在描述里写明请提取关键词填入不要填完整句子问题立刻解决。参数名看着是小细节但模型对名字的语义理解非常敏感。第二件枚举值写全了没有。凡是有固定取值范围的参数都要穷举出来并配上中文说明。比如查询周期的取值就写清楚1d代表近一天、7d代表近七天、30d代表近一个月模型就不会自己去猜。第三件有没有给示例值。描述里给一个例如上海这样的示例比用一长段抽象描述管用得多。参数校验的正确姿势是执行前用JSON Schema校验校验失败不要直接给用户报错让模型重填一次。你可以把错误信息直接抛回给模型比如调用get_weather时缺少必填参数city请先补齐参数再调用。实测下来这种给模型一次纠错机会的机制能把参数填充成功率从70%拉到95%以上。注意只给一次纠错机会避免陷入循环调用。4.3 多个技能互相抢活如何隔离技能多了之后就会出现一个麻烦两个技能长得像模型不知道该选哪个。比如查询天气和查询空气质量两个技能用户问今天上海适合跑步吗模型一会儿选天气一会儿选空气质量甚至两个都调用结果发散。我常用的解决办法有三个。第一在技能描述里主动声明边界。比如在天气技能描述末尾加一句不要用于判断空气质量空气指数请调用查询空气质量技能。这个和之前说的负面约束是同一个思路对强相似技能非常有效。第二在技能路由层做互斥规则。当两个技能同时被模型选中时用程序判断哪个更相关。比如跑步环境场景业务上天气和空气都要看那就直接用一个聚合技能查询跑步环境综合指数把它俩包起来模型只需要选一次。第三定期检查技能列表合并相似技能。如果发现多个技能经常被同时触发说明它们在模型眼里高度相关这时候就应该把它们升级成一个组合技能从根源上解决抢活问题。4.4 技能执行失败后的降级与恢复技能执行失败是必然事件不是偶然事件。设计技能库时就要提前想好失败后的处理策略。失败要区分可重试和不可重试。接口超时、网络抖动这种瞬时错误可以自动重试一两次参数非法、业务规则不满足这种确定性错误重试没有意义应该尽快把失败信息反馈给模型让它换一种处理方式。然后要有降级策略。主技能失败时有没有备用路径比如查询实时天气API失败了可以先读取昨天的天气缓存数据或者直接告诉用户当前无法获取实时数据请稍后再试。这个降级策略的执行逻辑我建议放在编排层做而不是让模型自己临场发挥。模型的临场反应不稳定同样是失败它可能这次给用户说稍后再试下次直接编一个数据。程序化降级至少在不造假这件事上是可靠的。我的一个经验是不要让模型自己决定重试还是降级。模型对错误类型的判断能力其实一般把它放在根据技能返回内容判断结果是否满足用户需求这个环节就好。重试逻辑、降级路径、失败反馈格式都应该在代码里写死。职责清晰系统才能稳定。5. 技能体系的长期维护不只是写函数5.1 版本管理与兼容策略技能库一旦上线就会面临持续迭代。改一个参数名、改一个返回字段、调一段描述都可能影响正在跑的线上任务。所以技能也要像接口一样做版本管理。我给每个技能加一个version字段在调用日志里带上版本号方便定位问题。变更技能接口时不要直接覆盖旧版本保留旧版本一段时间用能力标记做灰度切换。比如新版本的技能先让10%的流量使用观察几天再全量切换。技能描述的变化尤其需要谨慎。模型对新描述有个适应期实测中直接替换描述后往往会有一两天的准确率波动。所以重要技能的描述变更我建议先在测试集上验证再小流量灰度别急着全量上线。5.2 日志追踪与归因分析技能库运行一段时间后日志就是最重要的资产。每次Agent调用技能至少记录五类信息用户原始请求、模型最终选择了哪个技能、传入的参数快照、技能执行结果摘要、最终回答摘要。有了这些日志失败案例就能快速归因。我通常把失败分成四类技能选择错、参数传错、执行结果差、编排顺序不对。归类之后针对性修复比漫无目的地调Prompt高效得多。没有归因日志的技能库排查问题的时间会从半小时拖到半天这是很贵的成本。另外我还会记录模型没有调用技能但完成了任务的情况这类样本同样有价值。如果训练样本里大量出现这种跳过技能直接回答的情况说明技能描述或系统Prompt对模型来说不够有吸引力需要优化技能暴露方式。5.3 技能复用与团队沉淀技能库做到一定规模就不该只是个人资产了应该沉淀成团队的公共资产。统一命名规范、统一描述规范、统一参数规范新项目直接复用成熟技能而不是重复写一个几乎一样的函数。我自己的命名习惯是领域_动作_对象的格式比如data_query_tasks、mail_send_report。一眼就能看出这个技能属于哪个领域、做什么动作、操作什么对象。描述统一用固定模板第一句写该技能用于……第二句写当用户需要……时优先调用第三句写注意……。这个格式固定之后团队里任何一个人写新技能其他人也能快速看懂和维护。把验证过的技能沉淀下来还有一个好处团队的技术判断会越来越集中于场景拆解和技能设计这些上游决策而不是反复争论这个函数怎么写。这才是技能库真正变成团队资产的时候。5.4 权限边界与安全控制技能是Agent的手和脚这句话的另一个含义是技能也具备对外部系统的操作能力。权限控制必须跟上不能让模型随便调写接口。我的权限设计原则有四条。第一可读技能和写操作技能分开存放写操作必须有更强的触发条件。第二发送消息、提交订单、删除数据这类高风险操作执行前加一道二次确认不能在模型擅自调用时直接生效。第三敏感数据在传给模型之前要脱敏模型不需要看到完整的用户隐私字段和密钥。第四记录全链路的审计日志谁调用了什么技能、传了什么参数、返回了什么结果全部留痕。这些听上去像运维话题但Agent真正用起来之后安全问题是暴露得最快的。我见过一个团队Agent有权限绕过校验直接调内部接口出了问题半天定位不到最后只能把权限模块从头补起来。前期设计权限边界成本远远低于事后补救。最后分享一个我花了大半年才真正想明白的体会agent-skills从来不是一个技术名词它更像团队内部的一种工程纪律。你愿意花多少精力去打磨技能描述、规范参数Schema、固化回归测试决定了Agent在真实业务里到底可不可靠。模型每隔几个月就会升级一次但技能库的沉淀速度才是Agent项目真正的壁垒。如果你准备开始做自己的Agent我的建议是从最小的闭环开始先认真写好两三个技能跑通注册、调用、反馈的完整链路再逐步扩展。技能不在多在于每个技能都经得起真实业务的折腾。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑