资讯动态

Agent技能系统设计:从Prompt失控到300+技能的可装配架构

发布时间:2026/10/14 10:18:26 来源:尧图企业网站定制
去年年底我们团队开始做 Agent 方向的研究一开始用的还是最朴素的“一个大 Prompt 包一切”的套路把角色设定、工具说明、任务目标、输出格式全部塞进上下文里。前几个 Demo 跑得挺顺可一旦任务从“查一下天气”变成“跨系统完成一个供应链对账流程”Prompt 就膨胀到失控了——改一个工具的说明会影响所有对话调一次输出格式要重新测一周工具一多模型连“什么时候该用哪个工具”都开始犯迷糊。也就是在那时候我们决定做一套独立的技能系统项目代号就叫 agent-skills。核心思路很简单不把能力塞进 Prompt而是把 Agent 能做的事拆成一个个独立、可注册、可编排、可版本化的“技能单元”让模型通过一套统一的协议去发现、调用、组合它们。这套系统跑了大半年从最初 20 多个技能增长到现在的 300 多个支撑了内部几个自动化项目稳定运行。这篇就聊聊我们是怎么设计、踩坑和迭代这套系统的适合正在做 Agent 工具层/技能层设计、或者被“工具一多就乱”困扰的团队参考。1. 为什么要单独做技能系统从“全知型 Agent”退回到“可装配的 Agent”先说说我们最初遇到的问题。当时团队内部有两条产品线一个做表格类数据的自动整理一个做内部审批流的自动化操作。两条线都让大模型调用工具但各自的 Prompt 里写满了“你可以使用以下工具xxx参数为 yyy”之类的说明。用户多问几个场景Prompt 就得加长几百行过后模型开始把 A 工具的参数填到 B 工具里。1.1 “全能 Agent”的三大瓶颈第一个瓶颈是上下文污染。工具说明和业务提示词混在同一个上下文窗口里模型面对无关工具时会出现“强行调用”的倾向。比如处理一份 Excel 时它非要去调一下并不需要的邮件发送接口。第二个瓶颈是变更成本。某个内部系统升级了接口我们得去翻遍所有用到该工具的 Prompt逐一修改措辞否则模型就按过时的参数格式去调用。第三个瓶颈是复用困难。A 项目里写好的一个“PDF 转图片”的处理流程搬到 B 项目时只能靠复制粘贴然后两边各自维护后面常常出现 B 项目用的是旧版逻辑的情况。1.2 技能与工具、工作流、记忆的边界划分很多团队混淆了“工具”和“技能”的区别。我们的定义是这样的概念定义例子工具单次可执行的外部能力HTTP 请求、读本地文件、调某个 API技能围绕一个目标组织的可复用能力可能由多个工具或多个子步骤构成“根据发票 PDF 生成会计凭证”工作流技能的编排组合通常面向完整业务流程“月初自动对账 → 差异上报 → 凭证归档”记忆Agent 跨会话保留的偏好、事实、执行经验用户习惯用竖版 PDF、上次执行失败码 504也就是说工具是原子的技能是半成品工作流是成品。agent-skills 项目要管理的不是工具函数而是“技能”——它封装了某个能力的目标、适用条件、执行步骤、输入输出规范和失败处理策略。模型调用技能时不需要知道底层调了几个工具只需要按照技能描述传参数、拿结果。这让我们可以把“怎么做这件事”的细节从 Prompt 里彻底剥离出来放进技能代码里。提示如果团队还在“Prompt 里写工具说明”阶段先不要急着上技能系统。我们是在单条 Prompt 超过 800 行的项目里被逼着做的早期确实只要十几个函数就能满足需求。技能系统是一套有成本的架构适合工具数量超过 30 个、或者一个工具被多个项目复用的情况。2. 技能模型的核心协议注册、发现、调用三层架构技能系统跑起来的前提是先定义一套统一的协议。我们参考了现有开源项目里“技能包”的设计思路但做了不少调整。整个协议分三层注册层、发现层、调用层。2.1 技能描述文件SKILL.md 加参数 Schema每个技能被封装成一个目录目录下至少包含两个文件人类可读的技能说明和机器可读的参数 Schema。技能说明是一个轻量的文本文件里面规定字段包括技能名称、目标、适用条件、图标我们后来加了这个多技能列表展示时可以快速定位、示例查询、版本号。这个文件不是给模型看的——确切地说不是直接塞进 Prompt 里的而是给技能注册中心做索引的。机器可读的部分用 JSON Schema 描述包括输入参数、输出格式、错误码定义。比如一个“读取发票表格数据”的技能参数 Schema 里会有“文件地址”“页码”“是否启用 OCR”这几个字段。每个字段都需要写清楚类型、默认值、边界约束和示例值。这段描述完整定义了这个技能“可以被如何调用”是发现层给模型生成调用结构体的依据。整套文件结构是这样的skills/ invoice-extract/ SKILL.md schema.json run.py history.mdhistory.md 是技能运行的历史记录每条记录包含调用参数、结果摘要、执行耗时、失败类型由系统自动追加。这个文件后续在做技能迭代时非常有用后面会讲。2.2 技能调用链路由规则与限流当模型决定使用某个技能时请求并不会直接落到技能代码里而是先经过一个调用链输入校验 → 路由 → 鉴权 → 限流 → 执行 → 反馈。这套流程我们用了一个独立的网关模块来实现。输入校验由 JSON Schema 的校验器完成不合法的参数直接拒绝这一步非常关键——早期没有它模型传错参数时技能代码里报的异常千奇百怪排错效率极低。路由规则方面我们给技能打上了“域”的标签比如“表格处理域”“邮件域”“审批域”。网关根据技能的域、执行耗时、当前负载决定把它调度到本地进程还是另一台执行机上。鉴权和限流统一走内部的一套令牌机制不同项目调用同一个技能时申请不同的令牌方便事后审计每个项目的调用量。2.3 技能版本与灰度发布技能代码也是会改的。我们给每次技能变更都加了版本号描述文件里的 version 字段从 v1 递增到当前值。模型调用时默认走最新版本但上游项目可以指定“用 v1 还是 v2”。这样当我们对某个技能做了破坏性重构时比如改了返回字段的命名方式老项目不会被无预警地打断。灰度发布是我们后期才加上的。每次技能大版本更新先让 10% 的调用流量打到新版本观察成功率、耗时、报错类型三个指标。如果新版本的表现稳定在一个阈值之上才逐步放开到全量。整个灰度过程都是配置驱动的不写额外代码。注意版本号千万不能只改不改记录。我们的做法是每个技能的变更历史自动追加到 history.md 里后面排查某个功能“从什么时候开始行为变了”时直接翻版本变更记录不用去 git 里逐条 diff。3. 技能编排当原子技能组合成复杂流程时说实话一开始我们觉得技能系统能做到“模型发现技能、正确调用技能”就够了。但真正和业务方联调以后发现单技能的调用远不能满足需求。比如“每月对账”这个动作内部实际需要拉取账单 → 清洗明细 → 匹配两边的订单 → 生成差异清单 → 发送通知。如果这五个步骤每次都由模型自己临场决定怎么串结果不稳定——有时先发通知再生成清单有时匹配完不清洗直接产出结果。所以我们在技能系统之上加了一层编排规则让部分高频流程以声明式的方式固化下来模型只需要负责在入口处选对流程。3.1 四类编排原语顺序、条件、并行、回退我们最终抽出了四个最常用的编排原语顺序执行步骤严格按定义顺序跑上一步通过才能进入下一步。条件分支根据上一步的结果决定走哪条分支。并行执行几个互相独立的技能同时触发适合批量处理场景。回退节点当某一步失败时不是立即终止整个流程而是回到特定节点用替代技能重新尝试。这套原语用一份简单的 YAML 配置表达workflow: monthly_reconcile version: 1.3 steps: - id: fetch_bills skill: bills.fetch next: clean_rows - id: clean_rows skill: data.clean params: rules: [drop_duplicates, fill_null] next: match_orders - id: match_orders skill: match.two_sources next: diff_report - id: diff_report skill: report.generate next: notify - id: notify skill: message.send on_failure: fallback_to: fetch_bills max_retries: 2早期我犯过一个错误就是试图在这个文件里塞“思考逻辑”——比如让流程根据匹配率的阈值动态决定要不要人工复核。这种能力其实依赖外部判断条件不应该内嵌在编排配置里。我们最后的处理方式是在流程里增加一个“条件判断节点”它内部挂一个小的表达式片段由表达式的返回结果决定下一步分支。3.2 为什么要用声明式配置而不是让模型自己写工作流有段时间我们尝试让模型每次执行时动态生成工作流也就是“模型自己画流程图”。结果不尽如人意。模型生成的流程代码偶尔很惊艳但大部分时候不稳定且极难调试。尤其是当一个流程跑失败时你根本分不清是技能本身报错还是模型生成的流程编排有误。所以我个人的建议是高频流程用声明式配置固化低频个性化流程才让模型自由编排。把编排行为分层既能保证核心业务链路稳定又保留了开放性。agent-skills 里我们做了一个“流程模板库”业务方可以挑选模板也可以自定义自由流程但自由流程默认不进生产环境只能小范围试用。3.3 一次多技能协作的真实执行过程用一个实际例子说明编排引擎的工作方式。某天上游系统推送了一批新供应商的资质文件到网盘目录Agent 接手后先调用“目录监听”技能发现新文件再调用“文档解析”技能抽取资质类型和有效期接着调用“匹配供应商数据库”技能找到对应主体最后调用“更新资质记录”技能把结果写回业务系统。在这个过程里Agent 的角色是流程入口的选择者——它根据“文件放在哪个目录、命名是否符合规则”这些上下文决定启动哪条流程。而流程内部每一步具体调用哪个技能、传什么参数由编排引擎按照配置执行。这样模型的推理负担被大大降低了它只需要做好“判断该走哪条路”而不是“每一步怎么走”。这种分工让我们系统里的 Agent 稳定性明显提升尤其处理批量文件时不会出现中途改变执行策略的情况。4. 技能与记忆联动Agent 越用越顺的秘密真正把 agent-skills 从“工具管理框架”变成“技能进化系统”的是记忆模块的接入。技能本身是静态代码运行多了如果没有反馈机制它就只能靠我们人肉去发现“这个技能最近失败率高了”。我们希望技能能根据执行历史和用户反馈自动优化——这里的优化不是改代码而是调整技能的描述、触发条件、参数默认值。4.1 技能执行反馈通道每次技能执行完毕后执行结果会留三条记录执行是否成功、异常类型、结果摘要。网关还会额外记录“模型用了多少轮才选定这个技能”这一项是当初团队一个同学坚持加的后来成了判断“技能是否容易被发现”的重要指标。如果某个技能在连续几次执行中模型都需要绕好几个弯才选中它说明它的描述不够清晰或者触发条件有歧义。我们针对这种情况开发了一个“描述优化建议”功能它会对比技能的目标描述和用户的实际提问计算向量相似度分布当相似度长期偏低时自动在后台给研发打出提示。4.2 自动微调技能的标准不能乱改但自动迭代不能乱来。我们设了三条硬边界不自动改代码逻辑。自动流程只能建议修改描述文件和 Schema核心执行代码必须人工 review。必须有成功样例支撑。任何描述调整至少得有 20 条成功执行记录否则可能是调用方瞎传参数不是描述本身的问题。每次微调要生成对比报告。把调整前后各 100 条调用的成功率、平均对话轮数放一起比数据不倒退才允许上线。这三条边界让我们避免了早期那种“模型觉得这样描述更好结果一改所有人找不到技能”的翻车事故。4.3 两层记忆结构短期执行上下文与长期技能画像我们最终把记忆拆成了两层。第一层是短期执行上下文存的是当次任务里临时出现的信息比如这个用户这批文件的特殊命名规则。它只活在当前会话里不会沉淀到技能层。第二层是长期技能画像存的是“这个技能面向哪些常见输入表现更好”的经验信息。比如一个识别发票的技能画像里会记录“对多页扫描件启用 OCR 后准确率高 12%”这类规律。长期技能画像的更新逻辑是这样的系统每 500 次执行做一个聚合分析找到“某一类输入条件下成功率显著偏高/偏低”的特征组合再把这些特征组合写回技能描述的适用条件部分。这样下次模型决定是否调用这个技能时能看到“如果你手里的文件是多页扫描件建议优先选择启用 OCR 参数”这样非常具体的提示。这个设计让技能不是越用越“僵”而是越用越“懂行”。5. 技能调试与可观测性Agent 黑盒里的“行车记录仪”Agent 应用最让人头疼的是排错。普通程序出 bug你打断点看堆栈就行Agent 出问题可能是 Prompt 理解偏差、技能选错、参数填错、编排规则有 bug、外部接口返回异常……五个环节里任何一环出问题表象都是“功能不对”。没有良好的可观测性排查就像在没有监控的系统里找故障点只能靠猜。所以 agent-skills 从早期就把“执行轨迹录制”当成核心功能来开发。5.1 技能执行轨迹录制与回放我们把一次完整的 Agent 任务执行录制成一条轨迹轨迹里包含四类数据模型在每一步的推理摘要、发起的函数调用请求包含参数和返回、编排引擎的决策记录、底层的日志输出。录制好的轨迹可以在一个界面里逐帧回放就像看行车记录仪一样能看到“模型当时为什么选择了这个技能”“参数被填成了什么”“编排引擎做了什么判断”。这个功能救了我们无数次。有次一个“生成销售周报”的技能持续输出超长表格导致后续步骤全部超时。我们在轨迹里发现模型看到了技能描述里的“输出格式支持 Markdown 表格”于是给了一个铺满 50 行的表格参数。后来我们把描述里的示例改成“输出 5 行以内摘要表格”问题就消失了。5.2 技能沙箱代码执行类技能的安全边界agent-skills 里有一部分技能是会执行代码的比如“跑一段 Python 脚本处理 CSV”。这类技能必须做沙箱隔离这个没有商量余地。我们的沙箱做了三层限制网络隔离、文件系统限制、资源配额。网络层面沙箱内的脚本默认只能访问白名单内网地址不能出公网。文件系统层面脚本只能读写自身工作目录目录外的文件一律不可见。资源配额方面单脚本最大 CPU 时间、内存上限、临时文件大小全部有硬限制。这些限制不是写在文档里让大家自觉遵守的而是直接由运行侧强制执行的越权行为会直接返回“‘技能’越权访问”的特定错误码。提示如果团队刚起步还没有完整的沙箱能力至少也要做到“对技能代码做静态扫描动态执行隔离”。千万别把本地文件系统的读写权限直接开放给 Agent尤其是它会根据模型自由生成的脚本出过事故的都懂。5.3 三个最常见的故障模式与排查套路在长达半年的运行中我总结出 Agent 技能侧最常出现的三类问题第一类是技能描述与 Schema 不一致。描述里写“支持上传多个文件”Schema 却只定义了一个 file_path 字段模型按描述理解去调用必然出错。这种问题的排查要看轨迹里模型生成的调用参数和校验器报错信息。第二类是外部服务返回数据结构漂移。技能代码本身没变但下游接口悄悄改了一个嵌套字段的层级解析全乱。这种情况要在技能代码里增加结构校验并且在轨迹里对比“输入结构”“输出结构”“预期结构”三个快照一眼就能定位。第三类是编排引擎的回退死循环。我们早期在配置里允许某步骤失败后回退到上一步重试但没限制回退次数。当外部接口持续故障时流程就在两个节点间反复横跳直到资源耗尽。后来我们增加了两个约束回退只能发生一次并且回退后的执行必须转人工确认。故障现象可能根因排查建议模型总选错技能描述关键词与用户提问差异大看技能相似度分布重写描述6. 落地过程中踩过的几个大坑都是真金白银换来的给想直接复刻这套思路的朋友几条避坑经验。每个坑我们都至少在线上环境疼过一次有的还疼了不止一次。6.1 技能命名的“口语化”陷阱早期我们为了省事给技能取名特别随意比如“读 PDF”“发邮件”“算个税”。结果模型在遇到复杂任务时经常把“读 PDF”误当成“从 PDF 里提取结构化数据”来用参数里连提取规则都想让模型自己编。后来我们强制所有技能命名采用“动词 对象 目的”的格式例如“read_pdf_to_records”。并且给每个技能增加了 aliases 字段把同义说法也挂上去。虽然描述文件多了一行配置但模型调用的精确度明显提升。6.2 Schema 校验太宽松导致“技能空转”我们曾有一个“数据匹配”技能Schema 里对两个输入表的字段名称没有任何约束只要求是字符串。结果模型经常传入两个实际结构不一致的数据表技能返回的结果看似“匹配了”实际上匹配率低得离谱下游环节拿到数据全是脏数。后来我们改变了 Schema 设计原则凡是技能代码里会硬编码依赖的字段Schema 里就必须声明 required并用枚举或 pattern 约束字段名。宁可模型调用时多被告知一次“参数不符合条件”也不能放行让它用错误数据一路跑下去。6.3 技能数量增长到 300 个之后的系统和性能问题技能个数从 20 涨到 80 时一切尚可但突破 200 个以后出现了几个新问题。一是模型在技能列表里做选择的时间明显变长推理成本上升二是相似技能之间的“辨识度”下降比如有“识别增值税发票”和“识别出租车发票”两个技能模型有时会混淆。我们的对策是引入了“技能分组召回”机制在编排层和调用层之间加一个分类器先根据任务入口判断可能涉及的技能域只把该域内的技能列表交给模型选择。从全部 300 多个技能中先筛到 20 个以内再推理效果非常明显。不过这个分类器不是万能的。如果用户任务特别跨界比如“读一张图片里的表格并发送到群里”分类器可能把域定位在“图像处理”而不是“消息发送”导致模型看不到发送技能。后来我们在分组召回时允许跨域召回 top-2 相关域基本就覆盖了这类跨界需求。6.4 不要把“技能描述”写成小论文写 SKILL.md 时最容易犯的毛病是“想表达得尽善尽美”。我们早期有个技能描述写了 300 多行包含背景、动机、完整流程、历史教训结果模型反而抓不住焦点。后来我们学到的经验是技能描述只写“这个技能在什么情况下适用、接受什么输入、产出什么结果、有什么限制”最多 40 行。细节留给 Schema 和执行代码描述文件的价值是帮模型做“要不要用”的判断不是教模型“怎么用”。7. 从 agent-skills 里沉淀下来的一些个人体会如果非要用一句话总结这个项目带给我的最大认知那就是Agent 系统里最不应该动的部分恰恰是你最想让“智能”去代替的部分。技能设计看似是“把一件事写清楚”其实是在定义智能体的能力边界和行为契约。描述文件就是契约文本Schema 就是契约细则编排规则就是履约流程。把这三样东西设计稳了Agent 的稳定性自然就高了。另一个很深的体会是技能的进化不能靠“模型自我感觉良好”得靠结构化的反馈。我们所有技能描述和参数 Schema 的优化都来自轨迹数据和聚合统计极少来自某人“我觉得这样改更好”。数据驱动的思路也减少了团队内部的争论——大家面对的不是“谁说得对”而是“哪组数据更支持哪个方案”。最后分享一个实用技巧给每个技能目录里放一个“运行样本”文件夹里面放 5 到 10 组典型输入和对应输出。这个文件夹在调试、回归测试、新人上手时都是救命的。很多问题不用看代码跑一下样本立刻就知道技能逻辑有没有被改坏。而且当你想重新整理技能描述时样本能帮你快速回忆起这个技能最初要解决的问题是什么。动手干吧迭代一套属于自己的 agent-skills这个方向确实值得投入。

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

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

免费获取报价 →
↑