AI Services:注解 @SystemMessage

@SystemMessage 是 LangChain4j 提供的一个注解,专门用于为 AI 模型设置系统级提示(System Prompt)。

系统提示的作用是定义 AI 的行为准则、角色定位、回答风格等基础规则,是 AI 生成回复的核心上下文依据,优先级高于用户输入的提示(User Prompt)。

@SystemMessage 可以指定每次调用 AI 服务时要使用的完整系统消息(提示词)或系统消息模板。示例如下:

interface Assistant {

    @SystemMessage("You are a helpful assistant")
    String chat(String userMessage);
}

系统消息可以包含模板变量,这些变量将通过带有 @V 注解的方法参数中的值来解析。例如:

interface Assistant {

    @SystemMessage("You are a {{characteristic}} assistant")
    String chat(@UserMessage String userMessage, @V("characteristic") String characteristic);
}

注意:@SystemMessage 和 AiServices.systemMessageProvider(Function) 时,@SystemMessage 具有更高的优先级。

@SystemMessage 定义

该注解位于 dev.langchain4j.service 包下面,定义如下:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemMessage {
    // 提示模板可以定义为一行或多行。如果模板定义为多行,这些行将通过下面定义的分隔符连接起来。
    String[] value() default {""};
    // 当 value 为多字符串数组时,用于拼接各段文本的分隔符。
    String delimiter() default "\n";
    // 读取提示模板的资源。如果未指定资源,则提示模板取自 value()。
    // 如果未找到该资源,将抛出IllegalConfigurationException。
    // 资源将通过在 AI 服务类(接口)上调用 Class.getResourceAsStream(String) 的方式来读取
    String fromResource() default "";
}

@SystemMessage 简单示例

现在,让我们来看一个更复杂的例子。我们会强制大型语言模型使用俚语(Slang)来回复 😉。

注意:Slang(俚语)是一种非正式的语言变体,通常在特定群体(如年轻人、特定职业人群、亚文化圈等)中流通,核心特点是打破常规语法或词汇规则,追求表达的生动性、亲切感或群体归属感。

下面示例,将通过 @SystemMessage 注解为 chat() 接口提供系统提示词(SystemMessage):

interface Friend {
    // 这里是系统提示词
    @SystemMessage("你是我的好哥们儿/好姐们儿。用俚语来回答哈。")
    String chat(String userMessage);
}

// 发起会话
Friend friend = AiServices.create(Friend.class, model);
String answer = friend.chat("你好"); // Hey! What's up?

在上面示例中,我们添加了带有我们想要使用的系统提示模板的 @SystemMessage 注解。这将在后台转换为 SystemMessage,并与 UserMessage 一起发送给大语言模型(LLM)。

完整示例如下:

package com.hxstrive.langchain4j.aiServices;

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;

public class AnnotationSystemMessageDemo {
    // 推荐:将OPEN_API_KEY设置成环境变量, 避免硬编码或随着代码泄露
    // 注意,设置完环境变量记得重启IDEA,不然可能环境变量不会生效
    private static final String API_KEY = System.getenv("OPEN_API_KEY");

    // 定义业务接口
    interface Friend {
        @SystemMessage("你是我的好哥们儿/好姐们儿。用俚语来回答哈。")
        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(false)
                .build();

        // 使用 AiServices 创建服务
        Friend assistant = AiServices.builder(Friend.class)
                .chatModel(chatModel)
                .build();

        // 发起对话
        String answer = assistant.chat("你好! ");
        System.out.println(answer);
    }
}

运行示例,输出如下:

[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.7,
  "stream" : false
}

哟~来啦老铁 😄  
最近咋样?干啥呢,唠两句!

注意,@SystemMessage 还可以从资源中加载提示模板,例如:

@SystemMessage(fromResource = "my-prompt-template.txt")

上面注解将从类路下的 my-prompt-template.txt 文件加载系统提示词。

完整示例如下:

package com.hxstrive.langchain4j.aiServices;

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;

public class AnnotationSystemMessageDemo2 {
    // 推荐:将OPEN_API_KEY设置成环境变量, 避免硬编码或随着代码泄露
    // 注意,设置完环境变量记得重启IDEA,不然可能环境变量不会生效
    private static final String API_KEY = System.getenv("OPEN_API_KEY");

    // 定义业务接口
    interface Friend {
        @SystemMessage(fromResource = "my-prompt-template.txt")
        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(false)
                .build();

        // 使用 AiServices 创建服务
        Friend assistant = AiServices.builder(Friend.class)
                .chatModel(chatModel)
                .build();

        // 发起对话
        String answer = assistant.chat("你好! ");
        System.out.println(answer);
    }
}

系统消息提供器

系统消息也可以通过系统消息提供程序(SystemMessageProvider)动态定义,如下:

Friend friend = AiServices.builder(Friend.class)
    .chatModel(model)
    .systemMessageProvider(chatMemoryId -> "你是我的好哥们儿/好姐们儿。用俚语来回答哈。") // 关注这里
    .build();

上面代码中,你可以根据聊天记忆 ID(用户或对话)提供不同的系统消息。systemMessageProvider() 方法是 LangChain4j 中用于自定义系统提示生成逻辑的核心配置方法,定义如下:

public AiServices<T> systemMessageProvider(Function<Object, String> systemMessageProvider) {
    //...
}

该方法用来配置系统消息提供程序,该提供程序会在每次调用 AI 服务时提供一条系统消息(SystemMessage)。当同时配置了 @SystemMessage 和系统消息提供程序时,@SystemMessage 具有更高的优先级。

参数说明:

  • systemMessageProvider - 该 Function(一个函数式接口)接收一个聊天记忆 ID(即标注有 @MemoryId 注解的方法参数值),并返回待使用的系统消息。如果方法中无标注 @MemoryId 注解的参数,该聊天记忆 ID 的值则为 "default"。

注意:函数返回的字符串既可以是完整的系统消息,也可以是包含未解析模板变量(如 {{name}})的系统消息模板,这些变量会通过标注有 @V 注解的方法参数值完成解析。

完整示例:

package com.hxstrive.langchain4j.aiServices;

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.*;

public class AnnotationSystemMessageDemo3 {
    // 推荐:将OPEN_API_KEY设置成环境变量, 避免硬编码或随着代码泄露
    // 注意,设置完环境变量记得重启IDEA,不然可能环境变量不会生效
    private static final String API_KEY = System.getenv("OPEN_API_KEY");

    // 定义业务接口
    interface Friend {
        @UserMessage("{{message}}")
        String chat(@MemoryId String memoryId, @V("message") 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(false)
                .build();

        // 聊天记忆的ID
        final String memoryId = String.valueOf((long)(Math.random()*1000000L));

        ChatMemory chatMemory = MessageWindowChatMemory.builder()
                .id(memoryId)
                .maxMessages(10) // 记忆窗口大小
                .build();

        // 使用 AiServices 创建服务
        Friend assistant = AiServices.builder(Friend.class)
                .chatModel(chatModel)
                .chatMemoryProvider((chatMemoryId) -> chatMemory)
                .systemMessageProvider((chatMemoryId ) -> {
                    System.out.println("chatMemoryId=" + chatMemoryId);
                    if(Long.parseLong(String.valueOf(chatMemoryId)) % 2 == 0) {
                        return "你是我的好哥们儿/好姐们儿。用俚语来回答哈。";
                    } else {
                        return "你是我的好哥们儿/好姐们儿。用正常语言来回答哈。";
                    }
                })
                .build();

        // 发起对话
        String answer = assistant.chat(memoryId, "你好! ");
        System.out.println(answer);
    }
}

运行示例,输出如下:

chatMemoryId=909415
[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.7,
  "stream" : false
}

你好呀!😄  
今天过得咋样?有啥想聊的、想问的,随时说,我在呢。

Process finished with exit code 0

👉更多 LangChain4j 知识请继续阅读后续章节……

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号