乐于分享
好东西不私藏

LangChain4j源码到使用 java大模型开发必备的工具包

LangChain4j源码到使用 java大模型开发必备的工具包

本教程共包含 6 个核心示例,从基础到高级,循序渐进地介绍 LangChain4j 框架的使用:

📦 基础部分

示例
内容
重点知识点
示例01
Hello World
ChatModel 基础调用
示例02
模型参数配置
temperature(温度)、maxTokens(最大令牌数)
示例03
流式输出
StreamingChatModel、StreamingChatResponseHandler 回调
示例04
大模型没有记忆
HTTP 无状态、每次调用独立、需要 ChatMemory 实现记忆
05-01
简单 AI Service
接口定义、AiServices.create()
05-02
系统消息
@SystemMessage 注解设定 AI 角色
05-03
变量模板
@V 注解、{{变量名}} 模板语法
05-04
返回枚举/布尔值
自动类型转换、Sentiment 枚举
05-05
返回 POJO
@Description 注解、结构化数据提取
05-06
对话记忆
ChatMemory、@MemoryId 多用户记忆
示例06
Function Calling
@Tool 注解、AI 自动调用工具、Agent 雏形

为什么需要 LangChain4j?

LangChain4j 官方文档:https://docs.langchain4j.dev/

LangChain4j 解决了什么问题?

  • 接口+注解定义 AI 服务,告别字符串拼接
  • 自动类型转换,支持 String、枚举、boolean、POJO
  • 内置记忆管理,轻松实现多轮对话
  • 简化工具调用,AI 自动决定何时调用

环境准备

Maven 依赖

<properties>
<langchain4j.version>1.11.0</langchain4j.version>
</properties>

<dependencies>
<!-- LangChain4j Core -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>${langchain4j.version}</version>
</dependency>

<!-- OpenAI 兼容模块(阿里百炼、DeepSeek 等都兼容) -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>${langchain4j.version}</version>
</dependency>
</dependencies>

模型配置

本教程使用阿里百炼(DashScope)的通义千问模型,通过 OpenAI 兼容 API 接入:

publicclassDashScopeProperties{
// API Key - 请替换为您自己的 Key
publicstaticfinal String API_KEY = "your-api-key";

// 阿里百炼 OpenAI 兼容 API URL
publicstaticfinal String BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";

// 模型名称
publicstaticfinal String DEFAULT_MODEL_NAME = "qwen-plus";
publicstaticfinal String QWEN_MAX = "qwen-max";
publicstaticfinal String QWEN_PLUS = "qwen-plus";
publicstaticfinal String QWEN_TURBO = "qwen-turbo";
}

示例 01:Hello World

最简单的示例,使用 ChatModel 进行对话。

代码实现

publicclassHelloWorld{
publicstaticvoidmain(String[] args){
// 创建 ChatModel
        ChatModel model = OpenAiChatModel.builder()
                .baseUrl(BASE_URL)
                .apiKey(API_KEY)
                .modelName(DEFAULT_MODEL_NAME)
                .build();

// 发送消息
        String answer = model.chat("你好,请用中文说 Hello World");
        System.out.println(answer);
    }
}

设计重点

ChatModel 是最基础的模型接口:

  • 调用 chat() 方法发送消息
  • 返回字符串类型的响应
  • 每次调用都是独立的,模型不记住之前的对话

爱码说:这是最原始的调用方式,适合单轮问答场景。


示例 02:模型参数配置

大模型支持多种参数,最常用的是 temperature 和 maxTokens

代码实现

publicclassModelParametersExample{
publicstaticvoidmain(String[] args){
        ChatModel model = OpenAiChatModel.builder()
                .baseUrl(BASE_URL)
                .apiKey(API_KEY)
                .modelName(QWEN_PLUS)
                .temperature(0.3)      // 温度参数
                .maxTokens(500)        // 最大输出长度
                .build();

        String response = model.chat("用三行话解释如何画一幅美丽的画");
        System.out.println(response);
    }
}

设计重点

temperature(温度)

  • 值范围 0~1,默认约 0.7
  • 值越小,输出越确定、一致性强
  • 值越大,输出越随机、创意性强

maxTokens(最大令牌数)

  • 限制输出长度,控制成本
  • 一个中文字约等于 1-2 个 token

爱码说:temperature 不是越低越好,要根据场景选择。翻译场景需要确定性,而创意场景需要随机性。


示例 03:流式输出

等待大模型完整响应再显示,用户体验很差。流式输出(Streaming) 实现打字机效果。

代码实现

publicclassStreamingExample{
publicstaticvoidmain(String[] args){
        StreamingChatModel model = OpenAiStreamingChatModel.builder()
                .baseUrl(BASE_URL)
                .apiKey(API_KEY)
                .modelName(DEFAULT_MODEL_NAME)
                .build();

        String prompt = "写一首关于程序员和空指针异常的短诗,最多10行";

        CompletableFuture<ChatResponse> future = new CompletableFuture<>();

        model.chat(prompt, new StreamingChatResponseHandler() {
@Override
publicvoidonPartialResponse(String partialResponse){
// 逐块输出
                System.out.print(partialResponse);
            }

@Override
publicvoidonCompleteResponse(ChatResponse completeResponse){
                System.out.println("\n--- 完成 ---");
                future.complete(completeResponse);
            }

@Override
publicvoidonError(Throwable error){
                future.completeExceptionally(error);
            }
        });

        future.join();
    }
}

设计重点

StreamingChatModel 与 ChatModel 的区别:

特性
ChatModel
StreamingChatModel
返回方式
同步等待完整响应
异步逐块返回
用户体验
等待时间长
即时反馈
适用场景
批处理、后台任务
对话、实时交互

StreamingChatResponseHandler 三个回调方法:

  1. onPartialResponse() – 每收到一块数据就调用
  2. onCompleteResponse() – 全部完成后调用
  3. onError() – 发生错误时调用

爱码说:Web 应用中可以配合 SSE(Server-Sent Events)实现真正的打字机效果。


示例 04:大模型没有记忆

这是一个非常重要的概念:大模型本身是没有记忆的!

代码验证

publicclassMemoryExample{
publicstaticvoidmain(String[] args){
        ChatModel model = createChatModel();

// 第一次对话
        String answer1 = model.chat("你好!我叫小明。");
        System.out.println("AI: " + answer1);

// 第二次对话
        String answer2 = model.chat("我叫什么名字?");
        System.out.println("AI: " + answer2);
// AI 回答:抱歉,我不知道您的名字...
    }
}

设计重点

为什么模型记不住?

  • HTTP 是无状态的,每次调用都是独立的请求
  • 模型只看到当前这条消息,看不到之前的对话

如何实现记忆?

  • 每次请求时,把之前的对话历史一起发送
  • LangChain4j 提供了 ChatMemory 来管理对话历史

爱码说:这就像你每次打电话都要重新自我介绍,因为对方不记得你是谁。解决方法就是——每次都说”我是上次跟您聊过的xxx”。


示例 05:AI Service 入门

直接用 ChatModel 有什么问题?

  • 手动拼接 prompt 字符串
  • 返回值只能是自己解析
  • 记忆管理需要手动处理

AiServices 提供了更优雅的方式:用接口定义 AI 服务

05-01:简单 AI Service

// 定义接口
publicinterfaceSimpleAssistant{
String chat(String message);
}

// 使用
SimpleAssistant assistant = AiServices.create(SimpleAssistant.classmodel);
String answer = assistant.chat("请翻译: 'Hello, how are you?'");

就这么简单!不需要实现类,LangChain4j 会自动生成代理。

05-02:系统消息(设定角色)

publicinterfaceChefAssistant{
@SystemMessage("你是一位专业的厨师。你友好、礼貌且简洁。")
String answer(String question);
}

ChefAssistant chef = AiServices.create(ChefAssistant.classmodel);
chef.answer("烤鸡需要多长时间?");
// AI 会以厨师的角色回答

@SystemMessage 注解设定 AI 的角色和行为规范。

05-03:变量模板

publicinterfaceTextUtilsAssistant{
@SystemMessage("你是一位专业的{{language}}翻译")
@UserMessage("翻译以下文本: {{text}}")
String translate(@V("text") String text, @V("language") String language);
}

TextUtilsAssistant utils = AiServices.create(TextUtilsAssistant.classmodel);
utils.translate("Hello""中文");

注解说明

  • @V("变量名") – 方法参数绑定到模板变量
  • {{变量名}} – 模板中的占位符
  • {{it}} – 特殊变量,代表第一个参数

05-04:返回枚举和布尔值

// 情感枚举
publicenum Sentiment {
    POSITIVE, NEUTRAL, NEGATIVE
}

publicinterfaceSentimentAnalyzer{
@UserMessage("分析以下文本的情感: {{it}}")
Sentiment analyzeSentimentOf(String text);

@UserMessage("以下文本是否是正面情感?")
booleanisPositive(String text);
}

SentimentAnalyzer analyzer = AiServices.create(SentimentAnalyzer.classmodel);

Sentiment s = analyzer.analyzeSentimentOf("这个产品非常好用!");  // POSITIVE
boolean p = analyzer.isPositive("这个产品太差了!");            // false

重点:AI Service 自动将 AI 响应转换为目标类型!

05-05:返回 POJO(结构化数据提取)

publicclassPerson{
@Description("人的名字")
private String firstName;

@Description("人的姓氏")
private String lastName;

@Description("出生日期")
private LocalDate birthDate;

// getter/setter...
}

publicinterfacePersonExtractor{
@UserMessage("从以下文本中提取人物信息: {{it}}")
Person extractPersonFrom(String text);
}

PersonExtractor extractor = AiServices.create(PersonExtractor.classmodel);

String text = "1968年,国庆节的余韵中,一个名叫小明的孩子降生了。这个新生儿姓张...";
Person person = extractor.extractPersonFrom(text);
// Person{firstName="小明", lastName="张", birthDate=1968-10-01}

@Description 注解帮助 AI 理解每个字段的含义,提高提取准确性。

爱码说:这在 RAG、知识图谱构建中非常有用。从非结构化文本提取结构化数据,只需要定义一个 POJO!


示例 05-06:对话记忆

单用户记忆

publicinterfaceAssistantWithMemory{
String chat(String message);

static AssistantWithMemory create(ChatModel model){
        ChatMemory memory = MessageWindowChatMemory.withMaxMessages(10);

return AiServices.builder(AssistantWithMemory.class)
                .chatModel(model)
                .chatMemory(memory)
                .build()
;
    }
}

// 使用
AssistantWithMemory assistant = AssistantWithMemory.create(model);
assistant.chat("你好!我叫小明。");
assistant.chat("我叫什么名字?");  // AI 会回答:你叫小明

MessageWindowChatMemory

  • 自动保存最近 N 条消息
  • 每次调用时自动带上历史消息

多用户记忆

publicinterfaceAssistantWithMultiUserMemory{
String chat(@MemoryId int userId, @UserMessage String message);

static AssistantWithMultiUserMemory create(ChatModel model){
return AiServices.builder(AssistantWithMultiUserMemory.class)
                .chatModel(model)
                .chatMemoryProvider(id -> MessageWindowChatMemory.withMaxMessages(10))
                .build()
;
    }
}

// 使用
AssistantWithMultiUserMemory assistant = AssistantWithMultiUserMemory.create(model);

assistant.chat(1"你好,我叫小明");
assistant.chat(2"你好,我叫小红");
assistant.chat(1"我叫什么名字?");  // AI 回答:你叫小明
assistant.chat(2"我叫什么名字?");  // AI 回答:你叫小红

@MemoryId 注解标识用户 ID,每个用户有独立的对话记忆。

爱码说:这在多用户聊天场景中非常重要。用户 A 的对话不应该影响用户 B。


示例 06:工具调用(Function Calling)

工具调用是大模型的高级能力:AI 可以调用你提供的函数来完成任务

定义工具

publicclassCalculator{
@Tool("计算字符串的长度")
intstringLength(String s){
return s.length();
    }

@Tool("计算两个数的和")
intadd(int a, int b){
return a + b;
    }

@Tool("计算一个数的平方根")
doublesqrt(int x){
return Math.sqrt(x);
    }
}

@Tool 注解标记可被 AI 调用的方法,描述帮助 AI 理解何时调用。

注册工具并使用

interfaceAssistant{
String chat(String userMessage);
}

Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(model)
        .tools(newCalculator())  // 注册工具
        .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
        .build()
;

String question = "请计算: 'hello' 和 'world' 两个单词的字母数量之和的平方根是多少?";
String answer = assistant.chat(question);

AI 的执行过程

用户: 'hello' 和 'world' 两个单词的字母数量之和的平方根是多少?

AI 自动执行:
1. stringLength('hello') -> 5
2. stringLength('world') -> 5
3. add(5, 5) -> 10
4. sqrt(10) -> 3.162...

最终回答: 'hello' 有 5 个字母,'world' 也有 5 个字母,它们之和是 10,
         10 的平方根约等于 3.162。

AI 会自动决定

  • 是否需要调用工具
  • 调用哪个工具
  • 传递什么参数
  • 如何组合结果

爱码说:这就是 Agent 的雏形!AI 不只是回答问题,还能”动手做事”。查询天气、调用数据库、执行计算…都可以封装成工具。


总结

核心组件对比

组件
用途
特点
ChatModel
基础对话
同步、无记忆
StreamingChatModel
流式对话
异步、打字机效果
AiServices
高级封装
接口+注解、自动类型转换
ChatMemory
对话记忆
自动管理历史消息
@Tool
工具定义
让 AI 调用 Java 方法

AiServices 支持的返回类型

  • String – 原始文本
  • boolean / Boolean – 布尔判断
  • 枚举类型 – 分类任务
  • List<String> – 列表
  • POJO – 结构化数据提取

最佳实践

  1. 简单场景:直接用 ChatModel
  2. 需要类型转换:使用 AiServices
  3. 多轮对话:配置 ChatMemory
  4. 多用户场景:使用 @MemoryId + chatMemoryProvider
  5. 需要外部能力:定义 @Tool 工具

思路,比结论重要

LangChain4j 解决了什么问题?让 Java 开发者用熟悉的方式(接口、注解、POJO)与大模型交互

不需要手动拼接字符串,不需要手动解析 JSON,不需要手动管理对话历史。定义好接口,剩下的交给框架。

点赞+关注 后台回复 langchain4j 获取源码

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » LangChain4j源码到使用 java大模型开发必备的工具包

评论 抢沙发

9 + 3 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮