一、引言
本文将带您学习如何借助 Quarkus LangChain4j 项目,构建基于不同聊天模型的应用程序。Quarkus 提供的 AI 聊天模型接口兼具可移植性与简洁性,能让开发者与各类 AI 模型实现无缝交互。我们将搭建一个示例 Quarkus 应用,实现 OpenAI、Mistral AI 和 Ollama 这三款主流聊天模型的切换使用。
本文是 Quarkus LangChain4j 系列 AI 教程的第一篇,后续还会在博客中推出更多相关内容。本教程的设计思路与 Spring AI 系列教程相似,示例应用的功能也与对应的 Spring Boot 应用保持一致,方便您直观对比两种框架的实现方式。
若您对 Quarkus 感兴趣,可前往博客的 Quarkus 分类专栏,查找更多您关注的主题内容。
二、源码获取
如果您想亲自实践本教程的示例,可直接使用我提供的源码。操作步骤很简单:先克隆我的 GitHub 示例仓库,再按照文中的步骤指引执行即可。
三、开发背景
每次撰写 AI 相关的文章或开发示例时,我都会先明确要解决的问题。本次示例要解决的问题其实很常见:在讲解复杂技术概念时,我常会发布一些小型演示应用,而这些应用通常需要测试数据来展示输出效果。以往,我要么手动添加演示数据,要么使用 Datafaker 这类库自动生成数据;这次,我们可以借助 AI 聊天模型的 API 来实现这一需求——接下来,就让我们正式开始吧!
值得一提的是,我此前已针对 Spring Boot 框架讲解过类似主题。若您想对比两种框架在 AI 聊天模型简单交互场景下的功能差异,可参考这篇关于 Spring AI 的文章。
四、依赖配置
本示例应用使用的是当前最新版本的 Quarkus 框架,首先需要配置依赖管理与核心依赖:
4.1 依赖管理配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4.2 多 AI 模型依赖切换
通过激活特定的 Maven Profile,可轻松实现不同 AI 模型依赖的切换。默认情况下,open-ai Profile 处于激活状态,会在 Maven 依赖中引入 quarkus-langchain4j-openai 模块;若激活 mistral-ai 或 ollama Profile,则会分别替换为 quarkus-langchain4j-mistral-ai 或 quarkus-langchain4j-ollama 模块。
<profiles>
<profile>
<id>open-ai</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-openai</artifactId>
<version>${quarkus-langchain4j.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>mistral-ai</id>
<dependencies>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-mistral-ai</artifactId>
<version>${quarkus-langchain4j.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>ollama</id>
<dependencies>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-ollama</artifactId>
<version>${quarkus-langchain4j.version}</version>
</dependency>
</dependencies>
</profile>
</profiles>
4.3 核心与测试依赖
示例应用功能简洁,主要通过暴露 REST 接口与选定的 AI 模型交互,并返回 AI 生成的响应。因此,只需引入 quarkus-rest-jackson、quarkus-arc 等核心 Quarkus 模块即可。为实现 REST API 的 JUnit 测试,还需在 test 作用域中引入 quarkus-junit5 和 rest-assured 模块。
<dependencies>
<!-- 核心 Quarkus 依赖 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
五、Quarkus LangChain4j 聊天模型集成
Quarkus 提供了一套创新的 AI 聊天模型交互方案,核心步骤如下:首先,通过 @RegisterAiService 注解标记接口,并定义面向 AI 的方法;然后,在 @SystemMessage 和 @UserMessage 注解中分别添加系统提示与用户输入提示。
下面以 PersonAiService 接口为例,该接口定义了两个核心方法:
generatePersonList:请求 AI 模型生成 10 个唯一的人员数据,且数据格式需与输入对象结构一致;getPersonById:从聊天记忆中读取之前生成的人员列表,返回指定id对应的人员数据。
5.1 AI 服务接口实现
@RegisterAiService
@ApplicationScoped
public interface PersonAiService {
@SystemMessage("""
你是一个擅长生成真实人员数据的助手,始终以有效的 JSON 格式返回结果。
""")
@UserMessage("""
生成恰好 10 个唯一的人员数据,需满足以下要求:
- 每个人员必须有唯一的整数 ID(如 1、2、3 等);
- 结合不同国籍,使用真实的姓名;
- 年龄范围在 18 至 80 岁之间;
- 仅返回 JSON 数组,不要包含任何额外文本。
""")
PersonResponse generatePersonList(@MemoryId int userId);
@SystemMessage("""
你是一个能够从聊天记忆中调取已生成人员数据的助手。
""")
@UserMessage("""
在之前为用户 {userId} 生成的人员列表中,查找并返回 ID 为 {id} 的人员数据。
仅返回 JSON 对象,不要包含任何额外文本。
""")
Person getPersonById(@MemoryId int userId, int id);
}
关于上述代码,有几点补充说明:
- 作用域配置:
@RegisterAiService注解默认创建的 Bean 为@RequestScoped作用域,但 Quarkus LangChain4j 文档指出,为了确保getPersonById方法能通过@MemoryId找到对应用户生成的人员列表,需将PersonAiService接口标记为@ApplicationScoped; - 聊天记忆存储:默认已启用
InMemoryChatMemoryStore实现,无需额外声明 Bean 即可直接使用。
5.2 数据模型定义
Quarkus LangChain4j 可自动将 LLM 返回的 JSON 响应映射为输出 POJO,但目前暂不支持直接映射到集合类型,因此需要用一个包装类包裹人员列表:
5.2.1 人员列表包装类
public class PersonResponse {
private List<Person> persons;
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
}
5.2.2 人员实体类
public class Person {
private Integer id;
private String firstName;
private String lastName;
private int age;
private String nationality;
private Gender gender;
// GETTER 和 SETTER 方法
}
5.3 REST 控制器实现
最后,通过 REST 控制器注入并使用 PersonAiService,与 AI 聊天模型交互。控制器暴露两个接口:
GET /api/{userId}/persons:根据userId生成人员列表;GET /api/{userId}/persons/{id}:根据userId和id查询指定人员数据。
@Path("/api")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PersonController {
private static final Logger LOG = Logger.getLogger(PersonController.class);
PersonAiService personAiService;
public PersonController(PersonAiService personAiService) {
this.personAiService = personAiService;
}
@GET
@Path("/{userId}/persons")
public PersonResponse generatePersons(@PathParam("userId") int userId) {
return personAiService.generatePersonList(userId);
}
@GET
@Path("/{userId}/persons/{id}")
public Person getPersonById(@PathParam("userId") int userId, @PathParam("id") int id) {
return personAiService.getPersonById(userId, id);
}
}
六、Quarkus LangChain4j 多 AI 模型切换使用
6.1 配置文件设置
在 application.properties 文件中配置 AI 模型相关参数。使用前,需先生成 OpenAI 和 Mistral AI 的 API 令牌,并将其作为环境变量导出;此外,还可启用 AI 模型通信过程中的请求与响应日志记录,并将单次请求的默认超时时间从 10 秒延长至 20 秒(或更长)。
# 配置 AI 模型提供商,默认使用 openai
quarkus.langchain4j.chat-model.provider = ${AI_MODEL_PROVIDER:openai}
# 启用请求和响应日志
quarkus.langchain4j.log-requests = true
quarkus.langchain4j.log-responses = true
# OpenAI 配置
quarkus.langchain4j.openai.api-key = ${OPEN_AI_TOKEN}
quarkus.langchain4j.openai.timeout = 20s
# Mistral AI 配置
quarkus.langchain4j.mistralai.api-key = ${MISTRAL_AI_TOKEN}
quarkus.langchain4j.mistralai.timeout = 20s
# Ollama 配置
quarkus.langchain4j.ollama.base-url = ${OLLAMA_BASE_URL:http://localhost:11434}
6.2 集成 OpenAI 模型
运行示例应用并连接 OpenAI 时,需先设置 OPEN_AI_TOKEN 环境变量。由于 open-ai Maven Profile 默认激活,启动应用时无需额外配置其他参数:
# 导出 OpenAI API 令牌
$ export OPEN_AI_TOKEN=<your_openai_token>
# 启动 Quarkus 开发模式
$ mvn quarkus:dev
应用启动后,可调用 GET /api/{userId}/persons 接口(替换 userId 为不同值)生成人员列表,以下是示例请求与响应:
示例 1:请求用户 ID 为 1 的人员列表
$ curl http://localhost:8080/api/1/persons
响应结果:
{
"persons": [
{"id":1,"firstName":"Liam","lastName":"Connor","age":25,"nationality":"Irish","gender":"MALE"},
{"id":2,"firstName":"Sofia","lastName":"Gonzalez","age":34,"nationality":"Spanish","gender":"FEMALE"},
{"id":3,"firstName":"Akira","lastName":"Takahashi","age":29,"nationality":"Japanese","gender":"MALE"},
{"id":4,"firstName":"Fatima","lastName":"Ali","age":42,"nationality":"Egyptian","gender":"FEMALE"},
{"id":5,"firstName":"Lucas","lastName":"Zhang","age":38,"nationality":"Chinese","gender":"MALE"},
{"id":6,"firstName":"Emma","lastName":"Smith","age":19,"nationality":"American","gender":"FEMALE"},
{"id":7,"firstName":"Giovanni","lastName":"Rossi","age":57,"nationality":"Italian","gender":"MALE"},
{"id":8,"firstName":"Maya","lastName":"Patel","age":31,"nationality":"Indian","gender":"FEMALE"},
{"id":9,"firstName":"Hans","lastName":"Müller","age":46,"nationality":"German","gender":"MALE"},
{"id":10,"firstName":"Chloe","lastName":"Taylor","age":72,"nationality":"British","gender":"FEMALE"}
]
}
示例 2:请求用户 ID 为 2 的人员列表
$ curl http://localhost:8080/api/2/persons
响应结果:
{
"persons": [
{"id":1,"firstName":"Liam","lastName":"Sullivan","age":28,"nationality":"Irish","gender":"MALE"},
{"id":2,"firstName":"Sofia","lastName":"Garcia","age":34,"nationality":"Spanish","gender":"FEMALE"},
{"id":3,"firstName":"Akira","lastName":"Takahashi","age":45,"nationality":"Japanese","gender":"MALE"},
{"id":4,"firstName":"Maya","lastName":"Patel","age":22,"nationality":"Indian","gender":"FEMALE"},
{"id":5,"firstName":"John","lastName":"Doe","age":51,"nationality":"American","gender":"MALE"},
{"id":6,"firstName":"Elsa","lastName":"Johansen","age":29,"nationality":"Norwegian","gender":"FEMALE"},
{"id":7,"firstName":"Carlos","lastName":"Silva","age":39,"nationality":"Brazilian","gender":"MALE"},
{"id":8,"firstName":"Fatima","lastName":"Khan","age":27,"nationality":"Pakistani","gender":"FEMALE"},
{"id":9,"firstName":"Lucas","lastName":"Schmidt","age":63,"nationality":"German","gender":"MALE"},
{"id":10,"firstName":"Nina","lastName":"Petrova","age":78,"nationality":"Russian","gender":"FEMALE"}
]
}
之后,可调用 GET /api/{userId}/persons/{id} 接口,从聊天记忆中查询指定人员数据:
示例 3:查询用户 ID 为 2、人员 ID 为 4 的数据
$ curl http://localhost:8080/api/2/persons/4
响应结果:
{"id":4,"firstName":"Maya","lastName":"Patel","age":22,"nationality":"Indian","gender":"FEMALE"}
示例 4:查询用户 ID 为 1、人员 ID 为 4 的数据
$ curl http://localhost:8080/api/1/persons/4
响应结果:
{"id":4,"firstName":"Fatima","lastName":"Ali","age":42,"nationality":"Egyptian","gender":"FEMALE"}
6.3 集成 Mistral AI 模型
若需切换到 Mistral AI 模型,需执行以下步骤:
- 将
AI_MODEL_PROVIDER环境变量设置为mistralai; - 导出 Mistral AI 的 API 令牌作为
MISTRAL_AI_TOKEN环境变量; - 启动应用时激活
mistral-aiProfile。
# 配置 AI 模型提供商为 Mistral AI
$ export AI_MODEL_PROVIDER=mistralai
# 导出 Mistral AI API 令牌
$ export MISTRAL_AI_TOKEN=<your_mistralai_token>
# 激活 mistral-ai Profile 并启动应用
$ mvn quarkus:dev -Pmistral-ai
应用成功启动后,日志会输出类似以下信息:
2025-06-18 16:27:12,334 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) Quarkus AI 示例应用启动
2025-06-18 16:27:12,334 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) 选定的 AI 模型提供商:MISTRALAI
2025-06-18 16:27:12,334 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) 应用已就绪!可用接口:
2025-06-18 16:27:12,334 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) GET /api/{userId}/persons - 生成 10 条人员数据
2025-06-18 16:27:12,334 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) GET /api/{userId}/persons/{id} - 根据 ID 查询人员数据(支持记忆)
2025-06-18 16:27:12,376 INFO [io.quarkus] (Quarkus Main Thread) ai-showcase 1.0.0-SNAPSHOT 已启动(基于 Quarkus 3.23.3),启动耗时:2.8s
2025-06-18 16:27:12,376 INFO [io.quarkus] (Quarkus Main Thread) 监听地址:http://localhost:8080
2025-06-18 16:27:12,377 INFO [io.quarkus] (Quarkus Main Thread) 已激活 dev 环境,启用实时编码功能
2025-06-18 16:27:12,377 INFO [io.quarkus] (Quarkus Main Thread) 已安装特性:[cdi, langchain4j, langchain4j-mistralai, qute, rest, ...]
此时,可重复执行 OpenAI 场景下的接口请求,获取 Mistral AI 生成的人员数据。应用日志会记录发送给 AI 模型的请求内容,示例如下:
2025-06-18 16:29:52,858 INFO [io.qua.lan.mis.QuarkusMistralAiClient$MistralAiClientLogger] (vert.x-eventloop-thread-0) 请求:
方法:POST
URL:https://api.mistral.ai/v1/chat/completions
请求头:[...]
请求体:
"You are a helpful assistant that generates realistic person data. Always respond with valid JSON format.
Generate exactly 10 unique persons
Requirements:
- Each person must have a unique integer ID (like 1, 2, 3, etc.)
- Use realistic first and last names per each nationality
- Ages should be between 18 and 80
- Return ONLY the JSON array, no additional text
You must answer strictly in the following JSON format: {
"persons": [
{
"id": (type: integer),
"firstName": (type: string),
"lastName": (type: string),
"age": (type: integer),
"nationality": (type: string),
"gender": (type: enum, must be one of [MALE, FEMALE])
}
]
}"
同时,日志也会记录 AI 模型的响应内容,示例如下:
2025-06-18 16:29:57,788 INFO [io.qua.lan.mis.QuarkusMistralAiClient$MistralAiClientLogger] (vert.x-eventloop-thread-0) 响应:
状态码:200
响应头:[Date: Wed, 18 Jun 2025 14:29:57 GMT, Content-Type: application/json, Content-Length: 2200, ...]
响应体:
{
"persons": [
...
{"id":5,"firstName":"Hiroshi","lastName":"Tanaka","age":41,"nationality":"Japanese","gender":"MALE"},
...
]
}
6.4 集成 Ollama 模型
最后,我们来集成 Ollama 模型。默认情况下,LangChain4j Ollama 扩展使用 llama3.2 模型,若需修改模型,可在 application.properties 中配置 quarkus.langchain4j.ollama.chat-model.model-id 属性。以下以使用 llama3.3 模型为例,配置如下:
# Ollama 基础地址配置
quarkus.langchain4j.ollama.base-url = ${OLLAMA_BASE_URL:http://localhost:11434}
# 指定 Ollama 使用的模型 ID
quarkus.langchain4j.ollama.chat-model.model-id = llama3.3
# 设置 Ollama 请求超时时间
quarkus.langchain4j.ollama.timeout = 60s
6.4.1 启动 Ollama 模型
在启动应用前,需先在本地运行 llama3.3 模型(注:llama3.3 模型大小约为 42GB,若设备性能有限,可选择更小的模型):
$ ollama run llama3.3
模型启动过程可能耗时较长,成功启动后会显示类似以下信息:
pulling manifest
pulling 4824460d29f2: 100% |████████████████████████████████| 42 GB
pulling 948af2743fc7: 100% |████████████████████████████████| 1.5 KB
...
verifying sha256 digest
writing manifest
success
>>> Send a message (/? for help)
6.4.2 启动 Quarkus 应用
模型启动后,需将 AI_MODEL_PROVIDER 环境变量设置为 ollama,并激活 ollama Profile 启动应用:
# 配置 AI 模型提供商为 Ollama
$ export AI_MODEL_PROVIDER=ollama
# 激活 ollama Profile 并启动应用
$ mvn quarkus:dev -Pollama
应用成功连接 Ollama 模型后,日志会输出类似以下信息:
2025-06-18 17:07:57,963 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) Quarkus AI 示例应用启动
2025-06-18 17:07:57,964 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) 选定的 AI 模型提供商:OLLAMA
2025-06-18 17:07:57,964 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) 应用已就绪!可用接口:
2025-06-18 17:07:57,964 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) GET /api/{userId}/persons - 生成 10 条人员数据
2025-06-18 17:07:57,964 INFO [pl.pio.qua.ai.Config] (Quarkus Main Thread) GET /api/{userId}/persons/{id} - 根据 ID 查询人员数据(支持记忆)
2025-06-18 17:07:58,088 INFO [io.quarkus] (Quarkus Main Thread) ai-showcase 1.0.0-SNAPSHOT 已启动(基于 Quarkus 3.23.3),启动耗时:1.227s
2025-06-18 17:07:58,088 INFO [io.quarkus] (Quarkus Main Thread) 监听地址:http://localhost:8080
2025-06-18 17:07:58,088 INFO [io.quarkus] (Quarkus Main Thread) 已激活 dev 环境,启用实时编码功能
2025-06-18 17:07:58,088 INFO [io.quarkus] (Quarkus Main Thread) 已安装特性:[cdi, langchain4j, langchain4j-ollama, langchain4j-ollama-dev-service, ...]
6.4.3 Ollama Dev Services 支持
Quarkus LangChain4j Ollama 扩展还提供了 Dev Services 功能——无需在本地安装 Ollama 或通过 CLI 启动模型,Quarkus 会自动以 Docker 容器的形式运行 Ollama,并在容器中启动选定的 AI 模型。此时,无需配置 quarkus.langchain4j.ollama.base-url 属性。
若需使用更小的模型(如 mistral),可先修改配置:
quarkus.langchain4j.ollama.chat-model.model-id = mistral
再按照上述方式启动应用,Quarkus 会自动拉取 Ollama 镜像并启动 mistral 模型,日志会输出类似以下镜像拉取信息:
2025-06-18 17:18:13,859 INFO [tc.ollama/ollama:latest] (docker-java-stream-1866434735) 开始拉取镜像
2025-06-18 17:18:14,521 INFO [tc.ollama/ollama:latest] (docker-java-stream-1866434735) 拉取镜像层:3 个待拉取,1 个已下载,0 个已解压
...
2025-06-18 17:19:45,177 INFO [tc.ollama/ollama:latest] (docker-java-stream-1866434735) 拉取完成,共 5 个镜像层,耗时 91 秒(下载速度:26 MB/s,总大小:2 GB)
2025-06-18 17:19:48,127 INFO [io.qua.lan.oll.dep.dev.OllamaDevServicesProcessor] (build-57) Ollama Dev Services 已启动
2025-06-18 17:21:08,044 INFO [io.qua.lan.oll.dep.dev.DevServicesOllamaProcessor] (HttpClient-2-Worker-2) 正在下载 mistral 模型,进度:...
七、总结
不得不说,Quarkus LangChain4j 扩展的使用体验十分出色——只需几个简单的注解,就能轻松配置应用,与选定的 AI 模型实现交互。本文通过一个简洁的示例,演示了 Quarkus 与 AI 聊天模型的集成过程,同时也简要介绍了提示词设计、结构化输出、聊天记忆等核心功能。
后续,我会继续推出 Quarkus AI 系列的更多文章,深入探讨更多进阶用法,敬请期待!






