Spring AI Alibaba 入门开发2-提示词功能、提示词模板、格式化输出

前置内容:Spring AI Alibaba 入门开发一-CSDN博客

一、提示词(Prompt)------基础

1.1 介绍

Prompt 是引导 AI 模型生成特定输出的输入格式,Prompt 的设计和措辞会显著影响模型的响应。

Prompt 最开始只是简单的字符串,随着时间的推移,prompt 逐渐开始包含特定的占位符,例如 AI 模型可以识别的 "USER:"、"SYSTEM:" 等。阿里云通义模型可通过将多个消息字符串分类为不同的角色,然后再由 AI 模型处理,为 prompt 引入了更多结构。每条消息都分配有特定的角色,这些角色对消息进行分类,明确 AI 模型提示的每个部分的上下文和目的。这种结构化方法增强了与 AI 沟通的细微差别和有效性,因为 prompt 的每个部分在交互中都扮演着独特且明确的角色。

Prompt 中的主要角色(Role)包括:

  • 系统角色(System Role):指导 AI 的行为和响应方式,设置 AI 如何解释和回复输入的参数或规则。这类似于在发起对话之前向 AI 提供说明。
  • 用户角色(User Role):代表用户的输入 - 他们向 AI 提出的问题、命令或陈述。这个角色至关重要,因为它构成了 AI 响应的基础。
  • 助手角色(Assistant Role):AI 对用户输入的响应。这不仅仅是一个答案或反应,它对于保持对话的流畅性至关重要。通过跟踪 AI 之前的响应(其"助手角色"消息),系统可确保连贯且上下文相关的交互。助手消息也可能包含功能工具调用请求信息。它就像 AI 中的一个特殊功能,在需要执行特定功能(例如计算、获取数据或不仅仅是说话)时使用。
  • 工具/功能角色(Tool/Function Role):工具/功能角色专注于响应工具调用助手消息返回附加信息。

1.2 API 概览

Prompt

通常使用 ChatModel 的 call() 方法,该方法接受 Prompt 实例并返回 ChatResponse。

Prompt 类充当有组织的一系列 Message 对象和请求 ChatOptions 的容器。每条消息在提示中都体现了独特的角色,其内容和意图各不相同。这些角色可以包含各种元素,从用户查询到 AI 生成的响应再到相关背景信息。这种安排可以实现与 AI 模型的复杂而详细的交互,因为提示是由多条消息构成的,每条消息都被分配了在对话中扮演的特定角色。

下面是 Prompt 类的截断版本,为简洁起见省略了构造函数和实用方法:

java 复制代码
public class Prompt implements ModelRequest<List<Message>> {

    private final List<Message> messages;

    private ChatOptions chatOptions;
}

Message

Message 接口封装了一个提示文本、一组元数据属性以及一个称为 MessageType 的分类。

该接口定义如下:

java 复制代码
public interface Content {

  String getContent();

  Map<String, Object> getMetadata();
}

public interface Message extends Content {

  MessageType getMessageType();
}

Message 接口的各种实现对应 AI 模型可以处理的不同类别的消息。模型根据对话角色区分消息类别。

1.3 提示词的四个角色

角色在 Spring AI 中表示为枚举:

java 复制代码
public enum MessageType {
  USER("user"),
  ASSISTANT("assistant"),
  SYSTEM("system"),
  TOOL("tool");
}

具体实现类如下:

各角色功能如下:

SYSTEM:设定AI行为边界/角色/定位。指导AI的行为和响应方式,设置AI如何解释和回复输入的.

USER:用户原始提问输入。代表用户的输入他们向AI提出的问题、命令或陈述。

ASSISTANT:AI返回的响应信息,定义为"助手角色"消息。用它可以确保上下文能够连贯的交互,且记忆对话,积累回答。

TOOL:桥接外部服务,可以进行函数调用如,支付/数据查询等操作,类似调用第3方util工具类,后面章节详细介绍。

总结如下:

1.4 开发

新建子工程,项目结构如下:

1、修改pom.xml

XML 复制代码
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-ai-alibaba dashscope-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

2、新增配置文件

复制代码
server.port=8888

#解决中文乱码
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

spring.application.name=ssa-05-Prompt
#Sprig AI Alibaba 相关配置
spring.ai.dashscope.api-key=${qianwen-api}
spring.ai.dashscope.base-url=https://ws-6tq01jo6mtthlhoq.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
#spring.ai.dashscope.chat.options.model=qwen-max

3、新增启动类

java 复制代码
@SpringBootApplication
public class SSA_05_Prompt_Application {
    public static void main(String[] args) {
        SpringApplication.run(SSA_05_Prompt_Application.class, args);
    }
}

4、新增配置类------多模型共存、并分别创建ChatModel和ChatClient对象

java 复制代码
@Configuration
public class LLMConfig {
    //定义各个模型名称
    private final String DEEPSEEK_MODEL = "deepseek-v4-pro";
    private final String QWEN_MODEL = "qwen-max";

    //创建deepseekChatModel
    @Bean(name = "deepseekChatModel")
    public ChatModel deepseekChatModel() {
        return
                DashScopeChatModel.builder().dashScopeApi(
                        DashScopeApi.builder().apiKey(System.getenv("qianwen-api")).build())
                        .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build())
                        .build();

    }

    //创建qwenChatModel
    @Bean(name = "qwenChatModel")
    public ChatModel qwenChatModel() {
        return
                DashScopeChatModel.builder()
                        .dashScopeApi(DashScopeApi.builder().apiKey(System.getenv("qianwen-api")).build())
                        .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
                        .build();
    }

    //创建deepseekChatClient
    @Bean(name = "deepseekChatClient")
    public ChatClient deepseekChatClient(@Qualifier("deepseekChatModel") ChatModel deepseek) {
        return
                ChatClient.builder(deepseek)
                        .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build()).build();
    }

    //创建qwenChatClient
    @Bean(name = "qwenChatClient")
    public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel qwen) {
        return
                ChatClient.builder(qwen)
                        .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build()).build();
    }
}

5、创建Controller------设置SYSTEM

java 复制代码
@RestController
public class Prompt_V1_Controller {

    //创建deepseekChatModel
    @Resource(name = "deepseekChatModel")
    private ChatModel deepseekChatModel;

    //创建qwenChatModel
    @Resource(name = "qwenChatModel")
    private ChatModel qwenChatModel;

    //创建deepseekChatClient
    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;

    //创建qwenChatClient
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;

    //使用SYSTEM角色
    @GetMapping("/v1/chat")
    public Flux<String> chat(String msg){
        return deepseekChatClient.prompt()
                .system("你是一位历史学家,只回答历史问题。其他问题则回复:我是一位历史学家,只回答历史问题!")
                .user(msg)
                .stream()
                .content();
    }
}

6、运行结果如下:

7、修改controller------使用ChatModel调用,注意返回类型。

复制代码
@GetMapping("/v2/chat")
public Flux<ChatResponse> chat2(String msg){
    UserMessage userMessage = new UserMessage(msg);
    SystemMessage systemMessage = new SystemMessage("你是一位历史学家,只回答历史问题。其他问题则回复:我是一位历史学家,只回答历史问题!");
    Prompt prompt = new Prompt(userMessage, systemMessage);
    return qwenChatModel.stream(prompt);
}

8、修改controller------设置ASSISTANT,注意返回类型

复制代码
//使用ASSISTANT角色
@GetMapping("/v3/chat")
public String chat3(String msg){
    AssistantMessage assistantMessage = deepseekChatClient.prompt()
            .user(msg)
            .call()
            .chatResponse()
            .getResult()
            .getOutput();
    return assistantMessage.getText();
}

9、使用TOOL------模拟调用,后面章节会演示

复制代码
//使用tool,模拟调用第三方接口
@GetMapping("/v4/chat")
public String chat4(String city){
    String answer = deepseekChatClient.prompt()
            .user(city + "明天天气如何?")
            .call()
            .chatResponse()
            .getResult()
            .getOutput()
            .getText();
    ToolResponseMessage toolResponseMessage = new ToolResponseMessage(
            List.of(new ToolResponseMessage.ToolResponse("1","获得天气",city))
    );
    String toolResponse = toolResponseMessage.getText();
    return answer + toolResponse;
}

二、提示词(Prompt)------模板

引入占位符(如{占位符变量名})以动态插入内容。

2.1 API介绍

Prompt Template

Spring AI 中用于提示模板的关键组件是 PromptTemplate 类。该类使用 Terence Parr 开发的 OSS StringTemplate 引擎来构建和管理提示。PromptTemplate 类旨在促进结构化提示的创建,然后将其发送到 AI 模型进行处理

java 复制代码
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {

// Other methods to be discussed later

}

该类实现的接口支持提示创建的不同方面:

PromptTemplateStringActions 专注于创建和呈现提示字符串,代表提示生成的最基本形式。

PromptTemplateMessageActions 专门用于通过生成和操作 Message 对象来创建提示。

PromptTemplateActions 旨在返回 Prompt 对象,该对象可以传递给 ChatModel 以生成响应。

虽然这些接口可能在许多项目中没有得到广泛使用,但它们展示了创建提示的不同方法。

实现的接口是

复制代码
java 复制代码
public interface PromptTemplateMessageActions {

Message createMessage();

Message createMessage(List<Media> mediaList);

Message createMessage(Map<String, Object> model);

}

方法 String render():将提示模板渲染为最终字符串格式,无需外部输入,适用于没有占位符或动态内容的模板。

方法 String render(Map<String, Object> model):增强渲染功能以包含动态内容。它使用 Map<String, Object>,其中映射键是提示模板中的占位符名称,值是要插入的动态内容。

复制代码
java 复制代码
public interface PromptTemplateMessageActions {

Message createMessage();

Message createMessage(List<Media> mediaList);

Message createMessage(Map<String, Object> model);

}

方法 Message createMessage():创建一个不带附加数据的 Message 对象,用于静态或预定义消息内容。

方法 Message createMessage(List mediaList):创建一个带有静态文本和媒体内容的 Message 对象。

方法 Message createMessage(Map<String, Object> model):扩展消息创建以集成动态内容,接受 Map<String, Object>,其中每个条目代表消息模板中的占位符及其对应的动态值。

复制代码
java 复制代码
public interface PromptTemplateActions extends PromptTemplateStringActions {

Prompt create();

Prompt create(ChatOptions modelOptions);

Prompt create(Map<String, Object> model);

Prompt create(Map<String, Object> model, ChatOptions modelOptions);

}

方法 Prompt create():生成不带外部数据输入的 Prompt 对象,非常适合静态或预定义提示。

方法 Prompt create(ChatOptions modelOptions):生成一个 Prompt 对象,无需外部数据输入,但具有聊天请求的特定选项。

方法 Prompt create(Map<String, Object> model):扩展提示创建功能以包含动态内容,采用 Map<String, Object>,其中每个映射条目都是提示模板中的占位符及其关联的动态值。

方法 Prompt create(Map<String, Object> model, ChatOptions modelOptions):扩展提示创建功能以包含动态内容,采用 Map<String, Object>,其中每个映射条目都是提示模板中的占位符及其关联的动态值,以及聊天请求的特定选项。

2.2 开发

1、新增子模块,修改pom.xml、新增配置文件、新增配置类、新增启动类,与第一部分一样,不再赘述。相关代码如下:

XML 复制代码
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-ai-alibaba dashscope-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
复制代码
server.port=8888

#解决中文乱码
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

spring.application.name=ssa-06-PromptTemplata
#Sprig AI Alibaba 相关配置
spring.ai.dashscope.api-key=${qianwen-api}
spring.ai.dashscope.base-url=https://ws-6tq01jo6mtthlhoq.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
#spring.ai.dashscope.chat.options.model=qwen-max
java 复制代码
@Configuration
public class LLMConfig {
    //定义各个模型名称
    private final String DEEPSEEK_MODEL = "deepseek-v4-pro";
    private final String QWEN_MODEL = "qwen-max";

    //创建deepseekChatModel
    @Bean(name = "deepseekChatModel")
    public ChatModel deepseekChatModel() {
        return
                DashScopeChatModel.builder().dashScopeApi(
                                DashScopeApi.builder().apiKey(System.getenv("qianwen-api")).build())
                        .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build())
                        .build();

    }

    //创建qwenChatModel
    @Bean(name = "qwenChatModel")
    public ChatModel qwenChatModel() {
        return
                DashScopeChatModel.builder()
                        .dashScopeApi(DashScopeApi.builder().apiKey(System.getenv("qianwen-api")).build())
                        .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
                        .build();
    }

    //创建deepseekChatClient
    @Bean(name = "deepseekChatClient")
    public ChatClient deepseekChatClient(@Qualifier("deepseekChatModel") ChatModel deepseek) {
        return
                ChatClient.builder(deepseek)
                        .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build()).build();
    }

    //创建qwenChatClient
    @Bean(name = "qwenChatClient")
    public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel qwen) {
        return
                ChatClient.builder(qwen)
                        .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build()).build();
    }
}
java 复制代码
@SpringBootApplication
public class SSA_06_PromptTemplate {
    public static void main(String[] args) {
        SpringApplication.run(SSA_06_PromptTemplate.class, args);
    }
}
java 复制代码
@RestController
public class PromptTemplateController {
    //创建deepseekChatModel
    @Resource(name = "deepseekChatModel")
    private ChatModel deepseekChatModel;

    //创建qwenChatModel
    @Resource(name = "qwenChatModel")
    private ChatModel qwenChatModel;

    //创建deepseekChatClient
    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;

    //创建qwenChatClient
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;

    @GetMapping("/v1/chat")
    public Flux<String> chat1(String topic,String output_format,String wordCount){
        PromptTemplate promptTemplate = new PromptTemplate("""
                讲一个关于{topic}的故事,
                并以{output_format}格式输出,
                字数控制在{wordCount}以内。
                """);
        Prompt prompt = promptTemplate.create(Map.of("topic", topic, "output_format", output_format, "wordCount", wordCount));
        return deepseekChatClient.prompt(prompt).stream().content();

    }
}

2、PromptTemplate读取模版文件实现模版功能。

在/resource下新建路径,存放模板文件

修改controller

java 复制代码
@RestController
public class PromptTemplateController {
    //创建deepseekChatModel
    @Resource(name = "deepseekChatModel")
    private ChatModel deepseekChatModel;

    //创建qwenChatModel
    @Resource(name = "qwenChatModel")
    private ChatModel qwenChatModel;

    //创建deepseekChatClient
    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;

    //创建qwenChatClient
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;

    @Value("classpath:/prompt-template/01-template.txt")
    private org.springframework.core.io.Resource template;

    @GetMapping("/v1/chat")
    public Flux<String> chat1(String topic,String output_format,String wordCount){
        PromptTemplate promptTemplate = new PromptTemplate("""
                讲一个关于{topic}的故事,
                并以{output_format}格式输出,
                字数控制在{wordCount}以内。
                """);
        Prompt prompt = promptTemplate.create(Map.of("topic", topic, "output_format", output_format, "wordCount", wordCount));
        return deepseekChatClient.prompt(prompt).stream().content();

    }

    @GetMapping("/v2/chat")
    public Flux<String> chat2(String topic,String output_format,String wordCount){
        PromptTemplate promptTemplate = new PromptTemplate(template);
        Prompt prompt = promptTemplate.create(Map.of("topic", topic, "output_format", output_format, "wordCount", wordCount));
        return deepseekChatClient.prompt(prompt).stream().content();
    }
}

3、多角色设定

复制代码
//系统消息:SystemMessage:设定AI的行为规定和功能边界
// 用户消息:用户的提问
@GetMapping("/v3/chat")
public String chat3(String sysTopic,String userTopic){
    SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate("""
            你是{systemTopic}助手,只回答{systemTopic}其他无可奉告,以markdown格式的结果返回。
            """);
    Message sysMessage = systemPromptTemplate.createMessage(Map.of("systemTopic", sysTopic));

    PromptTemplate userPromptTemplate = new PromptTemplate("解释一下{userTopic}");
    Message userMessage = userPromptTemplate.createMessage(Map.of("userTopic", userTopic));
    Prompt prompt = new Prompt(List.of(sysMessage, userMessage));
    return deepseekChatClient.prompt(prompt).call().content();
}

4、分别使用ChatModel和ChatClient实现PromptTemplate人物设定

复制代码
@GetMapping("/v4/chat")
public String chat4(String msg){
    //系统信息
    SystemMessage systemMessage = new SystemMessage("你是一位历史学家,拒绝回答非历史问题");
    //用户信息
    UserMessage userMessage = new UserMessage(msg);
    //完整提示词 = 系统信息 + 用户信息
    Prompt prompt = new Prompt(systemMessage, userMessage);
    //调用大模型
    return deepseekChatModel.call(prompt).getResult().getOutput().getText();
}

@GetMapping("v5/chat")
public Flux<String> chat5(String msg){
    return deepseekChatClient.prompt()
            .system("你是一位历史学家,拒绝回答非历史问题")
            .user(msg)
            .stream().content();
}

三、格式化输出(Structured Output)

3.1 介绍

Structured Output 可以协助将 ChatModel/ChatClient 方法的返回类型从 String 更改为其他类型。LLM 生成结构化输出的能力对于依赖可靠解析输出值的下游应用程序非常重要。开发人员希望快速将 AI 模型的结果转换为可以传递给其他应用程序函数和方法的数据类型,例如 JSON、XML 或 Java 类。Spring AI 结构化输出转换器有助于将 LLM 输出转换为结构化格式。

在 LLM 调用之前,转换器会将期望的输出格式(output format instruction)附加到 prompt 中,为模型提供生成所需输出结构的明确指导,这些指令充当蓝图,塑造模型的响应以符合指定的格式。

在 LLM 调用之后,转换器获取模型的输出文本并将其转换为结构化类型的实例,此转换过程涉及解析原始文本输出并将其映射到相应的结构化数据表示,例如 JSON、XML 或特定于域的数据结构。

当前 Spring AI 提供的 Converter 实现有 AbstractConversionServiceOutputConverter, AbstractMessageOutputConverter, BeanOutputConverter, MapOutputConverter and ListOutputConverter

  • BeanOutputConverter - 使用指定的 Java 类(例如 Bean)或 ParameterizedTypeReference 配置,此转换器指示 AI 模型生成符合 DRAFT_2020_12 的 JSON 响应,JSON 模式派生自指定的 Java 类,随后,它利用 ObjectMapper 将 JSON 输出反序列化为目标类的 Java 对象实例。
  • MapOutputConverter - 该实现指导 AI 模型生成符合 RFC8259 的 JSON 响应,此外,它还包含一个转换器实现,该实现利用提供的 MessageConverter 将 JSON 负载转换为 java.util.Map<String, Object> 实例。
  • ListOutputConverter - 该实现指导 AI 模型生成逗号分隔的格式化输出,最终转换器将模型文本输出转换为 java.util.List。

3.2 开发

1、创建子模块,修改pom.xml,新增启动类、配置文件、配置类。代码分别如下:

XML 复制代码
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--spring-ai-alibaba dashscope-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
java 复制代码
@SpringBootApplication
public class SSA_07_StrucOutputApplication {
    public static void main(String[] args) {
        SpringApplication.run(SSA_07_StrucOutputApplication.class, args);
    }
}
复制代码
server.port=8888

#解决中文乱码
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

spring.application.name=ssa-07-StrucOutput
#Sprig AI Alibaba 相关配置
spring.ai.dashscope.api-key=${qianwen-api}
spring.ai.dashscope.base-url=https://ws-6tq01jo6mtthlhoq.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
#spring.ai.dashscope.chat.options.model=qwen-max
java 复制代码
@Configuration
public class LLMConfig {
    //定义各个模型名称
    private final String DEEPSEEK_MODEL = "deepseek-v4-pro";
    private final String QWEN_MODEL = "qwen-max";

    //定义配置API-KEY的环境变量
    private final String API_KEY = "qianwen-api";

    //创建deepseekChatModel
    @Bean(name = "deepseekChatModel")
    public ChatModel deepseekChatModel() {
        return
                DashScopeChatModel.builder()
                                .dashScopeApi(DashScopeApi.builder().apiKey(System.getenv(API_KEY)).build())
                        .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build())
                        .build();


    }

    //创建qwenChatModel
    @Bean(name = "qwenChatModel")
    public ChatModel qwenChatModel() {
        return
                DashScopeChatModel.builder()
                        .dashScopeApi(DashScopeApi.builder().apiKey(System.getenv(API_KEY)).build())
                        .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
                        .build();
    }

    //创建deepseekChatClient
    @Bean(name = "deepseekChatClient")
    public ChatClient deepseekChatClient(@Qualifier("deepseekChatModel") ChatModel chatModel) {
        return
                ChatClient.builder(chatModel)
                        .defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build())
                        .build();
    }

    //创建qwenChatClient
    @Bean(name = "qwenChatClient")
    public ChatClient qwenChatClient(@Qualifier("qwenChatModel") ChatModel chatModel) {
        return
                ChatClient.builder(chatModel)
                        .defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
                        .build();
    }
}

2、新增record

java 复制代码
public record EmperorInfoRecord(String name,String country,Integer lifespan) { }

3、新增controller

java 复制代码
@RestController
public class StrucOutPutController {
    //创建deepseekChatModel
    @Resource(name = "deepseekChatModel")
    private ChatModel deepseekChatModel;

    //创建qwenChatModel
    @Resource(name = "qwenChatModel")
    private ChatModel qwenChatModel;

    //创建deepseekChatClient
    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;

    //创建qwenChatClient
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;


    @GetMapping("/v1/chat")
    public EmperorInfoRecord chat1(String name,String country,Integer lifespan) {
        return
                qwenChatClient.prompt()
                .user(new Consumer<ChatClient.PromptUserSpec>() {
                    @Override
                    public void accept(ChatClient.PromptUserSpec promptUserSpec) {
                        promptUserSpec.text("姓名:{name},国号:{country},寿命:{lifespan}岁")
                                .param("name",name)
                                .param("country",country)
                                .param("lifespan",lifespan);
                    }
                }).call().entity(EmperorInfoRecord.class);
    }

    //函数式写法
    @GetMapping("/v2/chat")
    public EmperorInfoRecord chat2(String name,String country,Integer lifespan) {
        String template = """
                姓名:{name},国号:{country},寿命:{lifespan}岁
                """;
        return
                qwenChatClient.prompt()
                        .user(promptUserSpec ->promptUserSpec.text(template)
                                .param("name",name)
                                .param("country",country)
                                .param("lifespan",lifespan))
                        .call().entity(EmperorInfoRecord.class);
    }

}
相关推荐
llwszx12 天前
【Java/Go后端手撸原生Agent(第十一篇):RAG检索——给Agent加上“查资料“能力】
llm·向量检索·rag·ai智能体·大模型应用·agent开发·后端转ai
小沈同学呀14 天前
【Agent开发第三期】短期记忆history,让模型“记住“上一句
人工智能·ai编程·agent开发·agent记忆
llwszx20 天前
【Java/Go后端手撸原生Agent(第七篇):Token预算管理 + 滑动窗口上下文裁剪】
java·后端·python·agent开发·上下文工程·上下文裁剪·滑动窗口裁剪
llwszx21 天前
【Java/Go后端手撸原生Agent(第八篇):摘要压缩——让Agent“记要点“而不是“记流水账“】
java·后端·python·agent开发·上下文工程·上下文压缩·上下文管理
NPE~22 天前
[AI]Agent开发——ADK框架使用
人工智能·python·ai·教程·adk·agent开发
llwszx22 天前
【Java/Go后端手撸原生Agent(第九篇):Plan-and-Execute规划模式——从“走一步看一步“到“先谋后动“】
java·python·golang·agent开发·plan模式·规划执行模式
深海鱼肝油ya25 天前
基于FastAPI的AI智能体Web系统构建(二)
人工智能·fastapi·python开发·异步框架·agent开发
早春的树长在理想三旬1 个月前
从LLM到Agent:ReAct推理模式的底层原理
人工智能·spring boot·springai·agent开发
Elias不吃糖2 个月前
AI Resume Forge:基于 LangGraph 的 AI 简历优化与模拟面试平台
java·人工智能·面试·agent开发