Agent技能系统设计:从参数Schema到技能编排的工程实践
发布时间:2026/10/7 19:19:43 作者:尧图编辑部 阅读量:1,286

1. Agent技能的本质为什么一定要有技能系统这层抽象1.1 从会聊天到会干活差的不只是模型能力做过Agent落地项目的人应该都有同感模型推理能力再强如果它只能空谈不能动手那离真正解决业务问题还差着十万八千里。我们团队做客服、知识库、内部效率工具这类Agent时早期最头疼的瓶颈反而不是模型本身而是怎么让模型安全、稳定、可控地调用外部能力。你直接给模型一个Python执行环境让它随便写代码十个里有九个会在边界情况上翻车你给它接一堆乱七八糟的API它可能连哪个接口能买菜都分不清。所以业界逐步形成了Agent技能Skill这个概念也是agent-skills这类工具集出现的背景。技能层做的事情说简单也简单把模型可以调用的能力做成一整套有名字、有描述、有参数约束、有边界控制的标准化模块。模型不直接接触底层API和代码而是通过技能这个中间层来完成具体动作。这样既保住了模型的理解能力又把失控风险锁在可控范围内。技能体系和传统RPA、普通脚本调度有一个本质区别RPA是预先编排好的固定流程而Agent技能是由模型在对话中动态选择的。这意味着技能的门面描述和参数说明必须设计得足够好模型才能在合适的场景主动找到它。这个门面设计的功夫在实际项目里往往比技能内部实现更影响成败后面我会详细展开。1.2 agent-skills的核心注册表、调用协议、安全护栏回到agent-skills这个标题本身它如果要成为一个真正有用的工程化项目核心得解决四件事。第一是技能的注册与发现。Agent运行时有几十上百个技能不能靠一堆if else硬编码去判断该调谁。需要一套注册表机制让技能开发者声明我这个技能叫什么、干什么、什么时候该用然后由调度层根据模型的意图匹配最合适的技能。第二是统一的调用协议。所有技能无论内部实现是什么语言、什么框架对外都得遵循相同的入参、出参、错误码规范。这样模型侧只需要学会一套调用语法切换技能时不会产生认知负担。协议统一还有个好处可以集中做日志、限流、审计不用每个技能各搞一套。第三是安全护栏。技能能碰什么资源、不能碰什么资源必须由平台层面做白名单控制。比如一个发送邮件技能它只能发到企业内部域名且同一收件人一分钟最多一封。这些策略不能指望模型自觉遵守必须在技能执行层硬性卡住。第四是技能的组合编排。单个技能解决单点问题但真实任务往往要多个技能协作。比如帮我整理本周所有项目周报并提取风险项需要检索技能、读取文档技能、结构化输出技能协同。而agent-skills这类系统需要在技能之上提供编排能力让模型能按步骤调用多个技能并把上下文串联起来。这四件事做扎实了Agent才真正从聊天机器人进化为数字员工。很多人觉得技能开发就是写个函数加个注解那是把问题想浅了。真正的技能工程化要在一开始就把描述规范、参数校验、错误恢复、观测日志这几层全部考虑进去否则技能数量一多系统立刻变成一团乱麻。2. 技能开发的核心环节与设计要点2.1 技能描述怎么写模型才听得懂我开始做技能时踩过最大的坑就是写技能描述时太开发化总把描述写成给人类同事看的接口文档。结果模型经常在错误的场景下调用技能或者在正确场景下压根不调用。后来我慢慢摸到规律技能描述本质上写在给大模型看的提词它的核心目标是让模型在意图匹配阶段就建立清晰的触发条件。一个高质量技能描述至少要包含三层信息这个技能做什么、什么时候该用、什么时候不该用。光说获取天气信息远远不够要补充仅在用户询问当前天气或未来天气预报时使用不要将历史天气数据用于气候分析。模型对否定性条件的理解能力很强主动写清不要做什么能大幅减少误调用。另外技能名称也大有讲究。不要用内部代号要用自然语言中用户和模型都容易理解的名字。比如calc_engine_v3这种命名就要改叫数学计算器或calculator更直白。模型在意图匹配时对名称的语义非常敏感一个清晰的名字比什么配置都管用。下面是我常用的一张技能注册对照表能帮助你在设计阶段就自查描述质量项目反面示例正面示例说明技能名称data_proc_util销售额数据汇总助手名称要语义化避免缩写和版本号做什么处理数据按月份汇总各渠道销售额返回表格型结果说明输入输出形态何时触发用户需要数据时用户要求汇总统计近一段时间的销售额时明确触发场景何时禁用无用户要求预测未来销售趋势时不使用本技能主动划定边界我建议每个技能的描述控制在120到200个中文字符之间。太短说不清楚上下文太长模型在意图匹配时会分散注意力。如果确实需要大量说明把补充信息放到参数描述里而不是堆在技能主描述里。2.2 参数Schema设计的坑与对策参数Schema是整个技能系统里最容易偷懒、也最容易出问题的地方。模型调用技能时参数要靠LLM从对话里抽取填充如果Schema设计不合理模型就频繁传错类型、漏传必填项或者把含义相近的参数搞混。参数Schema设计有几条实务经验值得拿出来说第一参数数量宁少勿多。一个技能超过6个参数模型填参的错误率会明显上升。遇到复杂需求宁可拆成两个技能也不要把12个参数塞到一个技能里。比如创建报销单技能不要同时包含费用明细、审批人、预算科目、附件路径等全部字段可以把上传附件拆成独立技能用组合的方式完成完整流程。第二该用枚举的地方绝不用自由文本。模型对开放输入的把握能力不稳定但对枚举值的理解相当准确。比如费用类型直接列出餐饮、交通、住宿、办公用品、其他模型几乎不会选错如果放开让它填就会出现饭钱打车费买文具和枚举对不上的情况。第三参数与参数的依赖关系要显式声明。有些技能里B参数只在A参数等于某值时才有意义这种关系如果只写在文档里模型根本不会看正确做法是利用JSON Schema里的oneOf或allOf做条件约束让模型在结构上就无法生成非法组合。下面给一个参数Schema的示例这是我在实际开发中沉淀的较稳健的写法用来定义一个创建工单技能{ type: object, properties: { title: { type: string, minLength: 5, maxLength: 50, description: 工单标题需概括问题核心 }, priority: { type: string, enum: [P0, P1, P2, P3], description: 工单优先级P0为最高 }, category: { type: string, enum: [网络故障, 账号权限, 硬件报修, 软件使用, 其他], description: 问题分类 }, description: { type: string, maxLength: 2000, description: 问题详细描述包含时间、影响范围、复现步骤 }, contact: { type: string, description: 提交人联系方式工号或分机号 } }, required: [title, priority, category, contact], additionalProperties: false }minLength和maxLength不是摆设能有效过滤掉模型生成的空字符串和超长垃圾文本。additionalProperties: false要记得加上否则模型偶尔会自作主张多传字段导致服务端校验失败。参数里的description同样要按告诉模型该怎么填的标准来写而不是简单罗列字段含义。2.3 技能内部的稳定性闭环技能被模型调用只是开始执行过程中的稳定性才是真正决定用户体验的地方。我见过太多Agent项目模型意图理解都挺好结果技能一执行就超时、报错、返回格式混乱用户对Agent的信任瞬间崩塌。技能的稳定性通常要围绕四个维度做闭环。第一个是超时控制。Agent交互本身有实时性要求一个技能如果5秒内没返回对话就明显卡顿。技能代码里必须设置合理的超时阈值并设计降级策略。比如检索类技能超时后返回暂时无法访问知识库请稍后重试而不是让用户对着转圈界面干等。第二个是幂等性。技能被重试时要保证不产生重复副作用。以创建工单为例如果模型第一次调用超时后重试了两次系统就创建了三张一模一样的工单用户来投诉时你都没法解释。解决办法是在技能入口做去重根据对话上下文里的关键内容生成请求指纹相同指纹的请求直接返回已有结果。第三个是异常分类。技能报错时返回的错误码要尽量语义化因为Agent需要根据错误信息决定下一步动作。比如区分参数校验失败模型可以自己调整参数再试一次、外部服务不可用应该告诉用户过会再试、权限不足要提示用户联系管理员。如果所有错误都返回一个笼统的失败Agent的恢复能力就是一句空话。第四个是可观测性。每个技能调用都应该记录输入、输出、耗时、错误便于复盘模型是不是在正确的场景下做了正确的调用。这一步在当前Agent应用的Debug阶段尤其重要因为模型行为有随机性没有日志你根本没法定位问题出在意图理解还是技能实现。3. 实操过程从零开发一个周报汇总技能并接入Agent3.1 需求拆解先划清楚技能边界为了把前面讲的原理落到地上我完整走一遍开发周报汇总技能的过程。这个技能要完成的事情是用户丢进来几段零散的周报文字技能自动提炼出本周关键进展、风险与阻塞、下周计划三个板块并按统一模板输出。在写代码之前先做两件重要的事。第一是划定技能边界输入是纯文本的周报片段输出是结构化汇总不涉及写文件、不发送邮件、不查询其他系统。第二是设计参数参数越少越好这个概念我最终确定只暴露两个参数report_text必填待汇总的原始周报原文和tone可选可选值formal/concise控制汇总风格。这里有个容易被忽略的点为什么不把生成汇总直接用提示词让模型做而要包成技能因为周报汇总在真实业务里有固定格式约束和后续处理需求技能可以把模板校验、敏感信息过滤、格式规范化这些逻辑固化下来不依赖于每次对话的随机发挥。比如我们公司要求周报里的客户名称必须用脱敏后的代号这种规则就必须在技能代码里做硬处理不能指望模型每次记得。3.2 代码实现与注册接入技能代码用Python写框架上不依赖具体Agent平台核心逻辑就两部分技能函数本体和注册声明。# skill_weekly_report.py import re import json from typing import Literal def summarize_weekly_report( report_text: str, tone: Literal[formal, concise] formal ) - dict: 周报汇总技能核心函数。 使用规则 1. 仅在用户提供多段周报草稿并要求汇总、整理时调用 2. 不要将多段文字做简单拼接必须按照固定模板重新结构化 # 敏感信息过滤手机号脱敏后再进入后续处理 cleaned_text re.sub(r(?\d{3})\d{4}(?\d{4}), ****, report_text) # 这里在真实项目中会调用LLM做信息抽取和重组。 # 技能函数内部调用LLM时需要带上自己的结构化输出约束 # 要求模型严格输出如下字段 # - highlights: 本周关键进展 # - risks: 风险与阻塞 # - next_plan: 下周计划 extracted _call_internal_llm(cleaned_text, tone) # 输出格式必须固定方便Agent在后续对话中引用 return { summary: { highlights: extracted[highlights], risks: extracted[risks], next_plan: extracted[next_plan] }, source_length: len(cleaned_text), tone: tone } # 注册描述这部分是给模型看的重要性等同于函数实现 SKILL_DEFINITION { name: weekly_report_summarizer, description: 周报汇总与结构化整理技能。当用户提供零散的周报段落 要求提炼进展、风险或整理为规范周报时使用。 不适用于生成全新周报场景。, parameters: { type: object, properties: { report_text: { type: string, description: 用户提供的原始周报内容可包含多段、多个项目信息 }, tone: { type: string, enum: [formal, concise], description: 输出风格formal为完整句式concise为精简条目 } }, required: [report_text], additionalProperties: False } }真正的Agent平台接入时技能注册的过程就是把你写好的SKILL_DEFINITION传给注册中心再把函数挂到执行runtime上。注册中心会为技能分配一个唯一ID并同步到模型侧的tool列表里。做完注册之后模型才会在对话中感知到周报汇总技能的存在。3.3 联调测试与效果评估这是整个流程里最花时间的部分很多人以为技能写完就完事了实际联调才是决定质量的关卡。我一般会准备一套覆盖正常与异常路径的测试用例逐个检查模型是否按预期调度技能。测试场景输入示例期望行为关键检查点正常汇总两段周报草稿一段写已完成工作一段写遇到一个供应商延迟问题调用技能返回三板块结构化汇总风险项是否被正确识别边界禁止用户说帮我写一份下周的新品发布计划不调用周报汇总技能模型是否理解不适用边界缺参处理用户只说汇总周报但没给内容追问用户索要周报原文是否出现空参数调用风格参数用户说简短一点汇总调用技能并传toneconcise参数映射是否准确异常输入传入内容全是乱码技能返回规范错误不崩溃错误信息是否可理解联调期间要尤其关注模型的参数填充质量。我实测中发现模型对于枚举参数的把握力不错但只要参数描述里有歧义它就会按自己理解随意填。比如tone字段如果描述写成汇总语气模型就会传简短精简轻松等超出枚举范围的值。把描述改成可选值为formal完整正式句式或concise精简关键词列表当用户要求简短时使用concise准确率立刻上来了。另一个联调时容易忽略的是技能输出太大。周报汇总技能如果输入几千字模型输出结构化摘要时token消耗很厉害。要在大模型返回前做好截断否则Agent上下文很快被撑爆后续对话质量直线下降。我在技能函数里对highlights、risks、next_plan各限定了最多10条超出部分合并为其他事项这样既保持信息完整又控制上下文占用。4. 常见问题与排查技巧实录4.1 Agent不调用技能或者老调错技能遇到这种情况先别怀疑模型能力九成是技能门面出了问题。排查时我会按顺序做三件事第一检查技能描述里是否写清了触发条件和禁用条件。描述写的过于宽泛模型就会犹豫要不要调用描述太具体模型在其他相关场景又识别不出来。理想状态是让技能描述和业务里用户最常说的那几句话对齐。比如用户习惯说把这几段话理一理那描述里就应该包含整理理一理规范化这类口语触发词而不是只写汇总这种书面词。第二检查技能名称是否和平台内已有技能冲突或产生歧义。一个经典案例系统里同时有发送邮件和邮件草稿助手两个技能模型很容易混淆。遇到这种情况要合并技能或在描述中明确分工比如邮件草稿助手用于创建邮件内容发送邮件用于最终投递后者依赖前者生成的草稿ID。把技能间的关系讲清楚误调用会大幅减少。第三检查是不是上下文里信息不充分。模型无法从对话里提取技能所需的必填参数时会倾向于不调用技能。比如用户只说帮我汇总一下但没有给任何素材模型不知道拿什么填report_text。这时候技能侧可以做善意引导把参数改成可选技能内部用提示词反问用户补充素材而不是让模型直接放弃调用。4.2 参数频繁传错有必要上参数校验三连参数层面的问题我的经验是做三层校验缺一不可。第一层是Schema硬校验用前面提到的enum、minLength、additionalProperties: false挡掉那些明显的类型错误。第二层是语义校验在技能函数入口写一些检查逻辑比如report_text长度少于10个字就判定输入无效因为真正的周报不可能这么短。第三层是修正引导校验不通过时返回给模型的信息必须是正确填法示例而不只是参数错误这几个字。举个例子实际测试中模型曾经把contact字段要求填工号填成了用户的手机号。单纯报错只会让模型下一次继续猜。后来我在错误信息里加了正则要求工号为5位数字您填写的值不匹配请询问用户工号后重试模型就能准确引导用户补齐信息。说白了给模型的错误反馈要像给实习生反馈一样具体、可执行。4.3 技能执行太慢拖垮了整个对话Agent场景下用户可没有耐心等一个技能跑10秒。技能耗时长主要两个原因一是内部调用外部服务没做超时二是返回数据量过大序列化传输开销高。处理手段上第一优先级是缓存。我们项目里知识检索类技能结果缓存了15分钟完全不影响使用体验却把平均响应时间从4秒压到不足1秒。第二优先级是异步化。耗时不敏感的技能可以走异步通道先给用户一句话正在处理约需要20秒处理完成后主动推送结果很多内部工具型Agent都适合这种交互。第三是做好输出裁剪返给模型的只保留最精炼信息冗余字段一律在技能内部消化掉。4.4 技能权限边界安全底线不能省技能开发里还有一个经常被低估的环节就是权限控制。绝对不能所有技能一个权限级别必须做到最小权限原则。我见过一个项目因为文档管理技能权限过大模型被诱导读取了不该访问的目录教训很深刻。安全实践上技能平台层要做三层隔离身份隔离技能调用者是谁、资源隔离技能能访问哪些服务、动作隔离技能能执行哪些操作写操作是否需要二次确认。像发送邮件删除文件转账这类高风险动作应该在技能描述里显式声明执行前必须与用户确认并在技能实现里强制做二次确认逻辑不能只依赖模型自觉。这个习惯趁早养成比出事之后补救靠谱得多。关于技能的迭代我体验最深的一点是不要追求一次性把技能设计得完美技能这种东西天生就是要跟模型、跟用户一起打磨的。上线后盯着日志里的调用成功率、误调用率、参数错误率每周迭代一次描述和校验逻辑比憋大招管用得多。等你把一套技能的门面打磨到位会发现Agent的整体表现比换更大参数的模型提升得还明显——很多团队总是迷信模型选型却忽略了下半场的技能工程质量这才是Agent落地真正的分水岭。