把AI Agent真正塞进企业应用里,和拿Agent做个聊天Demo是两码事。我花了一整个交付周期,把一个以AI Agent为核心的企业应用从零搭到上线,从技术选型、多智能体协作、工具接入到安全管控全部趟了一遍,中间踩了不少坑,也沉淀出一套可以复用的打法。这篇算是我对这个完结项目的一次全面复盘,适合正在做或者准备做企业级Agent应用的开发者、架构师,尤其是那些已经跑通Demo、但不知道怎么把Agent做得能扛住业务压力的朋友。
先说清楚这个项目能解决什么问题。大部分团队做Agent,往往停在“能聊”“能查资料”“能调一两个API”的阶段,一放到企业环境里就露馅:没人审批、工具乱调、上下文越聊越乱、模型偶尔胡说八道,出了问题也不知道怎么追踪。我这套实战体系的核心,就是把Agent从“一个会聊天的模型”变成“一个能干活的生产系统”,围绕任务规划、多Agent协作、工具协议、记忆管理、安全审计这几个维度做工程化落地,而不是停留在调用模型的层面。
整条技术链路我采用了Spring AI Multi Agent作为后端多智能体管理框架,用LangGraph编排复杂工作流,再用MCP协议把所有企业工具统一接入,模型层可以随时切换私有化部署的大模型或云端API。这一套组合在国内企业环境里是能真正跑起来的,下面我把每个环节的设计思路和实操过程拆开讲。
1. 项目定位与整体设计思路
1.1 企业需要什么样的Agent:从Demo到生产的三条硬约束
做这个项目之前,我先把市面上的Agent教程大概翻了翻,发现大多数都停在“怎么调用模型API”“怎么写Prompt”“怎么接一个简单工具”,真正到生产环境要解决的问题反而很少有人讲透。企业应用的场景里,Agent面对的不只是“用户问一句话,模型回一句话”,而是背后一连串业务动作:查数据、改状态、发通知、触发审批、生成报告,每一步都可能造成实际影响。
所以我在项目一开始就定下了三条硬约束,后面所有技术决策都围绕它们展开。
第一条是可管控。Agent不能想调什么就调什么,企业系统里每个工具、每类数据都有权限边界。我见过有Demo里让Agent去调删除接口,后果想想都后怕。企业环境必须做到“Agent能做什么、不能做什么,管理员在后台一眼能看明白”。
第二条是可观测。模型输出是概率性的,同一个问题两次的回答可能完全不一样。生产环境一旦出问题,不能靠猜。这就要求每一次Agent思考、每一次工具调用、每一次结果生成,都得留痕,得能回放整个过程。
第三条是可回滚。Agent升级了提示词、换了模型版本、改了工具配置,效果变差怎么办?必须有机制能快速回退到上一个稳定版本,而不是让业务方干等着。
这三条约束直接决定了我的技术选型:不能简单用“模型+工具”的裸编写法,需要一个能编排流程、管理状态、记录日志的整体框架。
1.2 技术选型:为什么是Spring AI Multi Agent + LangGraph + MCP
技术选型这块我花了不少时间对比。最开始我也想过纯Python写LangChain或者纯LangGraph,后来实际做企业项目时发现,大部分中大型企业的后端基础设施是Java系,Spring Boot占了绝大多数。如果Agent服务用Python单独起一套,运维、监控、权限体系都要重新对接,成本很高。
因此我把主框架定在Spring AI Multi Agent上。这个方案的好处是能和现有Java后端服务无缝集成,Agent的管理、调度、生命周期都能纳入Spring的生态,开发团队上手成本低。而且Spring AI对主流模型厂商做了统一抽象,换模型厂商不用改业务代码,这对国内企业尤其重要,因为模型供应商随时可能调整服务策略。
复杂流程编排这块,我用LangGraph来补充。LangGraph的核心是“有向状态图”,每个节点是一个处理步骤,节点之间定义好流转条件,比如“工具调用失败走重试分支”“审批未通过走终止分支”。这种状态机的设计比单纯让模型自由发挥稳定得多,至少能保证流程不会跑飞。
工具接入层我用了MCP协议。以前接企业工具是最痛苦的,每个系统一套API、一种认证方式、一种数据格式,Agent接十个工具就要写十套适配代码。MCP把工具统一成标准协议:模型通过协议发现工具、调用工具、拿结果,你只需要为每个系统写一个MCP Server,后续模型升级、Agent框架更换都不影响工具层。
模型层我的做法是可插拔。开发环境接云端API快速迭代,生产环境切换成内网部署的开源模型,比如Qwen系列的72B版本或者GLM系列,具体看算力情况。
1.3 整体架构与数据流
整个系统的架构分五层,我按数据流方向理一遍。
最上层是接入层,包括IM工具里的企业聊天入口、Web端的管理后台、以及API网关对外暴露的接口。用户在这个层级发起请求,比如在IM里对Agent说“帮我查一下上季度华东区的销售报表”。
下来是Agent编排层,也是核心大脑。这一层先经过意图识别,判断用户是要查数据、生成内容还是执行操作;然后走任务规划,把复杂需求拆解成多个步骤;再经过多Agent调度,决定是让单个Agent直接完成,还是让多个Agent协作。所有流程状态都被LangGraph记录成节点图,便于追踪和回放。
第三层是工具服务层。所有企业系统的能力,比如ERP的数据查询、CRM的客户信息、审批流引擎、消息通知服务,都通过MCP Server封装成标准工具,Agent通过统一的协议去调用。
第四层是模型服务层,可以连接私有化部署的大模型,也可以连云端API,由模型网关统一转发,做负载均衡和降级。
最底层是数据与基础设施层,包括存放业务数据的向量数据库、保存对话与操作日志的日志系统、以及模型评测集。整个链路的关键设计是“每一步都有记录、每一个动作都有权限校验、每一条数据都有来源标注”,这样Agent才能真正从开发玩具变成企业生产力工具。
2. 企业级Agent的核心设计拆解
2.1 任务规划:把复杂需求拆成可执行节点
Agent能不能干复杂活,第一步看任务规划能力。我在项目里把规划分成两层:一层是“流程级规划”,由开发人员预先定义好业务流程的节点和流转条件;另一层是“任务级规划”,由模型根据用户的具体请求动态生成执行步骤。
流程级规划适合那些流程相对固定的场景。比如“报销审批Agent”,节点就是固定的:收集票据信息→调用财务系统校验→生成审批单→推送审批人→通知结果。这种流程不能全靠模型自由发挥,必须由开发人员把节点固化下来,每个节点做什么、参数从哪里来、校验规则是什么,全部写清楚。模型只是在每个节点上负责“理解输入、提取关键信息”这一步。
任务级规划适合开放式的场景。比如“数据分析Agent”,用户的问题可能是“分析一下为什么这个月退货率上升了”,模型需要自己决定:先查订单数据,再做品类维度拆解,再对比上个月的数据,最后生成分析报告。这种情况我会让模型输出一份结构化的执行计划,而不是一次性把结果生成完。
我在项目里让规划器输出类似下面的JSON结构,后续执行引擎按这个结构去跑:
{ "plan_id": "plan_20250101_001", "nodes": [ { "node_id": "n1", "type": "data_query", "params": { "table": "orders", "time_range": "2024-11-01~2024-12-31" } }, { "node_id": "n2", "type": "data_query", "params": { "table": "orders", "time_range": "2023-11-01~2023-12-31" } }, { "node_id": "n3", "type": "compare_analysis", "deps": ["n1", "n2"], "params": { "dimension": "category" } }, { "node_id": "n4", "type": "report_generation", "deps": ["n3"], "params": { "format": "markdown" } } ] }这里的deps字段表示节点依赖关系,执行引擎会先跑没有依赖的节点,等依赖完成后再跑后续节点。这样做的好处是:复杂任务可以并行执行,比如同时查两个时间段的数据,最后汇总对比,显著缩短整体耗时。
2.2 工具调用:以MCP协议统一接入企业系统
工具调用是Agent真正产生业务价值的环节,也是工程上最容易出问题的地方。我在这个项目里做了一个决定:所有工具接入全部走MCP,不直接写业务系统的客户端代码。
为什么坚持用MCP?举个实际例子。项目里要接入企业微信发送消息,如果不用MCP,你可能要引入企业微信SDK,封装发送接口,然后在Agent代码里写死调用逻辑。后续如果要从企业微信换到钉钉,或者同时支持两套IM,就得改Agent代码。用MCP后,我只需要写一个通用的MCP Server,对外暴露一个send_message工具,内部再根据配置决定走企业微信还是钉钉的API,Agent层完全不用动。
MCP Server的配置大概长这样:
{ "mcpServers": { "wecom": { "url": "http://mcp-internal.xxx.com/wecom/sse", "headers": { "Authorization": "Bearer xxx" } }, "erp": { "url": "http://mcp-internal.xxx.com/erp/mcp", "headers": { "Authorization": "Bearer xxx" } } } }工具接入后,Agent调用工具的流程是:模型根据用户问题选择工具并生成参数JSON→框架校验参数格式→通过MCP协议分发到对应的Server→Server调用真实业务系统→返回结构化结果→模型基于结果生成最终回复。
有一个细节很重要——工具描述必须写清楚。模型选择工具靠的就是工具名和描述,描述写得太泛,模型可能选错;写得太长,又容易占用上下文。我总结的经验是:工具名用“动词+对象”的格式,描述控制在三句话以内,第一句说明功能,第二句说明适用场景,第三句说明重要限制。
2.3 多Agent协作:Supervisor模式、串联任务与并行分解
单个Agent的能力终归有限,这次项目里我把多Agent协作做成了三种模式,按需求灵活选择。
第一种是Supervisor模式,适合“有一个总指挥”的场景。一个主Agent负责理解用户意图、拆解任务,然后分发给多个子Agent,子Agent各自完成后把结果交回主Agent汇总。我在客户服务场景里就是这种结构:主Agent负责人接待,遇到技术问题转给技术Agent,遇到订单问题转给订单Agent,遇到投诉情绪激烈的转给安抚Agent。主Agent负责统筹语气和最终回复,子Agent只处理自己的专业领域。
第二种是串联模式,适合流程明确的场景。Agent A的输出作为Agent B的输入,像流水线一样。比如“合同审查Agent”:先由合同解析Agent提取合同关键条款,再由风险识别Agent对照企业风控规则库标出风险点,最后由报告Agent生成审查意见。每个环节的Agent只做一件事,做精做专,出问题了也容易定位。
第三种是并行分解模式,适合数据处理量大的场景。把一个大任务拆成多个互不依赖的子任务,多个Agent同时执行。比如“季度经营分析Agent”,可以同时让销售数据Agent、库存数据Agent、财务数据Agent各自去查数,最后统一汇总生成分析报告。这种模式能把处理时间从几十秒压缩到几秒,用户体验提升明显。
在Spring AI Multi Agent里实现这几种模式,核心是给每个Agent定义好角色、工具和协作协议。我在代码里是这样注册一个Agent的:
@Bean public Agent orderAgent(OrderToolService orderToolService) { return Agent.builder() .name("orderAgent") .description("处理订单查询、订单变更、物流跟踪等订单相关问题") .model(chatModel) .tools(orderToolService) .memory(conversationMemory) .build(); }子Agent注册好后,主Agent通过名字引用它们,框架自动处理调用链和上下文的传递。我实测下来,这种模式比用一个巨大的全能Agent请可靠得多,因为每个Agent的上下文窗口负担小,工具选择也更精准。
2.4 记忆与上下文管理
Agent的记忆是企业应用里经常被忽略、但实际上决定体验天花板的部分。用户问“帮我查一下上季度的销售数据”,过一会儿说“再把图表画出来”,如果Agent不记得“图表”指的就是上季度的销售数据,那就抓瞎了。
我在这个项目里把记忆分成三层。
短期记忆就是当前会话的上下文,直接放在模型上下文窗口里。但要注意,业务场景下的对话往往很长,几十轮之后上下文很容易超长。我的做法是:超过阈值后对历史对话做摘要,把摘要保留在上下文中,细节信息存到外部存储里,用户问到再检索。
长期记忆用来保存跨会话的关键信息。比如一个用户多次询问某个客户的项目进展,我会把“这个用户关注的客户是XXX”这类实体关系抽取出来,存到向量数据库里。下次用户再提类似问题,先做一次语义检索,把相关信息拉回上下文。
实体记忆是保存用户偏好和身份信息,比如“用户是华东区销售经理”“用户偏好看周维度数据”“用户常用报表格式是Excel”。这些信息以结构化JSON的形式存储,每次请求进来先加载到上下文里。
记忆模块的存储我用的是PostgreSQL加pgvector插件,量不大不需要上独立的向量数据库,一个数据库全搞定。检索时按用户ID过滤,保证A用户查不到B用户的记忆,这一点权限隔离在记忆设计阶段就要做好,不然后面会很麻烦。
3. 从零搭建一套企业级Agent(实操记录)
3.1 环境准备:本地模型、向量库与内网部署
企业项目对数据安全的要求通常很高,不少客户明确要求数据不出内网。所以这次部署我走的是内网私有化路线。模型我用vLLM部署了Qwen2.5-72B-Instruct,量化精度用AWQ 4bit,四张A100的机器可以稳定跑起来,单次推理延迟大概在1.5到2秒之间,对大多数企业内部场景够用了。Embedding模型用的BGE-M3,中文语义检索效果稳定,部署起来也轻量。
向量库方面,我先跑通的是Milvus,后来发现项目数据量其实没那么大,又换成了pgvector。省掉一个组件,运维负担小很多。这里我给个建议:数据规模在千万级以下,直接用pgvector,足够用;如果做到千万级以上或者有复杂的过滤需求,再上独立的向量数据库。
整套环境跑起来后,我先做了一轮模型能力摸底。用企业内部常见的50个问题测试了一遍,重点关注模型在工具选择、多轮对话、中文指令跟随上的表现。摸底结果会决定后面的提示词怎么写、哪些流程需要工程兜底。这一步不要省,能帮你少走很多弯路。
3.2 基础Agent流程落地:意图识别、工具选择、参数填充、结果校验
基础Agent是后面所有复杂玩法的最小单元,它的工作流看起来很简单,但每一步都有坑。标准的调用流程是:用户输入→意图识别→选择工具→填充参数→调用工具→校验结果→生成回复。
意图识别这一步,我用的不是让模型单独分类,而是把它融入到工具选择的环节里。模型根据用户输入直接判断应该调用哪个工具,如果所有工具都不匹配,就走兜底回复。这样做的好处是省一次模型调用,延迟更低。
参数填充是最容易出错的环节。举个例子,用户说“给张三发个消息说我下午三点到”,模型需要判断出:接收人是张三、消息内容整体是“我下午三点到”、可能需要附带时间信息。如果工具接口要求传user_id,模型必须先从用户表里查出张三对应的ID,再填入参数。我在工具定义时专门加了required_parameters字段,框架在调用前做校验,缺参数就让模型补充,而不是直接把错误请求发出去。
结果校验这个环节我投入的精力最多。工具返回的数据不一定符合模型生成回复的需求,可能是空值、格式不对、或者数据项太多。我的处理是:工具返回后先经过一层结构化处理,把关键字段提取出来,再交给模型生成回复。比如查询订单接口返回了完整对象,包含20多个字段,但用户只关心状态和预计送达时间,那就只把这两个字段给模型,减少上下文消耗,也降低模型胡说八道的概率。
这里给一段简化后的核心调用逻辑示例,帮助理解调用时序:
def run_agent(user_query, available_tools): # 1. 让模型选择工具并生成参数 tool_call = model.select_tool(user_query, available_tools) # 2. 校验参数完整性 missing = validate_params(tool_call, available_tools) if missing: tool_call = model.fill_missing_params(tool_call, missing) # 3. 调用工具 result = execute_tool(tool_call) # 4. 结构化处理返回结果 extracted = extract_key_fields(result, tool_call["output_schema"]) # 5. 生成最终回复 reply = model.generate_reply(user_query, extracted) return reply3.3 用LangGraph编排复杂工作流
基础Agent跑通之后,我开始处理复杂的业务流程。举个项目里实际做过的“差旅报销Agent”例子,这个流程涉及多轮确认和审批。
完整流程是这样:用户提交报销申请→Agent检查票据信息是否完整→不完整则返回补材料→完整则生成报销单→如果金额大于5000元,走部门审批节点→审批通过后推送财务系统→最后通知用户结果。
用LangGraph实现这个流程,核心是定义状态图和节点函数:
from langgraph.graph import StateGraph, END class ExpenseState(TypedDict): user_input: dict receipts: list is_complete: bool amount: float approved: bool result: str def check_receipts(state: ExpenseState) -> ExpenseState: # 检查发票信息是否完整 state["is_complete"] = validate_receipts(state["receipts"]) return state def generate_expense_report(state: ExpenseState) -> ExpenseState: state["amount"] = calculate_total(state["receipts"]) # 调用报销系统生成报销单 return state def approval_route(state: ExpenseState) -> str: # 路由条件:金额大于5000需要审批 if state["amount"] > 5000: return "approval" return "submit" graph = StateGraph(ExpenseState) graph.add_node("check", check_receipts) graph.add_node("generate", generate_expense_report) graph.add_node("approval", approval_agent) graph.add_node("submit", submit_to_finance) graph.add_node("notify", notify_user) graph.add_edge("check", "generate") graph.add_conditional_edges("generate", approval_route) graph.add_edge("approval", "submit") graph.add_edge("submit", "notify") graph.add_edge("notify", END)LangGraph的好处在于流程是显式的,开发人员能完全控制流转逻辑。哪一步卡住了、哪一步耗时长,整个图就是现成的排查工具。做企业应用,稳定性比灵活度重要,这也是我坚持用图编排而不是让模型自由发挥的原因。
3.4 集成Spring AI Multi Agent与运营后台
后端集成是很多开发者忽略但企业最关心的部分。Agent不是独立运行的,它要和现有的用户体系、权限系统、消息服务打通。
我在Spring Boot项目里做了这样一个结构:Controller层只负责接收HTTP请求;Service层调用Spring AI Multi Agent的AgentRunner来执行任务;MCP Server单独部署成微服务,统一对接外部系统。整个链路走内部网络,所有调用都经过网关,方便统一鉴权和限流。
运营后台是让我自己最满意的一部分。后台能看到所有会话的完整记录,包括:用户输入、模型思考过程、工具调用结果、耗时、消耗的token数。每条记录都有关联的trace_id,出了问题点进去就能看到完整链路。我还会在这个后台里配置工具开关,某个工具出问题时,管理员一键关停,业务系统不受影响。这个能力看起来不起眼,但真正救过我好几次。
前端项目里还用到了Continue这个开源AI代码助理插件,自动生成工具接入代码和测试用例,开发效率提升明显。不过也要提醒一句:AI生成的代码一定要人工review,尤其是涉及权限和数据操作的逻辑,不能让AI直接写进生产环境。
4. 落地过程中的关键保障机制
4.1 幻觉治理:提示约束、结构化输出与RAG溯源
企业应用里,模型“一本正经地胡说八道”是最大的风险点。我在项目里做了三层防线。
第一层是提示词约束。在系统提示词中明确写清楚:“如果你不知道答案,请直接说不知道,不要编造。”“所有数据结论必须来源于工具返回结果,不能凭记忆补充。”这层约束能解决一部分问题,但不能完全依赖,因为模型的指令遵循能力有限。
第二层是结构化输出。很多幻觉发生在自由生成的环节。我在项目中尽量让模型输出JSON等结构化格式,并对关键字段做校验。比如生成报告时必须包含数据来源字段,没有来源就视为生成失败,重新生成或走兜底。
第三层是RAG加溯源。对于需要引用企业文档和知识的场景,我用RAG把相关信息检索出来,作为上下文提供给模型,并要求模型在回答中引用来源文档编号。用户能看到“这个答案来自《差旅报销制度》第2.3条”,有源头就能追责,也更容易赢得业务方的信任。
除了这三层,我还折中设置了温度参数为0.2,降低模型随机性,牺牲一点“创造力”换取稳定性。在企业内部工具型应用里,稳定性远重要于花哨的表达。
4.2 企业安全与权限控制
安全是企业选型的底线,Agent在这方面比普通应用多了一层风险——模型可能因为用户的诱导而绕过限制,“越狱”的风险是真实存在的。
我在项目里做的第一个安全措施是RBAC权限体系。每个用户有角色,每个工具声明需要的角色权限。用户输入进来后,Agent调用工具前先做一次权限检查,没有权限直接拒绝,错误信息也不会透传给模型生成。这个校验放在Agent前面,而不是靠提示词约束,因为提示词可以被绕过,代码逻辑不会。
第二个措施是操作审计。所有Agent发起的工具调用,无论成功还是失败,全部记录审计日志,包括操作人、操作时间、调用的工具、参数内容、返回结果。这个日志永久保存,不能删除,出了问题一查一个准。金融行业客户尤其看重这个能力。
第三个措施是敏感信息隔离。模型服务层对输入输出做敏感信息过滤,识别手机号、身份证号、银行卡号等信息,识别到就脱敏或者打标签提示。模型本身不应该接触这些原始敏感数据,需要查询时由工具层处理后返回“已脱敏”状态。
另外要提一个很实际的问题——企业终端安全策略。我们项目里Agent调用的部分工具依赖本地客户端程序,比如需要打开Excel处理报表、调用某个桌面端软件抓数据。企业在Windows终端上开启了应用控制策略后,会直接拦截Agent发起的程序调用,弹出一句“你的组织使用适用于企业的应用控制阻止此应用”。这不是Agent的问题,而是终端安全策略和自动化脚本之间的冲突。解决方案一般是两个方向:把Agent执行环境迁到服务器端,消除对本地客户端的依赖;或者在客户端给Agent的执行进程添加白名单,通过企业的IT审批流程解决。我强烈建议优先做第一种,服务器端执行更可控,也更容易管理。
4.3 可观测性、评测与持续回归
Agent的调试难度比传统软件高,因为同样的输入可能每次输出都不一样。没有一套评测体系,你根本分不清改动是变好了还是变坏了。
我在项目里建了一个回归评测集,规则很简单:积累一批高频问题,配上标准答案,每次改提示词、换模型、调参数,都跑一遍这个评测集。评测指标我自己设计了一套,见下表:
| 指标名称 | 计算方式 | 目标值 |
|---|---|---|
| 工具调用准确率 | 正确工具调用次数 / 总测试次数 | ≥95% |
| 参数填充正确率 | 参数完全正确的调用次数 / 总调用次数 | ≥90% |
| 答案相关度 | 人工评分或LLM评分,1-5分 | ≥4.2 |
| 幻觉发生率 | 包含未来源信息的答案数 / 总答案数 | ≤5% |
| 端到端成功率 | 完整完成流程的次数 / 总测试次数 | ≥90% |
这套评测集从一开始的50条逐步沉淀到现在的600多条,覆盖了各种业务场景和边界情况。每次模型更新,我先跑评测集,不通过就不上线,把问题控制在开发阶段,而不是留给用户去发现。
日志链路我用的是SLF4J加MDC记录trace_id,把Agent一次会话的所有日志串起来。配合Spring Boot Actuator上报指标,每个Agent的调用量、成功率、平均延迟、token消耗都一清二楚。有一次线上Agent响应突然变慢,我一看监控面板,发现是某个工具调用超时拖累全链路,立刻定位并做了超时降级,整个过程不到10分钟。
5. 调试实录与坑点速查
5.1 高频问题现象与对应解法
这一节整理一下我在项目里实际遇到的高频问题,给朋友们做个速查表:
| 问题现象 | 根因分析 | 有效解法 |
|---|---|---|
| 模型不调用工具,直接编答案 | 工具描述不清晰、上下文里工具信息占位不合理 | 精简工具描述,在提示词中明确要求“必须选择工具后才回答” |
| 工具参数格式错误 | 模型对参数枚举不熟悉,比如日期格式要求不明确 | 在工具描述里写例子,如“日期格式: YYYY-MM-DD,例如2025-01-01” |
| 连续对话后上下文超长报错 | 长对话没有摘要压缩机制 | 实现对话摘要策略,超过阈值自动压缩早期内容 |
| 多Agent协作时子Agent结果丢失 | 子Agent返回内容未做结构化解析 | 规范子Agent输出为JSON,主Agent从JSON中提取字段 |
| RAG检索结果与问题无关 | 向量检索噪声大,检索策略单一 | 增加关键词过滤、rerank环节,限制检索范围 |
| Agent在审批环节“替用户做决定” | 系统提示词没有明确审批边界 | 在流程节点中加入“等待人工审批”的强制等待逻辑,不自动放行 |
| 工具调用超时导致整体卡死 | 未设置合理的超时和降级策略 | 工具调用设置超时上限,超时后返回“系统繁忙”并终止流程 |
5.2 工具调用失败的重试与降级设计
工具调用不可能永远成功,网络抖动、服务重启、数据异常都会导致失败。我在项目里设计了一套三级处理机制。
第一级是自动重试。针对网络类错误和瞬时错误,采用指数退避策略重试三次,间隔分别是1秒、2秒、4秒。注意,不是所有错误都适合重试,比如参数校验失败,重试一百次也没用,这种情况直接进入下一级处理。
第二级是模型自愈。工具调用失败后,把错误信息返回给模型,让模型判断是否能调整参数重新调用。比如用户传了一个不存在的订单号,模型可以反问用户确认订单号,或者改用模糊查询。这一步利用了模型的推理能力,很多时候比硬编码的处理方式灵活得多。
第三级是人工降级。如果自动重试和模型自愈都搞不定,就把这个会话标记为“需要人工介入”,转接给人工客服,并且把Agent已经尝试过的步骤完整地带给客服,让客服不用重复问用户一遍。这个设计在客服场景里特别受好评,用户感知是“系统很聪明,搞不定的马上有人工接管”。
5.3 上下文膨胀与成本控制
大型模型按token计费,上下文越长成本越高,响应也越慢。我测算过,一个中大型会话如果全程不压缩,跑几十轮下来token消耗是初始对话的十几倍。企业应用用户量一大,这笔钱真不是小数目。
我常用的控制策略有三个。第一个是工具结果裁剪,工具返回的数据不做全量传入模型,只提取关键字段。第二个是历史摘要压缩,超过一定轮数后,把早期对话用独立的摘要模型总结成几句话,替代原始内容。第三个是热点知识预加载,对于高频查询的企业文档,提前把内容分块向量化,查询时只检索相关片段,而不是把整篇文档塞进上下文。
实测下来的成本控制效果是:平均每个会话的token消耗下降了约60%,首字响应时间也快了将近一半。这笔优化在数据量大的企业场景里非常值得投入。
5.4 一阶段做完后的实操心得
这个项目做下来,我最大的体会是:Agent落地的难点从来不在模型能力,而在工程化能力。模型选型、API调用这些反而是最简单的部分,真正考验人的是流程设计、状态管理、权限控制、异常处理这些“不性感”的工作。
我建议准备做企业级Agent的朋友,动手写代码之前先做三件事:把用户所有可能请求列出来,分类整理,看哪些需要走工具、哪些需要走知识库、哪些是纯闲聊;每个涉及工具操作的流程,先画出流程图,标出可能失败的点;提前设计好评测方案,哪怕是最简单的“50个问题打一分”,也比没有强。
这个项目完结后,我又把这套体系沉淀成了一个更通用的交付框架,从需求澄清、方案设计、实施验证到灰度上线的全流程,每个阶段都定义了明确的准入准出标准。下一批项目再落地时,我的目标是复制这套经验,而不是每次从零开始趟坑。最后再分享一个小技巧:多和业务方聊天,尤其是那些天天用系统的操作员,他们知道最多系统哪里容易出错、哪里不顺手,这些信息比任何技术文档都值钱。Agent做得再好,最终是为了帮他们省时间,别为了炫技丢了初衷。