
1. 为什么我最终把整套 Agent 流水线压进了 LangChain4j1.1 从“能跑”到“能维护”的转折点最早做 AI Agent 项目的时候我和很多人一样是拿 Python 生态起步的。原型阶段确实爽几十行代码就能把大模型、工具调用、向量检索串起来Demo 演示效果拉满。但一旦进入真实业务问题就来了线上服务是 Java 写的团队里大部分工程师日常写 Spring Boot运维体系、监控体系、权限体系全是 Java 那一套。你硬塞一个 Python 服务进去等于凭空多出一条技术栈部署、扩缩容、日志采集、链路追踪全都要重新搭一遍。我印象特别深的一次是一个内部知识库问答项目。Python 侧的原型两周就跑通了但接入公司统一网关、统一鉴权、统一配置中心的时候前后折腾了一个多月。那段时间我就在想能不能把 Agent 这套东西直接做在 Java 里让业务代码和智能逻辑待在同一个进程、同一套工程规范里。后来接触到LangChain4j这个念头才算真正落地。LangChain4j 的定位很清晰它是 LangChain 思想在 Java 世界的实现把大模型调用、提示词模板、工具调用、记忆、RAG 检索、Agent 编排这些能力用 Java 开发者熟悉的方式封装起来。它不是一个玩具库而是能直接进生产工程的框架。我现在手上的几个项目从最简单的“单工具问答”到“多 Agent 协作流水线”全部用 LangChain4j 一套库搞定没有再引入第二套编排框架。这篇文章我想聊的就是这条完整的进阶路径从最基础的Tool注解开始一步步走到 RAG 检索增强再走到多 Agent 流水线。中间会讲清楚每一步为什么这么设计、参数怎么算、坑在哪里。如果你也是 Java 背景、想认真做 Agent 而不是玩票这篇应该能帮你少走不少弯路。1.2 这套内容适合谁能解决什么问题先说清楚受众。如果你是完全没碰过大模型的纯后端这篇能让你理解 Agent 到底是怎么回事并且知道怎么用 Java 落地如果你已经用 Python 做过 RAG 或 Agent想迁移到 Java 工程体系这篇能帮你把概念映射过来避开 Java 生态特有的坑如果你已经在用 LangChain4j 但只停留在“调个模型问答”的阶段那Tool、多路召回、Agent 流水线这几块应该能让你把项目档次提上去。它能解决的核心问题有三个。第一是技术栈统一Agent 逻辑和业务逻辑同进程、同语言、同构建工具不用维护跨语言调用。第二是能力递进从工具调用到 RAG 到多 Agent是一条平滑的升级路线不用中途换框架。第三是可维护性LangChain4j 的抽象层次比较克制没有过度封装出问题的时候你能顺着调用栈一路查下去而不是对着一堆黑盒魔法干瞪眼。我个人的判断是Java 生态做 AgentLangChain4j 目前是最省心的选择。它不像某些框架那样什么都想管反而留出了足够的空间让你按自己的工程习惯去组织代码。接下来我按进阶顺序一层层拆开讲。2. 打地基把 Tool 用到位的几个关键认知2.1 Tool 到底做了什么为什么它是 Agent 的起点很多人第一次看到Tool注解会觉得它就是个语法糖把方法暴露给模型调用而已。这个理解不算错但太浅了。Tool真正的价值在于它把“Java 方法”翻译成了“模型能理解的工具描述”这个翻译过程包含三件事方法名和参数被转成自然语言描述、参数类型被映射成模型能识别的 schema、返回值被约定成模型可消费的格式。我举个具体例子。假设你有一个查询订单状态的方法Tool(根据订单号查询订单的当前状态返回状态码和描述) public OrderStatus queryOrderStatus( P(订单号格式为 ORD 开头的 12 位字符串) String orderId) { return orderService.getStatus(orderId); }模型看到的不是 Java 代码而是一段类似“有一个工具叫 queryOrderStatus作用是查询订单状态需要一个参数 orderId是 ORD 开头的 12 位字符串”的描述。模型根据用户的问题判断要不要调用这个工具、传什么参数。所以Tool里的描述文字直接决定了模型调用工具的准确率。这里有个我踩过的坑早期我图省事Tool描述写得很短比如就写“查询订单”。结果模型经常在用户问“我的包裹到哪了”的时候不调用这个工具因为它不知道“包裹”和“订单”是一回事。后来我把描述改成“根据订单号查询订单状态和物流进度适用于用户询问包裹、快递、订单进展等场景”调用准确率肉眼可见地提升了。工具描述不是注释是给模型看的提示词必须写得像在跟一个新人解释这个工具什么时候用。2.2 参数设计让模型少犯错的第一道防线参数设计比工具描述更容易被忽视。模型调用工具时参数是它自己“填”的填错的原因通常有两个一是参数类型太自由二是参数含义有歧义。先说类型。能用枚举就别用字符串能用数字就别用字符串。比如一个“设置提醒”的工具时间参数如果定义成String time模型可能传“明天下午三点”“3pm”“15:00”各种格式你后端解析起来要命。更好的做法是拆成int hour和int minute或者定义一个明确的枚举。LangChain4j 会把参数类型转成 JSON Schema类型越明确模型填错的概率越低。再说歧义。我做过一个“发送通知”的工具参数是String target本意是接收人。结果模型有时候传人名有时候传部门名有时候传邮箱。后来我把它拆成String userName和String channel两个参数并在描述里写清楚“userName 是接收人的登录名channel 是通知渠道如 email、sms”问题就解决了。参数名和描述要消除一切可能的解释空间宁可多写几个字也不要让模型去猜。还有一个细节参数尽量必填少用可选参数。可选参数会让模型在“要不要填”上纠结增加不确定性。如果确实有可选逻辑不如拆成两个工具让模型根据场景选择调用哪个。2.3 工具粒度太粗和太细都是灾难工具粒度是个经验活。太粗一个工具干太多事模型不知道该传什么参数太细工具数量爆炸模型选择困难而且每次调用都要消耗 token 去理解工具列表。我的经验法则是一个工具对应一个明确的业务动作参数控制在 1 到 4 个之间。比如“查询订单”和“取消订单”应该是两个工具而不是一个“订单操作”工具加一个 action 参数。因为查询和取消的语义差异很大拆开之后模型判断起来更干脆。但也不能拆得太碎。我曾经把一个“创建用户”拆成了“校验用户名”“校验邮箱”“写入数据库”三个工具结果模型经常只调用前两个就以为完事了。后来合并成一个“创建用户”工具内部自己走校验和写入反而稳定。判断标准是这个动作在业务上是不是一个原子操作用户会不会把它当成一件事来说。如果用户会说“帮我建个账号”那创建用户就是一个工具内部的校验步骤不该暴露给模型。工具数量上我实测下来单个 Agent 挂 5 到 15 个工具是比较舒服的区间。超过 20 个模型的选择准确率会下降这时候就该考虑用多 Agent 拆分或者用路由先做一层筛选。这个后面讲 Agent 流水线的时候会展开。2.4 工具调用的错误处理与幂等设计工具被模型调用和被人调用最大的区别是模型可能会用你想不到的方式调用。所以错误处理和幂等设计必须做扎实。错误处理上工具方法不要往外抛异常而是返回一个结构化的结果对象里面包含成功标志和错误信息。因为异常信息模型不一定能正确理解但结构化的错误描述它能读懂甚至能根据错误信息调整参数重试。比如Tool(根据订单号查询订单状态) public ToolResult queryOrderStatus(P(订单号) String orderId) { try { OrderStatus status orderService.getStatus(orderId); return ToolResult.success(status); } catch (OrderNotFoundException e) { return ToolResult.failure(订单号不存在请确认后重试); } }这样模型收到 failure 之后可能会反问用户“您确认一下订单号是否正确”而不是直接报错给用户。幂等设计同样重要。模型有可能在同一个对话里重复调用同一个工具尤其是它不确定上一次调用是否成功的时候。所以写操作类的工具比如“创建工单”“发送通知”一定要做幂等比如用请求 ID 去重或者先查后写。我吃过一次亏模型连续调了两次“发送通知”用户收到了两条一样的消息体验很差。凡是会产生副作用的工具都要假设它会被调用多次。3. RAG 进阶从单路检索到多路召回的真实调优3.1 RAG 的瓶颈到底在哪先定位再优化RAG 这东西入门容易做好难。很多人搭完第一版 RAG发现效果不理想就开始盲目换 embedding 模型、换向量库、调 chunk size折腾一圈还是不行。问题在于没有先定位瓶颈。RAG 的链路可以拆成四段文档切分、向量化、检索、生成。瓶颈可能出在任何一段。我的排查顺序是这样的先看检索出来的内容对不对如果检索结果里根本没有正确答案那是切分或向量化的问题如果检索结果里有正确答案但模型没用上那是提示词或生成的问题如果检索结果相关但不够全那是召回策略的问题。怎么判断检索结果对不对我会准备一批测试问题每个问题标注好“标准答案所在的文档片段”然后跑检索看这些片段有没有被召回、排在第几位。这个评估集不用很大二三十个问题就能看出问题。没有评估集的 RAG 调优就是盲人摸象你永远不知道改动是变好了还是变坏了。我遇到最多的瓶颈是切分。默认的按固定长度切分经常把一段完整的逻辑切碎导致检索出来的片段缺头少尾。后来我改成按语义切分优先在段落、标题、列表项边界切效果明显好转。LangChain4j 提供了多种文档分割器选对分割器比调参数重要得多。3.2 多路召回为什么单路检索总是不够单路检索的问题在于它只用一种方式理解“相关性”。向量检索擅长语义相似但对精确匹配、关键词、专有名词不敏感。比如用户问“ORD20240115001 这个订单怎么了”向量检索可能召回一堆讲订单流程的文档但真正包含这个订单号的记录反而排不上来。多路召回的思路是用多种检索方式各召回一批再融合排序。常见的组合是向量检索加关键词检索BM25 之类一个管语义一个管精确匹配。LangChain4j 里可以分别配置两个检索器然后用一个融合策略合并结果。融合策略我试过几种。最简单的是加权求和给向量检索和关键词检索各一个权重按分数加权排序。这个方法的坑在于两边的分数尺度不一样向量相似度通常在 0 到 1 之间BM25 分数可能是任意正数直接加权会失真。所以要先做归一化把两边分数都映射到 0 到 1再加权。另一种是 RRFReciprocal Rank Fusion不看分数只看排名把两边的排名做倒数加权。这个方法对分数尺度不敏感实现简单我实测下来在多数场景下比加权求和更稳。它的逻辑是一个文档如果在两路检索里都排得靠前那它大概率真的相关。// 伪代码示意 RRF 融合 MapString, Double fusedScores new HashMap(); for (int i 0; i vectorResults.size(); i) { fusedScores.merge(vectorResults.get(i).id(), 1.0 / (60 i), Double::sum); } for (int i 0; i keywordResults.size(); i) { fusedScores.merge(keywordResults.get(i).id(), 1.0 / (60 i), Double::sum); }那个 60 是 RRF 的经验常数作用是平滑排名差异让靠前的几名差距不要拉得太大。这个值可以调但一般 60 附近都差不多。3.3 重排序把真正相关的顶上来多路召回解决了“召回不全”的问题但召回多了之后排序又成了问题。这时候就需要重排序Rerank。重排序的本质是用一个更精细但更慢的模型对召回的一批文档重新打分。向量检索用的是双塔模型快但粗重排序用的是交叉编码器把问题和文档拼在一起过模型慢但准。所以典型流程是向量检索召回 50 条重排序精选 5 条再送给大模型生成。LangChain4j 支持接入重排序模型。我一般会把召回数量设成最终需要的 5 到 10 倍比如最终要 5 条就召回 30 到 50 条给重排序。召回太少重排序没得选召回太多重排序耗时上去了。这个比例要根据你的延迟要求来定。重排序的收益在什么场景下最明显我观察下来是那种“问题里有多个关键词但只有一个文档同时命中所有关键词”的场景。向量检索可能因为语义泛化把只命中一个关键词的文档排前面重排序能识别出同时命中多个关键词的文档更相关把它顶上来。如果你的 RAG 场景里用户问题经常包含多个限定条件重排序几乎是必选项。3.4 知识库结构结构化、半结构化、非结构化怎么混热词里有人问“kg 知识库、rag 知识库和结构知识库区分以及应用场景”这个问题很实在。我的理解是它们不是互斥的而是可以叠加的。纯非结构化的 RAG就是把文档切块向量化适合问答、摘要这类场景。但如果你要回答“A 和 B 是什么关系”这种问题纯向量检索就吃力了因为它不理解实体之间的关系。这时候知识图谱KG就有用武之地把实体和关系显式建模查询的时候走图遍历。结构化知识库比如数据库表适合精确查询。用户问“上个月销售额多少”这种问题走 SQL 比走向量检索靠谱得多。所以我的做法是把结构化查询也封装成工具让 Agent 自己判断该走向量检索还是走 SQL。这就是 RAG 和工具调用结合的地方也是从“检索增强”走向“Agentic RAG”的关键一步。具体到 LangChain4j你可以把向量检索器、SQL 查询、图谱查询都封装成工具挂给 Agent。Agent 根据用户问题决定调用哪个。这样一套系统既能处理模糊的语义问题也能处理精确的数据问题覆盖面比单一 RAG 宽得多。3.5 RAG 实战里那些文档不会写的坑第一个坑是文档更新。知识库不是一次建好就完事的文档会增删改。如果每次更新都全量重建向量库成本高、耗时长。我的做法是给每个文档块打上文档 ID 和版本号更新时只重建变化的文档对应的块删除时按文档 ID 批量删。LangChain4j 的向量库接口支持按元数据过滤删除用起来还算顺手。第二个坑是chunk 重叠。切分的时候设置一定的重叠长度能避免关键信息正好被切在边界上导致两边都不完整。重叠长度一般是 chunk 大小的 10% 到 20%。但重叠太多会引入冗余检索时可能召回一堆内容重复的块浪费上下文窗口。我一般设 15% 左右。第三个坑是元数据过滤。真实场景里用户的问题往往隐含了过滤条件比如“今年的政策”“技术部的文档”。如果检索时不带过滤可能召回一堆过期或无关部门的文档。所以切分的时候要把文档的年份、部门、类型这些元数据存进去检索时根据问题解析出过滤条件。LangChain4j 支持在检索时传过滤表达式这块一定要用起来。第四个坑是上下文窗口管理。召回 5 条文档每条 500 字加起来 2500 字再加上对话历史和系统提示很容易超模型上下文。我的做法是给召回内容设一个总长度上限超了就按相关性截断优先保留高分片段。同时对话历史也要做滑动窗口或摘要压缩不能无限增长。4. Agent 流水线从单 Agent 到多 Agent 协作的架构演进4.1 单 Agent 的天花板在哪里单 Agent 加一堆工具能解决不少问题但它有天花板。第一个天花板是工具数量前面说过超过 20 个工具模型选择准确率下降。第二个天花板是职责混杂一个 Agent 既要理解用户意图又要查知识库又要调业务接口还要生成回复提示词会变得又长又矛盾。第三个天花板是上下文污染不同任务的中间结果混在一个上下文里互相干扰。我遇到过一次典型情况一个客服 Agent既要回答产品问题走 RAG又要处理退换货走业务工具。结果用户问“这个产品怎么退货”Agent 一会儿去检索产品文档一会儿去调退货接口最后回复得驴唇不对马嘴。问题就在于它没有一个清晰的“先判断意图再分派”的机制。这时候就该上多 Agent 了。多 Agent 的核心思想是分而治之每个 Agent 只负责一个明确的领域有自己的工具集和提示词通过一个协调者或者叫路由、编排器来分派任务。这样每个 Agent 的提示词可以写得很聚焦工具集也很干净整体准确率反而比单 Agent 高。4.2 路由 Agent流水线的入口怎么设计路由 Agent 是整个流水线的入口它的职责只有一个判断用户的问题该交给哪个下游 Agent 处理。它自己通常不挂业务工具只挂“分派”这个能力。路由的实现方式有两种。一种是基于分类把用户问题分类到预定义的几个类别每个类别对应一个下游 Agent。这种方式简单直接适合类别边界清晰的场景。另一种是基于工具调用把每个下游 Agent 封装成一个工具路由 Agent 通过调用工具来分派。这种方式更灵活因为下游 Agent 的描述可以写得很详细路由 Agent 根据描述来判断。我倾向于第二种因为它复用了Tool这套机制不用额外写分类逻辑。比如Tool(处理产品咨询类问题包括功能、价格、使用方法等) public String handleProductInquiry(P(用户问题) String question) { return productAgent.chat(question); } Tool(处理退换货和售后类问题) public String handleAfterSales(P(用户问题) String question) { return afterSalesAgent.chat(question); }路由 Agent 看到用户问题判断该调哪个工具调用之后把结果返回给用户。整个流程很自然。路由的准确率是关键。我一般会在路由 Agent 的系统提示词里写清楚每个下游 Agent 的职责边界并且给出几个边界案例。比如“如果问题同时涉及产品和售后优先走售后”。这种边界规则能显著减少路由错误。4.3 串行与并行流水线的两种编排模式多 Agent 编排有两种基本模式串行和并行。串行就是 A 的输出是 B 的输入像流水线一样。典型场景是“先检索再生成”“先分析再执行”。串行的好处是逻辑清晰每一步的输入输出都明确坏处是延迟累加而且前一步错了后面全错。并行是多个 Agent 同时处理最后汇总。典型场景是“多个专家同时给意见然后综合”。并行的好处是快而且能覆盖多个角度坏处是汇总逻辑要设计好不然就是一堆信息的堆砌。LangChain4j 里实现串行很直接就是方法调用链。实现并行可以用 Java 的CompletableFuture或者虚拟线程把多个 Agent 的调用并发出去然后join汇总。我用虚拟线程做过一个“多专家会诊”的场景三个 Agent 分别从技术、成本、风险角度分析同一个方案并发执行最后汇总成一个报告延迟比串行低了三分之二。选择串行还是并行取决于任务之间有没有依赖。有依赖必须串行没依赖尽量并行。但并行也不是越多越好并发太多会给下游模型服务压力而且汇总逻辑会变复杂。我一般控制在 3 到 5 个并行分支。4.4 状态传递与上下文隔离多 Agent 协作里状态传递是个容易出问题的地方。每个 Agent 有自己的对话历史Agent 之间传递的是“任务”和“结果”而不是完整的对话上下文。如果把所有 Agent 的历史都混在一起上下文会爆炸而且会互相干扰。我的做法是每个 Agent 维护自己的记忆Agent 之间只传递结构化的任务描述和结果。比如路由 Agent 分派任务时传的是“用户问题原文”加“必要的上下文摘要”而不是整个对话历史。下游 Agent 处理完返回的是“结果”加“置信度”这类元信息路由 Agent 再决定怎么呈现给用户。这样做的另一个好处是可测试。每个 Agent 可以单独测试给定输入看输出不用管上游是谁。整个流水线的调试也简单哪个环节出问题单独拎出来看就行。上下文隔离还涉及一个安全问题不同 Agent 能访问的数据权限可能不同。比如售后 Agent 能查订单产品 Agent 不能。这种权限边界要在 Agent 层面就隔离好不能靠提示词去约束因为提示词是可以被绕过的。权限控制要落在代码层而不是提示词层。4.5 Agent 安全与并发生产环境必须面对的两件事热词里“agent 安全”和“ai agent 怎么扛并发”出现频率很高说明大家已经从“能不能跑”进入到“能不能上生产”的阶段了。安全方面我关注三个点。第一是工具调用的权限校验每个工具在执行前都要校验当前用户有没有权限不能因为模型调用了就放行。第二是输入输出过滤用户输入里可能包含提示词注入试图让 Agent 执行非预期操作Agent 输出里可能包含敏感信息需要过滤。第三是操作审计所有工具调用都要记日志谁在什么时候调了什么工具、传了什么参数、返回了什么都要可追溯。并发方面核心是无状态化。Agent 本身应该尽量无状态状态放在外部存储比如 Redis里这样多个实例可以水平扩展。LangChain4j 的组件大多是无状态的你只要把对话记忆、向量库这些外部化就能轻松扩容。另外要注意模型服务的限流并发太高会被限流需要做队列和退避重试。我实测下来一个 4 核 8G 的实例用虚拟线程处理 Agent 请求配合外部记忆存储扛几百 QPS 是没问题的瓶颈通常在模型服务那边不在应用本身。5. 常见问题与排查技巧实录5.1 工具调用相关的高频问题问题一模型不调用工具直接编答案。这是最常见的。原因通常是工具描述不够清楚模型没意识到该用工具。解决办法是把工具描述写得更具体明确“什么时候用这个工具”。另外可以在系统提示词里强调“涉及事实性问题必须调用工具不要凭记忆回答”。问题二模型调用了错误的工具。通常是工具之间职责重叠。解决办法是检查工具描述确保每个工具的适用场景互斥。如果确实有重叠可以在描述里写明优先级比如“如果同时符合 A 和 B优先用 A”。问题三模型传错参数。检查参数类型和描述。类型尽量用枚举或数字描述要消除歧义。另外可以在工具方法里做参数校验返回明确的错误信息让模型有机会重试。问题四工具调用死循环。模型反复调用同一个工具。这通常是因为工具返回的结果模型不理解或者模型陷入了某种循环。解决办法是设置最大调用次数超过就强制结束并返回兜底回复。5.2 RAG 效果不佳的排查路径RAG 效果不好按这个顺序排查排查项判断方法常见原因解决方向召回内容看检索结果里有没有正确答案切分不当、embedding 不匹配换分割器、换 embedding 模型排序位置正确答案排在第几单路检索、缺重排序加多路召回、加重排序生成质量答案有没有用上召回内容提示词不当、上下文超限优化提示词、控制上下文长度覆盖范围问题类型是否都覆盖知识库不全、缺结构化查询补文档、加工具调用我一般会先跑评估集看召回率。召回率低就优化检索召回率高但答案不对就优化生成。分开定位不要一起改。5.3 多 Agent 流水线的调试技巧多 Agent 调试比单 Agent 麻烦因为链路长。我的做法是给每个 Agent 的输入输出都打日志并且给每次请求分配一个 trace ID串起整条链路。这样出问题的时候能一眼看出是哪个 Agent 出的错。另外我会给每个 Agent 单独写单元测试用固定的输入验证输出。这样改一个 Agent 的提示词不会影响其他 Agent 的测试。整个流水线再写集成测试验证端到端的效果。还有一个技巧是降级开关。多 Agent 流水线复杂出问题的时候要能快速降级到单 Agent 或者纯 RAG。我会给每个 Agent 加一个开关出问题就关掉走兜底逻辑。这样线上出问题不至于全挂。5.4 我踩过的几个印象深刻的坑第一个坑是向量库的维度不匹配。换 embedding 模型的时候忘了重建向量库结果新模型生成的向量和旧库里的维度对不上检索直接报错。后来我养成了习惯换 embedding 模型必须重建整个库并且在配置里把模型名和维度绑定防止误用。第二个坑是对话记忆无限增长。早期没做记忆压缩一个长对话跑下来上下文越来越长最后超限报错。后来加了滑动窗口只保留最近 N 轮再对更早的历史做摘要。这个摘要本身也可以用一个轻量模型来做成本不高。第三个坑是工具调用的超时。有些工具是调外部接口的外部接口慢的时候整个 Agent 就卡住了。后来给所有工具调用加了超时超时就返回失败让模型决定是重试还是走别的路径。任何外部调用都必须有超时这是生产环境的基本要求。第四个坑是提示词里的变量注入。用户输入直接拼进提示词如果用户输入里包含类似“忽略以上指令”的内容可能造成提示词注入。解决办法是对用户输入做转义或隔离不要直接拼进系统提示词而是放在明确的用户消息位置。6. 从单库到全套我的工程组织经验6.1 项目结构怎么分层用 LangChain4j 做 Agent 项目我一般会分成这么几层config层放模型、向量库、记忆存储的配置tool层放所有Tool工具类agent层放各个 Agent 的定义和编排逻辑rag层放文档加载、切分、检索相关代码web层放对外的接口。这样分层的好处是职责清晰改哪块找哪块。工具类只关心业务逻辑不关心被谁调用Agent 类只关心编排不关心工具内部实现。测试也好写工具类单独测Agent 类 mock 工具测。配置我建议用 Spring Boot 的ConfigurationProperties管理把模型名、API 地址、超时时间这些外部化不同环境用不同配置。不要把配置硬编码在代码里尤其是模型相关的参数调优的时候要频繁改。6.2 依赖选型与版本管理LangChain4j 的模块划分比较细用哪个引哪个不要一股脑全引进来。核心是langchain4j-core然后按需引langchain4j-open-ai或对应的模型集成、langchain4j-easy-rag快速 RAG、langchain4j-spring-boot-starterSpring 集成等。版本管理上LangChain4j 迭代比较快建议锁定版本升级前先看 changelog。我一般会在测试环境先跑一轮评估集确认效果没退化再上生产。另外注意模型集成的版本要和核心版本匹配不然可能有兼容问题。6.3 监控与可观测性Agent 上生产监控必须做。我关注几个指标每次请求的 token 消耗、工具调用次数和成功率、RAG 检索的召回率和延迟、端到端的响应时间。这些指标能帮你发现性能瓶颈和效果退化。日志方面每次请求的完整链路都要记包括用户输入、路由决策、工具调用、检索结果、最终输出。这些日志不仅是排查问题的依据也是优化提示词和工具描述的素材。我会定期抽样看日志找那些效果不好的 case针对性优化。LangChain4j 本身提供了一些监听器接口可以在模型调用、工具调用这些关键节点挂回调用来采集指标和日志。这块建议在项目早期就搭好不要等出问题再补。6.4 后续可以怎么扩展这套架构搭好之后扩展方向有几个。一是接入更多模型LangChain4j 支持多种模型集成可以根据成本和效果做路由简单问题用便宜模型复杂问题用强模型。二是增加更多 Agent按业务领域拆分每个领域一个专家 Agent。三是引入工作流引擎对于特别复杂的流程可以用更正式的工作流编排LangChain4j 的 Agent 作为其中的节点。我个人在实际操作中的体会是Agent 项目最怕的不是技术难而是需求变。今天加个工具明天改个流程如果没有好的分层和抽象很快就会变成一团乱麻。所以前期在结构上多花点时间后面会省很多事。LangChain4j 这套库的好处就在于它的抽象层次刚好既给了你足够的结构又没有把你绑死你可以按自己的工程习惯去组织。这一点是我用了大半年之后最满意的地方。