这一部分描述了Spring AI使用的核心概念。我们建议仔细阅读以理解实现Spring AI背后的思想。

模型

AI模型是设计用来处理和生成信息的算法,经常模仿人类认知功能。通过从大型数据集中学习模式和洞察力,这些模型可以做出预测、文本、图像或其他输出,增强跨行业的各种应用。

有许多不同类型的人工智能模型,每种都适用于特定的用例。虽然ChatGPT及其生成AI能力通过文本输入和输出吸引了用户,但许多模型和公司提供多样化的输入和输出。在ChatGPT之前,许多人对Midjourney和Stable Diffusion等文本到图像生成模型着迷。

下表根据它们的输入和输出类型对几种模型进行了分类:

输入 输出 案例

语言/代码/图片(多模态)

语言/代码

GPT4 - OpenAI,谷歌Gemini

语言/代码

语言/代码

GPT 3.5 - OpenAI-Azure OpenAI,谷歌Bard,Meta Llama

语言

图片

Dall-E - OpenAI + Azure,Deep AI

语言/图片

图片

Midjourney,Stable Diffusion,RunwayML

文本

数字

许多(也称为嵌入)

Spring AI最初关注的是那些处理语言输入并提供语言输出的模型,起初是OpenAI + Azure OpenAI。在上一个表格的最后一行,接受文本作为输入并输出数字,这种方式通常被称为嵌入文本,代表了AI模型中使用的内部数据结构。Spring AI支持嵌入技术以支持更高级的用例。

将GPT这样的模型区别于其他的一个特点是它们的预训练本质,如GPT中的“P”——聊天生成预训练变换器所示。这种预训练功能将AI转变为一个通用的开发工具,它不需要广泛的机器学习或模型训练背景。

提示

提示是基于语言输入的基础,这些输入指导AI模型产生特定的输出。对于那些熟悉ChatGPT的人来说,提示可能只看起来像是输入到对话框中的文本,然后发送给API。然而,它涵盖的内容远不止于此。在许多AI模型中,提示文本不仅仅是一个简单的字符串。

ChatGPT的API在一个提示中有多个文本输入,每个文本输入被分配了一个角色。例如,有系统角色,它告诉模型如何行为,并为交互设置上下文。还有用户角色,通常是来自用户的输入。

设计有效的提示既是一门艺术也是一门科学。ChatGPT旨在用于人类对话。这与使用SQL之类的东西“提问”相比,有很大的不同。人必须像与另一个人交谈一样与AI模型进行沟通。

这种交互方式的重要性如此之大,以至于“提示工程”一词已经成为一个独立的学科。有一系列不断增长的技术可以提高提示的效果。投入时间来精心制作一个提示可以极大地提高最终输出的质量。

分享提示已经成为一个社区实践,围绕这个主题的学术研究也正在积极进行。举个例子,如何创建一个有效的提示可能违反直觉(例如,与SQL形成对比),一个[最近的研究论文](https://arxiv.org/abs/2205.11916)发现,你可以使用的最有效的提示之一是以短语“深呼吸,一步步地解决这个问题。”开头。这应该能给你一个指示,为什么语言如此重要。我们还没有完全理解如何最有效地利用这项技术的前几轮迭代,比如ChatGPT 3.5,更不用说正在开发中的新版本了。

提示模板

创建有效的提示需要建立请求的上下文,并将请求的部分内容用特定于用户输入的值来替换。

这个过程使用传统的基于文本的模板引擎来创建和管理提示。Spring AI使用开源软件库[StringTemplate](https://www.stringtemplate.org/)来达成这个目的。

例如,考虑这个简单的提示模板:

Tell me a {adjective} joke about {content}.

在Spring AI中,提示模板可以类比于Spring MVC架构中的“视图”(View)。通常会提供一个模型对象,比如`java.util.Map`,来填充模板中的占位符。渲染后的字符串成为提供给AI模型的提示内容。

向模型发送的提示的具体数据格式存在相当大的变化性。起初以简单的字符串形式出现,提示已经演变为包含多条消息,每条消息中的每个字符串代表模型的一个独特角色。

嵌入

嵌入(Embeddings)将文本转换为数值数组或向量,使得人工智能模型能够处理和理解语言数据。这种从文本到数字再到文本的转换是人工智能与理解人类语言互动的关键要素。作为一个探索人工智能领域的Java开发者,并不需要完全理解这些向量表示背后复杂的数学理论或具体实现。只需要基本了解它们在人工智能系统中的作用和功能,特别是当你将人工智能功能整合到你的应用程序时。

嵌入(Embeddings)在实际应用中尤为重要,例如在检索增强生成(Retrieval Augmented Generation,简称RAG)模式中。它们使数据能够以语义空间中的点来表示,这类似于欧几里得几何的二维空间,但在更高的维度中。这意味着,就像在欧几里得几何的平面上,根据坐标可以确定点之间是近是远一样,在语义空间中,点之间的接近程度反映了意义上的相似度。关于相似主题的句子在这个多维空间中的位置更靠近,就像图表上彼此靠近的点一样。这种接近性有助于文本分类、语义搜索甚至产品推荐等任务,因为它允许AI根据概念在这个广阔的语义景观中的“位置”来辨别和归类相关概念。

你可以将这个语义空间想象成一个向量。

代币

令牌作为人工智能模型工作的基石。输入时,模型将单词转换为令牌。输出时,它们将令牌转换回单词。

在英语中,一个token大致对应着一个单词的75%。作为参考,莎士比亚的全部作品,总计大约90万个单词,转换成大约120万个tokens。

也许更重要的是 Tokens = $

在托管的AI模型环境下,你的费用由使用的令牌数量决定。输入和输出都会对总令牌数产生贡献。

此外,模型受到令牌限制,这限制了在单次API调用中处理的文本量。这个阈值通常被称为“上下文窗口”。模型不会处理超出此限制的文本。

例如,ChatGPT3的令牌限制是4K,而GPT4提供了不同的选项,如8K、16K和32K。Anthropic的Claude AI模型具有100K令牌限制,而Meta最近的研究产出了一个1M令牌限制模型。

要用GPT4概括莎士比亚收集的作品,你需要设计软件工程策略来切割数据,并将数据呈现在模型的上下文窗口限制之内。春季AI项目可以在这项任务中帮助你。

输出解析

AI模型的输出传统上以`java.lang.String`形式出现,即使你要求回复为JSON格式。它可能是正确的JSON,但它不是JSON数据结构。它只是一个字符串。此外,作为提示的一部分要求“for JSON”并不是100%准确的。

这种复杂性导致了一个专门的领域的出现,该领域涉及创建提示以产生预期的输出,然后将得到的简单字符串解析成可用的数据结构,以便于应用程序集成。

输出解析采用精心设计的提示,通常需要与模型进行多次交互以实现所需的格式化。

这个挑战促使OpenAI引入了“OpenAI Functions”作为一种精确指定模型期望输出格式的方法。

将您的数据带入AI模型

您如何使AI模型携带上它未经训练的信息?

请注意,GPT 3.5/4.0 数据集仅扩展到 2021 年 9 月。因此,对于需要超出该日期知识的问题,模型表示它不知道答案。一个有趣的小知识是,这个数据集大约有 650GB。

有三种技术可用于自定义AI模型以结合您的数据:

  • Fine Tuning`:这种传统的机器学习技术涉及调整模型并改变其内部权重。然而,对于机器学习专家来说,这是一个挑战性的过程,对于GPT这样的模型由于其规模而极其耗费资源。此外,一些模型可能不提供这个选项。

  • “Prompt Stuffing”:一种更实际的替代方法涉及将数据嵌入到提供给模型的提示中。考虑到模型的令牌限制,需要技术来在模型的上下文窗口内呈现相关数据。这种方法俗称为“填充提示”。Spring AI库帮助你实现基于“填充提示”技术的解决方案,也就是所谓的检索增强生成(RAG)。

  • 函数调用`:这种技术允许注册自定义的用户函数,这些函数将大型语言模型与外部系统的APIs连接起来。Spring AI大大简化了你需要编写的支持函数调用的代码。

检索增强生成

一种名为检索增强生成(Retrieval Augmented Generation, RAG)的技术已经出现,用于解决在提示框中加入相关数据以获得准确的AI模型响应的挑战。

这种方法涉及一种批处理风格的编程模型,该模型从文档中读取非结构化数据,对其进行转换,然后将其写入向量数据库。在较高层面上,这是一个ETL(提取、转换和加载)流程。向量数据库用于RAG技术的检索部分。

在将非结构化数据加载到向量数据库的过程中,最重要的转换之一是将原始文档拆分成更小的部分。将原始文档拆分成更小片段的过程包括两个重要步骤:

  1. 将文档分割成多个部分,同时保留内容的语义边界。例如,对于一个包含段落和表格的文档,应避免在段落或表格的中间拆分文档。对于代码,避免在方法实现的中间拆分代码。

  2. 将文档的部分进一步拆分为大小是AI模型令牌限制的一小部分的部分。

RAG中的下一阶段是处理用户输入。当用户的问题需要通过AI模型来回答时,问题以及所有“相似”的文档片段都会放入发送给AI模型的提示中。这就是使用向量数据库的原因。它非常擅长找到相似的内容。

在实现RAG时使用了几个概念。这些概念映射到Spring AI中的类上:

  • DocumentReader`:一个Java函数式接口,负责从数据来源加载`List<Document>`。常见的数据来源有PDF、Markdown和JSON。

  • "`Document`:一种基于文本的数据源表示形式,同时包含元数据以描述内容。"

  • DocumentTransformer`:负责以各种方式处理数据(例如,将文档拆分成更小的片段或向`Document`添加额外的元数据)。

  • DocumentWriter`:允许您将文档持久化到数据库中(在AI技术栈中,最常见的是向量数据库)。

  • Embedding`:表示您的数据作为`List<Double>`的一种形式,向量数据库使用它来计算用户查询与相关文档的“similarity”(相似度)。

函数调用

大型语言模型(LLMs)在训练后被冻结,导致知识陈旧,它们无法访问或修改外部数据。

Function Calling`机制解决了这些不足。它允许你注册自定义的用户函数,这些函数将大型语言模型与外部系统的API连接起来。这些系统可以为LLMs提供实时数据,并代表它们执行数据处理操作。

Spring AI大大简化了你需要编写的支持函数调用的代码。它代理了函数调用交流。你可以将你的函数提供为一个`@Bean`,然后在你的提示选项中提供函数的bean名称以激活该函数。你还可以在单个提示中定义和引用多个函数。

评估AI响应

高效地评估AI系统对用户请求的响应非常重要,它能确保最终应用的准确性和实用性。几种新兴的技术可以使我们能够直接利用预训练模型本身来达到这个目的。

这个评估过程涉及分析生成的回应是否与用户的意图和查询的上下文一致。诸如相关性、连贯性和事实正确性之类的指标用来衡量AI生成回应的质量。

一种方法涉及向模型提供用户的请求和AI模型的响应,并查询响应是否与所提供的数据一致。

进一步来说,利用向量数据库中存储的信息作为补充数据可以增强评估过程,有助于确定响应的相关性。

Spring AI项目目前提供了一些非常基本的示例,展示了你如何评估提示形式的响应,并将其包含在JUnit测试中。