此版本仍在开发中,尚未被视为稳定版。如需最新的快照版本,请使用 Spring AI 1.1.3spring-doc.cadn.net.cn

提示

提示是指导AI模型生成特定输出的输入。 这些提示的设计和措辞显著影响模型的响应。spring-doc.cadn.net.cn

在与Spring AI中的AI模型进行最低层次的交互中,处理Spring AI中的提示与管理Spring MVC中的"View"有些相似。 这涉及到创建包含动态内容占位符的大段文本。 这些占位符随后会根据用户请求或其他应用代码被替换。 另一个类比是一个包含某些表达式占位符的SQL语句。spring-doc.cadn.net.cn

随着Spring AI的发展,它将引入更高层次的抽象来与AI模型进行交互。 本节中描述的基础类可以类比为JDBC的角色和功能。 例如,ChatModel类类似于JDK中的核心JDBC库。 ChatClient类可以被类比为JdbcClient,建立在ChatModel之上,并通过Advisor提供更高级的构造,考虑过去与模型的交互,增加提示的相关背景文档,并引入代理行为。spring-doc.cadn.net.cn

AI领域中提示结构随着时间的推移而演变。 最初,提示只是简单的字符串。 后来,它们发展成为包含特定输入占位符的形式,例如“USER:”,这种占位符会被AI模型识别。 OpenAI进一步通过在将多个消息字符串按不同角色分类后再提交给AI模型处理,为提示结构引入了更多的规范性。spring-doc.cadn.net.cn

API概述

提示

它通常会在使用ChatModelcall()方法时,该方法接受一个Prompt实例并返回一个ChatResponsespring-doc.cadn.net.cn

Prompt 类作为一组有序的 Message 对象和请求 ChatOptions 的容器使用。 每个 Message 都在提示中扮演一个独特的角色,内容和意图各不相同。 这些角色可以包括多种元素,从用户询问到AI生成的回应再到相关背景信息。 这种排列方式使得与AI模型进行复杂的详细交互成为可能,因为提示是由多个消息构建而成的,每个消息都被分配了一个特定的角色来参与对话。spring-doc.cadn.net.cn

以下是一个`Prompt`类的截断版本,为了简洁起见省略了构造方法和辅助方法:spring-doc.cadn.net.cn

public class Prompt implements ModelRequest<List<Message>> {

    private final List<Message> messages;

    private ChatOptions chatOptions;
}

便利方法

Prompt 类提供了几种方便的方法,用于通过其角色访问消息:spring-doc.cadn.net.cn

单条消息访问:spring-doc.cadn.net.cn

  • getUserMessage(): 返回提示中的最后一个用户消息,或者如果不存在则返回空的UserMessagespring-doc.cadn.net.cn

  • getSystemMessage(): 返回提示中的第一个系统消息,如果不存在则返回一个空的 SystemMessagespring-doc.cadn.net.cn

  • getLastUserOrToolResponseMessage(): 返回最后一个用户或工具的响应消息,有助于保持对话连贯性spring-doc.cadn.net.cn

多个消息访问:spring-doc.cadn.net.cn

这些方法在处理多轮对话或需要按角色处理消息时特别有用。spring-doc.cadn.net.cn

消息

The Message 接口封装了一段 Prompt 文本内容、一组元数据属性以及一种名为 MessageType 的分类。spring-doc.cadn.net.cn

接口定义如下:spring-doc.cadn.net.cn

public interface Content {

	String getContent();

	Map<String, Object> getMetadata();
}

public interface Message extends Content {

	MessageType getMessageType();
}

多模态消息类型也实现了MediaContent接口,提供了一组Media内容对象。spring-doc.cadn.net.cn

public interface MediaContent extends Content {

	Collection<Media> getMedia();

}

各种实现Message接口的类对应于AI模型可以处理的不同类别消息。 这些模型根据对话角色区分消息类别。spring-doc.cadn.net.cn

Spring AI Message API

这些角色如下面所述通过MessageType进行有效映射。spring-doc.cadn.net.cn

角色

每个消息都被分配了一个特定的角色。 这些角色将消息归类,明确每个提示段落的上下文和目的。 这种结构化的做法增强了与AI沟通的细腻度和有效性,因为提示中的每一部分在交互中都扮演着独特的定义角色。spring-doc.cadn.net.cn

主要角色是:spring-doc.cadn.net.cn

  • 系统角色:指导AI的行为和响应风格,设置参数或规则以确定AI如何解释和回复输入。这类似于在开始对话之前向AI提供指令。spring-doc.cadn.net.cn

  • 用户角色:表示用户的输入——他们的问题、命令或对AI的陈述。这一角色是基础性的,因为它构成了AI回应的基础。spring-doc.cadn.net.cn

  • Assistant 角色:AI 对用户输入的响应。 不仅仅是回答或反应,对于保持对话流畅至关重要。 通过跟踪 AI 的先前响应(即其 'Assistant 角色' 消息),系统确保了连贯且上下文相关的互动。 Assistant 消息中可能还包含函数工具调用请求的信息。 这就像 AI 中的一项特殊功能,在需要时用于执行特定的功能,例如计算、获取数据或其他超出单纯对话的任务。spring-doc.cadn.net.cn

  • Tool/Function 角色:Tool/Function 角色专注于在响应 Tool Call Assistant 消息时返回额外信息。spring-doc.cadn.net.cn

角色在Spring AI中作为枚举表示,如下所示spring-doc.cadn.net.cn

public enum MessageType {

	USER("user"),

	ASSISTANT("assistant"),

	SYSTEM("system"),

	TOOL("tool");

    ...
}

提示模板

Spring AI框架中用于提示模板的关键组件是PromptTemplate类,该类旨在促进结构化提示的创建,然后将这些提示发送给AI模型进行处理。spring-doc.cadn.net.cn

public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {

    // Other methods to be discussed later
}

此类使用了TemplateRenderer API来渲染模板。默认情况下,Spring AI 使用了基于开源的 StringTemplate 引擎(由 Terence Parr 开发)的 StTemplateRenderer 实现。模板变量通过{} 语法标识,但你可以配置使用其他语法作为分隔符。spring-doc.cadn.net.cn

public interface TemplateRenderer extends BiFunction<String, Map<String, Object>, String> {

	@Override
	String apply(String template, Map<String, Object> variables);

}

Spring AI 使用 TemplateRenderer 接口来处理将变量实际插入模板字符串的过程。 默认实现使用了 [StringTemplate]。 如果你需要自定义逻辑,可以提供你自己的 TemplateRenderer 实现。 在不需要进行模版渲染的场景中(例如,模板字符串已经完整),你可以使用提供的 NoOpTemplateRendererspring-doc.cadn.net.cn

使用自定义的StringTemplate 渲染器并使用'<'和'>'分隔符的示例
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"));

此类实现的支持不同方面提示创建的接口:spring-doc.cadn.net.cn

PromptTemplateStringActions 聚焦于创建和渲染提示字符串,代表最基础的提示生成形式。spring-doc.cadn.net.cn

PromptTemplateMessageActions 是为了通过生成和操作 Message 对象来创建提示而设计的。spring-doc.cadn.net.cn

PromptTemplateActions 旨在返回 Prompt 对象,该对象可以传递给 ChatModel 以生成响应。spring-doc.cadn.net.cn

这些接口在许多项目中可能不会被广泛使用,但它们展示了不同类型的提示创建方法。spring-doc.cadn.net.cn

已实现的接口是spring-doc.cadn.net.cn

public interface PromptTemplateStringActions {

	String render();

	String render(Map<String, Object> model);

}

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

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

public interface PromptTemplateMessageActions {

	Message createMessage();

    Message createMessage(List<Media> mediaList);

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

}

方法 Message createMessage():创建一个 Message 对象,不包含额外的数据,用于静态或预定义的消息内容。spring-doc.cadn.net.cn

The method Message createMessage(List<Media> mediaList): 创建一个包含静态文本和媒体内容的Message对象。spring-doc.cadn.net.cn

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

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` 对象,适用于静态或预定义提示。spring-doc.cadn.net.cn

方法Prompt create(ChatOptions modelOptions):生成一个Prompt对象,无需外部数据输入,并针对聊天请求设置了特定选项。spring-doc.cadn.net.cn

方法Prompt create(Map<String, Object> model):扩展提示创建功能,使其能够包含动态内容,在提示模板中的每个映射项是一个占位符及其关联的动态值。spring-doc.cadn.net.cn

该方法Prompt create(Map<String, Object> model, ChatOptions modelOptions):扩展了提示创建能力,使其包括动态内容。它接受一个Map<String, Object>,其中每个映射条目是提示模板中的占位符及其关联的动态值,并且具有针对聊天请求的具体选项。spring-doc.cadn.net.cn

示例用法

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研讨会,具体内容如下。spring-doc.cadn.net.cn

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来创建一个带有系统角色和占位符值的Message,从而构建起Prompt实例的过程。 具有角色user的消息随后与具有角色system的消息结合以形成提示。 然后将该提示传递给ChatModel来获取生成性的响应。spring-doc.cadn.net.cn

使用自定义模板渲染器

您可以实现TemplateRenderer接口来自定义模板渲染器,并将其传递给PromptTemplate构造函数。您也可以继续使用默认的StTemplateRenderer,但可以自定义配置。spring-doc.cadn.net.cn

默认情况下,模板变量由{}语法标识。如果您计划在提示中包含JSON,请考虑使用不同的语法以避免与JSON语法冲突。例如,您可以使用<>作为分隔符。spring-doc.cadn.net.cn

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"));

使用资源代替原始字符串

Spring AI 支持 org.springframework.core.io.Resource 抽象,因此您可以将提示数据放在一个文件中,该文件可以直接在 PromptTemplate 中使用。 例如,您可以在 Spring 管理的组件中定义一个字段来检索 Resourcespring-doc.cadn.net.cn

@Value("classpath:/prompts/system-message.st")
private Resource systemResource;

然后直接将该资源传递给SystemPromptTemplatespring-doc.cadn.net.cn

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);

提示工程

在生成式AI中,提示的创建是开发人员的一项关键任务。 这些提示的质量和结构极大地影响着AI输出的效果。 投入时间和精力设计周到的提示可以显著提高AI的结果。spring-doc.cadn.net.cn

在AI社区中,分享和讨论提示是一种常见做法。 这种协作方式不仅创建了一个共享的学习环境,还促进了高效提示的识别与应用。spring-doc.cadn.net.cn

在这一领域中的研究往往涉及分析和比较不同的提示,以评估它们在不同情况下的有效性。 例如,一项重要研究表明,使用“深呼吸,然后一步步解决这个问题”这样的开头显著提升了问题解决的效率。 这强调了精心选择的语言对生成式AI系统性能的影响。spring-doc.cadn.net.cn

掌握最有效的提示使用方法,尤其是在AI技术飞速发展的今天,这是一个持续的挑战。 你应该认识到提示工程的重要性,并考虑利用社区和研究中的见解来改进提示创建策略。spring-doc.cadn.net.cn

创建有效的提示

在开发提示时,确保整合几个关键组件以保证清晰和有效性非常重要:spring-doc.cadn.net.cn

  • 指令:向AI提供清晰直接的指示,类似于与人交流的方式。这种清晰性对于帮助AI“理解”预期的要求至关重要。spring-doc.cadn.net.cn

  • 外部上下文: 在必要时,包括相关的背景信息或具体的指导方针,以帮助AI的响应。这种“外部上下文”为提示语设定框架,并帮助AI把握整体情境。spring-doc.cadn.net.cn

  • 用户输入: 这是直接的部分 - 用户的直接请求或问题,构成了提示的核心。spring-doc.cadn.net.cn

  • 输出指示符: 这个方面可能会有些棘手。它涉及到指定AI响应所需的格式,例如JSON。但是请注意,AI并不总是严格遵守这种格式。举例来说,它可能会在实际的JSON数据前面加上一个像“这里是你的JSON”的短语,或者有时生成一种看似是JSON结构但实际上不准确的数据。spring-doc.cadn.net.cn

提供给AI一些预期中的问题和答案格式的示例,在构建提示时会非常有益。 这种做法有助于让AI“理解”查询的结构和意图,从而获得更精确和相关的回应。 尽管本文档未深入探讨这些技术,但它们为进一步探索AI提示工程提供了起点。spring-doc.cadn.net.cn

以下是一些可供进一步调查的资源。spring-doc.cadn.net.cn

简单技术

高级技术

Microsoft 指导

  • 框架构建与优化:
    Microsoft 提供了一种结构化的方法来开发和优化提示。此框架指导用户创建有效的提示,以从AI模型中获得所需的响应,从而优化交互以提高清晰度和效率。spring-doc.cadn.net.cn

标记

文本标记在AI模型处理文本的过程中至关重要,它们充当了一座桥梁,将我们理解的词语转换成AI模型能够处理的格式。 这个转换过程分为两个阶段:输入时将单词转换为标记,输出时再将这些标记转换回单词。spring-doc.cadn.net.cn

分词,将文本分解为标记的过程,是AI模型理解和处理语言的基础。 AI模型使用这种标记化格式来理解并回应提示。spring-doc.cadn.net.cn

要更好地理解词元,可以将它们视为单词的部分。通常,一个词元代表大约三个四分之一的单词。例如,《莎士比亚全集》共计约90万单词,会转换为大约120万个词元。spring-doc.cadn.net.cn

尝试使用OpenAI 分词器 UI查看单词是如何转换为标记的。spring-doc.cadn.net.cn

Tokens 在其在AI处理中的技术角色之外还具有实际意义,尤其是在计费和模型能力方面:spring-doc.cadn.net.cn

  • 计费:AI模型服务通常根据token使用量进行计费。输入(提示)和输出(响应)都会计入总token数,因此较短的提示更具成本效益。spring-doc.cadn.net.cn

  • 模型限制:不同的AI模型具有不同的标记限制,定义了它们的“上下文窗口”——即它们一次可以处理的最大信息量。例如,GPT-3的限制是4K个标记,而像Claude 2和Meta Llama 2这样的其他模型则有10万个标记的限制,还有一些研究型模型能够处理多达100万个标记。spring-doc.cadn.net.cn

  • <p>上下文窗口:模型的标记限制决定了其上下文窗口。超过此限制的输入不会被模型处理。发送用于处理的信息时,仅需发送最小有效的信息集至关重要。例如,在查询《哈姆雷特》时,无需包含莎士比亚其他作品的标记。</p>spring-doc.cadn.net.cn

  • 响应元数据:AI模型响应的元数据包括使用的Tokens数量,这是管理和控制使用及成本的重要信息。spring-doc.cadn.net.cn