Agent技能化实战:用AI Skills重构工具调用与腾讯云部署全记录 📅 发布时间:2026/9/5 19:18:20 👁 浏览次数: 如果你最近也在做 Agent 项目大概率体会过这种痛苦业务需求本身并不复杂难的是模型总是选错技能、参数填得乱七八糟、业务一扩展就要在主流程里重新梳理一遍工具注册逻辑。上个月在腾讯云上重构手头这个 Agent 时我把所有可复用能力全部抽成了独立的 AI Skills顺便把二级域名、安全组、API 网关、评测和灰度链路也完整收拾了一遍整个过程踩了不少坑。这篇文章就把我如何设计技能描述、如何部署到腾讯云、如何调优调用链路以及最终怎么把一个单 Agent 养成能稳定调度多个云端技能的“全能 Agent”的过程完整记录下来。不聊空概念适合正在做 Agent 应用、想用一套可落地的云端方案承接多个技能的开发者参考。1. 为什么最终要把能力抽成 Skills从一次工具注册失控说起1.1 项目做大的失控现场最开始我手上的 Agent 其实很单纯一个模型入口加四个内部函数就能跑通一个“帮用户查资料、做总结”的演示项目。那时函数列表短模型基本不会选错参数错误靠日志也能兜住。真正出问题是在业务方开始往里塞能力之后——接入天气接口、查产品库、生成 SQL、拉取订单、做文本切片、调用内部审批单不到一个月工具函数就膨胀到了 14 个。14 个听起来不多但模型做工具调用时的失败率开始明显升高。有的是工具描述互相覆盖比如“查库存”和“查订单状态”都出现了“查询商品相关信息”的说法模型经常把订单号塞进库存查询里有的是参数约束太弱明明days只接受 1 到 5模型却会生成 9最麻烦的是注册逻辑散落在代码各处——后来加新工具要改主流程还要担心会不会影响旧工具的调用格式。那段时间我意识到问题不在模型能力而在于我一直在往 Agent 的“大脑”里塞具体动作却没有给这些动作建立一套统一、可独立部署、可单独验证的“能力层”。1.2 Skill 不是工具函数换了个名字很多人会把 Skill、Tool、Function、Plugin 混在一起实际上它们的抽象层级不太一样。工具函数是代码层面的最小执行单元Plugin 通常指已经打包好的软件扩展而我在腾讯云上沉淀的 AI Skills是一种以“声明 执行体 返回规范”三件套构成的完整技能单元。一句话解释的话Agent 是大脑负责拆解目标、记忆上下文、决定下一步做什么Skill 是双手负责把模型“想调用的意图”变成真正可执行的动作并且以固定结构把结果返回给大脑。传统的工具注册是把函数直接暴露给模型模型能看到什么、能不能准确调用完全取决于函数命名和当前代码实现的一致性。而 Skill 模式相当于在模型和真实执行逻辑之间加了一层“职业技能描述”每个 Skill 有独立的 slug、版本号、清晰的描述、严格的参数 Schema、标准化的返回格式甚至可以单独部署到云服务器或云函数上。这么做最大的好处是解耦——加一个新能力时不需要动 Agent 主干只需要新增一个 Skill 包并注册进技能清单。我在设计时还用了另一个类比Skill 不是“一个 API 接口”而是“一个能独立上岗的小外包团队”。比如天气查询这类 Skill内部可能还要处理城市名归一化、请求第三方接口、解析时区、缓存热数据但 Agent 只需要知道“我给它城市名和天数它回我结构化天气结论”。模型不需要理解内部细节也不需要被进程内函数绑死。1.3 哪些能力值得写成 Skill哪些不值得不是所有逻辑都适合沉淀成 Skill。我现在的判断标准很直接值不值得写成 Skill如果这个能力要在多个 Agent、多个会话或多条业务线里复用且接口边界足够清晰就值得。如果这个能力强依赖当前对话的上下文、状态机或者主流程临时变量那它更适合留在 Agent 编排层而不是强行抽出来。如果业务逻辑每天都在改可能今天加字段、明天换接口我会先用硬编码跑通等接口和参数结构稳定后再抽成 Skill。如果能力涉及外部系统调用、需要独立鉴权或需要审计留痕也应该用 Skill 独立承载避免让 Agent 主进程直接持有太多权限。另外有一点容易被忽略当 Skill 数量接近 10 个以后技能注册中心的价值才真正体现出来。如果只有三五个技能手工维护还不算难一旦超过十个模型选择出错的概率会急剧上升这时候“技能描述怎么写、参数约束怎么定、版本怎么切换”就成了决定 Agent 能不能落地使用的生死线。这也是为什么下一章我要把技能标准化设计放在最前面讲。2. 技能清单的标准化设计让模型第一次就能调对2.1 描述是给模型看的不是写给人的需求文档我见过很多人写技能描述特别像写接口注释比如“天气查询接口返回天气信息”。这种描述除了占 Token对模型做工具选择几乎没有任何帮助。模型不是人它不会从接口名里猜业务含义它需要的是一个足够明确的使用说明书。我现在给每个 Skill 写描述时基本会覆盖四块内容什么时候调用、什么时候不要调用、输入内容从哪里来、以及对输出的预期。以天气查询为例我不会只写“查询天气”而会写成“当用户询问某个城市未来 1 到 5 天的天气、气温、降水概率时调用。城市名必须是中文城市名或标准行政区划名称不要使用‘这里’、‘我家’等模糊位置。若用户只提供了省份或区域但未明确具体城市先向用户确认城市再调用。”这种写法看着啰嗦但实际跑下来效果差别非常大。模型在“要不要调用这个技能”“参数能不能从上下文里抽出来”两个节点上的准确率都会明显提升。负面说明也很重要它能帮助模型排除一些容易被名字误导的使用场景。比如名为“query_to_code”的技能若描述里不写清楚“仅在用户明确要求生成代码时调用”模型极有可能顺手拿它去干文本润色或者 SQL 生成的活。2.2 参数 Schema 要写到“不允许模型自由发挥”的程度如果说描述决定了模型会不会选对技能那么参数 Schema 就决定了模型会不会调对技能。标准做法是给每个 Skill 维护一份完整的 JSON Schema并且描述里的字段说明也要一并提供给模型。内容型技能最容易犯的错是只写type: string不给格式约束。比如日期字段模型可能输出“后天”也可能输出“2026-01-15”但你的业务系统只认时间戳再比如城市字段模型可能输出“杭州市”也可能输出“hangzhou”。如果 Schema 里显式声明了格式和枚举范围模型返回非法值的概率会明显下降。下面是我常用的一个简化版本{ type: object, properties: { city: { type: string, description: 中文城市名例如北京、杭州市 }, days: { type: integer, minimum: 1, maximum: 5, default: 3, description: 预报天数必须是 1 到 5 之间的整数 } }, required: [city] }在minimum、maximum、enum、format这些约束能写的地方全部写上不要寄希望于模型“自己理解”。很多模型在参数约束明确时表现还不错一旦约束缺失就会开始自由发挥。我也曾在某些模型上用“必填字段不写 required”测试过结果模型把非必填项当成必填项甚至自己编造出一个不存在的字段来补全调用。这类问题不是靠换模型解决的而是靠把 Schema 写严谨。还有一个实操技巧如果某个参数需要模型从历史上下文里推导最好在字段描述里注明推导来源例如“从用户当前问题或近期对话中提取城市若无法确定则返回 UNKNOWN”。这样能明显减少模型用空值或者自创值的情况。2.3 返回结构必须带 code、message、data 三层Skill 执行体返回给 Agent 的内容也需要有约定。我早期直接把业务数据 JSON 返回给模型结果模型经常分不清“这次调用是不是成功了”有时还把错误信息当成正常数据来总结。后来的标准化返回结构统一为三层{ code: 0, message: ok, data: { location: 杭州市, forecast: [], source_updated_at: 2026-01-15T10:00:0008:00 } }当执行体里出现异常时code是非 0 值message是人类可读的错误说明data里只放与本次请求相关的部分结果或为空。这样 Agent 层可以通过code快速判断调用是否成功再决定是结束任务、换一种调用方式还是直接告诉用户请求失败。加了这层结构之后还有一个额外收益日志和监控好做了。之前排查问题需要反推整个 JSON现在只需要查code。给 Agent 用的data也要做好裁剪能返回精简字段就不要把原始全量数据直接塞回上下文因为返回内容最终会占用模型上下文窗口影响下一次决策。2.4 别忘了幂等键、超时和可观测性技能执行不是本地函数调用它可能跨网络、跨服务甚至通过云函数冷启动。一旦超时或重试就可能出现重复下单、重复发送通知这类严重问题。所以我的每个 Skill 在执行层都要求把透传的request_id作为幂等键记录到日志里写操作类技能的接口层要做重复请求校验。超时设置同样值得单独规划。Agent 调技能时如果执行端迟迟不返回模型侧通常只有一个笼统的 “execution provider did not respond in time” 之类的错误提示既看不出是哪一步慢也看不出请求到底打到哪台机器。后来我把每个 Skill 的预期耗时写进注册信息里比如天气查询timeout_ms: 5000生成类技能timeout_ms: 15000然后在网关和 Agent 层同时做超时告警。这样一旦出现超时我可以先查网关日志确认是不是执行体本身的问题再决定是否调大超时或优化代码。3. 腾讯云部署实录域名、安全组、API 网关与自动上传3.1 执行体选型常驻服务 云函数兜底怎么组合技能执行体放在哪跑是我反复调整过的问题。最初图省事把全部 Skill 逻辑都放在一台 CVM 的 Python 服务里结果每次加技能、改依赖都要 SSH 上去重新部署回归测试也麻烦。后来我改成了一种混合部署方式高频、需要长连接或大量内存的 Skill放在一台 CVM 常驻服务里用 Nginx 反代低频、间歇调用、依赖明确的 Skill打包成云函数 SCF真没人调用时不占用资源技能注册清单和描述文件单独放在对象存储 COS 上由 Agent 服务定时拉取或通过 API 强制刷新。这套组合的出发点是成本和维护速度的平衡。云函数天然适合“偶尔跑一次”的技能而且可以直接配合 API 网关暴露但如果是耗时特别久、内存要求高的技能云函数的资源上限和计费模式不一定划算常驻服务会更灵活。还需要注意的是不要把所有 Skill 的执行体都做成一个巨大的单体服务。随着技能数量增长单体服务重启时间会越来越长依赖冲突也会互相影响。我现在的倾向是互相独立的领域尽量拆成不同执行体共享部分通过公共库或对象存储来同步。3.2 二级域名与 HTTPS 证书配置从解析到 Nginx 的完整链路Agent 服务和技能执行体之间有大量通信不可能每次都用 IP 访问所以统一为每个执行环境配一个独立的二级域名是最省心的做法比如skill-api.yourdomain.com专门承载技能网关agent.yourdomain.com承载 Agent 主服务。在腾讯云上给已有域名配置二级域名比较简单在 DNSPod 解析记录里添加一条 A 记录或 CNAME 记录主机记录填你想要的二级域名前缀记录值指向服务器的公网 IP 或负载均衡实例。如果还没有域名需要先完成域名注册和实名认证再进行解析。需要注意 DNS 解析生效不是瞬时的通常几分钟到几十分钟不等刚配完如果 ping 不通不用急着反复改记录。域名解析完成后我强烈建议立刻把 HTTPS 配好不要用裸 HTTP 做 Agent 回调。腾讯云提供免费版 SSL 证书申请完成后需要下载证书文件然后在 Nginx 里配置。下面是我在 CVM 上一个很常见的站点配置片段server { listen 443 ssl; server_name skill-api.yourdomain.com; ssl_certificate /etc/nginx/ssl/skill-api_fullchain.crt; ssl_certificate_key /etc/nginx/ssl/skill-api.key; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }如果同一个服务还要暴露给 Agent 侧做工具回调建议把执行体的监听地址绑定内网或 127.0.0.1让流量只经过 Nginx。另外证书都会过期免费证书一般只有三个月或一年我后来在定时任务里加了证书到期告警避免半夜 Agent 突然报证书错误。3.3 安全组端口最小化别听“把端口全开”的馊主意我在调服务时也遇到过“怎么连不上、是不是没开放端口”的困惑。实际上腾讯云服务器的公网访问受两层控制控制台安全组规则以及云服务器操作系统自身的防火墙。很多教程会让人在安全组里把所有端口全部放行图省事但我强烈不建议这么做。端口全开意味着你的数据库、Redis、调试端口全部暴露在公网扫描之下Agent 技能执行体一旦出现未授权访问漏洞业务数据就没保护了。我给技能执行机器设置的安全组规则非常简单443 端口对全网开放因为对外 API 服务必须让人能访问22 端口只允许公司办公出口 IP 访问用于 SSH 管理80 端口不开或只用于跳转 443不让明文流量暴露3306、6379 等数据库和缓存端口一律不对公网开放只在云服务器内网访问。如果你需要临时调试某个端口建议先把来源 IP 限定为当前网络的公网出口而不是设置0.0.0.0/0。测试完立刻删掉规则。安全组本质上是白名单不是“先全部放行再靠业务层防御”的黑名单思路。在云服务器内部还可以用firewalld或ufw再做一道限制只放行 Nginx 和必要的内网端口。两层叠加确实会让首次配置变得繁琐但换来的是后面不用半夜爬起来处理扫描攻击。3.4 统一接入网关把鉴权、限流、审计收口到一个入口当多个 Skill 分布在不同的执行体上时最大的隐患是“入口太多”。如果每个 CVM、每个云函数都各自暴露公网地址Agent 调度时就要维护一堆地址和调权信息审计也非常分散。我后来把所有 Skill 执行统一收敛到一个 API 网关后面外部只看到一个入口路径内部再根据skills/{skill_slug}把流量转发到对应的云函数或 CVM 服务。在这个统一入口层我会做三件基础事情鉴权、限流和请求审计。Agent 侧每次调用都携带一个短期有效 Token网关校验通过后才转发每个调用都记录下request_id、技能 slug、调用方来源、耗时和返回码方便事后回溯问题另外为了避免某个技能异常时拖垮整个执行体每个技能路由会设置独立的 QPS 上限。模型接入侧也可以使用同样的思路。很多人会在项目里同时接多家模型做对比这时如果每个 Skill 都直接拼各家的原生接口代码里会塞满 if else。我在模型接入层用 LiteLLM 做了统一网关通过一个兼容层把各家模型的工具调用格式收敛成一套这样技能描述和参数结构只需要维护一份切模型时不用改动 Agent 的执行逻辑。这个选择后来帮我省下了大量时间因为多云切换和 A/B 测试都会变成改配置而不是改代码。4. Agent 调用 Skills 的实测链路与性能优化4.1 一次完整调用到底经历了什么在把技能全部标准化之后一次 Agent 调用执行体的过程大概是这样的用户输入问题Agent 主服务结合会话历史决定是否需要调用技能系统把候选 Skill 的描述和参数 Schema 注入模型上下文模型返回工具调用意图包含目标 skill slug 和参数字段本地调度层对参数做一次 Schema 校验校验不通过会让模型补充或修正调度层携带鉴权信息通过统一网关请求对应执行体执行体完成业务逻辑返回标准的三层 JSONAgent 把返回结果与原始问题合并决定是继续调用其他技能还是生成最终回复。这七步看上去不复杂但每一步都可能成为瓶颈。最容易被忽视的是第 4 步的 Schema 校验——我见过太多项目直接把模型返回的参数原样转发给执行体结果执行体收到days: 9可能返回一个难以理解的错误。在校验层做一次“防御性兜底”比如自动裁剪超出上限的枚举值、数字转字符串标准化通常可以把最终成功率拉高一大截。4.2 耗时分布实测模型决策是大头执行体不是我把自己部署的 CVM 技能服务跑了几轮基准测试记录了各个环节的耗时分布。数据不算严谨但很有参考价值。环节平均耗时说明模型规划1800~2600ms模型决定调用哪个技能、生成参数Schema 校验 10ms本地执行开销很小网关转发20~60ms内部网络的延迟通常可控Skill 执行体300~1500ms取决于业务逻辑与第三方接口模型总结1200~2400ms拿到结果后生成最终回复整体端到端4~6s实际体验略长需要流式输出辅助从这份数据能看出真正决定用户体验的不是 Skill 执行体本身而是模型规划与总结这两段大模型推理时间。所以当整体响应变慢时先不要急着优化执行体代码先看是不是模型参数选得太大、上下文塞得太长或者模型因多次无效工具调用导致来回太多次。4.3 真正有效的三个优化技能预筛、流式返回、结果摘要第一个优化是技能预筛。当一个系统里注册了十几个 Skill 时把所有描述全量塞给模型会让上下文变得很长而且无关技能描述会干扰决策。我给每个技能预先生成一段 Embedding 向量用户每次提问时先用向量检索取 Top K 候选技能再把这些候选的描述注入上下文。实测下来技能列表占用的 Token 从全量时的 2400 左右降到了 400 到 600决策准确率反而有所提升因为模型不会被其他领域的技能描述带偏。第二个优化是流式返回。Agent 调用模型生成最终结论时如果不用流式输出用户会看到长达好几秒的空白等待体验非常差。接入流式输出后哪怕后端还没完成最终总结用户已经能看到“正在调用天气查询”“查询到杭州市未来三天天气”等阶段性状态等待感会下降一大截。腾讯云 CVM 上做 WebSocket 或 SSE 转发并不复杂重点是把执行日志和阶段状态推送到前端。第三个优化是结果摘要。有些 Skill 返回的数据很长比如数据库查询结果可能包含几十行明细全塞回模型上下文既费 Token 又容易“淹没”关键信息。我在 Agent 层做了一层结果摘要器先由一个小模型把长结果压缩成要点式的结构化摘要再把摘要送回主模型继续推理。这个操作对包含长列表的 Skill订单查询、日志检索、文档搜索效果立竿见影上下文占用可能降到原来的五分之一。5. 从单 Agent 到多 Agent 协作Skills 编排与记忆5.1 单 Agent 的天花板以及如何拆角色技能数量超过 20 个之后即使做了预筛单一 Agent 的准确率还是会下降。原因不全是模型能力还有一个现实问题用户的复杂需求往往需要多个技能按顺序调用比如先查资料再写报告再发送通知这个过程中仅靠一个 Agent 同时管理任务拆解、参数收集和分支判断上下文很容易混乱。后来我把单 Agent 拆成了几个职责更纯粹的 Agent分别承担拆解任务的调度 Agent、执行专项能力的领域 Agent以及负责最终回复质量检查的质检 Agent。每个领域 Agent 只需要维护自己那部分 Skill 的注册表和上下文调度 Agent 负责任务分发和结果汇总。拆分成多 Agent 的第一周我遇到了新的麻烦技能按角色分了但不同 Agent 可能需要调用同一个公共 Skill。如果每个 Agent 各自维护一份“命名相同、描述却不一样”的技能那么同一个 slug 在不同 Agent 里可能执行完全不同的逻辑。这个坑很容易在初期埋下等到出问题再排查就要翻半天日志。5.2 Skill 注册中心是共享的同名技能必须全局唯一多 Agent 共享技能的正确做法是建立一个集中的 Skill 注册中心所有技能只有一份定义、一个版本号、一个执行入口。Agent 自身可以有“专属的编排逻辑”和“独特的系统提示词”但底层调用的 Skill 不应该各自复制一份。我维护 skill slug 时有一条不成文的规矩slug 一旦发布不允许改名只能通过新版本替代旧版本。这样即使老 Agent 还在使用旧版本也不会因为名字变化而彻底调不到服务。另外注册中心里每个技能都带有负责人信息和变更日志跨团队共同维护时才不会出现“改完没人知道”的情况。技能版本管理要比普通代码更谨慎。因为同一个技能可能同时被多个 Agent 引用直接覆盖式更新可能让正在执行的旧会话突然调用到不兼容的新结构。我采用的方案是发布时生成新版本号在注册中心里保留“当前默认版本”和“历史版本”Agent 会话创建时可以把技能版本固定住避免会话中途行为漂移。5.3 会话记忆如何与 Skill 分层存储多 Agent 场景下记忆不能只堆在模型上下文里。把用户长期偏好、短期会话上下文、技能执行产生的中间状态混在一起模型很快就分不清哪些才是对当前任务有用的信息。我这里简单分了三个层次高层会话记忆存用户本轮对话的目标、已经确认过的关键信息、以及最终输出的摘要用户级长期记忆存用户的固定偏好比如“默认城市是杭州”“喜欢简洁回答”Skill 执行状态存某个技能在一次任务中的中间结果供后续调度预筛使用。用户级长期记忆的一个展示片段大概是这样{ user_id: u_123, key: preferred_city, value: 杭州, scope: weather_query, updated_at: 2026-01-15T10:00:0008:00 }记录时要注意 scope。一个用户的“城市偏好”也可能在不同领域有不一样的值比如查天气时喜欢杭州查门店时喜欢上海如果不带 scope 就写进长期记忆很容易误伤其他技能。更稳妥的做法是先由调度 Agent 判断某个事实是否具有跨会话复用价值确认后再写入长期存储不要把一次性的上下文误当成长期偏好。5.4 编排里最容易被忽视的循环调用问题多 Agent 协作之后最危险的问题不是调用链太长而是两个 Agent 互相调用导致死循环。比如调度 Agent 觉得需要让内容 Agent 生成文案内容 Agent 又为了补充上下文反过去调用了“通用问答”技能而这个技能本身又由调度 Agent 管理就可能出现两边的请求一直在兜圈子。我在编排层做了两个硬限制一是所有 Agent 间调用都设置max_nested_calls超过两层就强制终止并回到主调度 Agent二是给每个任务设置总时间预算比如 30 秒内如果不能完成就输出部分结果或让用户继续补充信息。经验表明真正需要多层 Agent 深挖的任务占比并不高绝大多数业务需求一次调用或两次调用就能完成把复杂循环的支持做好是为了防患于未然。6. 养成一个“全能”Agent 的日常评测、灰度与回滚6.1 没有评测集所有技能改动都是在赌技能描述、参数 Schema、返回结构都是对业务逻辑的高敏感改动。表面上看只是改了描述实际上模型的调用行为会发生很大变化。我吃过一次亏把一个技能描述从“查询订单”改得更详细之后没有跑回归测试就直接上线结果模型开始频繁把“查询物流”的需求划分到“查询订单”业务方当天就收到了几次用户投诉。从那以后我养成了维护一个“技能回归评测集”的习惯。每条评测集是一组真实用户问题配合预期的技能调用和参数约束。举几个例子用户问题期望调用技能期望参数杭州明天会下雨吗weather_querycity杭州市, days1帮我查一下最近一周杭州的天气趋势weather_querycity杭州市, days5把这段话翻译成英文language_translatetext..., targeten查询订单 OD20260115 的物流order_queryorder_idOD20260115每次修改任何技能的定义之后我都要先在评测集上跑一遍。不用追求所有 case 都必须通过目标是观察“修改前能通过的 case 在修改后是否仍然通过”。如果某个原本稳定的技能因为描述改动而开始误选择那就要立刻从头审查描述内容而不是继续叠加新的修正语句。6.2 灰度发布与一键回滚的落地做法技能的灰度发布比功能发布更难做因为模型调用是动态的我无法保证某个版本的技能一定会被哪些会话使用。我的处理方式是给技能开一个“双版本并存”的路由开关注册中心里同一 slug 下存在 v2 和 v1默认按 10% 的流量路由到 v2剩余 90% 留在 v1。灰度期间观察 v2 的技能调用失败率、参数校验失败率和模型误选率如果指标明显优于 v1就逐步把流量切到 50% 再切到 100%。一旦灰度出现问题需要能够一键回滚到旧版本。我的做法不是重新部署代码而是在注册中心里把“默认版本”指向旧版本号然后让 Agent 服务强制刷新技能清单。整个回滚动作可以在一分钟内完成。如果执行体代码本身也有改动那就需要把旧版本的执行体以独立部署单元保留一段时间不能直接覆盖覆盖式删除否则版本虽然还是 v1执行逻辑却已经变了。6.3 日常监控里最重要的四个指标技能上线之后我最有价值的监控指标不是整体的“成功率”而是下面几个看起来没那么亮眼的子指标技能调用失败率按 skill slug 分别看识别某个执行体的异常参数校验失败率模型生成参数后被本地 Schema 校验拦下的比例如果偏高说明描述与 Schema 不够清晰平均往返次数完成一个用户请求平均要调用几次模型和 Skill。如果这个值莫名上涨很可能模型在反复试错或选了不合适的技能未命中技能占比用户明显有需求但最终没有触发任何技能调用。这类场景的复盘往往能发现新的高价值 Skill 应该被补上。只看端到端成功率很容易掩盖问题。比如用户问“帮我查天气”Agent 最终直接回复了自己瞎编的结果端到端成功率可能仍然显示为 100%但实际业务价值是负的。所以我会同时检查模型输出里是否出现了未经技能调用就做出的具体数据声明。如果模型开始“自作主张”编造数据那需要回头检查系统提示词并强化“没有拿到技能返回就不能声称已获取结果”的约束。6.4 半年后我沉淀出来的实操经验最后聊几条我踩坑踩出来的实在经验。技能描述不是越短越好而是越“防呆”越好。写描述时我会把自己想象成一个第一天入职的新同事如果只看到这段描述能不能在正确场景调用正确工具如果不能说明描述还要补场景示例。改返回结构时必须排查所有依赖这个技能的 Agent。即使 Agent 的代码逻辑没变只要返回字段名变了下游摘要逻辑可能就会静默出错。我后来给所有返回字段都加了兼容层新版本返回多一个字段不影响旧逻辑去掉字段则必须通过强校验提醒。不要追求把所有能力一次做成“技能全家桶”。Agent 养成的正确节奏是先做骨架把十几条真实评测集跑通再以每周一两次的小迭代频率新增技能。每次迭代后观察误选率和失败率确认没有回退再继续扩张。全能 Agent 不是一蹴而就的产物而是技能定义、云端部署、评测灰度这一整条链路持续运转之后的结果。