Agent技能体系实战:从会聊天到会干活的LLM工程化

发布时间:2026/10/8 21:23:41
Agent技能体系实战:从会聊天到会干活的LLM工程化 我真正开始把 Agent 从玩具推向生产可用是在搭了一套连续扔了三个月的 agent-skills 技能体系之后。这个标题看起来只是两个单词但它背后真正的问题其实是大模型光会聊天没有用你得让它会干活。而会干活这件事靠的不是把 Prompt 写得更长而是把能力拆成一个个可以被复用、被调度、被验证的技能组件再围绕这些组件搭出完整的工作流。所以这篇文章我打算从项目本身的定位讲起接着拆解技能组件的内部结构、调度编排逻辑再到我在实测中踩过的边界问题最后聊一聊技能库怎么长期维护。内容比较偏向工程实践适合正在做 AI Agent 应用、或者准备把 LLM 接进业务系统但还没想清楚能力封装这层怎么做的人阅读。纯研究算法和模型的人可以跳过但如果你负责的是落地这篇文章应该能帮你少走不少弯路。1. 从会聊天到会干活agent-skills 要解决的根本问题1.1 大模型的能力边界不在参数里在外挂上先说一个很残酷的事实无论你用 GPT-4 还是开源模型做底座模型本身只擅长文本生成。你问它今天天气怎么样它能基于训练数据给你一个大概率正确的回答但它其实并不知道此刻窗外的天气也不会帮你打开任何系统、查询任何数据库、提交任何工单。它唯一能做的是根据上下文推测一个合理的文本输出。在项目早期我也犯过这个错误——指望靠一个巨大的 System Prompt 把业务规则全塞进去让模型扮演一个全能助手。结果就是Prompt 越来越长、模型越来越容易忘了自己是谁、回答越来越模棱两可而且每一次业务规则调整都要重写 Prompt根本没有工程上的可维护性。agent-skills 这套思路换了一个方向把能力本身从对话中剥离出来做成独立的、可被调用的技能单元。模型仍然只负责理解用户意图 决定调用哪个技能但真正执行动作的是技能背后的代码、工具和 API。一句话总结就是模型负责思考技能负责干活。1.2 技能和工具调用不是一回事很多人一听到技能就会想到 Function Calling。但我想先厘清一个概念工具调用是模型与外部世界交互的通道而技能是更高一层的抽象。一个技能可以封装一个工具也可以封装多个工具的编排甚至可以不调用任何工具只做一段特定规则的后处理。举个例子查询用户本月账单并判断是否超支这个技能在它的执行逻辑里可能要调账单 API、读用户的历史消费配置、再跑一段阈值判断逻辑。如果你只把它暴露成查账单这一个函数给模型模型就不知道后面还有阈值判断这一步如果你把它拆成查账单判断超支两个函数给模型模型又要多一次决策多一个出错点。技能的本质是把一组可能相关的能力打包成一个模型容易理解、容易触发的整体。模型不需要关心技能内部是怎么实现的它只需要知道什么时候该用这个技能、用完后能得到什么结果。1.3 这个项目适合什么场景我自己的实践环境是几个 To B 的客服与工单系统要求 Agent 能查订单、改状态、发通知、生成摘要。这些场景有一个共同特点业务流程相对固定但请求模式千变万化。用户可以说我的快递怎么还没到也可以说帮我催一下那个订单——表述不同但本质都是查物流状态。这种多变的话术、固定的动作场景就是 agent-skills 最典型的适用场。想清楚这一点比任何技术选型都重要因为如果你的业务本身就充满开放式探索比如让 Agent 帮你写小说那技能体系带来的结构化反而会变成束缚。2. 技能的内部结构怎么定义一段能力契约2.1 我用的技能四件套元信息、输入 Schema、执行逻辑、验证器在项目里我把每个技能都按固定的四段式结构来定义。这套结构一开始很简单后来踩了坑才补全现在基本稳定元信息metadata技能名字、描述、作者、版本、标签。描述是给模型看的特别重要后面我会专门讲。输入 Schema一段 JSON Schema声明这个技能需要哪些参数、参数类型、哪些必填。模型会参考这个 Schema 来抽取用户输入中的实体。执行逻辑一段可调用代码可以是 Python 函数、HTTP 请求、Shell 脚本负责真正干活返回结构化结果。验证器一段独立于执行逻辑的校验代码负责判断这次执行的结果是否合理。验证器是后来加的没有它技能出错时你根本不知道。这一整套合起来我把它叫能力契约。因为它的本质是技能承诺在什么样的输入条件下、能产出什么样格式的结果模型承诺在什么样的意图下触发它。两边的约定都明确了系统才敢把执行权交给自动化。2.2 一个完整的技能定义长什么样我拿查询订单物流这个技能举个例子代码不是真实生产代码但结构完全一致。技能用 yaml 描述元信息和输入 Schema执行逻辑是独立的 Python 模块name: query_logistics description: 根据订单号查询物流状态返回最新的物流轨迹与预计送达时间。 当用户询问快递到哪了、物流信息、催件、订单发货情况时使用此技能。 注意本技能只读物流信息不执行任何催办操作。 version: 1.2.0 tags: [order, logistics, query] input_schema: type: object properties: order_id: type: string description: 订单号或快递单号 user_id: type: string description: 当前用户的身份标识用于权限校验 required: [order_id]# skills/query_logistics.py async def execute(ctx, params): order_id params[order_id] # 内部会调用物流API拼权限校验、超时、重试 resp await logistics_api.query(order_id, timeout5) return { status: resp.status, trace: resp.trace[:5], eta: resp.eta, }# skills/query_logistics.validator.py def validate(result): if not result.get(trace): return False, 物流轨迹为空可能订单号错误 if result.get(status) not in {pending, shipping, delivered}: return False, f未知物流状态: {result[status]} return True, 你可能注意到我刻意把描述写得很具体甚至写了本技能只读物流信息不执行催办操作。这个细节特别关键因为模型对技能描述的依赖程度远超你的想象。描述写得太笼统比如只写查询物流模型在用户说帮我催一下快递的时候也会触发它因为它觉得反正跟物流有关。加上那句不执行催办操作就是给模型一个明确的负向边界。2.3 为什么不把技能做成一个大函数有朋友问过我你这套东西本质上不就是把函数注册给模型调用吗为什么要搞 yaml、搞验证器这么重我的回答是当技能只有两三个的时候确实没必要。但当你面对几十个技能、多个业务线共用一套 Agent 底座的时候技能作为独立实体带来的好处就会显现出来可以独立测试每个技能都有自己的输入样例和验证器离线就能跑回归。可以独立发布A 技能出了 bug不需要重启整个 Agent 服务热更新一个技能文件就行。可以统计效果每个技能的调用次数、成功率、失败原因都是独立维度的数据你能看出哪个技能是短板。这就像写代码的时候你不会把所有逻辑都塞进 main 函数而是拆成类、拆成模块。技能体系的本质就是把 Agent 的行为逻辑也做了模块化。3. 调度与编排模型怎么知道该用哪个技能、多个技能怎么协作3.1 设计一个轻量的技能调度器技能定义好了之后下一步是让模型在合适的时机选择正确的技能。我先试过最暴力的方式把全部几十个技能的定义都塞进 System Prompt。结果上下文爆炸、模型选择准确率下降效果非常糟糕。后来我参考了业界常见的做法改成了两阶段路选粗筛阶段用一个词匹配/向量检索模块在技能库里快速找出与当前用户问题相关的候选技能控制在 5 个以内。精排阶段把候选技能的完整描述、输入 Schema 交给模型由模型决定调用哪个或哪几个。这个设计的理由很简单模型做二选一、三选一的准确率远高于几十选一。而且粗筛阶段用的是非模型逻辑跑一趟只要几毫秒成本几乎可以忽略。粗筛我用的是关键词权重加向量相似度两手抓后面会细讲评测时踩的坑。3.2 技能编排一个请求怎么流经多个技能真实的业务请求很少是单一技能能搞定的。拿帮我查一下订单如果超时了就发起催件来说这个请求背后包含三类动作查订单状态、判断是否超时、发起催办。我采用的方案是技能链skill chain即在一个任务定义里预先声明技能的执行顺序和依赖关系name: order_expedite_chain steps: - skill: query_logistics alias: logistics_result - skill: judge_expired input: logistics_result: ${logistics_result} alias: expired_flag - skill: create_followup filter: ${expired_flag.is_expired} input: order_id: ${logistics_result.order_id}这套链式编排里最核心的是两点一是前一个技能的结构化输出可以直接作为后一个技能的输入模型不需要在中间再做一次翻译减少了出错点二是每个步骤都可以挂 filter满足条件才继续往下走这样催件不会在没有超时时误触发。有人会问为什么不直接让模型生成这段编排逻辑我早期也这么干过但实践下来发现让模型动态编排多个技能的稳定性还不够高——它有时候会生成根本不存在的技能名有时候会漏掉关键步骤。固定链式编排适合流程稳定的业务场景动态编排适合探索性强的场景。以我的项目为例90% 的工单请求都能落到预先定义的技能链上所以我会优先保证这一部分的稳定性剩下的 10% 长尾场景才走模型自由调度。3.3 状态传递和上下文管理技能编排过程中有一个特别容易被忽略的问题上下文传什么、传多少。我见过一种错误的做法把整个对话历史都传给技能执行器让技能自己去找需要的字段。这会让技能的执行逻辑和对话格式强耦合对话结构调整一次技能就要跟着改。我的做法是技能只接收经过 Schema 校验的 params以及一个轻量的 context 对象包含当前用户身份、租户信息、请求追踪 ID。任何跟业务相关的信息都必须在调度层完成抽取、显式传入技能。这样技能本身是无状态的方便测试和复用。数据流上还要注意幂等。技能链中的步骤如果因为网络超时重试了两次不能产生两条催办记录。我一般要求写技能的同事在技能内部实现操作类技能去重每次进入技能时带上 request_id后端用这个 ID 做幂等判断。这个问题在单体应用里不突出但在技能的异步调用、消息队列场景下非常致命。4. 实测中的坑与优化技能命中、误触发与并发问题4.1 技能描述里的语义陷阱导致的误触发先讲一个真实案例。有一次我在技能库里加了一个查天气的技能描述写的是查询任意城市的天气情况。结果上线后用户说我今天心情不太好Agent 竟然调用了天气技能还问用户您想查哪个城市的天气。原因定位后发现模型把心情不好和天气关联到了认为用户想通过天气话题来缓解情绪。这个案例告诉我两件事技能描述必须区分触发场景和能力范围尽量用用户的实际话术样本来写描述而不是用功能描述。比如查询任意城市的天气情况不如写成当用户直接询问今天/明天/本周某城市的天气、温度、降水情况时使用例如北京明天多少度、上海下雨吗。要建立一套负向规则明确这个技能不应该在什么场景下使用。像天气技能就加一句如果用户只是提到天气相关情绪不查询具体天气数据不要使用此技能。这类优化做多了之后我形成了一个经验技能描述不是写给文档看的是写给模型看的。写的时候要想象模型会根据你的描述去做意图分类描述写得越像真实用户话术的转述分类越准。4.2 多个 Agent 同时跑资源限制与超时管理技能体系一旦上线就不会只有一条对话链在跑。我的环境里最多的时候有十几个业务 Agent 并行每个 Agent 的内存、CPU、API 配额都很容易打满。这个阶段我踩了不少坑最典型的是技能超时没有兜底。比如订单查询接口本身需要 3 秒当并发一高变成 5 秒、8 秒技能执行器如果只设了 5 秒超时那一旦超时整个技能链就中断。后来我加了三层兜底技能调用级别超时重试第一次超时后自动重试一次重试时用备用的只读只读副本接口。技能链级别熔断如果链上某一步连续失败 3 次整个链直接终止不再触发后续技能。结果降级当核心技能失败时返回一个当前系统繁忙/无法获取数据的标准提示而不是让模型自由发挥编造数据。这里要给一个明确的建议技能体系的容错要分层不要让模型自由发挥成为兜底方案。模型自由发挥在低风险场景可以但涉及订单、资金、工单状态时一旦编造数据比系统不可用的后果严重得多。4.3 离线评测技能召回率、命中准确率怎么建我在项目进行到第三个月的时候才意识到一个严重的问题我根本不知道技能质量是变好了还是变差了。于是一口气补了一套离线评测流程。评测集用的是真实对话脱敏后的样本每个样本标出应该命中的技能 ID。离线跑的时候我会统计三个指标召回率应该命中技能 A 的样本里有多少真的把 A 选进了候选集。准确率模型最终选择的技能里有多少是样本标注的正确技能。误触发率不该触发任何技能的场景里有多少场景误触发了技能。这套评测集大约 800 条样本每两周跑一次全量回归。效果非常直观我优化过一次天气技能的描述误触发率从 6.2% 降到了 1.8%没有这个评测体系我根本感知不到这种变化。评测集的价值还不止于此。当新技能上线时我会拿评测集里所有同类意图的样本去回归防止新技能抢走旧技能的触发。这个机制在技能数量超过 20 个之后几乎是必需品——因为技能之间天然存在领地重叠。5. 版本、灰度与技能库的长期维护5.1 技能也要做版本管理和灰度发布技能不是写一次就完事的。业务方的规则会变比如超时判定从 48 小时改成 24 小时你改的可能只是技能内部的一个阈值但如果不小心影响到了判断逻辑的兼容性就可能引发连环故障。我给技能库引入了语义化版本号主版本号变化表示输入输出契约不兼容副版本号变化表示新增能力或参数修订号变化表示内部逻辑的小修复。执行引擎只认契约不看实现细节。这样当技能从 1.2.0 升到 2.0.0 时调度系统会自动停止这条技能被旧技能链引用直到所有技能链都完成适配。灰度发布也做了。新版本的技能先只在一组测试 Agent 上生效跑一天观察调用成功率和验证器通过率稳定后再全量。这一套流程本质上跟微服务发布没啥区别但很多人做 Agent 项目时会想当然地认为技能就是一段 Prompt改完直接生效结果改错了没有回滚途径。5.2 从对话日志里发现新技能需求技能库不是设计出来的是从真实对话里长出来的。我在每个 Agent 后面都挂了日志分析流程每周看一次模型没有选择任何技能但用户仍然期望得到具体操作结果的对话片段。这些片段就是新技能的需求池。举个例子我们的客服 Agent 一开始没有改收货地址技能用户只能在对话里反复要求改地址、Agent 只会回复请自行前往个人中心修改。这个体验很差但从日志里可以看到每周有几十个这样的诉求于是我们补了一个修改收货地址技能。上线后这类问题的解决率几乎翻倍。这个过程也让我意识到技能库的维护不是你一个人在后台写代码而是要形成一条从用户需求到技能上线的反馈回路日志采集、意图聚类、技能定义、离线评测、灰度发布、效果监控。每一步都不复杂但缺了任何一环技能库都会慢慢腐化。5.3 跨 Agent 共享与被调用的技能市场设想agent-skills 本身还有一个很有意思的方向技能库不绑定单个 Agent而是可以在多个 Agent 之间共享。我目前的做法是维护一个中央注册中心各业务 Agent 按需拉取自己需要的技能包。这样订单查询技能只需要维护一份客服 Agent 和用户运营 Agent 可以复用同一套实现。但这只是第一步。更进一步可以用标准接口把技能封装成能力服务开放给外部调用方也就是类似技能市场的形态。企业内部可以有一个技能商店不同部门贡献自己的技能统一注册、统一计费、统一审计。这个方向我觉得是 Agent 应用走向成熟的一个重要标志——因为能力一旦变成可交易、可编排的标准化单元Agent 的扩展性会呈指数级增长。不过我也要提醒一点技能共享的前提是权限隔离做扎实。不同业务的 Agent 可以共享查询类技能但修改删除审批类技能必须有严格的调用方身份校验和数据权限控制。我们甚至在技能定义里增加了allowed_callers字段显式声明哪些 Agent、哪些角色可以调用这个技能防止越权。这块如果有疏漏技术上的便利就会变成业务上的灾难。最后说一点个人体会。agent-skills 这个项目最大的收获不是代码本身而是让我彻底转变了对 Agent 的认知Agent 不是一个大模型而是一个模型 一群技能 一套调度逻辑的组合体。你投入在技能抽象、评测、编排这些工程细节上的时间会在系统复杂度和稳定性上得到超额的回报。如果你的 Agent 还停留在模型回答一切的阶段我建议你从最小成本的技能封装开始试点——把一两个高频动作做成独立技能加上验证器和日志跑两周看效果。你会发现这条路才是把 AI 应用推向生产环境的正解。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询