腾讯云上打造全能Agent:AI Skills、云函数与LiteLLM实践

📅 发布时间:2026/9/8 2:59:44
腾讯云上打造全能Agent:AI Skills、云函数与LiteLLM实践
做 Agent 开发的圈子最近有个很有意思的现象框架越来越成熟模型越来越聪明但大家聊得最多的话题反而是怎么让 Agent 真的能干成一件实事。市面上大量 Agent 只是给大模型套了一个对话壳子真正要落地到业务里关键都藏在 AI Skills 的设计、工具的编排和云上部署这些脏活累活里。这篇博客我就打算用自己在腾讯云上把一个带 AI Skills 的 Agent 从零到一跑通的全过程把云函数、LiteLLM Proxy、API 网关、Redis 这些环节串起来聊一聊一个全能 Agent是怎么养成的。这不是一篇纯理论的科普也不是产品文档。我默认你至少知道大模型 API 怎么调懂一点 Python但对 Agent 的开发方式、Skills 的落地方案、云上部署的坑还不太清楚。看完之后你可以照着这套思路自己搭一个能调用外部工具、能动态配技能的 Agent并且知道出问题的时候该去哪里查。1. Agent 与 AI Skills先想清楚你要养的是一个什么东西1.1 什么是 Agent它和普通的 AI 对话应用差在哪很多人把能用大模型做对话等同于做了一个 Agent这个误解特别常见。我的理解里大模型本身是一个会说话的大脑你问它问题它能答但这个能力停留在生成文字的层面。Agent 不一样它的核心特征是能行动——能自己拆解任务、能调用外部工具、能根据返回结果调整下一步动作直到把目标完成。举个例子你就明白了。你直接问某个大模型明天杭州适合穿什么衣服如果它没有联网检索和天气工具它只能根据训练数据给你一个泛泛的答案比如建议穿长袖。真正的 Agent 会把这个问题拆解成三步先定位杭州再查明天杭州的天气结合温度、降水等信息给出穿衣建议。这里的查天气就是一次工具调用而决定什么时候查、查完怎么用就是 Agent 的规划能力。从工程实现角度看一个完整的 Agent 至少包括四个部分模型层负责理解和生成可以是某个大模型的 API也可以本地部署开源模型规划层把用户目标拆解为计划决定下一步要调用哪个工具、参数是什么工具层 / Skills 层封装外部能力比如查天气、操作数据库、发消息、调企业 API 等执行与记忆层记录每一步执行的结果、状态、上下文让 Agent 不至于说完就忘。1.2 Skills技能到底是什么这里重点说一下 Skills因为它是我这次实践里花时间最多、也最有收获的部分。你可以把 Skill 理解成 Agent 的可插拔能力包它解决的问题是不让 Agent 对工具的使用方式靠猜而是给它一份明确的说明书。比如说你要让 Agent 具备查订单、改订单、取消订单的能力传统做法是在代码里把这三个操作写死遇到对应意图就去调用。问题在于当操作越来越多Agent 怎么知道该在什么时候调用哪个操作参数怎么填这就是所谓 Function Calling / Tool Calling 要解决的问题。而 Skill 是比单个工具更高一层的抽象一个 Skill 可以包含触发条件、输入数据的 Schema、执行逻辑、输出格式甚至可以内嵌一段提示词来告诉模型这个技能在什么场景下用、用的时候要注意什么。Skill 和 Agent 的关系我习惯用一个生活化的类比Agent 是员工Skill 是员工的岗位技能证书和作业手册。员工只有一张嘴模型是没办法干活的他需要知道公司有哪些系统工具、每个系统怎么操作Skill 定义、操作的时候遵循什么规范Prompt 约束。你把 Skill 备齐了员工就能独立解决很多问题缺了某个 Skill遇到对应需求时他就只能答复我不会。1.3 我在腾讯云上选型时的思路动手之前我先梳理了一遍自己的约束条件。我的目标不是做一个研究型的 Demo而是希望真正部署到公网、能稳定跑、方便后续加技能。基于这个目标我定了几个选型原则计算资源要弹性短期没有很高的固定并发不想为了一个 Agent 专门养一台高配服务器模型调用要统一管理因为我会同时对接多个模型供应商不想在 Agent 代码里写成千上百个 if-else技能要动态扩展最好新增一个 Skill 的时候不用改主流程代码部署在腾讯云上主要是为了和云上的其他资源数据库、消息队列、对象存储天然打通。综合下来我最终选了腾讯云云函数SCF作为 Agent 的执行载体用 LiteLLM Proxy 做模型网关用 API 网关把入口暴露出去用云 Redis 做会话记忆。这个组合不是唯一解但在成本可控、扩展方便、部署简单这三者的平衡上是我试下来最舒服的一个组合。2. 关键技术选型Agent 落地腾讯云的四梁八柱2.1 云计算载体云函数还是容器怎么选你在搜索腾讯云怎么部署 Agent时最常见的两种方案是云函数和容器服务。我分别用过说下我的感受。云函数SCF的优势是省心不用管理服务器写完代码打包上传就能跑弹性伸缩可以处理突发流量你不需要预估需要几台机器按调用计费如果 Agent 一天只有几十次调用成本基本可以忽略。短板也有冷启动。如果一段时间没有请求下一次请求触发时函数可能需要加载运行时和依赖这个延迟可能到几秒对对话场景来说体验不算好。容器服务的优势是可控你想装什么依赖就装什么环境完全自己说了算长驻运行没有冷启动问题。但你需要自己处理负载均衡、弹性伸缩、镜像仓库、日志监控这些事日常运维成本明显更高。我的选择是主体逻辑放云函数部分耗时较长的初始化任务放到容器里做。具体来说Agent 的主执行链路是云函数HTTP 请求进来之后由 API 网关转发到函数模型网关 LiteLLM Proxy 部署在一个轻量容器上因为网关需要常驻、需要做请求转发和缓存冷启动会拖慢第一轮对话。这个混合架构既有弹性又兼顾了响应速度。2.2 模型网关 LiteLLM Proxy统一模型调用的最佳实践我最早想把模型调用直接在 Agent 代码里写死后面发现完全不现实。因为我会同时用国内几个大模型 API不同供应商的请求格式、鉴权方式、限流策略都不一样。如果每个模型都单独写一个客户端Agent 代码会变得又臭又长而且一旦要切换主模型或者做 A/B 测试改起来特别痛苦。LiteLLM Proxy 在这里的作用相当于一个模型调用路由器。所有 Agent 代码只认一个 OpenAI 兼容的接口LiteLLM Proxy 接收到请求后根据你配置的路由规则把请求转发到实际的模型供应商并统一返回结果。实际放到项目里效果是切换模型时改动很小在配置文件里改一行目标模型即可可以配置多个供应商做 fallback一个模型访问失败自动切下一个可以对请求做缓存相同的 prompt 不必重复计费。如果你也想在腾讯云上用这个方案部署本身不复杂用一个容器跑 litellm[proxy]把供应商的 API Key 通过环境变量注入配置文件里写清楚路由规则就可以了。我建议把 LiteLLM Proxy 和 Agent 执行逻辑放在同一个私有网络里入口不直接暴露到公网避免被扫描或盗刷。2.3 记忆与存储Redis 在 Agent 里的角色Agent 和普通问答最重要的区别之一是有记忆。没有记忆的 Agent 每次对话都是从零开始你没法让它记得你之前的偏好、项目背景、上一次讨论到哪儿了。我在腾讯云上用云 Redis 做会话记忆主要是为了把上下文放在外部存储里。这样即使 Agent 执行函数重启用户的对话上下文也不会丢。Redis 的好处是速度快、数据结构灵活非常适合存 key-value 形态的会话状态。严格来说Agent 的记忆不应该只放在 Redis 里因为 Redis 存长文本并不是最优解。更好的做法是把短期上下文最近几轮对话存在 Redis把长期知识用户的偏好、历史决策、文档摘要放到向量数据库里。不过对于我目前这个 Agent 的应用强度Redis 足够用了后续如果要做更复杂的长期记忆再引入向量数据库也不迟。这里稍微提醒一句如果是自己买服务器装 Redis修改密码后重启连不上是特别常见的问题。原因通常是两个一是改了配置文件但是进程没有用新配置启动二是客户端连接时没有携带密码。我在腾讯云上用过云 Redis 以后觉得省心很多因为密码、网络白名单、版本维护都是平台帮你处理好的。在 Agent 项目里我建议优先考虑云数据库而不是自己在服务器上硬装一个把精力留给业务逻辑。2.4 外部系统打通API 网关和动态技能注册Agent 不能只活在对话里它最终要和其他系统打交道。在云函数架构里外部系统怎么找到你的 Agent答案是通过 API 网关。API 网关负责把公网进来的 HTTPS 请求转发给云函数同时可以处理鉴权、限流、CORS 这些通用问题。我自己的实践是API 网关暴露一个统一的/agents/{agent_id}/chat接口请求体里带用户输入和会话 ID。云函数接收到请求后调用 Agent 核心循环返回结果。这样一个接口可以服务多个 Agent 实例通过路径参数区分。Skills 的动态注册则是另一个关键点。我不想每新增一个技能就重新部署一次云函数所以我采用了一个轻量的技能注册表机制每个 Skill 对应一段独立代码模块模块用统一的接口暴露描述信息和执行函数Agent 启动时动态扫描并加载所有 Skill生成工具描述列表后发送给模型。这样新增 Skill 的时候只需要新增一个模块文件主流程不用动。3. 从零实操在腾讯云上把一个带 AI Skills 的 Agent 跑起来3.1 总体架构与项目目录设计先别急着写代码把目录结构想清楚。我最终的项目结构大致是这样agent-project/ ├── agent/ │ ├── core.py # Agent 核心循环 │ ├── registry.py # Skill 注册与发现 │ ├── memory.py # 基于 Redis 的会话记忆 │ └── llm.py # 对接 LiteLLM Proxy 的客户端 ├── skills/ │ ├── weather/ # 天气技能 │ │ ├── skill.yaml # 技能描述、触发条件、参数 Schema │ │ └── main.py # 技能执行逻辑 │ ├── time_tools/ # 时间/日期相关技能 │ │ ├── skill.yaml │ │ └── main.py │ └── custom_api/ # 对接企业自定义 API │ ├── skill.yaml │ └── main.py ├── deploy/ │ ├── serverless.yaml # 腾讯云函数部署配置 │ └── Dockerfile # LiteLLM Proxy 容器镜像 └── requirements.txt这个结构的核心思想是解耦Agent 主程序不关心具体技能怎么实现只依照注册表里的描述来路由新技能就是一个新目录往 skills 里一放就完事。3.2 Skills 的定义与注册一个 Skill 到底长什么样我以一个非常简单的查询当前时间技能为例展示 Skill 的核心要素。文件skills/time_tools/skill.yaml像下面这样name: current_time description: 获取指定时区的当前时间。当用户询问现在几点、今天几号等与当前时间相关的问题时使用。 parameters: type: object properties: timezone: type: string description: IANA 时区名称例如 Asia/ShanghaiAmerica/New_York default: Asia/Shanghai required: []对应的执行逻辑skills/time_tools/main.py大概是from datetime import datetime from zoneinfo import ZoneInfo def run(timezone: str Asia/Shanghai) - dict: 执行技能并返回结果返回的 dict 会作为模型进一步推理的观察结果 try: tz ZoneInfo(timezone) except Exception: tz ZoneInfo(Asia/Shanghai) now datetime.now(tz) return { timezone: str(tz), local_time: now.strftime(%Y-%m-%d %H:%M:%S %Z), }这个示例简单但里面有几个 Skill 设计的通用套路值得讲描述必须具体到什么时候用。模型是根据 description 来决定是否调用这个技能的如果描述写得太笼统比如查询时间工具模型可能不知道该在什么场景使用。写清楚触发场景调用准确率会明显提升。参数尽可能给默认值。能不给必填参数就不给降低模型生成参数出错的概率。返回值必须是结构化数据。模型拿到返回结果后要接着推理如果返回一大段格式混乱的文本后续规划会跟着乱。最好统一返回 dict 或 JSON。注册逻辑我放在agent/registry.py里核心代码其实就几十行扫描 skills 目录下每个子目录读取skill.yaml动态导入main.py把完整描述和数据结构列表汇总起来供 Agent 主循环使用。3.3 Agent 核心循环规划、调用、观察、再规划搞定了 Skills 之后Agent 主循环才有意义。我用一个很简洁的循环来组织整个执行过程你可以把它理解成小步快跑的思维链def run_agent(user_input: str, session_id: str) - str: memory load_memory(session_id) messages build_messages(memory, user_input) for round_idx in range(MAX_ROUNDS): # 1. 从模型获取回复可能是普通回复也可能请求调用某个 Skill response llm_client.chat(messages, toolsall_skill_schemas) messages.append(response) # 2. 如果模型没有请求调用 Skill说明已经产出最终答复 if not response.tool_calls: save_memory(session_id, messages) return response.content # 3. 否则逐个执行技能调用把结果作为观察信息传回给模型 for tool_call in response.tool_calls: result skill_registry.execute(tool_call.name, tool_call.arguments) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) raise TimeoutError(Agent 执行超过最大轮次已终止)这段逻辑做的事情是给模型发送当前会话消息并附带所有 Skills 的调用描述。模型如果觉得需要查个什么东西就会返回一个 tool_call我们执行对应的技能把结果作为工具消息回填给模型然后继续下一轮。模型发现结果已经满足用户需求以后就会停止调用工具直接产出最终答复。这里面隐藏了一个很关键的取舍轮次上限不能太大。我一开始设了 10 轮结果模型偶尔会在多技能场景里陷入查一下、再确认一下、再查一下的循环既消耗算力又让用户等得久。后来我把 MAX_ROUNDS 改成 5同时要求模型每一轮都尽量带上对中间结果的判断体验反而好了很多。合理轮次上限是一种很实用的 Agent 保护机制。3.4 对接 LiteLLM Proxy让 Agent 只认一个模型接口我在agent/llm.py里没有直接对接某个厂商的 SDK而是统一请求 LiteLLM Proxy。伪代码大概是import httpx PROXY_BASE_URL http://localhost:4000 # 根据你的实际地址修改 def chat(messages, toolsNone): payload { model: gpt-4o, # 这个名字在 LiteLLM 路由配置里映射到真实的模型 messages: messages, tools: tools, tool_choice: auto, } resp httpx.post(f{PROXY_BASE_URL}/v1/chat/completions, jsonpayload) return resp.json()[choices][0][message]为什么这么做因为 LiteLLM Proxy 默认暴露的是 OpenAI 兼容接口而腾讯云上的环境变量、配置管理都很方便把不同供应商的 Key 塞进 LiteLLM 的配置里就可以在 Agent 代码里完全屏蔽厂商差异。如果你后续想把主模型从一家换到另一家只需要改 LiteLLM 的路由配置Agent 一行代码都不用动。有一点要提醒LiteLLM Proxy 的地址不要写死在代码里。我通过环境变量注入部署到不同环境时改环境变量即可避免把内网地址或者 Key 一起提交到代码仓库。3.5 部署到腾讯云从本地到线上的完整链路本地跑通之后我开始部署。这一步充分体现了选腾讯云的便利性整体链路大概是第一把 LiteLLM Proxy 打包成容器镜像推到腾讯云容器镜像服务TCR然后在轻量服务器或 TKE 上启动这个容器。镜像推送用 Docker 命令就可以注意在腾讯云的镜像仓库控制台里拿到登录凭据docker login之后docker push这一步不要在公网明文操作凭据分分钟会泄露。第二创建云函数服务把 Agent 代码和 skills 目录打包上传。函数入口设置为一个 WSGI/ASGI 应用或一个处理事件的方法腾讯云会把 API 网关的请求转换成函数事件。第三在 API 网关控制台创建 API选择云函数作为后端函数选择刚部署的 Agent 服务。路径设置成/chat或/agent/chat然后发布到对应环境。第四在云函数的配置里设置环境变量LLM_PROXY_URLhttp://容器内网地址:4000、REDIS_URLredis://内网地址:6379、API_ACCESS_KEY你的自定义密钥。云函数和容器、Redis 尽量放到同一个 VPC 里这样数据链路不经过公网安全性和速度都好很多。部署完以后我习惯先在本地 Postman 或 curl 里模拟一遍完整请求再打开 API 网关的公网地址测试。第一次出现 500 不奇怪多半是环境变量没配上或函数入口路径写错了后面单独一节说排查。4. 常见问题排查与避坑实录4.1 Agent execution terminated due to error 到底在报什么搜这个关键词的人特别多说明这是个高频问题。这个报错在各类 Agent 框架里都有本质上是 Agent 执行过程中某一个环节抛了异常框架兜不住就把整个执行终止了。我遇到过的情况主要有三类结构化输出解析失败模型返回的 tool_calls 里参数不是合法 JSON或者字段名和 Schema 对不上。解决思路是所有 Skill 的参数解析要容错解析失败时返回一个格式化异常的工具消息让模型自己修正而不是直接抛异常终止。模型响应被限流或超时调用模型 API 时偶发 429 或 504导致本轮循环没拿到模型消息。解决思路是在 llm 客户端里加重试机制配合 LiteLLM Proxy 的 fallback 配置一次失败自动换另一个供应商。某个 Skill 内部抛了业务异常比如查数据库查不到数据、第三方接口返回 500。解决思路是Skill 执行函数要做异常捕获把错误消息作为工具结果返回给模型让模型基于错误信息决定下一步而不是把异常抛出到 Agent 主循环。一句话总结Agent 的容错设计应该是把错误变成观察结果而不是把错误变成异常。这一步做扎实了很多奇奇怪怪的终止报错都会消失。4.2 云函数超时和冷启动怎么处理云函数一个很常见的限制是执行超时时间。默认可能只有几秒但 Agent 的核心循环动不动就要调用两三轮模型每轮模型响应可能就要几秒整体很容易超过函数超时限制。所以在创建云函数时我会把超时时间调大到合理范围比如 60 秒。也不适合设置得太夸张超时时间越长计费越高而且确实挂了的话用户等得越久。冷启动的问题我用了两个办法缓解在云函数的并发配置里开启预置并发让一定数量的实例常驻付一点冷启动成本换响应速度把所有重的初始化比如 Skills 扫描、模型工具列表生成尽量放到函数外部的全局作用域。腾讯云函数的执行环境在一定时间内会复用实例全局变量可以减少重复初始化的消耗。4.3 自己装 Redis 改完密码重启失败一个云上依赖服务的经典教训虽然我在腾讯云上更推荐用云 Redis但如果你还是想自己装我把这个搜索热度很高的问题单独说下。我总结的排查顺序是确认配置文件里requirepass是否已修改daemonize yes是否开启停止 Redis 后用redis-server /你的/redis.conf显式指定配置启动不要只敲redis-server因为后者可能用了默认配置检查启动日志有没有报auth相关的警告客户端连接时使用redis-cli -h 127.0.0.1 -p 6379 -a 你的新密码测试注意-a在公网环境下会出现在进程列表里自己测试没问题生产环境要用REDISCLI_AUTH环境变量或配置文件方式。这里有个容易踩的细节如果你修改了密码但系统里有其他服务比如 Agent 的 memory 模块还在用旧密码连接重启 Redis 之后所有连接都会瞬间断开。部署顺序最好是先把依赖方切换到新密码再重启 Redis这样业务中断时间最短。4.4 密钥和安全Agent 项目里的底线问题Agent 项目因为天然要调用外部 API密钥管理尤其重要。我在这个项目里强制规定了三条底线模型供应商的 Key、云 API 的 SecretKey、Redis 密码等一律放在腾讯云的环境变量或密钥管理系统里严禁写进代码或镜像里默认关闭公网对 LiteLLM Proxy 和 Redis 的暴露这两个组件只在 VPC 内网访问API 网关入口做鉴权最简单的方式是在网关层设置一个自定义 Header 校验Agent 服务校验通过才继续处理。安全这块没有多少高深技术就是别偷懒。一旦 Key 泄露损失的不只是钱还有可能影响整个项目的可用性。5. 我的实操心得与后续扩展建议5.1 本地部署与云上部署的配合最后聊一点我自己的体会。很多人会纠结 Agent 到底是本地部署还是放云上我实际用下来这俩不是二选一的关系。本地部署的价值在于开发和调试效率高。我在本地直接跑 Agent 主循环每天迭代 Skills 定义、调参、看日志速度非常快。云上部署的价值在于稳定和可共享。跑通以后部署到腾讯云API 网关给一个公网地址任何人、任何系统都可以调用同时云上的云函数、数据库、网关都自带监控和告警不用自己操心。我现在的习惯是本地一个开发环境云上一个测试环境正式环境再套一层更严格的权限控制。三个环境的代码同源通过环境变量区分配置这样既快又稳。5.2 Agent 记忆的最简实现关于记忆很多人一上来就想上向量数据库、搞知识库我觉得可以分步走。对于很多场景Redis 存最近几轮消息已经能解决大部分需求。实现上就是给消息设置一个session_id按agent:{session_id}:messages这个 key 存一个列表每次对话前把上下文取出来拼到 messages 里对话结束后再追加保存。真正的长期记忆比如用户是新手、偏好简洁回答、上周讨论过某项目的架构这些更适合在用户画像或项目档案的结构化存储里维护不一定非要靠对话历史自动推测出来。做 Agent 有一个朴素的道理先解决记忆有没有再解决记忆准不准。5.3 后续还能往哪些方向扩展我后续计划给这个 Agent 加的技能和方向大概有三个接入企业内部的 API让 Agent 能查订单、建工单、发审批真正变成业务助手给 Skills 加上权限分级不同用户能看到不同的技能防止越权操作用流水线的方式做一批回归测试集每次加新 Skill 以后自动跑一遍确保旧技能没有被新改动破坏。说实话Agent 这个领域变化太快今天的最佳实践过几个月可能就是老古董。但有一个判断我觉得不会变真正有价值的 Agent不是模型有多大、框架多花哨而是它到底能不能稳定地替你干成一件实事。Skills 设计的用心程度、部署链路的可靠程度、出问题之后的排查能力这些才是决定一个 Agent 能从 Demo 走向生产的关键。我这次在腾讯云上从零到一跑通的过程最大的收获不是做出了某个具体的 Agent而是把这套模型 技能 云上基建的方法论跑顺了。顺着这条链路以后每加一个场景就是往 skills 里塞一个新模块的事。这篇博客提到的架构、代码片段和踩坑记录都是我自己实测过的希望也能帮你少走一点弯路。