做 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能