从源码到实战:LangChain4j 1.14 完整学习指南(14 课全解)

LangChain4j 是什么?

一句话:Java 生态的 LLM 应用开发框架

核心设计理念是声明式抽象------你只定义接口,框架用 JDK 动态代理生成实现,把 LLM 调用、工具编排、记忆管理、RAG 检索等复杂性全部封装在底层。

架构分层

四层架构,职责分明:

  • core 层 :纯接口,零依赖,Provider 只需实现 doChat() 一个方法
  • 框架层:AiServices 动态代理 + 工具执行循环 + RAG 管线
  • Provider 层:15+ 模型提供商,统一接口即插即用
  • agentic 层:多 Agent 编排(实验中)

核心设计模式

模式 体现 源码位置
动态代理 AiServices 通过 Proxy.newProxyInstance() 生成接口实现 DefaultAiServices.java:108
Builder 模式 几乎所有组件都用 Builder 构建 全项目
SPI(ServiceLoader) JSON 编解码、Prompt 模板、Embedding 工厂可替换 全项目
策略模式 RAG 管线每一步都是可替换接口 langchain4j
观察者模式 ChatModelListener、AiServiceListener 监听全生命周期 langchain4j-core

学习路线总览

markdown 复制代码
阶段一「基础」        阶段二「增强」         阶段三「进阶」            阶段四「工程化」
ChatModel             ChatMemory            StructuredOutputs        Observability
  ↓                     ↓                     ↓                       ↓
AI Services           Tools                 RAG                      Logging+Params
                        ↓                     ↓                       ↓
                      Streaming             Classification          Testing
                                              ↓                       ↓
                                            Guardrails              MCP → SpringBoot

阶段一:入门基础

第一课:ChatModel --- 和 LLM 的第一次对话

源码模块langchain4j-core(接口)+ langchain4j-open-ai(实现)

ChatModel 是最底层的 LLM 调用接口------把消息发出去,把响应拿回来。所有 Provider 实现同一个接口,换模型不需要改业务代码。

java 复制代码
ChatModel model = OpenAiChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("gpt-4o-mini")
    .build();

// 最简调用
String answer = model.chat("你好");

// 多轮对话(手动管理历史)
UserMessage msg1 = UserMessage.from("我叫小明");
AiMessage ai1 = model.chat(msg1).aiMessage();
UserMessage msg2 = UserMessage.from("我叫什么?");
ChatResponse resp2 = model.chat(msg1, ai1, msg2);  // → "小明"

接口设计的精妙之处 :所有方法都是 default,Provider 唯一需要实现的只有 doChat()

java 复制代码
default ChatResponse chat(ChatRequest chatRequest) {
    listeners.forEach(l -> l.onRequest(...));
    ChatResponse response = doChat(chatRequest);  // Provider 实现
    listeners.forEach(l -> l.onResponse(...));
    return response;
}

五种消息类型构成了完整的对话模型:

arduino 复制代码
ChatMessage
├── SystemMessage      --- 系统指令(角色定义、行为约束)
├── UserMessage        --- 用户输入(支持多模态:文本/图片/音频/视频/PDF)
├── AiMessage          --- AI 响应(text + toolExecutionRequests)
├── ToolExecutionResultMessage --- 工具执行结果
└── CustomMessage      --- 自定义

第二课:AI Services --- 声明式接口,框架帮你干一切

源码模块langchain4j(核心实现)

第一课直接用 ChatModel 调 LLM,所有事都要手动管理。AI Services 翻转了这个模式------你定义接口,框架生成实现

java 复制代码
// 1. 定义接口
interface Assistant {
    @SystemMessage("你是一个友好的助手,回答简洁")
    String chat(String message);
}

// 2. 框架生成实现(JDK 动态代理)
Assistant assistant = AiServices.create(Assistant.class, model);

// 3. 像调普通方法一样
String answer = assistant.chat("什么是 Java?");

模板变量替换:

java 复制代码
interface Translator {
    @UserMessage("将以下文本翻译为{{targetLang}}:{{it}}")
    String translate(@V("targetLang") String lang, String text);
}

translator.translate("中文", "Hello World");  // → "你好世界"

一次 AI Service 调用的 12 步内部流程

scss 复制代码
用户调用 assistant.chat("你好")
  → Proxy 拦截 → DefaultAiServices.invoke()
    → 1. 解析 @SystemMessage → SystemMessage
    → 2. 解析 @UserMessage + {{it}} → UserMessage
    → 3. RAG 增强(contentRetriever)
    → 4. Input Guardrails 检查
    → 5. JsonSchema 自动生成(结构化输出)
    → 6. 格式指令追加到 prompt(降级路径)
    → 7. ChatMemory 管理(取历史、加新消息)
    → 8. 构建 ChatRequest → ChatModel.doChat()
    → 9. Tool 执行循环(finishReason==TOOL_EXECUTION → 调工具 → 再请求)
    → 10. Output Guardrails 检查
    → 11. ServiceOutputParser 解析输出 → 返回类型
    → 12. Result<T> 包装
  → 返回结果给用户

何时用 ChatModel,何时用 AI Services? 简单场景用 ChatModel,涉及模板/记忆/工具/RAG 时用 AI Services。


阶段二:核心增强

第三课:Chat Memory --- 让 LLM 有了记忆

源码模块langchain4j-core + langchain4j

LLM 是无状态的------每次请求都需传入完整对话历史。Chat Memory 把这个过程自动化:框架自动存储对话历史,每次请求前自动注入

java 复制代码
Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model)
    .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
    .build();

assistant.chat("我叫小明");  // 框架自动记住
assistant.chat("我叫什么?"); // → "小明"(框架自动注入历史)

多用户隔离(@MemoryId):

java 复制代码
interface MultiUserAssistant {
    String chat(@MemoryId String userId, @UserMessage String message);
}

assistant.chat("user-1", "我叫小明");
assistant.chat("user-2", "我叫小红");
assistant.chat("user-1", "我叫什么?"); // → "小明"
assistant.chat("user-2", "我叫什么?"); // → "小红"

两种淘汰策略:

  • MessageWindowChatMemory:按消息数量淘汰
  • TokenWindowChatMemory:按 Token 数量淘汰(更精确)

💡 设计细节 :SystemMessage 默认不会被淘汰。ToolExecutionResultMessage 成为孤儿时自动移除。多用户隔离底层用 ConcurrentHashMap<Object, ChatMemory> + computeIfAbsent 懒加载。

第四课:Tools --- 让 LLM 能「动手」

源码模块langchain4j-core(@Tool 注解)+ langchain4j(ToolService)

前三课的 LLM 只能「说」,不能「做」。Tools 让 LLM 能调用你的 Java 方法------查数据库、调 API、做计算。LLM 自主决定是否调用、调用哪个、传什么参数。

java 复制代码
class MathTools {
    @Tool("计算两个数的和")
    double add(@P("第一个数") double a, @P("第二个数") double b) {
        return a + b;
    }

    @Tool("计算平方根")
    double squareRoot(@P("要求平方根的数") double x) {
        return Math.sqrt(x);
    }
}

Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model)
    .tools(new MathTools())
    .build();

assistant.chat("3的平方根加上5乘以7等于多少?");
// LLM 自主编排: squareRoot(3) → multiply(5,7) → 加和 → 输出

高阶用法 --- AI Service 作为工具(Router Agent 模式)

java 复制代码
interface LegalExpert {
    @Tool("法律专家,回答法律问题") String askLegal(String question);
}
interface TechExpert {
    @Tool("技术专家,回答技术问题") String askTech(String question);
}

RouterAgent router = AiServices.builder(RouterAgent.class)
    .chatModel(model)
    .tools(legalExpert, techExpert)  // AI Service 作为工具!
    .build();

工具调用循环:

  1. 发送请求 → LLM 返回 finishReason=TOOL_EXECUTION + ToolExecutionRequests
  2. DefaultToolExecutor 执行对应 Java 方法
  3. 将结果追加到消息列表
  4. 再次发送请求 → 如果还是 TOOL_EXECUTION,回到步骤 2
  5. 直到 finishReason=STOP → 返回最终回答

第五课:Response Streaming --- 逐字呈现

源码模块langchain4j-core(StreamingChatModel)+ langchain4j(TokenStream)

前面的调用都是同步的------等完整响应返回后才能处理。Streaming 让 LLM 逐 token 推送,用户体验大幅提升。

高层 API(推荐,链式调用):

java 复制代码
interface StreamingAssistant {
    TokenStream chat(String message);
}

StreamingAssistant assistant = AiServices.create(StreamingAssistant.class, streamingModel);

assistant.chat("解释什么是流式响应")
    .onPartialResponse(token -> System.out.print(token))
    .onCompleteResponse(response -> System.out.println("\n[完成]"))
    .onError(Throwable::printStackTrace)
    .start();  // 必须调用 start()

💡 避坑TokenStreamdev.langchain4j.service 包,不在 dev.langchain4j.model 包,导入时容易出错。


阶段三:进阶能力

第六课:Structured Outputs --- 从字符串到对象

源码模块langchain4j-core(JsonSchema)+ langchain4j(ServiceOutputParser)

前面 LLM 输出都是 String,业务代码需要手动解析。Structured Outputs 让 AI Service 直接返回 POJO / Enum / 基本类型

java 复制代码
record Person(String name, int age, double height, boolean married) {}

interface PersonExtractor {
    Person extractPersonFrom(String text);
}

PersonExtractor extractor = AiServices.create(PersonExtractor.class, model);
Person p = extractor.extractPersonFrom("John is 42 years old, 1.75m tall, unmarried.");
// → Person[name=John, age=42, height=1.75, married=false]

框架的智能降级机制

javascript 复制代码
if (模型支持 RESPONSE_FORMAT_JSON_SCHEMA && 非流式 && 非图片)
    → 自动生成 JsonSchema → 注入 ChatRequest.responseFormat
    → LLM 被 API 级约束输出合法 JSON → 解析返回

if (模型不支持 JSON Schema || schema 生成失败)
    → 生成文本格式指令 → 追加到 UserMessage 末尾
    → LLM 靠文本指令理解格式 → 从输出中提取并解析 JSON

💡 避坑 :POJO 所有字段默认可选------LLM 缺少信息时容易幻觉填充。用 @JsonProperty(required = true) 标记必填字段。

第七课:RAG --- 让 LLM 读你的知识库

源码模块langchain4j-core + langchain4j + langchain4j-embeddings-all-minilm-l6-v2-q

LLM 的知识截止于训练日期。RAG 让 LLM 在回答前先从你的知识库中检索相关信息,注入 prompt 后再回答。

完整流程(Naive RAG):

java 复制代码
// 1. 加载并切分文档
List<Document> docs = List.of(
    Document.from("LangChain4j 是 Java 的 LLM 应用开发框架..."),
    Document.from("RAG 全称 Retrieval-Augmented Generation...")
);
var splitter = DocumentSplitters.recursive(200, 20);
List<TextSegment> segments = splitter.splitAll(docs);

// 2. Embedding + 存入向量库
EmbeddingModel embModel = new AllMiniLmL6V2QuantizedEmbeddingModel();
InMemoryEmbeddingStore<TextSegment> embStore = new InMemoryEmbeddingStore<>();
embStore.addAll(embModel.embedAll(segments).content(), segments);

// 3. 创建检索器并绑定到 AI Service
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
    .embeddingStore(embStore).embeddingModel(embModel)
    .maxResults(3).minScore(0.5)
    .build();

Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model).contentRetriever(retriever)
    .build();

assistant.chat("What is LangChain4j?");      // 基于知识库精确回答
assistant.chat("Who won the 2025 World Cup?"); // 诚实说不知道

两阶段架构:

  • 索引阶段(离线):文档 → 解析 → 切分 → 向量化 → 存储
  • 检索阶段(在线,AI Service 自动完成):提问 → embed → 搜索 → Top-K → 注入 prompt

AllMiniLmL6V2QuantizedEmbeddingModel 是进程内 Embedding 模型(384 维,23MB ONNX),无需调用远程 API。

第八课:Classification --- 文本分类利器

源码模块langchain4j(EnumOutputParser)

很多时候不需要完整文本回答,只需要一个分类标签------情感正负、优先级高低、意图类别。

java 复制代码
enum Sentiment { POSITIVE, NEUTRAL, NEGATIVE }
enum Priority { LOW, MEDIUM, HIGH, CRITICAL }
enum Intent { QUESTION, COMPLAINT, FEATURE_REQUEST, BUG_REPORT, GREETING }

interface SentimentAnalyzer {
    @UserMessage("Analyze sentiment of {{it}}")
    Sentiment analyzeSentimentOf(String text);
}

实战用例------客服工单自动分流:

yaml 复制代码
用户消息:"支付页面一直转圈,试了三次都付不了款!"
  → Intent: COMPLAINT, Priority: CRITICAL, Sentiment: NEGATIVE
  → 自动路由: 推送值班群 + 分配投诉专员 + 发优惠券安抚

第九课:Guardrails --- 输入输出的安全防护栏

源码模块langchain4j-core + langchain4j

LLM 越强大,风险越大。Guardrails 在调用前后做验证,确保输入安全、输出合规。

输入护栏(注入检测 + 敏感词过滤):

java 复制代码
public class PromptInjectionGuardrail implements InputGuardrail {
    @Override
    public InputGuardrailResult validate(UserMessage userMessage) {
        if (userMessage.singleText().contains("ignore previous instructions"))
            return fatal("Prompt injection detected");
        return success();
    }
}

输出护栏(竞品检测):

java 复制代码
public class CompetitorMentionGuardrail implements OutputGuardrail {
    @Override
    public OutputGuardrailResult validate(AiMessage responseFromLLM) {
        if (responseFromLLM.text().contains("CompetitorX"))
            return failure("Mentions competitor");
        return success();
    }
}

注册方式(注解声明式):

java 复制代码
interface Assistant {
    @InputGuardrails({PromptInjectionGuardrail.class, ProfanityFilterGuardrail.class})
    @OutputGuardrails({CompetitorMentionGuardrail.class})
    String chat(String message);
}

四种护栏结果

  • success → 继续
  • successWith → 改写消息后继续
  • failure → 记录失败,继续执行收集所有失败
  • fatal → 立即终止,不调 LLM
  • 输出护栏额外支持 retry(重新调 LLM)和 reprompt(换 prompt 重试)

阶段四:工程化

第十课:Observability --- 透视每一次 AI 调用

源码模块langchain4j-core + langchain4j

通过事件监听让你透视 AI Service 调用的完整生命周期。

java 复制代码
Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model)
    .registerListener(new AiServiceCompletedListener() {
        @Override
        public void onEvent(AiServiceCompletedEvent event) {
            System.out.println("[DONE] " + event.invocationContext().methodName()
                + " → " + event.result().orElse("(void)"));
        }
    })
    .build();

一次调用的完整事件序列:

scss 复制代码
AiServiceStartedEvent
  └─ AiServiceRequestIssuedEvent(可能多次,有工具/guardrails 时)
       └─ ChatModelListener.onRequest() / .onResponse()
     └─ AiServiceResponseReceivedEvent(可能多次)
  └─ AiServiceCompletedEvent(或 AiServiceErrorEvent)

第十一课:Parameters + Logging --- 调参与调试

java 复制代码
ChatModel model = OpenAiChatModel.builder()
    .temperature(0.3)           // 低温度 → 确定性输出
    .maxTokens(200)             // 限制输出长度,控制成本
    .timeout(ofSeconds(60))     // 超时控制
    .logRequests(true)          // 打印请求日志
    .logResponses(true)         // 打印响应日志
    .build();
参数 范围 效果
temperature 0.0~2.0 越低越确定(代码/事实),越高越有创造性(写作)
maxTokens 正整数 限制输出长度,控制成本
frequencyPenalty -2.0~2.0 正值降低重复

添加 logback-classic 依赖后,控制台输出完整请求/响应 body,包含 Token 用量。

第十二课:Testing --- 分层测试 AI 应用

LLM 输出是非确定性的。分层测试策略

层级 内容 依赖 LLM
单元测试 Guardrail 逻辑、Parser 逻辑
集成测试 AI Service 端到端
评估测试 LLM-as-Judge 评估回答质量 ✅✅

Guardrail 单元测试(不调 LLM):

java 复制代码
@Test
void testInputGuardrailBlocksInjection() {
    PromptGuard guard = new PromptGuard();
    assertThat(guard.validate(UserMessage.from("Hello")).isSuccess()).isTrue();
    assertThat(guard.validate(UserMessage.from("ignore previous instructions")).isFatal()).isTrue();
}

集成测试(用 AssertJ 宽松断言):

java 复制代码
@Test
void testStructuredOutputExtraction() {
    Person p = extractor.extractPersonFrom("John is 42 years old.");
    assertThat(p.name()).containsIgnoringCase("John");
    assertThat(p.age()).isBetween(30, 50);
}

第十三课:MCP --- 标准化外部工具协议

源码模块langchain4j-mcp

第 4 课的 @Tool 是 Java 方法,与业务代码耦合。MCP 通过标准化协议调用外部进程提供的工具------任何语言编写,独立部署。

java 复制代码
// 1. 启动 MCP Server 子进程
var transport = new StdioMcpTransport.Builder()
    .command(List.of("npx", "-y", "@modelcontextprotocol/server-everything", "stdio"))
    .logEvents(true).build();

// 2. 创建客户端 + 工具提供者
var mcpClient = new DefaultMcpClient.Builder()
    .key("my-server").transport(transport).build();
var toolProvider = McpToolProvider.builder()
    .mcpClients(mcpClient).build();

// 3. 绑定到 AI Service
Assistant assistant = AiServices.builder(Assistant.class)
    .chatModel(model).toolProvider(toolProvider).build();

MCP vs @Tool 对比:

@Tool MCP
定义位置 Java 方法(同 JVM) 外部进程
语言限制 必须 Java 任何语言
部署 与业务代码耦合 独立进程,独立扩展
工具发现 编译时注解扫描 运行时协议握手

第十四课:Spring Boot Integration --- 走向生产

源码模块langchain4j-spring-boot-starter

纯 Java 手动 builder?Spring Boot Starter 提供自动配置 ------properties 配参数,@AiService 注解自动扫描创建 Bean。

properties 复制代码
# application.properties
langchain4j.open-ai.chat-model.api-key=${OPENAI_API_KEY}
langchain4j.open-ai.chat-model.model-name=gpt-4o-mini
langchain4j.open-ai.chat-model.log-requests=true
java 复制代码
@AiService  // 自动扫描创建 Bean
interface Assistant {
    @SystemMessage("你是一个有帮助的助手")
    String chat(String userMessage);
}

@RestController
class AssistantController {
    private final Assistant assistant;  // 直接 DI 注入

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return assistant.chat(message);
    }
}

启动即可用:curl "http://localhost:8080/chat?message=Hello"


写在最后

LangChain4j 的设计哲学很 Java------用接口和注解声明意图,框架在底层把脏活累活干了。14 课学下来,从最基础的 ChatModel.chat() 到生产级的 Spring Boot 部署,覆盖了构建 LLM 应用需要的所有核心能力。

关键收获

  • AiServices 是整个框架的核心入口,动态代理 + 12 步自动流程
  • @Tool / MCP 让 LLM 从「只能说」变成「能做事」
  • RAG + Structured Outputs 让输出既准确又可用
  • Guardrails + Observability 让应用安全可观测

完整示例代码和学习笔记:GitHub - langchain4j-learning

相关推荐
老陈说编程2 小时前
12. LangChain 6大核心调用方法:invoke/stream/batch同步异步全解析,新手也能轻松学会
开发语言·人工智能·python·深度学习·机器学习·ai·langchain
网络工程小王4 小时前
【LangChain Output Parser 输出解析器】输出篇
人工智能·学习·langchain
Zfox_6 小时前
【LangChain】核心组件(上)
后端·langchain·ai编程
yanghuashuiyue6 小时前
Deep Agents 框架-开发部署
langchain·langgraph·deepagents
FrontAI6 小时前
深入浅出 LangGraph —— 第12章:多Agent系统架构
人工智能·langchain·ai agent·langgraph
狐狐生风6 小时前
LangChain实现简易版-----PDF 文档问答机器人
人工智能·langchain·机器人·pdf·prompt
测试员周周6 小时前
【AI测试系统】第5篇:AI 编码工具抛硬币?我们用 LangGraph 做了个“确定性+AI”的测试系统(附自愈架构)
人工智能·python·功能测试·测试工具·架构·langchain·单元测试
H_unique6 小时前
LangChain:创建工具Ⅰ
python·langchain
狐狐生风17 小时前
LangChain 向量存储:Chroma、FAISS
人工智能·python·学习·langchain·faiss·agentai