大家好,我是晚安code。
前两篇我们把对话跑通了、把 AiService 用起来了,感觉一切美好。可 demo 和上线之间隔着一整条河:模型不知道你公司的文档、不能操作你系统里的数据、还可能一本正经地乱说话。这篇 LangChain4j 实战就是把桥搭起来------RAG 知识库、工具调用、Guardrail 护轨、可观测性、SSE 流式输出,五个能力一次讲清。点个收藏,我们开始。
一、demo 到生产之间缺什么
跑通一个对话 demo,和生产上能用的 AI 应用,差的不是模型,是工程能力。我把缺的东西列成清单:
- 知识库:模型不知道你的私有文档,得用 RAG 喂给它
- 工具:模型不能操作数据、调服务,得用 Tool Calling 给它装手
- 护轨:模型可能被提示词攻击、吐敏感信息,得用 Guardrail 兜底
- 可观测性:一次调用花多少 token、是不是答非所问,得能看得到
- 流式服务化:完整回复要等十几秒,得用 SSE 让用户边等边看
五件事都围绕 AiService 一个入口装配------这也是为什么上一篇坚持先把 AiService 讲透。对一个 Java 服务来说,AI 能力最后都要落到「接口 + 配置」上,低层 API 手工拼是不利于上生产的。

二、RAG 知识库:让模型回答私有文档
RAG(Retrieval-Augmented Generation,检索增强生成):在让大模型回答前,先从你自己的知识库里检索出相关片段,连同问题一起喂给模型,让它基于这些材料回答。解决大模型不知道私有数据、又容易一本正经胡说八道的问题。
对私有知识,RAG 是成本最低也最该先上的一步------不用重新训练模型,改的是检索和提示词。LangChain4j 给了三档口味(示例按 1.17.x 编写,2026 年 8 月核对):
| 档位 | 适用 | 特点 |
|---|---|---|
| Easy RAG | 快速验证、demo | 引 langchain4j-easy-rag,切分/向量化/检索全默认 |
| Naive RAG | 标准场景 | 自己控切分、向量库、检索参数 |
| Advanced RAG | 复杂生产 | 查询改写、多源检索、重排序 |
标准姿势是「摄入 + 检索」两段。先摄入文档------加载、切分、向量化、存进向量库:
java
// 1. 加载文档(PDF/TXT/MD 都行)
Document document = FileSystemDocumentLoader.loadDocument(
"docs/产品手册.pdf", new ApachePdfBoxDocumentParser());
// 2. 切分:每块 300 token,重叠 50 token 保上下文连续
DocumentSplitter splitter = DocumentSplitters.recursive(300, 50);
// 3. 向量化 + 存进向量库
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor.builder()
.documentSplitter(splitter)
.embeddingModel(embeddingModel)
.embeddingStore(store)
.build()
.ingest(document);
检索时,把检索器接到 AiService 上,用户问什么就自动去知识库捞相关片段:
java
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.75) // 相似度低于 0.75 的不要
.build();
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(model)
.contentRetriever(retriever)
.build();
一张图看懂整条链路:

两个提醒:一是 InMemoryEmbeddingStore 只在 demo 用,生产换 pgvector、Milvus 这类持久化向量库;二是切分大小直接影响检索质量,块太大检索不准、块太小上下文割裂,300 token 起步,按文档特性调。
三、工具调用 Tool Calling:把 Java 方法变成模型的手
Tool Calling(工具调用):让大模型在回答时调用你准备好的 Java 方法。模型先「想清楚」需要什么参数,框架负责执行方法、把结果还给模型继续生成。相当于给 AI 装了一双手。
一个天气查询的例子,方法上标 @Tool,参数用 @P 写清含义:
java
public class WeatherTools {
@Tool("查询指定城市的天气")
String getWeather(@P("城市名,如 北京") String city) {
return "晴,26℃";
}
}
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(model)
.tools(new WeatherTools())
.build();
String answer = assistant.chat("北京明天适合穿什么?");
模型会自己判断「这个问题需要调用 getWeather」,生成带参数的调用,框架执行后把结果喂回去再生成最终回答。你完全不用管调用循环------工具方法的名称和 @Tool 描述,就是给模型看的说明书,写得越清楚,调用得越准。
有个坑要提前说:模型是自主决定调不调用、调哪个的,所以有副作用的操作(下单、改库、发消息)别直接给 @Tool,要么加人工确认,要么在方法里做权限校验。工具即入口,入口即攻击面。

四、Guardrail 护轨:守住输入输出边界
Guardrail(护轨):挂在 AI 服务输入和输出两侧的检查器,在请求发给模型前拦截,或在响应返回给用户前校验,不满足就拒绝或重试。相当于给 AI 装了个安全闸门。
先说清楚一件事:Guardrail 只在 AiService 层可用,低层 ChatModel 没有这个概念------这就是用 AiService 的又一条理由。
输入侧,拦截敏感信息、提示词注入:
java
public class PIIGuardrail implements InputGuardrail {
@Override
public GuardrailResult check(InputGuardrailContext context) {
if (context.userMessage().singleText().contains("身份证号")) {
return failure("检测到敏感信息,已拦截");
}
return success();
}
}
@InputGuardrails(PIIGuardrail.class)
public interface Assistant {
String chat(String userMessage);
}
输出侧,校验回复格式,不合格自动重试:
java
@OutputGuardrails(value = JsonOutputGuardrail.class, maxRetries = 3)
public interface Assistant {
String chat(String userMessage);
}
maxRetries = 3 的意思是:模型第一次输出没过关,框架自动让它重新生成,最多重试 3 次。官方还内置了 PatternBasedPromptInjectionGuardrail(拦提示词注入)、JsonExtractorOutputGuardrail(强制 JSON 结构)这类现成的护轨,能省不少事。护轨是生产上线的安全底裤,输入输出都要挂,别指望模型自律。
五、可观测性:看懂每次调用
模型调用本质也是接口调用,该有的日志、指标、链路追踪一样不能少。最低成本的起步,构建模型时打开请求/响应日志:
java
ChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.logRequests(true)
.logResponses(true)
.build();
要精细控制,用 ChatModelListener------它有三个回调,请求发出、响应回来、出错时各触发一次:
java
ChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.listeners(List.of(new ChatModelListener() {
@Override
public void onResponse(ChatModelResponseContext context) {
// 每次调用都记录 token 用量
System.out.println("本次调用 tokens: "
+ context.chatResponse().metadata().tokenUsage());
}
@Override
public void onError(ChatModelErrorContext context) {
System.err.println("模型调用失败: " + context.error().getMessage());
}
}))
.build();
要上指标面板,官方有 langchain4j-observation 模块,接 Micrometer------MicrometerMetricsChatModelListener 直接帮你把调用次数、token、耗时打进 Prometheus,Grafana 画图监控。再进阶接 Langfuse 这类可观测平台,做链路追踪。我的态度(示例场景):可观测性不是上线后补的,模型调用就是接口调用,第一天就该有日志和指标。
六、服务化:SSE 流式输出
一次性等完整回复,用户早就划走了。流式输出让模型一边生成一边吐,用户几乎秒看到第一个字。LangChain4j 用 StreamingChatModel + TokenStream 做这件事:
java
StreamingChatModel streamingModel = OpenAiStreamingChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.build();
streamingModel.chat("讲个笑话", new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String partial) {
System.out.print(partial); // 每个增量都回调
}
@Override
public void onCompleteResponse(ChatResponse response) {
System.out.println("\n[完成]");
}
@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});
在 AiService 里更简单,接口返回 TokenStream:
java
public interface Assistant {
TokenStream chat(String userMessage);
}
服务化这步,我用 Spring 的 SSE(Server-Sent Events)把流式响应推给前端------一次 HTTP 连接,服务端持续推送,比 WebSocket 简单太多,够用:
java
@RestController
public class ChatController {
private final Assistant assistant;
@GetMapping(path = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chat(@RequestParam String message) {
SseEmitter emitter = new SseEmitter();
executor.submit(() -> {
assistant.chat(message)
.onPartialResponse(partial -> safeSend(emitter, partial))
.onCompleteResponse(r -> emitter.complete())
.onError(e -> emitter.completeWithError(e))
.start();
});
return emitter;
}
}
整条链路的时序关系:

SSE 是 LLM 应用服务化的标配 ------请求到 /chat,前端收到一帧帧 data:,体验跟打字机一样。唯一要注意的是超时和断连重连,流式连接别让网关给掐了。
七、小结
这一篇 LangChain4j 实战把这五件事串完了:RAG 喂知识、Tool Calling 装手、Guardrail 守边界、可观测性看全局、SSE 做服务化,全部挂在 AiService 一个入口上。三篇下来,从 ChatModel 单点对话到能上生产的完整应用,这条路就算走通了。
最后给我的判断:LangChain4j 最值钱的地方,不是某个单一能力,而是这些能力在 AiService 上的一致性------学一遍,全通用。 以 2026 年中为准,它是 Java 生态里投入产出比最高的 AI 框架选择。
我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你上生产时,被 AI 哪块工程能力卡过最久?