【SpringAIAlibaba新手村系列】(5)Prompt 提示词基础与多种消息类型

0 阅读6分钟

第五章 Prompt 提示词基础与多种消息类型

版本标注

  • Spring AI: 1.1.2
  • Spring AI Alibaba: 1.1.2.0

章节定位

  • Prompt 仍然是基础,但在 1.1.2.x 中,Prompt 往往会与 Tool Calling、MCP、RAG、结构化输出、Agent System Prompt、Routing Prompt 一起协同工作。

s01 > s02 > s03 > s04 > [ s05 ] s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > s18

"同一句话, 放在不同消息角色里, 效果可能完全不同" -- Prompt 的本质不是提问, 而是精确表达任务。


一、Prompt 的核心概念

1.1 什么是 Prompt?

Prompt(提示词) 是我们与 AI 沟通的唯一方式,你可以把它理解成:

"给 AI 写的 prompt 就是给 AI 下达的指令或提出的问题"

就像和人沟通一样,你说的越清楚,对方理解得越准确。Prompt 写得好不好,直接决定了 AI 输出的质量。

1.2 Prompt 的组成要素

一个完整的 Prompt 通常由两部分组成:

┌────────────────────────────────────────────────────┐
│                    Prompt 的组成                    │
├────────────────────────────────────────────────────┤
│                                                    │
│  【系统消息 System Message】                        │
│  ─────────────────────────                         │
│  你是一个法律助手,只回答法律相关问题               │
│  其他问题回复"抱歉,我只能回答法律问题"             │
│                                                    │
│  【用户消息 User Message】                          │
│  ──────────────────                                │
│  什么是知识产权法?                                │
│                                                    │
└────────────────────────────────────────────────────┘

1.3 Spring AI 中的消息类型

在 Spring AI 中,消息被抽象为几个类:

消息类型说明典型用途
SystemMessage系统提示词,设定 AI 角色和行为"你是一个Java专家"
UserMessage用户消息,实际的问题"什么是反射?"
AssistantMessageAI 的回复消息记录对话历史
ToolResponseMessage工具调用返回的结果天气查询结果

二、多种模型支持

2.1 多模型配置

本章的项目展示了如何在同一个应用中支持多个不同的 AI 模型:

// 项目中配置了两种模型
@Resource(name = "deepseek")       // DeepSeek 开源模型
private ChatModel deepseekChatModel;

@Resource(name = "qwen")           // 阿里云通义千问
private ChatModel qwenChatModel;

// 对应的两个 ChatClient
@Resource(name = "deepseekChatClient")
private ChatClient deepseekChatClient;

@Resource(name = "qwenChatClient")
private ChatClient qwenChatClient;

2.2 模型选择策略

不同模型有不同的特点:

模型特点适用场景
DeepSeek开源免费,中文能力强成本敏感场景
Qwen (通义千问)阿里云服务稳定,中文优化好生产环境首选

三、项目代码详解

3.1 控制器代码

package com.atguigu.study.controller;

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.ToolResponseMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.List;

/**
 * Prompt 提示词控制器
 * 展示各种 Prompt 的使用方式
 */
@RestController
public class PromptController
{
    // 注入 DeepSeek 模型和 ChatClient
    @Resource(name = "deepseek")
    private ChatModel deepseekChatModel;
    
    @Resource(name = "qwen")
    private ChatModel qwenChatModel;

    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;
    
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;

    /**
     * 方式一:使用 ChatClient 的简洁 API(推荐)
     * 
     * .system() 方法设置系统提示词
     * .user() 方法设置用户消息
     * .stream() 开启流式输出
     *
     * 接口:http://localhost:8005/prompt/chat?question=火锅介绍下
     */
    @GetMapping("/prompt/chat")
    public Flux<String> chat(String question)
    {
        return deepseekChatClient.prompt()
            // system() 设置系统消息:AI的角色设定
            .system("你是一个法律助手,只回答法律问题,"
                   + "其它问题回复,我只能回答法律相关问题,其它无可奉告")
            // user() 设置用户消息
            .user(question)
            // stream() 流式输出
            .stream()
            .content();
    }

    /**
     * 方式二:使用底层 Message 对象(更底层灵活)
     * 
     * 创建 SystemMessage 和 UserMessage 对象
     * 组合成 Prompt 进行调用
     * 
     * 接口:http://localhost:8005/prompt/chat2?question=葫芦娃
     */
    @GetMapping("/prompt/chat2")
    public Flux<ChatResponse> chat2(String question)
    {
        // 1. 系统消息:设定AI为"讲故事助手"
        SystemMessage systemMessage = new SystemMessage(
            "你是一个讲故事的助手,每个故事控制在300字以内"
        );

        // 2. 用户消息:用户的问题
        UserMessage userMessage = new UserMessage(question);

        // 3. 组合成 Prompt
        //    Prompt 是 Message 的容器,可以包含多个消息
        Prompt prompt = new Prompt(userMessage, systemMessage);

        // 4. 调用并返回流式响应
        return deepseekChatModel.stream(prompt);
    }

    /**
     * 方式三:提取响应中的文本
     * 
     * 获取 ChatResponse 对象后,需要手动提取内容
     * 
     * 接口:http://localhost:8005/prompt/chat3?question=葫芦娃
     */
    @GetMapping("/prompt/chat3")
    public Flux<String> chat3(String question)
    {
        SystemMessage systemMessage = new SystemMessage(
            "你是一个讲故事的助手,每个故事控制在600字以内且以HTML格式返回"
        );

        UserMessage userMessage = new UserMessage(question);
        Prompt prompt = new Prompt(userMessage, systemMessage);

        // 使用 map 转换响应,提取文本内容
        // getResults().get(0) 获取第一个结果块
        // getOutput().getText() 获取生成的文本
        return deepseekChatModel.stream(prompt)
            .map(response -> response.getResults().get(0).getOutput().getText());
    }

    /**
     * 方式四:获取 AssistantMessage 对象
     * 
     * 如果需要获取 AI 回复的完整对象(包含元数据)
     * 可以获取 AssistantMessage
     * 
     * 接口:http://localhost:8005/prompt/chat4?question=葫芦娃
     */
    @GetMapping("/prompt/chat4")
    public String chat4(String question)
    {
        // 通过 ChatClient 获取完整响应
        AssistantMessage assistantMessage = deepseekChatClient.prompt()
                .user(question)
                .call()
                .chatResponse()            // 获取 ChatResponse 对象
                .getResult()               // 获取结果
                .getOutput();              // 获取输出消息

        // 通过 getText() 获取文本内容
        return assistantMessage.getText();
    }

    /**
     * 方式五:模拟工具调用场景(ToolResponseMessage)
     * 
     * 这个示例展示了 ToolResponseMessage 的使用场景
     * 实际使用会在 ToolCalling 章节详细讲解
     * 
     * 接口:http://localhost:8005/prompt/chat5?city=北京
     */
    @GetMapping("/prompt/chat5")
    public String chat5(String city)
    {
        // 1. 用户问题:询问城市天气
        String answer = deepseekChatClient.prompt()
                .user(city + "未来3天天气情况如何?")
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();

        // 2. 模拟工具返回结果(实际是外部工具调用的返回值)
        ToolResponseMessage toolResponseMessage = new ToolResponseMessage(
                List.of(
                    // ToolResponse 参数:toolCallId, toolName, content
                    new ToolResponseMessage.ToolResponse("1", "获得天气", city)
                )
        );

        // 3. 组合结果
        //    在实际应用中,会把工具返回的信息再发送给 AI,让它结合信息回答
        String toolResponse = toolResponseMessage.getText();
        String result = answer + toolResponse;

        return result;
    }
}

四、系统消息的最佳实践

4.1 系统消息的作用

系统消息(SystemMessage)就像是给 AI 设置的"人格"和"工作规则":

// ❌ 模糊的系统消息(AI 可能自由发挥)
.system("你是一个助手")

// ✅ 明确的系统消息(AI 知道该怎么做)
.system("""
    你是一个专业的Java技术博主。
    1. 回答问题时优先使用代码示例
    2. 解释概念时要用通俗易懂的语言
    3. 每次回答控制在500字以内
    4. 使用Markdown格式输出代码块
    """)

4.2 优秀的系统消息包含要素

要素说明示例
角色设定AI 是什么身份"你是一个法律顾问"
能力边界能回答什么,不能回答什么"只回答法律相关问题"
输出格式要求如何返回结果"用HTML格式返回"
字数控制要求输出多长"控制在300字以内"
风格要求语气、措辞要求"用通俗易懂的语言"

五、本章小结

5.1 核心概念回顾

概念说明
Prompt提示词,发送给 AI 的完整指令
SystemMessage系统消息,设定 AI 的角色和行为
UserMessage用户消息,用户实际提出的问题
AssistantMessageAI 回复的消息对象
ToolResponseMessage工具调用返回的结果消息

5.2 使用建议

  1. 简单场景:使用 ChatClient.prompt().system().user().call() 链式 API
  2. 需要精细控制:创建 SystemMessage + UserMessage 组装 Prompt
  3. 多模型切换:通过 @Qualifier 区分不同的 ChatModel

本章重点

  1. 理解 Prompt 的组成:系统消息 + 用户消息
  2. 掌握多种创建和使用 Prompt 的方式
  3. 学会在系统中切换使用不同模型

下章剧透(s06):

了解了 Prompt 的基本使用后,下一章我们将学习 PromptTemplate(提示词模板)——如何用占位符实现可复用的提示词。


📝 编辑者:Flittly
📅 更新时间:2026年3月
🔗 相关资源Spring AI Prompt 官方文档