在与大语言模型(LLM)交互的过程中,ChatRequest 作为承载对话上下文和模型配置的核心数据结构,在发送给模型前对其进行重写,是实现灵活业务适配的关键能力。
因此,在某些情况下,在将 ChatRequest 发送到 LLM(大语言模型) 之前对其进行修改会非常有用。例如,可能需要在用户消息后附加一些额外的上下文,或者根据某些外部条件修改系统消息。
上面这些需求,均可以通过创建一个 UnaryOperator<ChatRequest>,然后通过 chatRequestTransformer() 方法配置给 AI 服务来实现这一点。
方法定义如下:
public AiServices<T> chatRequestTransformer(UnaryOperator<ChatRequest> chatRequestTransformer) {
this.context.chatRequestTransformer = (req, memId) -> {
return (ChatRequest)chatRequestTransformer.apply(req);
};
return this;
}UnaryOperator 运算符实现了要应用于 ChatRequest 的转换,可以这样做:
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(model)
.chatRequestTransformer(transformingFunction) // 配置要应用于 ChatRequest 的转换函数
.build();什么是 UnaryOperator?
UnaryOperator 是 Java 8 引入的一个函数式接口(位于 java.util.function 包下),它属于 Function 接口的特殊子类。
它的核心特点是:输入参数和返回值的类型完全相同,相当于「一元操作符」—— 接收一个同类型参数,经过处理后返回一个同类型结果,没有其他额外输出。
我们可以在 UnaryOperator 的 apply() 方法中实现对 ChatRequest 的修改。
下面示例通过 UnaryOperator 在 ChatRequest 中添加一个系统消息 SystemMessage,以及修改用户消息 UserMessage,添加输出限制。
代码如下:
package com.hxstrive.langchain4j.aiServices;
import dev.langchain4j.data.message.*;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiChatRequestParameters;
import dev.langchain4j.service.AiServices;
import java.util.ArrayList;
import java.util.List;
public class RewriteChatRequestDemo {
// 推荐:将OPEN_API_KEY设置成环境变量, 避免硬编码或随着代码泄露
// 注意,设置完环境变量记得重启IDEA,不然可能环境变量不会生效
private static final String API_KEY = System.getenv("OPEN_API_KEY");
// 定义业务接口
interface Assistant {
// userMessage 是用户输入的消息
// 返回值是 AI 回复的内容呢
String chat(String userMessage);
}
public static void main(String[] args) {
// 创建 ChatModel 实现类(OpenAI 为例)
ChatModel chatModel = OpenAiChatModel.builder()
.baseUrl("https://api.xty.app/v1")
.apiKey(API_KEY)
.modelName("gpt-3.5-turbo")
.temperature(0.7)
.logRequests(true)
.logResponses(true)
.build();
// 使用 AiServices 创建服务
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(chatModel)
.chatRequestTransformer((originalRequest) -> {
// 步骤1:获取原始请求中的所有消息
final List<ChatMessage> originalMessages = originalRequest.messages();
final List<ChatMessage> modifiedMessages = new ArrayList<>(originalMessages);
// 步骤2:重写/修改请求内容(示例场景)
// 给所有请求添加一个统一的系统提示(前置追加)
SystemMessage customSystemMessage = SystemMessage.from(
"你是一个严谨的助手,名字叫做“小彩”。"
);
modifiedMessages.add(0, customSystemMessage); // 插入到消息列表头部
// 修改用户消息的内容(例如补充格式要求)
for (int i = 0; i < modifiedMessages.size(); i++) {
ChatMessage message = modifiedMessages.get(i);
// 可以使用 message.type() == ChatMessageType.USER 进行判断,
// 但是,笔者 IDEA 识别不了 ChatMessageType 和 ContentType,不知什么原因
if (message instanceof UserMessage) {
UserMessage originalUserMsg = (UserMessage) message;
List<Content> contents = new ArrayList<>(originalUserMsg.contents());
for (int j = 0; j < contents.size(); j++) {
if(contents.get(j) instanceof TextContent) {
TextContent textContent = (TextContent) contents.get(j);
String newContent = textContent.text() + "(注意:请使用英文和中文回复)";
modifiedMessages.set(i, UserMessage.from(newContent));
}
}
break; // 只修改第一个用户消息,按需调整
}
}
// 步骤3:构建并返回修改后的 ChatRequest
return originalRequest.toBuilder()
.messages(modifiedMessages) // 替换为修改后的消息列表
.parameters(OpenAiChatRequestParameters.builder()
.temperature(0.3) // 修改参数
.maxOutputTokens(1024) // 修改参数
.build())
.build();
})
.build();
// 发起对话
String answer = assistant.chat("你好! 你叫什么名字?");
System.out.println(answer);
}
}运行示例,输出日志如下:
// 请求报文
14:07:15.893 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP request:
- method: POST
- url: https://api.xty.app/v1/chat/completions
- headers: [Authorization: Beare...00], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "gpt-3.5-turbo",
"messages" : [ {
"role" : "system",
"content" : "你是一个严谨的助手,名字叫做“小彩”。"
}, {
"role" : "user",
"content" : "你好! 你叫什么名字?(注意:请使用英文和中文回复)"
} ],
"temperature" : 0.3,
"stream" : false,
"max_tokens" : 1024
}
// 响应报文
14:07:22.448 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP response:
- status code: 200
- headers: [:status: 200], [access-control-allow-headers: *], [access-control-allow-methods: POST, GET, OPTIONS, DELETE,PUT], [access-control-allow-origin: *], [access-control-max-age: 3600], [alt-svc: h3=":443"; ma=86400], [cf-cache-status: DYNAMIC], [cf-ray: 9c7fbf431a3cf5e2-AMS], [content-length: 734], [content-type: application/json;charset=UTF-8], [date: Tue, 03 Feb 2026 06:07:22 GMT], [nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}], [report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=hNxz8MwvpJ%2FG%2Fge1DttU23jrSpOL78tiQr7OjBTqZpAfdEuNqbfMCiEl5Gj3KgGbbasqcqrAJzlZjSh%2FSGzKVjV6CxuBLkyoaA%3D%3D"}]}], [server: cloudflare], [server-timing: [cfCacheStatus;desc="DYNAMIC", cfEdge;dur=9,cfOrigin;dur=5283]], [x-oneapi-request-id: 20260203140717207806817lAGVMyNz]
- body: {
"id": "chatcmpl-T6U7Q7KHjurp8vngqLsCjeoINPZA1",
"object": "chat.completion",
"created": 1770098840,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你好!很高兴认识你 😊 \nHello! Nice to meet you!\n\n**中文:** 我叫 **小彩**。 \n**English:** My name is **Xiaocai**.\n\n随时找我聊天或帮忙都可以~ \nFeel free to chat with me anytime!"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 60,
"completion_tokens": 76,
"total_tokens": 136
},
"system_fingerprint": "fp_b28b39ffa8"
}
你好!很高兴认识你 😊
Hello! Nice to meet you!
**中文:** 我叫 **小彩**。
**English:** My name is **Xiaocai**.
随时找我聊天或帮忙都可以~
Feel free to chat with me anytime!
Process finished with exit code 0如果还需要访问聊天记忆(ChatMemory)来实现所需的聊天请求(ChatRequest)转换,也可以使用 BiFunction<ChatRequest, Object, ChatRequest> 来配置 chatRequestTransformer() 方法,该函数的第二个参数为记忆 ID。
方法定义如下:
public AiServices<T> chatRequestTransformer(BiFunction<ChatRequest, Object, ChatRequest> chatRequestTransformer) {
this.context.chatRequestTransformer = chatRequestTransformer;
return this;
}使用方式如下:
AiServices.builder(SimpleAiServicesDemo.Assistant.class)
.chatModel(chatModel)
.chatRequestTransformer((originalRequest, memoryId) -> {
//...这里写修改逻辑...
return originalRequest;
})
.build();package com.hxstrive.langchain4j.aiServices;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import java.util.ArrayList;
import java.util.List;
public class RewriteChatRequestDemo2 {
// 推荐:将OPEN_API_KEY设置成环境变量, 避免硬编码或随着代码泄露
// 注意,设置完环境变量记得重启IDEA,不然可能环境变量不会生效
private static final String API_KEY = System.getenv("OPEN_API_KEY");
// 定义业务接口
interface Assistant {
// userMessage 是用户输入的消息
// 返回值是 AI 回复的内容呢
@UserMessage("{{userMessage}}")
String chat(@MemoryId String memoryId, @V("userMessage") String userMessage);
}
public static void main(String[] args) {
// 创建 ChatModel 实现类(OpenAI 为例)
ChatModel chatModel = OpenAiChatModel.builder()
.baseUrl("https://api.xty.app/v1")
.apiKey(API_KEY)
.modelName("gpt-3.5-turbo")
.temperature(0.7)
.logRequests(true)
.logResponses(true)
.build();
final String myMemoryId = "45de4db8-4ed87ef2d44d9fd44dd8b8de";
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
// 使用 AiServices 创建服务
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(chatModel)
// 设置默认的聊天记忆 ChatMemory
.chatMemory(chatMemory)
// 为指定的聊天记忆ID返回 ChatMemory
// 如果聊天记忆ID是特意设计过的,是不是可以通过聊天记忆ID选择不同的 ChatMemory
// 如以 TEMP- 开头的使用内存存储,REDIS- 开头的使用Redis存储,DB- 开头的使用数据库存储
.chatMemoryProvider((chatMemoryId) -> chatMemory)
.chatRequestTransformer((originalRequest, memoryId) -> {
// 步骤1:非空校验,保障健壮性
if (memoryId == null || originalRequest == null) {
return originalRequest;
}
System.out.println("originalRequest: " + originalRequest);
System.out.println("memoryId: " + memoryId);
System.out.println("\n===========================================\n");
// 步骤2:整理消息列表,追加系统提示(要求结合历史记录回答)
List<ChatMessage> modifiedMessages = new ArrayList<>(originalRequest.messages());
SystemMessage customSystemMessage = SystemMessage.from(
"你需要结合用户的历史聊天记录回答问题,回答简洁明了,不超过50字。"
);
modifiedMessages.add(0, customSystemMessage);
// 步骤3:构建修改后的 ChatRequest
return originalRequest.toBuilder()
.messages(modifiedMessages)
.build();
})
.build();
// 发起对话
String answer = assistant.chat(myMemoryId, "你好! 我的名字是张三。");
System.out.println(answer);
String answerWithName = assistant.chat(myMemoryId, "我叫什么名字?");
System.out.println(answerWithName);
}
}运行示例,输出日志如下:
originalRequest: ChatRequest { messages = [UserMessage { name = null, contents = [TextContent { text = "你好! 我的名字是张三。" }], attributes = {} }], parameters = DefaultChatRequestParameters{modelName='null', temperature=null, topP=null, topK=null, frequencyPenalty=null, presencePenalty=null, maxOutputTokens=null, stopSequences=[], toolSpecifications=[], toolChoice=null, responseFormat=null} }
memoryId: 45de4db8-4ed87ef2d44d9fd44dd8b8de
===========================================
14:53:04.315 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP request:
- method: POST
- url: https://api.xty.app/v1/chat/completions
- headers: [Authorization: Beare...00], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "gpt-3.5-turbo",
"messages" : [ {
"role" : "system",
"content" : "你需要结合用户的历史聊天记录回答问题,回答简洁明了,不超过50字。"
}, {
"role" : "user",
"content" : "你好! 我的名字是张三。"
} ],
"temperature" : 0.7,
"stream" : false
}
14:53:11.234 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP response:
- status code: 200
- headers: [:status: 200], [access-control-allow-headers: *], [access-control-allow-methods: POST, GET, OPTIONS, DELETE,PUT], [access-control-allow-origin: *], [access-control-max-age: 3600], [alt-svc: h3=":443"; ma=86400], [cf-cache-status: DYNAMIC], [cf-ray: 9c800266bf47ef92-AMS], [content-length: 555], [content-type: application/json;charset=UTF-8], [date: Tue, 03 Feb 2026 06:53:10 GMT], [nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}], [report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=sk%2Fhph7IveJmtOvYfFAUgHB546oqjvg%2BSRkNCzgHL5C8IU%2B35kgBPDHZvrodMKWfo24HHjc8bGa06vIrjv2aGe5OHeYROZPOCCDv"}]}], [server: cloudflare], [server-timing: [cfCacheStatus;desc="DYNAMIC", cfEdge;dur=7,cfOrigin;dur=3852]], [x-oneapi-request-id: 20260203145307246422021jcpNSSEV]
- body: {
"id": "chatcmpl-zOr5gM9JtpWoj5RwCo4K5GAR2RzYy",
"object": "chat.completion",
"created": 1770101589,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你好,张三!很高兴认识你 😊"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 56,
"completion_tokens": 17,
"total_tokens": 73
},
"system_fingerprint": "fp_b28b39ffa8"
}
你好,张三!很高兴认识你 😊
originalRequest: ChatRequest { messages = [UserMessage { name = null, contents = [TextContent { text = "你好! 我的名字是张三。" }], attributes = {} }, AiMessage { text = "你好,张三!很高兴认识你 😊", thinking = null, toolExecutionRequests = [], attributes = {} }, UserMessage { name = null, contents = [TextContent { text = "我叫什么名字?" }], attributes = {} }], parameters = DefaultChatRequestParameters{modelName='null', temperature=null, topP=null, topK=null, frequencyPenalty=null, presencePenalty=null, maxOutputTokens=null, stopSequences=[], toolSpecifications=[], toolChoice=null, responseFormat=null} }
memoryId: 45de4db8-4ed87ef2d44d9fd44dd8b8de
===========================================
14:53:11.288 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP request:
- method: POST
- url: https://api.xty.app/v1/chat/completions
- headers: [Authorization: Beare...00], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "gpt-3.5-turbo",
"messages" : [ {
"role" : "system",
"content" : "你需要结合用户的历史聊天记录回答问题,回答简洁明了,不超过50字。"
}, {
"role" : "user",
"content" : "你好! 我的名字是张三。"
}, {
"role" : "assistant",
"content" : "你好,张三!很高兴认识你 😊"
}, {
"role" : "user",
"content" : "我叫什么名字?"
} ],
"temperature" : 0.7,
"stream" : false
}
14:53:15.333 [main] INFO dev.langchain4j.http.client.log.LoggingHttpClient -- HTTP response:
- status code: 200
- headers: [:status: 200], [access-control-allow-headers: *], [access-control-allow-methods: POST, GET, OPTIONS, DELETE,PUT], [access-control-allow-origin: *], [access-control-max-age: 3600], [alt-svc: h3=":443"; ma=86400], [cf-cache-status: DYNAMIC], [cf-ray: 9c80028299aaef92-AMS], [content-length: 528], [content-type: application/json;charset=UTF-8], [date: Tue, 03 Feb 2026 06:53:14 GMT], [nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}], [report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=GaYJ1w1r06XOopjn61bPSbBQM55CDDxrEMMUjZv6OjaPNcb%2FWdTG7sbYf8T0ZDFMe%2Fue18YuSnlxbe%2BAh%2FrHtVyTmbT%2BAANuazh4"}]}], [server: cloudflare], [server-timing: [cfCacheStatus;desc="DYNAMIC", cfEdge;dur=2,cfOrigin;dur=3468]], [x-oneapi-request-id: 20260203145311537327136OkNWVRe7]
- body: {
"id": "chatcmpl-q2RGh2XEDdxzsgcayt8xo6KQWu7K1",
"object": "chat.completion",
"created": 1770101594,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你叫张三。"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 90,
"completion_tokens": 6,
"total_tokens": 96
},
"system_fingerprint": "fp_b28b39ffa8"
}
你叫张三。
Process finished with exit code 0更多 LangChain4j 知识请阅读后续教程……