Spring AI 整合大模型:Prompt 提示词的标准化设计与最佳实践

Prompt

思维导图

为什么需要有这个?

这是用户发给大模型的完整对话输入,设计一个好的prompt,能够更好的让大模型懂用户的意图,因此设计了prompt让大模型更好的理解用户的意图。

Prompt组成

  • 角色(Role)
    给模型设定身份和视角,如"你是一名医疗AI领域专家"。
  • 指令(Instruction)
    明确告诉模型要做什么任务,这是最核心部分。
  • 上下文(Context)
    提供任务背景、受众、应用场景等信息,帮助模型理解语境。
  • 输入(Input)
    模型需要处理的具体数据或内容。
  • 输出(Output Indicator)
    明确输出的格式、结构、风格,如 Markdown、JSON、列表等,但是模型输出不一定按照给出的格式进行百分百的输出
  • 约束(Constraints)
    对结果进行限制,如字数、语气、必须包含的内容、不允许的内容等。
要素 语义作用 Spring AI 对应
Role 角色定位 SystemMessage
Instruction 任务定义 PromptTemplate 主体
Context 场景说明 SystemMessage/模板变量
Input 输入数据 UserMessage/{input}
Output Indicator 输出格式 模板中"输出要求"
Constraints 行为边界 模板中"约束说明"

Prompt = 角色 + 指令 + 上下文 + 输入 + 输出指示 + 约束

在工程中应当把它们"接口化、模板化、结构化",而不是随意拼接一句话,这个大模型能够更加准确的理解用户的意图。

Spring AI相关的接口

组件 包路径(示意) 作用
Prompt org.springframework.ai.chat.prompt.Prompt Prompt 的核心接口/类,封装所有消息
PromptTemplate org.springframework.ai.chat.prompt.PromptTemplate 模板化 Prompt,支持变量替换
Message org.springframework.ai.chat.messages.Message 所有消息的父接口
SystemMessage org.springframework.ai.chat.messages.SystemMessage 角色 + 上下文
UserMessage org.springframework.ai.chat.messages.UserMessage 用户输入
AssistantMessage org.springframework.ai.chat.messages.AssistantMessage few-shot 示例
ChatClient org.springframework.ai.chat.client.ChatClient 调用模型的客户端
ChatResponse org.springframework.ai.chat.ChatResponse 模型返回结果

prompt 接口核心组成

java 复制代码
public class Prompt implements ModelRequest<List<Message>>{
    private final List<Message> messages;

   // 封装了大模型的可选参数,后续说明
    private final ChatOptions options;
}

//ModelRequest = 发给大模型的一次"完整请求"抽象
public interface ModelRequest<T> {
   // 真正要交给模型的输入内容"
    T getInstructions();

  //这次请求调用模型时的参数配置  
    ModelOptions getOptions();
}
接口方法 Prompt 内部字段
getInstructions() messages
getOptions() options

Message

每一条 Message 都包含:

  • 文本内容(Content): 人类能读懂、模型直接处理的文本本体
  • 元数据(Metadata):大模型的附加消息,存放模型的行管的附加消息,便于后续的处理。后续接口模块详细说明

这些不是写给模型看的,而是给服务端程序用来分辨、分类、管理消息流的辅助信息。

  • 消息类型(MessageType / Role)

Message / Content / MediaContent 接口层级

java 复制代码
public interface Content {
    //文本的内容
    String getContent();  

    //元数据
    Map<String, Object> getMetadata();
}

public interface Message extends Content {
    //消息角色,是下述的枚举类型
    MessageType getMessageType();
}

public enum MessageType {
    USER("user"),
    ASSISTANT("assistant"),
    SYSTEM("system"),
    TOOL("tool");
}


//带附件的消息接口,普通的Content 只有文本+元数据 而 MediaContent 在此基础上还能带一组 Media(多媒体附件)
public interface MediaContent extends Content {

    Collection<Media> getMedia();

}

Metadata 会放什么内容?举几个常见且实际会用到的例子:

元数据 Key 意义 用途
**userId** 用户身份 系统识别用户、区分对话
**sessionId** 会话 ID 统计、上下文区分
**messageId** 当前消息编号 唯一标识一条消息
**timestamp** 时间戳 排序、日志分析
**priority** 优先级 决策调度(比如高优先级消息)

java 复制代码
Message (interface)
 ├── SystemMessage    → Role(系统角色) + Context 
 ├── UserMessage      → Input + Instruction
 ├── AssistantMessage → 示例(Few-shot)
 └── ToolMessage      → 工具调用结果(高级用法)

**SystemMessage:**系统限制信息,权重最大,AI会有优先根据这个进行内容进行回复

**UserMessage:**用户发送的消息

**AssistantMessage:**AI回复的消息

ToolMessage: 工具返回的消息

ChatOptions

ChatOptions封装了大模型的可选参数

  • 模型选择(model)
  • 温度(temperature,控制随机性)
  • topP/topK(采样方式)
  • 最大输出长度(maxTokens)
  • 惩罚项(presencePenalty/FrequencyPenalty):控制模型生成时的重复问题,数值越大,模型越倾向于往"新话题"拓展。

Prompt = 内容 + 参数

java 复制代码
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.messages.*;
import org.springframework.ai.chat.options.ChatOptions;

import java.util.List;
import java.util.Map;

// 1️⃣ 构建消息内容(Prompt 的"内容部分")
List<Message> messages = List.of(

    // SYSTEM:最高优先级规则
    new SystemMessage(
        "你是一个订单查询助手,只能根据工具返回的数据回答问题。",
        //系统元数据
        Map.of("sessionId", "session-001", "policy", "NO_HALLUCINATION")
    ),

    // USER:用户输入
    new UserMessage(
        "帮我查一下订单 10002 的状态",
       //  用户身份元数据
        Map.of("userId", "u-888", "channel", "web")
    ),

    // TOOL:工具真实返回
    new ToolMessage(
        "{ \"orderId\": \"10002\", \"status\": \"已签收\" }",
        //工具元数据
        Map.of("toolName", "OrderQueryService", "latencyMs", 42)
    )
);

// 2️⃣ 构建 ChatOptions(Prompt 的"参数部分")
ChatOptions options = ChatOptions.builder()
        .withModel("gpt-4.1-mini")      // 模型选择
        .withTemperature(0.2)          // 随机性低,偏确定性
        .withTopP(0.9)                 // nucleus sampling
        .withMaxTokens(100)            // 最大输出长度
        .withPresencePenalty(0.6)      // 鼓励引入新内容
        .withFrequencyPenalty(0.2)     // 减少重复
        .build();

// 3️⃣ Prompt = 内容 + 参数
Prompt prompt = new Prompt(messages, options);

** 内容部分(Messages)**

  1. SystemMessage → 定规则
  2. UserMessage → 提问题
  3. ToolMessage → 给事实

参数部分(ChatOptions)

参数 作用
model 用哪个大模型
temperature 回答随机性
topP 采样策略
maxTokens 最大输出长度
presencePenalty 鼓励"新话题"
frequencyPenalty 降低重复

说白了这个prompt,简单点说就是不同的角色+元数据(不同角色的附加信息)。

PromptTemplate

上述的接口,足以创建提示词,为啥还需要这个PromptTemplate,从这个名字就可以看出来,这个作用,提示词模版。官方解释:使用该类<font style="color:rgb(25, 30, 30);">PromptTemplate</font>来处理用户和系统文本,并根据给定的实现,在运行时将变量替换为提供的值<font style="color:rgb(25, 30, 30);">TemplateRenderer</font>这还是比较拗口,难以理解,我们换种说法,PromptTemplate 是"用来生成 Prompt 的模板工具"。Prompt每次创建都需要说明,系统身份,还需要表明背景,上下文信息,以及指令的需求,而PromptTemplate 解决的问题是:不想在代码里到处拼字符串,不想每次都 new Prompt 手写内容。想用"模板 + 变量"的方式批量生产 Prompt。直接举个例子进行说明这个。

不使用模版创建Prompt提示词

java 复制代码
String systemText = "你是一名耐心的中文少儿科普老师。";
SystemMessage systemMessage = new SystemMessage(systemText);

//用户的中获取
String topic = "火山爆发";
int age = 10;

String userText = "请用适合 " + age + " 岁孩子理解的方式,讲解一下 " 
        + topic + ",并举一个生活中的例子。";

UserMessage userMessage = new UserMessage(userText);

Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

使用模版创建Prompt提示词

java 复制代码
// System 模板
String systemText = "你是一名耐心的中文少儿科普老师。";
SystemMessage systemMessage = new SystemMessage(systemText);

// User 模板
String userTemplate = """
请用适合 {age} 岁孩子理解的方式,
讲解一下 {topic},并举一个生活中的例子。
""";

PromptTemplate userPromptTemplate = new PromptTemplate(userTemplate);

// 用户输入
Map<String, Object> vars = Map.of(
    "topic", "火山爆发",
    "age", 10
);

// 用模板生成 UserMessage
Message userMessage = userPromptTemplate.createMessage(vars);

// 构建 Prompt
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

可以看出来,使用模版可以进行复用,减少了相关的拼接过程。

可以用一句话概括:
PromptTemplate = 提示词模板引擎 + 变量渲染器 + Message / Prompt 生产器

它做三件事:

能力 对应方法
存模板 template字符串 / Resource
填变量 render() / render(Map)
造对象 createMessage()/ create()
类层级结构
java 复制代码
PromptTemplate  (核心模板引擎)
 ├── SystemPromptTemplate     → 产 SystemMessage
 ├── AssistantPromptTemplate  → 产 AssistantMessage
 └── FunctionPromptTemplate   → 产 FunctionMessage(工具/函数)

也就是说:PromptTemplate 负责"怎么把模板变成文字",子类负责"这段文字属于哪个角色"

PromptTemplate核心组成
java 复制代码
private String template; // 模板文本,例如 "告诉我 {city} 的天气"
private final Map<String, Object> variables;// 模板变量,如 {city -> 北京}
private final TemplateRenderer renderer;   // 渲染器(负责把 {city} 替换成 北京)
方法 作用
render() 把模板 + 变量 → 生成最终字符串
createMessage() 用 render 结果 → 生成 UserMessage
create() 用 render 结果 → 生成 Prompt
create(vars, options) 生成带 ChatOptions 的 Prompt
java 复制代码
String text = "请给我推荐 {city} 的 3 个旅游景点";

PromptTemplate pt = new PromptTemplate(text);

Map<String, Object> vars = Map.of("city", "杭州");

// 👉 生成 UserMessage
Message userMsg = pt.createMessage(vars);

// 👉 生成 Prompt
Prompt prompt = pt.create(vars);

//生成的效果是这样的
UserMessage: "请给我推荐 杭州 的 3 个旅游景点"
SystemPromptTemplate
java 复制代码
public class SystemPromptTemplate extends PromptTemplate {
    public Message createMessage() {
        return new SystemMessage(this.render());
    }
}

和 PromptTemplate 唯一的区别:它不是产 UserMessage,而是产 SystemMessage

String systemText = "你是一个旅游专家,只能用中文回答,不要超过 100 字";

SystemPromptTemplate sysPt = new SystemPromptTemplate(systemText);

Message systemMsg = sysPt.createMessage();

得到:

plain 复制代码
SystemMessage: "你是一个旅游专家,只能用中文回答,不要超过 100 字"
AssistantPromptTemplate
java 复制代码
public class AssistantPromptTemplate extends PromptTemplate {
    public Message createMessage() {
        return new AssistantMessage(this.render());
    }
}
java 复制代码
String assistantText = "当然可以,我来为你介绍一下杭州。";

AssistantPromptTemplate ap = new AssistantPromptTemplate(assistantText);

Message assistantMsg = ap.createMessage();

//得到结果
AssistantMessage: "当然可以,我来为你介绍一下杭州。"
FunctionPromptTemplate(函数工具角色)
java 复制代码
public class FunctionPromptTemplate extends PromptTemplate {
    private String name;
}

这个用于 Tool / Function Calling 场景,给模型一个"函数说明模板"

java 复制代码
SystemPromptTemplate sysPt =
        new SystemPromptTemplate("你是一个旅游专家,只用中文回答");

PromptTemplate userPt =
        new PromptTemplate("请给我推荐 {city} 的 2 个景点");

AssistantPromptTemplate asPt =
        new AssistantPromptTemplate("好的,我来帮你推荐。");


//创建message
Message systemMsg = sysPt.createMessage();
Message userMsg = userPt.createMessage(Map.of("city", "成都"));
Message assistantMsg = asPt.createMessage();

Prompt prompt = new Prompt(List.of(systemMsg, userMsg, assistantMsg));
相关推荐
翱翔的苍鹰2 小时前
完整的“RNN + jieba 中文情感分析”项目之一:添加 API 接口(FastAPI) 和 支持 批量分析
人工智能·rnn·fastapi
安畅检测齐鲁物联网测试中心2 小时前
企业数字化转型
人工智能
驭白.2 小时前
当硬件成为载体:制造端如何支撑持续的OTA与功能进化?
大数据·人工智能·ai·制造·数字化转型·制造业·新能源汽车
北京耐用通信2 小时前
耐达讯自动化Profibus光纤中继模块实现冶金车间长距离抗干扰通信
人工智能·物联网·网络协议·自动化·信息与通信
zy_destiny2 小时前
SegEarth-OV系列(二):面向遥感图像的无训练开放词汇分割
人工智能·深度学习·算法·机器学习·计算机视觉·语义分割·开放词汇
NCU_wander2 小时前
RAG Embedding Reranker 、Bert、CLIP&T5
人工智能·深度学习·bert
武汉唯众智创2 小时前
基于大语言模型的自助式 AI 心理咨询系统
人工智能·语言模型·自然语言处理·大语言模型·自助式 ai 心理咨询系统·ai 心理咨询系统·ai 心理咨询
Python_Study20252 小时前
制造业数字化转型中的数据采集系统:技术挑战、架构方案与实施路径
大数据·网络·数据结构·人工智能·架构
敲上瘾2 小时前
用Coze打造你的专属AI应用:从智能体到Web部署指南
前端·人工智能·python·阿里云·aigc