资讯动态

腾讯云AI Agent实战:AI Skills体系从设计到部署

发布时间:2026/9/8 15:20:45 来源:尧图企业网站定制
在做腾讯云上的 AI Agent 项目之前我一直以为 Agent 就是一个更聪明的聊天框。你给它一个问题它给你一个答案顶多再带点联网搜索。但这个项目做到后面我发现真正让 Agent 从“演示玩具”变成“生产助理”的不是模型智商而是它身边那套 AI Skills 体系。Skills 决定了 Agent 能不能真正调用云资源、查监控、发消息、执行任务。这篇文章我会用自己在腾讯云上从零搭 Agent 的经历把 AI Skills 的划分、注册、调度、部署和排障讲清楚适合已经在用大模型 API、想开始做 Agent 工程化的人参考。如果你正准备在腾讯云上跑一个能稳定干活的 Agent这篇应该能帮你省掉不少试错成本。1. 先把 Agent 的“身体”搭对Skills 和腾讯云的分工1.1 单模型 Prompt 的极限逼我转向 Skills我一开始的做法特别天真写一个超长 system prompt把所有功能描述、处理规则、返回格式全塞给大模型。用户说“帮我看看服务器磁盘”我就期待模型在文本里给出答案。但真正跑起来以后问题立刻暴露出来。一旦任务涉及多步骤比如“检查几台服务器的磁盘使用情况顺手把超过 80% 的日志清理掉”模型就经常出现两种情况一是只给出建议不真正执行动作二是返回格式千奇百怪我在后端不得不写一堆正则去猜它到底想干什么。这种方案说白了就是把 Agent 当成一个“文本生成器”而不是一个“任务执行器”。后来我把思路换了一下模型只负责“判断该调用什么技能、填什么参数”具体的动作交给一段段独立的 Skills 去执行。技能可以是 Python 函数、HTTP 接口、命令行脚本也可以是腾讯云的各种 API 封装。模型拿到了用户的请求后先从注册表里选一个最匹配的技能按照预定 schema 输出参数然后我这边执行技能再把结果返回给模型让模型整理成用户能看懂的答复。这个循环就是 Agent 的核心骨架比单纯堆 prompt 要可靠得多。1.2 Skills 到底是什么以及它和“工具调用”的区别很多框架里已经有类似的概念比如 function calling、tool calling甚至 Claude 生态里的 Skills。本质上它们是同一个东西让模型不止会“说”还会“做”。我给 Skills 定的标准是一个完整的技能必须包含四部分名字、描述、参数定义、执行逻辑。名字和描述是给模型看的参数定义决定模型怎么填参数执行逻辑才是真正干活的部分。比如说“查询 CVM 实例列表”这个技能模型看到描述里写了“可用于查询云服务器、实例、CPU 使用情况”之后就会在合适的时机触发它并按要求补上地域、数量这些参数。Skills 和普通“工具调用”的区别我觉得在于描述方式。工具调用经常只给一个抽象的函数名但 Skills 更强调“使用边界”。一个技能描述里不仅要写它“什么时候用”还要写它“什么时候不要用”这样模型才不会瞎选。例如一个“查询实例列表”的技能描述里就应该明确说“当用户想查看云主机、轻量服务器、实例 ID、公网 IP 时使用当用户只是解释概念时不要用”。这些细节看起来不起眼但对模型选对率的影响非常大。我在一次测试里只修改了几个技能描述模型技能选择的准确率就从 67% 提到了 91%。1.3 腾讯云在整套体系里提供的其实是一副“骨架”有人可能会问Agent 开发不是有大模型就行了吗为什么非要扯上腾讯云我的回答是大模型只能给智慧和决策但 Agent 要真正落地必须有地方跑代码、有地方存状态、有地方暴露接口、有地方看日志。腾讯云在这套体系里提供的不是“现成的 Agent”而是 DevOps 层面的能力云服务器或轻量服务器负责跑调度器Redis 负责存会话状态API 网关负责把 Agent 暴露给外部调用方容器镜像服务负责分发部署包日志服务负责全链路追踪。我选择腾讯云并不是因为它有什么特殊的 Agent 黑魔法而是因为它的基础组件刚好覆盖了 Agent 工程化最需要的几块而且这些组件之间内网互通延迟很低。如果你的 Skills 需要频繁调用云上的 CVM、监控、短信、对象存储这类服务把 Agent 部署在同一个云环境里比本地开发打 API 到公网省非常多事情。尤其在做多轮对话时Agent 每轮都要读写 Redis如果 Redis 不在同一网络环境延迟会非常刺眼。所以我的建议是先确定 Agent 要调用哪些云资源再决定把运行时部署在哪里而不是反过来。2. 技能拆分与注册表让 Agent 能“看见”自己的手2.1 技能粒度怎么定从用户意图反推而不是按系统模块技能拆分的粒度是整个项目里最容易返工的地方。我一开始按系统模块拆创建订单、查询订单、修改订单、删除订单一个个列得清清楚楚。但模型经常选错。用户说“把这个订单换成另一个规格”模型就不知道该调“修改”还是“删除”还是“重新创建”因为用户的表达不会天然对齐你后端的模块划分。后来我把技能改成按用户意图拆换货申请、取消订单、物流查询。这么一改模型的选择一下子清晰了很多。我总结出来的标准是从用户一句话里的“目的”出发而不是从系统的“功能”出发。你问自己如果用户说“我想知道我的服务器最近状态如何”他希望得到的是数据列表、告警通知还是操作入口这个希望对应一个独立动作就拆成一个技能。粒度太细会导致模型面对一堆近义词技能时选择困难太粗又会导致一个技能内部塞满一堆分支逻辑维护成本暴增。我的实操经验是一次用户请求最多给模型呈现 15 个技能描述再多模型就开始乱选。如果你的需求超过 15 个那就用 embedding 检索先筛一遍而不是一股脑塞给模型。2.2 注册表数据结构以及模型如何“看到”技能技能注册表其实就是一份结构化的清单我直接用 Python 里的列表加字典来维护。每个技能的核心结构长这样SKILLS [ { name: get_cvm_instance_list, description: 获取腾讯云 CVM 实例列表。当用户想查看云服务器、实例、CPU、内存、公网 IP 等信息时使用。注意只负责查询不负责创建或删除实例。, parameters: { type: object, properties: { region: { type: string, description: 地域如 ap-guangzhou可选默认 ap-guangzhou }, limit: { type: integer, description: 返回的实例数量上限默认 20, minimum: 1 } }, required: [] } }, { name: send_sms, description: 发送短信通知。当用户要求向指定手机号发送验证码、通知或告警时使用。禁止用于发送营销或其他骚扰类内容。, parameters: { type: object, properties: { phone: {type: string, description: 接收短信的手机号必须为 11 位数字}, content: {type: string, description: 短信内容需匹配审核模板} }, required: [phone, content] } } ]这个注册表要转成大模型 API 能识别的tools格式我写了一个小函数做映射。关键点在于字段名和描述必须稳定。我见过很多人把技能描述写得特别随意结果模型才过一轮就忘了。正确做法是每次请求都把最新注册表传给模型不要只传一次就让模型“记住”。模型没有记忆每一次用户消息都要重新提供可选项。对于技能数量不多的项目全量注册表就够了。数量超过 20 个后我会先用标题和描述做向量检索拿出 top 8 到 10 个技能再传给模型。这里有一个容易忽略的细节检索用的是“技能描述文本”而不是“技能代码”所以描述写得好不好直接影响检索质量。我踩过坑当时一门心思优化代码忽略了描述文本结果很多技能模型根本没被检索到后来把描述统统重写一遍效果立竿见影。2.3 用 Redis 接管会话上下文顺带解决一个重启故障Agent 的多轮对话不能只靠模型上下文窗口状态必须落到外部存储。我用腾讯云 Redis 存 session 上下文键是session_id值是序列化后的 JSON里面包含历史消息摘要、最近一次技能执行结果、用户偏好等。这样即使 Agent 服务重启用户也能接着上一轮继续聊。Redis 在这里不是缓存而是真正的工作存储所以我会给每个键设置合理的 TTL防止内存无限膨胀。说到 Redis我 must 分享一个真实事故。当时我在云服务器上装了 Redis修改了密码之后重启 Redis 服务一直不成功systemctl状态显示 failed但看服务日志又不像端口占用。最后还是通过journalctl -u redis看到了NOAUTH Authentication required的报错。我一度以为是新密码没有生效后来排查才发现是 systemd 的 override 文件里通过环境变量传了一个旧密码给启动脚本而客户端连接时又用旧密码去认证自然过不去。解决办法很简单把/etc/systemd/system/redis.service.d/override.conf里的密码改成和redis.conf一致再systemctl daemon-reload重启。这个经验提醒我改密码不是改一个文件就完事所有依赖 Redis 的服务都得同步检查尤其是 Agent 的.env、LiteLLM 的配置、还有 systemd 里的启动参数。2.4 一份可以直接抄的技能注册清单为了方便你起步我把一个真实项目里常用的技能清单简化后放在这里。它不一定适合所有业务但字段结构和描述方式可以借鉴。技能名触发场景入参后端操作超时get_cvm_list用户查询云服务器、实例、公网 IPregion, limit腾讯云 CVM DescribeInstances API3 秒get_monitor_data用户查询 CPU、内存、磁盘监控曲线instance_id, metric, start_time, end_time腾讯云云监控 API3 秒send_sms用户要求发验证码、通知、告警phone, content腾讯云 SMS API5 秒upload_to_cos用户上传附件到对象存储bucket, object_key, file_path腾讯云 COS SDK10 秒confirm_operation高风险操作前向用户确认operation, detail生成一次性确认令牌2 秒这份清单里每个技能都必须有明确的后端实现不能只留一个空壳。我最开始做的时候很多技能只有一个“占位符”返回 hardcode 的结果给模型。小程序演示没问题一上真实流量就露馅。所以我的建议是宁可只有 5 个真实可用的技能也不要规划 20 个“看起来有用”但根本没实现的技能。3. Agent 调度核心从消息到动作的完整链路3.1 用函数调用协议把模型输出变成可执行动作现在主流大模型 API 都支持函数调用也就是function calling。这比让模型输出 JSON、再自己写解析器要稳定得多。做法很简单把技能注册表映射成 API 的tools模型在合适的时机返回tool_calls。以下是我在 Agent 循环里最核心的一段调用逻辑response client.chat.completions.create( modelMODEL_NAME, messagesmessages, tools[{type: function, function: skill_to_tool(s)} for s in SKILLS], tool_choiceauto ) message response.choices[0].message if message.tool_calls: for tool_call in message.tool_calls: result execute_skill( tool_call.function.name, tool_call.function.arguments ) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse) }) # 拿到技能结果后让模型把结果“翻译”成用户能懂的话 messages.append(message) final_respond client.chat.completions.create( modelMODEL_NAME, messagesmessages, tools[{type: function, function: skill_to_tool(s)} for s in SKILLS], tool_choicenone ) return final_respond.choices[0].message.content我把这个循环封装成一个run_agent_loop函数它的职责很纯粹发消息给模型看模型要不要调用技能如果要就执行然后把结果塞回去再让模型继续直到模型不再请求技能才把最终文本返回给用户。这里最容易被忽略的是技能执行结果一定要通过roletool传回去而不是直接拼进 system prompt。我早期偷懒拼接结果模型经常混淆“技能返回的数据”和“用户原话”逻辑混乱到没法看。3.2 Skills 执行器的健壮性设计执行器是连接模型和后端动作的中转站如果它不够健壮Agent 再聪明也白搭。我写的执行器很简单但包含了几条硬性规则SKILL_MAP {skill[name]: skill for skill in SKILLS} def execute_skill(name, arguments): skill SKILL_MAP.get(name) if not skill: return {success: False, error: no such skill} try: params json.loads(arguments) if isinstance(arguments, str) else arguments handler skill.get(handler) if not handler: return {success: False, error: handler not registered} result handler(**params) return {success: True, data: result} except TypeError as e: return {success: False, error: f参数错误: {e}} except Exception as e: return {success: False, error: str(e)}规则有三条。第一每个技能必须有超时控制方法是在 handler 外层加一个functools.wraps装饰器或者用asyncio.wait_for超时后立刻返回错误不能让技能调用卡死整个 Agent 循环。第二返回给模型的结构必须固定不管成功失败都要包含success字段失败时把错误信息放在error字段。模型很擅长把错误信息翻译成用户友好的话但这需要结构化输入。第三对未知技能名和未知参数要宽容处理宁可返回错误让模型换一个技能也不要抛异常把整个进程打挂。这里我还加入了“技能调用频控”的概念。比如send_sms这样的技能我会在 handler 里检查同一个手机号在 60 秒内是否已经发过验证码。如果是就直接返回success: false和提示文本防止用户手贱连点导致短信费用飙升。频控逻辑我没放在模型层因为模型不可控必须放在执行器或者云服务层。3.3 把腾讯云 API 封装成 Skill一个 CVM 实例查询的例子下面是一个完整的技能实现示例。目标很直接用户问“帮我查一下广州区域的云主机列表”模型调用get_cvm_list执行器去腾讯云查数据最后把实例 ID、名称、IP、状态返回给模型整理。from tencentcloud.common import credential from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.cvm.v20170312 import cvm_client, models def get_cvm_list(regionap-guangzhou, limit20): # 密钥从环境变量读取不要硬编码进代码 cred credential.Credential( os.environ[TENCENTCLOUD_SECRET_ID], os.environ[TENCENTCLOUD_SECRET_KEY] ) http_profile HttpProfile() http_profile.endpoint cvm.tencentcloudapi.com client_profile ClientProfile() client_profile.httpProfile http_profile client cvm_client.CvmClient(cred, region, client_profile) req models.DescribeInstancesRequest() req.Limit limit resp client.DescribeInstances(req) instances [] for item in resp.InstanceSet: instances.append({ instance_id: item.InstanceId, name: item.InstanceName, private_ip: item.PrivateIpAddresses[0] if item.PrivateIpAddresses else , public_ip: item.PublicIpAddresses[0] if item.PublicIpAddresses else , status: item.InstanceState, }) return instances然后把 handler 注册进技能字典skill_entry { name: get_cvm_list, description: 获取腾讯云 CVM 实例列表。当用户想看云服务器、实例、公网 IP、状态时使用不支持创建或者删除实例。, parameters: { type: object, properties: { region: {type: string, description: 地域如 ap-guangzhou}, limit: {type: integer, description: 返回数量默认 20} }, required: [] }, handler: get_cvm_list, } SKILLS.append(skill_entry)这套模式的通用性很强。不管你是查监控、发短信、上传文件还是操作数据库核心逻辑都一样模型填参数执行器调 SDK把结果转成结构体返回。这样 Agent 不需要知道腾讯云 SDK 里面有多少种请求对象它只需要知道技能名和描述剩下的全部是确定性代码。3.4 用 LiteLLM Proxy 统一模型入口降低迁移成本项目做到中期我开始嫌直接调用各家模型 API 太麻烦。不同供应商的模型请求格式、超时定义、错误码都不一样每次换模型都要改一遍 Agent 代码。后来我在腾讯云的云服务器上跑了一个 LiteLLM Proxy把用的几个模型全部统一成 OpenAI 兼容格式。Agent 只认一个base_url底层是混元、千问还是别的模型对 Agent 透明。LiteLLM 的配置大概长这样model_list: - model_name: hunyuan-pro litellm_params: model: tencent/hunyuan-pro api_key: os.environ/HUNYUAN_API_KEY - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY启动之后Agent 的client只需要设置base_urlhttp://127.0.0.1:4000就能切换模型。这个组件对多 Agent 项目很有用尤其是你想对比不同模型做技能选择的效果时一个 Proxy 就能统一入口。它的一个隐藏坑是模型名称配置错误时会直接 401排查时需要看 Proxy 日志而不是只看 Agent 日志。还有一个和 Redis 类似的问题如果 LiteLLM 所在服务需要连接 Redis 做缓存那么改 Redis 密码后也要同步更新 LiteLLM 的环境变量否则全部请求都会报认证错误。这个我在 2.3 节已经踩过了现在改密码前会先列一张“依赖清单”。4. 部署到腾讯云容器镜像、网关和实测排障4.1 Docker 镜像构建与推送到容器镜像服务Agent 服务我用 Docker 打包。Dockerfile 写得非常简单但已经能满足大多数场景FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . ENV PYTHONUNBUFFERED1 CMD [python, main.py]本地构建并推送到腾讯云容器镜像服务时命令大概是这样的docker build -t ccr.ccs.tencentyun.com/my-namespace/my-agent:latest . docker login ccr.ccs.tencentyun.com --username你的腾讯云账号ID docker push ccr.ccs.tencentyun.com/my-namespace/my-agent:latest这里有一个非常实用的经验云服务器和镜像仓库选同一个地域然后用内网地址推送速度比公网快很多也不容易因网络超时失败。推送完成后我直接在 CVM 上docker pull再启动。如果用的是腾讯云的容器服务或轻量云也可以在控制台直接创建服务指定镜像地址就行。我建议把镜像打上带版本号的 tag而不要只打latest。后期出问题要回滚时你能明确知道线上跑的是哪一版代码。4.2 API 网关作为 Skills 的统一出口Agent 服务如果只是本地跑那还叫演示。要真正接入 App、小程序或运维平台就要把接口暴露出去。我用腾讯云 API 网关作为统一入口后端指向运行 Agent 的内网 IP 端口。网关负责了 TLS 证书、鉴权、限流和一部分安全防护Agent 服务本身可以保持在内网环境不直接暴露到公网。API 网关在处理 Agent 这种对话式请求时有一点需要特别注意接口超时时间要设得足够长。大模型推理本身就有延迟Agent 循环还可能调用多个技能如果网关超时设成 10 秒很可能模型还没回答完就被网关截断。我的做法是把同步请求超时设在 60 秒以上同时在前端做流式输出或者轮询。如果你做的是实时流式 Agent网关还需要支持 WebSocket 或 SSE否则体验会很差。我这次项目走的是普通 HTTP 轮询简单可靠够用就好。4.3 实测中三个最隐蔽的坑第一个坑就是前面反复提到的 Redis 密码不同步。我再补充一个细节如果你用了 systemd 管理 Redis除了 override.conf 之外还要看 Redis 主配置里的bind、protected-mode是否限制了内网访问。Agent 服务在另一台机器上要通过内网连 Redis如果只改密码没改 bind会连接超时容易误判成密码错误。排查顺序我建议先从客户端本地redis-cli -a 新密码 ping试起再沿着服务端配置逐步查。第二个坑是技能内部超时缺失。我一开始只在执行器外层做了一个全局超时结果某个技能内部调用的第三方 API 卡住了 50 秒把整个 Agent 循环拖死。后来我给每一个 handler 单独设置超时比如查询类技能 3 秒发送类技能 5 秒文件上传类 10 秒。这里没有银弹不同操作的成本和响应时间完全不同必须按技能去调优。第三个坑是并发重复执行。用户在网络波动时通常会对同一个操作点多次提交如果技能不是幂等的就会产生重复资源或者重复扣费。我后来在 Redis 里放了一把简单的分布式锁以request_id为 key使用SET NX EX 30保证同一个请求只执行一次。第二次请求进来时直接返回“该操作正在处理中”而不是再次触发技能。就这么一个简单的锁线上减少了很多重复告警。有一个细节这个request_id必须在入口层生成并且透传到所有技能调用中否则锁就没有意义。5. 从“能跑”到“好用”我给 Agent 定下的四条规矩5.1 限定能力域做“专才”而不是“全才”很多 Agent 项目失败的原因不是能力不够而是想做的事情太多。我的项目只保留了三类技能云资源查询、消息通知、文件处理。用户问天气、问八卦、让写诗Agent 会明确说“这个我不会”。这不是在打压 Agent 潜力而是减少模型在技能选择上的错误空间。技能列表越短模型的选择准确率越高用户体验反而更好。我后来在 system prompt 里加了一句话“你是一个云资源运维助理只处理与服务器、监控、通知相关的任务其余问题请礼貌拒绝。”整体表现立刻稳定下来。“全能”这个词其实有另外一层含义不是所有话题都能聊而是在自己负责的领域内任务完成的深度和可靠度足够高。所以我建议你也先列出业务里最高频的 10 个动作把它们的准确率打磨到 95% 以上再谈增加新技能。半吊子的技能越多越容易干扰模型判断。5.2 技能描述是写给模型看的不是写给人看的这是我在整个项目里收获最大的一条经验。当初我把技能描述写成标准的接口文档风格比如“获取云服务器实例列表返回 JSON 数组”模型照样选错。后来我改成了用户意图导向的描述“当用户想查看云服务器、实例、CPU、内存、公网 IP 时使用当用户只是解释概念时不要使用。”模型的选择准确率明显提升。区别在于前者描述的是“我能做什么”后者描述的是“用户什么时候会想让我做”。模型本质上是在做意图分类所以描述必须贴近真实用户的表达而不是贴近开发者的技术文档习惯。我整理描述词的时候会先用 50 条典型用户语句跑一遍看哪些句子匹配错了技能然后针对错误反过来改描述。比如用户说“我的机器是不是被攻击了”我一开始把它匹配到了“查询实例列表”后来发现用户其实是想要安全告警于是我把“查询安全告警”技能的描述改成“当用户怀疑服务器被入侵、攻击、异常登录时使用”这个问题就解决了。技能描述是需要持续迭代的数据资产千万别当成一次性文档。5.3 给拒绝路径留好接口一个稳定的 Agent一定要知道什么时候说“不”。比如用户说“把生产环境数据库删了吧”如果模型直接调用了一个带删除能力的技能后果不堪设想。我在系统里专门设计了一个confirm_operation技能。当模型识别到高风险操作时先调用这个技能把一个二次确认链接或者确认码发给用户用户确认后技能才会返回允许继续的信号。如果用户没有确认后续执行技能会直接失败。这套机制的价值在于它把“人机共识”环节显式化了。模型不需要自己判断“这个请求是否危险”它只需要判断“这个请求属于高风险类别”然后走确认流程。我还在描述里写了明确的规则“涉及删除、更新生产环境、发送短信、产生费用等操作必须调用 confirm_operation 获得用户确认后才能继续。”这样一来模型面对风险请求时就有了一个标准动作而不是在回答里打嘴炮。5.4 可观测性是 Agent 的第五项技能最后我想强调的是Agent 的调试比普通后端服务难得多。因为同一个用户请求模型可能走不同的技能分支你很难直接从最终回答判断它中间经历了什么。所以我在入口层生成一个全局trace_id然后把它塞进所有日志、Redis 键、API 调用上下文里。腾讯云日志服务里按trace_id搜索就能看到一次完整请求的链路模型收到了什么消息、选了什么技能、参数是什么、技能返回了什么、模型最终怎么回复的。我在开发阶段几乎每天都查日志。有一次 Agent 老是答非所问打开日志发现模型把“查询 CPU 监控”和“查询实例列表”两个技能都调用了然后把两份数据混在一起用。发现问题后我把两个技能的描述边界重新写清楚问题立刻解决。没有可观测性这种问题只能靠猜。我甚至做了一个简单的告警当技能错误率超过 10% 时日志服务会发消息通知我让我能及时介入而不是等用户来投诉。最后说点个人体会。把一个 Agent 养成“全能”的过程其实跟训练一个新人很像先给他划定职责范围把操作手册写成他能看懂的样子再给他准备几件称手的工具然后盯着他的每一次操作错了就复盘。Skills 就是那本操作手册和工具箱。腾讯云上这些组件没什么魔法真正花时间的是把每个技能定义得足够清楚把状态、超时、幂等这些细节做扎实。我的建议是先在腾讯云上跑通一个最小闭环一个调度器、两个技能、一个 Redis、一个容器然后再慢慢加能力。你会发现自己培养出来的不是一个会聊天的模型而是一个真的能帮你干活的下属。

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

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

免费获取报价