1. 项目概述:当Java遇上LangChain4j
三年前第一次接触LangChain时,我就被这个框架的设计哲学所吸引。如今其Java版本LangChain4j的成熟,终于让我们Java开发者也能在本地环境快速构建AI应用。不同于Python生态的LangChain,LangChain4j针对Java开发者做了大量优化:更符合Maven规范的依赖管理、与SpringBoot无缝集成的自动配置、对Java流式API的深度支持。本文将基于1.0.0最新稳定版,带你体验如何用Java构建一个具备长期记忆和工具调用能力的智能问答系统。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 依赖管理实战
在pom.xml中需要同时声明核心库和扩展模块。这里有个容易踩的坑:不同模块的版本号必须严格一致,否则会出现类加载冲突。建议使用dependencyManagement统一管理:
xml复制<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
</dependency>
</dependencies>
2.2 模型连接配置
与OpenAI等商业API不同,本地部署的Ollama需要特别注意超时设置。我在实际使用中发现,当模型首次加载或处理长文本时,默认的30秒超时经常不够用:
java复制OllamaChatModel model = OllamaChatModel.builder()
.baseUrl("http://localhost:11434")
.modelName("llama3")
.timeout(Duration.ofMinutes(5)) // 生产环境建议5-10分钟
.temperature(0.7)
.build();
重要提示:如果在Docker中运行Ollama,需要将容器端口映射到宿主机,并确保防火墙放行11434端口。测试连接时可以用curl命令:
curl http://localhost:11434/api/generate -d '{"model":"llama3","prompt":"Why is the sky blue?"}'
3. 核心功能实现解析
3.1 对话记忆管理
LangChain4j的Memory管理比Python版更加类型安全。下面示例展示如何实现带历史记录的对话:
java复制// 使用持久化存储的对话记忆
ChatMemoryStore store = new InMemoryChatMemoryStore();
ChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(20)
.id("user123") // 按用户ID隔离记忆
.chatMemoryStore(store)
.build();
// 记忆绑定到AI服务
Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(model)
.chatMemory(memory)
.build();
// 对话示例
String answer = assistant.chat("你好,我是张三");
System.out.println(answer); // "你好张三,有什么可以帮您?"
String followUp = assistant.chat("你还记得我是谁吗?");
System.out.println(followUp); // "当然记得,您是张三先生。"
3.2 工具调用实战
工具调用(Tool Calling)是LangChain4j最强大的特性之一。下面实现一个查询天气的案例:
首先定义工具接口:
java复制interface WeatherTools {
@Tool("获取指定城市的当前天气")
String getWeatherAtCity(@P("城市名称") String city);
}
然后注册到AI服务:
java复制Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(model)
.tools(new WeatherTools())
.build();
// 触发工具调用
String response = assistant.chat("上海现在天气怎么样?");
// 输出类似:"让我查询一下... [调用getWeatherAtCity工具] 上海当前晴天,25℃"
调试技巧:在开发阶段可以添加
. logRequestsTo(System.out) .logResponsesTo(System.out)来查看原始请求/响应数据
4. 生产级优化策略
4.1 性能调优参数
在负载较高的生产环境中,这些配置参数值得关注:
java复制OllamaChatModel optimizedModel = OllamaChatModel.builder()
.baseUrl("http://ollama-cluster:11434")
.modelName("llama3-8b-quantized") // 量化模型减少内存占用
.timeout(Duration.ofMinutes(3))
.maxRetries(3) // 失败自动重试
.logRequests(true)
.logResponses(true)
.executorService(Executors.newFixedThreadPool(10)) // 独立线程池
.build();
4.2 异常处理模式
对于生产系统,推荐使用响应式编程处理可能的异常:
java复制public Mono<String> safeChat(String message) {
return Mono.fromCallable(() -> assistant.chat(message))
.timeout(Duration.ofSeconds(30))
.onErrorResume(e -> {
log.error("AI服务异常", e);
return Mono.just("系统繁忙,请稍后再试");
});
}
5. 典型问题排查指南
以下是实际开发中遇到的常见问题及解决方案:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 工具调用不触发 | 方法签名不符合规范 | 确保工具方法有@Tool注解和@P参数说明 |
| 中文回答质量差 | 提示词未指定语言 | 在系统消息中添加"你是一个专业的中文助手" |
| 响应时间过长 | 模型未量化 | 使用llama3-8b-quantized等量化版本 |
| 记忆丢失 | ChatMemoryStore未持久化 | 改用RedisChatMemoryStore |
| 线程阻塞 | 未配置独立线程池 | 设置executorService参数 |
6. 进阶应用场景
6.1 文档问答系统实现
结合Embedding和向量数据库,可以构建本地知识库问答系统:
java复制// 文档嵌入处理
EmbeddingModel embeddingModel = new OllamaEmbeddingModel();
EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
// 文档加载与分块
DocumentSplitter splitter = new DocumentByParagraphSplitter();
List<TextSegment> segments = splitter.split(document);
// 生成嵌入并存储
for (TextSegment segment : segments) {
Embedding embedding = embeddingModel.embed(segment.text()).content();
store.add(embedding, segment);
}
// 构建问答链
Retriever<TextSegment> retriever = EmbeddingStoreRetriever.from(store, embeddingModel);
AnsweringChain chain = AnsweringChain.builder()
.chatModel(model)
.retriever(retriever)
.build();
String answer = chain.execute("文档中提到的技术指标是什么?");
6.2 多智能体协作系统
通过Agent协调多个专业模型协同工作:
java复制Agent planner = AiServices.builder(Planner.class)
.chatLanguageModel(model)
.tools(new ResearchTools(), new AnalysisTools())
.build();
Agent executor = AiServices.builder(Executor.class)
.chatLanguageModel(model)
.tools(new CodingTools(), new TestingTools())
.build();
String task = "开发一个天气预报小程序";
String plan = planner.plan(task); // 生成执行计划
String result = executor.execute(plan); // 执行具体任务
在实际项目中,我发现将LangChain4j与Spring Boot集成时,最佳实践是:
- 使用@ConfigurationProperties管理模型参数
- 通过HealthIndicator暴露模型健康状态
- 利用AOP统一处理Prompt注入攻击防护
- 结合Micrometer实现性能指标监控
对于需要处理复杂业务流程的场景,可以采用StatefulChain模式,将对话状态持久化到数据库,实现跨会话的长期记忆和流程恢复能力。
