上一个系列讲了Spring AI得到反馈效果不错,有人私信我说这个和Langchain4j有什么区别。如果站在使用方面,都是基于Java的大模型应用研发的工具,本质上没太大区别。但是从细节层面来说还是有很多不同之处,所以索性借此机会,给大家分享一下Langchain4j框架。在本系列中会按照Spring AI系列的顺序来写Langchain4j,这样的好处是可以对比两者不同的细节。
注意 :由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是langchain4j-1.9.1,JDK版本使用的是19。另外本系列尽量使用Java原生态,尽量不依赖于Spring和Spring Boot。虽然langchain4j也支持Spring Boot集成,但是如果是使用Spring Boot框架,那为何不索性使用Spring AI。
本系列的所有代码地址: https://github.com/forever1986/langchain4j-study
目录
- [1 Observability](#1 Observability)
- [2 AiServices的Observability](#2 AiServices的Observability)
-
- [2.1 说明](#2.1 说明)
- [2.2 示例演示](#2.2 示例演示)
- [2.3 Observability源码分析](#2.3 Observability源码分析)
-
- [2.3.1 listener的注册](#2.3.1 listener的注册)
- [2.3.2 event的触发](#2.3.2 event的触发)
- [3 ChatModel的Observability](#3 ChatModel的Observability)
上两章讲解了Langchain4j中的Guardrails,接下来两章,将讲解Langchain4j的Observability。
1 Observability
Langchain4j 利用设计模式中的注册模式,实现了Langchain4j 中的可观测性功能,其中包括AiServices这种高级版的API,也包括ChatModel这种低级别的API。可观测性的作用其实是监听大模型调用的流程,同时还可以在流程中做一些处理,包括集成第三方可观测性平台进行数据采集。举一个场景,假如用户希望开发的AI功能是按次消费的,根据用户每一次的调用大模型、工具、MCP等次数以及token数计费,那么Langchain4j 的Observability就为用户专门定做的功能。
2 AiServices的Observability
2.1 说明
首先来看看高级版API的AiServices是如何使用Observability。默认情况下,AiServices层定义了如下的一些事件:

关于上面的类图,每个事件的相关监听器、触发条件和可获取到的数据如下表:
| Event | Listener | 触发条件 | 可获取数据 |
|---|---|---|---|
| AiServiceStartedEvent | AiServiceStartedListener | 当模型调用开始时会触发此事件 | InvocationContext、SystemMessage、UserMessage |
| AiServiceResponseReceivedEvent | AiServiceResponseReceivedListener | 由模型的回复后调用,但是如果是报错情况,则不会被调用 | InvocationContext、ChatResponse |
| AiServiceErrorEvent | AiServiceErrorListener | 当模型调用出现失败情况时 | InvocationContext、Throwable |
| AiServiceCompletedEvent | AiServiceCompletedListener | 当模型调用成功完成时会触发此事件 | InvocationContext、Optional |
| ToolExecutedEvent | ToolExecutedEventListener | 当工具调用完成时会触发此事件 | InvocationContext、ToolExecutionRequest、resultText |
| InputGuardrailExecutedEvent | InputGuardrailExecutedListener | 当InputGuardrail验证执行完毕时会触发此事件 | InvocationContext、UserMessage |
| OutputGuardrailExecutedEvent | OutputGuardrailExecutedListener | 当执行OutputGuardrail验证时会触发此事件 | InvocationContext、GuardrailRequest、GuardrailResult |
在上面的所有Event中都可以获得一个InvocationContext上下文接口类,看看这个接口的实现类 DefaultInvocationContext 可以获取的内容:
java
public class DefaultInvocationContext implements InvocationContext {
private final UUID invocationId; // 本次调用的id
private final String interfaceName; // AiServices注入的接口名称
private final String methodName; // AiServices注入的方法名称
private final List<Object> methodArguments = new ArrayList<>(); // 方法的参数
private final Object chatMemoryId; // 聊天记忆
private final InvocationParameters invocationParameters; // 调用参数
private final Map<Class<? extends LangChain4jManaged>, LangChain4jManaged> managedParameters; // 参数管理
private final Instant timestamp; // 本次调用时间
}
2.2 示例演示
代码参考lesson13子模块
1)新建lesson13子模块,其pom引入如下:
xml
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
</dependencies>
2)在lesson13子模块下,新建Assistant 接口
java
package com.langchain.lesson13.service;
public interface Assistant {
String chat(String userMessage);
}
3)在lesson13子模块下,新建MyAiServiceResponseReceivedListener监听器
java
package com.langchain.lesson13.listener;
import dev.langchain4j.observability.api.event.AiServiceResponseReceivedEvent;
import dev.langchain4j.observability.api.listener.AiServiceResponseReceivedListener;
public class MyAiServiceResponseReceivedListener implements AiServiceResponseReceivedListener {
@Override
public void onEvent(AiServiceResponseReceivedEvent event) {
System.out.println("invocationContext上下文内容:"+event.invocationContext());
System.out.println("大模型回复内容:"+event.response().aiMessage().text());
System.out.println("本次调用大模型名称:"+event.response().modelName());
System.out.println("本次消耗的token数:"+event.response().tokenUsage());
System.out.println("其它一些元数据:"+event.response().metadata());
}
}
4)在lesson13子模块下,新建ObservabilityAiServicesTest类
java
package com.langchain.lesson13;
import com.langchain.lesson13.listener.MyAiServiceResponseReceivedListener;
import com.langchain.lesson13.service.Assistant;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
public class ObservabilityAiServicesTest {
public static void main(String[] args) {
//1.获取API KEY
String apiKey = System.getenv("ZHIPU_API_KEY");
//2.加载大模型
ChatModel model = OpenAiChatModel.builder()
.apiKey(apiKey)
.baseUrl("https://open.bigmodel.cn/api/paas/v4")
.modelName("glm-4-flash-250414")
.build();
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(model)
// 加入监听器
.registerListeners(new MyAiServiceResponseReceivedListener())
.build();
// 3.访问大模型
String response = assistant.chat("直接给我推荐一本书,直接给出书名");
System.out.println(response);
}
}
5)运行ObservabilityAiServicesTest测试,结果如下:

说明:可以看到,只需要定义监听器,在监听器中写入要做的事情,之后将监听器加入到AiServices中即可。并且监听器中可以获取到本次调用的所有信息以及每个监听器特有的信息
2.3 Observability源码分析
Langchain4j 的Observability是通过设计模型中的注册模式原理实现的。因此只需要看listener的注册和event的触发即可。
2.3.1 listener的注册
1)当往 AiServices 中注册监听器时,会被 AiServiceListenerRegistrar 注册器进行注册

2)在 AiServiceListenerRegistrar 的实现类 DefaultAiServiceListenerRegistrar 中,可以看到其使用一个Map存储事件与注册器的关系,key为 AiServiceEvent ,value则是被装的 AiServiceListener (可以多个)

2.3.2 event的触发
1)先看看 DefaultAiServiceListenerRegistrar 实现了 AiServiceListenerRegistrar 接口中的fireEvent()方法,其结果就循环已经注册的listeners,判断其key与Event匹配的,如果匹配则触发listener的onEvent()方法

2)再来看看 AiServiceListenerRegistrar 中的fireEvent()方法在项目中被使用的地方:

说明:从上面这些,就能够知道各种不同的Event给调用的地方
3 ChatModel的Observability
关于ChatModel的Observability,其实早在《Langchain4j 系列之五 - 大模型参数和常用配置》的监听这小节中已经说过了,这里就不累赘,可以去看看前面的内容。
结语:本章讲解了Langchain4j中Observability的功能,并通过代码演示了。可观测性在生产级别是比较重要的内容,下一章将再进一步讲解如何结合可视化平台展现数据。
Langchain4j 系列上一章:《Langchain4j 系列之三十 - Guardrails之二》
Langchain4j 系列下一章:《Langchain4j 系列之三十二 - Observability之集成Arize-Phoenix》