上周,我和一个在律所做技术负责人的朋友吃饭,他聊起最近团队正在搞的“AI Agent项目”,说每天站会听得他头大。不是“RAG接口又超时了”,就是“MCP服务观测数据对不上”,还有“客户给的合同PDF,Agent解析出来的条款上下文对不上,法务差点炸了”。
这让我想起一个现象:现在网上关于AI Agent、RAG、MCP的教程和概念文章铺天盖地,但大多停留在“Hello World”级别。告诉你一个工具链怎么搭起来,跑通一个Demo,然后就说“搞定”。但真到了企业级开发,尤其是像律所这种对准确性、稳定性和流程有严苛要求的场景,你会发现从“跑通”到“能用”,再到“敢用”和“好用”,中间隔着十万八千里。
今天,我就借这个“律所AI Agent项目”的日常,拆解一下真实的企业级AI应用开发,到底在忙些什么。你会发现,核心矛盾从来不是某个算法多先进,而是如何把前沿的、不稳定的AI能力,封装成一个稳定、可靠、可观测、可维护的工程系统。这其中的关键,往往是一些听起来很“工程”、很“枯燥”的细节。
1. 从“玩具”到“工具”:企业级AI Agent的核心不是智能,是可靠性
很多人对AI Agent的想象,还停留在“一个超级智能的虚拟员工,能理解一切,自主完成复杂任务”。但在企业级场景,尤其是法律、金融、医疗等领域,首要需求恰恰相反:不是要它多“智能”,而是要它多“可靠”。
一个能回答80%问题但偶尔会“幻觉”出错误答案的Agent,其破坏力远大于一个只能回答50%问题但答案100%准确的系统。因为前者会带来巨大的信任崩塌和潜在风险。律所的合同审阅、法律咨询,错一个字、漏一个条款,都可能意味着巨额赔偿。
所以,这个律所项目组每天开会,讨论最多的不是“我们怎么让Agent更聪明”,而是:
- 稳定性:服务会不会挂?响应时间是否稳定?
- 准确性:RAG召回的内容是否精准?有没有被无关信息污染?
- 可解释性:Agent给出的结论,依据是什么?能追溯到原文的哪一段吗?
- 边界控制:什么问题Agent能答,什么问题必须转人工?这个边界怎么定义和监控?
这就引出了他们日常工作的第一个重头戏:RAG(检索增强生成)系统的“对接”与“打磨”。这里的“对接”,远不是调个API那么简单。
1.1 RAG对接:不是调用接口,是定义数据契约
在Demo里,RAG可能就是一段代码:用户提问 -> 向量化 -> 检索向量数据库 -> 返回Top K文档 -> 拼接到Prompt里 -> 交给大模型生成答案。干净利落。
但在企业里,尤其是律所,数据源是复杂的:
- 内部知识库:历年案例汇编、法律法规库、内部办案指引(Word、PDF、Markdown)。
- 动态数据源:客户管理系统中的案件基本信息、日程安排。
- 第三方数据:裁判文书网、企业信息查询平台等(需要合规接入)。
- 非结构化文档:客户发来的合同、证据材料扫描件(格式五花八门)。
“对接”RAG,首先要解决的是数据接入与清洗的标准化。他们需要为每一种数据源编写特定的“解析器”和“加载器”:
- PDF解析器:不能只用通用的PyPDF2或pdfplumber,因为法律文书有固定结构(标题、条款、附录)。他们需要能识别“第X条”、“双方约定”等法律文本结构的解析器,确保条款不被切碎。
- 文档分块策略:法律文档分块不能简单按字数或段落。一个完整的“违约责任”条款可能跨越好几页,必须保证其完整性。他们采用了基于语义和规则的分块策略,比如结合NLP识别出的“条款边界”进行分块。
- 元数据注入:为每一块文本注入丰富的元数据,例如:
文档来源、文档类型(合同/法条/案例)、生效日期、相关案号、所属客户。这些元数据在后续检索和结果过滤中至关重要。
他们为此专门建立了一套数据预处理流水线,所有外部文档必须经过这条流水线的清洗、解析、分块、向量化,才能进入核心的向量数据库。每天的站会,都会有类似“XX客户的新版投资协议PDF,解析后第8条和第9条合并了,导致检索不准”这样的问题讨论。
1.2 检索质量:精准率 vs. 召回率的永恒博弈
即使数据准备好了,检索本身也是个大坑。简单使用余弦相似度去向量库找最像的文本,在法律场景下很容易出问题。
问题一:语义相似但主题无关。比如用户问“劳动合同中试用期最长多久”,向量检索可能返回一堆讲“试用期工资”的段落,因为它们都有“试用期”这个词,语义相近。但用户要的是“时长”。
解决方案:他们引入了混合检索(Hybrid Search)。结合:
- 密集向量检索:捕捉深层语义。
- 稀疏向量检索(如BM25):捕捉关键词匹配。比如“最长”、“多久”这些关键词能有效过滤掉只讨论工资的文档。
- 元数据过滤:在检索前,先根据问题类型(是问法条还是问合同范本?)用元数据过滤一遍候选集,缩小范围。
问题二:长尾问题与冷启动。一些非常专业、冷僻的法律概念,在有限的内部知识库中可能没有直接对应的向量表示。
解决方案:建立查询重写(Query Rewriting)和扩展(Query Expansion)层。利用大模型本身的能力,将用户的原始问题,重写或扩展成多个从不同角度切入、或更接近知识库表述方式的查询语句,分别进行检索,再合并结果。例如,将“试用期最长多久”扩展为“《劳动合同法》关于试用期期限的规定”、“试用期的最长法定期限”。
这些策略的调优,需要大量的测试和评估。他们构建了一个测试集,包含历史上律师常问的几百个问题及其标准答案,每天跑一遍,监控检索模块的精准率、召回率等指标。这才是“RAG对接”的日常。
2. “超时熔断”:给不确定的AI能力装上保险丝
如果说RAG对接是解决“输入”的可靠性问题,那么“超时熔断”就是解决“过程”和“输出”的可靠性问题。
大模型API(无论是云端还是本地部署)不是百分之百稳定的。网络抖动、服务端负载过高、遇到复杂问题导致生成时间过长……任何意外都可能导致请求挂起,进而拖垮整个Agent服务,甚至引发连锁反应。
在律所的项目里,Agent可能被集成到内部OA系统、律师工作台,甚至客户门户。一个前端页面因为Agent接口超时而一直转圈,用户体验是毁灭性的。因此,“熔断”机制不是可选项,是必选项。
2.1 超时控制:每一层都要有“守门人”
他们的超时控制是分层级的:
- 客户端超时:前端或调用方设置的超时,比如10秒。超过就显示“请求超时,请稍后再试”。
- 网关/API网关超时:在请求到达具体Agent服务前,网关层面设置一个稍短于客户端的超时(如8秒),用于保护后端服务不被慢请求拖累。
- 服务内部超时:这是最精细的一层。一个完整的Agent处理流程可能包含多个步骤:
- 意图识别:超时2秒。
- RAG检索:超时3秒。
- 大模型调用:这是大头,也是最不稳定的。他们根据任务类型设定了不同超时:
- 简单QA:超时5秒。
- 复杂合同条款分析:超时15秒。
- 批量文档摘要:超时30秒(并采用异步任务)。
- 后处理(格式化、日志记录等):超时2秒。
任何一个步骤超时,整个流程不会傻等,而是会触发降级策略。例如:
- RAG检索超时 -> 跳过检索,直接让大模型基于通用知识回答,并在答案前提示“本次回答未参考您提供的资料”。
- 大模型生成超时 -> 返回一个预设的友好提示,如“问题较为复杂,分析中…已记录您的问题,稍后由专业律师为您解答”,并将任务转入人工处理队列。
2.2 熔断机制:防止雪崩
超时是针对单次请求的防护,熔断是针对连续故障的防护。他们使用了类似“断路器(Circuit Breaker)”的模式来封装对大模型API的调用。
- 关闭状态:正常调用。
- 打开状态:当一段时间内(如10秒)失败率(超时、服务不可用等)超过阈值(如50%),断路器“跳闸”,进入打开状态。此时所有新请求立即失败(快速失败),不再尝试调用不稳定的下游服务。
- 半开状态:断路器打开一段时间后(如30秒),会进入半开状态,允许少量试探请求通过。如果试探成功,则关闭断路器,恢复常态;如果失败,则继续保持打开。
这样,当大模型服务出现区域性故障或自身负载极高时,Agent服务能快速隔离故障,避免线程池被占满、资源耗尽,导致整个服务不可用。站会上经常听到:“昨晚XX云的大模型服务波动,我们的熔断器触发了好几次,前端大部分请求都走了降级策略,没出大乱子。”
3. MCP观测:看见AI的“思考过程”
MCP(Model Context Protocol)是一个新兴的协议,它允许外部工具(如计算器、代码解释器、搜索引擎)以一种标准化的方式被大模型调用。在这个律所项目里,他们利用MCP协议,让Agent可以调用内部的法律法规查询工具、案例检索工具,甚至是一个简单的法律条款冲突检查工具。
但引入MCP,带来了新的挑战:可观测性(Observability)。
当Agent只是单纯问答时,输入和输出是清晰的。但当Agent开始通过MCP调用各种工具时,它的“思考过程”就变成了一个黑盒:它为什么决定调用这个工具?调用时传了什么参数?工具返回了什么结果?这个结果如何影响了最终的输出?
对于需要审计和追责的法律应用,这是不可接受的。律师需要知道,Agent给出的“根据《XX法》第Y条,本条款无效”这个结论,到底是检索了哪一年的法条,具体是哪一款。
3.1 构建MCP调用的全景观测
因此,他们投入了大量精力构建MCP的观测体系:
- 结构化日志:每一次MCP工具调用,都必须记录下完整的“轨迹(Trace)”。
trace_id: 本次用户会话的唯一标识。tool_name: 被调用的工具名称(如search_legal_clause)。tool_input: 调用参数(如{“law_name”: “劳动合同法”, “keyword”: “试用期”})。tool_output: 工具返回的原始结果。timestamp: 调用时间。duration: 调用耗时。
- 链路追踪:将一次用户问答中,可能发生的多次LLM调用、多次RAG检索、多次MCP工具调用,通过
trace_id串联起来,形成一个完整的“执行图谱”。这样,任何一个最终答案,都可以回溯到其所有的中间步骤和依据。 - 指标监控:监控每个MCP工具的成功率、平均响应时间、错误类型。例如,发现
calculate_damages(计算损失赔偿)工具最近错误率飙升,可能是因为输入参数格式变了,或者依赖的某个内部API挂了。
3.2 观测数据驱动优化
这些观测数据,反过来成了优化Agent的宝贵资源。
- 工具使用分析:他们发现,Agent在回答“合同审查”类问题时,调用“条款冲突检查”工具的频率很低。经过分析,不是不需要,而是Prompt里没有明确指引Agent去调用。于是他们优化了系统Prompt,加入了更明确的工具调用建议。
- 错误根因分析:当用户反馈一个答案不准确时,他们可以通过
trace_id快速定位。发现是RAG检索阶段,某个关键词权重设置不合理,导致召回了一篇过时的司法解释。于是去调整检索器的权重配置。 - 成本与性能优化:观测发现,对于简单的定义查询,Agent有时也会走一遍完整的RAG+LLM流程,耗时又费钱。他们据此引入了一个更轻量级的路由(Router)机制:先通过一个快速的分类模型(或规则)判断问题类型,如果是简单事实性问题,直接走基于关键词的精准文档查找(甚至缓存),绕过重型RAG和LLM。
站会上,关于MCP的讨论常常是:“昨天trace_id=abc123的那个咨询,Agent调了三次案例检索工具,但最终答案却没引用最后一次检索到的最相关案例,得查查是不是结果融合逻辑有问题。”
4. 真实开发日常:在确定性与不确定性之间走钢丝
梳理下来,你会发现,这个律所AI Agent团队的日常,充满了与“不确定性”的斗争:
- 数据的不确定性:客户给的文档格式不确定、质量不确定。
- 模型的不确定性:大模型的输出有随机性,偶尔会“幻觉”。
- 服务的不确定性:依赖的外部API、自身基础设施可能出问题。
- 需求的不确定性:律师们使用后,会提出各种意想不到的用法和边界情况。
而他们的工作,就是用工程化的确定性手段,去封装和约束这些不确定性。
日常一:数据运维与迭代。每天都有新文档入库,需要跑预处理流水线,监控解析错误率,定期更新向量库索引。同时,要根据律师们的反馈,持续优化分块策略和检索算法。
日常二:监控与告警响应。盯着仪表盘:大模型API的P99延迟是否突增?R检索的召回率是否下降?MCP工具调用失败率是否异常?一旦告警,立刻排查。
日常三:Prompt工程与测试。这可能是最像“AI”的工作,但目的极其工程化:如何设计System Prompt能让Agent更稳定地使用工具?如何通过Few-shot示例减少错误格式的输出?他们建立了庞大的测试用例库,每次Prompt调整都必须通过回归测试。
日常四:流程与边界定义。和业务部门(律师们)开会,明确哪些问题Agent可以自主回答,哪些必须提示“建议咨询专业律师”,哪些应该直接转人工工单。将这些边界规则,写成代码里的判断逻辑。
所以,回到开头的问题:真实的企业级AI Agent开发在忙什么?
他们忙的不是炫酷的算法,而是管道、护栏、仪表盘和流程。是把那个能力强大但性格跳脱的“天才实习生”(大模型),训练成一个遵守流程、记录在案、有明确职责边界、且关键时刻知道求助的“可靠助理”。这个过程,百分之八十是软件工程,百分之十五是数据工程,可能只有百分之五,是纯粹的AI算法研究。
如果你也想从“玩具”走向“工具”,那么在你设计下一个Agent的架构时,不妨先问问自己这四个问题:
- 我的数据管道足够健壮吗?能处理各种脏数据、怪格式吗?检索结果真的准吗?
- 我的服务有熔断和降级吗?上游挂了,我的系统会一起挂掉吗?
- 我能看见Agent的“思考过程”吗?出现错误答案,我能在5分钟内定位到是哪个环节出了问题吗?
- 我有清晰的边界和流程吗?用户知道什么能问、什么不能问吗?出了问题,有兜底方案吗?
想清楚这些,你的Agent项目,才算真正上了路。