langchain4j是干嘛的?
它就是一个面向java生态的LLM应用开发框架,,他主要是为了让你能够快速接入模型,是一个开源社区维护的,他其中包括了提示词、上下文、多伦记忆、工具调用、RAG知识库、检索、结构化输出、流式输出等功能,让你写AI应用想写java业务代码一样,说白了就是封装了各种调用AI大模型的功能,让你方便开发,现在最新版本是1.10.0了,避免你用http到处去拼接请求。

截图是他们的官网,支持的大模型也是相当的多,但很多模型都兼容OPENAI的标准,为啥要兼容他?因为他是最早出来并且指定标准的,各大厂商为了方便开发中调用,基本都兼容了openAI的调用方式,比如国内的deepseek和阿里千问都支持这种调用。
langchain和langchain4j有什么关系
langchain是最早出来的东西,他主要是支持python语言和JavaScript语言,langchain4j是后面出来的,专门为java开发者设计的,然后langchain4j不是又出了和springboot集成吗,以及又出了springAI,说白了就是为了抢占市场,springboot正在做一系列努力,不然到时候大家都去用python了,没有人用java写代码了、
LlamaIndex主要是python为主,他和langchain又有区别,langchain属于比较全能,封装的接口功能很多,但LlamaIndex主要是偏向于RAG知识库,具体可以看下这篇文章,讲的很详细
https://blog.csdn.net/weixin_41046245/article/details/150060929
还有springAI上面也说了,就是为了springboot依赖者,快速去接入开发AI应用的
LangChain4j 代码示例
//需要导入的依赖
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>2.21.0</version>
</dependency>
<!-- ollama工具依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>1.10.0</version>
</dependency>
</dependencies>
LangChain4j 最简单的openAI模式调用
//OpenAI模型调用
@Test
void test01() {
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey("demo")
.modelName("gpt-4o-mini")
.build();
String answer = model.chat("你好,你是谁?");
System.out.println(answer);
}
//deepseek模型调用
@Test
void test02(){
OpenAiChatModel model = OpenAiChatModel.builder().baseUrl("https://api.deepseek.com")
.apiKey(System.getenv("DEEPSEEK_API_KEY"))
.modelName("deepseek-reasoner").build();
String answer = model.chat("你好,你是谁?");
System.out.println(answer);
}
//阿里千问模型调用
@Test
void test03(){
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("ALI_API_KEY"))
.modelName("qwen-plus").build();
String answer = model.chat("你好,你是谁?");
System.out.println(answer);
}
//阿里千问模型调用,上面是阿里兼容openai的调用方法,这个是阿里原生的,在阿里云百炼平台有示例,不是 OpenAI 兼容模式
// - 优点:完全按阿里原生能力走(有些高级能力/参数在这里更完整)。
// - 缺点:代码与供应商绑定更强,不如 OpenAI-compatible 通用。
@Test
void test04(){
try {
GenerationResult result = callWithMessage();
System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent());
// 如需查看完整响应,请取消下列注释
// System.out.println(JsonUtils.toJson(result));
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
System.err.println("错误信息:"+e.getMessage());
System.out.println("请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code");
}
}
public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException {
// 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:https://dashscope-intl.aliyuncs.com/api/v1
Generation gen = new Generation(Protocol.HTTP.getValue(), "https://dashscope.aliyuncs.com/api/v1");
Message systemMsg = Message.builder()
.role(Role.SYSTEM.getValue())
.content("You are a helpful assistant.")
.build();
// userMsg 就是用户问题(User message)
Message userMsg = Message.builder()
.role(Role.USER.getValue())
.content("65*889等于几")
.build();
GenerationParam param = GenerationParam.builder()
// 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apiKey("sk-xxx")
// 各地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
// 建议:学习阶段可以先写死;实战建议改成 System.getenv("DASHSCOPE_API_KEY")。
.apiKey(System.getenv("ALI_API_KEY"))
.model("qwen-plus")
.messages(Arrays.asList(systemMsg, userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.build();
return gen.call(param);
}
本地大模型调用
上面都是接入的几个别人家的大模型,但很多实际应用场景里面是需要自己部署开源大模型的,市面上的开源大模型很多,ollama是一个部署大模型的工具,官网是https://ollama.com/download。可以下载这个功能,然后直接部署大模型到本地,


ollama里面已经写好了各种命令,可以帮助你直接安装各种模型,不过一般自己电脑配置不行,就只能安装deepseek-r1 1.5b...不过这个模型是真的拉。部署完以后,就可以直接访问自己部署的模型了,不在需要apikey了
//Ollama(本地大模型服务)
@Test
void test05(){
OllamaChatModel model = OllamaChatModel.builder()
.baseUrl("http://localhost:11434")
//.apiKey("sk-1639b23a1d3148cb8912dcddf78f0bdc")
.modelName("deepseek-r1:1.5b").build();
String answer = model.chat("65*889等于几");//算这个就花了十几分钟,1.5b的模型就只能部署了玩玩
System.out.println(answer);
}
文生图模型
上面几个都是文生文的模型,也可以文生图等等,可以去各大官网去看看,下面这个代码是阿里的文生图的模型调用
//阿里千问官方示例
@Test
void test06(){
String prompt = "一个美女图片";
Map<String, Object> parameters = new HashMap<>();
parameters.put("prompt_extend", true);
parameters.put("watermark", false);
parameters.put("negative_prompt", " ");
ImageSynthesisParam param =
ImageSynthesisParam.builder()
.apiKey(System.getenv("ALI_API_KEY"))
// 当前仅qwen-image-plus、qwen-image模型支持异步接口
.model("qwen-image-plus")
.prompt(prompt)
.n(1)
.size("1664*928")
.parameters(parameters)
.build();
ImageSynthesis imageSynthesis = new ImageSynthesis();
ImageSynthesisResult result = null;
try {
System.out.println("---同步调用,请等待任务执行----");
result = imageSynthesis.call(param);
} catch (ApiException | NoApiKeyException e){
throw new RuntimeException(e.getMessage());
}
System.out.println(JsonUtils.toJson(result));
}
AiServices
在 LangChain4j 里,AiServices 可以理解成:把"调用大模型"封装成一个 Java 接口的实现(动态代理)。
主要是四个地方:
- Prompt/消息自动装配:SystemMessage 设定助手规则,UserMessage 标记用户输入
- 多轮记忆:MemoryId + chatMemoryProvider(...) 实现"会话隔离 + 记忆注入"
- 结构化输出:返回 POJO(比如你的 LessonPlan),框架帮你做映射(失败会抛异常)
- 流式输出:让模型的回答是一段段的,而不是直接返回所有结果
消息自动装配
interface QwenAssistant {
// @SystemMessage:给模型的"系统提示词"(System Prompt),用于设定角色/风格/规则。
// 这里固定为"严谨中文助手",让回答更稳定。
@SystemMessage("你是一个严谨的中文助手。")
// @UserMessage:标记这是用户输入。
// 不加也能用,但加上后在多参数、多组件场景更清晰。
String chat(@UserMessage String message);
}
@Test
void test07(){
ChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("ALI_API_KEY"))
.modelName("qwen-plus")
.build();
// AiServices.builder(QwenAssistant.class) 会创建一个实现了 QwenAssistant 的代理对象。
// 代理对象内部会把你的方法调用转换成一次(或多次)LLM 调用。
QwenAssistant assistant = AiServices.builder(QwenAssistant.class)
.chatModel(model)
.build();
System.out.println(assistant.chat("请你说一下以后AI的发展方向"));
}
带记忆的对话
上面的示例都是不带记忆的,他不知道你是谁,下次对话就记不住了
// 带记忆的 Assistant:
// - @MemoryId:用来区分"哪个用户/哪个会话"的对话历史。
// - MessageWindowChatMemory:一个最简单的内存实现,只保留最近 N 条消息。
// (生产中你可以换成 Redis/DB 持久化,或者自己实现 MemoryStore)
interface QwenAssistantWithMemory {
@SystemMessage("你是一个严谨的中文助手。")
String chat(@MemoryId String userId, @UserMessage String message);
}
// 示例 08:ChatMemory + MemoryId(多用户对话隔离)
// 知识点:ChatMemory(对话记忆)、MessageWindowChatMemory(窗口记忆)、@MemoryId(多会话隔离)
// 目标:让模型"记住上下文",并且不同 userId 之间互不串台。
// 运行预期:
// - u1 先说"我叫李雷",再问"我叫什么?"模型应回答"李雷"。
// - u2 没有说过名字,模型不应该知道。
// 你可以改动点:
// - withMaxMessages(20) 改大/改小,观察记忆窗口对效果的影响。
@Test
void test08(){
ChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("ALI_API_KEY"))
.modelName("qwen-plus")
.build();
// chatMemoryProvider:根据 MemoryId 动态创建/获取一个记忆对象。
// 这里演示最简单的:每个 userId 都用一个"窗口记忆"。
QwenAssistantWithMemory assistant = AiServices.builder(QwenAssistantWithMemory.class)
.chatModel(model)
.chatMemoryProvider(userId -> MessageWindowChatMemory.withMaxMessages(20))
.build();
System.out.println(assistant.chat("u1", "我叫李雷"));
System.out.println(assistant.chat("u1", "我叫什么?"));
System.out.println(assistant.chat("u2", "我叫什么?"));
}
结构化输出
static class LessonPlan {
// 结构化输出示例:
// LangChain4j 可以让模型把回答"映射"为一个 POJO。
// 注意:
// - 这依赖模型的"结构化输出/JSON 生成能力"。
// - 如果模型没按结构返回,可能会解析失败(抛异常)。
public String topic;
public int days;
public String[] tasks;
}
interface QwenStructuredAssistant {
@SystemMessage("你是一个教学规划助手。请严格返回结构化结果。")
LessonPlan plan(@UserMessage String request);
}
@Test
void test09(){
ChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("ALI_API_KEY"))
.modelName("qwen-plus")
.build();
QwenStructuredAssistant assistant = AiServices.builder(QwenStructuredAssistant.class)
.chatModel(model)
.build();
LessonPlan plan = assistant.plan("我想 7 天入门 LangChain4j,请给计划");
System.out.println(JsonUtils.toJson(plan));
}
流式输出
这里是TokenStream(边生成边回调),也属于import dev.langchain4j.service.TokenStream;下面的方法,他的效果就是TokenStream(边生成边回调),就类似你去请求豆包一样,他是一段话一段话的输出。
interface QwenStreamingAssistant {
@SystemMessage("你是一个简洁的中文助手。")
TokenStream chat(@UserMessage String message);
}
@Test
void test10() {
// Streaming 必须使用 StreamingChatModel(普通 ChatModel 不支持 token-by-token 输出)
StreamingChatModel model = OpenAiStreamingChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("ALI_API_KEY"))
.modelName("qwen-plus")
.build();
QwenStreamingAssistant assistant = AiServices.create(QwenStreamingAssistant.class, model);
TokenStream stream = assistant.chat("用 3 句话解释 Java 的 GC,并给一个调优建议");
CompletableFuture<Void> done = new CompletableFuture<>();
// 每次收到一段增量输出都会回调(适合"打字机效果")
stream.onPartialResponse(System.out::print)
// 全部完成后回调(你也可以在这里拿到完整 ChatResponse)
.onCompleteResponse(r -> done.complete(null))
.onError(done::completeExceptionally)
.start();
// 等待流式完成,避免 JUnit 提前结束导致看不到输出
done.orTimeout(60, TimeUnit.SECONDS).join();
System.out.println();
}
工具调用(Function/Tool Call)
Tool Call也可以叫Function Call,让大模型不只是"生成文字",而是能在回答过程中调用你提供的函数/工具,拿到"可验证的结果/外部数据",再把结果组织成最终回复。
你可以把它理解成:模型会"发起一次函数调用请求" → 你的程序执行真实逻辑 → 把执行结果回给模型 → 模型再输出最终答案。
通过调用工具,可以让大模型根据真实数据去回答,而不是胡编乱造,模型负责理解意图、拆解步骤、决定何时调用哪个工具。
// 知识点:@Tool(把 Java 方法暴露给模型)、AiServices.tools(...)、让模型"会用工具"而不是纯嘴算
// 注意:
// - 是否支持工具调用取决于模型/网关能力;如果服务端不支持会报 400/Unsupported。
interface QwenToolAssistant {
@SystemMessage("你是一个严谨的计算助手。需要计算时优先调用工具。")
String ask(@UserMessage String question);
}
static class CalculatorTools {
@Tool("计算两个整数的乘积")
int multiply(int a, int b) {
System.out.println("调用了工具");
return a * b;
}
}
@Test
void test11(){
ChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("ALI_API_KEY"))
.modelName("qwen-plus")
.build();
QwenToolAssistant assistant = AiServices.builder(QwenToolAssistant.class)
.chatModel(model)
.tools(new CalculatorTools())
.build();
System.out.println(assistant.ask("请调用工具计算 65*889,最后只输出结果"));
}