资讯详情

资讯详情

从只会聊到能干活:AI Skills让Agent真正落地业务

这几个月我一直在忙一件事把一个只会“嘴上答应”的 Agent练成一个真能接手具体任务的“全能打工人”。聊天、检索、任务规划这些能力模型早就给得很足了真正卡住项目进度的从来不是“模型会不会聊”而是“Agent 能不能把活儿干完”。我见过不少团队在 Demo 阶段表现得头头是道一接真实业务就露怯让它查个订单它只会说“我可以帮你查”让它改个配置它能现场编一套不存在的 API。最后把整个项目捞起来的不是更聪明的模型而是一层不起眼但极其关键的东西——AI Skills。这篇我把在腾讯云上从“只会聊”到“能干活”的完整养成过程梳理一遍包括 Skill 的定位设计、服务端托管选型、Agent 侧集成、上线后的运维与安全以及几处实测踩出来的坑。想自己搭 Agent、把智能体真正落到业务里的开发者这应该是一份可以直接参考的实战记录。1. 先想清楚一件事Skill 到底在替 Agent 干什么很多人一上来就急着写工具函数、接 API结果做出来的东西不叫 Agent叫“套了层对话外壳的接口文档”。所以在动手之前我想先把 Skill 的定位掰扯清楚。1.1 Skill、Workflow、Function Calling 三者是什么关系我在社区里看到不少人在搜“skill和agent的区别”“harness和agent区别”“agent框架与编排”这类问题说明大家对这些概念其实还是模糊的。不把概念拆干净后面设计接口、写提示词、做编排都会跑偏。用最直白的话讲Function Calling是模型的一种底层能力让模型在对话中决定“要不要调用某个函数”并输出结构化的调用参数。它解决的是“模型怎么开口”的问题。Workflow是预先编排好的流程节点固定、分支确定适合业务流程稳定的场景比如“先查库存再算价格最后生成订单”。它解决的是“事情按什么顺序做”的问题。Skill是给 Agent 准备的一组“可复用的能力单元”每个 Skill 封装了特定任务的完整处理逻辑可以是单个函数也可以是多个工具的联动加提示词模板。它解决的是“Agent 遇到这类事该找谁、怎么干”的问题。这三者的关系在我看来是这样的Skill 在更高层面对能力做了封装Function Calling 是模型触达能力的手段Workflow 则可以在 Skill 内部作为实现方式之一。打个比方一个刚入职的实习生Agent什么都不会你教他各种工作技能Skill他需要打电话订会议室、发邮件确认日程、提交报销单。他每一次“开口办事”的能力是 Function Calling而“订会议室”这件事该先做什么、后做什么的固定流程就是 Workflow。没有 Skill 的 Agent 就像一个只有通讯录但没有办事能力的实习生——什么都能问什么都办不成。1.2 为什么 Skill 值得单独沉淀一层我见过不少项目第一版把工具函数直接写死在提示词里或者一股脑全塞给模型。前几次跑通 Demo 很爽等到要加业务逻辑、要复用、要给别人调用的时候痛点全来了重复劳动接单、查库存、发通知这些基础能力每个 Agent 项目都要重写一遍。上下文爆炸所有工具的说明都塞给模型一次对话光工具描述就占两三千 token模型反而不知道该用哪个。能力边界模糊同一个动作这个 Agent 里叫query_order那个 Agent 里叫getOrderInfo维护的人直接崩溃。没法灰度改一个工具的实现所有依赖它的 Agent 全部受影响上线前要全部回归。把 Skill 单独抽出来本质上是在“模型”和“业务能力”之间加了一层标准化的中间层。模型不需要理解订单系统底层是 MySQL 还是 Redis也不需要知道下发工单走的是 HTTP 还是消息队列它只需要知道“这个 Skill 能干什么、需要什么参数、返回什么结果”。这样 Agent 和 Skill 之间就变成了一个相对稳定的契约关系业务代码怎么改都不会影响 Agent 的“认知”。这也是为什么我在腾讯云上做这套东西时宁可前期多花一点时间把 Skill 的接口定义清楚也不愿意图快塞一堆临时函数进去。后面所有项目都能复用这套能力这笔账是算得过来的。2. 服务端 Skill 的接口契约把“干活”变成可调用的服务想清楚了 Skill 的定位接下来最核心的事就是把“干活”这件事定义成一个可调用的服务。这里不是简单写个接口就行接口契约没定好模型再聪明也会用错工具。2.1 输入参数与 Schema 设计AI Skills 的消费方不是浏览器里的前端页面而是模型。这决定了接口的输入输出设计天然面向“机器可理解”而非“人可阅读”。我自己常用的一个设计范式是三步第一步给 Skill 起一个极有辨识度的名字和一句话描述。模型是靠这个名字在工具列表里做匹配的命名含糊等于没命名。比如query_order_status就比getData好一百倍描述里要写明“根据订单号查询当前订单的处理状态适用于用户催单、订单跟踪场景”这种明确的描述能显著降低模型误调用的概率。第二步用 JSON Schema 严格定义入参。参数名要可读类型要严格描述要完整。比如{ name: query_order_status, description: 根据订单号查询订单当前状态适用于订单跟踪、催单处理等场景, parameters: { type: object, properties: { order_id: { type: string, description: 订单号格式为 14 位数字例如 20250101000123 }, include_detail: { type: boolean, description: 是否返回商品明细默认为 false } }, required: [order_id] } }这里有个很容易踩的坑参数的 description 写得越具体模型的参数提取准确率越高。如果你只写“订单号”三个字模型面对用户那句“帮我看看我前天买的那单到哪了”很可能不知道把“前天买的那单”化约成哪个订单号。但如果你说明“订单号格式为 14 位数字用户通常能在短信或订单列表中找到”模型就多了一个推理依据。第三步设计统一的响应结构。我习惯用这样的格式{ code: 0, message: success, data: { order_id: 20250101000123, status: shipping, tracking: SF1234567890 } }不管底层逻辑多复杂返回结构必须统一。这样 Agent 侧解析结果时只需要写一个通用解析器而不是每个 Skill 写一套。2.2 幂等、超时与错误码定义模型调用 Skill 和人在浏览器里点按钮有一个本质区别模型在拿不到明确结果时会倾向于“再试一次”。这是大模型的通病。所以 Skill 服务端必须把幂等性和超时策略设计好不然一个重复提交就能让你的订单系统多出几笔脏数据。幂等性最简单的做法是在参数里加一个request_id服务端收到请求时先查这个 ID 是否处理过处理过就直接返回上一次的结果。这个字段由 Agent 侧在发起调用时生成保证每次模型重复调用传递的是同一个 ID 即可。超时策略上我给 Skill 设定的经验值是普通查询类操作控制在 3 秒以内返回写操作可以放宽到 5 到 10 秒。模型侧的超时应设置得略长于服务端留出网络和排队的时间。如果服务端超时了必须返回一个明确的“超时”错误码而不是返回一段让人摸不着头脑的异常文本否则模型会把异常文本当作正常结果拿去做下一步推理。错误码设计有一个原则宁可多分几个不要一码通吃。我至少会定义这几个错误码含义Agent 侧建议处理方式0成功直接使用 data40001参数校验失败提取缺失参数向用户追问40002业务校验失败直接向用户说明原因50001服务内部异常重新调用一次若仍失败则升级为人工50002上游依赖超时延迟后重试连续两次失败转人工这套设计在第一次上线时可能看不出多大优势等到模型在长链路任务中多次调用 Skill、或者并发量上来之后它的价值会非常明显。排查问题的速度、模型的自愈能力全靠这些细粒度错误码撑着。3. 腾讯云上的 Skill 托管选型云函数、容器还是网关Skill 本质上是无状态的服务托管在哪、怎么暴露给外部调用是整个方案里最需要结合自身情况做选择的部分。腾讯云上常见的路线有三条云函数SCF、容器服务TKE 或 CVM Docker、API 网关。我三条都实测过各自特点非常明显。3.1 三种托管方式的对比与选型我根据自己的项目经验整理了一个对比表维度云函数 SCF容器服务CVM / TKEAPI 网关启动速度冷启动一般几百毫秒到 1 秒热启动毫秒级取决于容器镜像和实例规格取决于后端服务扩缩容自动扩缩按调用次数计费手动或配置 HPA按资源计费可做限流、转发不算计算资源适用场景轻量接口、简单聚合、低频调用复杂业务逻辑、长连接、有状态服务统一入口、鉴权、限流、多后端路由运维成本低几乎不用管服务器需要管理镜像、节点、网络中低需要管理路由配置典型费用结构按调用次数 资源使用量按实例规格 运行时长按调用量 流量我的建议很简单Skill 是轻量查询类、逻辑不复杂选云函数。比如查订单、查天气、查库存这种云函数跑起来毫无压力还省去了运维服务器的精力。Skill 依赖了复杂的运行环境比如需要特定 Python 包、模型推理、音视频处理选容器。把依赖全部打包进镜像环境一致性好不会出现“本地能跑、服务器跑不了”的玄学问题。多个 Skill 需要统一入口、统一鉴权、统一限流前面挂一层 API 网关。网关本身不跑业务逻辑它把请求路由到不同的后端服务上相当于给整套 Agent 能力做了一个统一门面。我在实际项目里最常用的组合是“API 网关 云函数”或者“API 网关 容器服务”。Agent 侧只面对一个网关地址网关根据 path 或 header 把请求转发给对应的 Skill 实现。这样后续加新的 Skill只是多一条路由的事。3.2 Docker 镜像推送与配置一次完整的踩坑记录说到容器就绕不开把本地构建好的镜像推到腾讯云容器镜像服务TCR这一步。我最早在这一步上折腾了小半天问题都不是什么高深原理全是细节。流程本身不算复杂# 1. 本地给镜像打上腾讯云仓库的 tag docker tag my-skill-image:latest ccr.ccs.tencentyun.com/my-namespace/my-skill:latest # 2. 登录镜像仓库 docker login ccr.ccs.tencentyun.com --username 你的腾讯云账号ID # 3. 推送 docker push ccr.ccs.tencentyun.com/my-namespace/my-skill:latest看起来很简单对吧但我第一次推的时候踩了三个坑每一个都让人头大第一个坑登录用户名不是你的登录邮箱也不是你的昵称而是腾讯云账号 ID。很多人在这里卡住拿注册邮箱登录一直报认证失败。实际上控制台里把鼠标悬停在右上角头像上能看到那串数字账号 ID那才是docker login要的用户名密码用的是账号关联的 API 密钥或临时密钥。第二个坑命名空间要先在控制台创建。你本地 tag 里的my-namespace必须是在 TCR 控制台里已经创建好的命名空间不能随便编一个。我见过有人直接写项目名push 的时候报namespace not found又回去翻文档。第三个坑内网环境和公网环境的镜像仓库地址不一样。如果你的 CVM 和镜像仓库在同一个地域建议用内网域名推送速度快、还免流量费。公网域名在本地推送没问题但到了服务器上有时会因为网络策略走不通。这三个坑属于那种“知道了一次之后就再也不会踩”但第一次踩的时候确实能消耗掉大量耐心。我之后的做法是把docker login和docker push写进部署脚本参数自动从环境变量读取尽量减少手敲命令出错的机会。3.3 域名、端口与安全组配置的细节Skill 服务起来之后要让 Agent 能访问到就绕不开域名解析和端口开放的问题。很多人在腾讯云服务器上部署完服务发现从外部访问不了第一反应是“防火墙是不是有问题”然后去控制台把安全组端口全部放通。这里我要给一个明确的建议别开放所有端口务必按需放行。腾讯云服务器本身默认的安全组策略是只放行常用端口比如 22、80、443这是好事。Skill 服务的 HTTP 端口比如 8080、9090默认是不通的需要自己在安全组规则里加一条“放行 TCP 端口 8080”的规则。站在安全角度我一般建议如果 Skill 只给 Agent 调用不直接暴露给公网用户那最好通过 API 网关转发安全组只放行来自网关所在网段的流量。如果有公网访问需求建议用 HTTPS 域名而不是裸 IP端口。申请一个二级域名子域名并在 DNS 解析里加一条 A 记录指到服务器公网 IP再用 Nginx 或网关层做 TLS 终结比直接公网裸奔稳得多。云服务器安全组里的“来源”不要填0.0.0.0/0让全网都能访问能限定 IP 就限定 IP哪怕先限定为自己的出口 IP 或网关 IP 也好。这件事上我吃过一次教训顺手把安全组配成全部放通结果服务上线第二天日志里就全是扫描器的探测记录。后来严格收敛到朗指定源之后干净多了。4. Agent 侧集成让模型真正会用这套 SkillSkill 服务端准备好了并不意味着 Agent 就能用得好。模型怎么知道什么场景用哪个 Skill、怎么把用户的话转成正确的参数、拿到了结果怎么组织成回复这中间还有一道关键的集成工程。4.1 工具描述与上下文裁剪给模型一份精准的“使用手册”大多数 Agent 框架在接工具时都会要求开发者提供工具名、工具描述和参数 Schema。这个环节看似简单恰恰是决定“模型会不会用错工具”的分水岭。我的经验是描述里要写清楚三件事这个工具解决什么问题、什么场景下调用、什么情况下不要调用。反面教材是只写一句“查询订单信息”正面教材是下面这样查询订单状态。当用户询问订单进度、物流信息、发货状态、签收情況时调用。 仅在用户提供明确订单号时适合直接调用若用户只提供了模糊信息如前天下的单 应先用对话引导确认订单号不要调用此工具。加了“不要调用”的边界之后模型在模糊场景下的表现会好很多。因为大模型在不确定时倾向于调用工具“证明自己能干”但你明确告诉它“这种情况不该调”它反而会收敛到先追问用户。上下文裁剪是另一个容易忽略的点。模型上下文窗口再大也不能把所有 Skill 的描述一股脑全塞进去。我现在会先给模型按命名空间或业务域分组在对话前根据用户消息的关键意图做一次粗筛只把可能相关的 Skill 描述挂到工具列表里。比如用户问的是订单问题那就只挂订单相关的 3 到 5 个 Skill而不是把库存、支付、售后、物流的所有工具全部挂上去。这一步能显著降低模型的误调率同时省下大量 token。4.2 多 Skill 编排从单工具调用到组合执行单个 Skill 可以解决一件事但真实业务往往是一个流程。在接收到“帮我取消昨天买的那个蓝牙耳机订单”这种需求时Agent 至少需要拆成三步先定位订单再查询订单状态最后如果订单还没发货才允许取消。这就涉及到多 Skill 的编排。这里我踩过一个大坑早期把编排逻辑写在提示词里让模型自己“看着办”。模型确实有编排能力但稳定性差同一个请求可能今天是“先查订单再取消”明天就变成“直接调取消接口”。后来我把编排分成两层硬流程有严格顺序和依赖关系的步骤放在 Agent 的编排层用代码固定。比如“先查单确认状态为待发货才能调取消接口”这一步不允许模型自由发挥。软决策多条路线都合理的时候才交给模型根据上下文选择。比如查询订单既可以用订单号也可以用手机号让模型根据已有的信息决定用哪个参数。这个“硬编码 软决策”的混合编排模式是我在多次试错后觉得最稳的方案。全软全靠模型结果不可控全硬写死又失去了 Agent 的灵活性。另外多 Skill 协作时还有一个细节后一个 Skill 的参数可能来自前一个 Skill 的响应。这时候要给模型明确的字段映射指引。比如取消订单需要 order_id而这个 order_id 恰好是上一个查询接口返回结构里的data.order_id我会在 Skill 描述里标注“该参数来源于 query_order_status 的返回字段 data.order_id”模型顺着这个提示几乎不会搭错线。4.3 结果回流别让模型把结构化数据原样甩给用户Skill 返回的是结构化 JSON用户看到的不应该是这段 JSON。模型拿到结果之后还需要做一层“翻译工作”把数据结构转成自然语言。比如查询接口返回{ code: 0, data: { status: shipping, tracking_company: SF, tracking_no: SF1234567890, estimated_arrival: 2025-02-02 } }好的回复是“您的订单已经发货啦用的顺丰单号是 SF1234567890预计 2 月 2 日送达。”而不是甩给你一个 JSON 块。这段转化提示词也要写得具体包括哪些字段直接告诉用户status、tracking_no哪些字段要在特定条件下才展示estimated_arrival 只有在下单当天到送达前展示什么情况下需要引导用户做下一步动作订单状态是 signed可追问是否需要售后模型在这方面的表现直接决定了用户体感。同样一个 Skill有的 Agent 用起来像专业客服有的像接口调试工具差别全在这层回流设计上。5. 上线之后的运维与安全从能用到好用Skill 部署上去、Agent 跑通了项目才完成了一半。另一半在于上线之后怎么保证它稳定、安全、可排查。这部分的经验是我在被真实流量毒打之后一点点攒下的。5.1 日志与链路追踪不然出问题只能靠瞎猜Agent 调 Skill 是一次典型的跨系统调用用户输入 → 模型推理 → 框架调度 → 网关转发 → 云函数/容器执行 → 返回结果。任意一环出问题都可能表现为“Agent 回答得不对劲”。如果没有链路追踪排查一个异常可能要翻四五个系统的日志而且彼此之间完全对不上时间线。我的做法是在 Agent 侧生成一个trace_id随 HTTP Header 传给 Skill 服务端。Skill 侧的所有日志都带上这个 IDtrace_id8f3a9c1b 2025-01-20 14:23:01 INFO 参数校验通过 order_id20250101000123 trace_id8f3a9c1b 2025-01-20 14:23:02 INFO 上游订单系统返回 statusshipping trace_id8f3a9c1b 2025-01-20 14:23:02 INFO 响应耗时 120ms这样不管问题出现在哪个环节只要有个 trace_id就能把整条链路的日志串起来。成本很低收益极高。腾讯云上云函数本身自带日志查询容器服务也能接日志服务。我习惯把所有 Skill 的日志统一投递到一个日志主题里按trace_id建索引。排查问题的时候直接在日志平台里搜一个 trace_id从头到尾的调用过程一目了然效率比从前翻服务器的/var/log高多了。另外日志中不要打印敏感信息。身份证号、手机号、支付账号这类字段能脱敏就脱敏。既是为了合规也是防止日志泄露造成安全问题。5.2 限流、密钥管理与安全边界Agent 一旦面向真实用户Skill 就处于“不可信流量”的前沿。防刷、防滥用、防越权这些事不能等出事了再想。限流是第一个要做的。API 网关层我一般会配置两档限流一是按调用方维度限制 QPS防止某个异常用户把后端打爆二是按 Skill 维度限制总流量防止某个 Skill 成为热点后拖垮整个系统。腾讯云 API 网关自带限流插件配置好之后后端服务基本不用关心流量洪峰的问题。密钥管理是另一个重点。Skill 服务里经常要调用第三方 API、访问数据库免不了要存密码和密钥。我见过最危险的做法是把密钥写死在代码里或者放在配置文件的明文里镜像一打包全带出去了。在腾讯云上我现在的标准做法是数据库密码、第三方 API Key 全部放在密钥管理服务里运行时通过 API 读取。云函数或容器运行时关联一个有最小权限的服务角色而不是在代码里保存长期密钥。所有密钥定期轮换轮换时只改密钥管理里的版本不重新发版。安全边界上还要考虑一件事Skill 服务不应该默认信任调用者传过来的数据。参数校验要严格该鉴权的必须鉴权该校验归属的必须校验归属。比如取消订单的 Skill只校验“这个订单号存在”是不够的还要校验“这个订单属于当前这个用户”否则就是一个越权漏洞。模型只是帮你生成参数它可不会帮你做权限判断这个责任得靠业务代码扛。5.3 一个典型的坑Redis 改完密码重启后服务起不来说到密钥和基础服务分享一个我在腾讯云服务器上真实遇到过的坑。本身跟 AI Skills 没有直接关系但它是整套服务链路里最容易卡住部署的环节。当时我在云服务器上装了 Redis准备给 Skill 服务做缓存。装好后修改了redis.conf里的requirepass设置了新密码然后执行redis-server restart。结果 Redis 一直启动失败或者启动了但日志里报NOAUTH Authentication required。更奇怪的是明明改了配置文件redis-cli连上去之后跑CONFIG GET requirepass显示的仍然是旧密码。排查了半天才发现原因Redis 启动时加载的配置文件不是我以为的那个或者 systemd 服务脚本里指定了另一个配置路径。你在/etc/redis/redis.conf里改了requirepass但 systemd 启动的 Redis 实际加载的是/etc/redis/redis.conf.bak或者压根没有显式指定配置文件导致 Redis 以默认配置无密码启动。这个问题排查链路其实不复杂但需要对 Linux 服务管理有一定了解# 先看 Redis 进程的实际启动参数 ps aux | grep redis-server # 看 systemd 服务文件里指定的配置路径 systemctl cat redis # 用命令行验证是否真的加载了目标配置 redis-cli -a 新密码 CONFIG GET requirepass看到实际加载路径之后把修改写到正确的配置文件中再重启问题解决。这个坑我和不少同行都踩过核心教训是不要凭直觉以为“我改了配置文件”要用命令验证进程到底加载了哪个配置。这类基础服务的坑平时看起来跟 AI 关系不大但在真正落地部署 Agent 服务链路时往往会成为最耗时的拦路虎。我后来养成的习惯是所有基础组件Redis、MySQL、Nginx的配置文件统一管理启动命令统一进脚本每次部署后跑一轮排查命令验证状态而不是“看着似乎起来了就行”。6. 一次 0 到 1 的落地复盘可以照搬的最小闭环最后把整个从零到一的过程串一下算是我个人认为比较省力的一套最小闭环路径。这套路径适合第一次在腾讯云上从零搭 Agent AI Skills 的团队我后来好几个项目都沿用了这个节奏。6.1 最小闭环的七个步骤第一步选一个具体业务场景不要贪多。比如“查订单状态”就比“做一整套售后服务机器人”好落地得多。场景越聚焦Skill 的边界越清晰模型越容易用对。第二步定义 Skill 的接口契约。按照前面说的 Schema 规范把输入参数、输出结构、错误码定义好。这个步骤一定要写文档不然后面接 Agent 框架时会来回扯皮。第三步在腾讯云上部署 Skill 服务。轻量场景直接云函数复杂场景用容器。先保证通过 Postman 或者 curl 能直接调用通再进下一步。第四步把 Skill 描述接入 Agent 框架。用框架提供的工具注册机制把 Skill 的名字、描述、参数 Schema 挂上去先用简单对话验证模型能不能正确调用。第五步逐个打磨模型对 Skill 的使用效果。测试不同问法下模型的参数提取能力调整 Skill 描述直到模型在绝大多数情况下都能给出正确参数。第六步加入多 Skill 编排。从两个 Skill 开始先把硬流程用代码固定再把软决策交给模型。第七步上线前补上运维三件套日志链路、限流配置、密钥管理。把安全边界的最后一块补上然后再放流量。这套路径走下来通常一到两周就能看到一个能真实干活的 Agent。我自己的体会是最难的不是写代码而是克制住“再加一个功能”的冲动。每多塞一个 Skill模型的调度难度就上一点后续的回归测试工作量也大一截。Skill 的边界守得住Agent 的稳定性才守得住。6.2 关于 Skill 持续演进的几条建议等第一版跑起来之后Skill 的运营才真正开始。我自己总结了几条经验给每个 Skill 加版本号。更新时先灰度一部分流量确认无误再全量。模型面向的是真实用户一个 Skill 的故障会直接表现为 Agent 胡说八道。建立 Skill 效果评估集。拿一批真实用户问题每次改完 Skill 描述或实现之后跑一遍回归对比正确调用率。这个数据集会越攒越值钱。关注模型误调用的日志。如果模型经常在不需要查询的时候调了查询 Skill或者反复传错参数说明 Skill 描述里的边界写得不够清楚需要回炉优化。Skill 之间尽量解耦。不要让一个 Skill 内部去调另一个 Skill 的接口这种跨层调用会形成隐式依赖出问题的时候排查链路会变得很长。项目前期这种设计看起来省事到了后期都是技术债。在这种模式下Agent 本身反而有点像一张“会思考的嘴”真正干活的是那几只不断打磨的“手”。把手上的肌肉练扎实了嘴才能说到做到。最后再分享一个我在实际使用中建立的习惯每当遇到模型调用 Skill 出错我不急着去改提示词碰运气而是先把整条链路的日志翻出来定位到底是模型理解错了、参数传错了、还是服务端返回有问题。把每次出错的根因记下来攒一段时间再回头看你会发现模型行为规律其实很清晰改起来也更有方向。这套“以日志为老师”的办法比拍脑袋调参靠谱得多。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →