提示(Prompt)
本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。 |
提示词是引导 AI 模型生成特定输出的输入,其设计和措辞显著影响模型响应。
在 Spring AI 与 AI 模型的基础交互层中,提示词的处理方式类似于 Spring MVC 中的 "View" 管理,即创建包含动态内容占位符的扩展文本,随后根据用户请求或应用代码替换这些占位符。另一种类比是包含表达式占位符的 SQL 语句。
随着 Spring AI 的发展,它将引入更高级别的 AI 模型交互抽象。本节描述的基础类在角色和功能上可类比 JDBC — 例如 ChatModel
类类似于 JDK 中的核心 JDBC 库,而构建于 ChatModel 之上的 ChatClient 类则可比作 JdbcClient
,通过 Advisor 实现更高级的构造:考虑与模型的历史交互、用附加上下文文档增强提示词,并引入代理行为。
提示词结构在 AI 领域持续演进:最初是简单字符串,逐渐发展为包含 "USER:" 等模型可识别的特定输入占位符。OpenAI 进一步引入结构化设计,在 AI 模型处理前将多条消息按不同角色分类。
API 概览
Prompt
通常使用 ChatModel
的 call()
方法,该方法接收 Prompt
实例并返回 ChatResponse
。
Prompt
类作为有序 Message
对象和请求 ChatOptions
的容器。每个 Message
在提示中扮演独特角色,其内容和意图各异 — 从用户询问到 AI 生成响应,再到相关背景信息。这种结构支持与 AI 模型的复杂交互,因为提示由多条消息构建而成,每条消息在对话中承担特定角色。
以下是 Prompt
类的简化版本(省略构造函数和工具方法):
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;
private ChatOptions chatOptions;
}
Message
Message
接口封装了 Prompt
文本内容、元数据属性集合以及称为 MessageType
的分类标识。
接口定义如下:
public interface Content {
String getContent();
Map<String, Object> getMetadata();
}
public interface Message extends Content {
MessageType getMessageType();
}
多模态消息类型还实现了 MediaContent
接口,提供 Media
内容对象列表。
public interface MediaContent extends Content {
Collection<Media> getMedia();
}
Message
接口的多种实现对应 AI 模型可处理的不同消息类别,模型根据对话角色区分消息类型。

这些角色由 MessageType
有效映射,如下所述。
角色(Role)
每条消息被分配特定角色,这些角色对消息进行分类,向 AI 模型阐明提示每个片段的上下文和目的。这种结构化方法通过让提示的每个部分在交互中扮演明确角色,增强了与 AI 沟通的精细度和有效性。
主要角色包括:
-
System 角色:指导 AI 的行为和响应风格,设定 AI 解释和回复输入的参数或规则,类似于在开始对话前向 AI 提供指令。
-
User 角色:代表用户的输入 — 包括问题、命令或对 AI 的陈述。该角色构成 AI 响应的基础,具有根本重要性。
-
Assistant 角色:AI 对用户输入的响应,不仅是答案或反应,更对维持对话流至关重要。通过追踪 AI 之前的响应(其 "Assistant Role" 消息),系统确保连贯且上下文相关的交互。助手消息也可能包含函数工具调用请求信息 — 这是 AI 的特殊功能,在需要时执行计算、获取数据等超越对话的特定任务。
-
Tool/Function 角色:专注于响应工具调用类助手消息,返回附加信息。
角色在 Spring AI 中以枚举形式表示,如下所示:
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
TOOL("tool");
...
}
PromptTemplate
Spring AI 中提示词模板化的核心组件是 PromptTemplate
类,专为简化结构化提示词的创建而设计,这些提示词随后会发送给 AI 模型处理。
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {
// Other methods to be discussed later
}
该类使用 TemplateRenderer
API 渲染模板。默认情况下,Spring AI 采用基于 Terence Parr 开发的开源 StringTemplate 引擎的 StTemplateRenderer
实现。模板变量通过 {}
语法标识,但也可配置为其他分隔符语法。
public interface TemplateRenderer extends BiFunction<String, Map<String, Object>, String> {
@Override
String apply(String template, Map<String, Object> variables);
}
Spring AI 通过 TemplateRenderer
接口处理模板字符串中的变量替换,默认实现使用 [StringTemplate]。若需自定义逻辑,可提供自己的 TemplateRenderer
实现。对于无需模板渲染的场景(如模板字符串已完整),可使用提供的 NoOpTemplateRenderer
。
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
Tell me the names of 5 movies whose soundtrack was composed by <composer>.
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));
该类实现的接口支持提示词创建的不同方面:
PromptTemplateStringActions
专注于创建和渲染提示词字符串,代表最基础的提示生成形式。
PromptTemplateMessageActions
专为通过生成和操作 Message
对象来创建提示词而设计。
PromptTemplateActions
设计用于返回 Prompt
对象,该对象可传递给 ChatModel
生成响应。
虽然这些接口在许多项目中可能不会被广泛使用,但它们展示了提示词创建的不同方法。
实现的接口包括:
public interface PromptTemplateStringActions {
String render();
String render(Map<String, Object> model);
}
String render()
:将提示词模板渲染为最终字符串格式(无需外部输入),适用于不含占位符或动态内容的模板。
String render(Map<String, Object> model)
:增强渲染功能以包含动态内容,使用 Map<String, Object>
参数(Key 为提示模板中的占位符名称, Value 为待插入的动态内容)。
public interface PromptTemplateMessageActions {
Message createMessage();
Message createMessage(List<Media> mediaList);
Message createMessage(Map<String, Object> model);
}
-
Message createMessage()
:创建不带附加数据的Message
对象,适用于静态或预定义的消息内容。 -
Message createMessage(List<Media> mediaList)
:创建包含静态文本和媒体内容的Message
对象。 -
Message createMessage(Map<String, Object> model)
:扩展消息创建以整合动态内容,接收Map<String, Object>
参数(每条记录代表消息模板中的占位符及其对应的动态值)。
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>
参数(每个 Map 条目代表提示模板中的占位符及其关联的动态值)。 -
Prompt create(Map<String, Object> model, ChatOptions modelOptions)
:扩展提示创建能力以包含动态内容和聊天请求特定选项,接收Map<String, Object>
参数(每个 Map 条目代表提示模板中的占位符及其关联的动态值)及ChatOptions
参数。
示例用法
以下是 AI Workshop 中关于 PromptTemplates 的简单示例:
PromptTemplate promptTemplate = new PromptTemplate("Tell me a {adjective} joke about {topic}");
Prompt prompt = promptTemplate.create(Map.of("adjective", adjective, "topic", topic));
return chatModel.call(prompt).getResult();
以下是 AI Workshop 中关于 Role 的另一个示例:
String userText = """
Tell me about three famous pirates from the Golden Age of Piracy and why they did.
Write at least a sentence for each pirate.
""";
Message userMessage = new UserMessage(userText);
String systemText = """
You are a helpful AI assistant that helps people find information.
Your name is {name}
You should reply to the user's request with your name and also in the style of a {voice}.
""";
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));
Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
List<Generation> response = chatModel.call(prompt).getResults();
该示例展示如何通过 SystemPromptTemplate
构建 Prompt
实例:使用 system
角色创建含占位值的 Message
,再与 user
角色的 Message
组合成提示,最终传递给 ChatModel
获取生成式响应。
使用自定义模板渲染器
你可通过实现 TemplateRenderer
接口并将其传入 PromptTemplate
构造函数来使用自定义模板渲染器,也可继续使用默认的 StTemplateRenderer
但采用自定义配置。
默认情况下,模板变量通过 {}
语法标识。若提示中包含 JSON,建议改用 <
和 >
等分隔符以避免与JSON语法冲突。
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
Tell me the names of 5 movies whose soundtrack was composed by <composer>.
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));
使用 Resource 替代原始字符串
Spring AI 支持 org.springframework.core.io.Resource
抽象,因此可将提示数据存入文件并直接用于 PromptTemplate
。例如:在 Spring 托管组件中定义字段来获取 Resource
。
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
然后将该资源直接传递给 SystemPromptTemplate
。
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
提示词工程
在生成式 AI 中,提示词创建是开发者的关键任务。这些提示词的质量和结构显著影响 AI 输出的有效性。投入时间精心设计提示词可大幅提升 AI 生成结果。
在 AI 社区中,分享和讨论提示词是常见实践。这种协作方式不仅创造了共享学习环境,还能促成高效提示词的识别与应用。
该领域研究常涉及分析和比较不同提示词在各种情境下的有效性。例如,一项重要研究表明,以 “深呼吸后逐步解决这个问题” 开头的提示词能显著提升解题效率,这凸显了精心设计的语言对生成式AI系统性能的影响。
掌握提示词的最有效使用方式(尤其是随着 AI 技术的快速发展)是持续挑战。应认识到提示词工程的重要性,并考虑采用社区和研究中的洞见来改进提示创建策略。
创建高效提示词
开发提示词时,需整合以下关键组件以确保清晰度和有效性:
-
指令:向 AI 提供清晰直接的指示,类似于与人沟通的方式。这种明确性对帮助AI “理解” 预期目标至关重要。
-
外部上下文:必要时包含相关背景信息或对 AI 响应的具体指导。这种 “外部上下文” 构建了提示框架,帮助 AI 理解整体场景。
-
用户输入:这是直接部分 — 用户构成提示核心的明确请求或问题。
-
输出指示器:这部分可能很棘手。它需要指定 AI 响应的期望格式(如 JSON),但需注意 AI 可能不会严格遵循该格式。例如,它可能在实际 JSON 数据前添加 “这是您的JSON” 等短语,或有时生成不准确的类 JSON 结构。
为 AI 提供预期问答格式的示例在构建提示词时极为有益。这种做法帮助AI “理解” 查询的结构与意图,从而产生更精准相关的响应。虽然本文档未深入这些技术,但它们为提示词工程的进一步探索提供了起点。
以下是供进一步研究的资源列表:
高级技巧
-
零样本、 小样本学习:
使模型能在极少或没有特定问题类型示例的情况下做出准确预测或响应,利用已学习的泛化能力理解并执行新任务。 -
思维链:
串联多个AI响应以创建连贯且上下文感知的对话,帮助AI保持讨论主线,确保相关性与连续性。 -
ReAct(推理+行动):
该方法中,AI 首先分析(推理)输入内容,随后确定最合适的行动方案或响应,将理解过程与决策机制相结合。
微软 Guidance 框架
-
提示创建与优化框架:
微软提供结构化方法来开发和改进提示词,该框架指导用户创建能有效引导 AI 模型产生预期响应的提示,优化交互的清晰度和效率。
Token
Token 是 AI 模型处理文本的关键要素,作为桥梁将人类理解的单词转换为模型可处理的格式。该转换分两阶段进行:输入时单词转为 Token,输出时 Token 再转回单词。
Token 化(将文本分解为 Token 的过程)是 AI 模型理解和处理语言的基础。模型通过这种 Token 化格式来理解并响应提示词。
要理解 Token,可将其视为单词的组成部分。通常一个 Token 相当于单词的约四分之三,例如莎士比亚全集约 90 万单词,会转换为约 120 万Token。
通过 OpenAI Tokenizer UI 实验观察单词如何转换为 Token。
Token 除在 AI 处理中的技术角色外,还对计费和模型能力具有实际影响:
-
计费:AI 模型服务通常按 Token 使用量计费。输入(提示词)和输出(响应)均计入总 Token 数,因此更短的提示词更具成本效益。
-
模型限制:不同 AI 模型拥有不同的 Token 限制,即其 “上下文窗口” — 单次可处理的最大信息量。例 如GPT-3 限制为 4K Token,而 Claude 2 和 Meta Llama 2 等模型可达 100K Token,某些研究模型甚至能处理 100 万 Token。
-
上下文窗口:模型的 Token 限制决定了其上下文窗口大小。超过该限制的输入不会被处理。关键在于仅发送最小必要有效信息集,例如查询《哈姆雷特》时,无需包含莎士比亚其他作品的 Token。
-
响应元数据:AI 模型响应的元数据包含使用的 Token 数,这是管理使用量和成本的关键信息。