尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

腾讯云AI Skills实战:从裸函数到会干活的Agent养成指南

腾讯云AI Skills实战:从裸函数到会干活的Agent养成指南 我最早折腾 Agent 的时候犯过一个特别典型的错误把十几个工具函数一股脑塞给大模型觉得只要模型够聪明它自然会调用。结果任务一复杂整个系统就开始胡来——该调日志分析的技能触发了配置查询该写工单的技能自己编了个结果最离谱的一次是模型没等工具返回就开始总结把一段空白当成了“查询结果为空”。后来我才想明白问题根本不在模型而在于我把“能力”和“使用能力的方式”混在了一起。那段时间我重新把腾讯云 AI Skills 的最佳实践从头捋了一遍推翻重来才有了后面这套跑得还算稳的 Agent 体系。这篇就把整个“养成”过程完整复盘一遍聊聊怎么在腾讯云上把一个只会聊天的模型培养成真正能干活的 Agent。如果你正准备上手 Agent 开发或者已经搭了个 Demo 但总觉得“不够聪明”这篇值得花十分钟看完。我不会只讲概念每一步都会告诉你当时为什么这么选、踩了什么坑、换什么方案能绕过去。1. 为什么你的 Agent 总是“看起来强用起来垮”1.1 一次真实的翻车复盘先说我的第一个 Agent 项目给一台云服务器做日常巡检自动分析日志、检查磁盘水位、定位异常进程最后生成一份巡检报告。听起来不复杂对吧我当时把所有能力写成函数直接暴露给模型run_shell(command)、query_log(keyword)、check_disk()、fetch_metrics(metric_name)……模型确实能调用但上线第一周就出了三次严重问题。第一次用户问“帮我看看昨晚为啥告警”模型调用了query_log(keyword告警)拿回来的是一大堆原始日志然后它试图把整段日志都塞进最终回答里Token 直接爆掉。第二次模型调用check_disk()后没有等待结果返回就基于历史记忆开始编造“磁盘使用率 70%”。实际上当时磁盘已经 92% 了。第三次告警里提到了nginx进程异常模型查了query_log之后居然自己推断“重启一下就好”然后调用了run_shell(systemctl restart nginx)。可是这台服务器上跑着另一个业务重启服务属于高危操作压根不该由模型自主决定。这三个问题的共同点是什么不是模型不够好而是我把“能力”直接裸奔交给了模型却没有给它“如何正确使用能力”的规则。函数只是一个动作模型并不知道什么场景下该触发这个动作、调用前要满足什么条件、返回值要怎么校验、失败之后往哪条路走。这就是“看起来强用起来垮”的根源。1.2 Skill 在 Agent 里到底扮演什么角色很多人把 Skill 简单理解成“插件”其实不是。插件是被动加载的代码包而 Skill 更像“带使用协议的完整能力单元”。打个比方工具是一把扳手Skill 是一个老师傅用扳手修水管的全套经验包括什么时候用扳手、需要哪些前置准备、拧到什么程度停手、拧滑丝了怎么处理。你把扳手扔给一个新手他可能反过来用它砸核桃但你把“拧水管接头”的完整经验传给他他才知道遇到哪种漏水情况该上扳手。在 Agent 体系里一个合格的 Skill 至少包含四样东西触发条件什么类型的用户请求会用到这个技能用自然语言描述清楚。输入协议需要哪些参数每个参数的类型、范围、默认值。执行逻辑技能内部真正做的事可以是调用 API、查数据库、跑脚本。输出协议返回给模型的数据结构以及错误状态的处理方式。缺少任何一样技能就退化成一个裸函数模型要么不知道该不该用要么用了不知道怎么处理结果。腾讯云 AI Skills 的实践思路里最核心的一点就是把“工具函数”升级为“带协议的技能包”让模型把精力放在决策上而不是猜测工具怎么用。1.3 从三层模型理解 AI Skills我自己在实践过程中把 AI Skills 分成了三个层次设计完这套分层之后Agent 的能力边界一下子就清晰了。第一层叫原子技能对应单一确定性操作。比如“读取指定路径日志文件”“查询云服务器 CPU 使用率”“调用某 API 获取数据”。原子技能不做决策只负责执行要求快、稳定、可重试。第二层叫组合技能把多个原子技能按业务规则串起来。比如“巡检服务健康状态”这个组合技能内部先拉取进程列表再检查端口连通性然后查最近日志里的错误码最后汇总成一个健康状态报告。组合技能内部是固定流程不依赖模型临场发挥只是把“巡检”这个标准动作固化下来。第三层叫策略技能负责在更高维度做选择。它决定“面对一个复杂目标先跑哪些组合技能、结果异常时怎么切换方案”。策略技能往往是模型发挥主动性的地方但它不做具体执行只产出行动序列。这三层设计有一个直接好处你不需要让一个技能包办所有事情而是通过编排把它们组合起来。模型只在策略层做决策具体动作交给原子技能和组合技能这样既保留了灵活性又不会失控。后面我在腾讯云上做的“运维助手 Agent”就是严格按这个三层模型搭的。2. 动手前的环境盘算腾讯云上养 Agent 的基础配置2.1 服务器规格怎么定先说一个容易跑偏的点很多人一听 Agent 就想着上 GPU我劝你先冷静。如果模型调用走 APIAgent 本体只是一个编排调度服务CPU 和内存才是大头。GPU 只有在你要本地部署推理模型、或者要做向量化嵌入的时候才真正需要。我目前的推荐配置是 4 核 CPU、8GB 内存起步磁盘 50GB SSD。这套配置可以稳定运行 Agent 调度服务、Redis 缓存、多个 Skill 容器以及一个轻量级的向量库。如果你要同时跑本地小模型做意图分类建议内存升到 16GB。我自己之前只开了 2 核 4GB结果同时跑 Redis、Agent 服务和两个 Skill 容器内存直接吃满服务开始频繁 GC模型调用超时率明显上升。后来升到 4 核 8GB整个世界清净了。2.2 依赖与部署的最小清单用我实际的项目为例基础依赖有这么几项组件用途版本建议PythonAgent 与 Skill 开发语言3.11Redis会话日志、技能状态、记忆存储7.xDockerSkill 容器化与隔离24.xNginx反向代理、域名接入1.24这里特别提醒一下 Redis 密码的问题。我最初在腾讯云服务器上装好 Redis 后改了配置文件里的密码重启服务却一直失败反复排查才发现是 systemd 管理方式下启动命令里通过参数显式指定了--requirepass导致配置文件里的密码根本没生效。后面统一改成只在配置文件里维护密码指定好 systemd 依赖关系重启就没再出过问题。还有一个生产环境必须做的事申请一个二级域名。我之前图省事直接用 IP 加端口对外提供服务结果 Skill 回调、模型调用都变得很别扭而且日志里全是扫描器的探测记录。申请二级域名后在 DNS 解析里指向服务器再用 Nginx 做反向代理整个调用链路就干净了。2.3 第一个 Skill 从哪写起别急着追求复杂先写一个能跑的原子技能。我当时的第一个 Skill 是“统计日志文件中指定时间段的错误码 Top N”功能很简单但完整走了一遍“定义-实现-注册-调用”的闭环。直接看核心代码from datetime import datetime from collections import Counter import re def analyze_error_logs(log_path: str, start_time: str, end_time: str) - dict: 分析指定时间段内的错误日志返回错误码出现次数 Top N。 pattern re.compile(r\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\].*?code(\d)) start datetime.strptime(start_time, %Y-%m-%d %H:%M:%S) end datetime.strptime(end_time, %Y-%m-%d %H:%M:%S) counter Counter() with open(log_path, r, encodingutf-8) as f: for line in f: match pattern.search(line) if not match: continue ts datetime.strptime(match.group(1), %Y-%m-%d %H:%M:%S) if start ts end: counter[match.group(2)] 1 return {top_errors: counter.most_common(10)}这个函数本身没什么特别的但要是直接丢给模型它可能不知道start_time该传什么格式也不知道返回值结构。所以要加上描述元数据告诉模型“什么时候用、怎么用、返回什么”。这部分是 AI Skills 的关键下一节详细讲。这个阶段的核心目标是打通本地到云端的部署链路代码简单没关系链路通了后面才有意义。3. 核心玩法设计一个能被 Agent 真正调用的 Skill3.1 Skill 描述就是模型的路标这是我最想强调的一点Skill 描述写得好不好直接决定 Agent 到底聪不聪明。模型本身不会魔法它看到一堆函数只能靠描述文字判断该调用谁。你把描述写得含糊它就靠猜。我当时对比过两个版本的描述效果差异巨大。坏版本功能查询错误日志 参数path, st, et这个描述里的st、et是什么模型可能猜测是 “start time” 和 “end time”但它不确定格式更不确定这个函数是否适合“昨晚告警”这种模糊表达。好版本name: analyze_error_logs description: 当用户提到服务器错误日志、异常码、报错频率时使用。 适用于分析指定时间段内日志文件中的错误码分布情况。 不适合用于查询实时进程状态、磁盘容量或网络连通性。 parameters: log_path: 日志文件的绝对路径 start_time: 开始时间格式 YYYY-MM-DD HH:MM:SS end_time: 结束时间格式 YYYY-MM-DD HH:MM:SS关键差异在于描述里写清了“什么时候该用”和“什么时候不该用”。后者同样重要因为它能帮模型排除干扰项避免出现两个 Skill 都能处理时胡乱选择的情况。3.2 入参与出参的规范设计Skill 的参数不能随手定义要像设计接口一样严谨。我总结了三个原则。第一参数语义化。不要用a、b、tmp这类名字模型对它们的语义理解很弱。用log_path、start_time、limit这种一眼能看懂的名字。第二严格定义类型和格式。比如时间是字符串还是时间戳、日期格式是什么、数字上限是多少全部写清楚。不然模型给你传一个昨晚上8点解析逻辑直接崩溃。第三输出结构必须固定。我习惯让每个 Skill 返回统一的 JSON 包裹结构内容长这样{ status: success, data: { top_errors: [[500, 128], [404, 35]] }, meta: { elapsed_ms: 42, log_lines_scanned: 1024 } }如果执行失败返回{ status: error, error_code: LOG_NOT_FOUND, message: 日志文件不存在: /var/log/app/2024-01-01.log, suggestion: 请检查日志路径是否有效或联系管理员确认日志轮转策略 }注意suggestion字段它给模型提供了下一步行动的线索。模型看到这个提示才知道应该说“日志文件不存在请确认路径”而不是对着错误码干瞪眼。输出结构越规范模型后续编排就越稳。3.3 Skill 之间的编排与兜底当 Agent 挂了十几个 Skill 之后新的问题出现了同一个用户请求可能同时触发多个 Skill。比如“看看服务器状态”既可以触发“检查 CPU 内存”技能也可以触发“检查进程状态”技能还可能触发“查看最近告警”技能。我的处理方式是两层设计。第一层叫做路由优先集。在系统里给每个 Skill 设定一个触发优先级比如“查看服务健康状态”的优先级高于“查看历史告警”。当模型判断多个技能都命中时优先走优先级高的那个避免一次调用太多技能导致 Token 爆炸。第二层是兜底技能。当用户意图不明确、多个 Skill 的中置信度都偏低时触发一个特殊技能它的唯一作用就是向用户澄清你是想看 CPU 使用率还是想看进程状态这个兜底机制看起来笨但非常管用它压制了模型瞎猜的冲动。我还把“何时不该用”加入了每个 Skill 的描述当模型判断当前请求明显不属于该技能范围内时会直接跳过不参与路由竞争。3.4 复杂任务的拆分路径设计好单个 Skill 之后真正让 Agent 变“全能”的是任务拆分能力。以“帮我看看昨晚服务器为什么告警”为例我之前是直接在提示词里写“你要一步步分析”结果模型每次的思考路径都不一样质量极不稳定。后来我换成预设任务模板把复杂目标映射成固定的技能链路用户目标定位昨晚服务器告警原因 触发技能链路 1. analyze_error_logs分析告警时段的错误日志 2. query_metric_history查询同一时段 CPU/内存/磁盘指标 3. check_process_status检查关键进程是否存在异常 4. summarize_report汇总以上结果生成结论与建议模型只需要在预设链路基础上做微调比如发现日志里全是数据库连接失败它可以额外插入一个check_database_connections技能。这样既保证了确定性又保留了灵活性。这个思路有点像一个成熟的编辑拿到稿件之后先按标准流程处理遇到特殊情况再灵活上报而不是每次从头开始想“该怎么审稿”。4. 从本地到云端腾讯云上部署与发布的完整链路4.1 镜像打包与推送到云端仓库本地开发跑通之后下一步是把 Skill 容器化并部署到腾讯云。我是用 Docker 打包的这里分享一个让我少踩很多坑的 Dockerfile 模板FROM python:3.11-slim AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt FROM python:3.11-slim RUN groupadd -r skill useradd -r -g skill skill WORKDIR /app COPY --frombuilder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages COPY --frombuilder /usr/local/bin /usr/local/bin COPY . . USER skill EXPOSE 8080 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8080]这里用多阶段构建把镜像体积从 1.2GB 压到了 400MB 左右启动速度快了不少。而且创建了非 root 用户运行容器安全性也好一些。构建完镜像推送到腾讯云容器镜像服务的完整命令我列出来方便直接参考# 登录镜像仓库 docker login ccr.ccs.tencentyun.com --username 你的账号 # 给镜像打标签 docker tag agent-skill:latest ccr.ccs.tencentyun.com/demo/agent-skill:latest # 推送 docker push ccr.ccs.tencentyun.com/demo/agent-skill:latest推送完成后在服务器上用 docker pull 拉取镜像再通过 docker-compose 编排启动。4.2 配置与密钥的隔离这是安全层面的必修课。我见过太多人把数据库密码、API Key 直接写死在代码或 Dockerfile 里一旦镜像被推送到公共仓库等于把密钥拱手送人。我的做法是所有敏感配置通过环境变量注入本地开发用.env文件云端用腾讯云的密钥管理服务。代码里只读取环境变量不保存任何明文密钥。一个典型的docker-compose.yml片段services: agent-skill: image: ccr.ccs.tencentyun.com/demo/agent-skill:latest environment: - REDIS_HOST${REDIS_HOST} - REDIS_PORT6379 - REDIS_PASSWORD${REDIS_PASSWORD} - MODEL_API_KEY${MODEL_API_KEY} ports: - 8080:8080部署前检查一下把仓库设成私有密钥只用环境变量传递日志里不要打印任何包含敏感字段的配置对象。这三条做到位基本不会出大问题。4.3 服务注册与调用链观察服务部署好之后不能被动的等要有自检机制。我在每个 Skill 容器启动时加了一个健康检查端点/healthz返回包括依赖项状态和服务版本号。Nginx 定期请求它失败就自动摘除节点。接入二级域名后整个调用链是这样的用户请求 → Nginx域名接入 → Agent 调度中心 → 规则匹配路由 → Skill 容器 → 外部 API / 数据库 / 文件系统为了让调用链可追踪我给每个请求生成一个 request_id从入口一直传递到 Skill 内部所有日志都带上这个 ID。线上排查时只要拿到一个 request_id就能把整条调用链拉出来看。这比大海捞针似地翻日志高效了不知多少。另外提一点在 Nginx 层我加了基本的限流单 IP 每秒最多 5 个请求防止有人恶意调用把模型费用刷爆。这个后面在成本控制部分还会细聊。5. 上线后的三件大事性能、成本与可观测性5.1 减少 Token 浪费的三个手段Agent 上生产后最大的开销不是服务器是模型调用。我测过一个复杂任务一次完整执行消耗了一万多 Token其中大量都花在处理冗余信息上。优化之后同样的任务降到三千 Token 左右效果没打折。核心手段就三个。第一会话摘要代替全量历史。不要每轮对话都把之前所有消息塞给模型而是定期把旧消息浓缩成摘要只保留最近几轮完整上下文。这就像开会不用把过去三年的会议记录都念一遍主持人说一句“上次定的是 A 方案”就够了。第二用便宜模型做意图路由。我的 Agent 架构里真正负责“决定调用哪个 Skill”的意图分类部分用的是成本很低的轻量模型只有生成最终报告、结论建议时才用更强的大模型。这条非常重要因为大部分请求的 Token 消耗其实都烧在“决策”环节而决策本身并不需要那么强的生成能力。第三裁剪 Skill 返回内容。日志分析技能可能返回几百条记录但模型只需要 Top 10。所以我在 Skill 内部先做裁剪只返回摘要和关键数据模型拿到的是精简后的信息又可以省下一大截 Token。如果你觉得模型接入这块不好管理可以考虑在中间加一层模型网关比如 liteLLM proxy。统一维护模型路由、重试策略、Token 统计和费用上报这样就不用每个 Skill 各自处理模型客户端了调试起来方便很多这也是我现在在用的架构。5.2 超时、重试与降级的实战参数上线之前我从来没想过“超时”能带来这么多问题。第一次压测时某个外部 API 响应慢了几秒结果模型一直在等整个会话卡死。后来我整理了一套超时和重试参数分享出来供参考环节超时时间重试策略Skill 内部 API 调用5 秒只重试幂等请求最多 2 次模型调用30 秒最多 2 次退避 1 秒Skill 整体执行20 秒不重试直接返回超时错误外部数据查询8 秒可重试 1 次切换备用数据源这里的核心原则是幂等的请求可以放心重试非幂等操作比如重启服务、创建资源绝对不要自动重试宁可返回错误让用户确认也不能造成二次影响。降级策略我也做了预案。当模型服务不可用时Agent 自动切换到规则匹配模式直接用关键词和正则匹配用户意图命中就执行对应 Skill没命中则返回“当前服务暂时不可用”。这样虽然灵活度下降但核心功能不至于完全停摆。5.3 日志里藏着 Agent 的真实状态如果你问我 Agent 项目里最容易忽略的是什么我会毫不犹豫说结构化日志。Agent 是非线性执行的同一个用户问题可能走了完全不同的技能链路没有结构化日志几乎没法排查问题。我设计的日志规范包含四个固定字段request_id请求追踪、skill_name触发技能、trigger_score模型对该技能命中的置信度、elapsed_ms耗时。另外额外记录 token 消耗数和错误码。举个实际例子{ time: 2025-01-06T10:23:41Z, request_id: req_8f2a1c, skill_name: analyze_error_logs, trigger_score: 0.92, status: success, elapsed_ms: 156, tokens: 452 }有了这份日志我能直接统计出哪个技能被调用的频率最高、哪些请求的置信度低于 0.5说明描述还得优化、哪个技能经常超时。这些数据是迭代 Agent 最重要的依据比任何感觉都可靠。6. 全能 Agent 更进一步记忆、多 Agent 与自动验证6.1 记忆机制的第一版实现Agent 被人吐槽“没记性”核心原因是它本身无状态。我的第一版记忆机制很轻量但已经解决了大部分问题。短期记忆用 Redis 存会话上下文TTL 设为 30 分钟用户每次请求都把会话 ID 里的最近几轮消息取出来。长期记忆则做摘要归档每次任务完成后把这次任务的关键结论比如“服务器磁盘扩容到了 200G”“域名证书已续期到 2026 年”存到另一个 key 里下次同类任务开始时直接把摘要注入提示词。这套方案没有引入复杂的向量数据库效果却非常明显用户不用反复解释背景Agent 也能记得之前处理过什么。等到积累到上千条长期记忆后再考虑引入向量检索也不迟。6.2 单 Agent 到多 Agent 的演进当 Skill 数量超过三十个之后我遇到了新的问题单个 Agent 要维护的上下文太长路由准确率开始下降。这时候再往一个 Agent 里塞技能边际收益已经很低了。我的解法是拆成多 Agent 架构一个“主路由 Agent”负责理解用户意图然后分发给“运维 Agent”“数据分析 Agent”“工单处理 Agent”等子 Agent每个子 Agent 维护各自的 Skill 集合。主 Agent 不关心具体执行细节只负责精准分发。这就好比一个大公司不需要一个人干所有岗位而是按职能分成部门每个部门有自己的专业系统。Agent 之间的通信协议沿用之前统一的 request_id 和结构化日志所以拆分后整个系统依然可控。6.3 用自动化测试守住 Agent 的底线很多人写完 Agent 从来不测试上线全靠运气。我后来养成一个习惯维护了一个覆盖常见场景的回归测试集包含一百多条用户问题样本每条样本标注了“期望触发的 Skill”和“期望的行为路径”。每次改动 Skill 描述或新增技能后跑一遍回归测试统计意图命中率和执行成功率。一个精简版的测试脚本test_cases [ {query: 帮我看下昨晚日志里的错误码, expected_skill: analyze_error_logs}, {query: 服务器内存是不是不够了, expected_skill: query_metric_history}, {query: 帮我重启一下数据库, expected_skill: restart_service_confirm}, ] for case in test_cases: result agent_handler.handle(case[query]) print(case[query], -, result.selected_skill, 期望:, case[expected_skill])别小看这个笨方法它帮我发现了很多隐蔽回归。有一次我只是在“analyze_error_logs”的描述里加了一句“支持查询 access log”结果模型开始把访问日志请求也路由到错误日志技能就是靠测试集发现的。Agent 项目的质量不是靠想出来的是靠反复测出来的。最后再分享一点实际感受。Agent 开发跟传统后端开发最大的区别是你永远在跟一个“概率系统”打交道同样的输入这次可能对下次可能错。所以不要追求一次把 Agent 调到完美而是建好迭代闭环记录、分析、修正、回归。腾讯云 AI Skills 这套东西给我的最大价值不是某个具体功能而是逼我把“技能”当成产品去设计每个 Skill 有边界、有协议、有测试、有日志。等到这套体系转起来之后Agent 才真正从一个“实验品”变成了“能干活的生产工具”。如果你也卡在“什么都想做但什么都做不稳”的阶段建议先从设计一个边界清晰的 Skill 开始跑通一次完整闭环再逐步扩展。
返回列表