最近和几个团队聊 AI Agent,发现一个很有意思的现象:大家都在给自己的 Agent 做人设。有的叫“智能助理”,有的叫“资深顾问”,有的甚至给它设计了性格、口头禅和情感回应。每次我都会追问一句:“它在生产环境里,敢不敢承担真实的业务后果?”大多数时候,沉默。
我也不是说拟人化完全没用,在很多内部 Demo、创意互动、教学场景里,有人格的产品确实更讨喜。但一旦把 Agent 放到生产级系统里,事情就变了。生产级意味着它要处理真实数据、调用真实接口、影响真实业务;可管控意味着你随时要知道它做了什么、为什么这么做、能不能停下来。这两个词,和“拟人角色扮演”天然是矛盾的。所以这篇内容,我更想聊的是工程可靠的 AI Agent 架构——不是怎么让模型更像人,而是怎么让 Agent 像个真正靠谱的“系统模块”那样被设计、被测试、被运维。
这篇文章适合正在做企业级 Agent 落地的人,也适合被“Demo 很酷但不敢上线”困扰的团队。我会按一套足以支撑生产的架构思路,拆解从观念转变到实操落地的完整过程。不吹概念,只讲我实际验证过的东西。
1. 观念转变:从“角色扮演”到“任务工程”
1.1 为什么生产级 Agent 不该有“人设”
我刚接触大模型应用时也被“拟人”迷惑过。给模型一段“你是一个温暖的客服助手”的提示词,效果立竿见影,对话立刻变得亲切。但上线跑了一周后,问题开始密集暴露。
人设提示词最大的问题是不可预测。模型会把“温柔”理解成一种行为风格,然后延伸到它不该有自主裁量权的地方。有一次,它为了“表达关怀”,在工单回复里主动给用户承诺了赔偿额度——这在成本底线面前是无法接受的。你当然可以在提示词里补一句“注意不要承诺赔偿”,但拟人化的表述是开放的、无边界的,你永远有补不完的口子。
另一个问题是评估困难。测试 Agent 时,如果评价标准是“回复是否自然亲切”,这件事就没有客观标尺。不同人评审同一个结果,结论都不一样,回归测试根本无从谈起。可一旦你把评价标准改成“是否提取了正确字段、是否调用了正确工具、是否在权限范围内操作、输出是否符合执行规范”,每一轮效果都是可量化的。
所以我的观点是:在生产系统里,Agent 不需要人设,需要的是“岗位说明书”。岗位说明书定义职责、边界、工具权限、异常处理路径,剩下的执行全部由流程约束,而不是由“性格”驱动。
1.2 系统提示词的正确写法:职责清单优于人格描述
来看一个对比。
错误写法(拟人化):
你是一个温柔可靠的财务助理,名叫小E,用户问什么都耐心回答, 语气亲切友好,不要冷冰冰,努力让用户感受到贴心服务。正确写法(任务化):
你是财务发票处理系统的执行组件。你的任务是: 1. 从用户输入中提取发票代码、发票号码、金额、开票日期; 2. 校验字段是否完整且符合格式规范; 3. 调用提供的 validateInvoice 工具校验真伪; 4. 严禁自行推断未从工具返回中取得的信息; 5. 将结果按以下 JSON Schema 输出,不得附加任何自然语言解释。两者最大的区别在于:前者规定了“你是谁、你像谁”,后者回答了“你负责什么、你被允许做什么、你输出成什么样”。
我测试过很多次,任务化描述在复杂流程中的表现,远比人格化描述稳定。原因不复杂:大语言模型的生成随机性需要靠约束来收敛,而约束越具体,输出空间越小,幻觉空间也越小。
当然,任务化描述不等于一句废话都没有。你可以保留少量“上下文背景”,但要写业务背景,而不是心理背景。比如“这个接口每次调用会计费,请务必先确认再调用”,这种话对模型决策质量提升很大,因为它直接关联到调用成本。
2. 可管控的 Agent 核心架构:五层模型与职责边界
真正适合生产的 Agent 架构,我会把它拆成五层:入口编排层、意图解析层、工具执行层、记忆状态层、观测审计层。每一层都有独立的职责,也有明确的“不做清单”。这样拆完之后,团队里的工程师拿到任何一层,都能独立开发、独立测试、独立优化。
2.1 入口编排层:身份、鉴权、限额的第一道关卡
很多人把 Agent 的入口理解成“Chat 对话框”,这是第一个坑。生产级 Agent 的输入来源往往是多样的:内部系统的 Webhook、客服工单、定时触发的批处理任务,甚至另一个 Agent 的输出。所以入口层必须是统一的技术网关,而不是一个聊天气泡。
入口层至少要做四件事:身份识别、权限校验、限流配额、租户隔离。用户是谁、属于哪个组织、能调用到哪一层工具,这些问题必须在进入模型之前解决,绝不能交给模型自己去判断。模型判断权限是不靠谱的,它会漏判,也会过度放权。
这一层还要处理“请求体标准化”。把不同的输入来源统一成内部的数据结构,后面几层才不用为输入形态差异反复适配。标准化之后的 payload 会带上全局追踪 ID,这个 ID 会贯穿后续所有层级,是排查问题的关键索引。
2.2 意图解析层:识别“任务”而不是“情感”
意图解析层的任务是完成从自然语言到结构化任务指令的翻译。我建议你用“意图白名单”的模式,而不是开放式的“自由对话”。业务系统里真正会被执行的意图,往往就那么几十种:创建工单、查询状态、修改配置、发起审批、导出报表……把可能的意图枚举出来,让模型做分类,远比你让它自由发挥再事后兜底要安全得多。
判断意图置信度也很重要。如果模型对用户意图的置信度低于某个阈值(在真实使用中我一般设 0.7),不要硬猜。正确做法是进入澄清流程,向用户确认“你是要做 A 还是做 B”,或者返回候选数据源让用户选择。这一步能消灭一大部分错误执行。
在这一层还应该完成“参数槽位填充”。比如用户说“帮我查一下上周的项目预算”,你需要把“上周”解析成具体日期范围,把“项目预算”映射成对应的数据表查询参数。凡是解析不到的必填参数,直接触发反问,而不是默认填一个值。默认值在生产系统里是最危险的东西之一,模型猜错了,业务就错了。
2.3 工具执行层:让工具定义成为安全边界
工具执行层是整个架构里最关键的地方。模型不是来“思考业务”的,它是来“选择工具 + 填参数”的。所以工具注册表要认真设计,每一个暴露给模型的功能都必须做到三件事:声明式定义、幂等操作、可控副作用。
声明式定义的意思是,用函数调用的格式写清楚工具名称、参数结构、返回值结构、调用约束。不要把工具描述写成散文,要写出结构化的方法签名。模型读方法签名比读散文准确得多。
幂等操作的意思是,同一个请求不管执行一次还是十次,结果都一样。实现方式通常是为每个写操作生成一个 requestId,Agent 调用工具时带上这个 ID,服务端根据 ID 去重。这个细节极其重要。真实运行中模型经常因为超时重试而重复触发同一个写操作,没有幂等保护,重复扣款、重复建单都是分分钟的事。
可控副作用的意思是,高风险的写操作不应该直接暴露给模型随意调用。我会把工具分成只读工具和写工具两类,只读工具模型可以自主调用;写工具必须经过审批链,或者至少要在返回值中明确提示“这是一次不可逆操作,需要人工确认”。
2.4 记忆状态层:区分会话记忆和业务状态
“记忆”这个词在生产系统里很容易被误解。很多团队给 Agent 加“记忆”,就是无脑把历史对话全塞给模型,让模型“记住”上下文。这在小 Demo 里没问题,但在生产环境会导致两个严重后果:Token 成本飞涨,长对话后模型注意力分散严重。
我的做法是把记忆拆成两个完全不同的存储:会话记忆和业务态。会话记忆存的是对话本身,用于多轮上下文理解,它要设置预算上限——比如最近 10 轮,超出历史的自动做摘要压缩;业务态存的是流程状态,比如“这个工单目前进行到哪一步、已经审批到哪个层级、哪些字段已验证”,它应该存放在专门的流程引擎或者数据库里,而不是放在 Prompt 里让模型重复推断。
正确的做法是:模型在每一步需要决策时,从业务态中拉取当前快照,而不是从聊天历史里“猜”现在到哪一步了。这就像一辆车导航,你每次转弯前看的都是当前的 GPS 定位,而不是回忆两个小时前自己开到了哪里。
2.5 观测审计层:让每一次模型决策都有“行车记录仪”
没有观测和审计,生产级 Agent 就是一台失控的自动驾驶汽车。观测审计层要做的不只是打日志,而是完整的全链路追踪:哪个用户、在什么时间、输入了什么内容、模型生成了哪些中间结果、调用了哪个工具、工具返回了什么、最终结果是什么、延迟和成本是多少。所有这些都要串联到同一个追踪 ID 下。
这部分我通常用三类指标衡量:服务质量(延迟、错误率、超时率)、成本可控性(Token 消耗、工具调用频次)、内容安全性(敏感信息泄漏、越权访问尝试)。每个指标都设独立告警阈值,一旦触发就通知到具体负责人。
审计数据还要支持“重放”。出问题时,我拿到追踪 ID,能把这次请求的完整输入输出重新走一遍,看模型到底在哪一步犯了错。没有这种能力,排查 Agent 问题就像蒙着眼睛找插座,效率低得可怕。
3. 可靠性设计的关键抓手:结构化输出、双写校验、人类审批
有了层级架构,接下来要解决的是“模型输出不可靠”这个生产级 Agent 面临的最大难题。无他,就是要把模型的所有输出,都关进程序的笼子里。
3.1 结构化输出:让模型交“标准作业”
大模型直接输出自然语言文本,在生产系统里基本不可用。原因很简单:下游系统没法稳定解析。解决思路是强制模型输出符合预先定义 Schema 的 JSON,并且在下游解析时做严格的 Schema 校验,校验不通过就直接重试或者拒绝,不让一个坏结构流入后续环节。
看一个实际例子。在做发票信息抽取时,我自己会定义这样的约束:
{ "type": "object", "properties": { "invoice_code": { "type": "string", "pattern": "^[0-9]{10,12}$" }, "invoice_number": { "type": "string", "pattern": "^[0-9]{8}$" }, "amount": { "type": "number", "minimum": 0 }, "invoice_date": { "type": "string", "format": "date" }, "confidence": { "type": "number", "minimum": 0, "maximum": 1 } }, "required": ["invoice_code", "invoice_number", "amount", "invoice_date", "confidence"] }模型输出之后,程序依次做三件事:合法性校验(JSON 能不能解析)、Schema 校验(字段类型和枚举对不对)、业务规则校验(金额不能为负、日期不能在未来之类)。任何一步不过,要么重试,要么进入人工处理队列。
更稳妥的方式是利用函数调用机制(也常被叫作工具调用),让模型输出意图明确的“函数调用指令”,而不是自由文本。函数调用的参数天然就是结构化的,生成过程受约束更强,幻觉空间更小。我在实际项目中,凡是能走函数调用的场景,绝不让模型直接写 JSON。
3.2 双写校验:关键事实不能被“顺嘴编出来”
结构化解决了格式问题,但解决不了事实问题。模型可以输出完全符合 Schema 的中文错误信息,这是最危险的。
针对关键事实,我会做一些强制校验。比如 Agent 生成回复时如果要引用某个数据库里的客户姓名,我会要求它不得自己生成姓名文本,只能从工具返回结果中引用。如果工具没返回对应的 ID,模型必须拒绝回答,并说明信息不足。这一步配合“评论校验”可以彻底消掉“一本正经胡说八道”的问题。
另一种方式是“双写校验”:让模型生成结论时,同时给出结论的依据链。例如 Agent 说要推延某工单的截止日期,输出里必须携带依据 ID。程序拿到这个 ID,反向查数据库验证真伪,只有验证通过才会把结论写入结果。这类校验不是每个字段都做,成本太高,只针对业务敏感字段设置,比如金额、日期、提单人身份等。
3.3 人类审批回退:最后的守门员
再强的提示词约束,也拦不住低概率的边界行为。所以在写操作之前保留一条人工确认通道,是生产级 Agent 安全性的底线。
我习惯把工作流中的动作分为三个等级:自动执行(只读类、低风险)、半自动执行(需要人工点一次确认)、人工执行(高风险操作,Agent 只做信息预处理,最终提交由人完成)。等级划分不是拍脑袋,是根据“操作不可逆程度”和“影响范围”两个维度来定的。不可逆且影响面大的操作,永远要卡在人工审批环节。
审批环节还要设计超时路径。人工确认如果长时间没响应,Agent 不能无限等下去。合理的做法是超过预设时限后自动降级为“待办提醒”,通知给具体负责人,并把流程状态更新为阻塞。这条路径看起来简单,很多系统上线后才发现没做,结果一大批工单卡死在审批环节,生产事故就是这么来的。
4. 实操复盘:一个生产级 Agent 的落地样本
前面讲了不少设计原则,这一节拿出一个我实际搭过的场景来走一遍,方便你照着落地。我会用一个虚构但典型的企业服务台工单自动处理系统作为例子。
4.1 流程拆解:从原始工单到最终执行
需求场景是某公司在内部服务台上线一个“工单自动分拣与处理”Agent。用户上传统文本工单:“我的笔记本没法开机了,型号是 X200,今天下午约了客户会议,需要紧急处理。”Agent 要自动完成:意图识别、字段抽取、创建工单、分派给对应团队、给用户回复受理结果。
完整执行流程拆成六步。第一步,入口层接收请求,校验用户身份和组织归属,生成唯一追踪 ID。第二步,意图解析层将请求分类为“硬件故障报修”,并提取“型号 X200”“紧急程度高”“预约时间今天下午”等槽位。第三步,工具层调用工单系统接口,创建一张新工单,带上 requestId 做幂等控制。第四步,调用排班接口,查询当前值班维修人员,把工单分派给对应工程师。第五步,模型根据创建成功的工单号和分派结果,生成一段给用户的受理回复,回复内容里只允许引用上游返回的信息。第六步,全部过程写入审计日志,包括每一步的时延和 Token 消耗。
这套流程里最容易被忽视的是第二步和第五步之间的衔接。很多人会在第二步让模型“顺便生成回复内容”,结果模型在还没调用工具创建工单之前,就“猜”了一个工单号出来。我在这套系统里加了一条硬约束:工单号只能来自第三步工具返回结果,如果返回值中没有工单号,第五步必须生成“信息不足,稍后将补充”的回复,并触发人工兜底通知。
4.2 稳定性配置:超时、重试、熔断与回退
Agent 调用外部系统时,网络抖动、服务过载是家常便饭。不可能指望模型每次都一次成功,关键在于把它纳入稳定的容错框架。
我为工具调用设计了三级超时策略。第一级是快速失败,单次工具调用超过 3 秒直接中断,不等它慢慢超时;第二级是有限重试,重试次数上限设为 2 次,超过后进入降级;第三级是结果兜底,降级后将流程交由人工队列处理,并在审计日志中标记为“需要人工复核”。这个策略看起来简单,但能解决非常多的生产问题,因为 agent 最怕的不是出错,是卡住不返回。
成本控制方面,我给每次 Agent 请求设了 Token 强制预算。预算由程序控制,当某一轮对话消耗逼近上限时,自动触发上下文压缩或反问引导收束,而不是无限制生成。实际观察下来,这一步能把单次请求成本降 30% 以上,而且响应速度还有明显提升,用户体感反而更好。
回退策略也要在系统设计时留好“逃生舱”。模型新版本上线后如果指标异常,要有能力在几分钟内切回旧版本。我的做法是把模型版本、提示词版本、工具注册表版本都纳入配置中心管理,同一个 release 唯一的版本号,灰度发布时可以一键回滚到任意历史版本。很多团队只把代码纳入版本管理,忽略了提示词和工具定义也在变化,结果上线后出了问题,连“我现在线上是什么状态”都说不清楚。
4.3 常见问题与排查技巧实录
我把实际运行中遇到的高频问题整理成了一张速查表。这些坑都不是从文档里看来的,是实打实从告警和用户投诉里提炼出来的。
| 现象 | 可能原因 | 排查思路与处理建议 |
|---|---|---|
| 模型凭空生成不存在的客户姓名 | 提示词没限制信息引用来源 | 强制要求模型只能引用工具返回值,工具没返回的信息一律回答“未知”,禁止生成 |
| 同一个工单被创建了两次 | 工具调用重试时未带上请求幂等 ID | 所有写操作强制携带 requestId,服务端做去重,建立唯一索引 |
| 响应速度越来越慢 | 上下文无限增长,Token 预算失控 | 对会话记忆做截断压缩,只保留最近 N 轮和摘要,给每轮对话设 Token 上限 |
| 模型在低置信度下硬猜用户意图 | 意图识别没有置信度阈值 | 增加“确认流程”,置信度低于阈值时主动反问,宁可多一轮交互也不要错一次 |
| 告警没触发,出了问题才发现 | 审计指标只覆盖结果,没覆盖过程 | 对每一步延迟、重试次数、Token 消耗单独记录指标,并配置独立告警 |
| 新提示词上线后效果明显变差 | 没有做 A/B 对照 | 用配置中心做提示词版本管理,灰度发布,实时对比新旧版本的关键指标 |
还有一个排查技巧是小流量复现法。每次模型行为异常,我不会只去看线上日志猜原因,而是把异常输入拿到离线环境里,固定同一模型版本、同一提示词版本,用一个很小的测试集反复跑。这样能快速判断问题是出在提示词、出在模型版本,还是出在工具链路。定位效率会比直接在线上“盲调”高一个量级。
5. 最后分享一点个人体会
做 AI Agent 这段时间,我最大的转变是:不再追求让模型“看起来聪明”,而是追求让它“做完事之后,系统不会失控”。
我见过太多团队因为一个“看起来很惊艳”的 Demo 就兴冲冲投入生产,结果被幻觉、权限失控、链路不可观测轮流教训。其实 Agent 的本质,仍旧是一个软件系统。只不过它的“代码”由模型生成,“逻辑”由提示词约束,“稳定性”由编排层兜底。所有这些,本质上都是工程问题,而不是“角色扮演”问题。
踩过几次坑之后,我现在的习惯是:上线任何 Agent 功能之前,先写一份“暴力测试清单”——故意输入模糊信息、故意让工具接口超时、故意提供异常格式数据,看看系统是不是还能按预期响应。能通过这些测试的 Agent,才值得交给真实用户。这个习惯看起来笨,但非常有效,也一并分享给每一个正在构建生产级 Agent 的同行。