
写Agent写了快两年我最大的体会是别人口中啥都能干的Agent一落到自己的业务里就原形毕露。让它写个段子没问题让它按固定流程处理数据、调用内部接口、产出符合规范的报告它就开始自由发挥你得在Prompt里把每个步骤重复写十遍。后来我把一套AI Skills的玩法搬到腾讯云上效果完全不同——Agent不再是空有一张会聊天的嘴而是真能把外部能力和固定流程穿在身上随用随取。这篇文章就围绕全能 Agent 养成这件事分享我实际跑通的思路、踩过的坑以及在腾讯云上把Skill落地成可调用服务的具体做法。不管是刚开始做Agent开发还是已经被工具调用、上下文管理折磨得想摔键盘的人应该都能从这里找到一点可抄的作业。1. 先别急着写代码Agent与AI Skills的关系必须想清楚1.1 为什么没有技能库的Agent总在纸上谈兵很多人的Agent初版长这样一个大模型一大段System Prompt里面塞满了当你需要查询订单时调用get_order接口当你需要生成报表时按以下格式输出……。看起来功能齐全实际上模型经常会漏掉步骤或者把工具名记错甚至在没有必要的时候强行调用工具。本质问题在于你把执行知识和对话智能混在了一起。模型本身擅长的是语义理解、推理和表达但如果所有操作知识都堆在Prompt里它既要记住规则又要判断什么时候适合执行token消耗大不说规则稍微一复杂就容易失忆。类比一下你招了个聪明的新人却不给他岗位SOP只让他上班前把公司制度全文背下来。他当然能聊、能推理但具体办事一定会出错。AI Skills相当于给Agent准备了一套岗位SOP工具卡Agent按需取用而不是把整本手册记在脑子里。1.2 Skill、工具调用、Function Calling到底差在哪经常有人把Function Calling和Skill混为一谈。从我的实践来看两者的粒度完全不同。Function Calling更像是一份接口清单。它告诉模型系统里有这些函数参数是什么。模型的作用是决定调不调、传什么参数。例如状态机里定义的一个查询天气的函数。它解决的问题是让模型学会触发动作。Skill则是一个完整的能力包。它不只有接口定义还包含使用触发条件、执行步骤、领域知识、模板、校验逻辑甚至可以再调用更底层的Function Calling。它解决的问题是让Agent在特定场景下具备完整的执行能力。两者的区别可以用下面这个表格概括维度Function CallingAI Skill粒度单个工具调用一组完整工作流/能力集合内容函数名、参数、返回说明触发条件、操作说明、模板、校验规则装载方式常驻在请求里按需加载匹配到技能再执行适用问题帮我查一下某个数据按公司规范做完整个季度分析我倾向于把Skill理解为工作说明书工具箱把Function Calling理解为工具箱里的某一把工具。没有Skill封装时模型看到的是成堆散装工具不知道怎么组合才合理有了Skill之后它能判断当前任务对应哪套组合拳。1.3 这类技能化方案适合谁不适合谁在自己项目里推行技能化之前建议先对号入座如果你的场景是流程相对固定、重复执行率高、领域知识密度大的任务比如客服工单分类、周报汇总、数据清洗、合同初审、私有知识库问答那么Skills化是非常适合的。因为这些任务需要遵循一致的规则且每一步都有可能被审查。如果你的Agent本质上是一个持续性研究助手需要长时间自主探索、频繁自我修正、不停试错那么Skills化只能作为辅助。核心工作仍然要依赖模型推理能力和外部记忆设计硬把探索过程拆成固定技能反而会限制它。我的建议是先把高频、稳定的流程沉淀成Skill给Agent一个稳定的底座再在这个底座上去做自由探索。这样既能让Agent在关键环节上不出错又保留了它的智能弹性。2. 动手写一个Skill从SKILL.md到可执行脚本2.1 最少需要哪几个文件一个可交付的Skill按我现在的习惯最少包含下面这些文件sales-report-skill/ ├── SKILL.md # 技能入口模型首先读取的说明文件 ├── scripts/ │ ├── generate_report.py # 实际执行数据汇总和报告生成的脚本 │ └── validate_input.py # 校验输入数据的脚本避免脏数据进入主流程 └── reference/ ├── template.md # 报告输出模板按需加载不占主上下文 └── examples.json # 2~3个输入输出示例帮助模型理解边界SKILL.md是灵魂。它不是写给人看的项目README而是写给模型看的使用方法。文件不宜过长控制在能被完整读一遍、不把上下文撑爆的范围内。scripts目录放可执行逻辑。reference目录是辅助材料模型只有在需要查模板和具体样例时才去加载。有一点非常重要模型并不是每次请求都会把reference内容自动读一遍它通常在SKILL.md的指示下按需打开。所以文件组织越清晰模型越容易在合适时刻找到合适内容。2.2 描述文件这样写模型才愿意按规矩办事很多人在SKILL.md里写本技能用于生成销售报表你可以使用这个技能……这种写法太弱了。模型看了不会有强触发意愿。有效写法应当明确触发条件、执行步骤、输出规范和禁止事项。我最初一版SKILL.md开头是这样的# 销售周报生成技能 ## 用途 生成销售周报。 ## 步骤 1. 获取销售数据。 2. 统计各项指标。 3. 生成报告。结果模型动不动就用这个技能或者压根不用。问题在于没有说清楚什么时候必须用和怎么判断输入数据齐不齐。调整之后# 销售周报生成技能 ## 何时使用 仅当用户要求生成周报/月报并且提供了可访问的数据源或数据文件路径时使用本技能。 如果用户只是闲聊销售话题不要调用本技能。 ## 输入要求 - 必须存在 source_path 字段指向待分析数据文件。 - 必须存在 report_period 字段值为上周/上月等时间段描述。 - 如果缺少必要字段先向用户索要不要自行猜测。 ## 输出规范 严格按照 reference/template.md 的章节顺序生成禁止新增无关分析模块。 ## 禁止事项 - 不要在数据不足时编造指标。 - 不要修改原始数据文件。改动后最大的区别是模型知道边界了。它不再把这个技能当成万金油也知道输入条件不满足时应该反问而不是硬跑。2.3 拆技能的正确姿势把大而全改成小而精我踩过最大的一次坑是把数据处理流程做成了一个超大Skill。它的SKILL.md有两千多个字步骤多达二十步从数据清理一路写到图表生成。结果模型每次执行都会漏掉中间的某一步而且很难排查到底是哪一步出了问题。后来我把这个巨无霸拆成了三个子技能>import json from skill_lib import generate_report def main_handler(event, context): body json.loads(event.get(body, {})) source_path body.get(source_path) report_period body.get(report_period) if not source_path or not report_period: return { statusCode: 400, body: json.dumps({error: missing required params}) } result generate_report(source_path, report_period) return { statusCode: 200, body: json.dumps(result, ensure_asciiFalse) }第二步在腾讯云控制台创建云函数选择Python运行环境把代码上传。这一步对应的正是很多朋友提到的腾讯云上传操作不复杂但要注意上传时不要把本地依赖一股脑全打进去。建议在函数配置里引用层或使用依赖管理只保留核心代码不然上传包体积会大得离谱冷启动时间也会变长。第三步配置API网关触发器。创建触发器时会生成一个HTTPS访问地址把这个地址作为Skill服务的Endpoint。Agent调用Skill时本质上就是在调这个HTTP接口。第四步如果需要更友好的回调地址可以申请一个二级域名并做解析。比如把skill-api.mydomain.com这个子域名通过CNAME记录指向API网关默认域名。这里有个容易踩的坑很多人想申请二级域名却在DNS解析里配了A记录指向云函数的旧IP结果怎么都调不通。对这种托管服务优先用CNAME记录指到平台提供的域名而不是自己去猜IP。如果你希望模型能通过LiteLLM Proxy这类统一代理来调度模型与技能也可以把云函数接口登记到代理工具列表里。LiteLLM Proxy的优势是它对上层提供一个兼容格式的接口底层模型供应商切换时Skills本身不用改。3.3 域名、端口与安全边界别把公网全敞开围绕腾讯云如何开放所有端口这类需求我多说一句永远不要给服务器开放所有端口。正常业务只应该暴露必要端口其余的全部拒绝。我自己的安全基线如下访问来源开放端口用途API网关公网入口443外部Agent调用Skill服务办公网/管理网22仅指定IPSSH维护内网服务间按需最小开放数据库、缓存等如果ECS上的服务需要被Agent回调我建议在安全组里添加入站规则时来源写特定IP或IP段不要写0.0.0.0/0。如果图省事放开了所有端口用不了几天你就能在日志里看到各种扫描和爆破尝试这是必然结果。二级域名申请本身不难在DNS服务商处添加一条解析记录即可。但要想清楚为什么需要域名一是为HTTPS证书二是因为某些Agent回调场景要求Endpoint是固定域名而不是随机生成的临时地址。域名规划建议统一用skills.你的域名.com作为前缀后面再接具体技能名比如skills.yourdomain.com/sales-report这样Agent多了也好管理。3.4 密钥管理和多环境隔离把Skill放到云端之后代码里绝不能出现API Key和数据库密码。我见过有人把腾讯云密钥直接写进云函数环境变量之外还在脚本里硬编码了一遍看到后我整个人都不好了。正确做法是使用平台提供的密钥管理能力把密钥写入环境变量或密钥管理系统运行时读取。同时给每个环境单独配置一套密钥dev环境用一个只读权限的子账号密钥prod环境用另一个有独立审计轨迹的密钥。这样即使开发环境泄露也不会把生产数据一起搭进去。多环境隔离也很重要。我会在云函数名称里显式区分例如sales-report-dev和sales-report-prod。只在本地联调时访问dev环境线上Agent统一指向prod环境。Skill的版本更新先发到dev跑通后再切流量到prod避免把坏逻辑直接暴露给生产用户。4. Agent编排中的上下文、重试与评测4.1 技能输出不要一股脑丢进对话Skill跑出来的结果往往很长尤其当它生成完整报告时。早期的实现是脚本返回一大段文本Agent原封不动地把它拼到对话里再让大模型基于这些文本继续回答。后果是用不了几轮token窗口就满了而且大模型还要在超长上下文里重新提取关键信息回答质量反而下降。后来我改成结构化中间产物摘要回填的方案。Skill脚本先把结果写成一个JSON结构原始完整报告存到临时存储或对象存储Agent只把关键指标和结论摘要放进对话上下文。大模型不需要读全部内容也能回答用户问题用户要完整报告时再给一个下载链接。算过一笔实际账在一次销售数据分析任务里完整报告文本接近8000字如果全部放入上下文按主流模型的计费方式单轮成本很高。改成摘要回填之后对话内只保留约1500字的结构化关键信息成本下降非常明显同时回答的准确率反而提升了因为模型不再被无关细节干扰。4.2 失败处理与人类介入的兜底策略Skill和普通代码不一样它由模型触发触发时机和参数质量天生有不稳定性。所以失败处理不能只靠代码层的try-except还要在Agent编排层做设计。我在SKILL.md里通常会写清楚失败时的应对方式如果输入缺字段技能应返回明确的参数错误码Agent收到后应立即向用户追问而不是重试。如果是外部服务超时脚本最多自动重试两次两次后返回timeout错误Agent如实告知用户目前系统繁忙。当某个Skill连续三次执行都失败Agent应停止自动处理转人工队列并把前三次的执行日志一起附上。很多项目只关注Skill起来了没有忽略了Skill起不来时Agent怎么表现。一个人工兜底机制能挽救很多糟糕体验。线上Agent不是越自动化越好而是该停时能停下来才敢放开让它跑。4.3 用回归评测集盯住Agent的成长AI Agent 2026发展趋势这类话题经常讨论Agent能否越来越强但对我来说更实在的问题是我怎么知道这次改造确实让它变强了答案是用评测集。我会维护一个约20条任务的回归集覆盖典型的技能触发场景、参数缺失场景、边界模糊场景。每次改动SKILL.md或调整云函数逻辑后都拿这个集合跑一遍。每一条任务都记录四个指标指标说明完成率是否给出最终可用结果准确性结果与预期答案的吻合度步骤遗漏率是否漏掉某必要环节平均耗时从触发到结果返回的总时长没有评测集的Agent改造基本等于凭感觉做优化。你以为换了Skill描述效果会变好实际可能只是某个测试用例碰巧通过。回归集虽然只有二十条却能在任何一次调整后迅速暴露原来能做的现在做不了的退化问题。这个习惯帮我少走了很多弯路。5. 常见问题排查实录与避坑指南5.1 模型死活不调用Skill优先级最高的问题往往不是代码Bug而是模型压根不触发技能。排查时我按这个顺序查第一SKILL.md的何时使用是不是写得太宽泛例如只说用于生成报告模型判断不了当前用户请求是否属于报告需求。改成类似当用户提到周报、月报、季报并且给出数据源或文件路径这种明确条件后触发率会大幅上升。第二是不是同时存在另一个名称相近的Skill或Function Calling如果两个技能在描述上高度相似模型会随机选择一个。我一度同时定义了create_report和generate_sales_report两个技能模型经常选错。后来把旧技能下线只保留一个问题立刻消失。第三示例给得够不够。examples.json里的输入输出样例本质上是在教模型这个场景长这样你应该在遇到它时使用技能。我通常为每个Skill放三组典型场景样例一组普通输入一组边界输入一组不该触发本技能的负例。5.2 Skill执行了但结果一塌糊涂比不调用更让人头疼的是乱调用。模型确实执行了技能但产出完全不可用。常见原因之一是输入数据字段名不匹配。你在脚本里期待source_path字段但Agent从上一步拿到的是data_source于是脚本取不到值只能瞎跑。解决办法是在SKILL.md的输入要求里写清楚字段的别名并在代码里做兼容映射。另一个原因是输出规范不够严格。脚本返回的JSON字段含义不明确时模型会自行发挥生成一堆不在预期里的内容。规范做法是在SKILL.md里把输出JSON的每个字段都注释一遍并给出一份示例输出文件。模型有样可依时执行结果通常稳定得多。5.3 项目越写越乱Skill边界不清Skill边界问题很像代码里的模块划分问题。一个Skill该管多少事我的原则是能在一个执行单元里完成并验证的任务应该是一个Skill需要多阶段流转的任务即使最终目标是一个也拆成多个子技能。比如从原始Excel到可视化仪表盘这个完整流程如果做成一个技能模型不仅要做数据清洗、指标计算还要懂前端图表配置任何一步出错都不好排查。拆成data-clean、metric-compute、dashboard-generate三个技能之后每个技能的输入输出都清晰Agent能逐步推进出现问题时也能准确告诉你卡在哪。另外一个很容易犯的错是让Skill承担Agent的记忆职责。Skill不是记忆库它不应该帮你记录用户偏好或历史状态。需要长期记录的数据应放到独立的记忆服务里不要让技能脚本偷偷写全局变量。5.4 线上检查清单这样查能少走弯路上线新的Skill前我会跑一遍自己的检查清单这里分享出来供参考检查云函数入口的入参兼容性是否兼容缺失字段和额外字段有没有做参数校验。确认API网关超时配置如果Skill处理逻辑超过30秒网关默认超时时间是否够。不够的话调整网关或考虑把长任务改成异步回调模式。核对安全组和网络ACL端口只开放必要部分来源IP按最小范围进行限制。测试模型触发表现用评测集实际跑三轮确认模型稳定触发、稳定输出。检查密钥环境变量生产环境的密钥是否被硬编码权限是否为最小化。查看日志打点关键步骤是否打印了结构化日志能否在出问题时快速定位到具体执行环节。这些事都不复杂但每一项漏掉后续都可能变成线上事故。尤其是API网关超时和密钥泄露属于极其常见但又容易被忽略的问题。6. 一些写在后面的个人经验最后再分享一个我最近坚持的习惯给Skill里的每个脚本都加版本号并在SKILL.md中明确标注它依赖的最低版本。这是因为Agent的Skills是会漂移的——脚本更新了SKILL.md里的使用说明没同步模型照着旧说明去调新脚本就会莫名其妙地失败。每次上线新版本我会在脚本头部和技能说明中同时打上版本标记并在云函数注释里写明变更原因。这样当Agent行为出现异常时我可以立刻对比这个版本为什么和上次不一样。做Agent和做传统后端有一个很大的不同传统后端只要接口符合契约就能上线Agent的行为却依赖模型对技能描述的理解充满不确定性。因此AI Skills最佳实践的核心并不是把Skill做得多炫而是用更结构化的方式把这种不确定性一点点收敛住让Agent在关键流程上从偶尔发挥变成稳定发挥。希望这些经验能给你一些启发。