ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

腾讯云AI Agent部署实战:从Litellm代理到Skills插件体系

腾讯云AI Agent部署实战:从Litellm代理到Skills插件体系 我最近把一台闲置的腾讯云服务器彻底折腾了一遍从域名解析、容器镜像推送到 Litellm Proxy 部署最后接入 OpenAI SDK 兼容层再把 Skills 插件体系挂上去总算跑通了一个完整可用的 AI Agent 工作台。这套东西踩坑不少尤其是腾讯云容器镜像服务的权限配置、二级域名申请备案后的解析生效时间、以及 Redis 修改密码后重启失败的连锁反应每一个都够写一篇单独的排错记录。今天这篇就把整个链路串起来分享一份可以直接照抄的腾讯云 AI Skills 最佳实践。先说清楚这套方案解决了什么问题你不需要本地显卡不需要买昂贵的 GPU 云主机也不需要折腾复杂的 K8s只要一台最基础的腾讯云轻量服务器就能把 Agent 开发环境、模型代理层、技能插件体系全部跑起来。适合的人群很明确——正在做 AI Agent 原型验证的开发者、想把自己公司内部 API 封装成 Skills 的团队、以及想在云端搭一套统一模型网关给前端/后端同时调用的个人开发者。1. 环境准备腾讯云服务器选型与域名解析的隐藏坑1.1 轻量服务器配置怎么选才不浪费钱很多人第一步就纠结服务器配置其实 Agent 开发场景和传统 Web 服务不一样瓶颈通常不在 CPU 而在内存和网络带宽。我自己用的是 2C4G 的轻量应用服务器系统盘 80G SSD带宽 6M 峰值日常跑 Docker 容器、Litellm Proxy、Redis、多个 Node 服务完全够用。选型逻辑是这样的Agent 本身是个编排层真正吃算力的是底层模型推理而模型推理在云端 API 完成本机只做请求转发和逻辑编排所以 4G 内存已经富余。但如果你的 Agent 要加载本地向量数据库做 RAG或者要跑 embedding 模型建议直接上 8G因为 Chroma 或者 Qdrant 这类组件吃内存非常凶4G 跑起来 swap 会频繁触发响应时间直接崩。带宽这块反而是我最后悔的。轻量服务器的峰值带宽是共享的6M 在高峰期跑大模型流式输出时会明显感觉到瓶颈。如果你计划给团队多人共用这个 Agent 服务建议选按流量计费的带宽模式或者直接上独享带宽别在带宽上省钱。1.2 二级域名申请与解析的正确姿势腾讯云的二级域名申请是在云解析 DNS 控制台完成的但这里有个绝大多数新手都会踩的坑一级域名必须完成 ICP 备案二级域名才能正常解析访问否则 HTTP 请求会被拦截。我自己当时图省事拿着一个未备案的域名直接解析到服务器结果前端页面能打开 IP 访问域名死活不通排查了半天才发现是备案问题。正确的操作顺序是在腾讯云控制台先完成域名实名认证和 ICP 备案备案审核周期一般 5-7 个工作日备案通过后在云解析 DNS 控制台添加记录主机记录填 agent记录类型选 A记录值填服务器公网 IPTTL 建议先设 600 秒等解析稳定后再改回 60 秒这里补充一个小技巧备案审核期间千万不要闲着可以先把服务器的 Docker 环境、容器镜像仓库、Redis 全部配好因为 Docker 拉镜像和推送镜像走的是 IP 加端口不依赖域名解析完全不受备案影响。等域名备案下来直接改配置文件的 base_url 即可。1.3 Redis 修改密码后重启失败的典型排错链路这个坑我必须单独拎出来说因为太典型了。我最初在服务器上装 Redis 时用默认配置后来觉得不安全修改了 requirepass 密码然后执行 systemctl restart redis结果服务直接起不来。排查链路如下首先看systemctl status redis发现报错信息是Bad directive or wrong number of arguments这句话误导性很强我一度以为是配置文件语法写错了。后来用/usr/bin/redis-server /etc/redis/redis.conf前台启动才发现真正的报错——Redis 6.0 以上的版本如果配置了 requirepass必须同步配置 masterauth否则主从同步线程会反复尝试认证失败导致服务进入保护性退出。解决办法其实很朴素在 redis.conf 中同时配置这两个字段requirepass YourStrongPassword masterauth YourStrongPassword然后redis-cli -a YourStrongPassword ping验证。这里还有一个隐藏知识点Redis 7.0 之后默认开启了 protected-mode如果你用 ACL 用户体系替代 requirepass配置语法完全不同从 requirepass 迁移到 ACL 时不要漏掉user default on nopass ~* * all这行否则直接拒绝所有连接。2. 容器化部署Docker 推送腾讯云容器镜像服务的完整链路2.1 从本地构建到镜像仓库的权限配置把 Agent 服务容器化之后需要推到容器镜像仓库本地才能轻松拉取部署。腾讯云容器镜像服务 TCR 的个人版是免费的但权限认证方式和 Docker Hub 不一样有坑。首先在 TCR 控制台创建命名空间和镜像仓库命名空间是全局唯一的比如我用的agentforge。然后登录需要生成一个临时凭证腾讯云的镜像仓库登录凭证默认有效期是 12 小时这点和 Docker Hub 的长期 token 完全不同CI/CD 流水线里要特别注意定时刷新。本地登录命令docker login ccr.ccs.tencentyun.com --username1000xxxxxxx --passwordxxxxx这里 username 不是你的 Docker Hub 用户名而是腾讯云的账号 ID可以在控制台账号信息里找到。我第一次就在这里卡了半小时一直用自己的自定义登录名提示认证失败。推送镜像的标准流程docker tag agent-runner:latest ccr.ccs.tencentyun.com/agentforge/agent-runner:latest docker push ccr.ccs.tencentyun.com/agentforge/agent-runner:latest推完之后在服务器上拉取建议加--digest参数固定镜像版本避免 latest 标签被覆盖后产生非预期行为。生产环境千万别图方便用 latest这次推个坏的上去下次 pull 直接中招。2.2 Docker Compose 编排腾讯云服务器上的 Agent 服务栈涉及 Agent 的容器服务不止一个我用 docker-compose.yml 统一管理一份配置拉起所有服务。这里给出我的编排文件核心结构version: 3.8 services: redis: image: redis:7-alpine restart: always command: redis-server /usr/local/etc/redis/redis.conf volumes: - ./redis/redis.conf:/usr/local/etc/redis/redis.conf ports: - 6379:6379 litellm-proxy: image: ghcr.io/berriai/litellm:main-latest restart: always env_file: - .env ports: - 4000:4000 depends_on: - redis agent-runner: image: ccr.ccs.tencentyun.com/agentforge/agent-runner:latest restart: always environment: - LITELLM_PROXY_URLhttp://litellm-proxy:4000 - REDIS_URLredis://:YourStrongPasswordredis:6379 ports: - 3000:3000 depends_on: - litellm-proxy这个编排文件里有个非常关键的点容器之间通信用服务名而不是 IP 地址比如redis://litellm-proxy:4000。很多人在本地跑通后上服务器就挂了原因就是容器内使用 localhost 指向了自身容器而不是目标服务。Docker Compose 会自动创建内部 DNS服务名就是容器 IP 的映射直接用就行了。另外 Redis 的连接串里带密码需要注意特殊字符转义。如果密码里有 、:、/ 这类字符必须进行 URL 编码否则会被解析器误认为分隔符。我吃过亏密码里放了个 结果连接串直接炸了后来统一把密码改成大小写字母加数字的组合才消停。2.3 Docker 日志与资源监控的日常体检容器化部署起来之后最怕的就是半夜容器挂了还不知道。我把日志采集简单接了一下用docker logs --tail 100排查问题同时用docker stats监控 CPU 和内存。腾讯云轻量服务器自带的基础监控只有 CPU 和带宽不包含容器级监控所以容器状态我来处理。比较实用的组合是 crontab 加一段健康检查脚本每分钟探测一次 Agent 接口的 /health 端点连续失败三次就通过企业微信机器人发告警。这个脚本用 shell 就能写不需要额外部署 Prometheus 全家桶对轻量服务器非常友好。如果后续容器数量超过 5 个再考虑上完整的监控体系前期不要过度设计。3. 模型代理层Litellm Proxy 部署与 OpenAI SDK 兼容层的落地3.1 为什么需要 Litellm Proxy 作为模型统一入口这是整套架构的枢纽。直接调用各家模型 API 的问题在于接口格式、鉴权方式、限流策略完全不同Agent 每接一个新模型就要改一遍代码。Litellm Proxy 做的事情就是把这层差异全部屏蔽掉对外暴露一个 OpenAI 格式的 /chat/completions 接口内部再把请求转发给腾讯云混元、DeepSeek、通义千问等不同厂商。选型上我对比过 One API 和 LiteLLM最终选了 Litellm。理由是 LiteLLM 的模型兼容层更新速度极快几乎所有新发模型当天就能支持而且它原生支持 OpenAI SDK 的 streaming、tools、function calling 协议对 Agent 开发特别友好。One API 的 UI 管理界面更完善但在 Function Calling 的透传上有过兼容性问题对需要工具调用的场景不太友好。部署方式直接用 Docker 镜像一条命令搞定。配置通过 config.yaml 管理核心结构model_list: - model_name: hunyuan litellm_params: model: litellm_proxy/hunyuan api_key: os.environ/HUNYUAN_API_KEY api_base: https://api.hunyuan.cloud.tencent.com/v1 - model_name: deepseek litellm_params: model: litellm_proxy/deepseek-chat api_key: os.environ/DEEPSEEK_API_KEY litellm_settings: drop_params: true set_verbose: false其中model_name是你自定义的对外名称litellm_params.model是对应厂商的真实模型名api_base是厂商的接口地址。有个细节容易忽略腾讯云混元的接口地址是/v1结尾部分文档写的是/结尾相差一个斜杠会直接导致 404。3.2 用 OpenAI SDK 无缝切换腾讯云混元模型Litellm Proxy 搭好之后Agent 侧代码几乎不需要任何额外适配。只需要把 base_url 指到 Litellm 的地址api_key 随便填一个占位符即可。我实际验证过OpenAI 官方 Python SDK 直接改配置就能对接腾讯云混元from openai import OpenAI client OpenAI( api_keysk-litellm-local, base_urlhttp://your-server-ip:4000/v1 ) response client.chat.completions.create( modelhunyuan, messages[ {role: system, content: 你是一个擅长处理数据分析的 Agent}, {role: user, content: 请分析这份销售数据的异常波动} ], tools[{ type: function, function: { name: analyze_sales, description: 分析销售数据, parameters: {...} } }], streamTrue )这段代码里的关键信息是base_url和model的对应关系。model这个参数填的并不是混元在腾讯云控制台里的模型 ID而是你在 Litellm config.yaml 里定义的model_name这一点非常容易混淆。我在初期的老代码里写的是hunyuan-lite这种腾讯云原始模型名经 Litellm 转发时反而识别不了。另外streamTrue在大模型对话场景里建议默认开启因为用户打字等不了整段生成完毕。流式模式下Litellm 会把厂商的流式数据格式统一转换成 OpenAI 的 SSE 格式前端的 EventSource 或者 fetch ReadableStream 可以直接消费这个兼容层是 Litellm 做得最漂亮的地方。3.3 模型路由、请求转发和 Token 计数的日常维护Litellm Proxy 跑起来之后日常维护主要是三件事加新模型、看配额、查日志。添加新模型只需要改 config.yaml 然后重启容器不需要改 Agent 代码前提是 Agent 侧已经按 OpenAI 工具调用协议写好。比如我要接入腾讯云一个新出的模型配置里加一段- model_name: tencent-new-model litellm_params: model: litellm_proxy/tencent-new-model api_key: os.environ/TENCENT_API_KEY重启后立刻可以通过统一入口调用。配额查看直接用 Litellm 自带的 /spend 接口可以按 key、按用户、按模型维度统计 token 消耗。日志方面建议开启set_verbose: true跑一两天观察确认稳定后关掉因为 verbose 模式下的日志量很大轻量服务器的磁盘空间经不起几天折腾。4. Skills 插件体系让 Agent 真正变“全能”的关键设计4.1 Skills 到底是什么和普通 API 调用有什么区别很多人以为 Skills 就是把一堆 API 封装成函数给模型调用这个理解只对了一半。Skills 的核心价值在于它把自然语言意图到工具执行的映射过程体系化了。普通 API 调用需要你在代码里写死路由逻辑模型只能在一组固定函数里选而 Skills 体系则允许模型在执行过程中动态发现、加载和执行新技能这才是 Agent 能持续进化的原因。打个比方普通函数调用的关系就像是拿着菜单点菜菜单上有什么你点什么Skills 的关系则像是给厨师一本空菜谱他可以根据食材和口味自行研发新菜并记录进去。后者的上限高得多。我在实际项目里维护的 Skills 目录结构如下/skills /data-analysis SKILL.md execute.py requirements.txt /web-search SKILL.md execute.py /internal-api SKILL.md execute.py每个技能目录里必须有一个 SKILL.md这个文件是模型理解技能用途的入口里面的描述质量直接决定模型能否在正确的场景下选择这个技能。写 SKILL.md 是 Agent 开发中最容易被低估的事情很多人写完 execute.py 就不管文档了导致模型根本不知道这个技能是干嘛用的浪费了整套机制。4.2 SKILL.md 的写作规范与实践经验SKILL.md 说白了就是给大模型看的自然语言接口文档它的质量决定技能被正确调用的概率。我推荐的结构包括以下几个方面首先要用一句话说明这个技能解决什么问题。其次列出该技能的典型触发场景举出模型在用户提到哪些意图时应该考虑调用这个技能。然后是具体的工作步骤模型的推理过程会参考这些步骤来规划执行路径。最后是必要的注意事项和边界条件避免模型在不适用的场景下误用技能。我在给一个内部的数据分析技能写 SKILL.md 时初次写得太笼统只有一句“用于分析数据”。这个粒度下模型经常在用户问天气的时候也去调用数据分析技能调用完后生成了一个毫无意义的报告。后来我改成限定触发条件、明确输入格式、给出输出规范调用准确率明显提升。文档里明确写了“仅当用户提供结构化数据表格或明确要求统计指标时才使用”模型就不再乱调了。SKILL.md 里还可以补充一些示例对话few-shot 对模型理解技能边界很有帮助。例如## 触发场景示例 - 用户分析这份 1-6 月各区域销售数据找出下滑最明显的区域 → 调用>import subprocess import json result subprocess.run( [python, execute.py], inputjson.dumps(input_data), capture_outputTrue, timeout30, cwdstr(skill_dir) ) output json.loads(result.stdout)用 subprocess 而不是直接调函数虽然会有一点性能损耗但带来的是稳定性和隔离性对于一个同时跑多个技能的服务来说非常值得。另外超时时间要根据技能性质灵活调整数据分析类技能 30 秒是底线普通查询类技能 5 秒就足够了。4.4 将腾讯云内部 API 封装为 Skills 的完整实例前面讲了很多理论这里给一个我自己实操过的完整案例把腾讯云内部的一个短信发送服务封装成 Agent 技能。这个服务的原始接口是 HTTP POST 请求鉴权方式是腾讯云 API 网关的签名认证。直接让模型调用原始 HTTP 工具不是不行但有两个问题一是签名逻辑太复杂模型在生成签名头时很容易出错二是这个内部 API 涉及敏感操作不该让模型任意拼接参数。封装成技能之后代码内部处理签名对外只暴露语义化参数。execute.py 的关键结构如下from tencentcloud.common import credential from tencentcloud.sms.v20210111 import sms_client, models def execute(phone: str, content: str, template_id: str) - dict: cred credential.Credential(SECRET_ID, SECRET_KEY) client sms_client.SmsClient(cred, ap-guangzhou) req models.SendSmsRequest() req.PhoneNumberSet [phone] req.TemplateId template_id req.TemplateParamSet [content] req.SmsSdkAppId SMS_APP_ID req.SignName SMS_SIGN_NAME resp client.SendSms(req) return {message_id: resp.SendStatusSet[0].SerialNo}SKILL.md 则精确描述“该技能用于发送短信验证码/业务通知用户表达『发短信』『发验证码』『通知用户』时使用输入参数为手机号、消息内容、模板 ID”。这样封装后Agent 就能在需要触达用户时主动调用这个技能而且因为参数经过了强校验不会出现格式错误导致短信发送失败。封装时注意几个细节配置文件不要硬编码在 execute.py 里而是通过环境变量注入方便在不同环境之间切换返回结果要结构化便于模型理解执行结果日志要记录请求 ID、手机号、发送状态方便排障。4.5 Skills 生态的复用与共享给 Agent 持续“加技能”当你的 Agent 技能积累到一定数量后会进入一个良性循环每新增一个技能Agent 的能力边界就扩大一块能够解决的场景又多了好几类。我把已经调通的技能整理成了内部共享包团队成员可以直接拉取不需要重复造轮子。这里也推荐大家多关注社区里的 Skills 仓库比如 codex skills 和 claude code skills 的官方文档里提供了很多高质量范例学习它们的 SKILL.md 写法比自己闷头摸索效率高得多。共享技能时建议打上版本号用 Git 管理Skills 目录里的每个改动都能回溯。我在复盘的时候发现技能版本混乱导致的线上问题占比不低Agent 调用了旧版本技能逻辑而代码仓库已经是新版本这类问题加上版本号之后全都避免了。5. 实测效果、性能指标与后续演进方向整套链路跑通之后我做了几组压测和功能验证。Agent 通过统一模型入口调用腾讯云混元平均首字节响应时间在 800ms 左右完整回复生成速度受限于带宽流式输出体验基本和直连官方 API 没有差距。Litellm Proxy 单容器支撑 50 个并发请求没有出现超时CPU 占用稳定在 40% 以下内存占用约 1.2G。Redis 这边主要承担会话状态缓存和技能执行结果缓存命中率大约 68%有效降低了大模型重复调用的次数。Skills 体系的实测效果是最明显的。加载 15 个技能的情况下模型正确选择技能的准确率大概在 85% 上下剩余的 15% 主要集中在技能描述之间存在语义重叠的场景。解决的办法是梳理技能边界在 SKILL.md 里互相注明“此技能与 XX 技能的区别”效果立竿见影。性能指标方面有个值得留意的现象技能数量增加后发给模型的 tools 参数体积会快速膨胀每个技能的平均 JSON Schema 大约 1KB15 个技能就是 15KB 的额外上下文。这对上下文窗口较小的模型来说是一个不小的压力。我试过几种优化方案最有效的是给高频技能建立索引只把当前场景最可能用到的 5-6 个技能注入到 tools 参数其余技能保持“休眠”状态需要时再动态加载。后续演进方向上我在考虑引入基于 Embedding 的技能自动检索机制将技能描述向量化后存到向量数据库每次请求先计算用户意图与技能描述的相似度再决定加载哪些技能。这套方案做出来之后Agent 技能管理就真正从“手动编排”升级到“自动发现”了。另一个方向是给技能增加权限分级敏感操作类技能需要额外授权才能执行避免 Agent 在误解用户意图时触发高危操作。这两个方向都在验证阶段跑通之后会再写一篇详细拆解。如果从我实际维护这套系统的经验里提炼一句话那就是Agent 的外壳谁都能搭真正决定上限的是你往里面装了多少高质量 Skills以及你把这套技能体系管理得有多规范。腾讯云这台服务器现在每天稳定跑着我的 Agent 服务偶尔半夜收到企业微信告警打开看基本都是一些非致命错误远程修一下就好已经不怎么需要人工值守了。
返回列表