最近我在腾讯云上把一个只会聊天的 Agent,慢慢养成一个能查天气、能查股价、能写周报、还能自己调数据库的多面手。整个过程里最关键的转折点,就是引入了 AI Skills 这套东西——说白了,就是给大模型插上一堆"即插即用"的能力插件,让 Agent 不再停留在"嘴上说说",而是真正能动手干活。
这篇文章不是官方文档的复读,而是我这段时间踩坑、折腾、优化之后沉淀下来的实战笔记。我会从设计思路讲起,把技能拆解、云端环境准备、Skill 上传、Agent 框架接入、常见故障排查这几块都过一遍。无论你是刚接触 Agent 开发的新手,还是已经在用 Function Calling、MCP 想横向对比一下的老手,这篇应该都能给你一些能直接抄作业的东西。
1. 为什么我决定用 AI Skills 来养 Agent
1.1 从 Function Calling 到 AI Skills:工具能力的一次升维
先交代一下背景。我之前做的 Agent 基本都是走传统的 Function Calling 模式:先在代码里定义一堆 JSON Schema,每个函数对应一个能力,模型通过结构化输出决定"要调哪个函数、传什么参数"。这套方案用了快一年,最大的感受是:单机游戏可以,做成服务体系很痛苦。
最头疼的是三件事。第一,每加一个新工具都要改主线代码,改完还要重新部署整个 Agent 服务,发布粒度太粗。第二,Function 和 Agent 之间是强耦合,想在另一个项目里复用同一套工具,基本靠复制粘贴,后面维护起来想哭。第三,模型输出的函数调用格式偶尔会"发挥失常",要么参数对不上,要么选错函数,调试成本全压在我身上。
AI Skills 的思路就不太一样。它把"能力"做成了独立分发的技能包,每个 Skill 自己负责描述触发条件、输入参数、输出格式,甚至内部的执行逻辑。Agent 在运行时会根据用户意图动态选择加载哪个 Skill,相当于把"工具箱"从主业代码里拆了出去。我需要新增能力时,不用碰 Agent 主程序,只需要上传一个新的 Skill,然后让 Agent 在技能列表里能"看见"它就行。
1.2 腾讯云在这条链路里扮演的角色
为什么把这套东西放在腾讯云上,而不是我自己的笔记本或者一台裸服务器?原因其实很朴素:稳定、有配套、省心。
Agent 一旦跑起来,就不是本地 demo 那种"挂了重启一下"的状态了。技能调用要 hours 级在线,日志要能追溯,存储要可靠,这些单靠开发机很难扛住。腾讯云这边我主要用到了三块能力:云服务器 CVM 跑 Agent 运行时和 Skill 服务,对象存储 COS 放技能包和临时文件,再加云函数 SCF 做轻量级的技能回调。这样每个 Skill 天然就是"独立部署、独立伸缩"的,哪个技能流量大了,单独扩就行,不会拖垮整个 Agent。
另外,腾讯云开发者生态里对 AI 应用的支持比较完善,上传技能包、配置回调、查看调用日志这些操作都有现成入口。域名备案、SSL 证书、安全组这些基础设施也能在一个控制台里搞定。对一个个人开发者来说,这意味着我可以把精力放在 Agent 的能力设计上,而不是天天跟运维搏斗。
提示:这里说的"上传技能包"在不同产品形态里路径不太一样,有的是走控制台可视化上传,有的是走 CLI 或 API 推送。重点是理解"技能与主程序解耦"这一层逻辑,具体工具按你手头的产品能力来选就行。
2. 动手前想清楚:技能拆解与目录设计
2.1 先给 Agent 画一张"能力地图"
很多人一上来就急着写代码,结果技能做出来要么太粗糙,要么跟 Agent 主流程打架。我的做法是先画一张能力地图,把"用户可能让我干什么"列全,再逐个判断"这事应不应该做成 Skill"。
判断标准有三条:第一,这个能力是否是高频复用的,如果一个能力只在一个特定场景用一次,那就没必要做成独立 Skill;第二,是否适合异步执行,比如"查天气"这种实时请求适合做成 Skill,"每周自动生成报表"这种更适合走定时任务;第三,是否涉及外部资源,需要访问数据库、调第三方 API、读写文件的能力,做成 Skill 的价值最大。
以我这个"全能 Agent"为例,最后整理出来的能力地图分成了四层:信息查询层(天气、股票、新闻)、数据处理层(表格分析、文本摘要、格式转换)、业务操作层(创建工单、发送通知、查询订单)、系统管理层(日志检索、监控告警、数据备份)。每一层对应 2 到 3 个 Skill,总共做了 11 个,覆盖了日常工作里 90% 以上的请求。
2.2 Skill 目录与 JSON Schema 的设计要点
设计 Skill 的时候,我最看重的不是执行逻辑多复杂,而是"边界够不够清楚"。一个 Skill 最好只做一件事,不要做成"瑞士军刀"。比如我一开始做过一个"全能数据处理"技能,又做清洗又做可视化又做格式转换,结果模型经常不知道该用哪个参数,调用成功率惨不忍睹。后来把它拆成"表格清洗"、"图表生成"、"格式转换"三个独立 Skill,效果好得多。
每个 Skill 都有一个描述文件,我习惯用 YAML 写,结构大概是这样的:
name: stock_price_query description: 查询指定股票的实时价格和涨跌幅,支持 A 股、港股、美股。当用户问到股价、行情、涨跌时优先使用。 version: 1.0.0 endpoint: url: https://agent.example.com/skills/stock_price_query method: POST parameters: type: object properties: symbol: type: string description: 股票代码,例如 600519、00700、AAPL market: type: string enum: [CN, HK, US] default: CN required: - symbol returns: type: object properties: symbol: type: string price: type: number change_percent: type: number这里有个关键细节:description 字段要写清楚"什么时候该用这个技能",因为模型是靠 description 来做技能选择的。写得越具体,选错技能的概率越低。我一开始写的是"查询股票价格",模型经常在用户问"今天大盘怎么样"时也把它拉出来,后来改成"查询指定股票的实时价格和涨跌幅,支持 A 股、港股、美股"之后,误用率降了一大截。
参数设计上,我吃过不少亏。建议严格遵守两个原则:一是所有参数都给显式默认值,能枚举的用 enum 限定;二是参数描述要站在"模型视角"写,告诉它这个参数是什么格式、去哪找、传错了会怎样。比如 symbol 字段如果写成"股票代码",模型可能传"贵州茅台"进来,但接口需要的是"600519",那我就在描述里补一句"例如 600519、00700、AAPL",模型基本就不会传错了。
3. 腾讯云环境准备与核心部署实操
3.1 服务器与基础环境:别在第一步翻车
做 Agent 服务,第一台服务器我建议别贪大。我自己最开始是用 2C4G 的轻量应用服务器跑的,Agent 主程序加三五个 Skill 服务绰绰有余。如果以后技能数量多了、并发上来,再扩容就是几分钟的事,没必要一开始就上高配。
系统选型我用的是 Ubuntu 22.04 LTS,原因很简单:Python 生态兼容性好,跑 Docker 也省心。装完系统第一件事,我建议先把 Docker 装好,因为后面所有 Skill 我都会容器化部署,这样在本地开发什么环境,推到云上就是什么环境,不会有"在我电脑上是好的"这种尴尬。
Docker 装完之后,有几个基础配置我强烈建议顺手做完。第一,配置 Docker 镜像加速,不然拉镜像能急死人;第二,开启 Docker 的远程访问要慎重,不推荐直接暴露 2375 端口出去,我见过太多因为这个被入侵的案例;第三,给 Docker 的数据目录单独挂一块数据盘,避免日志和镜像把系统盘撑爆。
3.2 域名与端口:回调地址的合规姿势
Skill 的 endpoint 需要一个可以被公网访问的 HTTPS 地址。如果直接用 IP 加端口,也能跑通,但问题很多:模型调用时对 IP 地址的信任度低、证书不好配、以后换服务器 IP 变了所有技能都得改。
我建议去申请一个域名,再做解析。腾讯云控制台里能找到域名注册入口,注册好之后进入"解析"页,添加一条 A 记录,把域名指向你的服务器公网 IP。这里有个细节:如果你跟我一样只是做技能回调,可以申请一个二级域名专门给 API 用,比如 skill.example.com,这样和主站业务完全隔离,万一某个技能被攻击,也不会波及主域名下的其他服务。
端口这块要说点实在的。很多教程会让人"开放所有端口",这绝对是高危操作。我的做法是只开放必要端口:443 用来走 HTTPS 回调,22 用来 SSH 管理(而且仅限我自己的 IP),其他端口一律在安全组里关掉。腾讯云的安全组规则支持按 IP 段授权,你可以把自己的公网出口 IP 填进去,非授权来源直接连不上,能挡掉绝大多数扫描器。
域名解析好、安全组配置好之后,还要申请 SSL 证书。腾讯云有免费的证书可以申请,申请下来后在 Nginx 里配置一下就行。整个过程二十分钟能搞定,但这二十分钟能让你后续省掉大量"为什么模型调用失败"的排查时间。
注意:不要图省事用 IP 地址做 endpoint。我之前试过直接用 http://IP:8080 调技能,结果是模型经常在生成回调 URL 时拼错,而且浏览器和不少 HTTP 客户端会拦混合内容。换成 HTTPS 域名之后,这类问题基本绝迹。
3.3 用 Docker 把运行时打包成标准交付物
每个 Skill 我都是一个独立的 FastAPI 服务,跑在单独的容器里,然后通过 Nginx 做反向代理统一入口。这样做的收益是:技能的依赖互相隔离,不会出现 A 技能要 Python 3.10、B 技能要 Python 3.8 这种"依赖地狱"。
打包推送到腾讯云容器镜像服务,流程我实测下来很顺畅。先在本地给镜像打好 tag,格式一般是registry.cn-guangzhou.tencentcloudcr.com/你的命名空间/skill-名称:版本号,然后登录、推送:
docker tag skill-stock:v1.0.0 registry.cn-guangzhou.tencentcloudcr.com/agent/skill-stock:v1.0.0 docker login registry.cn-guangzhou.tencentcloudcr.com --username 你的账号ID docker push registry.cn-guangzhou.tencentcloudcr.com/agent/skill-stock:v1.0.0登录时用的不是控制台的登录密码,而是访问凭证里的密钥,这个在容器镜像服务的"访问凭证"页面里生成。推送完镜像,在镜像服务控制台能看到版本列表,后期回滚也方便。
用镜像服务管理技能包,我觉得最大的好处是"版本可追溯"。每次技能更新我都打个新 tag,哪个版本跑得稳就切到哪个版本,整个回滚过程就是改一下 tag 重新部署的问题,比在服务器上改代码然后手动重启要靠谱得多。
4. 把 AI Skills 真正跑起来的完整步骤
4.1 创建 Skill 的工作流演示
Skill 的整个生命周期,我习惯分成"本地开发 -> 推镜像 -> 上传技能定义 -> 联调测试 -> 灰度发布"五步。这里重点说上传技能定义和联调测试,因为这两步最容易出问题。
上传技能定义,本质上是把写好的 YAML 描述文件交给平台,让 Agent 在运行时能"发现"这个技能。如果走 CLI,命令大概长这样:
tccloud agent skill upload \ --file skill-stock.yaml \ --env production \ --token $TC_SECRET_ID上传成功后,建议先做一轮"脱离 Agent 的单独联调"。方法很简单:直接伪造一个模型可能生成的 JSON 调用请求,用 curl 打给技能的 endpoint,看返回格式和技能描述里定义的是否一致。这一步能筛掉大部分低级错误,比如字段名拼错、返回结构嵌套不对、超时时间设置太短。
联调通过后再切到 Agent 主流程测试。测试的时候不要用太复杂的意图,先问最简单的:"帮我查一下腾讯控股的股价",让模型自己去匹配技能。如果这一步能跑通,说明技能选择、参数填充、结果解析这条链路是通的,再慢慢加复杂场景。
4.2 通过 litellm proxy 统一接入 Agent 框架
Agent 框架这块,市面上可选的东西很多,有 LangChain、CrewAI,也有微软的 Agent Framework、近期很火的 Codex Agent、开源社区的 Hermes Agent 等等。我自己没有死守某一个框架,而是把"模型调用层"统一走 litellm proxy,这样不管底层接哪个大模型,上面的 Agent 逻辑都不用改。
litellm proxy 在我看来是一个标准的 LLM 网关,它能统一管理模型路由、API 密钥、速率限制和日志。我把腾讯云上可用的模型服务、以及其他的模型 API 都配置进 proxy,然后在 litellm 里设置不同的模型别名。Agent 代码里只认"gpt-oss"、"qwen-max"这种别名,实际调用时由 proxy 转发到对应供应商。
配 litellm proxy 的 config.yaml 大概是这样的:
model_list: - model_name: qwen-max litellm_params: model: openai/qwen-max api_base: https://your-gateway.example.com/v1 api_key: os.environ/TENCENT_API_KEY - model_name: embed-3 litellm_params: model: openai/text-embedding-3-small配置好之后,启动 proxy:
litellm --config config.yaml --port 8000然后用标准的 OpenAI SDK 就能访问所有模型。这段时间用下来,我觉得 litellm proxy 最大的价值是在"多模型灰度"上:我想试某个新模型时,只要在 proxy 里改一下 model_name 的映射,Agent 代码一行都不用动就能切过去。对 Agent 开发这种迭代很频繁的场景来说,这个灵活性太重要了。
4.3 打通 Agent 记忆与多技能编排
有了技能,Agent 能干活了,但离"全能"还差一口气——记忆和编排。
先说记忆。Agent 假如没有记忆,每次对话都像失忆患者,用户会很崩溃。我在实践里用了三层记忆架构:短期记忆放在会话上下文里,用向量数据库存储,每次新问题来了先做相似度检索,把相关的历史对话带进提示词;长期记忆用来存用户画像和偏好,比如用户常看的股票、常用的报表格式;技能调用记录单独存一份,方便我回溯"这个 Agent 上次调了哪个技能、为什么调"。
再说编排。多个技能同时可用时,模型会不会选错?我的经验是:不要把决策权完全交给模型,而是加一层"意图路由"做前置分流。比如用户说"今天的复盘报告",我先在编排层判断这涉及"数据查询"、"文本生成"、"格式转换"三个技能,让它们按依赖关系依次执行——先查数据,再生成文本,最后转成指定格式。编排层可以通过一个轻量级的 Python 脚本实现,也可以用现成的 Agent 框架里的 Task 机制来做。
async def handle_report_request(user_input): # 第一步:调度数据查询技能 data = await call_skill("stock_price_query", parse_symbols(user_input)) # 第二步:调度文本生成技能 summary = await call_skill("text_summarize", {"data": data}) # 第三步:格式化输出 report = await call_skill("format_convert", {"content": summary, "format": "markdown"}) return report这套流程跑通之后,Agent 的表现从一个"答题机器"升级成了"能完成完整任务的执行者"。我拿它跑了半个月的日报生成,基本稳定,偶尔出错也能通过调整技能描述或编排规则修回来。
5. 排查实录与避坑指南
5.1 从 Redis 密码修改失败聊起:基础设施的稳定性排查
Agent 跑起来之后,我顺手把 Redis 也部署在腾讯云那台服务器上,用来做缓存和会话存储。本来觉得这事再简单不过,结果某天在服务器上改了 Redis 密码,重启之后服务就一直起不来。报错信息翻来覆去就那几个,log 里只写着# Fatal error, can't open config file或者ERR Client sent AUTH, but no password is set。
排查到最后才发现两个问题。第一个是权限问题:Redis 的持久化目录和配置文件之前是用 root 启动时生成的,改成普通用户跑之后没权限读 dump.rdb。第二个是配置文件里的requirepass和启动参数里的密码不一致,重启时我用的 systemd 服务文件里写死了旧的--requirepass参数,改配置文件根本没生效。
这个坑让我养成了一个习惯:排查任何"改完配置重启失败"的问题,先检查三个地方——目录权限、启动参数优先级、日志完整输出。对 Agent 服务来说,缓存一挂,会话记录全部丢失,用户上下文完全断裂,表面上看起来是"模型变笨了",实际上底下是 Redis 挂了。这类问题排查顺序很重要:先看基础设施,再查业务代码,别一上来就怀疑模型。
5.2 上传与版本管理常见报错
Skill 上传这块,我遇到过几个比较典型的报错,整理成了一张速查表,方便大家直接对照:
| 报错现象 | 原因 | 解决方案 |
|---|---|---|
skill validation failed: missing required field | YAML 里漏了必填字段 | 对照官方文档检查 name、description、endpoint 是否齐全 |
duplicate skill name/version | 同名同版本技能已存在 | 提升 version 号,或者删除旧版本后再上传 |
invalid endpoint url | endpoint 不是 HTTPS 或格式错误 | 确认地址有 HTTPS 协议头,且能被公网访问 |
| 上传超时/网络异常 | 技能包太大或本地网络不稳 | 把大文件放到 COS,Skill 里只保留访问地址 |
Agent 报skill not found | 技能名拼写不一致,或环境隔离 | 检查 Agent 与 Skill 是否在同一个 environment |
其中"技能包太大"这个问题最隐蔽。我一开始把整套数据分析依赖库都打进了镜像,技能包体积好几个 G,上传一次要十几分钟,而且经常中途断掉。后来我把数据处理重活挪到云函数里,Skill 只做轻量转发,上传速度从十几分钟降到了几秒钟。
5.3 调用链路里的性能与安全注意事项
Agent 调用 Skill 时最大的性能杀手是"串行等待"。如果一次任务要调三个技能,每个技能平均响应 2 秒,串行就是 6 秒,用户早就等得不耐烦了。我的优化办法是:把相互之间没有依赖的技能调用并发化,用 asyncio.gather 同时发起。实测三个技能并发调用,整体耗时可从 6 秒压到 2.5 秒左右。
但我必须提醒一句:并发调技能要小心"上下文污染"。技能返回的结果如果都挤在上下文里,token 占用会暴涨,可能导致超出模型窗口,最典型的表现就是agent execution terminated due to error,或者生成开始没多久就被截断。这个错误一出现,我第一反应就是看上下文长度,而不是查模型配置。
安全意识也一定要有。我在开发初期犯过一个错:把腾讯云的 SecretKey 直接写死在 Skill 代码里,后来代码传到镜像仓库后,虽然仓库是私有的,但还是觉得不妥。现在所有密钥都统一走环境变量管理,在 litellm proxy 里也配置了统一的密钥轮换机制。另外,Skill 的入参如果会被拼进 SQL 或者命令行,一定要做转义和校验,防止提示词注入导致技能"做一些不该做的事"。Agent 安全这条路水很深,但基本原则就是:最小权限、输入校验、日志脱敏、密钥不落盘。
最后再说两句
这套"AI Skills + 腾讯云"的组合拳打下来,我最大的体会是:Agent 的进化不靠大模型本身,而是靠周边能力的完善。模型选得再好,工具接不通就是空中楼阁。我现在最常用的一个技巧是——每次给 Agent 加新技能之前,先拿旧问题列表回归测试一遍,防止"修了东墙拆了西墙"。
如果你也正在折腾 Agent,建议从一个小而实的技能入手,把链路走通,再慢慢扩展能力地图。技能不在多,在于每个都能稳定跑出预期结果。后续我打算给这套 Agent 再接上定时任务和主动通知的能力,让它从"有求必应"变成"主动汇报"。真到那一步,它才算真正意义上的"全能 Agent"。