LangChain4j 1.23 架构全景:Java 大模型应用的 6 层抽象

LangChain4j 1.23 架构全景:Java 大模型应用的 6 层抽象

一句话结论 :LangChain4j 1.23 的价值不在"帮你调通模型",而在用 Model → Prompt → Memory → RAG → Tool → Agent 六层可替换抽象,把 LLM 应用从 Demo 带到可运维的生产系统。选型时先看团队约束,再看框架能力。

适用版本 :LangChain4j 1.23.0 / JDK 21 / Spring Boot 4.1.x

阅读时间 :约 10 分钟

适合读者:正在做 Java LLM 应用选型、架构设计,或准备把 Demo 推向生产的工程师


0. 先说结论

先看一个典型的故障复盘。

一个客服助手 Demo,两周跑通;接入真实业务三周后,出现四个问题:

  • A 用户的对话记忆串到了 B 用户;
  • 模型调用了本不该开放的退款工具;
  • 知识库答非所问,换了 embedding 模型也没用;
  • 月底账单是预算的 4 倍。

代码每一行都能跑,但系统不可用。

根因不是模型,也不是 LangChain4j,而是把它当成了一个 HTTP 客户端:只关心 chat() 能不能返回字符串,没有按层设计隔离、权限、检索与可观测。

本文不复述 API,而是给出一张架构地图,回答四个问题:

  1. LangChain4j 在 Java AI 生态里到底处于什么位置?
  2. 六层抽象分别解决什么、不解决什么?
  3. 1.23 这次更新,对架构决策有什么影响?
  4. 和 Spring AI 比,什么时候该选谁?

1. LangChain4j 到底是什么?

一句话:它是 Java 生态的 LLM 应用装配框架,不是模型提供方,也不是 Spring 的替代品。

它有三个关键设计选择。

1.1 框架无关

langchain4j-core 不依赖 Spring。你可以在 Spring Boot、Quarkus、Micronaut、Helidon,甚至一个普通 main 方法里使用它。

Spring Boot Starter 只是集成层,不是框架本体。这一点很重要:它意味着你的领域代码可以不被 Web 框架绑架。

1.2 声明式:AiServices

LangChain4j 最有辨识度的设计是 AiServices:你定义一个 Java 接口,框架用动态代理生成实现,把 Prompt、记忆、RAG、工具装配进去。

java 复制代码
interface Assistant {
    String chat(String userMessage);
}

Assistant assistant = AiServices.create(Assistant.class, model);

这类似 Spring Data JPA 或 Retrofit:你声明"要什么",框架负责"怎么接"。

1.3 可替换:一切皆接口

模型、Embedding、向量库、记忆存储、检索器、工具执行器,全部是接口。换模型不应该影响记忆;换向量库不应该影响工具;换记忆存储不应该影响 Prompt。

这是六层抽象能够成立的前提。

1.4 模块地图

模块 作用 什么时候引入
langchain4j-core 核心抽象:模型、消息、记忆、RAG、工具接口 必选
langchain4j 主模块,聚合常用能力 必选
langchain4j-open-ai / langchain4j-ollama / langchain4j-anthropic 具体模型接入 按厂商
langchain4j-spring-boot-starter Spring Boot 集成、@AiService Spring 项目
langchain4j-mcp MCP 客户端 接外部工具生态
langchain4j-agentic 工作流、子代理、Supervisor 多步/多 Agent(实验性)
langchain4j-test Mock、Judge、请求断言 测试
langchain4j-community-* DashScope、国内模型等社区集成 按需

注意:Beta 模块的版本号独立于 core。1.23.0 的 core 不一定对应同版本的 starter 或 MCP 包,引入前要核对 Maven 坐标。


2. 六层抽象:一张图看懂 LangChain4j

"六层"不是官方术语,而是我在多个落地项目里总结的分层法。官方文档按组件组织,分层法更适合做架构决策:每一层都可以单独替换、单独测试、单独治理。
#mermaid-svg-WVqtvyx2qZl6lCrA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WVqtvyx2qZl6lCrA .error-icon{fill:#552222;}#mermaid-svg-WVqtvyx2qZl6lCrA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WVqtvyx2qZl6lCrA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WVqtvyx2qZl6lCrA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WVqtvyx2qZl6lCrA .marker.cross{stroke:#333333;}#mermaid-svg-WVqtvyx2qZl6lCrA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WVqtvyx2qZl6lCrA p{margin:0;}#mermaid-svg-WVqtvyx2qZl6lCrA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA .cluster-label text{fill:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA .cluster-label span{color:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA .cluster-label span p{background-color:transparent;}#mermaid-svg-WVqtvyx2qZl6lCrA .label text,#mermaid-svg-WVqtvyx2qZl6lCrA span{fill:#333;color:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA .node rect,#mermaid-svg-WVqtvyx2qZl6lCrA .node circle,#mermaid-svg-WVqtvyx2qZl6lCrA .node ellipse,#mermaid-svg-WVqtvyx2qZl6lCrA .node polygon,#mermaid-svg-WVqtvyx2qZl6lCrA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WVqtvyx2qZl6lCrA .rough-node .label text,#mermaid-svg-WVqtvyx2qZl6lCrA .node .label text,#mermaid-svg-WVqtvyx2qZl6lCrA .image-shape .label,#mermaid-svg-WVqtvyx2qZl6lCrA .icon-shape .label{text-anchor:middle;}#mermaid-svg-WVqtvyx2qZl6lCrA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WVqtvyx2qZl6lCrA .rough-node .label,#mermaid-svg-WVqtvyx2qZl6lCrA .node .label,#mermaid-svg-WVqtvyx2qZl6lCrA .image-shape .label,#mermaid-svg-WVqtvyx2qZl6lCrA .icon-shape .label{text-align:center;}#mermaid-svg-WVqtvyx2qZl6lCrA .node.clickable{cursor:pointer;}#mermaid-svg-WVqtvyx2qZl6lCrA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WVqtvyx2qZl6lCrA .arrowheadPath{fill:#333333;}#mermaid-svg-WVqtvyx2qZl6lCrA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WVqtvyx2qZl6lCrA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WVqtvyx2qZl6lCrA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WVqtvyx2qZl6lCrA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WVqtvyx2qZl6lCrA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WVqtvyx2qZl6lCrA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WVqtvyx2qZl6lCrA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WVqtvyx2qZl6lCrA .cluster text{fill:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA .cluster span{color:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WVqtvyx2qZl6lCrA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WVqtvyx2qZl6lCrA rect.text{fill:none;stroke-width:0;}#mermaid-svg-WVqtvyx2qZl6lCrA .icon-shape,#mermaid-svg-WVqtvyx2qZl6lCrA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WVqtvyx2qZl6lCrA .icon-shape p,#mermaid-svg-WVqtvyx2qZl6lCrA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WVqtvyx2qZl6lCrA .icon-shape rect,#mermaid-svg-WVqtvyx2qZl6lCrA .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WVqtvyx2qZl6lCrA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WVqtvyx2qZl6lCrA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WVqtvyx2qZl6lCrA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-WVqtvyx2qZl6lCrA .agent>*{fill:#2A1F3D!important;stroke:#A78BFA!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .agent span{fill:#2A1F3D!important;stroke:#A78BFA!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .agent tspan{fill:#E8EEF9!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .service>*{fill:#111A2E!important;stroke:#4F8CFF!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .service span{fill:#111A2E!important;stroke:#4F8CFF!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .service tspan{fill:#E8EEF9!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .store>*{fill:#0F2A1D!important;stroke:#22C55E!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .store span{fill:#0F2A1D!important;stroke:#22C55E!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .store tspan{fill:#E8EEF9!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .model>*{fill:#2A1F0B!important;stroke:#F5A524!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .model span{fill:#2A1F0B!important;stroke:#F5A524!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-WVqtvyx2qZl6lCrA .model tspan{fill:#E8EEF9!important;} AiServices / AgenticServices

L6 编排层
Prompt 模板

  • 输出解析

L2
ChatMemory

  • ChatMemoryStore

L3
ContentRetriever

  • EmbeddingStore

L4
@Tool

  • ToolExecutor

L5
ChatModel + EmbeddingModel

  • DecisionModel

L1

图 1:LangChain4j 的六层抽象。箭头表示装配/调用关系,不表示唯一的数据流向。

层 核心接口/类 解决什么 不解决什么
L1 模型 ChatModel、StreamingChatModel、EmbeddingModel、ImageModel、DecisionModel 统一不同厂商的模型调用 模型能力差异、成本、稳定性
L2 提示与 IO @SystemMessage、@UserMessage、@V、PromptTemplate、结构化输出 输入格式化、输出解析 Prompt 质量、注入防护
L3 记忆 ChatMemory、ChatMemoryStore、ChatMemoryProvider 多轮上下文 长期知识、租户隔离
L4 检索 DocumentLoader、DocumentSplitter、EmbeddingStore、ContentRetriever、RetrievalAugmentor 外部知识注入 数据质量、检索评估
L5 工具 @Tool、@P、ToolSpecification、ToolExecutor 让模型调用外部能力 权限、幂等、审计
L6 编排 AiServices、AgenticServices、工作流、Supervisor 组件装配、多步编排 业务正确性、失败恢复

2.1 L1 模型层:模型是依赖,不是架构

ChatModel 负责同步对话,StreamingChatModel 负责流式;EmbeddingModel 负责向量化;ImageModel 负责图像;1.21 之后新增的 DecisionModel 负责"带概率的类型化判断"。

这一层最容易让人产生"框架就是 SDK"的错觉。实际上,模型只是六层中的一层。换模型不应该影响记忆、检索和工具。

生产关注:模型路由、超时、重试、降级、Token 成本计量。

2.2 L2 提示与 IO 层:Prompt 是代码,不是配置

@SystemMessage、@UserMessage、@V 是声明式入口;PromptTemplate 是底层模板;结构化输出由框架的输出解析器负责。

很多团队把 Prompt 写在数据库或配置中心,改起来很方便,但没有版本、没有测试、没有灰度。上线后一次"优化 Prompt"就可能让结构化输出解析失败。

生产关注:Prompt 版本控制、注入防护、输出校验、回归测试。

2.3 L3 记忆层:记忆是有状态数据

ChatMemory 管消息窗口,ChatMemoryStore 管持久化,ChatMemoryProvider 按 @MemoryId 隔离会话。

官方文档特别提醒:同一个 @MemoryId 的 AI Service 不应并发调用 ,否则可能损坏 ChatMemory;框架目前不负责加锁。这是生产必须自己补的约束。

生产关注:租户隔离、Redis 持久化、Token 预算、并发控制、过期清理。

2.4 L4 检索层:RAG 的上限由数据管线决定

RAG 的主链路是:

text 复制代码
DocumentLoader → DocumentSplitter → EmbeddingModel → EmbeddingStore
→ ContentRetriever → RetrievalAugmentor → Prompt

EmbeddingStoreIngestor 把摄取管线串起来;EmbeddingStoreContentRetriever 提供 naive RAG;DefaultRetrievalAugmentor 支持 Query 改写、路由、聚合、注入,适合高级 RAG。

一个常见误区是"召回不准就换向量库"。在真实项目里,分块、元数据、混合检索、重排带来的收益,通常远大于换一个向量库。

生产关注:分块策略、元数据 Schema、混合检索、Rerank、评估集。

2.5 L5 工具层:工具是对外 API,不是普通方法

@Tool 描述工具,@P 描述参数,ToolExecutor 负责执行;底层还有 ToolSpecification。

工具一旦交给模型,就意味着模型可以触发真实副作用:查订单、发退款、重启服务。它必须有权限边界、幂等设计、超时、审计,必要时还要人工审批。

生产关注:白名单、参数校验、并行调用、失败回传、审批与审计。

2.6 L6 编排层:复杂度转移,不是复杂度消失

AiServices 是单服务装配器;AgenticServices 提供顺序、并行、循环、监督等工作流原语;@Agent 定义子代理。

这一层让代码看起来更少,但状态、失败恢复、成本控制变得更难。能用确定性代码解决的,不要交给 Agent。

生产关注:状态机、超时、重试、人工介入、成本上限。

2.7 故障与层的映射

现象 根因层 典型修复 对应篇目
记忆串号 L3 按 tenant/user 设计 memoryId 与 store key A04
答非所问 L4 分块、混合检索、重排、评估 A07--A11
工具越权 L5 权限矩阵、审批、幂等、审计 A06、A14
账单失控 L1/L6 路由、缓存、预算、级联 A13、A18
无法定位 全链路 Listener、Trace、指标 A13

2.8 六层的替换成本

层 变更频率 替换成本 主要风险 建议
L1 模型 高 低 能力与价格波动 用统一 Provider 隔离
L2 Prompt 高 低 输出回归 版本化 + 回归集
L3 记忆 中 中 串号、Token 成本 统一 memoryId 规范
L4 检索 中 高 索引重建、召回下降 先评估再换
L5 工具 低 高 权限、真实副作用 权限矩阵 + 审批
L6 编排 低 高 状态、失败恢复 先确定性,后 Agent

表中为经验判断,不是绝对结论;团队规模、合规要求与存量系统会显著改变替换成本。


3. 1.23 到底变了什么?

先看版本线。LangChain4j 的迭代节奏很快,单看 1.23 容易误判,放到时间线上才清楚。

版本 关键变化 对架构的影响
1.19 MCP 传输收敛到 Streamable HTTP;混合检索实现增多 MCP 接入方式变化,RAG 融合能力增强
1.20 返回类型驱动执行:CompletableFuture、Flow.Publisher、TokenStream 流式与异步不再依赖额外适配器
1.21 DecisionModel / DecisionServices 分类、路由、门控可以用低成本模型
1.22 OpenAiDecisionModel、Anthropic Prompt Caching TTL 等 决策模型跨厂商,缓存成为降本手段
1.23 OllamaDecisionModel、Confidence Cascade、AiServiceInvocationSummaryEvent、测试增强、MCP 服务端文档 本地决策、级联降本、可观测与测试补强

3.1 决策模型:从"生成文本"到"回答类型化问题"

DecisionModel 不生成文本,而是回答带名称的类型化问题,并返回概率。典型问题包括:

  • 这条工单该给哪个团队?(Choice)
  • 这条消息需要今天处理吗?(Yes/No)
  • 用户情绪有多强烈?(Scale)

1.23 新增 OllamaDecisionModel,意味着决策模型可以跑在本地;同时引入 Confidence Cascade 模式:先让便宜的小模型判断,置信度不足再升级到大模型。

这类能力的价值在"热路径":每个请求都要做的分类、路由、门控。用大模型做这些事,既慢又贵。

DecisionModel 与整个 langchain4j-agentic 模块目前都标注为实验性,生产使用要锁定版本,并准备回退方案。

3.2 可观测性:把一次调用的所有事件串起来

1.23 引入 AiServiceInvocationSummaryEvent,把一次 AI Service 调用产生的所有事件按 invocationId 聚合。配合 Micrometer 的 chat 调用耗时指标,可以回答一个关键问题:

这次回答慢,是检索慢、模型慢、工具慢,还是网络慢?

没有这层聚合,线上只能看到"总耗时",无法归因。

3.3 测试:不打真实模型,也能测行为

langchain4j-test 在 1.23 增强了 LLM Judge,并支持对出站 ChatRequest 做断言:Prompt 是否包含关键指令、工具是否注册、记忆是否被带上。

这意味着大部分回归测试不需要调用真实模型,成本和稳定性都可控。

3.4 MCP:Streamable HTTP 成为主线

MCP 传输在 1.19 收敛到 Streamable HTTP;1.23 补上了服务端文档。对 Java 团队的影响是:

  • 新接入不要再基于 SSE 设计;
  • 工具服务端要考虑无状态、鉴权、超时与审计;
  • MCP 适合把"工具"从应用内解耦成可复用服务,但不等于可以跳过权限设计。

4. LangChain4j vs Spring AI:怎么选?

先说结论:不是二选一。

Spring AI 2.x 绑定 Spring Boot 4.x,优势是 Spring 生态整合;LangChain4j 框架无关,优势是抽象细粒度与 Agent 编排。两者可以共存:Spring Boot 做工程骨架,LangChain4j 做复杂 RAG/Agent 管线。

4.1 能力对比

维度 Spring AI 2.x LangChain4j 1.23 判断
框架绑定 Spring 强绑定 框架无关 已有 Spring 团队,Spring AI 集成成本更低
声明式 API ChatClient + Advisors AiServices 动态代理 LangChain4j 更接近"服务层"
对话记忆 内置 ChatMemory ChatMemory + ChatMemoryStore 两者都能做,LangChain4j 存储扩展更灵活
RAG 粒度 VectorStore + Advisors Retriever / RetrievalAugmentor 复杂 RAG 选 LangChain4j
工具调用 @Tool @Tool + ToolExecutor 平手
Agent 编排 Advisors 组合 Agentic 工作流(实验性) 多 Agent 选 LangChain4j,但注意实验性
可观测性 Micrometer / OTel Listener / Micrometer 两者都能做,取决于接入深度
测试 通用测试 + 少量 AI 工具 langchain4j-test LangChain4j 更完整
国内模型 Spring AI Alibaba 等 社区模块丰富 看具体模型与维护状态

以上为基于公开文档的定性对比,不是性能 Benchmark;能力判断会随版本变化,选型前以目标版本为准。

4.2 选型决策树

#mermaid-svg-RdHkWNm27CYdkKLB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RdHkWNm27CYdkKLB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RdHkWNm27CYdkKLB .error-icon{fill:#552222;}#mermaid-svg-RdHkWNm27CYdkKLB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RdHkWNm27CYdkKLB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RdHkWNm27CYdkKLB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RdHkWNm27CYdkKLB .marker.cross{stroke:#333333;}#mermaid-svg-RdHkWNm27CYdkKLB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RdHkWNm27CYdkKLB p{margin:0;}#mermaid-svg-RdHkWNm27CYdkKLB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RdHkWNm27CYdkKLB .cluster-label text{fill:#333;}#mermaid-svg-RdHkWNm27CYdkKLB .cluster-label span{color:#333;}#mermaid-svg-RdHkWNm27CYdkKLB .cluster-label span p{background-color:transparent;}#mermaid-svg-RdHkWNm27CYdkKLB .label text,#mermaid-svg-RdHkWNm27CYdkKLB span{fill:#333;color:#333;}#mermaid-svg-RdHkWNm27CYdkKLB .node rect,#mermaid-svg-RdHkWNm27CYdkKLB .node circle,#mermaid-svg-RdHkWNm27CYdkKLB .node ellipse,#mermaid-svg-RdHkWNm27CYdkKLB .node polygon,#mermaid-svg-RdHkWNm27CYdkKLB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RdHkWNm27CYdkKLB .rough-node .label text,#mermaid-svg-RdHkWNm27CYdkKLB .node .label text,#mermaid-svg-RdHkWNm27CYdkKLB .image-shape .label,#mermaid-svg-RdHkWNm27CYdkKLB .icon-shape .label{text-anchor:middle;}#mermaid-svg-RdHkWNm27CYdkKLB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RdHkWNm27CYdkKLB .rough-node .label,#mermaid-svg-RdHkWNm27CYdkKLB .node .label,#mermaid-svg-RdHkWNm27CYdkKLB .image-shape .label,#mermaid-svg-RdHkWNm27CYdkKLB .icon-shape .label{text-align:center;}#mermaid-svg-RdHkWNm27CYdkKLB .node.clickable{cursor:pointer;}#mermaid-svg-RdHkWNm27CYdkKLB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RdHkWNm27CYdkKLB .arrowheadPath{fill:#333333;}#mermaid-svg-RdHkWNm27CYdkKLB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RdHkWNm27CYdkKLB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RdHkWNm27CYdkKLB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RdHkWNm27CYdkKLB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RdHkWNm27CYdkKLB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RdHkWNm27CYdkKLB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RdHkWNm27CYdkKLB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RdHkWNm27CYdkKLB .cluster text{fill:#333;}#mermaid-svg-RdHkWNm27CYdkKLB .cluster span{color:#333;}#mermaid-svg-RdHkWNm27CYdkKLB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RdHkWNm27CYdkKLB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RdHkWNm27CYdkKLB rect.text{fill:none;stroke-width:0;}#mermaid-svg-RdHkWNm27CYdkKLB .icon-shape,#mermaid-svg-RdHkWNm27CYdkKLB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RdHkWNm27CYdkKLB .icon-shape p,#mermaid-svg-RdHkWNm27CYdkKLB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RdHkWNm27CYdkKLB .icon-shape rect,#mermaid-svg-RdHkWNm27CYdkKLB .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RdHkWNm27CYdkKLB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RdHkWNm27CYdkKLB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RdHkWNm27CYdkKLB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-RdHkWNm27CYdkKLB .q>*{fill:#111A2E!important;stroke:#4F8CFF!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-RdHkWNm27CYdkKLB .q span{fill:#111A2E!important;stroke:#4F8CFF!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-RdHkWNm27CYdkKLB .q tspan{fill:#E8EEF9!important;}#mermaid-svg-RdHkWNm27CYdkKLB .lc>*{fill:#2A1F3D!important;stroke:#A78BFA!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-RdHkWNm27CYdkKLB .lc span{fill:#2A1F3D!important;stroke:#A78BFA!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-RdHkWNm27CYdkKLB .lc tspan{fill:#E8EEF9!important;}#mermaid-svg-RdHkWNm27CYdkKLB .sa>*{fill:#0F2A1D!important;stroke:#22C55E!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-RdHkWNm27CYdkKLB .sa span{fill:#0F2A1D!important;stroke:#22C55E!important;color:#E8EEF9!important;stroke-width:2px!important;}#mermaid-svg-RdHkWNm27CYdkKLB .sa tspan{fill:#E8EEF9!important;} 是
否
是
否
是
否
新项目 / 重构?
已深度使用

Spring 生态?
需要复杂 RAG

或 Agent 编排?
需要跨框架复用?
LangChain4j 编排

Spring AI 接入
Spring AI 2.x
LangChain4j
两者都可

按团队熟悉度选

图 2:选型决策树。先看团队约束,再看框架能力。

4.3 三个典型场景

场景 A:Spring Boot 为主,业务只需要模型调用 + 简单 RAG。

选 Spring AI。少一层抽象,团队学习成本低,和 Spring Security、Actuator、Micrometer 的整合更顺。

场景 B:需要复杂 RAG 管线、工具编排、多 Agent 工作流。

选 LangChain4j。RetrievalAugmentor、AiServices、AgenticServices 的可组合性更强。

场景 C:多框架、多模型、需要源码级定制。

选 LangChain4j。core 不绑定框架,替换模型与存储的代价更低。


5. 一条最小但完整的调用链

下面这段代码把 L1--L6 串起来:模型、Embedding、记忆、RAG、工具、AiServices。

示例使用 InMemoryEmbeddingStore,目的是复制即可运行;生产环境替换为 PgVector/Elasticsearch,记忆替换为 Redis 持久化。完整工程骨架见 A02。

java 复制代码
// LangChain4j 1.23.0 | JDK 21
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;

public class ProductionCallChain {

    public interface SupportAssistant {
        @SystemMessage("""
                你是企业客服助手。回答必须基于检索到的资料和工具结果。
                如果资料不足,直接说明"需要人工确认",不要编造。
                """)
        String chat(@MemoryId String conversationId,
                    @UserMessage String question);
    }

    public static class OrderTools {
        @Tool("查询订单状态。只读操作,不会修改订单。")
        public String queryOrderStatus(@P("订单号,例如 SO-2026-0001") String orderId) {
            return switch (orderId) {
                case "SO-2026-0001" -> "已发货,预计 2026-11-07 送达";
                default -> "未找到订单:" + orderId;
            };
        }
    }

    public static void main(String[] args) {
        // L1:模型与 Embedding
        ChatModel chatModel = OpenAiChatModel.builder()
                .baseUrl("https://api.deepseek.com/v1")
                .apiKey(System.getenv("DEEPSEEK_API_KEY"))
                .modelName("deepseek-chat")
                .temperature(0.2)
                .build();

        // 也可替换为本地 Embedding 模型;这里用 DashScope 兼容接口演示
        EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .modelName("text-embedding-v3")
                .build();
        // 注意:Embedding 维度必须与向量库表结构一致,换模型要重建索引

        // L4:摄取与检索(示例用内存存储)
        EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
        EmbeddingStoreIngestor.builder()
                .documentSplitter(DocumentSplitters.recursive(500, 80))
                .embeddingModel(embeddingModel)
                .embeddingStore(store)
                .build()
                .ingest(Document.from("""
                        退货政策:签收后 7 天内可无理由退货,商品需保持完好。
                        运费规则:质量问题由商家承担运费,非质量问题由买家承担。
                        """));

        ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(store)
                .embeddingModel(embeddingModel)
                .maxResults(4)
                .minScore(0.65)
                .build();

        // L6:装配 L2/L3/L4/L5
        SupportAssistant assistant = AiServices.builder(SupportAssistant.class)
                .chatModel(chatModel)
                .chatMemoryProvider(id -> MessageWindowChatMemory.withMaxMessages(20))
                .contentRetriever(retriever)
                .tools(new OrderTools())
                .build();

        String answer = assistant.chat(
                "user-42",
                "订单 SO-2026-0001 到哪了?顺便说下退货政策。");
        System.out.println(answer);
    }
}

90 行代码里,真正体现六层装配的只有 AiServices.builder(...) 这 6 行;其余是模型、Embedding、示例数据与工具。框架的价值是让这 6 行可替换、可治理,而不是让代码变短。

5.1 一次请求发生了什么

ChatModel OrderTools ContentRetriever ChatMemory SupportAssistant 用户 ChatModel OrderTools ContentRetriever ChatMemory SupportAssistant 用户 #mermaid-svg-fDsl4FkvIrSjmrQK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fDsl4FkvIrSjmrQK .error-icon{fill:#552222;}#mermaid-svg-fDsl4FkvIrSjmrQK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fDsl4FkvIrSjmrQK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fDsl4FkvIrSjmrQK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fDsl4FkvIrSjmrQK .marker.cross{stroke:#333333;}#mermaid-svg-fDsl4FkvIrSjmrQK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fDsl4FkvIrSjmrQK p{margin:0;}#mermaid-svg-fDsl4FkvIrSjmrQK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fDsl4FkvIrSjmrQK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fDsl4FkvIrSjmrQK .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-fDsl4FkvIrSjmrQK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-fDsl4FkvIrSjmrQK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-fDsl4FkvIrSjmrQK .sequenceNumber{fill:white;}#mermaid-svg-fDsl4FkvIrSjmrQK #sequencenumber{fill:#333;}#mermaid-svg-fDsl4FkvIrSjmrQK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-fDsl4FkvIrSjmrQK .messageText{fill:#333;stroke:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fDsl4FkvIrSjmrQK .labelText,#mermaid-svg-fDsl4FkvIrSjmrQK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .loopText,#mermaid-svg-fDsl4FkvIrSjmrQK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fDsl4FkvIrSjmrQK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-fDsl4FkvIrSjmrQK .noteText,#mermaid-svg-fDsl4FkvIrSjmrQK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-fDsl4FkvIrSjmrQK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fDsl4FkvIrSjmrQK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fDsl4FkvIrSjmrQK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fDsl4FkvIrSjmrQK .actorPopupMenu{position:absolute;}#mermaid-svg-fDsl4FkvIrSjmrQK .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-fDsl4FkvIrSjmrQK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fDsl4FkvIrSjmrQK .actor-man circle,#mermaid-svg-fDsl4FkvIrSjmrQK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-fDsl4FkvIrSjmrQK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} chat("user-42", "订单到哪了?") 1 读取 user-42 历史 2 检索退货政策 3 Top-4 文档 4 System + 历史 + 文档 + 问题 5 请求调用 queryOrderStatus 6 执行只读工具 7 订单状态 8 回填工具结果 9 最终回答 10 写入本轮消息 11 回答 12

图 3:一次带 RAG 与工具调用的请求生命周期。

5.2 这段代码对应六层

代码位置 对应层 说明
OpenAiChatModel / OpenAiEmbeddingModel L1 模型与 Embedding 接入
@SystemMessage / @UserMessage L2 提示模板
MessageWindowChatMemory / @MemoryId L3 按会话隔离的记忆
EmbeddingStoreIngestor / ContentRetriever L4 摄取与检索
@Tool / OrderTools L5 只读工具
AiServices.builder(...) L6 装配与编排

5.3 这段代码故意省略了什么

这不是一份可以直接上生产的完整实现,以下约束需要后续篇目补齐:

  • 记忆持久化与多租户隔离:A04;
  • 流式输出、取消、背压:A05;
  • 工具权限、幂等、审批:A06、A14;
  • 混合检索、Rerank、评估:A09--A11;
  • 可观测性与成本治理:A13;
  • 测试与护栏:A14、A15。

6. 五个常见误区

误区 1:把 AiServices 当黑盒

AiServices 不是魔法,它是"动态代理 + 上下文装配 + 输出解析"。不理解装配顺序,遇到"工具不触发""结构化输出失败"只能猜。

纠正:先理解 L2--L5 如何被织入,再使用声明式接口。A03 会拆源码。

误区 2:所有问题都上 RAG

RAG 适合"答案在文档里"的问题;结构化查询、实时状态、计算类问题,应该用工具或 SQL。

纠正:先做问题分类,再决定检索、工具还是直接生成。

误区 3:记忆就是保存全部历史

全量历史会带来三个问题:Token 成本、噪声干扰、串号风险。

纠正:窗口、摘要、检索式记忆按场景组合;记忆是有状态数据,要隔离、要过期、要审计。

误区 4:工具就是给方法加 @Tool

工具是模型可以触发的真实副作用,必须有权限、幂等、超时、审计,高风险操作还要人工审批。

纠正:把工具当 API 设计,而不是当方法暴露。

误区 5:选型只看 GitHub Star

Star 数不代表生产可用性。要看版本节奏、Beta 模块稳定性、团队生态、可观测与测试能力。

纠正:用约束清单做选型:团队技术栈、上线时间、定制深度、运维能力、合规要求。


7. 适用边界

适合 LangChain4j 的场景:

  • Java 团队需要把 LLM 能力嵌入现有服务;
  • 需要 RAG、工具调用、多步编排;
  • 需要跨框架、多模型、可替换抽象;
  • 需要源码级定制与可观测性。

不适合的场景:

  • 只调用一次模型、无状态、无 RAG/工具需求;
  • 团队完全绑定 Spring,且只需要简单 ChatClient;
  • 需要开箱即用的托管平台,而不是自建;
  • 对实验性 API 零容忍(应避开 Agentic/DecisionModel,或锁定版本)。

8. FAQ

LangChain4j 和 Python LangChain 是同一个东西吗?

不是。两者同名,但 LangChain4j 是独立的 Java 实现,不是逐 API 移植。不要把 Python LangChain 的教程直接套到 Java 代码上。

1.23 可以上生产吗?Beta 模块能用吗?

core 1.23.0 是 GA;langchain4j-mcp、langchain4j-agentic 等 Beta 模块按独立节奏发布,部分 API 标注实验性。生产使用要锁定版本、做兼容性测试、准备回退方案。

必须用 Spring Boot 吗?

不必须。core 不依赖 Spring;Spring Boot Starter 只是集成层。Quarkus、Micronaut、Helidon 或普通 Java 项目都可以用。

国内模型怎么接?

两种方式:一是使用厂商的 OpenAI 兼容接口(如 DeepSeek、DashScope);二是使用社区模块。注意不同模型的 Embedding 维度、上下文长度、工具调用能力不同,要做适配与回归测试。

AiServices 有性能损耗吗?

有,主要是动态代理、Prompt 组装、输出解析的开销;从调用链看,这部分通常远小于模型调用本身。真正的性能瓶颈通常在模型、网络、检索和线程模型,而不是 AiServices。

"六层抽象"是官方定义吗?

不是。这是我为架构决策总结的分层法,官方文档按组件组织。它的价值是帮助团队定位问题与划分职责,不是替代官方文档。

学习顺序建议?

先 L1--L3(模型、Prompt、记忆),再 L4(RAG),然后 L5(工具),最后 L6(编排)。每一层都要配一个可运行示例,不要只看不写。


9. 速查表

层 关键接口 一句话 对应篇目
L1 模型 ChatModel / EmbeddingModel / DecisionModel 统一模型调用,不统一模型能力 A01、A18
L2 提示与 IO @SystemMessage / @UserMessage / PromptTemplate Prompt 是代码,要版本化 A03
L3 记忆 ChatMemory / ChatMemoryStore 记忆是有状态数据,要隔离 A04
L4 检索 ContentRetriever / RetrievalAugmentor RAG 上限由数据管线决定 A07--A11
L5 工具 @Tool / ToolExecutor 工具是 API,不是普通方法 A06、A14
L6 编排 AiServices / AgenticServices 复杂度转移,不是消失 A03、A17

10. 系列导航

  • 下一篇:A02《LangChain4j 生产级工程骨架:12 个模块 + Docker 一键启动》------把本文的六层落成一个可运行仓库。
  • 全系列:《LangChain4j 生产级实战》20 篇路线图(专栏内查看)。

参考资料


相关推荐
聪明的笨猪猪1 小时前
实际工程问题:AI生成Redis分布式锁的原子性缺陷导致库存超卖
java·经验分享·面试·ai编程
软件技术NINI2 小时前
基于SpringBoot和Vue的新能源汽车销售推荐系统
java·vue.js·spring boot·后端·汽车·毕业设计·毕设
GISer_Jing2 小时前
Agent相关岗位时收集的各类技术面试题
后端·ai·langchain
武雄(小星Ai)2 小时前
Ollama报llama-server binary not found排坑实录:服务活着引擎没了
人工智能·windows·大模型·ollama·排坑
Flynn Liang2 小时前
LangChain4j 生产级工程骨架:12 个模块 + Docker 一键启动
java·spring boot·langchain·rag·langchain4j
叼烟扛炮2 小时前
[LangChain] 学习笔记(08):工具调用底层闭环与第三方搜索(Tavily)实战
人工智能·笔记·学习·langchain
噢,我明白了3 小时前
JAVA中的一些基础应用知识点
java·开发语言
GISer_Jing4 小时前
AI Agent秋招面试万字通关指南|架构、ReAct、上下文工程、RAG、评测、生产运维全解
后端·ai·langchain
SL_staff4 小时前
私有化低代码不是妥协,而是企业级数字化的自主可控主航道
java