AI Agent工程实践:AI Skills设计与腾讯云部署全解析
2026/9/5 8:04:24 网站建设 项目流程

聊到 AI Agent,我发现一个很有意思的现象:十个人里有八个都在做“全能 Agent”,但真正把“全能”落到实处的,靠的不是模型本身多聪明,而是你给 Agent 配了多少双“好用的手”——这些手就是 AI Skills。最近我在腾讯云上把一个会编程辅助、信息检索、日常任务处理的 Agent 从零搭到能稳定跑业务,中间折腾了不少 Skill 的定义、调试和部署。把这条链路里值得说的部分整理出来,能给正在做 Agent 开发、或者准备把 Agent 推向生产环境的朋友一些有效参考。

这篇内容适合两类人:一类是想做 Agent 但卡在“模型只会聊天,不会干活”这个阶段的开发者;另一类是已经在做一些 Skill 原型,但不知道怎么设计、测试、发布,更不知道如何在腾讯云这类云环境里把整套东西跑稳的工程师。我会按自己实际项目的推进路径来写,不会只讲概念,会把设计 Skill 时的关键判断、部署时会踩的坑、调优时的具体参数都摊开说。

1. 先想清楚:Agent、Skill、Workflow 三者到底谁管哪一层

1.1 Agent 不等于大模型:我习惯把能力拆成三层

很多人第一次做 Agent,会把 Agent 直接等同于“调用大模型”。实际跑过以后你会发现,如果只靠大模型的上下文对话能力,它什么都接不住。我习惯把 Agent 拆成三层来看:

  • 意图理解层:大模型负责理解用户诉求、拆解目标,决定第一步做什么。
  • 决策编排层:一段确定性的逻辑或者一个轻量级框架,负责决定调用哪个 Skill、按什么顺序调用、怎么处理中间失败。
  • 工具执行层:真正干活的 AI Skills,访问数据库、跑代码、发请求、操作文件、查文档,全部在这一层完成。

大模型在中间其实是“调度大脑”,但它不能自己执行动作。一个能干的 Agent,必须通过 Skills 把外部世界接进来。

Skill 是什么?我理解它是“一组对模型开放的、契约化的能力”。它不是简单的一个函数,也不是一个纯 Prompt,而是一整套能被模型理解、调用、返回结构化结果的接口。同一个 Agent 里,你可以挂“代码搜索”“单元测试生成”“日志分析”“数据报表生成”这些 Skills,每次由模型根据任务动态决定用哪一个。

1.2 Skill 和 Prompt、Function、Workflow 到底差在哪

在社区里经常看到有人把 Skill、Function、Workflow 混着说,这里我按自己的实践做个区分:

概念核心特征适合场景典型问题
Prompt一段自然语言指令一次性解释需求不可复用、不好测试、容易上下文污染
Function单个原子操作封装一个具体动作只能做单步,复杂任务要多次编排
Skill原子操作+执行策略+描述元数据可复用、可路由的完整能力需要单独设计接口和错误返回
Workflow预先编排好的执行路径固定流程,比如定时日报流程写死,不适合开放式任务

最开始我偷懒,把所有能力说明都塞进 Prompt 里,结果上下文一长,模型频繁漏掉工具约束。后来把所有工具调用抽成 Skill,每个 Skill 有独立的描述、参数 JSON Schema、执行函数,问题一下就解决了。Skill 最大的价值是“让模型在没有看到具体实现的情况下,也能知道这个能力是做什么的、什么条件下该调用”。

Workflow 和 Skill 的差别更大,Workflow 是确定性的“流程图”,Skill 是模型动态决策的“可选项”。全能 Agent 的“全能”恰恰来自动态能力组合,而不是把所有路径都预先画好。

1.3 为什么我把整套东西放到腾讯云上落地

原因有四条,都很现实。

第一,Agent 不能只活在本地。模型需要回调接口、前端页面、定时任务、文件存储,这些都需要一台 7x24 小时在线的服务器。第二,腾讯云的 CVM 或轻量应用服务器价格不贵,对个人开发者很友好,部署架构也成熟。第三,很多模型在海外,业务数据和用户请求在国内服务器上转发更稳定。第四,云厂商自带的对象存储、域名、密钥管理、安全组,这些是做一个生产级 Agent 的刚需,不用额外找服务。

我个人踩过一个坑:早期把 Agent 整个跑在本地笔记本上,Skill 里的定时任务一断网就挂,更别提把能力开放给同事用了。后来迁到云服务器上,配合安全组、HTTPS 域名和环境变量管理,才算真正“能用”。

2. 给 Agent 搭骨架:框架选型和云上资源规划

2.1 框架选型:别一上来就上重型编排框架

Agent 框架很多,比如 LangChain、LangGraph、字节的 Coze、开源的 Dify,以及一些轻量的 Agent SDK。我看到不少新手一上来就选最重的 LangGraph,结果状态图越画越乱,Skill 还没写几个就被框架本身困住了。

我的建议是分阶段选择:

  • 快速验证阶段:直接手写一个 while 循环 + Function Calling,把模型返回的 tool_calls 分发到具体 Skill 函数。这个过程能帮你深刻理解 Agent 内部是怎么运作的。
  • 业务复杂度上来后:再切换到带记忆、带多轮工具调用管理、带 Session 隔离的框架,比如 LangGraph 或 Harness 这类执行管控更细的方案。
  • 纯业务场景:可以直接用 Dify/Coze 这类低代码平台,把大部分 Skill 外包给平台插件。

“全能 Agent”容易犯的一个毛病是贪多,什么都想接。想避免这个问题,务必先跑通一个最小闭环:一个问题 -> 模型决策 -> 调用某个 Skill -> 返回可靠结果。这个闭环跑通后,新增 Skill 只是“填接口”的事情。

2.2 云上资源规划:CPU、内存、网络一个都不能少

Agent 服务对服务器的要求分两部分。

一部分是 Agent 调度服务本身,它很轻,主要是处理 HTTP 请求和逻辑编排,2 核 4G 的轻量服务器完全能跑。另一部分是 Skill 执行可能涉及的模型推理或数据处理,如果你用了本地模型做 embedding 或者重计算,就需要 GPU 实例;如果主要调用 API 模型,CVM 无需 GPU,多花点钱上满 4 核 8G 或 8 核 16G 反而收益更大,因为 Skill 执行多为 IO 密集。

我推荐的最小配置是:腾讯云轻量应用服务器 2 核 4G,系统盘 60G,带宽 5Mbps。这个配置用于部署 Agent API、LiteLLM Proxy、向量库和日志服务足够。如果同时要跑比较大的 embedding 模型,再单独开一台 GPU 实例。

网络规划上,有几个容易踩的坑:

  • 不要直接修改安全组“放通所有端口”,只需要放行真正要用的端口,一般是 80/443 给 Nginx,再加一个 SSH 端口。
  • Agent 回调(Webhook)尽量用域名而不是裸 IP,方便后面上 HTTPS。
  • 如果需要在腾讯云上申请二级域名,把域名解析到一个固定公网 IP,再用 Nginx 反代到本机服务。用域名最直接的好处是证书自动续期不用操心。

2.3 一台云服务器上的基础环境配置

写一下我每次新开服务器都会执行的基础配置步骤:

# 更新系统并安装基础工具 sudo apt update && sudo apt upgrade -y sudo apt install -y python3-venv python3-pip git nginx ufw # 创建独立用户,避免直接用 root 跑服务 sudo useradd -m -s /bin/bash agent sudo usermod -aG sudo agent # 简单防火墙策略:只开 SSH 和 HTTP/HTTPS sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable

重点说一下为什么要建独立用户和开防火墙。Agent 服务的 Skill 执行链里经常要跑代码、装依赖、操作文件,如果直接用 root 跑,一旦某个 Skill 的数据源被恶意构造,攻击面会波及整个服务器。用独立用户加上系统级最小权限,可以把爆炸半径压到最小。这套习惯应该从第一天就养成,别等出事了再补。

3. AI Skills 的写法比你想的更讲究

3.1 给 Skill 起名和写描述:这是模型能否正确调用的关键

我调试过二十多个 Skill 后得出的结论是:影响调用准确率最大的因素不是代码逻辑,而是“名字”和“描述”写得够不够清楚。模型是靠描述来决定什么时候调用什么工具的,描述一旦模糊,它就会到处乱点。

一个合格的 Skill 描述应该包含四要素:

  • 功能定义:这个 Skill 具体做什么。
  • 触发条件:用户问什么、处于什么上下文时,模型应该考虑调用它。
  • 限制条件:什么情况下一定不要调用它。
  • 输入说明:需要模型提供哪些关键参数。

举个例子,我写过一个编程类 Skill:代码仓库检索。它在描述里是这样写的:

检索指定 Git 仓库内的代码文件与关键符号。 当用户询问"代码在哪里"、"这个函数在哪个文件"、"项目结构是什么样"时调用。 不要用它来做代码修改或代码解释。 输入需要提供 repo_name,最好是完整仓库名。

加了最后一条“不要用它来做……”之后,模型误调用率明显下降。原因是模型有时会“自作主张”把相关但不同类型的任务都归结到同一个工具上。

3.2 参数定义:JSON Schema 里的每一个字段都值得打磨

Skill 的输入参数直接决定模型需要从对话里抽取什么信息。太粗糙的参数会让模型不知道给你什么,太繁复的参数又容易让模型抽取失败。

实践里有几个具体原则:

  • 参数尽量收敛到 3~6 个。
  • 能枚举的字段用 enum 写死可选值。
  • 所有参数必须写 description,说明格式和单位。
  • 对非必填参数,一定要设默认值,否则模型一旦漏传,Skill 只能直接报错。

以“生成单元测试”这个 Skill 为例,我的参数结构是这样设计的:

{ "name": "generate_unit_test", "description": "为指定文件或函数生成单元测试代码。当用户要求补测试、加单测、提升覆盖率时使用。", "parameters": { "type": "object", "properties": { "file_path": { "type": "string", "description": "需要生成测试的源文件路径" }, "function_name": { "type": "string", "description": "需要测试的函数名,如果测试整个文件则留空" }, "framework": { "type": "string", "enum": ["pytest", "unittest", "jest"], "description": "测试框架" } }, "required": ["file_path", "framework"] } }

这里有一个细节值得注意:function_name不是必填,所以模型如果不确定具体函数,也可以生成整文件测试,这比因为缺参直接失败要好得多。生产环境的 Skill 接口,应该允许模型在模糊情况下“后退到某个安全可用的默认行为”。

3.3 Skill 内部执行流程和返回结构

Skill 的执行函数要处理好“执行成功”“执行失败”“部分成功”三种情况的返回。返回结果最终会重新拼回模型的上下文,所以它同时承担着“给模型做参考”的功能。

我最开始写 Skill 时,只 return 一个字符串,比如“done”。后来发现模型根本不知道 done 意味着什么。正确做法是返回结构化结果:

{ "status": "success", "result": { "summary": "已在 src/main.py 中找到 3 处需要补测试的函数", "files_changed": ["src/main.py"], "coverage_before": 43.2, "coverage_after": 68.5 } }

模型拿到这个返回后,能直接组织成自然语言回复给用户:“这次一共改了 src/main.py,覆盖率从 43.2% 提升到 68.5%。”如果 Skill 返回的是含糊文本,模型就要靠猜,效果自然差一截。

3.4 从 OpenAPI 生成 Skill:和现有服务快速对接

如果你的 AI Skills 背后是现有 HTTP API,我强烈建议直接用 OpenAPI 规范来定义,省去手写 JSON Schema 的繁琐,还能让模型侧的路由更清晰。

一个简单的例子,假设你有一个查天气的接口GET /weather?city=xxx,那么 Skill 可以描述成一个 OpenAPI operation:

openapi: 3.0.0 info: title: Weather Skill version: 1.0.0 paths: /weather: get: summary: 查询指定城市当前天气 operationId: get_weather parameters: - name: city in: query required: true description: 城市名称 schema: type: string responses: '200': description: 天气数据

很多 Agent 框架和模型网关都支持直接加载 OpenAPI 文档生成可调用 Skill,比手写映射函数省太多时间。运行时再做一个很薄的适配层,把 HTTP 请求转发到实际业务服务即可。好处是业务团队改了接口描述,你同步更新 YAML,Skill 的“说明书”不会过期。

4. 模型接入和 Agent 的稳定性:模型代理层怎么做才靠谱

4.1 为什么需要单独再起一层模型网关

当 Agent 体量变大,你会发现直接在各业务代码里调用模型 API 是灾难。每一个 Skill 执行时都可能要用模型;不同环境又要切换不同模型;线上还要统计调用量、控制成本。这些问题最好由一个统一的“模型代理层”来解决。

我选的是 LiteLLM Proxy。它本质是一个把各种模型 API 统一成 OpenAI 兼容格式的网关服务。你在一个配置文件里声明要用的模型和对应的密钥,然后所有上游请求统一走这个代理网关。

这一层给我带来的实际收益有三个:

  • 切换模型不改业务代码,只改配置。
  • 集中处理限流、重试、超时,业务侧不用重复实现。
  • 统一记录调用日志,做成本分析时非常方便。

4.2 在腾讯云部署 LiteLLM Proxy 的步骤

假设你已经有一台 2C4G 的云服务器,部署过程大概是这样:

# 在 agent 用户下创建虚拟环境 cd /home/agent python3 -m venv litellm-env source litellm-env/bin/activate # 安装 litellm pip install 'litellm[proxy]' # 创建配置文件 mkdir -p /home/agent/litellm cd /home/agent/litellm touch config.yaml

config.yaml里声明一个你实际可用的模型列表,因为很多场景不只用一家模型,可以混合配置:

model_list: - model_name: main-assistant litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY - model_name: embedding-local litellm_params: model: openai/text-embedding-3-small api_key: os.environ/OPENAI_API_KEY - model_name: chat-llama litellm_params: model: openai/qwen-plus api_key: os.environ/DASHSCOPE_API_KEY

启动命令很直接:

export OPENAI_API_KEY=your_key export DASHSCOPE_API_KEY=your_key liteLLM --config /home/agent/litellm/config.yaml --port 4000

然后在 Agent 框架里把 base_url 指向http://127.0.0.1:4000,模型名填main-assistant,Agent 就通过代理层访问真正的大模型了。腾讯云服务器上用这种方式代理,业务代码完全感知不到背后的模型切换,这是我觉得最舒服的地方。

4.3 限流、重试与超时:Agent 稳定运行的底线

模型代理层不是配好路由就完了,最关键的是把“稳定性”做进去。Agent 和普通应用不一样:Agent 一个任务的结束可能需要多次调用模型,每次调用都可能超时、限流或返回格式错误。如果不做兜底,任务经常无规律地失败。

我在 LiteLLM Proxy 配置中会加上这些参数:

litellm_settings: drop_params: true set_verbose: true retry_policy: TimeoutError: retries: 3 retry_interval: 2 RateLimitError: retries: 5 retry_interval: 10

另外,在 Agent 调度层我也设置了模型调用的超时上限,单次模型请求最长 60 秒,不再无限等待。给模型配置的max_tokens也会控制一下,不让单次输出无限远。这里最容易忽略的坑是模型返回的 JSON 解析:当max_tokens太小,返回会被截断导致 JSON 不完整。解决方式是给 JSON 输出预留充足 token,同时在解析失败时增加一次“修正重试”,让模型根据报错信息重新输出完整 JSON。没有这层兜底,你会在生产环境遇到不少莫名其妙的报错。

5. Skill 运行不起来、被乱调用:调试与可观测性

5.1 先让每一次 Skill 调用留下完整轨迹

Skill 调试最痛苦的地方在于:它不像普通函数,你传入参数跑一下就出结果。它是“模型决定调不调、调哪个、传什么参数”的链路,一旦出问题,问题可能出在模型判断层、参数抽取层、Skill 执行层任意一环。因此日志就是最好的老师。

我给每个 Agent 请求设计了一张request_id,跟着完整链路走。日志格式尽量结构化,至少要记录以下内容:

  • 用户原始输入
  • 模型输出的 tool_calls 内容(含被选中的 skill 名称和参数)
  • Skill 实际收到的入参(模型抽参后的规范化结果)
  • Skill 执行返回结果或异常堆栈
  • 每次模型调用的耗时和 token 数

有了这套结构,再去复盘“为什么这个请求没调用该调的 Skill”就有据可依了。

5.2 “模型调错了 Skill”的排查链路

我曾遇到一个情况:明明提供了“SQL 查询”和“文档问答”两个 Skill,用户问“帮我看看这份文档里提到哪几个数据表”,模型居然去调用 SQL 查询 Skill 并抛错。整个排查链路走下来,定位到的问题挺有代表性:

  • 第一步看日志。发现文档问答 Skill 的描述里写的是“基于知识库回答问题”,没有说明它能“读取并理解用户上传的文档”。模型不知道文档可以靠这个 Skill 解析,就转而调用了名字里带“表/查询”的 SQL Skill。
  • 第二步看参数。SQL Skill 的参数里恰好有table_name,而文档里有“表”字,模型产生了错误联想。
  • 第三步改描述。把文档问答 Skill 的触发条件改成“当用户提供或上传文档、需要基于文档内容回答问题时优先调用”,并给 SQL Skill 限制条件加上“不要用于直接回答用户上传文档中的内容”。

改完后误调率几乎降为零。这个案例说明:模型对 Skill 的“语义边界”非常敏感。让描述互相区分,比把功能写得更复杂更重要。

5.3 长文本、大文件的性能优化

全能 Agent 经常要处理大文件。如果直接让 Skill 把几百 MB 的日志塞给模型,就算模型窗口再大,等待时间也会让人崩溃。我在生产里采用的处理思路是“分层压缩”:

  • 文本类文件:先做切割和摘要,只把摘要送给模型。
  • 日志类文件:先做关键字聚类,输出每类日志数量和典型样例。
  • 图片和音视频:先用专门的解析 Skill 提取文本信息,再做深度处理。

数据量一大,延时还会受网络影响。这时候建议把文件放到腾讯云 COS,让 Skill 直接返回对象存储 URL,而不是硬传模型上下文。这样既节省 token,也避免 Agent 响应时间被 IO 拖死。

6. 从“会做事”到“放得心”:记忆、安全与权限

6.1 记忆系统不只是存聊天记录

一个“全能”的 Agent 如果每次对话都是失忆的,体验会大打折扣。我理解的记忆系统分为三层:

  • 会话级记忆:当前任务的上下文,用短时列表维护。
  • 用户级记忆:用户偏好、常用配置,存入结构化数据库。
  • 语义级记忆:历史任务中的关键经验,切片后做 embedding,存向量库,需要时检索。

做语义级记忆时有个容易忽略的细节:直接整段存储聊天记录做 embedding 的效果很差。正确思路是先做摘要和意图归并,再生成结构化记录。比如用 Skill 把“用户连续问了三次行情相关的问题”压缩成“该用户对行情类问题有较高关注度”这类结论再去存储。这个先摘要后入库的流程,能让检索精度高很多。

6.2 权限最小化和密钥管理

安全可能是整个 Agent 开发里最容易被忽视的部分。给 Skill 的权限过大,会让一个漏洞变成一串漏洞。

我给自己定的安全红线:

  • Skill 执行 shell 命令必须走白名单,不允许模型自由拼接命令。
  • 数据库类 Skill 只连只读账号,必须有LIMIT和超时控制。
  • 涉及文件删除、覆盖的 Skill 必须二次确认。
  • 所有云厂商密钥都放环境变量或密钥管理服务,不写进代码仓库。

有一次我为了调试方便,把 API 密钥硬编码在 Skill 配置文件里,结果提交代码时差点一起推到远端仓库。后来立刻改了流程:本地用.env,生产环境用云上的密钥管理服务,并给每个密钥设置轮换周期。Agent 服务需要多个上游 API 的 secret,用环境变量管理会有个痛点:服务重启后要重新加载。所以尽量用 systemd service + EnvironmentFile 的方式管理,或者调用密钥管理接口获取。

6.3 多 Agent 编排:别让 Agent 无限互相调用

最后提一下多 Agent 协作。真正复杂的任务,一个 Agent 挂太多 Skills 后反而会决策混乱。我后来按场景拆成了几个子 Agent:编程助手 Agent、数据分析 Agent、文档处理 Agent,再暴露一个总调度 Agent 负责给它们派活,类似“老板 Agent”和“员工 Agent”的结构。

这时有两种实现方式:

  • 每个子 Agent 都是独立服务,总调度通过内部 API 路由。
  • 所有 Agent 都在同一个进程里,通过不同的 system prompt + 可用 Skill 集合隔离。

我建议第一阶段用第二种,资源共享简单、好调试;等业务分离度要求高了再升级到第一种。无论如何,要严格控制 Agent 之间的互相调用层级,防止出现 A Agent 调 B Agent,B 又回调 A 的死循环。简单做法是给每一次调用打上“深度”标记,超过两层就强制让总调度 Agent 直接接管。这在生产中不是以防万一,而是必然会发生的。

7. 复盘与最佳实践清单

7.1 我从这套项目里收敛出的 Checklist

回头把整个链路收束一下,我每次新写一个 Agent Skill 或调整 Agent 架构,都会拿着这份清单过一遍:

  1. Skill 名字是否只有一种语义解释?描述是否清楚写出了触发条件和禁用条件?
  2. 参数是不是少于 6 个?非必填是否有默认值?枚举值是否兜住了绝大多数情况?
  3. Skill 返回结构是否结构化?模型拿到结果后是否可以组织出能让用户满意的回复?
  4. 模型接入是否统一走代理网关?超时、重试、限流是否配置完备?
  5. 是否每个调用都有 request_id 全链路日志?是否能在 5 分钟内定位到误调或失败?
  6. 密钥是否全部从外部环境注入?是否做了最小权限?
  7. 是否有 Agent 互相调用的深度限制?
  8. 大文件是否走了对象存储或摘要预处理,而不是直接塞进模型上下文?

这份清单看起来琐碎,但每一件都在线上让我付出过代价。

7.2 如果从头做一次,我会按这个顺序推进

如果今天再让我从零开始做一个“腾讯云 + 全能 Agent”项目,我会圈定四个阶段:

第一阶段,先写 1 个核心 Skill,跑通完整闭环。这个 Skill 不追求复杂,用“检索项目代码并返回函数定义”这类高频需求来验证链路。

第二阶段,接入 LiteLLM Proxy,把“调模型”这件事从业务里剥出去,这会让你后面增加任何 Skill 时都很轻松。

第三阶段,做日志和观测。Agent 一旦在服务端跑起来,没有可观测性就是闭眼开车。这一步千万别省。

第四阶段,再谈“全能”。加 Skill 时做到两个原则:每个 Skill 对应一类真实、明确的使用场景;每次只加一个 Skill,并立刻回归测试它是否影响其他 Skill 的调用准确率。

最后说一点个人心得:别一上来就追求“什么都会”,先把两三个 Skill 打磨到能被稳定准确地调用,比挂十个半吊子 Skills 有用多了。Agent 的“全能”不是堆出来的,而是靠一个个高质量能力边界清晰叠出来的。腾讯云这套环境只是把底层的机器、网络、域名、密钥管理这些都给你备好了,真正的功夫还是在 Agent 设计和 Skill 工程上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询