用Serverless和AI Skills构建全能Agent的实践指南
做 Agent 项目做得越多我越觉得真正难的不是让模型“会聊天”而是让它“会干活”。我指的是像人一样能够根据一个模糊指令自己决定调什么接口、查什么数据、生成什么结果并且在出错时知道换一条路。腾讯云上的整套 Serverless 基础设施配合把能力沉淀成 AI Skills 的做法是我这两年实践下来最顺手的一条落地路径。这篇文章就是一份非常务实的“全能 Agent 养成记录”。我会从最容易被忽略的任务拆解开始讲到 Skill 描述怎么写、腾讯云云函数怎么承载技能再到记忆设计和上线后的排坑。不一定适合想研究论文级智能体的人但如果你正准备在公司里接入大模型、让 AI 真正处理业务动作那这里面的思路应该能帮你少走不少弯路。1. 动手前先做的事把“全能 Agent”翻译成第一批技能清单1.1 “全能”是一个伪命题先圈定要养成的能力半径我发现很多人一开始做 Agent目标都会写成“做一个全能助手”。这个目标听着很理想但基本上没办法落地。因为“全能”不是一个可验收的产品指标它只是你没想清楚时的防御性说法。我习惯的做法是先和业务方坐下来把“全能”翻译成具体场景再问三个问题——这个任务发生的频率高不高如果让 AI 自动处理最坏情况下能接受什么结果哪些动作在现阶段绝对不能自动执行举个例子我之前给自己定过一个“云资源运维助手”的范围。第一版本只要能干好三件事帮值班同学解读告警、根据实例 ID 查询性能指标并给出判断、把故障处理过程整理成日报。至于“自动重启实例”“自动变更配置”这种动作我明确划到第二阶段并且永远安排人工确认。这一个决定让项目研发量至少降了一半交付时间也缩短了很多。所以我给的第一条建议是不要追求大而全第一个版本 5 到 8 个技能就足够撑起一个可用 Agent。上线跑两周真实用户会告诉你哪里的能力需要补齐。这个过程中你会看到“Agent 不如预期”往往不是模型不行而是能力边界还没被讲清楚。1.2 Skill 与 Agent 的区别一个负责动手一个负责带脑很多人会把 Agent 和 Skill 混在一起描述但这两者的分工其实非常清晰。Agent 是一个有“脑子”的执行主体它负责理解目标、拆解步骤、决定先调用哪个服务、根据结果判断是否要继续、中途失败后如何调整。而 Skill 是一段相对确定的能力可以是一个函数、一个接口、一段工作流它接收明确的输入返回可解析的结果不做大方向的决策。我常用的比喻是Agent 像一个实习生Skill 像是给他配的专用工具。实习生不需要精通每种工具的制造工艺但他得知道在什么情境下拿起哪把螺丝刀反过来工具本身也必须稳定可靠不能每次用起来都让实习生自己现场瞎折腾。这也是为什么我一直强调Skill 的内部实现尽量保持“无状态、可重入”。因为 Agent 在失败后很可能重新调用同一个技能如果上一次执行留下脏数据下一次就会出问题。把 Skill 当成一个稳定的函数来看待Agent 的上层行为才可控。如果你的业务只有一个固定入口、用户问题也高度重复那就不要硬上 Agent。这时候直接写一个固定调用流程的 API往往比引入大模型规划更便宜、更稳定。Agent 的价值是在多个技能组合出无穷路径时才会体现出来。1.3 用任务反推技能清单回到实操层我一般会用下面这张表来梳理第一批技能。它不复杂但非常关键。真实用户任务需要获取的数据Agent 自动动作必须人工确认的环节建设优先级“这个月账单为什么涨了这么多”云账单、按项目标签分组的费用拉取账单、按产品归类、生成简表不做任何退款/停服动作P0“帮我看看这台服务器是不是要扩容”CVM 实例规格、最近 7 天 CPU/内存趋势查询监控指标、给出趋势摘要不自动扩容P0“整理一下今晚的故障记录并通知值班群”告警事件、操作日志生成故障时间线摘要、发送到群发送前在群里 相关人确认P1“根据会议纪要把待办创建到项目工具里”会议纪要文本抽取负责人、截止时间写入项目工具创建前展示待办清单供确认P1这张表的价值有两个。第一它强制你区分“查询类动作”和“变更类动作”。查询类可以让 Agent 自主完成变更类必须给人工留一个闸门这个设计后面会体现在技能的风险等级字段里。第二它让技能研发优先级变得非常清楚第一批只需要做表格里 P0 的两三个后端能力不需要把整个中台接完。把这张表里的每一行再拆开你就会发现技能开始自然涌现。比如“查费用”是一个技能“生成简表”是另一个技能“发送到群”又是一个技能。它们单独看都很小但组合起来正好覆盖用户一句话的完整需求。2. AI Skills 撰写的关键让大模型一眼看懂你的技能接口2.1 名称和描述写不好模型就只会“假装调用”Skill 落到实际工程里最终形态是给模型看的一份“接口说明书”。大模型不是编译器它不会去读你函数内部的实现它只通过技能的名字、描述和参数定义来判断“该不该调用”以及“参数怎么填”。很多新手在这里会踩坑把技能名称写成query_metric描述只写一行“查询指标”参数 description 也不写。结果你发现模型经常不调用它或者即使调用了参数也填得七零八落。原因很简单模型面对的是自然语言意图分类问题。用户说“这台机器最近老报警帮我看看”如果你的描述里没有“报警”“性能排查”“CVM 实例”这些词模型就很难把这个意图关联到那个名称很抽象的接口上。我建议技能描述至少包含四部分技能解决什么问题、典型触发条件是什么、哪些情况不要调用、返回的结果大概长什么样。直白一点这个描述是写给一个没见过你系统的同事看的而不是写给编译器看的。下面是一个典型对比差查询指标好查询指定地域下某台 CVM 的 CPU、内存、磁盘使用率。当用户询问服务器卡顿、负载高、告警严重程度或者需要判断是否扩容时使用。只支持腾讯云 CVM 实例传入的实例 ID 必须是 ins- 开头如果无法确定实例 ID不要猜测应引导用户提供或先调用实例列表接口。写清楚边界同样重要。一个技能如果描述得太宽模型会在不合适的场景调用它比如查账单时偏偏调了查实例状态的技能。所以在描述里加入“不处理哪些场景”能显著降低误调用率这是我在实际日志里确认过的效果。2.2 把技能契约写成 JSON Schema现在主流大模型服务提供 function calling 能力时基本都遵循一套 JSON 结构的工具描述。我一般会按下面的样式来注册技能SKILLS [ { type: function, function: { name: query_cvm_metric, description: ( 查询指定地域下某台云服务器 CVM 的 CPU、内存、磁盘使用率。 适合用户询问服务器卡顿、负载高、告警是否严重等场景。 只支持腾讯云 CVM 实例不支持裸金属与外部服务器 实例 ID 必须是以 ins- 开头如果不确定就先调用实例列表接口。 ), parameters: { type: object, properties: { region: { type: string, enum: [ap-guangzhou, ap-shanghai, ap-beijing], description: 实例所在的地域请转换为地域代码。 }, instance_id: { type: string, description: CVM 实例 ID形如 ins-xxxxxxxx。 }, metric: { type: string, enum: [cpu_usage, memory_usage, disk_usage], description: 需要查询的指标默认 cpu_usage。 }, time_range_minutes: { type: integer, minimum: 5, maximum: 1440, description: 查询最近多少分钟的数据默认 30。 } }, required: [region, instance_id] } } } ]这段结构看起来很啰嗦但这就是模型需要的“抓手”。enum能