LangChain4j 基础实践 -- 简易ai助手
该博客根据 鱼皮 程序员的langchain4j教程来创作,相关代码以及放在 github,前端代码由codex生成,后端代码参考了鱼皮 的教程
一、引言:为什么是 LangChain4j?
在企业后端、服务端开发领域,Java 的占有率极高,但以往 LLM 能力主要集中在 Python。
LangChain4j 的出现让 Java 开发者能够:
- 用熟悉的方式调用大模型
- 通过 Java 接口定义智能 Agent(AI Service)
- 轻松扩展工具、记忆、检索等能力
- 支持本地模型、云端模型、私有化模型
这意味着:AI 能力可以无缝融入你的现有 Java 业务系统。
二、准备工作:引入依赖与基础环境
本文将会使用国产大模型 Qwen 为例,先添加langchain4j依赖,以及相关网络检索库jsoup:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
<version>1.1.0-beta7</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.1.0-beta7</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.20.1</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>
<version>1.1.0-beta7</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.1.0-beta7</version>
</dependency>
在配置文件yml中配置你的百炼大模型的api 和 model-name,springboot会自动注入bean对象
langchain4j:
community:
dashscope:
chat-model:
model-name: qwen-max
api-key: <your api key>
streaming-chat-model:
model-name: qwen-max
api-key: <Your Api Key>
embedding-model:
api-key: <your api key>
model-name: text-embedding-v4
三、ChatModel:最基础的大模型调用方式
ChatModel 是最核心的模型接口,任何模型都可以通过它调用。传入UserMessage后可以直接调用chatModel.chat(UserMessage)获取大模型的返回结果。
需要配置好api key等信息后才能正确返回
@Service
@Slf4j
public class AiCodeHelper {
@Resource
private ChatModel qwenChatModel;
public void chat(String message) {
UserMessage userMessage = UserMessage.from(message);
ChatResponse chatResponse = qwenChatModel.chat(userMessage);
AiMessage aiMessage = chatResponse.aiMessage();
log.info("AI 输出:" + aiMessage.toString());
}
public void chatWithImage(String message, String imageUrl) {
UserMessage userMessage = UserMessage.from(
TextContent.from(message),
ImageContent.from(imageUrl)
);
ChatResponse chatResponse = qwenChatModel.chat(userMessage);
AiMessage aiMessage = chatResponse.aiMessage();
log.info("AI 输出:" + aiMessage.toString());
}
}
四、AiService:让你像写 Java 接口一样使用 AI
LangChain4j 最大的创新之一就是 AI Service 机制。
你可以像调用普通 Service 一样与大模型对话。使用@AiService注解会自动生成bean对象,注入类中。
使用该注解相当简单方便,适合快速开发,但是不够自由,我们更多时候会使用工厂模型进行注入。
@AiService
public interface AiCodeHelperService {
String chat(String userMessage);
}
大模型会自动解析参数 → 生成 prompt → 输出结果。
AI Service 本质上是“智能代理”的接口定义方式,非常适合企业项目结构化集成。
五、AiServiceFactory:可扩展、可注入的智能代理构造器
当你需要更多自定义能力时,例如,你想使用对话记忆功能,RAG等,就需要用到工厂模式。
示例:
@Configuration
public class AiCodeHelperServiceFactory {
@Resource
private ChatModel qwenChatModel;
@Bean
public AiCodeHelperService aiCodeHelperService(McpToolProvider mcpToolProvider){
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
return AiServices.builder(AiCodeHelperService.class)
.chatModel(myQwenChatModel)
.build();
}
}
这类似于 Spring Bean 的“组合模式”,可自由扩展 AI Agent 的能力。
六、chat():灵活构造对话的底层调用
如果 AiService 不够灵活,可以直接构造多轮消息:
ChatResponse response = model.chat(
ChatMessage.userMessage("你是谁?")
);
System.out.println(response.text());
对于:
- 多轮上下文
- 系统角色(system)注入
- 工具调用
- 自定义 prompt 模板
使用 chat() 会更加自由。
七、ChatMemory:让模型具备对话记忆能力
大模型默认不记住上下文,ChatMemory 用来保存对话历史。
7.1 内存实现
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
7.2 与 AiService 配合使用
@Bean
public AiCodeHelperService aiCodeHelperService(McpToolProvider mcpToolProvider){
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
return AiServices.builder(AiCodeHelperService.class)
.chatModel(myQwenChatModel)
.chatMemory(chatMemory) // 会话记忆功能
.build();
多轮对话示例:
String chat = aiCodeHelperService.chat("你好,我是程序员零食");
System.out.println(chat);
chat = aiCodeHelperService.chat("我是谁来着");
System.out.println(chat);
// → 大模型会回答:你是程序员零食
ChatMemory 让 AI 具备“会话上下文认知能力”。
八、RAG:LangChain4j 最常用的知识库增强能力
RAG(Retrieval-Augmented Generation)流程:
- 文档加载
- 文本切分
- 生成 embedding
- 存入向量数据库
- 检索相关内容
- 增强大模型回答

8.1 代码示例
我将相关数据放在resource目录下,下面是一个简易版基于内存的RAG
如果你想使用RAG功能,你就要在配置文件中配置embeding模型相关的apikey
- 注入向量模型和向量存储器
- 加载文档,对文档进行切割,可以按照段落、token等方式进行切割
- 使用文档加载器加载文档
- 定义内容查询器,使用哪一个模型,需要几个检索结果等
package com.lbk.aicodehelper.ai.rag;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.splitter.DocumentByParagraphSplitter;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* 加载RAG
*/
@Configuration
public class RagConfig {
// 向量模型
@Resource
private EmbeddingModel qwenEmbeddingModel;
// 向量储存器
@Resource
private EmbeddingStore<TextSegment> embeddingStore;
@Bean
public ContentRetriever contentRetriever() {
// ------ RAG ------
// 1. 加载文档
List<Document> documents = FileSystemDocumentLoader.loadDocuments("src/main/resources/docs");
// 2. 文档切割:将每个文档按每段进行分割,最大 1000 字符,每次重叠最多 200 个字符
DocumentByParagraphSplitter paragraphSplitter = new DocumentByParagraphSplitter(1000, 200);
// 3. 自定义文档加载器
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(paragraphSplitter)
// 为了提高搜索质量,为每个 TextSegment 添加文档名称
.textSegmentTransformer(textSegment -> TextSegment.from(
textSegment.metadata().getString("file_name") + "\n" + textSegment.text(),
textSegment.metadata()
))
// 使用指定的向量模型
.embeddingModel(qwenEmbeddingModel)
.embeddingStore(embeddingStore)
.build();
// 加载文档
ingestor.ingest(documents);
// 4. 自定义内容查询器
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(qwenEmbeddingModel)
.maxResults(5) // 最多 5 个检索结果
.minScore(0.75) // 过滤掉分数小于 0.75 的结果
.build();
}
}
在 AiService 中使用
public AiCodeHelperService aiCodeHelperService(McpToolProvider mcpToolProvider){
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
return AiServices.builder(AiCodeHelperService.class)
.chatModel(myQwenChatModel)
.chatMemory(chatMemory) // 会话记忆功能
.contentRetriever(contentRetriever) // RAG 检索增强生成
.build();
现在 assistant 的回答将具备文档知识。
九、Tool:让大模型可以“调用 Java 方法”
Tool 是 LLM 的 function calling 机制,让大模型执行代码。

9.1 定义一个工具
package com.lbk.aicodehelper.ai.tools;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class InterviewQuestionTool {
/**
* 从面试鸭网站获取关键词相关的面试题列表
*
* @param keyword 搜索关键词(如"redis"、"java多线程")
* @return 面试题列表,若失败则返回错误信息
*/
@Tool(name = "interviewQuestionSearch", value = """
Retrieves relevant interview questions from mianshiya.com based on a keyword.
Use this tool when the user asks for interview questions about specific technologies,
programming concepts, or job-related topics. The input should be a clear search term.
"""
)
public String searchInterviewQuestions(@P(value = "the keyword to search") String keyword) {
List<String> questions = new ArrayList<>();
// 构建搜索URL(编码关键词以支持中文)
String encodedKeyword = URLEncoder.encode(keyword, StandardCharsets.UTF_8);
String url = "https://www.mianshiya.com/search/all?searchText=" + encodedKeyword;
// 发送请求并解析页面
Document doc;
try {
doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0")
.timeout(5000)
.get();
} catch (IOException e) {
log.error("get web error", e);
return e.getMessage();
}
// 提取面试题
Elements questionElements = doc.select(".ant-table-cell > a");
questionElements.forEach(el -> questions.add(el.text().trim()));
return String.join("\n", questions);
}
}
9.2 注入工具
@Bean
public AiCodeHelperService aiCodeHelperService(McpToolProvider mcpToolProvider){
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
return AiServices.builder(AiCodeHelperService.class)
.chatModel(myQwenChatModel)
.chatMemory(chatMemory) // 会话记忆功能
.contentRetriever(contentRetriever) // RAG 检索增强生成
.tools(new InterviewQuestionTool())
.build();
}
现在你问:
给我一些计算机网络的面试题
→ 模型会自动调用 searchInterviewQuestions("计算机网络")
Tool 是打造 智能 Agent 的核心能力。
十、MCP 协议
(模型上下文协议)是一种开放协议,旨在实现 大型语言模型(LLM) 应用与外部数据源、工具和服务之间的无缝集成,类似于网络中的 HTTP 协议或邮件中的 SMTP 协议。
MCP 协议通过标准化模型与外部资源的交互方式,提升 LLM 应用的功能性、灵活性和可扩展性。

LangChain4j 可以作为 MCP 客户端,让你的程序连接各种 MCP Server。
这种能力让模型能真正执行任务、使用真实数据。
随着 OpenAI、Anthropic、DeepSeek 等统一 MCP 标准,这部分能力未来会极其重要。
代码示例
在这里我使用zhipu 提供的 web search 为例
- 首先前往质谱开放平台获取apikey,添加到你的配置文件中
bigmodel:
api-key: <Your Api Key>
- 根据质谱mcp文档说明,建立mcp客户端连接
- 获取工具后注入到aiservice中,这样你的大模型就有了调用mcp的能力
package com.lbk.aicodehelper.ai.mcp;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class McpConfig {
@Value("${bigmodel.api-key}")
private String apiKey;
@Bean
public McpToolProvider mcpToolProvider() {
// 和 MCP 服务通讯
McpTransport transport = new HttpMcpTransport.Builder()
.sseUrl("https://open.bigmodel.cn/api/mcp/web_search/sse?Authorization=" + apiKey)
.logRequests(true) // 开启日志,查看更多信息
.logResponses(true)
.build();
// 创建 MCP 客户端
McpClient mcpClient = new DefaultMcpClient.Builder()
.key("yupiMcpClient")
.transport(transport)
.build();
// 从 MCP 客户端获取工具
McpToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(mcpClient)
.build();
return toolProvider;
}
}
注入到AiService中
@Bean
public AiCodeHelperService aiCodeHelperService(McpToolProvider mcpToolProvider){
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
return AiServices.builder(AiCodeHelperService.class)
.chatModel(myQwenChatModel)
.chatMemory(chatMemory) // 会话记忆功能
.contentRetriever(contentRetriever) // RAG 检索增强生成
.tools(new InterviewQuestionTool())
.toolProvider(mcpToolProvider) // mcp
.build();
}
十一、Guardrail:内容安全与输出结构化控制
Guardrail相当于一个登陆拦截器,在调用大模型之前,检测用户信息是否有敏感词信息;在调用大模型之后,还会检测模型的输出是否有敏感信息
Guardrail 用于:
- 过滤危险内容
- 控制输出格式
- 校验结构化 JSON
- 防止越狱

示例:
一个简单的敏感词检测,当用户的输入信息有kill, evil时直接拦截,不调用大模型
package com.lbk.aicodehelper.ai.guardrail;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.guardrail.InputGuardrail;
import dev.langchain4j.guardrail.InputGuardrailResult;
import java.util.Set;
/**
* 输入安全词检测护轨
*/
public class SafeInputGuardrail implements InputGuardrail {
private static final Set<String> sensitiveWords = Set.of("kill", "evil");
/**
* 检测用户输入是否安全
*/
@Override
public InputGuardrailResult validate(UserMessage userMessage) {
// 获取用户输入并转换为小写以确保大小写不敏感
String inputText = userMessage.singleText().toLowerCase();
// 使用正则表达式分割输入文本为单词
String[] words = inputText.split("\\W+");
// 遍历所有单词,检查是否存在敏感词
for (String word : words) {
if (sensitiveWords.contains(word)) {
return fatal("Sensitive word detected: " + word);
}
}
return success();
}
}
结合 AiService:添加@InputGuardrails 即可添加输入护轨
@InputGuardrails({SafeInputGuardrail.class})
public interface AiCodeHelperService {
// 在 resources 目录下新建文件 system-prompt.txt 来存储系统提示词
@SystemMessage(fromResource = "system-prompt.txt")
String chat(String userMessage);
}
保证输出不包含敏感词
十二、Listener:监听 Prompt / Token / 调用过程
Listener 能监听模型生命周期事件:
package com.lbk.aicodehelper.ai.listener;
import dev.langchain4j.model.chat.listener.ChatModelErrorContext;
import dev.langchain4j.model.chat.listener.ChatModelListener;
import dev.langchain4j.model.chat.listener.ChatModelRequestContext;
import dev.langchain4j.model.chat.listener.ChatModelResponseContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class ChatModelListenerConfig {
@Bean
public ChatModelListener chatModelListener() {
return new ChatModelListener() {
@Override
public void onRequest(ChatModelRequestContext requestContext) {
log.info("onRequest(): {}", requestContext.chatRequest());
}
@Override
public void onResponse(ChatModelResponseContext responseContext) {
log.info("onResponse(): {}", responseContext.chatResponse());
}
@Override
public void onError(ChatModelErrorContext errorContext) {
log.info("onError(): {}", errorContext.error().getMessage());
}
};
}
}
;
新建一个qwen模型配置,可以设置listeners
@Configuration
@ConfigurationProperties(prefix = "langchain4j.community.dashscope.chat-model")
@Data
public class QwenChatModelConfig {
private String modelName;
private String apiKey;
@Resource
private ChatModelListener chatModelListener;
@Bean
public ChatModel myQwenChatModel() {
return QwenChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.listeners(List.of(chatModelListener))
.build();
}
}
用途:
- 打印 prompt(调试)
- 记录 token 消耗
- 性能监控
- 链路追踪
在企业应用中特别重要。
十三、SSE 流式输出:前端实时显示生成内容
大模型的最终体验通常需要流式输出。
LangChain4j 支持 Token 级别 stream:
@GetMapping("/chat")
public Flux<ServerSentEvent<String>> chat(int memoryId, String message) {
return aiCodeHelperService.chatStream(memoryId, message)
.map(chunk -> ServerSentEvent.<String>builder()
.data(chunk)
.build());
}
streaming-chat-model:
model-name: qwen-max
api-key: <Your Api Key>
@Resource
private StreamingChatModel qwenStreamingChatModel;
@Bean
public AiCodeHelperService aiCodeHelperService(McpToolProvider mcpToolProvider){
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(10).build();
return AiServices.builder(AiCodeHelperService.class)
.chatModel(myQwenChatModel)
.streamingChatModel(qwenStreamingChatModel) // 流式模型
.chatMemory(chatMemory) // 会话记忆功能
.chatMemoryProvider(MemoryId -> MessageWindowChatMemory.withMaxMessages(10))
.contentRetriever(contentRetriever) // RAG 检索增强生成
.tools(new InterviewQuestionTool())
.toolProvider(mcpToolProvider)
.build();
}
要在配置文件中配置流式模型,同时在AiService中设置
集成 Spring Boot:
- 后端使用
Flux推送 SSE - 前端实时接收并展示 token
这就是大模型常用的“流式对话体验”。
十四、总结:LangChain4j 让 Java 成为 AI 应用的主力军
本文从基础能力到高级特性,逐条介绍了 LangChain4j 的核心功能:
- ChatModel —— 基本模型调用
- AiService —— 结构化智能代理
- AiServiceFactory —— 可扩展的智能服务工厂
- chat() —— 底层自由度极高的自定义调用
- ChatMemory —— 让对话具备记忆能力
- RAG —— 构建知识库增强系统
- Tool —— 让大模型调用 Java 代码
- MCP —— 未来标准的智能扩展协议
- Guardrail —— 安全与结构化保障
- Listener —— 链路可观测性
- SSE —— 流式输出
这几乎覆盖了构建智能应用所需的全部能力。
未来你可以继续研究:
- 多 Agent 协作系统
- 更复杂的 Tool 与工作流
- 文档知识库 RAG 的大规模部署
- 与 Spring Cloud / 微服务集成
更多推荐


所有评论(0)