
我前阵子接了个内部提效项目目标很直接做一个能自动处理工单、查数据、写周报的“全能 Agent”。一开始我天真地以为把一堆 Prompt 堆进系统提示词里模型足够强就能搞定一切。结果一上线就翻车了——改一个字段描述要把几百行提示词翻个底朝天加一个新功能又怕影响老逻辑模型偶尔还会自作主张地“自由发挥”。那段时间我几乎以为 Agent 就是个玩具。直到我把思路从“让模型记住所有事”切换到“给模型配好技能包”用腾讯云的 AI Skills 把能力拆成一个个可插拔的模块整个项目才真正活过来。这篇文章不聊宏观概念就把我从零到一在腾讯云上构建 Agent、打磨技能、踩坑排错的全过程掰开揉碎讲一遍。适合手里已经有一个 Agent 项目、或者打算上 Agent 但被“一坨 Prompt”折磨过的开发者。全文以我的真实实践为主线所有方案都是基于腾讯云现有产品能力的合理组合不是纸面推演。1. 为什么“万能 Agent”总是翻车提示词堆不出生产力1.1 我在第一个版本里踩的坑第一版 Agent 我走的是“大而全”路线把所有业务规则、数据表结构、回复格式、判断逻辑全部写进系统提示词试图让模型成为一个全知全能的接线员。结果问题接踵而至改需求等于重写提示词业务方说要增加一个“跨部门审批”流程我需要在提示词里找到审批相关段落小心翼翼地插入新规则还得祈祷不会影响已有的判断分支。模型幻觉被放大提示词里塞了太多背景知识模型分不清哪些是“可查询的事实”、哪些是“可以编造的常识”经常一本正经地给出错误数据。没法复用另一个项目也想要相似功能我只能复制粘贴那一大段提示词稍微改改参数本质上等于重新调了一次“玄学”。根本原因在于我把 Agent 的“认知能力”和“执行能力”混在一起了。模型负责思考和生成这是它的长项但精准执行某一项具体任务比如查数据库、调接口、生成固定格式的报表用自然语言约束远不如用明确的代码和接口来约束。1.2 一个反直觉的结论Agent 的能力上限由工具决定圈子里有个说法“Agent 的能力上限取决于模型的推理能力。”这句话对了一半。模型推理确实重要但在我踩过坑之后我更认同另一个结论Agent 在真实业务里的能力上限取决于它拥有的工具Skills的质量和边界。打个比方给一个实习生模型配上计算器、Excel 模板、公司数据库账号Skills他能高效完成报表即使这个实习生很聪明但如果你只丢给他一张白纸纯提示词他再聪明也做不出自动化的活。Skills 就是那张白纸之外的所有生产力工具。顺着这个思路我在腾讯云上重构了 Agent 架构模型只负责理解意图、拆解任务、调用技能所有实际动作全部下沉到 Skills 里。这个转变是“全能 Agent 养成记”的真正起点。1.3 技能化之后问题的边界清晰了重构之后我那个“全能 Agent”变成了一个调度中枢加若干技能模块模型层负责理解用户说什么、判断该调用哪个技能、把结果组织成自然语言回复。技能层每个技能是一个独立的服务负责完成一件具体的事比如“查客户订单”“算月度消耗”“生成周报”。数据层技能通过标准的接口访问数据库、内部系统或者外部 API。这么做最大的好处是问题和责任边界都清晰了模型出错改提示词或换模型参数某个技能出错单独修那个技能不影响全局。这就像把一堆乱麻理顺成了一个个线头想处理哪根就处理哪根。2. AI Skills 到底是什么一个可插拔的职业技能包2.1 Skill 和 Agent 的分工边界这是很多刚接触 Agent 开发的人最常问的问题。我当时也被这个概念绕了一阵子。用我自己的理解来总结一下Agent是一个“角色”或“大脑”它负责感知用户输入、形成计划、决定下一步动作它本身不直接操作外部世界。Skill技能是一个“能力单元”它封装了完成某个特定任务所需的全部逻辑触发条件、输入参数、处理过程、输出格式。用生活化的比喻Agent 是一个厨师长Skill 是他厨房里的一口炒锅、一台烤箱、一把专用刀。厨师长决定今天做什么菜、用什么工具、按什么顺序做每个工具负责把自己那部分活干好。厨师长不会亲自颠勺也不会亲自发动烤箱他只需要知道每个工具能干什么、怎么调用。2.2 一个标准 Skill 应该包含哪些要素在实践中我把一个合格 Skill 的“内部结构”拆成六个部分构成要素作用对应到代码/配置中的注释技能名称让 Agent 知道这个技能叫什么、什么时候想起它等价于函数名要求语义明确技能描述用自然语言描述这个技能能干什么、在什么场景下调用Agent 根据描述做路由判断输入参数 Schema定义需要调用方提供哪些参数、类型、必选可选等价于函数签名和参数校验处理逻辑实际执行任务的代码可以是云函数、容器服务等等价于函数体输出结构定义返回值格式方便 Agent 解析和呈现等价于返回类型使用约束权限、超时、并发控制、白名单等限制条件保证技能在受控范围内执行说白了一个 Skill 就是一份“带说明书、带参数校验、带边界控制的函数”封装。Agent 通过描述来发现技能通过输入、输出 Schema 来调用技能通过约束来避免技能被滥用。2.3 我为什么选择在腾讯云上构建 Skills我并不是一开始就在腾讯云上做的。早期最朴素的做法是写本地函数再用 FastAPI 包一层 HTTP 接口手动维护一份工具清单给模型。一开始几个技能还行技能一多就乱了接口鉴权怎么做、超时怎么管、日志怎么看、版本怎么迭代全都得自己造轮子。腾讯云帮我把这些工程问题收敛了。我在实践中用到的核心服务组合是这样的云函数SCF承载单个 Skill 的实际逻辑支持 Python、Node.js、Java 等语言按调用次数计费冷启动延迟普遍在可接受范围内。API 网关给每个 Skill 暴露标准 HTTPS 接口统一做签名鉴权、限流、跨域处理。腾讯云 AI 相关能力内部集成了模型推理、知识检索等能力把 RAG 和 Agent 编排串在一起更顺滑。日志服务CLS所有 Skill 的调用日志统一接入排查问题再也不用登录一台台服务器翻日志了。这套组合的优势在于我不需要自己维护基础设施。技能跑在云的托管环境里我用 API 网关对外暴露用日志服务做观测用平台的监控做告警。作为一个十几人的小团队我们没有专职运维这套省下来的精力全部投入到业务逻辑里。3. 在腾讯云上从零养一个带技能的 Agent3.1 第一步定义第一个技能我建议你不要一上来就做特别复杂的技能。先用一个“无状态、逻辑简单”的技能跑通全链路。我的第一个练习技能是“翻译并格式化标题”流程很简单接收一个中文标题翻译成英文再输出成固定格式的 JSON。这个技能在腾讯云上对应的实现非常简单我用了 Python 云函数import json def translate_and_format_title(event, context): Skill: translate_format_title 输入: {title: 腾讯云AI技能实践} 输出: {translated_title: Tencent Cloud AI Skills Practice} # 在真实场景中,这里会调用模型接口进行翻译 # 这里为了演示,直接按规则处理 title event.get(title, ) # 调用模型 API 的代码略去,假设已经拿到翻译结果 translated call_translation_model(title) return { statusCode: 200, body: json.dumps({ translated_title: translated }, ensure_asciiFalse) }3.2 第二步把技能注册到 Agent 能力清单函数写完之后真正有价值的部分是把技能“介绍”给 Agent。在腾讯云 AI 平台上每个技能都需要提供一份机器可读的声明相当于技能的自述文件。我把这套声明类比成“简历”{ skill_id: translate_and_format_title, name: 标题翻译格式化技能, description: 当用户需要将一个中文标题翻译成英文并输出特定格式时,使用此技能。适用于文档翻译、内容国际化等场景。, input_schema: { type: object, properties: { title: { type: string, description: 需要翻译的中文标题 } }, required: [title] }, output_schema: { type: object, properties: { translated_title: { type: string, description: 翻译后的英文标题 } } }, endpoint: https://your-api-gateway-url/translate }这份声明的质量直接决定了 Agent 能不能在合适的时机正确调用技能。尤其是 description 字段很多人不重视随手写一句“做翻译”就完事。实际上模型是根据 description 来“匹配意图”的描述越具体、关键词越明确路由准确率越高。比如我把描述写成“当用户需要将一个中文标题翻译成英文并输出特定格式时”模型遇到“帮我把这个标题翻成英文”就会更倾向于选中这个技能而不是去翻别的技能。实践中我会多轮迭代这份描述根据误调用和漏调用的日志不断微调。3.3 第三步技能调试与验证技能注册之后不能直接丢给 Agent 生产环境。我通常会做三件事用固定的输入参数模拟调用先不经过 Agent直接在云函数控制台构造一个事件发请求看返回是否符合预期。通过 API 网关直接请求验证鉴权、超时、网关到函数的链路是否正常。接入 Agent 后做端到端测试用真实的用户话术测试路由是否正确、回复是否通顺。我特别想强调一个容易被忽略的点返回结构要稳定。云函数内如果抛异常API 网关可能返回 502但 Agent 期望的是结构化的 JSON。我的做法是在函数最外层包一层统一的 catch保证任何情况下都返回标准结构def main_handler(event, context): try: result process(event) return {success: True, data: result} except Exception as e: return {success: False, error: str(e)}这样 Agent 拿到输出后先看 success 字段再决定是直接回复用户还是走兜底话术。3.4 第四步把 Agent 接入具体的业务场景技能跑通之后我开始把多个技能组合进真实场景。我们团队有一个内部需求自动处理客户反馈工单。我设计了三个技能query_order_info根据客户 ID 或订单号查询订单状态。classify_intent对反馈内容做意图分类退货、换货、咨询、投诉。generate_reply_draft根据订单信息与意图分类生成回复草稿。Agent 的调度逻辑大致是这样的收到用户反馈后Agent 理解这段文字。调用classify_intent判断意图。如果涉及订单调用query_order_info查出订单状态。最后调用generate_reply_draft生成回复。用户确认后Agent 再触发后续的实际处理动作。每个技能只负责一小块但串起来就是一个闭环。这也正是“全能 Agent”的真实面貌它不是一个会做所有事的单体而是一个善于调用工具的组合体。4. 学会任务拆解用多个 Skills 编排出真正的“全能”4.1 编排是“全能”的关键而不是让单个技能变复杂有一个很容易走偏的方向既然调用技能这么方便那不如把每个技能做得尽量复杂减少技能数量。我试过结果是把一个技能变成了一座屎山。比如我一开始把“查询订单”“判断售后类型”“生成回复”“更新工单状态”全写在一个云函数里参数越加越多判断逻辑层层嵌套最后没人敢动那个函数。后来我强迫自己遵循一条原则一个技能只做一件事做完做到位。判断一个技能是否足够“原子化”我常用一个标准它的技能描述能不能用一句不超过 20 个字的句子说清楚。如果说不太清楚说明这个技能该拆了。4.2 一个真实的任务拆解案例周报自动生成我做过一个“周报自动生成”技能拆解过程比较有代表性。最初的需求是给 Agent 一堆聊天记录和项目文档让它自动产出一份周报。第一版我把它做成了一个巨大技能输入是聊天记录文本输出是完整周报。结果模型理解不了散乱的输入周报质量一塌糊涂。后来我把这个技能拆成了四个技能名职责输入输出summarize_daily_updates把一天的聊天记录压缩成几条工作项当日聊天记录原文结构化工作项列表retrieve_related_docs根据工作项检索项目文档补充上下文工作项关键词文档片段列表aggregate_weekly_report把多天工作项合并成周报框架7天的工作项列表周报Markdown草稿polish_report润色和周报格式规范化周报草稿最终周报拆完之后Agent 的任务规划就变得清晰了收到一周的原始材料后Agent 先按天调用summarize_daily_updates再把结果汇总给aggregate_weekly_report最后用polish_report定稿。每个技能只处理一小步模型在每一步上的负担都小了很多最终质量明显提升。4.3 编排时的任务规划策略在腾讯云上编排多个技能时我总结了一套比较实用的任务规划策略先分类再细化遇到复杂任务第一步不是执行而是判断这个任务属于什么大类然后在大类下选择合适的技能。比如“用户说订单有问题”先判断是发货问题还是产品问题再决定调用哪一套技能流程。允许 Agent 在规划中询问不是所有信息都在第一句里给全。如果技能需要的关键参数缺失应该让 Agent 主动反问用户而不是猜一个参数继续执行。这能减少很多低级错误。设置兜底路径Agent 可能找不到合适的技能。我的做法是给 Agent 一个fallback_human_handoff技能当技能匹配置信度不高时自动转入人工处理流程同时保留会话上下文。4.4 技能之间的通信与数据流转技能之间怎么传数据是编排过程中绕不开的工程问题。我在最开始犯过一个错让每个技能自己调数据库去“获取上下文”。后来发现这很危险——每个技能都去查一遍数据既慢还容易出现多个技能拿到的数据版本不一致。我的改进方案Agent 层统一维护上下文Agent 在规划阶段就把必要的公共参数整理好比如客户 ID、会话 ID、当前页面 URL放进调用每个技能时的通用字段里。技能输出标准化所有技能都返回统一的结构至少包含success、data、error三个字段。下游技能只需要解析data不需要关心上游技能的实现细节。大对象用引用传递如果某个技能的输出很大比如一份完整的文档内容不要直接塞进下一个技能的请求体而是先存到对象存储或临时存储中传给下一个技能一个引用 ID。这样能显著降低请求体积和超时风险。我用对象存储存大文档的时候云函数里大概是这样做的import boto3 # 腾讯云对象存储COS兼容S3协议 def generate_report(event, context): # 生成报告内容 report_content build_report() # 上传到COS,拿到引用ID cos_client boto3.client(s3, endpoint_urlhttps://cos.ap-guangzhou.myqcloud.com, aws_access_key_idos.environ[COS_SECRET_ID], aws_secret_access_keyos.environ[COS_SECRET_KEY]) key freports/{generate_uuid()}.md cos_client.put_object(Bucketmy-bucket, Keykey, Bodyreport_content.encode(utf-8)) # 返回给Agent一个引用ID,而不是完整内容 return {success: True, data: {report_ref: key}}下游技能如果需要这份报告直接通过引用 ID 去取。这种方式在数据量上来之后优势特别明显我强烈建议数据体积可能超过几十 KB 的场景都这么设计。5. 养成路上的几个深坑调试、性能与安全的实战排查5.1 技能粒度失控一个“万能技能”的教训前面提到我把大技能拆小的过程这里展开说一下具体的判断标准。有一次我把“文件处理”做成了一个技能文件夹里面能解析 PDF、能提取表格、能转格式、能 OCR听着很强大。结果在 Agent 调试的时候发现模型经常选错“子功能”明明是要提取表格却走到了 OCR 分支。我排查了技能描述、参数设计最后发现问题出在“能力范围太宽泛”上模型面对一个入口很难精确理解用户的细分意图。解决办法比较笨但有效拆技能一个入口对应一个原子能力。解析 PDF 一个技能、提取表格一个技能、格式转换一个技能、OCR 一个技能。虽然技能数量增加了但每个技能的意图清晰模型的调用准确率反而提升了不少。我总结了一条经验当你的技能描述里出现“以及”“或者”“根据情况”这类词时多半是技能粒度太大了。要时刻提醒自己原子化是 Agent 系统稳定性的基石。5.2 输入 Schema 设计不当导致的调用失败第二个我经常踩的坑是输入参数 Schema 设计。有一段时间我的 Agent 在调用query_order_info时经常报参数错误排查日志后发现模型有时传order_no有时传order_id还有时候两个都传了空字符串。根本原因是我的 Schema 里把order_no和order_id都定义成了必填参数但这两个其实是同一个概念模型不确定该用哪个。我修正的方法是合并同义参数只保留一个order_no在描述中明确说明“这是订单号用户可能说成订单ID本质是同一个值”。利用内部映射如果模型已经根据上下文拿到了客户信息可以在技能内部用一个映射表补齐缺失参数而不是粗暴地要求所有参数必填。设置默认值能设默认值的就设默认值减少模型临场判断的负担。参数越简单模型调用技能的可靠性越高。Schema 设计不是给开发者看的而是给模型看的要以“尽量减少模型猜谜空间”为原则。5.3 冷启动与超时云函数的现实约束我在最初使用腾讯云函数承载技能时对冷启动的感知不深因为内部测试时量小几乎没什么感觉。但到了生产环境一次业务方集中汇报瞬间来了几十个请求我眼睁睁看着监控里好几个调用超时。排查后发现一方面是我在云函数里做了不少初始化操作比如加载模型文件、建立数据库连接池另一方面是默认配置的超时时间太短没有为复杂技能预留足够的时间。针对这个问题我的调整方案热启动优化把可以复用的资源数据库连接、HTTP 客户端、缓存放在函数全局初始化区块而不是每次调用都重建。合理设置超时对于需要调用大模型 API 的技能我把超时设为 30 秒以上避免因为外部模型响应慢导致技能整体失败。异步化非关键路径有些技能不需要同步返回最终结果比如“生成报告后发送邮件通知”这种场景我把邮件发送逻辑放到异步队列里去技能本身只需要返回“已受理”。5.4 技能权限越大风险越大AI Skills 带来的一个隐含风险是Agent 一旦具备调用技能的能力也就具备了调用后端系统的能力。如果你的技能里有“删除订单”“修改库存”这种危险操作权限控制不到位一次误调用就可能酿成事故。我在腾讯云上的权限设计遵循最小权限原则不同技能使用不同的子账号/角色查询类技能只给只读权限写操作类技能单独用高权限账号并且在高权限账号上开启操作审批。关键操作二次确认危险技能比如删除、修改在内部实现时增加一个confirm参数Agent 必须先向用户确认拿到确认标志后才真正执行。所有技能调用留痕日志里记录下每一次技能调用的入参、出参、调用方标识、时间戳一旦出现问题可以快速定位是哪次误调度导致的。我记得腾讯云开发者社区里也有人踩过类似坑把管理员的 API 密钥直接配进了云函数环境变量然后函数又被 Agent 误调用结果一夜之间多了几十台云主机。这种事故完全可以通过“子账号最小权限操作审计”避免。5.5 调试技巧如何高效定位 Agent 与技能之间的“甩锅”问题Agent 项目排查问题最崩溃的地方在于定位“是谁的问题”——是模型没有理解意图还是模型理解了但技能调用失败了还是技能本身逻辑有 bug。我在实践中形成了一套固定排查流程先看调用链日志腾讯云日志服务里把每次 Agent 的思考过程、选中的技能、技能入参、技能出参串成一个调用链 ID根据这个 ID 能一次性看到全貌。区分“模型问题”和“技能问题”如果调用链里显示模型选择了一个明显不相关的技能那是路由或描述的问题如果选择的技能正确但技能返回错误那才是技能代码的问题。用最小复现法确定是某个技能的问题后我用调用链里记录的入参直接在云函数控制台里重新触发一次调用复现 bug。这样能避开 Agent 层直接对技能代码做调试。不要忽略输入参数的细微差异很多时候技能代码没问题但模型传的参数跟预期的不一致。比如模型把日期传成了“2025-03-04 12:00:00”你的函数只处理了“2025-03-04”。这种问题要多做参数兼容在技能入口做一个宽松解析层。调试 Agent 系统方法比工具重要。遇到问题先别急着改代码先搞清楚问题发生在哪个环节再动手。这是我反复提醒自己的。实践体会与扩展建议整套方案跑通之后我最大的体会是Agent 开发与其说是在“调模型”不如说是在“做工程”。模型本身的能力下限已经足够高真正决定一个 Agent 在业务里好不好用的是你给它配了哪些技能、这些技能靠不靠谱、能不能被正确调度。如果你正准备上手我的建议是从一个小小的、高频的业务场景切入先定义出一个原子技能跑通 Agent 调用技能的完整链路再逐步增加技能数量。千万不要一开始就想着“我要做一个全能的数字员工”而是先让它做好一件事。当你手上积累了五到十个高质量技能之后“全能”其实是水到渠成的事。我在腾讯云上这轮实践下来最值得复用的经验基本都在前面五章里了。过程中踩的坑、用的排查手段、总结的 Schema 设计原则都是实打实从生产环境里蹚出来的。如果你也在搞 Agent 技能化欢迎拿这些思路去对照自己的项目看能不能少绕几个弯。