LangChain4j 入门教学(Java 后端狂喜版

本篇目标 :从 Spring AI 切换到 LangChain4j,用"写 Java 接口"的方式驱动大模型------一个 @AiService 注解,让框架替你生成整个 AI 调用层。

前置知识:上面的 Spring AI 系列(概念全部打通,本篇随时做映射)


01 先破一个流传很广的误会

很多人一听 "LangChain4j" 就以为它是 Python LangChain 的 Java 翻译版。错。

💡 事实

LangChain4j 是从零构建的地道 Java 库:类型安全、POJO、注解、接口、流式 API------只是设计思想上借鉴了 LangChain 的"链式编排"理念。你不会看到一行 Python 味道的代码。

它对 Java 开发者的最大友好,是两级抽象

抽象层 是什么 适合谁
低层原语 ChatModelEmbeddingStore 等,自由度拉满 想精细控制每次调用的细节党
高层 AI Services 定义一个 Java 接口 + 注解,框架动态生成实现 想把"调 AI"写成"调本地方法"的效率党

低层是给 Spring AI 老手的亲切感,高层才是 LangChain4j 的招牌绝活。 本篇从低层玩到高层,最后给一张 Spring AI 概念映射表,让你无缝切换。


02 五分钟:第一声 Hello

不碰 Spring,纯 Java 先跑通------理解了裸用法,Spring 集成只是加糖

2.1 依赖

bash 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-bom</artifactId>
            <version>1.19.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
    </dependency>
    <!-- OpenAI 兼容接入(DeepSeek 直接用) -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
    </dependency>
</dependencies>

2.2 三行代码

bash 复制代码
ChatModel model = OpenAiChatModel.builder()
        .apiKey(System.getenv("OPENAI_API_KEY"))
        .baseUrl("https://api.deepseek.com/v1")   // OpenAI 兼容,一换就切厂商
        .modelName("deepseek-v4-flash")
        .build();

String answer = model.chat("用一句话解释什么是向量检索");
System.out.println(answer);

对,就是 model.chat(...)。没有 Client、没有 Prompt 对象、没有 Advisor------最原始的对话,一句话进一句话出

💡 与 Spring AI 对照

ChatModel.chat("...") ≈ Spring AI 的 ChatClient.prompt().user("...").call().content()。LangChain4j 把最常用路径压到了极限;需要复杂参数时,再用 chat(ChatRequest) 完整形态。


03 大杀器:AiServices------接口一写,AI 上岗

这是整篇文章的题眼。你只需要定义一个接口:

bash 复制代码
interface PetAssistant {

    @SystemMessage("""
            你是宠物医院的导诊助手,回答简洁专业。
            涉及用药时必须提醒:最终以兽医面诊为准。
            """)
    String chat(String userMessage);
}

然后让框架把它变成实现

bash 复制代码
PetAssistant assistant = AiServices.builder(PetAssistant.class)
        .chatModel(model)
        .build();

String reply = assistant.chat("猫咪吐了怎么办?");  // ← 像调本地方法一样调 AI

没有代理类、没有实现类,框架在运行时生成动态代理,你定义的每个方法 = 一种 AI 调用模板。整套原理一张图看懂:

3.1 参数模板:@UserMessage + @V

bash 复制代码
interface Translator {

    @SystemMessage("你是专业翻译")
    @UserMessage("把下面的文本翻译成{{lang}},只输出译文:\n{{text}}")
    String translate(@V("text") String text, @V("lang") String lang);
}

@V 把方法参数注入模板占位符------方法签名即 Prompt 契约,调用方完全无感。

3.2 结构化输出:返回值直接写 record

bash 复制代码
record PetSymptom(String species, String mainIssue, String urgency) {}

interface TriageService {

    @UserMessage("分析这段病情描述并输出结构化症状:{{text}}")
    PetSymptom triage(@V("text") String text);
}

PetSymptom symptom = triageService.triage("我家橘猫吐了 3 天,没精神");
symptom.urgency();   // "high",直接可路由可入库

方法的返回类型就是契约 ------想返回 StringrecordList<PetSymptom> 甚至枚举,框架自动处理 JSON Schema 生成与反序列化。还记得 Spring AI 里 .entity(PetSymptom.class) 那一行吗?这里它变成了方法签名本身

💡 类比

AiServices 之于大模型调用,就像 MyBatis Mapper 之于 SQL:你写接口 + 注解,框架生成实现。@SystemMessage@Select,返回 record 是自动结果映射------AI 调用被"Mapper 化"了


04 会话记忆:@MemoryId 一注解,多用户各聊各的

裸的 AI Service 是无状态的。加上记忆只需要两步:

bash 复制代码
interface PetAssistant {

    @SystemMessage("你是宠物医院导诊助手")
    String chat(@MemoryId String sessionId, @UserMessage String message);
}

PetAssistant assistant = AiServices.builder(PetAssistant.class)
        .chatModel(model)
        .chatMemory(MessageWindowChatMemory.withMaxMessages(20))  // 窗口记忆,默认在内存
        .build();

assistant.chat("session-A", "我家猫吐了");
assistant.chat("session-A", "需要禁食多久?");   // 记得上一句
assistant.chat("session-B", "有什么热门科室?"); // 与 A 完全隔离

核心就一个 @MemoryId同一个 id 共享一份记忆,不同 id 互不可见 。生产环境要持久化记忆时,换 ChatMemoryProvider 接上你的存储(Redis / DB),下篇进阶篇展开。

💡 与 Spring AI 对照

@MemoryId ≈ Spring AI 2.0 的 ChatMemory.CONVERSATION_ID 请求参数。LangChain4j 把它做成了方法参数,类型更硬、IDE 能跳转。


05 流式输出:TokenStream 三回调

把返回类型从 String 换成 TokenStream,就拿到打字机效果:

bash 复制代码
interface PetAssistant {
    @SystemMessage("你是宠物医生助手")
    TokenStream chat(String userMessage);
}

assistant.chat("讲讲猫咪肠炎护理")
        .onPartialResponse(token -> print(token))      // 每个 token 到达时
        .onCompleteResponse(resp -> save(resp))        // 完整响应(含 token 用量)
        .onError(err -> log.error("失败", err))
        .start();                                      // 触发执行

Spring 项目里更舒服 :加 langchain4j-reactor 模块,返回类型直接写 Flux<String>,SSE 接口一行串起来:

bash 复制代码
@AiService
interface PetAssistant {
    @SystemMessage("你是宠物医生助手")
    Flux<String> chat(String userMessage);
}

@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestParam String message) {
    return assistant.chat(message);
}

06 Spring Boot 集成:@AiService 注解版

回到你的主战场。LangChain4j 官方提供 Spring Boot starter

你的 Spring Boot 选哪个 starter
Boot 4.0+ langchain4j-open-ai-spring-boot4-starter
Boot 3.5+ langchain4j-open-ai-spring-boot-starter
声明式 AI Services 另加 langchain4j-spring-boot4-starter(SB4)/ langchain4j-spring-boot-starter(SB3)

两套 starter 并行发布、版本号一致,按 Boot 大版本选对后缀即可。

配置(键前缀是 langchain4j,不是 spring.ai):

bash 复制代码
langchain4j:
  open-ai:
    chat-model:
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.deepseek.com/v1
      model-name: deepseek-v4-flash
      log-requests: true      # 调试期打开,看真实报文
      log-responses: true

6.1 自动装配模式(默认)

bash 复制代码
@AiService
public interface PetAssistant {

    @SystemMessage("你是宠物医院的导诊助手")
    String chat(String userMessage);
}

启动时 starter 扫描所有 @AiService 接口,自动生成实现并注册为 bean,直接 @Autowired 就能用。上下文里这些组件会被自动接上ChatModelChatMemoryContentRetrieverRetrievalAugmentorToolProvider,以及所有 @Component 类里的 @Tool 方法------对,工具都自动挂上了。

⚠️ 唯一的坑 :同一类型组件存在多个 bean 时(比如两个 ChatModel),启动直接失败。这时切显式装配:

bash 复制代码
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
           chatModel = "openAiChatModel")     // 按 bean 名指定
interface OpenAiAssistant { ... }

@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
           chatModel = "ollamaChatModel")
interface OllamaAssistant { ... }

显式模式下所有组件都必须点名,适合多模型、多知识库的复杂项目。


07 一张表:从 Spring AI 迁移到 LangChain4j

给从阶段2 过来的你,概念一一对应:

概念 Spring AI 2.0 LangChain4j 1.19
底层模型接口 ChatModel(经 ChatClient 使用) ChatModel.chat(...)
门面/高层封装 ChatClient(链式 API) AiServices / @AiService(动态代理)
系统提示 .system("...") @SystemMessage
用户消息模板 PromptTemplate + .param() @UserMessage + @V
结构化输出 .entity(Class) 方法返回类型直接写 record
会话记忆 MessageChatMemoryAdvisor + CONVERSATION_ID chatMemory(...) + @MemoryId
工具调用 @Tool + .tools() @Tool@Component 自动拾取)
RAG QuestionAnswerAdvisor ContentRetriever / RetrievalAugmentor
流式 .stream()Flux<String> TokenStream / Flux<String>
配置前缀 spring.ai.* langchain4j.*
最低 JDK 21 17(存量项目友好)

一句话总结性格差异:Spring AI 是"Spring 全家桶原生的 AI 方言",LangChain4j 是"把 AI 调用 Mapper 化的独立军"。前者生态统一,后者抽象更激进、模型/向量库覆盖更广(还支持 Quarkus / Micronaut / 纯 Java)。


08 避坑清单

# 现象 解法
1 以为要 Java 21 存量 Java 17 项目不敢上 LangChain4j 最低 JDK 17;Spring AI 2.0 才要求 21
2 starter 后缀选错 Boot 4 项目引了 SB3 starter,自动装配失效 SB4 用 -spring-boot4-starter 后缀
3 上下文有两个 ChatModel bean 启动报错 @AiService(wiringMode = EXPLICIT, chatModel = "bean名")
4 DeepSeek 走 OpenAI 兼容忘了 /v1 404 / 鉴权怪错 baseUrl("https://api.deepseek.com/v1")
5 想当然找 ChatLanguageModel 类不存在 1.x 已统一为 ChatModelgenerate() 也改 chat()
6 @MemoryId 忘了加 所有人共享同一份记忆 多用户场景必须显式标注
7 集成模块版本混乱 BOM 管不到 beta 行为差异 集成模块以 1.19.0-beta29 这类号并行迭代,升级看 changelog
8 接口方法全是 String 返回 结构化能力没用上 返回值直接写 record / List / 枚举,框架自动转换

09 总结:你已经把 AI 调用"Mapper 化"了

本篇打穿的能力链:ChatModel 裸调用 → AiServices 动态代理 → @SystemMessage/@UserMessage 模板 → record 结构化返回 → @MemoryId 记忆 → TokenStream/Flux 流式 → @AiService Spring 自动装配。

下一篇进阶教学,把这个"Mapper"武装成全能选手@Tool 工具调用、RAG 三步走(Ingestor / ContentRetriever / RetrievalAugmentor),以及 LangChain4j 压轴的新东西------Agentic 模块(AgenticScope 共享状态、Supervisor 编排、Saga 式工具补偿),看看一个 Java 库怎么把 Agent 全家桶备齐。


若对你有帮助,点赞、推荐、分享

关注我,持续更新AI Agent学习内容,早日学会Agent开发!

相关推荐
数据库小学妹1 小时前
MySQL库存扣减实战:原子UPDATE、分桶方案与锁范围分析
数据库·后端·mysql
旺仔不是程序员1 小时前
LIMIT 1:PostgreSQL 只取一行的高效查询姿势
数据库·后端·sql
知守观1 小时前
Java POI 动态二级表头导出实战:并集计算 + 合并单元格 + 冻结列的完整实现
后端
Java_2017_csdn1 小时前
Java 8 Stream API 中的 map 和 flatMap 详解
java
知守观1 小时前
Snowflake 雪花算法实战:41位时间戳里的三个坑(时钟回拨、workerId、位运算)
后端
AI深栈1 小时前
第 15 章 · 第一个 AI 工作流:Hello Graph 从 START 跑到 END
java·人工智能
搜狐技术产品小编20231 小时前
解锁Kotlin Serialization高阶玩法:详解4种自定义序列化器与动态上下文策略
java·人工智能
花间相见2 小时前
【计算基础|网络04】—— HTTP接口实战(下):接口测试、鉴权与跨域排错
java·linux·人工智能·后端·python·计算机网络·postman