ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从会聊天到能干活:Agent技能库搭建全实践

从会聊天到能干活:Agent技能库搭建全实践 最近一直在折腾同一个问题为什么同一个大模型聊天的时候像个人放进业务系统就各种干不了活。不是模型不聪明是它没有“干活的手”。后来我试着把能力拆开一个个打包成独立的“技能”Skill才真正把智能体从一个会说话的模型变成能稳定交付任务的系统。这个思路圈子里的说法叫 agent-skills也就是把智能体需要的能力、上下文、脚本模板、评估方法都沉淀成一套工程资产。这篇文章想把这几个月搭建、调试、落地技能库的完整过程写下来给正在做 Agent 应用、尤其是被“模型不稳定、场景太散、迭代太慢”折磨的工程团队做个参考。1. 技能库到底是什么从“会聊天”到“能干活”的能力封装1.1 别再往系统提示词里堆需求了我第一次给 Agent 加能力的时候跟大多数人的做法一样在系统提示词里写“你是一个擅长文档处理的助手”然后把各种要求一条条列进去。结果并不意外——场景少的时候还凑合场景一多模型就开始顾此失彼。你今天让它生成日报明天让它解析合同提示词越来越长模型逐渐分不清边界甚至开始把文档解析的规则套用到日报生成上。这里有个很容易忽略的问题大模型的上下文窗口有限提示词越长实际任务的注意力占比就越低。把十几个场景的操作流程塞进一个提示词里相当于让一个人同时记住十本岗位手册再上岗出错是必然的。技能库的思路完全不同每个场景的能力单独成一个文件夹有描述、有脚本、有示例、有测试。模型每次只“加载”当前需要的那个技能而不是把全部业务规则背在身上。1.2 技能、工具、提示词三者到底差在哪很多人会问我有 Function Calling 了为什么还要技能这是个好问题。工具Tool解决的是“模型能调用外部函数”的通信问题它暴露的是函数签名和参数 Schema而技能解决的是“模型知道在什么场景该做什么事”的决策问题。一个工具是粒子的一次调用只做一件事一个技能是分子的它可以组合多个工具、固定流程、内置经验模板。对比维度Function Calling / ToolAgent Skill最小单位一次 API 调用一个完整场景能力包含内容函数名与参数 Schema描述 脚本 示例 评估用例触发方式模型按需发起调用模型按场景识别并加载可复用粒度小偏向原子操作大偏向解决方案调试成本低改单个函数中涉及描述与流程联动至于提示词它是技能的“内力”部分但一个正经技能库里通常不会只放一段提示词。它还会带上执行逻辑、数据模板、校验规则。换句话说提示词告诉模型“怎么想”技能告诉系统“怎么做完一件事”。把这两层拆开再合到一起才是技能库的正确用法。1.3 一个典型技能库里到底装了什么我现在维护的技能库每个技能固定由四部分组成说明文件、脚本目录、资产目录、测试目录。说明文件描述这个技能的职责边界、触发条件和使用示例脚本目录负责真正跑活资产目录放模板、样本数据测试目录存评估用例。这四样东西合起来才是一个可以被复用的“技能”。举个例子团队里有个写周报的技能。说明文件里只写“根据本周提交记录与项目进度生成周报”脚本目录里有一个收集 Git 提交记录的小程序、一个汇总进度的读接口资产里放着一份周报模板测试目录里有三种风格偏好的样本输入。模型负责根据用户说法决定要不要用这个技能真正干活的是脚本模板用来保证输出格式稳定。这样做的好处很直接换模型品牌、换提示词策略只要脚本和模板不动技能基本还能跑。2. 动手搭建技能库目录结构、说明文件与执行脚本2.1 目录与命名规则让模型一眼看懂边界目录和组织方式看起来不起眼实际直接影响模型能否正确命中技能。我见过不少半路夭折的技能库问题就出在目录混乱、命名含义模糊。比如有一个技能叫 “email_handle”它到底是写邮件、归档邮件还是自动回复模型在几十个技能里选中它的时候其实也很犹豫。我目前的目录规范是按“动词对象”命名全部小写加下划线比如generate_weekly_report、extract_invoice_data、summarize_meeting_notes。每个技能一个一级子目录目录内部不允许出现多层嵌套的复杂结构最多三层说明文件、脚本文件夹、资产文件夹。这样既方便人去维护也方便程序批量扫描更重要的是模型能从目录名上直接理解技能性质减少误触发。分支管理上我建议每个技能独立成一个可维护的单元在仓库里用skills/作为根目录统一收口。每个技能在提交前至少要能通过python -m pytest skills/xxx/tests的本地测试不能跑通的一律不进主线。skills/ generate_weekly_report/ SKILL.md scripts/ collect_git_log.py merge_project_progress.py assets/ templates/ weekly_report_template.md tests/ test_weekly_report.py extract_invoice_data/ SKILL.md scripts/ parse_pdf_invoice.py assets/ samples/ invoice_sample.pdf tests/ test_invoice_extract.py2.2 SKILL.md 的写法描述、触发条件与示例最重要技能说明文件是整个技能库的“心智入口”也是模型判断“该不该用这个技能”的依据。我在迭代中总结出一个说法说明文件写得越好技能被正确触发的概率越高说明文件稀里糊涂后面脚本写得再漂亮也没人调用。一份能用的 SKILL.md 至少要包含五个字段技能名称、一句话职责描述、触发信号、输入输出格式、典型使用示例。其中“触发信号”这块容易被忽略实际价值很高。比如generate_weekly_report的触发信号可以写成“包含本周、周报、工作汇总、周五下班前等信号”模型看到这些词组合时会有更大的概率选中这个技能而不是裸答。典型示例的效果最直接。模型在推理时会参考示例的类比示例写得好相当于给了模型一个“标准动作回放”。我的做法是每个技能至少写两条示例一条是标准场景一条是边界场景。边界场景明确写“当用户只说‘给我整个材料’但未指定材料类型时不要直接套用本技能”这比在描述里写一百遍“注意上下文”都管用。--- name: generate_weekly_report description: 根据本周 Git 提交记录与项目进度数据生成结构化周报适合研发团队每周五输出。 triggers: - 本周/周报/工作汇总 - 输出周报 - 周五工作小结 inputs: scope: string, 可填 all 或具体仓库名不填默认全仓库 style: string, 可选 concise / detailed默认 detailed --- # generate_weekly_report ## 行为说明 1. 读取本周提交数据按仓库分组统计 2. 合并项目进度接口数据 3. 按 assets/templates 下模板格式输出 Markdown 周报。 ## 使用示例 用户帮我把这周的活汇总成周报 助手调用 generate_weekly_reportscope 留空style 默认2.3 技能脚本纯 Python 够用就别急着上框架技能里的脚本部分职责越简单越好。我的原则是能用一个纯函数解决的绝不引入框架能用标准库的绝不引入第三方依赖。这听起来保守但技能库最怕的是“重依赖”。你想象一下一个技能依赖了某个版本的 requests另一个技能又依赖旧版 pandas环境一冲突整个 Agent 就废了。我最近重构了一个数据清洗技能原来是用一个有状态的框架类写的跑起来还要先启动一个服务进程。后来改成纯 Python 脚本入口函数接收输入参数输出标准结构化结果测试和维护都简单了一大截。技能脚本应该遵守“无状态、可重入、参数驱动”三条原则。无状态指技能不保存历史聊天状态可重入指同一个输入可以重复执行且结果稳定参数驱动指所有变化部分通过参数传入不写死在脚本里。脚本的入口我统一约定成run(input) - output内部自己处理异常返回时带一个status字段要么success要么needs_human。这样模型拿到结果后能明确判断下一步是继续处理还是找人介入而不是对着一段报错发呆。import json def run(input_data: dict) - dict: try: scope input_data.get(scope, all) style input_data.get(style, detailed) # 这里做实际的提交记录统计与进度合并 result collect_and_merge(scope, style) return {status: success, data: result} except Exception as exc: return {status: needs_human, message: str(exc)}2.4 模板资产的取舍既要稳定又要留出自由度技能库里的模板资产是新手最容易过度设计的地方。常见做法是恨不得把每一种输出格式做成一个模板最后模板比业务代码还多。我的经验是模板只锁“骨架”不锁“血肉”。所谓骨架就是标题层级、必填字段、输出顺序血肉是具体措辞、详细描述这部分让模型自由发挥。这样既保证了多轮输出的稳定性又不会让结果千篇一律得像机器人写的。周报表模板里我只固定了“工作概述 / 关键进展 / 风险与阻塞 / 下週计划”这四个区块以及“每个区块必须有数据支撑”的约束。至于每一条进展怎么描述不限定。实测下来不同风格偏好的队员拿到的周报是“同骨架、不同气质”的既稳定又不失个人化满意度反而比之前固定模板高很多。3. 技能设计的五个关键决策把模块边界敲定3.1 技能粒度一个技能该管多大范围的活技能粒度是设计阶段最头疼的决策。太粗一个技能里塞了十几个分支模型学不清楚太细十几个技能互相交叉模型又选不过来。我现在的分寸是一个技能负责“一类有明确交付物的工作”。什么叫有明确交付物周报技能交付一份周报账单解析技能交付一批结构化字段。凡是交付物不清晰的都不该单独成技能。举个例子我之前想把“文档操作”做成一个大技能包括读取、格式化、转换、总结、翻译。结果测试集里触发准确率只有六成左右因为模型很难判断“帮我改个错别字”到底属于格式化还是转换。拆掉之后每个子能力独立成技能准确率直接拉到了九成以上。粒度判断有个土办法如果一个技能描述里需要用到“并且”和“或者”去解释职责大概率是太粗了先拆。3.2 技能之间的依赖能合并就别搞调用链技能之间最理想的关系是“互不认识”。每个技能都能独立完成自己的交付物不调用别的技能也不共享可变状态。但实际业务里总有依赖比如“写周报”需要依赖“收集 Git 提交记录”。我的处理方式是把这种依赖做进脚本内部而不是在技能层做调用链。换句话说generate_weekly_report内部直接调用collect_git_log()这个函数而不是让模型先调用另一个技能再拿结果喂进来。为什么这么设计因为技能层调用链一旦变长出错概率指数级上升。模型在中间环节可能漏传参数、可能记录错变量甚至可能自我发挥改步骤。把稳定的依赖关系沉淀到代码里让模型只负责“决定做什么”不负责“记住怎么做”。如果需要跨技能的数据宁可写进同一个脚本里做函数复用也别搞成微服务式链式调用。3.3 上下文传递哪些该写死哪些该运行时注入技能描述里能写死的信息绝不留给模型临场发挥。很多技能失败案例都是因为把关键参数交给了模型“自由联想”。比如解析发票时需要的税率表、折扣规则这类业务常量要么写进脚本的默认配置要么由技能入口从外部系统拉取绝不能在提示词里让模型猜。运行时需要用户提供的东西也必须在 SKILL.md 的 inputs 声明里写清楚。我的约定是inputs 里的字段名做到和脚本参数名完全一致避免模型传错 key。字段默认值也要有兜底比如 scope 默认 allstyle 默认 detailed模型不传也不会崩。上下文注入遵循“不该给的别给”原则技能能看到的数据只包括完成任务所需的字段别把整个对话历史都倒进脚本里一来没必要二来容易泄露无关信息。3.4 失败反馈让技能知道自己什么时候该停下技能脚本必须学会“承认失败”。我见过太多技能失败后还硬着头皮返回一堆残缺结果模型拿到残缺结果又继续加工最后生成一份看似完整实则错误百出的答案。技能设计阶段就要定义清楚哪些情况算不可修复应该返回needs_human。比如周报技能的提交记录收集环节如果某个仓库网络不通脚本会重试两次两次仍失败直接标记该仓库失败而不是用一个空数组糊弄过去。输出里带上errors字段告诉模型“哪些数据缺失、为什么缺失、是否需要人工介入”。模型看到这个字段后要么向用户如实说明要么主动询问是否重试不会再傻乎乎往下编。这一步对最终交付质量的提升比优化任何提示词都明显。3.5 版本管理技能也要有兼容性策略技能和普通代码一样会演进。我踩过一个教训为了让周报技能支持新格式直接在原脚本里改结果旧的调用方全部出错。后来我规定任何技能的对外输入输出格式变化都必须走版本升级不能在原版本里原地修改。技能目录名带上主版本号是一种方式比如generate_weekly_report/v2或者通过配置声明字段记录版本。版本演进的兼容性策略我的底线是“输出只增字段不删字段”。旧字段继续返回新字段可以加这样依赖旧输出的调用方不会立刻爆掉。主版本升级时SKILL.md 里必须写清“本版本与上一版本的行为差异”模型也能据此调整触发策略。版本管理做不好技能库运行时间一长就会变成垃圾场没人知道哪个技能还能用。4. 调试与评估技能不生效时我在追查什么问题4.1 技能没被触发先查描述再查示例最后查覆盖技能库上线后最经典的问题是明明技能存在模型就是不用它。第一次遇到这种情况我花了三天排查把配置文件翻来覆去看了好几遍最后发现是 SKILL.md 里的描述写得太“口语化”模型无法把用户的实际说法和技能描述关联起来。排查链路应该是这样的第一检查描述里是否包含用户真实会说的词否则就加触发信号第二检查示例是否覆盖了常见说法变体用户说“帮我汇总一下这周的工作”和“写个周报”是两个说法但应当命中同一个技能第三检查技能库里是否有其他技能的部分职责和你重叠把触发逻辑给截胡了。按这个顺序查大多数“不触发”问题都能定位到原因而不是黑盒里瞎试。4.2 脚本执行出错把环境依赖从“隐式”变“显式”技能脚本执行出错最常见的原因不是逻辑写错而是环境问题。某个依赖库升级了、某个系统目录结构变了、某个环境变量没了都可能让技能突然从正常变为异常。我的排查第一步永远是看运行日志里有没有导入错误、权限错误这类基础问题第二步才是检查业务逻辑。处理环境问题我坚持一个原则所有依赖必须显式声明。技能目录里放一个requirements.txt哪怕只有一个依赖也要放所有外部路径通过配置注入不允许在脚本里写死绝对路径环境变量统一在技能说明文件里列出清单。经过这一轮梳理脚本执行出错的频率会显著下降。因为我发现很多执行故障不是真故障而是依赖和环境变量“藏在暗处”等到机器运行位置一变就暴露了。4.3 输出不稳定别靠感觉调提示词要建评估集评估技能质量最怕“拍脑袋式调优”。我见过同行改了几版提示词之后觉得“看起来好了”结果一上生产又崩。后来我用了一个笨办法给每个技能准备 20 条覆盖不同情况的测试问法里面既有标准场景也有刁钻场景每次改动后固定跑一遍人工对输出打分分数不升不合并。这个评估集不用很高大上但是要覆盖三类情况典型输入、边界输入、干扰输入。典型输入验证主流程通不通边界输入验证缺参数、传错格式时会不会优雅降级干扰输入验证那些“看似相关实则无关”的场景会不会被误触发。比如周报技能我专门加了一条“用户说‘我本周想请年假’”这就不该触发周报生成而是属于请假流程。没有这类负例技能触发边界永远模糊。4.4 实测案例一个文档处理技能从失败到稳定这里说一个真实的迭代记录。团队里有个extract_invoice_data技能早期经常出现解析字段缺漏的问题。第一次排查发现是描述里只写了“提取发票信息”没有写“遇到多页 PDF 时必须逐页解析”模型默认只解析了第一页自然缺字段。加上这条行为约束后缺漏问题缓解很多。第二次问题出在输出编码上解析出来的金额带上了倍率单位模型拿到“1.2万元”就直接当数字用导致后续汇总全错。后来在脚本里统一把金额转成纯数字并显式声明货币单位再在 SKILL.md 里写清“所有金额必须转为数值型禁止保留中文单位”。第三次是评估集里加入了“发票区域模糊”的图片样本踩出了数据增强的需求。这一个技能前后改了四轮每一轮都有明确问题、明确修复、明确回归验证。这也让我确定技能调试走不了捷径靠的就是可复现的样本和可度量的输出。5. 落地到业务里容易踩的隐藏问题5.1 安全边界技能不是任意代码执行器技能脚本在 Agent 环境里跑权限边界必须提前画好。谁允许访问本地文件系统、谁允许调外部接口、哪些命令是禁用的这些都要在设计阶段定清楚。我的做法是给每个技能打权限标签只有明确声明了filesystem: read_only或network: restricted的技能才被允许访问对应资源。落在全权开放的技能基本等于把内部网络暴露给模型自由发挥风险不可控。权限设计上最低权限原则是底线。技能只需要读文件就给只读只需要查接口就只给该域名的白名单。堵住不再需要的权限比事后补救安全漏洞划算得多。任何技能的权限升级都必须在变更记录里写清理由不能默默放行。这也是团队审计时候的重点关注项。5.2 技能数量膨胀检索冲突比想象中来得快技能库一开始只有三五个模型选得轻松技能库到三四十个之后选择就容易乱套。我见过一次线上事故某个技能描述和另一个技能高度相似模型同时命中两个结果生成了两份互相矛盾的结果。这事的根源不是模型而是技能之间职责边界模糊。控制膨胀的办法有两个。首先是准入控制新技能入库前必须跑一遍与现有技能描述两两对比相似度超过阈值就先把新旧边界划清其次是检索优化技能规模大了之后不能光靠模型在全部技能里找而是引入一个前置筛选层先用关键词把候选技能压缩到五六个再让模型决策。这套机制跑下来百来个技能的时候触发准确率还能维持在较稳水平。5.3 与现有 Agent 框架的配合技能是框架无关的资产说到落地有个不少人困惑的点技能库和自己用的 LangGraph、CrewAI 或者自研 Agent 调度器怎么配合我的实践是技能库隔离在框架之外通过标准输入输出协议对接。框架负责调度、记忆、用户交互技能只负责完成特定交付物。两边唯一约定就是入参出参格式框架不关心技能内部怎么实现技能也不关心框架怎么编排流程。这样设计的价值在于换框架的时候技能库原封不动拖过去就能用。我们团队从早期的自研调度器切到图框架时迁移成本几乎为零技能层的脚本一行没改。如果你在技术选型时把技能逻辑和业务流程耦合在了一起框架升级就会变成重写整个应用那才是真正的灾难。5.4 团队协作技能库要像代码库一样做评审技能库不是一个人的玩具。有人维护、有人评审、有版本记录它才能长期健康成长。我建议把技能库当独立的仓库治理每个技能的变更都走提交描述改了什么、为什么改、影响哪些场景。技能说明文件的任何改动都要评审因为描述变了模型触发行为就可能变这种变化不像代码那样容易通过测试暴露。可以用代码评审流程去管技能库。新技能入库要有技能说明、脚本、示例、评估结果四件套大版本变更要有人专门验证旧场景不受影响涉及权限变更更要单独审批。团队几个人一起维护时透明度和规范比个人技术能力更重要否则很容易出现“谁加的技能谁都看不懂”的状况。最后聊几句个人体会。做技能库这件事其实没什么玄学核心就是把“某个场景该怎么干活”从人脑里搬到文件里再从文件传到模型手上。这一路上遇到的大部分问题不是模型不够聪明而是技能的边界、依赖、权限、版本没有提前定义清楚。你如果正在给 Agent 搭建技能体系我建议不要一上来就铺几十个技能先挑三个核心场景跑通、评估、沉淀跑上一个月再回头看实践中的坑大概率全都踩一遍但踩完之后你对技能库的理解会踏实很多。
返回列表