我最早做 Agent 项目的时候犯过一个特别典型的错误本地 demo 跑得飞起模型一调用工具答案有板有眼我差点就以为这玩意儿能直接上生产了。结果一部署到腾讯云服务器上各种问题接二连三地冒出来超时、上下文爆掉、模型乱调工具、技能一多编排逻辑就成一团乱麻最后只能对着日志发呆。后来我把整个项目重写了一遍按照“Skill”的思路把 Agent 的能力彻底拆开再结合腾讯云上的容器服务、知识引擎这些基础设施重新组织整个系统才真正稳定下来。这篇文章就是把这次重构的完整过程整理出来核心就一句话Agent 能不能养成关键不在模型而在你怎么设计和编排它的 Skills。我会讲清楚 Skill 和 Agent 的区别、为什么要把能力拆成技能而不是塞进 Prompt、怎么在腾讯云上实现一套可复用可维护的技能体系包括 LiteLLM Proxy 做模型收口、Docker 镜像推送腾讯云容器镜像服务的完整步骤最后再分享一些实践中踩过的坑和排查经验。无论你是刚入门 Agent 开发还是已经在做企业级智能体交付这篇都能给你一个可以直接上手的参考路径。1. 先把概念理清Agent 和 AI Skills 到底什么关系1.1 Agent 不是框架是一种架构思路我发现很多刚接触 Agent 的开发者第一反应是找一个“Agent 框架”比如 LangChain、AutoGen、MetaGPT然后期待框架能解决一切。但实际上框架只是工具Agent 的核心是一种架构思路模型作为大脑负责理解任务、拆解计划、调用工具、评估结果外部系统负责执行具体动作把世界的信息反馈给大脑。这个“大脑手脚”的结构才是 Agent 区别于普通 ChatBot 的本质。一个真正能落地的 Agent 架构通常包含几个核心模块模型入口LLM Runtime、规划模块Planner/Reasoner、记忆模块Memory、工具/技能模块Tools/Skills、执行与反馈模块Executor/Environment。你可以把这块理解成一个公司模型是老板规划模块是秘书记忆模块是档案室工具和技能就是各个业务部门的专业人员。老板不需要亲自写代码、查库存、发邮件他只需要知道什么时候该叫哪个部门干活然后把结果汇总成最终答案。在这个架构里最容易被人忽略的就是“技能层”。很多人一开始只给 Agent 挂两三个 API 函数跑通一个 demo 就觉得自己做完了一旦业务复杂起来比如 Agent 需要同时处理订单查询、物流跟踪、售后话术生成、客户画像分析你会发现工具列表越加越长Prompt 越来越臃肿模型开始频繁选错工具甚至同时调用互斥的技能。这就是因为缺少了“Skill 层”的设计。1.2 Skill 是 Agent 的造血干细胞Skill 这个概念简单说就是把一组相关的原子能力封装成一个可被 Agent 识别、调用、组合的功能单元。它比单个 Function 的粒度更大比一个完整的业务流程更小是介于两者之间的“能力块”。比如“查询订单状态”是一个 Skill它内部可能包含调用订单系统 API、解析状态码、格式化输出、异常兜底这些步骤“生成售后话术”是另一个 Skill它内部可能包含检索售后政策、关联客户历史工单、调用模型生成话术、多版本润色等步骤。Skill 和 Agent 的关系就是技能与使用者的关系。Agent 负责“决策”Skill 负责“执行”。一个 Agent 可以挂载多个 Skill同一个 Skill 也可以被多个 Agent 复用。这种关系在工程上带来两个直接好处能力可复用一个团队把“发送短信”这个 Skill 沉淀好所有 Agent 都可以直接调用不用每个 Agent 各写一套调用逻辑。能力可隔离每个 Skill 的输入输出、错误处理、权限校验都是独立的。某一个 Skill 挂了不会拖垮整个 Agent模型也不会因为某个工具的异常输出而彻底崩溃。所以我一直坚持一个观点Skill 才是 Agent 的造血干细胞。Agent 的“智能上限”由模型决定但“能力边界”由 Skill 决定。你给 Agent 配齐了哪些 Skill它就能干什么活。与其不断堆 Prompt 去“教”模型更多领域知识不如把领域能力沉淀到 Skill 里让模型通过工具调用来获取这些能力。这样既降低了模型的认知负担也大大提升了系统的可维护性。2. 为什么我把业务拆成 Skill而不是全部塞进 Prompt2.1 一次改需求改到怀疑人生的经历我先讲一个让我决定重构的亲身经历。最早我负责一个客服 Agent所有指令、工具说明、回答风格全写在一个超长的 System Prompt 里工具定义也堆了十几个整个 Prompt 大概有四千多字。一开始模型表现还行但上线之后每次改需求都像在走钢丝。有一次产品经理说“售后话术里要加入最新的退换货政策”我只需要改一段 Prompt但改完发现模型开始把查询订单的工具也用错了甚至有些正常的“查物流”请求被模型强行包装成了“售后咨询”。这个问题背后的原因其实很典型当工具数量和指令复杂度超过一定阈值后模型在超长上下文中精准选择工具的准确率会明显下降。尤其当多个工具之间的功能边界比较接近时“工具选择”就成了一件高难度任务。而且 Prompt 里的信息是线性的模型需要从头到尾阅读一遍才能理解所有工具这个过程中很容易丢失细节。更重要的是这种“全塞 Prompt”的方案还带来安全和成本问题。工具多了以后Prompt 中必然包含大量描述文本这些文本会持续占用上下文窗口的 token 额度。用户随便聊几句上下文就接近窗口上限要么被迫走文本截断要么就得为超长上下文支付更高的推理成本。我当时的账单一个月下来光是上下文重建的 token 花销就占了总成本的三分之一这个数字让我彻底下定决心重构。2.2 腾讯云上搭建技能承载层我的架构选型重构的第一步是给 Skill 找一个可靠的“家”。我的选型思路是Skill 可以是一个独立的云函数也可以是一个容器服务甚至是一组通过 API 网关暴露的 HTTP 接口。只要它满足两个条件——可以被 Agent 通过标准协议调用且具备独立的生命周期管理能力那么就可以作为 Skill 的承载单元。我当时用了腾讯云的一套组合方案容器化部署核心的 Skill 用 Python 写成独立的 FastAPI 服务打包成 Docker 镜像推送到腾讯云容器镜像服务 TCR然后部署到轻量应用服务器或者 TKE 集群上。这样每个 Skill 都可以独立扩缩容独立发布版本。API 网关统一暴露通过 API 网关对外暴露 HTTPS 接口Agent 通过网关调用 Skill。这样可以在网关层面统一做鉴权、限流、日志记录避免每个 Skill 各搞一套安全机制。知识型 Skill 对接知识引擎对于需要检索企业内部文档的 Skill我没有自己搭 RAG 全链路而是直接对接腾讯云大模型知识引擎把文档库托管在上面。Skill 内部只需要调用知识引擎的检索接口把最相关的片段拉回来拼成上下文即可。这套架构的好处是每个 Skill 都是一个独立的服务拥有自己的版本号、日志、监控和扩缩容策略。Agent 侧不感知 Skill 的内部实现它只需要知道这个 Skill 是干什么的、输入什么、输出什么。这样一来“改需求”就变成了“升级某个 Skill 的版本”完全不影响其他能力和 Agent 的主逻辑。2.3 为什么我坚持用 LiteLLM Proxy 收口上游模型单独说一下模型层。如果你的 Agent 只服务一种模型比如只用通义千问或者只用 DeepSeek那确实不需要额外的模型网关。但现实是业务场景一变模型需求就五花八门有的场景要便宜快速的模型做简单分类有的场景要强推理模型做复杂规划有的场景要长上下文模型来处理大文档。每一次切换模型都要改代码、换 SDK、调参数这显然不可持续。我用 LiteLLM Proxy 把模型接入层统一收口所有 Skill 和 Agent 主流程只跟一个 OpenAI 兼容的接口打交道由 Proxy 负责把请求路由到不同的上游模型。这个方案在实践中有几个非常实用的收益无缝切换模型改一个配置文件就能把某个场景的模型从 A 换成 B不用动任何业务代码。统一限流和重试在 Proxy 层统一配置 QPS 限制、超时时间和重试策略避免上游模型偶尔限流直接把 Agent 流程打挂。我之前遇到过一个典型问题就是没有做限流时Agent 并发一上来多个 Skill 同时调模型直接把额度打爆后来在 LiteLLM Proxy 上做了排队和熔断才解决。集中埋点观测所有模型请求的 token 消耗、响应延迟、错误码都统一进了日志系统做成本分析的时候非常方便。如果你也在做 Agent 项目我强烈建议在一开始就把模型网关建好别等业务复杂了再补。这里说的不一定非要用 LiteLLM Proxy任何支持 OpenAI 兼容协议的网关都可以核心是让“模型”成为可替换的组件而不是和业务代码深度耦合。3. 手把手从零搭一个带 Skill 的 Agent 并部署到腾讯云3.1 整体目录与核心代码结构接下来是我的实操部分。我不会给你一个只能跑 demo 的玩具而是一个可以逐步扩展的骨架。我的项目目录大概是这样的agent-project/ ├── agent/ │ ├── __init__.py │ ├── core.py # Agent 主循环 │ ├── memory.py # 记忆模块 │ ├── registrar.py # Skill 注册与查询 │ └── logger.py # 结构化日志 ├── skills/ │ ├── __init__.py │ ├── order_query.py # 订单查询 Skill │ ├── after_sale.py # 售后话术 Skill │ └── weather.py # 天气查询 Skill示例 ├── config/ │ ├── litellm.yaml # LiteLLM 网关配置 │ └── agent.yaml # Agent 全局配置 ├── Dockerfile └── requirements.txtAgent 主循环的核心逻辑简单说就四步接收用户输入、判断意图并制定计划、调用对应的 Skill、汇总结果生成回复。我用一个最小实现演示一下思路# agent/core.py import json from typing import List, Dict from .registrar import SkillRegistrar class Agent: def __init__(self, model: str, registrar: SkillRegistrar, memory): self.model model self.registrar registrar self.memory memory async def run(self, user_message: str) - str: # 1. 从记忆读取历史上下文 history await self.memory.load_history() # 2. 让模型决定调用哪个 Skill decision await self.decide(user_message, history) if decision.get(type) call_skill: skill_name decision[skill_name] params decision[params] skill self.registrar.get(skill_name) # 3. 执行 Skill try: result await skill.execute(**params) # 4. 把结果交给模型生成最终回复 return await self.generate_reply(user_message, result) except Exception as e: self.memory.save_error(skill_name, str(e)) return 当前技能执行失败请稍后再试。 # 不需要调用 Skill 的情况 return await self.generate_reply(user_message, None)这里最关键的是 SkillRegistrar它维护了一个“技能注册表”Agent 在决定调用什么能力时会先从注册表里拉取每个 Skill 的“元信息”比如名称、功能描述、输入参数 schema。模型看到这些信息后再决定选哪个 Skill、传什么参数。# agent/registrar.py from typing import Dict, Type from pydantic import BaseModel class BaseSkill: 所有 Skill 的基类必须实现 execute 方法 name: str description: str parameters_schema: Dict {} async def execute(self, **params) - str: raise NotImplementedError class SkillRegistrar: def __init__(self): self._skills: Dict[str, Dict] {} def register(self, skill: BaseSkill): 注册一个 Skill 到注册表 self._skills[skill.name] { name: skill.name, description: skill.description, parameters_schema: skill.parameters_schema, handler: skill, } def list_registry(self) - list[Dict]: 返回所有 Skill 的元信息供模型决策使用 return [ {name: v[name], description: v[description], parameters_schema: v[parameters_schema]} for v in self._skills.values() ] def get(self, name: str) - BaseSkill: return self._skills[name][handler]每个具体的 Skill 只需要继承 BaseSkill实现 execute 方法。我拿一个“售后话术生成”的 Skill 举例# skills/after_sale.py from agent.registrar import BaseSkill class AfterSaleSkill(BaseSkill): name after_sale_reply description 生成售后话术。当用户咨询退换货、退款、维修、投诉等问题时使用需要用户订单号和问题描述。 parameters_schema { type: object, properties: { order_id: {type: string, description: 用户订单号}, issue: {type: string, description: 用户描述的问题}, }, required: [order_id, issue], } async def execute(self, **params) - str: order_id params[order_id] issue params[issue] # 简化处理正常场景这里会调用知识引擎检索售后政策 policy await self._retrieve_policy(issue) return f针对订单 {order_id} 的售后问题「{issue}」处理建议{policy}写到这里你会发现Agent 本身不需要理解售后政策的细节它只需要知道“遇到售后问题就去调用 after_sale_reply 这个 Skill传订单号和问题描述”。所有业务复杂度都被封装在 Skill 内部Agent 的主循环始终保持清爽。这个架构还有一个隐藏好处新接手项目的同事不需要通读全部 Prompt只需要打开技能注册表看看每个 Skill 是干什么的就能快速定位问题。3.2 Skill 的本地调试先用 CLI 跑通再套 HTTP 壳很多新手写 Agent 喜欢直接把 Skill 暴露成 HTTP 服务然后从测试工具开始调。我建议反过来先把 Skill 做成可以独立运行的模块在本地用命令行直接测。这样调试效率最高因为你可以绕开网络、鉴权、序列化这些干扰项直接验证核心逻辑。具体做法是给每个 Skill 写一个简单的本地调用入口我在项目里直接用 pytest 写用例# tests/test_after_sale.py import pytest, asyncio from skills.after_sale import AfterSaleSkill def test_after_sale_params(): skill AfterSaleSkill() with pytest.raises(TypeError): # 缺少 order_id 时必须报错 asyncio.run(skill.execute(issue想退款))这些用例的价值在于它们把 Skill 的输入输出约束固化下来了。将来你调模型、改 Prompt、换算法只要跑一遍测试就能确认 Skill 的行为没有被意外破坏。等本地逻辑稳定了再用 FastAPI 把 Skill 包成 HTTP 服务加一个统一路由# skills/http_server.py from fastapi import FastAPI from pydantic import BaseModel from skills.after_sale import AfterSaleSkill app FastAPI() skill AfterSaleSkill() class RequestBody(BaseModel): order_id: str issue: str app.post(/skills/after_sale_reply) async def call_after_sale(req: RequestBody): result await skill.execute(order_idreq.order_id, issuereq.issue) return {result: result}这里要注意HTTP 层的参数校验一定要独立做一遍不能完全依赖模型传参。模型有可能把一个必填字段传成空字符串或者把字符串传成对象这些脏输入必须在进入 Skill 业务逻辑之前被拦截住。3.3 Docker 打包与推送腾讯云容器镜像服务把 Skill 本地跑通之后就要上云部署了。这里说下我在腾讯云上的完整流程特别是镜像推送这块第一次操作的时候踩了好几个坑。先写 Dockerfile没什么花哨的FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://mirrors.cloud.tencent.com/pypi/simple COPY . . CMD [uvicorn, skills.http_server:app, --host, 0.0.0.0, --port, 8000]然后本地构建镜像。我习惯给镜像打两个 tag一个是带版本号的一个是 latestdocker build -t after-sale-skill:1.0.0 . docker tag after-sale-skill:1.0.0 ccr.ccs.tencentyun.com/your-namespace/after-sale-skill:1.0.0 docker tag after-sale-skill:1.0.0 ccr.ccs.tencentyun.com/your-namespace/after-sale-skill:latest接下来是登录腾讯云容器镜像服务。走了几次弯路之后我总结了一下登录有两种方式一个是直接用 docker login 登录到 TCR 的域名另一个是先在控制台拿到访问凭证再登录。我用的是第一种比较直接docker login ccr.ccs.tencentyun.com --username你的腾讯云账号ID注意这里的 username 不是邮箱也不是手机号而且密码不是腾讯云登录密码而是访问凭证。第一次我就是搞混了这个输了一堆正确但无效的账号密码折腾了半天。在腾讯云容器镜像服务控制台“访问凭证”页面生成一个临时凭证拉到密码输入框中回车就能成功登录。然后 pushdocker push ccr.ccs.tencentyun.com/your-namespace/after-sale-skill:1.0.0 docker push ccr.ccs.tencentyun.com/your-namespace/after-sale-skill:latest推送成功后到控制台确认一下镜像版本没错然后就可以拿着镜像地址去创建服务了。我当时的部署目标是轻量应用服务器因为 Skill 的并发请求不算高轻量服务器性价比更好如果你的 Agent 要面对大流量建议上 TKE 之类的容器服务方便自动扩缩容。部署完成后还需要在腾讯云 API 网关新建一个 API把对/skills/after_sale_reply的 POST 请求转发到轻量服务器对应的端口然后在网关层配好鉴权和限流。这一步千万不要偷懒因为你的 Agent 可能在任何时间发起请求没有网关的统一入口后期排查问题会非常痛苦。3.4 Skill 上线后先做横向回归再切流量Skill 部署完不等于完事。我的习惯是在正式把 Agent 的流量切到新 Skill 之前先做一轮“横向回归测试”也就是把历史对话记录里的典型请求一条条抽取出来重新跑一遍看新 Skill 的结果和之前有没有明显差异。这个步骤听起来很繁琐但能拦下绝大多数回归问题。具体做法很简单把用户问题、期望调用的 Skill、期望的参数、期望的回复风格整理成一个 JSON 文件然后在测试环境用脚本批量回放。我一般会关注几个维度Skill 选择是否正确该调用售后 Skill 的 case 有没有被模型错误路由到订单查询 Skill。参数提取是否完整模型有没有把必要的参数全部提取出来有没有漏字段。最终回复是否达标把回复结果和人工标注的参考回复做对比确认没有答非所问。这一步做完我才会在 API 网关上把流量从旧版本切到新版本。整个过程尽量用灰度方式先切 10% 流量观察一两天没有问题再逐步全量。4. Agent 记忆与 Skill 编排的几个关键细节4.1 记忆分层短期记忆、长期记忆和工作记忆Agent 能不能像人一样“记住”之前聊过什么直接影响用户体验。我按标准的三层记忆模型来设计短期记忆管理当前对话的上下文长期记忆存用户的偏好和历史事实工作记忆记录当前任务执行到哪一步、哪些 Skill 还没调用完。短期记忆我直接走内存用一个 LRU 队列控制长度超出窗口就丢弃最早的消息。这里有个坑模型上下文窗口不是无限的。如果你只是简单地把所有历史消息都塞给模型很快上下文就会爆掉推理成本也会失控。我的做法是给每条消息打上时间戳和 token 数满了之后按照重要性策略淘汰比如系统级指令和最近两次用户消息保留其他历史消息做摘要化压缩。长期记忆我放在云端的 Redis 和向量数据库里。Redis 存 KV 型数据比如“user_123 的会员等级是银卡”“user_123 偏好简洁回复”向量库存用户历史订单、文档片段这类需要语义检索的数据。这里有必要提醒一下如果你在腾讯云服务器上装了 Redis 并修改了密码一定要同时更新所有客户端的连接配置并且确认 Redis 配置文件中requirepass持久化了。我之前就遇到过改了密码后重启 Redis 服务结果发现redis.conf里根本没保存新密码服务起不来排查了很久才发现是配置文件权限问题导致修改没写入。工作记忆比较容易被忽略它的作用是在多步任务中记录执行状态。比如 Agent 要完成一个“查订单-核对地址-生成退款单”的流程工作记忆会记录当前已经执行到哪一步、每一步的结果是什么。一旦中间某一步失败Agent 可以基于工作记忆判断是从头再来还是从失败步骤重试。这个设计能极大提高复杂任务的健壮性强烈建议你在 Agent 主循环中预留一个task_state字段。4.2 多 Skill 编排并行、串行、回退与超时当 Agent 挂了五六个 Skill 之后如何编排它们的执行顺序就成了新的问题。不是所有任务都只调一个 Skill 就能完成的。我遇到过三种典型场景串行依赖比如“查询订单状态”之后根据状态决定是否“发起售后”或者“推送物流信息”。这种场景需要把图式流程拆成一步步的串行调用。并行拉取比如用户问“我的订单什么时候到顺便看看这个商品有没有优惠”Agent 需要同时查询物流接口和优惠接口。并行执行能明显缩短响应时间。回退降级比如某个 Skill 内部报错Agent 不能直接摆烂要有一套降级方案比如改用另一个相似 Skill 或者直接给用户一个保守回答。我在 Agent 主循环里写了一个简单的“计划执行器”它的职责是把模型的决策转换成实际调用。核心原则是一次任务尽量只让模型做一次“计划”不要让模型每走一步都重新思考。因为模型在多轮工具调用中很容易“迷失方向”尤其当上下文里堆了几轮工具返回结果之后。超时控制也特别重要。每个 Skill 调用都必须有超时上限和对应的错误处理。我一般在网关层设置 10 秒超时在 Agent 主循环里再设一道 8 秒超时给自己留 2 秒处理错误和生成回复。如果 Skill 超时了Agent 应该向用户说明“这个操作比较慢我已经帮你转到人工处理”而不是让用户一直看着转圈。4.3 Skill 版本管理与灰度发布Skill 也是软件有版本有变更。最怕的情况是Agent 运行得好好的突然某个 Skill 的输出格式变了导致后续步骤解析失败。我用两个手段避免这种事故版本号硬编码到请求头Agent 调用 Skill 时在请求头里带上X-Skill-Version: 1.0.0网关根据版本号把请求路由到旧版或新版服务。这样即使新版有 bug也能快速通过网关回退。Schema 兼容性检查Skill 的参数和返回结构做了严格定义后每次发布前都跑一次 schema 对比测试确保新增字段不会破坏旧的解析逻辑。如果确实要改字段类型就立一个新版本号而不是原地修改接口。除此之外每个 Skill 上线前都要检查“幂等性”。尤其是金融、订单这类敏感领域同一个请求如果因为网络重试被执行两次后果很严重。我的订单查询 Skill 是天然幂等的查询不会改数据但“发起退款”这种写操作就必须加唯一请求号Agent 侧每次调用都生成一个request_idSkill 侧根据这个 ID 去重。5. 实战复盘常见问题与排查技巧实录5.1 高频问题速查表这里我把实操中遇到的高频问题整理成一个速查表方便你遇到问题时直接对号入座问题现象常见原因定位思路解决方案Agent 一直说“当前技能执行失败”上游模型超时 / Skill 服务异常 / 参数解析错误看 Agent 日志里最后一行异常栈看是 HTTP 调用失败还是模型返回不合法在 LiteLLM Proxy 层查请求和响应在 API 网关看 Skill 返回码模型选错 SkillPrompt 中的技能描述太模糊查看模型决策的原始输出看它认为每个 Skill 是干什么的重写每个 Skill 的“description”说清楚能力边界和适合场景上下文爆掉导致调用失败没有做记忆裁剪历史消息无限累积看请求日志里的 token 数是否接近窗口上限实现 LRU 淘汰和摘要压缩长对话做分段切割Docker push 到腾讯云镜像服务失败登录凭证过期 / 命名空间不对先执行docker info看登录状态再确认仓库路径重新生成访问凭证确认命名空间名拼写Agent 执行中途报agent execution terminated due to error多步计划中某一步异常导致整个会话中断查看是哪一步异常是模型调用超时还是工具执行报错对每个 Skill 调用加上超时和降级逻辑在计划执行器里 catch 异常Redis 修改密码后重启失败requirepass没写进配置文件或权限导致写不进去用redis-server /path/to/redis.conf手动启动看报错信息确认 redis.conf 保存成功改完密码后同时更新所有客户端连接配置5.2 “agent execution terminated due to error”深度排查这是我在各种 Agent 项目里见过最多的一条报错也是最难排查的一条因为它太笼统了只告诉你“执行终止出错”却不告诉你是哪一步出错。我花过几个晚上去追一个这样的 bug后来总结出一套排查流程第一步先看 Agent 主循环的完整日志而不是只看最后的错误信息。我的做法是把每一次工具调用的请求和响应都打到结构化日志里包括模型决策内容、Skill 名称、开始时间、结束时间、返回结果摘要、异常信息。这样报错出现时能直接定位是第几步调用出了问题。第二步区分是“模型决策错误”还是“Skill 执行错误”。如果日志显示模型决定调用某个 Skill 但传参完全不对那是决策层的问题如果 Skill 确实收到正确的参数但返回了 500那是 Skill 实现的问题。这两个方向的排查思路完全不一样前者要去看模型的能力描述和示例后者要去看代码和依赖。第三步也是最容易被忽略的一点多步任务的幂等和状态恢复问题。如果 Agent 在执行到第三步时挂了重新拉起之后它往往会从头执行这可能造成重复操作或者产生脏数据。我的方案是给每一步操作加上“已完成”标记Agent 启动时先检查工作记忆里的任务状态跳过已经完成的步骤。5.3 成本与性能优化在给用户回复前先“算账”最后说说大家都关心的成本问题。Agent 项目比普通 Chatbot 贵因为它每次任务可能多次调用模型每次模型调用都产生 token 开销。我做了几个优化效果非常明显优先用便宜模型做意图识别和 Skill 路由。我的架构里判断“用户想干嘛、该调哪个 Skill”这个任务不需要强推理模型用便宜快速的模型就够。等真正要生成话术、总结结论的时候才切换到能力更强的模型。压缩工具返回内容。Skill 返回的结果往往又长又结构化但模型回复用户时可能只需要其中一小段。我会在传给模型前对结果做裁剪只保留关键字段大大减少上下文 token 消耗。对常规问题做缓存。比如“退货政策是什么”“营业时间几点到几点”这类高频问题直接在 LiteLLM Proxy 或 Agent 层做语义缓存命中缓存就直接返回答案连模型都不调用。这四个点做下来我的月度成本大概降了 40%而且响应速度明显提升。尤其是缓存那一步收益立竿见影。5.4 给新手的最后几条实在建议如果你准备开始做 Agent 项目我把这几条压箱底的经验给你第一不要一上来就追求“全知全能”。先用最小的闭环跑通一个流程比如只做一个 Skill让 Agent 能解决一类问题然后慢慢加技能。技能多了以后你会发现维护成本是线性增长的如果一开始就没设计好后面会越来越痛苦。第二日志一定要从第一天就做好结构化。不要偷懒不要用 print 凑合。Agent 的调试比传统后端难得多因为它的行为是概率性的同一个问题两次可能走完全不同的路径。没有完整日志你根本没法定位问题。第三把模型当作一个“能力不错但容易犯错的实习生”来管理。你要给它清晰的指令Skill 描述、给它必要的工具Skill 实现、给它明确的反馈错误处理还要给它留后路降级方案。你把这几件事做扎实了Agent 的稳定性自然就上来了。我个人在把项目重构完之后的最大感受是Agent 养成的过程其实是在培养一套工程化的能力体系模型的智商只是起点决定 Agent 真正能飞多高的是它脚下那块由 Skill 组成的踏脚石。每次新业务进来我只需要评估“要不要加一个 Skill”而不是“要不要改 Prompt”这个变化让整个团队的交付效率提升了一大截。希望这篇实战记录能帮你少走一些弯路。