恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
腾讯云AI Agent实战:从架构选型到Skills设计全复盘
首页
资讯中心
/
腾讯云AI Agent实战:从架构选型到Skills设计全复盘
腾讯云AI Agent实战:从架构选型到Skills设计全复盘
发布时间:2026/9/7 4:38:56
上个月我花了两周时间在腾讯云上把一个只会聊天的大模型服务养成了一套能独立完成服务器巡检、部署脚本生成、DNS解析修改、异常告警的全能Agent。说实话最开始我以为这就是套个大模型框架写几个Prompt的事真正做下来才发现全能这两个字背后藏着大量工程细节。这篇文章不是我给Agent概念做科普而是把我从架构选型、Skills设计到最终部署踩过的坑完整复盘一遍。如果你也想在腾讯云上落地一套自己的Agent甚至已经在开发Agent但不清楚AI Skills到底该怎么设计这篇应该能帮你省掉不少摸索时间。1. 先把全能这个词拆清楚架构选型决定了后面所有坑很多人在做Agent时犯的第一个错误就是恨不得把所有功能一次性堆上去。我今天要查天气、明天要写代码、后天要订机票结果Agent没做出来先被各种插件的兼容性问题折磨到崩溃。我做这个项目的第一件事不是写代码而是把全能拆成一张需求清单明确每个能力到底由谁来提供、以什么方式提供。1.1 从我想要什么倒推我需要什么我把全能Agent拆成了6个核心能力域系统运维、代码生成、网络诊断、定时任务、内容输出、外部API调度。这6个域不是拍脑袋定的而是从日常使用频率倒推的——我会让Agent帮我查服务器负载、帮我生成Python脚本、帮我看域名解析是否正常这些行为最终沉淀成能力域。每个能力域背后对应一组Skills。比如系统运维域下面挂着服务器状态查询进程管理磁盘空间分析这三个Skills网络诊断域下面挂着DNS解析检测端口连通性检查HTTP状态码探测。这样做的好处是每个Skills都足够小、足够单一大模型在意图识别时不会混淆出问题时也容易定位。1.2 三层架构核心、技能、基础设施整个系统我设计成了三层架构Agent核心层负责理解用户意图、拆分任务、编排调用顺序、汇总结果。这一层不关心具体操作只做决策。Skills层以标准接口暴露的原子能力每个Skills解决一个具体问题接收结构化参数返回结构化结果。基础设施层腾讯云服务器、数据库、Redis、容器镜像服务等提供稳定的运行底座。这个分层的核心逻辑是能力与决策分离。Agent核心像项目经理Skills层像执行员工基础设施是办公场地。项目经理不写代码但他知道该叫谁来写执行员工不关心项目整体进度只把自己的活干好。这个架构的好处是每增加一个新能力只需要新增一个Skills核心层和已有Skills完全不用动。我用表格把各个能力域和技术选型做了映射方便后面开发时对照能力域支撑Skills技术方案系统运维状态查询、进程管理、日志分析Shell Python脚本封装代码生成代码生成、命令执行、代码审查大模型 沙箱环境网络诊断DNS检测、端口扫描、HTTP探测Python socket 腾讯云DNS API定时任务定时提醒、周期巡检APScheduler 消息推送内容输出文本摘要、报告生成大模型 模板引擎外部API调度工单系统、IM机器人Webhook 腾讯云API网关从这套架构再回头看全能就不再是一个模糊的口号而是一张可以逐项落地的清单。这也是我在这个项目里得到的第一条经验别急着写代码先给Agent做岗位说明书。2. Skills不是插件也不是函数调用它是一层能力契约在做这个项目之前我也尝试过直接给大模型塞Function Calling定义一套工具函数下来模型确实会调用但稍微复杂一点的需求就要反复调、反复错。后来我把思路从函数调用换成了AI Skills整个效果上了一个台阶。2.1 Skills和普通API调用的本质区别AI Skills不是简单把一段代码包一个函数名让模型去调它是一套完整的能力契约至少包含四个部分自然语言描述告诉模型这个技能是干什么的“在什么场景下应该触发”“什么情况下不要触发”。参数Schema定义入参格式、必填项、取值范围让模型能正确理解并生成参数。执行实现真正干活的代码接收参数并返回结果。经验校验在交付结果前做合法性检查防止模型幻觉产生无效输出。举一个实际例子。我之前写了一个查天气的函数按Function Calling的做法我只需要传一个城市名称。但做成Skills之后我在描述里加了这样一段当用户问明天会不会下雨周末适合去郊游吗这类问题时调用本技能当用户只是随口聊天时不要触发。结果差异非常明显模型不再因为聊天内容里出现天气两个字就跑去调用API误触率大幅下降。2.2 一套可复用的Skills定义规范我最终定型了一套Skills定义结构用JSON描述。每个Skills文件统一遵循这套schema注册到Skills中心后Agent核心启动时自动加载{ skill_name: server_status, version: 1.0.0, description: 查询腾讯云服务器CPU、内存、磁盘、网络等实时状态。当用户询问服务器负载/资源占用/运行状态时触发。, trigger_keywords: [服务器状态, CPU, 内存, 磁盘, 负载, 卡], parameters: { type: object, properties: { server_ip: { type: string, description: 服务器IP地址默认127.0.0.1 } } }, output_schema: { cpu_percent: float, memory_percent: float, disk_percent: float }, timeout_ms: 5000 }这里trigger_keywords不是给模型硬匹配用的而是辅助模型做意图判断。真正让模型学会触发一个Skills靠的是System Prompt里的技能清单和少量示例而不是简单的关键词匹配。我在实际项目中发现如果把所有Skills的描述、参数、示例都塞进System PromptToken消耗会很高而且模型在超长上下文中反而容易漏掉后面的技能。后来我的做法是System Prompt里只保留所有Skills的名称和一句话描述完整的参数Schema放在一个向量索引里模型需要调用哪个Skills时再动态检索把对应的详细定义注入到当轮上下文。这种做法不仅省Token还让规则更清晰。模型先通过一句话描述判断这个能力我有再用检索到的详细Schema学会怎么用这个能力准确率比一次性把所有定义全塞进去高了不少。3. 腾讯云上从零到能跑域名、端口、镜像推送一条龙我的Agent最终跑在一台腾讯云服务器上整个部署链路涉及域名申请、DNS解析、安全组配置、Docker镜像构建和推送。这一段我把每一步的细节和理由都说清楚因为很多人在这些地方浪费了大量时间。3.1 服务器选型和域名申请里的隐藏坑我这次用的是2核4G的云服务器为什么不选1核2G因为Agent核心层要跑大模型推理时还有Skills执行时可能会有并发的Python进程2G内存很容易OOM。这里真的不建议省。很多人不知道腾讯云怎么申请二级域名。其实流程很简单在腾讯云DNS解析控制台里先确保你已经有一个主域名然后添加记录主机记录填你想用的二级域名前缀比如agent记录类型选A记录值填云服务器的公网IP。等TTL生效后agent.yourdomain.com就可以用了。但我在这里遇到的实际问题是光在DNS控制台加记录还不够。如果你之后要配HTTPS证书必须先在腾讯云SSL证书控制台申请免费证书申请时填的域名要和二级域名完全一致然后去DNS控制台加一条CNAME验证记录。等证书签发后下载Nginx版本证书配置到服务器上。这整条链路里只要域名填错一个字符证书都签不下来。3.2 安全组端口千万别学开放所有端口网上有人为省事直接开放所有端口这绝对是大忌。我的做法是只放行必要端口80HTTP、443HTTPS给外部访问22给SSH管理再给Agent调试临时开一个内部端口用完就关。如果你在配置后发现Agent服务外部访问不了第一反应别急着改安全组策略先用curl -v在服务器本机测试确认服务是否真的在监听。很多人的问题根本不是安全组而是服务只绑定了127.0.0.1外部访问自然不通。监听地址改成0.0.0.0后再检查安全组和防火墙规则。这里我要重点说一句腾讯云控制台的安全组和服务器内部的firewalld/ufw是两套独立的规则必须同时放行才能通。很多端口神秘关闭的问题排查到最后都是服务器内防火墙没放行。这个坑我在后面专门讲。3.3 Docker镜像构建与TCR推送全流程Agent服务我用了Docker来打包原因很直接本地环境和服务器环境不一致依赖装起来太痛苦。我的发布流程是这样的先在本地写Dockerfile基础镜像用Python 3.11-slim把依赖装好后复制代码暴露端口。然后构建镜像docker build -t agent-core:v1.0.0 .接下来推送到腾讯云容器镜像服务TCR。登录TCR的完整命令是docker login ccr.ccs.tencentcloud.com --username你的账号ID这里容易踩的坑是用户名不是你的邮箱也不是实例名称而是腾讯云账号ID。密码要用在TCR控制台里创建的访问凭证密钥不是你登录腾讯云的密码。登录成功后给本地镜像打标签标签格式必须与你的TCR仓库地址一致docker tag agent-core:v1.0.0 ccr.ccs.tencentcloud.com/你的命名空间/agent-core:v1.0.0 docker push ccr.ccs.tencentcloud.com/你的命名空间/agent-core:v1.0.0推完后在服务器上拉取并运行docker pull ccr.ccs.tencentcloud.com/你的命名空间/agent-core:v1.0.0 docker run -d --name agent-core -p 8080:8080 \ -e API_KEY你的密钥 \ --restartalways \ ccr.ccs.tencentcloud.com/你的命名空间/agent-core:v1.0.0--restartalways非常重要。Agent核心服务必须保证高可用一旦进程挂了自动拉起否则你在外面一天回家发现Agent罢工了。TCR私有仓库的镜像在服务器上拉取时需要服务器也登录一次TCR。如果你有多台服务器要部署建议在TCR控制台把仓库设为私有后用访问凭证登录或者用腾讯云的CVM实例ID做免密授权这个比较方便。4. 第一个Skills从设计到上线拿服务器体检练手整个项目里最有代表性的一个Skills就是服务器状态体检。我把它作为第一个练手项目的原因很简单它足够独立、输入参数少、输出结果清晰可以完整验证Skills从定义到调度的整条链路。4.1 实现一个服务器体检Skills的完整代码首先定义这个Skills按照前文的规范创建一个server_status.json{ skill_name: server_status, description: 获取腾讯云服务器当前CPU、内存、磁盘、网络IO使用情况。当用户询问服务器卡不卡、资源占用高不高、内存够不够、磁盘还剩多少时触发本技能。, parameters: { type: object, properties: { full_report: { type: boolean, description: 是否输出完整报告默认false只输出简要状态 } } } }然后实现真正的执行函数import psutil import json def server_status(full_report: bool False): cpu_percent psutil.cpu_percent(interval1) memory psutil.virtual_memory() disk psutil.disk_usage(/) result { cpu_percent: cpu_percent, memory_percent: memory.percent, memory_used_gb: round(memory.used / 1024**3, 2), memory_total_gb: round(memory.total / 1024**3, 2), disk_percent: disk.percent, disk_used_gb: round(disk.used / 1024**3, 2), disk_total_gb: round(disk.total / 1024**3, 2) } if full_report: result[top_processes] [ {name: p.info[name], cpu_percent: p.info[cpu_percent]} for p in sorted( psutil.process_iter([name, cpu_percent]), keylambda p: p.info[cpu_percent], reverseTrue )[:5] ] return json.dumps(result, ensure_asciiFalse)前文提过的经验在这里派上了用场我在函数入口加了一层参数校验如果full_report被模型传成了字符串yes而不是布尔值就直接转换避免执行时报错。不要让模型直接控制你的代码执行逻辑你只接收它解析出来的参数然后自己判断参数合法性。这一步我在后面又遇到了更极端的例子后面说。4.2 让大模型正确选择SkillsPrompt编排是关键Skills实现了还得让Agent核心知道什么时候调用它。我在System Prompt里是这样组织的你是一个可调用多技能的智能助手。以下是可用技能列表 - server_status查询服务器CPU、内存、磁盘等实时状态。用户反馈服务器卡顿、资源不足、磁盘空间紧张时使用。 - code_runner执行用户提供的代码并返回运行结果。用户要求写脚本、跑代码时使用。 - dns_check检测域名解析状态。用户询问域名解析是否正常时使用。 当用户的任务需要多个技能配合时请先规划执行步骤再有顺序地调用技能。这里的关键是每个技能描述的最后都要给出触发时机。模型通过描述判断这个请求属于哪个技能的职责范围。如果你的描述只写查询服务器状态模型容易被相近的需求带偏写了用户反馈服务器卡顿、资源不足这类行为描述后模型的判断准确率明显提升。跑通后我加了一个技巧把技能的调用日志打印出来。每次模型调用技能我都记录它选择了哪个技能、传了什么参数、结果如何、用户是否满意。积累几百条日志后去分析哪些描述容易被误解然后针对性修改技能描述。这比一次一次手工测试高效得多。4.3 技能网关把执行和管控收拢到一个入口Skills多起来之后不能再让Agent核心直接执行各种脚本了。我加了一个技能网关所有技能注册到网关里Agent核心只和网关通信。网关负责超时控制、并发限制、参数校验、错误归一化。网关的基本结构from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class SkillRequest(BaseModel): skill_name: str parameters: dict SKILLS { server_status: server_status, code_runner: execute_code, dns_check: check_dns } app.post(/execute) def execute_skill(req: SkillRequest): if req.skill_name not in SKILLS: return {error: skill not found} try: # 统一超时控制 result SKILLS[req.skill_name](**req.parameters) return {status: success, result: result} except Exception as e: return {status: error, message: str(e)}加了网关之后Agent核心不再关心技能内部实现负载由网关统一处理。后面我再加新技能只需要在SKILLS字典里加一个键值对核心层零改动。5. 让Agent有记性上下文窗口、Redis缓存和长期记忆一个没有记忆的Agent每次对话都是初次见面这种体验很割裂。我在项目里做了三层记忆短期记忆靠上下文窗口持久记忆靠Redis长期记忆靠本地向量库。但这块也是我踩坑最多的区域尤其是和Redis相关的那个经典问题。5.1 三层记忆系统怎么设计短期记忆最简单就是每次请求把最近几轮对话拼接进Prompt。在腾讯云上跑了一段时间后发现随着对话轮次增加Token开销线性上涨。我的优化是给对话设了一个最长长度超过就把最老的对话摘出去换成早期对话的摘要。名为摘要压缩实现起来就是每隔几轮调一次大模型把之前的对话总结成一段话。持久记忆放在Redis里。比如用户偏好、常用服务器IP、上次巡检时间这些信息用Redis的String或Hash类型存。优点是读写快、TTL过期方便。长期记忆我用了一个本地向量库把历史任务的处理结果和用户反馈保存成向量类似经验库的角色。当新任务进来Agent先检索向量库找有没有类似问题的处理记录可以直接借鉴。这一步相当于让Agent从每次从零思考变成参考历史经验执行效果明显更稳定。5.2 Redis修改密码后重启失败一条完整的排查链路这里说我踩的最深的坑。我的Agent内部用Redis做记忆缓存跑了一段时间觉得默认密码不安全就去/etc/redis/redis.conf里改了requirepass然后执行systemctl restart redis结果服务再也起不来了。我当时的排查过程是这样的第一步查看Redis运行状态。systemctl status redis提示failed但是没给具体原因。第二步查看Redis日志。tail -50 /var/log/redis/redis-server.log发现报错信息是# Changing to user redis failed: 权限不允许这个报错有点迷惑性我一开始以为是redis用户权限问题折腾了半天用户组和目录权限完全无效。后来仔细看了完整日志才发现错误真正发生在我修改requirepass之后Redis以redis用户身份启动时需要读取配置目录下的某些文件而我改配置时误操作把目录权限改成了700且属主变成了rootredis用户根本没有权限读取配置。第三步修复权限。执行chown -R redis:redis /etc/redis chmod 750 /etc/redis chmod 640 /etc/redis/redis.conf之后再重启Redis服务正常起来了。这里我把教训总结为一条修改Redis配置后千万别直接kill掉进程再手动起一定要用systemctl restart redis让systemd统一管理启动环境。如果起不来先看日志日志永远比猜测靠谱。另一个和Redis相关的坑是protected-mode。默认开启的情况下Redis只允许本机连接。如果你的Agent核心和Redis不在同一台服务器上配置里必须显式设置protected-mode no并且在bind里加上对应IP。很多人只改了密码忘了处理这两个参数然后用远程客户端连接时报DENIED Redis is running in protected mode排查半天才反应过来。5.3 缓存层的收益加了Redis缓存后最直观的收益是成本降了。对于重复性问题比如当前服务器状态怎么样Agent先查Redis里有没有1分钟内的缓存结果有就直接返回不调大模型也不执行实际采样。实测下来高频查询场景下API调用量降了约40%。在腾讯云上跑的话ECS和Redis在同一个私有网络内延迟非常低这个组合用起来还是比较舒服的。6. 上线两周我踩过的坑从端口神秘关闭到模型幻觉传参项目上线后问题并没有结束反而是另一批问题的开始。这一节把我在线上运行过程中遇到的真实故障和排查思路完整梳理一遍每一个都是线上环境才暴露出来的。6.1 安全组明明放行了端口还是连不上的真相这是我第一次在线上排查耗时最久的问题。Agent的API服务部署在8080端口我在腾讯云安全组里已经放行了TCP:8080从服务器本机用curl测试也正常但是从外部访问始终超时。我的排查链路是这样的在服务器上执行ss -lntp | grep 8080确认服务监听在0.0.0.0:8080排除了绑定127.0.0.1的问题。在本地电脑执行telnet 服务器公网IP 8080超时。回到服务器执行iptables -L -n发现有一条REJECT规则拦住了8080。查了半天发现是firewalld没放行执行firewall-cmd --permanent --add-port8080/tcp firewall-cmd --reload后外部访问正常。问题根源就是腾讯云安全组和服务器内部防火墙两套体系都要放行。安全组在云网络层面做过滤firewalld在操作系统层面做过滤两道关卡少一道都不通。排查这类问题时别一上来就去翻控制台先按本机curl - ss监听检查 - 服务器防火墙 - 安全组的顺序从上往下查效率高得多。6.2 模型幻觉传参代码跑飞了责任算谁的上线几天后我发现某些情况下Skills收到了完全不合理的参数。比如Agent要查服务器磁盘居然把IP参数传成了server_ip: localhost——这个还算合理但有一次用户问内存够不够Agent调server_status时传了memory_percent: -20执行端如果不校验这个负数会直接进入后续的判断逻辑导致误报。根因是大模型在生成结构化参数时偶尔会脑补一些不存在的值。这在大模型领域很常见尤其是当用户问题的上下文不够明确时模型会尝试补全信息补出来的东西不一定合理。我的解决方案是三层防御Skills入口加参数校验非法的值直接报错返回给Agent让它重新分析用户意图。一个异常处理层捕获所有Skills抛出异常返回统一格式避免把Python原生异常抛给Agent核心。在System Prompt里加了一句硬性要求如果用户提供的上下文不足以确定参数调用技能前必须追问用户不得自行猜测。三层防御上线后因为幻觉参数导致的误报基本清零了。这也是一条很实用的经验再好的Agent编排也抵不过一个健壮的校验层。大模型的能力边界就在这里你没法完全杜绝它犯错但可以用工程手段把错误的伤害降到最低。6.3 超时与重试别让一个慢技能拖死整个Agent我一开始没有设置超时控制这导致了一个很尴尬的场景用户让Agent做一次完整巡检Agent按计划依次调用了server_status、dns_check、disk_analyze三个技能第一个很快第二个卡住了第三个直接被阻塞在队列里。用户等了很久什么也没等到。问题出在Skills执行时间不可控而Agent核心是同步调用的。我最终加了两个机制每个技能调用都加了超时上限比如server_status最多3秒超时就返回一个执行超时的标准化错误Agent核心拿到这个错误后直接告诉用户该技能暂不可用而不是一直死等。对可重试的技能做了指数退避重试。第一次超时等1秒第二次等2秒第三次等4秒最多重试3次。如果重试还不成功就标记为故障技能后续任务直接跳过它。从用户体验角度说一个告诉用户某功能暂时不可用的Agent比一个卡住几分钟没回应的Agent让人安心太多。6.4 安全加固Agent不是用来裸奔的最后是安全这一关这一点容易被忽略但Agent一旦暴露在公网面临的风险比普通Web服务更大——因为它有执行能力。我做了这几个加固措施密钥统一放腾讯云的凭据管理服务里代码和环境变量中不硬编码任何Secret。Agent的API服务只对腾讯云API网关暴露网关层做鉴权和限流避免直接裸奔到公网。命令执行类Skills放到容器沙箱里容器里不挂载生产数据盘即使被攻击损失能被隔离。每次技能调用的输入输出都写审计日志谁在什么时候调了什么技能、传了什么参数、返回了什么结果全部留痕。这些加固动作不会让Agent更智能但能让它更可靠。一个会执行命令的Agent如果没有完整的日志和权限隔离本质上就是一个别人可以远程利用的跳板。安全怎么强调都不过分。7. 如果让我重做一次有哪些可以加速的捷径项目走到这个阶段整套体系已经稳定运行了两周。如果让我重新做一遍这个项目在保持工程质量的前提下我会从这几处在最初就拉满效率。第一Skills描述一定用真实对话日志去迭代。我最早是一边写代码一边凭感觉写描述懒省事的结果就是上线后频繁误触发。后来我把历史真实对话跑了一遍根据失败案例逐条修正描述效果立竿见影。建议你项目启动时就搭好日志系统前期的数据会成为优化的重要素材。第二TCR容器镜像服务第一次就配好自动构建。我在前期是本地手动build再push每天改代码来回搞浪费了不少时间。后来接上TCR的镜像自动构建代码推送到仓库后自动build服务器上拉一下就行。这条链路你实践一次就会明白为什么值得一开始就配好。第三Redis的持久化策略在生产环境直接默认appendonly yes。我因为贪图恢复速度快一开始用的是RDB快照结果一次断电丢了一小段缓存数据。虽然只是缓存层丢了不致命但不该在已经知道坑的情况下再踩一遍。第四Agent的Prompt不是写一次就完事的。我两周内改了不下十版System Prompt每次都是根据线上运行的失败案例迭代。你如果期望写一个完美Prompt然后一直用趁早放弃这个念头。Prompt是要养的和Agent一样。我现在的感受是AI Skills这套体系的价值不在于它有多炫酷而在于它让Agent的每一个能力都可治理、可度量、可优化。腾讯云这套基础设施配合下来Agent从一台只会聊天的模型慢慢养成了真正能干活、有记性、知道自己能干什么不能干什么的协作体。如果你也在做Agent记住我的忠告先设计能力边界再准备部署环境最后才是写代码。顺序反了你会在后续每一步都为前面的草率买单。