腾讯云AI Skills实战:打造全能Agent的技能体系与工程实践
我前后在两个项目里踩过完全相同的坑提示词里塞了一堆“你会调用XX工具”“你可以做XX事”结果Agent一问三不知或者该调工具的时候开始胡编。后来把技能体系结构化配合腾讯云上的AI Skills实践才算真正把Agent从“能聊”养成了“能干活”。这篇就完整分享一下我搭建、部署、迭代这个全能Agent的全过程包括技能设计、云端环境配置、模型接入、记忆管理以及上线后的排错思路适合正在做Agent落地的开发者参考。1. 为什么Agent需要技能体系从“能聊天”到“能办事”的坎1.1 提示词驱动的Agent为什么一上生产就露馅先说个很常见的场景。很多人第一次做Agent习惯把所有能力描述都堆在System Prompt里比如“你可以查询天气”“你可以操作Redis”“你可以生成周报”。Demo阶段跑起来确实像模像样模型能根据对话内容“自由发挥”看起来什么都会。但一旦接上真实业务问题就冒出来了输出格式不稳定该返回JSON的时候夹带Markdown工具调用混乱明明只需要查一个字段它把整个接口调了一遍还带副作用更麻烦的是没有权限边界提示词里写了能操作Redis它就可能真的去执行一些危险命令。这里面的根本原因在于提示词只是“描述能力”而不是“定义能力”。模型对技能的理解完全靠语义猜测没有明确的触发条件、参数约束、执行步骤和失败处理。生产环境需要的不是“看起来会”而是“稳定地做对”。我最早那个对话机器人就是活生生的例子用户问“帮我看看服务器内存”它能回答出一个看起来合理、实际上完全编造的数值。这种Agent别说全能连基本可用都谈不上。1.2 Skill、Tool、Agent三者的边界别再混为一谈热词里很多人搜“skill和agent的区别”“tool和skill的区别”这个确实需要先理清楚否则后面设计技能体系会一团乱麻。我习惯用这样一个分层方式来理解Tool是单一功能接口输入输出确定。比如“查询天气API”“执行shell命令”“发一封邮件”。它不关心业务只负责把一件事情做对。Skill是面向一个任务域的完整能力组合。它包含触发条件、执行步骤、依赖哪些Tool、参数Schema、输出规范、失败处理甚至包含该场景下的提示词语气。一个Skill可以理解成“一组Tool加上执行策略和边界”的打包。Agent是运行时大脑。它负责理解用户意图、决定调用哪个Skill、管理多轮上下文、执行技能编排并在技能返回结果后组织回复。三者的关系用生活化类比来说Tool像工具箱里的具体工具Skill像一本“操作手册”告诉你怎么用几个工具完成一件完整的事Agent则是那个阅读手册、判断当前该干什么的工人。很多项目失败就是因为把Agent直接做成了“一堆Tool的集合”跳过了Skill这一层导致模型每次都不知道按什么流程执行。1.3 腾讯云AI Skills的定位把技能做成“一等公民”腾讯云的AI Skills实践最核心的变化就是把“技能”从提示词里拆出来做成平台层可注册、可路由、可观测的独立单元。我不需要自己维护一套复杂的提示词编排引擎技能的定义、注入、调用跟踪都可以在云端统一管理。选择在腾讯云上做这件事还有一个实际考虑Agent不是只有一个对话接口它通常还要连数据库、读对象存储、触发云函数、调用容器服务。腾讯云的AI Skills和这些云资源在同一个账号体系下打通起来方便很多。比如我在一个技能里编排了“读取COS上的日志文件→调用模型分析异常→把结果写入Redis缓存→返回结构化报告”这几个步骤涉及对象存储、模型推理、缓存服务靠本地代码自己去对接也不是不行但要处理鉴权、网络、重试、监控一堆事。把技能放在云端统一托管之后这些基础问题平台已经解决了一部分我只需要专注业务设计。2. 腾讯云上的Agent地基服务器、域名与镜像仓库的标准化配置2.1 二级域名申请与解析给Agent的每个入口单独划地盘Agent部署到云端后绝不会只有一个访问入口至少有Webhook回调、API网关、管理后台、OAuth跳转地址这几个。我强烈建议用二级域名把它们分开而不是全部挂在主域名下。原因很简单不同入口的暴露面不同、安全策略不同、证书管理维度也不同。腾讯云上的实际做法并不复杂。我以agent.example.com为例在DNSPod里添加解析记录把二级域名通过CNAME或A记录指向云服务器公网IP。需要注意如果你要用HTTPS记得先完成主域名的ICP备案否则腾讯云的SSL证书申请和负载均衡配置都会被卡住。这块很多人容易忽略域名解析配好了但证书一直签不下来查了半天是备案问题。实际项目中我习惯这样规划子域二级域名用途是否公网暴露api.agent.example.comAgent核心API服务是仅开放必要端口webhook.agent.example.com外部系统回调入口是加签名校验admin.agent.example.com管理后台否仅内网或白名单broker.agent.example.com消息队列或流式接口视架构而定这样隔离的好处是某个子域对应的服务被攻击或需要下线时不会影响到其他入口。运维上也能针对不同子域配置不同的WAF策略和限流规则。2.2 Docker镜像推送到腾讯云容器镜像服务Agent服务本身我选择容器化部署镜像统一放在腾讯云容器镜像服务里。这里有一个完整的推送链路第一次接触的人可能会在登录这步卡住。登录命令是docker login ccr.ccs.tencentyun.com --username你的腾讯云账号ID注意用户名不是你登录腾讯云控制台的邮箱或昵称而是账号ID。密码不是登录密码而是访问凭证里生成的密钥。在控制台“容器镜像服务-访问凭证”页面可以创建复制下来用于docker login。推镜像前先打标签把本地镜像和远程仓库地址对应起来docker tag agent-core:0.3.2 ccr.ccs.tencentyun.com/namespace/agent-core:0.3.2 docker push ccr.ccs.tencentyun.com/namespace/agent-core:0.3.2这里有一个核心经验不要用latest标签。Agent服务迭代很快但生产环境需要的是可回滚的确定性版本。我习惯把版本号打进镜像标签和代码仓库的Tag里保持一致出现线上问题可以精准回退到上一个版本。同时在镜像仓库里开启漏洞扫描基础镜像一旦发现高危漏洞可以第一时间定位到哪些运行中的服务受影响。2.3 Redis改密码重启失败的完整排查链路热词里有人提到“在腾讯云服务器上安装Redis修改密码之后再重启Redis就一直不行”这个问题我遇到过不止一次而且每次原因都不一样。这里把完整的排查链路写出来大家可以直接照着走。第一步确认你改的密码到底有没有生效。Redis的配置优先级是命令行参数 配置文件 默认配置。如果你启动时用了redis-server --requirepass oldpass那么就算改了redis.conf里的requirepass重启后用的还是命令行参数里的旧密码。第二步重启失败先看日志。systemd管理的话systemctl status redis journalctl -u redis -n 100日志里最常见的是# Warning: config file permissions或者Cant open the log file: Permission denied前者说明配置文件权限不对后者说明日志目录的所有者不是redis用户。第三步一个极其隐蔽的坑密码里带着特殊字符。比如密码里包含$、、!在systemd的EnvironmentFile或者shell命令行里会被解析成变量或控制符号导致实际写入的requirepass和预期不一致认证永远失败。这个问题排查起来最折磨人表面上看密码改对了实际上Redis进程读到的是被截断的字符串。最终我的做法是密码统一由随机工具生成放在单独的文件里systemd用EnvironmentFile注入同时redis.conf里关闭protected-mode但bind到内网IP而不是0.0.0.0安全组层面只放行特定来源IP。改密码后重启的验证方式也别用交互式redis-cli而是直接跑redis-cli -h 127.0.0.1 -p 6379 -a $REDIS_PASSWORD ping能返回PONG才算真正成功。这套流程跑通之后我的Agent会话缓存服务再也没出现过重启失联的问题。3. 设计一套可复用的AI Skills注册、路由与编排3.1 Skill元数据描述信息就是给LLM看的“说明书”腾讯云AI Skills里每个Skill的本质是一份结构化的元数据。我见过很多人写技能定义时参数、步骤都写得很全唯独description随便糊弄一句结果意图路由一塌糊涂。这里要特别强调description不是给人看的注释是给LLM判断“什么时候该调用这个技能”的关键依据。我目前使用的Skill元数据结构大致如下{ name: server_inspection, description: 对云服务器进行基础巡检包括CPU、内存、磁盘和Redis状态采集。适合用户询问服务器负载、磁盘空间或Redis运行状态时使用。不适合处理日志分析或代码部署请求。, trigger_examples: [ 帮我看看服务器负载, 检查一下Redis还正常吗, 磁盘是不是快满了 ], params: { target: { type: string, enum: [cpu, memory, disk, redis, all], description: 巡检范围默认all } }, steps: [ collect_metrics, call_llm_analyze, generate_report ], timeout_secs: 30, error_handler: report_partial_result }关键点在于description里的“适合”和“不适合”两个半句。前者告诉模型什么时候该用后者告诉模型什么时候别用。这个负向描述非常有用能大幅降低误触发率。我在另一个技能上做过对比description里加了“不适合处理XX场景”之后误调用率从17%降到4%左右。3.2 意图路由与技能编排Agent怎么决定下一步调谁多个Skill注册上去之后Agent面临的核心问题就是路由。目前实践中效果好的是“LLM函数调用 规则约束”的组合方式优先通过结构化函数调用让模型选择技能同时对高风险技能加一层规则校验。比如“执行shell命令”这类技能LLM可以选中它但最终是否放行还需要经过预定义命令白名单校验。技能编排方面我建议把“单个Skill内部多步执行”和“多个Skill之间流转”区分开。前者是技能内部的编排可以使用状态机后者是Agent层面的编排更像一个DAG流程。举个例子我的“服务器异常诊断”流程是这样的Skill A采集服务器基础指标如果磁盘使用率超过80%自动触发Skill B分析大文件目录Skill B的结果作为上下文传给模型生成诊断结论结论写入消息队列同时推送给管理员Webhook这种跨技能流转在AI Skills平台里可以直接用工作流定义。我在实践中的体感是复杂流程不要全部塞给模型自由规划能用编排固定下来的步骤就固定下来。模型擅长的是理解意图和生成文本不擅长每一步都稳定执行。3.3 技能内的状态机设计一次技能调用不是一把梭单个技能内部我同样不建议写成一长串流水线代码。尤其是涉及外部依赖的步骤比如下载文件、调用模型、写数据库每一步都可能失败或超时需要明确的执行状态。我用的是一个非常轻量的状态机核心状态只有四五个状态含义允许流转到pending技能被触发等待执行runningrunning正在执行某一步骤success, failed, pendingsuccess所有步骤完成无failed某个步骤失败进入错误处理retry, pendingretry重试失败步骤最多重试N次running, failed这个状态机带来了两个好处。第一可观测性变得很强每一步卡在哪个环节一目了然排查问题不用靠猜。第二失败恢复有章可循。比如调用模型超时我可以选择重试一次但如果采集数据这一步就失败重试没有意义应该直接返回部分结果让Agent告知用户“磁盘数据采集失败但CPU数据正常”。这种部分成功的能力对生产环境的Agent来说非常重要比整个任务一把梭失败要体面得多。4. 记忆与上下文管理全能Agent不能是“鱼的记忆”4.1 短期记忆与长期记忆的分层设计热词里频繁出现“agent记忆”说明这是大家公认的难点。Agent如果没有记忆每次对话都是“初见”用户上一轮说过“我是运维负责人”下一轮就忘了体验很割裂。但如果把所有对话历史全部塞进上下文token消耗会爆炸模型注意力也会被无关信息稀释。我采用的方案是分层记忆短期记忆当前会话窗口内的原始对话记录按条数或token数限制超出后做截断或摘要。长期记忆跨会话持久化的用户画像、偏好、关键结论通常以结构化的key-value或向量形式存储在需要时检索注入。腾讯云AI Skills本身提供了部分上下文管理能力但业务侧的长期记忆我仍然建议自己掌控这样灵活度最高。4.2 基于Redis的会话记忆实现我的短期记忆存储直接复用腾讯云服务器上的Redis因为Agent服务本身就是容器化部署在附近的内网访问延迟极低。实现逻辑不复杂每个会话一个keyvalue是对话历史的JSON数组import redis import json r redis.Redis(host10.0.0.5, port6379, passwordos.getenv(REDIS_PASSWORD), db0) SESSION_TTL 3600 # 会话一小时过期 def append_message(session_id: str, role: str, content: str): key fsession:{session_id} history r.get(key) messages json.loads(history) if history else [] messages.append({role: role, content: content}) # 只保留最近20条 messages messages[-20:] r.set(key, json.dumps(messages), exSESSION_TTL)这里有两个从实际中总结的细节。第一TTL一定要设置否则会话id一旦被随机遍历Redis内存会被堆积的聊天记录打满。第二保存前做条数截断不能无限追加。20条听起来少但对大多数场景够用真正有价值的早期信息应该通过摘要沉淀到长期记忆里而不是一直霸占短期窗口。4.3 记忆压缩与摘要策略长期记忆的生成我采用异步摘要的方式不阻塞主对话流程。每个会话结束后把累积的对话记录交给模型生成一份结构化摘要内容包含用户身份与偏好本次对话解决的核心问题未完成的事项值得长期记住的约束条件然后存入Redis的另一个命名空间memory:{user_id}同样设置TTL但时间可以很长比如30天。下次该用户发起新会话时先加载这份摘要作为系统上下文的一部分让Agent“想起来”之前聊过什么。这个方案相比直接塞全部历史token开销小了一个数量级而且摘要本身是经过提炼的信息密度更高。我实测同一个用户第二次咨询时Agent能准确说出“您上次提到这台服务器是预发环境部署策略要保守”这就是短期记忆做不到的体验。5. 从本地到云端LiteLLM Proxy与多模型接入的工程化5.1 为什么用LiteLLM Proxy做统一模型网关Agent服务不可能只用一家模型。以我的实践为例日常对话用性价比高的模型复杂代码生成用更强的大模型特定场景可能还要切换DeepSeek或其他兼容OpenAI接口的模型。如果业务代码里直接逐个对接各家SDK每换一个模型就要改一遍代码维护成本太高。我选择在Agent服务和模型之间架一层LiteLLM Proxy把所有上游模型统一成OpenAI兼容的/chat/completions接口。业务侧只认一个base_url和一套API规范模型切换、流量分配、失败降级全部在Proxy层搞定。实践中的推荐配置是本地或内网部署LiteLLM Proxy腾讯云服务器上通过Docker运行。这样Agent服务调用Proxy走内网延迟可控也不存在公网暴露模型密钥的风险。Proxy的配置核心是模型路由表需要仔细设计。5.2 模型路由、降级与成本控制的最佳实践LiteLLM Proxy最有价值的能力是模型之间的自动切换和降级。你可以在配置里定义一组模型设置优先级当主模型不可用时自动fallback到备用模型。我的配置大致长这样model_list: - model_name: primary-chat litellm_params: model: tencent/hunyuan-turbo api_key: os.environ/HUNYUAN_API_KEY model_info: mode: chat - model_name: backup-chat litellm_params: model: deepseek/deepseek-chat api_key: os.environ/DEEPSEEK_API_KEY model_info: mode: chat router_settings: fallbacks: - {primary-chat: [backup-chat]} num_retries: 2 timeout: 30业务代码请求时只需要指定modelprimary-chat真正用哪个上游模型由路由器决定。这个抽象层在线上救过我一次腾讯云侧模型临时限流请求自动切到了备用模型用户无感知业务没有中断。成本控制方面我建议按技能粒度配置模型。成本敏感的通用问答走便宜的模型代码生成、深度分析这类高价值场景走贵但强的模型。LiteLLM的budget功能可以给每个key设置配额超出后自动拒绝请求避免失控调用。5.3 密钥管理与上云安全密钥管理是我每次复盘都会强调的点。环境变量里直接写死API key、代码仓库里提交明文密钥这两种操作在生产环境都是灾难。腾讯云上的Agent服务密钥建议放在环境变量或专门的密钥管理服务里在启动容器时通过安全的方式注入不要让密钥出现在镜像层里。我自己的标准做法是写一个.env.example模板提交到仓库字段名列清楚真实值只在服务器上维护一份.env并且文件权限设为600。部署脚本从环境变量或腾讯云的密钥服务读取再传给容器。这样即使代码仓库泄露攻击者也拿不到任何有效凭证。安全另外一个要点是网络隔离。Redis、数据库这类有状态服务配置安全组时只允许Agent服务所在的内网IP访问不要对公网开放。我在腾讯云上排查过一些异常登录最后发现都是因为这类端口暴露在了公网上密码再长也顶不住暴力破解。6. 上线后的驯化测试、监控与技能迭代闭环6.1 给Agent建立测试集意图路由、技能正确性、回归验证Agent上线后最大的问题是“这次改动到底有没有变好”。没有测试集全靠人工聊几轮永远无法量化。我根据实际经验把Agent测试分成三层第一层是意图路由测试验证用户说某句话Agent是否选择了正确的技能。比如“帮我看看Redis内存”应该命中server_inspection而不是log_analysis。这一层可以用离线case直接跑不依赖真实环境。第二层是技能正确性测试验证技能内部的步骤执行结果是否符合预期。比如server_inspection返回的JSON结构、字段值是否和真实监控数据一致。第三层是端到端回归测试模拟真实用户多轮对话验证记忆、上下文、技能编排整体工作是否正常。我给Agent维护了一个很小的测试集也就几十条case但每次调整技能描述或编排逻辑后都会全量跑一遍。不要小看这个动作它能在你“觉得优化了”的时候及时发现另一个技能的召回率被误伤了。6.2 可观测性三板斧技能调用日志、Token消耗、错误堆栈Agent的可观测性比普通API复杂很多因为不仅要看请求成功失败还要看模型当时“想了什么”“做了什么选择”。我的监控体系围绕三块展开技能调用日志记录每个会话触发了哪些技能、每个技能的执行时长和结果状态。通过这个日志能看出哪些技能被高频误调用哪些技能执行时间过长。Token消耗统计按技能、按用户、按模型维度统计token用量。这个数据既能帮助成本控制也能暴露异常流量。某用户token消耗突然飙升很可能是在恶意刷接口。错误堆栈与模型输出日志模型返回了非预期格式、技能内部某个依赖超时、LLM选了一个不该选的技能这些都要有痕迹可查。我甚至建议把模型每次选择技能时的完整输入输出存下来这对后续优化description非常有价值。这几种日志我统一收集后接入腾讯云的日志服务按关键字告警。出现“技能调用失败率超过10%”或“某个技能平均耗时超过阈值”时自动通知不用等用户反馈问题。6.3 从反馈中迭代技能一次误触发率和一次超时问题的复盘最后分享一个真实的迭代案例。我的Agent上线第一周“服务器巡检”技能误触发率很高用户提“帮我分析一下最近日志里的报错”结果系统调用了巡检技能采集了一堆CPU和内存数据完全答非所问。排查日志后发现问题出在三个地方。第一description写得太宽泛只写了“适合服务器相关问题时使用”模型的理解边界模糊。第二缺少负向描述没有明确告知“不适合日志内容解析类问题”。第三训练集里的触发示例太少“日志分析”相关的意图没有沉淀到记忆里。修复方案也很直接重写description明确列出适用和不适用场景增加5个日志分析类trigger examples在意图路由层加了一条规则用户消息中出现“日志”“报错”“异常堆栈”等关键词时优先匹配日志分析技能。改完之后误触发率从17%降到了2%以内。这类问题光靠调代码是发现不了的必须依赖日志和调用记录。这也是为什么我反复强调可观测性要在一开始就铺好等用户来骂再补就已经晚了。在我自己的实践里Agent能力的成长本质上就是一个不断定义技能、测试边界、观察反馈、再修正描述的循环。腾讯云AI Skills的价值是把这些繁琐的工作从“靠自己写一套框架”变成了“在平台上配置和编排”让开发者能把精力集中在最核心的业务逻辑上。如果你也在做Agent落地我的建议是不要一上来追求复杂框架先从一个最小技能跑通全链路再加上记忆、路由、降级这些工程能力一步步把Agent养全能。