最近一段时间我一直在做一件事把公司里一堆散落的自动化脚本重构成一个真正意义上能“自己干活”的全能 Agent。初步跑通之后我总结出一个规律——凡是能用好的 Agent背后一定有一套设计良好的 AI Skills凡是动不动就翻车的 Agent问题九成出在技能边界没划清楚。这篇文章不聊概念只聊我实际在腾讯云上把一个 Agent 从“会聊天”变成“能干活”的完整过程包括 Skills 怎么设计、怎么部署、怎么排障全部是可落地的最佳实践。如果你已经知道 Agent 是什么但卡在“框架搭好了却不知道该让它干什么”的阶段或者你有一些 Python 脚本想封装成 Agent 能调用的能力又或者你正在纠结 Skill 和 Agent 到底怎么分工——那么这篇文章就是给你写的。1. 先想清楚Agent 和 Skill 到底是什么关系1.1 我踩过的一个坑最早我做 Agent 的时候犯过一个特别典型的错误把需求一股脑全塞进 System Prompt 里。当时要做一个运维巡检助手我在提示词里洋洋洒洒写了两千多字告诉模型看到 CPU 高了要怎么办、看到磁盘满了要怎么办、看到日志报错又要怎么查。结果上线第一天就翻车了——模型确实“知道”所有规则但它不知道如何去调用真实的服务器 API也不知道该在什么时机触发检查最后只是凭空生成了一堆看似合理但完全没法执行的建议。后来我才明白问题出在哪Prompt 只能让模型“知道”无法让模型“做到”。Agent 的本质是一个决策和调度系统它需要外部能力来真正完成动作。这些外部能力就是 AI Skills。1.2 Skill 是一张“技能卡”Agent 是持卡人我现在的理解方式比较接地气把 Agent 想象成一位项目经理把 Skill 想象成一张张技能卡。项目经理自己不亲自写代码、不发请求但他看到任务之后会从手里的技能卡里挑出最合适的一张照着卡上的说明去执行。Skill 通常包含三样东西一个可以被程序调用的函数或服务真正干活的代码一份参数 Schema告诉 Agent 这个技能需要什么输入比如 IP 地址、时间范围、阈值一段自然语言描述告诉 Agent 这个技能是干嘛的、什么时候用它、什么时候别用它这三者缺一不可。没有描述模型不知道该选它没有 Schema模型传参会靠猜没有服务本体整个 Skill 就是个空壳。1.3 为什么要拆 Skill而不是全塞进 Prompt这个问题我反复被问到过。很多人觉得既然大模型能力这么强我写清楚它自己去执行不就行了答案是不行原因有三点第一可测试性。Prompt 是黑盒你没法单独验证某一段逻辑是否正确。但 Skill 是一个独立函数你可以像测普通接口一样给它喂测试数据断言返回结果。哪个 Skill 挂了单独修哪个不需要把整段 Prompt 重新调一遍。第二可复用性。一个“日志查询”Skill既可以让运维 Agent 用也可以让数据分析 Agent 用甚至可以让客服 Agent 用它来查订单日志。如果你把逻辑写死在 Prompt 里换个场景就得重新写一段。第三可灰度性。Skill 可以单独升级、回滚、限流。今天把一个 Skill 从 v1 升到 v2完全不影响 Agent 的其他部分。这在生产环境里太重要了——我经历过一次 Prompt 改了一个词结果整个 Agent 回复风格全变的诡异事故但换成 Skill 之后就再没出过这种问题。2. 全能 Agent 的 Skill 规划与设计规范2.1 一个 Agent 挂多少 Skill 才合理这是我在设计初期最纠结的问题。挂少了Agent 能力不够挂多了模型在“选择障碍”里迷失反而什么都不敢调。实测下来我的经验是一个 Agent 日常挂载的 Skill 数量控制在 5 到 8 个之间超过 10 个之后模型选错工具的概率会明显上升。你想想让一个人在二十个工具里挑一个他都要犹豫一会儿大模型也一样。工具越多参数空间越大出错概率越高。如果你确实有超过 10 个能力怎么办两个办法第一做“Skill 分组”比如把监控类、数据处理类、消息通知类各编成一组Agent 先选组再选具体 Skill第二把能力相关的 Skill 合并比如“查服务器 CPU”“查磁盘使用”“查内存占用”合并成一个“查服务器基础指标”Skill通过参数区分。2.2 Skill 的输入输出设计把不确定变成确定Skill 和普通函数的区别在于普通函数的调用方是人人懂得变通Skill 的调用方是大模型它只会照着 Schema 理解参数。所以设计 Skill 时输入输出必须极度明确把一切模糊空间堵死。我整理了一套自己的设计模板你可以直接参考设计项要求示例名称动词开头目标明确query_server_metrics描述说明用途、适用场景、不适用场景查询指定服务器的 CPU、内存、磁盘使用率。仅用于查询实时指标不可用于历史数据分析输入参数必有默认值、取值范围、单位timeout 默认 10 秒范围 1-60 秒输出结构固定字段扁平化避免嵌套过深返回 status、data、message 三个字段特别注意输出结构一定要固定。我在初版 design 的时候有个 Skill 返回的 JSON 结构不固定有时候带 error 字段有时候直接抛异常导致 Agent 在解析结果时经常猜一猜就出错。后来把所有 Skill 的输出统一成{ code: 0, data: ..., message: ok }这种结构模型解析的成功率一下子拉满了。2.3 Agent 记忆与上下文Skill 之间如何共享状态设计完单个 Skill 之后另一个问题是多个 Skill 之间怎么共享状态。比如用户问“帮我看看北京的服务器怎么样了”Agent 需要先通过定位 Skill 拿到北京机房的 IP 列表再把 IP 列表传给巡检 Skill 去查状态。这两次调用是有先后依赖的后者依赖前者的输出。处理这个问题的核心策略就是让 Agent 自己管理中间结果Skill 尽量保持无状态。换句话说Skill 不记忆任何东西只负责基于输入参数执行并返回结果“北京的 IP 列表是什么”这个状态由 Agent 的上下文窗口来维护。这样一来每个 Skill 都是幂等的、可重试的。同样的输入进去永远得到同样的输出。这种设计在后端排查问题时特别方便——任何一次异常你都可以拿着当时的参数重新调用一遍接口复现问题而不是靠猜。3. 腾讯云 AI Skills 落地选型与架构拆解3.1 为什么选择腾讯云这套生态说句实话Skills 的代码逻辑本身并不复杂有一台服务器就能跑。但真正让它变成“能稳定服务业务”的能力需要解决部署、弹性扩容、日志、鉴权、域名等一系列工程问题。我自己尝试过自己买服务器折腾后来还是把整套能力搬到了腾讯云上。原因有三个。第一是弹性云函数按调用次数计费高峰期自动扩容低峰期不产生费用不用再为闲置算力买单第二是生态整合云函数、API 网关、对象存储、日志服务这些组件都是打通好的不需要自己拼装第三是开发调试体验本地写好代码之后一条命令推上去马上就能在线测试。我见过不少团队花大量时间在自建服务上最后发现真正花在 Agent 业务逻辑上的时间反而不到一半。如果目标是尽快把 Agent 跑起来、把 Skills 沉淀下来用托管服务是更现实的选择。3.2 Skill 的三种部署形态对比虽然最终我推荐用云函数但你得先搞清楚不同形态的适用场景别一上来就选错。我把常用的三种部署形态整理成了一张对比表形态适用场景优点缺点腾讯云云函数SCF轻量 API、单次任务、调用不频繁免运维、按量付费、冷启动可接受不适合长时间运行、大内存任务容器服务TKE / 容器镜像 负载均衡重型计算、常驻服务、GPU 推理资源可预估、可控性高成本高、运维复杂API 网关 自建后端已有后端服务需要快速接入复用现有能力需要自己处理鉴权和限流大多数 Agent 的 Skill 都属于“轻量、低频率、逻辑明确”的类型所以我建议首选**云函数 **。如果你有某个 Skill 需要跑模型推理或者处理大文件再单独把它拆成容器服务通过 HTTP 接口暴露给 Agent 调用。混合架构完全没问题Agent 的调度层根本不关心后端是什么只要遵循统一接口协议就行。3.3 推荐的整体架构调度层、服务层、存储层我把整个系统的架构分成三层每一层的职责边界非常清晰调度层负责接收用户问题调用大模型进行意图识别和工具选择把用户的自然语言拆解成 Skill 调用计划。这一层我通常不写死逻辑而是完全依赖模型能力通过精心设计的 System Prompt 来引导。服务层由多个独立的 Skill 组成每个 Skill 是一个云函数通过 API 网关暴露给调度层调用。这一层只做一件事输入参数进来执行逻辑返回固定结构的结果。存储层负责存放运行时产生的数据比如 Agent 的会话历史、Skill 的执行日志、临时文件。我一般用对象存储 COS 存文件用数据库存结构化的事件记录。这里有一个关键点调度层不要直接访问存储层一切读写都通过 Skill 完成。这样做的好处是存储的变更不会影响 Agent 主链路你以后把 COS 换成别的存储只改对应 Skill 就行。4. 实操从 0 到 1 实现一个“日志巡检 Skill”4.1 场景拆解从用户需求到 Skill 边界光讲架构有点飘我来用一个完整的案例带你走一遍。假设我要做一个“日志巡检”Skill需求场景是用户对 Agent 说“帮我看看这几天有没有报错”Agent 需要去服务器上拉取日志、分析异常关键字、返回一个汇总报告。第一步不是写代码而是拆边界。这个需求里有几个子任务拉日志、过滤关键字、汇总统计、生成报告。我决定把它们都收进一个 Skill 里因为这是一条连贯的流水线拆成多个 Skill 反而增加模型编排的负担。Skill 的输入参数定成三个start_time开始时间、end_time结束时间、keywords一个关键字列表。输出结果定义为一个 JSON包含total_logs日志总数、matched_logs匹配数、top_errors出现最多的前五个错误和suggestion给用户的建议。4.2 编写 Skill 代码函数、Schema、Prompt 模板三段式我的 Skill 代码永远分成三段来组织。第一段是入口函数第二段是参数 Schema第三段是给模型看的描述文本。这里给一个简化版的示例# skill_log_audit.py import json from datetime import datetime def run(event, context): 云函数入口这里接入 API 网关的请求事件 # 1. 参数校验 params event.get(queryStringParameters) or {} try: start_time datetime.fromisoformat(params[start_time]) end_time datetime.fromisoformat(params[end_time]) keywords json.loads(params.get(keywords, [])) except (KeyError, ValueError) as e: return {code: 400, data: None, message: f参数错误: {e}} # 2. 核心逻辑伪代码拉日志、过滤、统计 raw_logs fetch_logs(start_time, end_time) matched [log for log in raw_logs if any(kw in log for kw in keywords)] top_errors count_and_sort(matched, limit5) # 3. 返回统一结构 return { code: 0, data: { total_logs: len(raw_logs), matched_logs: len(matched), top_errors: top_errors, suggestion: 建议优先处理出现频率最高的错误关注生产环境稳定性。 }, message: ok }Schema 部分用 JSON 描述告诉模型这个 Skill 接受什么参数{ name: log_audit, description: 查询指定时间段内的日志过滤关键字并返回错误统计。当用户询问日志异常、报错情况时使用。, parameters: { type: object, properties: { start_time: { type: string, format: date-time, description: 开始时间格式如 2025-01-01T00:00:00 }, end_time: { type: string, format: date-time, description: 结束时间格式如 2025-01-02T00:00:00 }, keywords: { type: array, items: { type: string }, description: 要过滤的关键字列表如 [\error\, \timeout\] } }, required: [start_time, end_time, keywords] } }这个 Schema 千万别写得太笼统。我第一次写的时候keywords忘了定义items的类型结果模型传进来一个字符串而不是数组直接导致解析失败。Schema 写得越死模型发挥越稳。4.3 部署上云云函数加 API 网关完整流程代码准备好之后部署到腾讯云上。我用的工具是scf命令行你也可以用控制台但命令行适合自动化。# 登录腾讯云 CLI初次使用 tccli configure # 创建云函数 tccli scf CreateFunction \ --FunctionName skill_log_audit \ --Handler index.run \ --Runtime Python3.9 \ --Code ZipFile:$(base64 -w0 skill_log_audit.zip) \ --Namespace default \ --Role QCS_SCF_QcsRole函数创建好之后创建一个 API 网关触发器把 HTTP 请求映射到云函数# 创建 API 网关服务 tccli apigateway CreateService --ServiceName skill-gateway --Protocol https # 创建 API绑定云函数 tccli apigateway CreateApi \ --ServiceId service-xxxx \ --ApiName logAudit \ --Path /log/audit \ --Method GET \ --ServiceType SCF \ --ScfNamespace default \ --ScfFunctionName skill_log_audit到这里一个可访问的 Skill 接口就生成了。你可以在本地用curl测一下通不通curl https://service-xxxx.coolops.cn/log/audit?start_time2025-01-01T00:00:00end_time2025-01-02T00:00:00keywords[\error\,\timeout\]提示第一次测试建议直接返回原始结果不走 Agent。先把 Skill 本身调通再接 Agent不要一上来就联调否则出了错根本分不清是 Skill 的问题还是模型编排的问题。4.4 在 Agent 中注册 Skill 并做一次完整调用Skill 部署完成之后下一步是把它注册到 Agent 的工具列表里。不同 Agent 框架的写法略有不同但核心都差不多——把上面写的那个 JSON Schema 加到工具的tools参数中。我用的是兼容 OpenAI 工具调用协议的方式tools [ { type: function, function: { name: log_audit, description: 查询指定时间段内的日志过滤关键字并返回错误统计。当用户询问日志异常、报错情况时使用。, parameters: { type: object, properties: { start_time: {type: string, description: 开始时间格式 2025-01-01T00:00:00}, end_time: {type: string, description: 结束时间格式 2025-01-02T00:00:00}, keywords: {type: array, items: {type: string}, description: 过滤关键字列表} }, required: [start_time, end_time, keywords] } } } ] # 后续正常调用大模型模型会自行决定是否调用这个工具当 Agent 收到“帮我看看昨天服务的报错情况”这个问题时模型会在内部判断应该调用log_audit工具然后生成一个参数值start_time 是昨天零点end_time 是今天零点keywords 是 [“error”, “exception”]再发给我们注册的 HTTP API。整个过程模型扮演的是“调度者”真正执行的是我们这个云函数。注册完之后我强烈建议你跑一遍端到端测试真实调用 Agent输入一句口语化的请求看它是否能够正确选对这个 Skill、传对这些参数。如果传错了不要急着改 Prompt先看看是不是 Schema 描述不够清晰——大概率是。5. 线上运行常见问题与排查实录5.1 冷启动超时一次真实故障还原上线初期我遇到了一个让人头疼的问题第一次调用 Skill 时经常超时但第二次调用就正常了。排查之后发现是云函数的冷启动导致的——函数在长时间没有请求之后运行时环境被回收下一次请求需要重新初始化耗时可能达到几秒钟而我的 API 网关超时时间设置得太短。解决办法有几个按推荐优先级排序调大 API 网关的超时时间建议至少 30 秒把数据库连接、HTTP 客户端等重资源的初始化移到全局作用域避免每次冷启动都重建如果对延迟要求极高开启云函数的预置并发牺牲一点成本换稳定性我自己最终是组合了前两个方案冷启动从之前的 5 秒降到了 1 秒以内完全在可接受范围内。5.2 模型乱传参用 Schema 把“自由发挥”关进笼子另外一个高频问题是大模型传参不规范。比如我明明定义了keywords是数组它却给我传字符串我定义了start_time是 ISO 格式它给我传“昨天”。这本质上是模型对 Schema 理解不够造成的但根因往往是你 Schema 写得不够“死”。我的建议是给每个参数加详细的description说明格式、单位、取值范围在required里把必填参数列全不要给模型自己选择的机会云函数入口做二次校验后端再兜底一遍而不是完全信任模型后端二次校验特别重要。就算模型传了奇怪的参数你的代码也能返回一个清晰可读的错误而不是直接抛异常。这样 Agent 能根据错误信息自我纠正重新生成参数再试一次这是提高成功率的很有效的手段。5.3 密钥泄露风险环境变量和最小权限原则Skills 里经常需要访问 COS、数据库、内部接口这就会用到各种密钥。我见过有人在云函数代码里硬编码数据库密码结果代码仓库一泄露生产数据库直接暴露在公网。这种低级错误绝对不能犯。腾讯云上有两个机制来解决这个问题环境变量和CAM 角色授权。敏感信息一律放环境变量代码里用os.getenv()读取如果 Skill 需要访问腾讯云内部资源尽量用角色而非密钥让云函数在创建时绑定一个权限受限的 CAM 角色这样连密钥都不用在代码里出现。我记得最清楚的一次教训是一个 Skill 只需要读取 COS 里的某个文件我却给它配了一个完全读写权限的角色。后来发现这个 Skill 的日志被反复尝试访问其他存储桶虽然没造成实际损失但那次之后我再也没给 Skill 赋过超出需求范围的权限。5.4 Docker 镜像推送失败的三个高频原因如果你不是用云函数而是把 Skill 打包成容器镜像部署那你大概率会遇到 Docker 镜像推送到腾讯云容器镜像服务TCR失败的问题。我先后遇到过三种情况列出来给你避坑现象原因解决办法denied: requested access to the resource is denied没有登录镜像仓库或者登录凭证过期执行docker login重新登录腾讯云侧用访问令牌方式登录unauthorized: authentication required镜像名称和仓库地址对不上检查镜像 tag 是否包含完整的命名空间和仓库名格式应为ccr.ccs.tencentyun.com/{命名空间}/{仓库名}:{标签}manifest invalid本地镜像架构和远端不匹配构建镜像时加上--platform linux/amd64确保和服务器的 CPU 架构一致说到底推送镜像就和上传文件到网盘一样登录对了、路径对了、格式对了基本就成功了。把上面三个问题排查一遍90% 的推送失败都能解决。最后再分享一个我个人的体会写 Agent 最大的成就感不是模型又学会了什么新话术而是那些沉淀下来的 Skills 真正变成了“可以被复用的资产”。我用同一套日志巡检 Skill先是给运维 Agent 用后来又接进了数据分析 Agent几乎零成本复用。所以如果你正在做 Agent别急着追求“全能”先把你手上最熟悉的那几件事打磨成靠谱的 Skill你会发现整个系统的能力会上一个台阶。