langchain4j笔记-05

AI Services

简单使用
java 复制代码
public static StreamingChatModel STREAMING_BASE_MODEL = OpenAiStreamingChatModel.builder()
            .baseUrl("https://api.deepseek.com")
            .apiKey(System.getenv("DS_API_KEY"))
            .modelName("deepseek-v4-flash")
            .logRequests(true)
            .logResponses(true)
            .build();
java 复制代码
interface Assistant {
    String chat(String userMessage);
}
java 复制代码
@Test
void test01() {
    /**
     * 您将接口的Class与底层组件一起提供给AiServices,然后AiServices会创建一个实现该接口的代理对象。
     * 目前这一过程使用的是反射机制,但我们也在考虑其他替代方案。
     * 这个代理对象会处理所有输入和输出的转换。在本例中,输入是一个简单的String,但我们使用的是以ChatMessage作为输入的ChatModel。
     * 因此,AiService会自动将其转换为UserMessage并调用ChatModel。
     * 由于chat方法的输出类型是String,当ChatModel返回AiMessage后,该消息会在chat方法返回之前被转换为String类型。
     */
    Assistant assistant = AiServices.create(Assistant.class, BASE_MODEL);
    String answer = assistant.chat("Hello");
    System.out.println(answer);
}
添加SystemMessage

方式一:通过注解,但是注解可以是文本,也可以从配置文件获取

java 复制代码
interface Friend {

    //@SystemMessage("你是一个AI建模专家,只能回答关于脑建立的建模问题。")
    @SystemMessage(fromResource = "my-prompt-template.txt")
    String chat(String userMessage);
}

@Test
void test02() {
    Friend friend = AiServices.create(Friend.class, BASE_MODEL);
    String answer = friend.chat("腿抽筋怎么办");
    System.out.println(answer);
    // 我专注于脑建立的建模问题,无法提供医疗建议。建议你咨询医生或查看可靠的健康资源来处理腿抽筋。如果你有关于脑建模(例如神经网络、认知架构等)的问题,我很乐意帮助!
}

方式二:通过代码配置(可以给不同的chatMemoryId提供不同的SystemMessage)

java 复制代码
@Test
void test03() {
    Friend friend = AiServices.builder(Friend.class)
            .chatModel(BASE_MODEL)
            .systemMessageProvider(chatMemoryId -> "你是一个AI建模专家,只能回答关于脑建立的建模问题。")
            .build();
    String answer = friend.chat("腿抽筋怎么办");
    System.out.println(answer);
    // 抱歉,我无法回答关于腿抽筋的医学建议。。。。。。。。。
}
在运行时修改系统提示词, 使用 System Message Transformer
java 复制代码
@Test
void test04() {
    Friend friend = AiServices.builder(Friend.class)
            .chatModel(BASE_MODEL)
            .systemMessageProvider(chatMemoryId -> "你是我的好朋友,请用俚语回答.")
            .systemMessageTransformer(systemMessage -> systemMessage + " Today's date is " + LocalDate.now() + ".")
            .build();
    String answer = friend.chat("腿抽筋怎么办");
    System.out.println(answer);
}

请求的部分json如下:

json 复制代码
{
    "role" : "system",
    "content" : "你是我的好朋友,请用俚语回答. Today's date is 2026-05-12."
}
获取上下文参数
java 复制代码
@Test
void test05() {
    Friend friend = AiServices.builder(Friend.class)
            .chatModel(BASE_MODEL)
            .systemMessageProvider(chatMemoryId -> "你是我的好朋友,请用俚语回答.")
            .systemMessageTransformer((systemMessage, context) ->
                    systemMessage + " Tenant: " + context.invocationParameters().get("tenant") + ".")
            .build();

    String answer = friend.chat("腿抽筋怎么办");
    System.out.println(answer);

}
// "content" : "你是我的好朋友,请用俚语回答. Tenant: null."

UserMessage

java 复制代码
interface Friend {

    @UserMessage("你是我的好朋友,请用俚语回答. {{it}}")
    String chat(String userMessage);
}
java 复制代码
interface Friend {

    @UserMessage("You are a good friend of mine. Answer using slang. {{message}}")
    String chat(@V("message") String userMessage);
}
配置 ChatMemory
java 复制代码
@Test
    void test01() {

        //RedisChatMemoryStore chatMemoryStore = new RedisChatMemoryStore("192.168.6.15:6379", 6349, 11, userId, "redis@2025");
        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .id(UUID.randomUUID().toString())
                .chatMemoryStore(new InMemoryChatMemoryStore())
                .maxMessages(10).build();

        Friend friend = AiServices.builder(Friend.class)
                .chatModel(BASE_MODEL)
                .systemMessageProvider(chatMemoryId -> "你是一个智能助手")
                .chatMemory(chatMemory)
                .build();

        List<String> questions = new ArrayList<>();
        questions.add("北京大学是211么?");
        questions.add("是985么?");
        questions.add("是双一流么?");

        for (String userMessage : questions) {
            String answer = friend.chat(userMessage);
            System.out.println(answer);
        }
    }
通过程序对 ChatRequest 重写
java 复制代码
/**
 * 通过程序对 ChatRequest 重写
 */
@Test
void test02() {
    Assistant assistant = AiServices.builder(Assistant.class)
            .chatModel(BASE_MODEL)
            .chatRequestTransformer(new UnaryOperator<ChatRequest>() {
                @Override
                public ChatRequest apply(ChatRequest chatRequest) {
                    List<ChatMessage> messages = chatRequest.messages();
                    System.out.println(messages.getLast().toString());
                    return chatRequest;
                }
            })  // Configures the transformation function to be applied to the ChatRequest
            .build();

    String res = assistant.chat("你好");
    System.out.println(res);

}
获取ChatRequest同时也需要获取ChatMemory,不过这里存在问题
java 复制代码
/**
 * 如果需要同时访问 ChatMemory 来实现所需的 ChatRequest 转换,
 * 还可以通过配置 chatRequestTransformer 方法并传入一个
 * BiFunction<ChatRequest, Object, ChatRequest> 来实现,
 * 其中传递给该函数的第二个参数是 memory ID。
 */
@Test
void test03() {
    ChatMemory chatMemory = MessageWindowChatMemory.builder()
            .id(UUID.randomUUID().toString())
            .chatMemoryStore(new InMemoryChatMemoryStore())
            .maxMessages(10).build();

    System.out.println(chatMemory.id()); // 这里输出的uuid字符串

    Assistant assistant = AiServices.builder(Assistant.class)
            .chatModel(BASE_MODEL)
            .chatMemory(chatMemory)
            .chatRequestTransformer(new BiFunction<ChatRequest, Object, ChatRequest>() {

                /**
                 *
                 * @param chatRequest ChatRequest
                 * @param o memoryID
                 * @return
                 */
                @Override
                public ChatRequest apply(ChatRequest chatRequest, Object o) {
                    System.out.println(o.toString()); // 这里输出的是default,和上面的ChatMemoryId 不一样
                    //todo: 这里需要排查为什么????
                    return chatRequest;
                }
            })
            .build();

    String res = assistant.chat("你好");
    System.out.println(res);

}
请求的时候携带请求参数
java 复制代码
interface AssistantWithChatParams {

    String chat(@UserMessage String userMessage, ChatRequestParameters params);
}
java 复制代码
@Test
void test04() {

    AssistantWithChatParams assistant = AiServices.builder(AssistantWithChatParams.class)
            .chatModel(BASE_MODEL)  // or whichever model
            .build();

    ChatRequestParameters customParams = ChatRequestParameters.builder()
            .temperature(0.85)
            .build();

    String answer = assistant.chat("Hi there!", customParams);

}
SystemMessage 和 UserMessage 注解混合
java 复制代码
interface Friend {

    @UserMessage("你是我的好朋友,请用俚语回答. {{it}}")
    String chat(String userMessage);


    @SystemMessage("Given a name of a country, {{answerInstructions}}")
    @UserMessage("{{country}}")
    String chat(@V("answerInstructions") String answerInstructions, @V("country") String country);
}
多模态
java 复制代码
String chat(@UserMessage AudioContent audio, @UserMessage ImageContent image);
返回类型
java 复制代码
interface Assistant {

    String chat(String message);

    @UserMessage("产生一个给定主题的文章的大纲: {{it}}")
    Result<List<String>> generateOutlineFor(String topic);
}

@Test
void test05() {
    Assistant assistant = AiServices.builder(Assistant.class)
            .chatModel(BASE_MODEL)  // or whichever model
            .build();
    Result<List<String>> result = assistant.generateOutlineFor("软件架构设计");
    List<String> outline = result.content();
    TokenUsage tokenUsage = result.tokenUsage();
    List<Content> sources = result.sources();
    List<ToolExecution> toolExecutions = result.toolExecutions();
    FinishReason finishReason = result.finishReason();
}
返回pojo
java 复制代码
import dev.langchain4j.service.UserMessage;
import lombok.Data;

import java.time.LocalDate;

interface PersonExtractor {

    @UserMessage("Extract information about a person from {{it}}")
    Person extractPersonFrom(String text);
}

@Data
class Person {

    String firstName;
    String lastName;
    LocalDate birthDate;
    Address address;
}

@Data
class Address {
    String street;
    Integer streetNumber;
    String city;
}
测试
java 复制代码
    @Test
    void test06() {

        PersonExtractor personExtractor = AiServices.create(PersonExtractor.class, BASE_MODEL);

        String text = """
            In 1968, amidst the fading echoes of Independence Day,
            a child named John arrived under the calm evening sky.
            This newborn, bearing the surname Doe, marked the start of a new journey.
            He was welcomed into the world at 345 Whispering Pines Avenue
            a quaint street nestled in the heart of Springfield
            an abode that echoed with the gentle hum of suburban dreams and aspirations.
            """;

        Person person = personExtractor.extractPersonFrom(text);

        //Person(firstName=John, lastName=Doe, birthDate=1968-07-04, address=Address(street=Whispering Pines Avenue, streetNumber=345, city=Springfield))
        System.out.println(person);

    }
大模型的JSON模式: the LLM will be forced to respond with a valid JSON.
java 复制代码
public static final ChatModel BASE_MODEL = OpenAiChatModel.builder()
        .baseUrl("https://api.deepseek.com")
        .apiKey(System.getenv("DS_API_KEY"))
        .modelName("deepseek-v4-flash")
        .strictJsonSchema(true) // 指定为json格式
        .logRequests(true)
        .logResponses(true)
        .build();
streaming
java 复制代码
interface Assistant {
    TokenStream chat(String message);
}
java 复制代码
@Test
void test01() {

    Assistant assistant = AiServices.create(Assistant.class, STREAMING_BASE_MODEL);

    TokenStream tokenStream = assistant.chat("给我讲个笑话");

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

    tokenStream
            .onPartialResponse((String partialResponse) -> System.out.println(partialResponse))
            //.onPartialThinking((PartialThinking partialThinking) -> System.out.println(partialThinking))
            //.onRetrieved((List<Content> contents) -> System.out.println(contents))
            //.onIntermediateResponse((ChatResponse intermediateResponse) -> System.out.println(intermediateResponse))
            // This will be invoked every time a new partial tool call (usually containing a single token of the tool's arguments) is available.
            //.onPartialToolCall((PartialToolCall partialToolCall) -> System.out.println(partialToolCall))
            // This will be invoked right before a tool is executed. BeforeToolExecution contains ToolExecutionRequest (e.g. tool name, tool arguments, etc.)
            //.beforeToolExecution((BeforeToolExecution beforeToolExecution) -> System.out.println(beforeToolExecution))
            // This will be invoked right after a tool is executed. ToolExecution contains ToolExecutionRequest and tool execution result.
            //.onToolExecuted((ToolExecution toolExecution) -> System.out.println(toolExecution))
            .onCompleteResponse((ChatResponse response) -> futureResponse.complete(response))
            .onError((Throwable error) -> futureResponse.completeExceptionally(error))
            .start();

    futureResponse.join(); // Blocks the main thread until the streaming process (running in another thread) is complete
}
返回Flux
xml 复制代码
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
    <version>1.14.1-beta24</version>
</dependency>
java 复制代码
interface Assistant {
    //TokenStream chat(String message);
    Flux<String> chat(String message);
}
java 复制代码
@Test
void test01() {
    Assistant assistant = AiServices.create(Assistant.class, STREAMING_BASE_MODEL);
    Flux<String> chat = assistant.chat("给我讲个笑话,200字以上");
    CompletableFuture<ChatResponse> futureResponse = new CompletableFuture<>();
    chat.doOnNext(System.out::print).subscribe();  // 触发执行
    futureResponse.join();
}
相关推荐
bukeyiwanshui1 小时前
20260512 docker笔记
linux·运维·笔记·docker·容器
奋斗的小乌龟1 小时前
langchain4j笔记-04
笔记
他是龙5512 小时前
SQLi-Labs 通关笔记(Less-38 ~ Less-53):堆叠注入与 ORDER BY 注入
数据库·笔记·less
渣渣灰95872 小时前
U-Boot启动流程
经验分享·笔记
问心无愧05132 小时前
ctf show web入门48
android·前端·笔记
咸甜适中2 小时前
rust语言学习笔记Trait之Default(默认值)
笔记·学习·rust
半导体守望者2 小时前
RF电源架构设计匹配器设计步骤功率放大器拓扑图滤波器设计电路布局设计指南
经验分享·笔记·功能测试·自动化·制造
智者知已应修善业2 小时前
【51单片机一个按键切合初始流水灯按一下对半闪烁按一下显示时间】2023-10-16
c++·经验分享·笔记·算法·51单片机
奋斗的小乌龟2 小时前
langchain4j笔记-03
笔记