更新 SpringAI/0_使用SpringAI接入AI模型.md
This commit is contained in:
parent
46f1cb0d4f
commit
b402ba3b86
@ -150,29 +150,27 @@ spring:
|
|||||||
model: qwen-max # 阿里云的文档中有提供模型名称
|
model: qwen-max # 阿里云的文档中有提供模型名称
|
||||||
```
|
```
|
||||||
|
|
||||||
### 使用ChatClient发送消息示例
|
### 使用ChatClient发送消息
|
||||||
|
|
||||||
1. 引入ChatModel
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 如果需要根据名称注入,则可以指定为:dashScopeChatModel
|
// 注入ChatModel,如果需要根据名称注入,则可以指定为:dashScopeChatModel
|
||||||
private final ChatModel chatModel;
|
private final ChatModel chatModel;
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 阻塞式传输
|
#### 阻塞式传输
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@GetMapping("chat")
|
@GetMapping("chat")
|
||||||
public String chat(@RequestParam String prompt) {// 用户输入的prompt
|
public String chat(@RequestParam String prompt) {
|
||||||
return ChatClient.create(chatModel)
|
return ChatClient.create(chatModel)
|
||||||
.prompt()
|
.prompt()
|
||||||
.user(prompt)
|
.user(prompt) // 用户输入的prompt
|
||||||
.call() // 阻塞等待返回,结果可以是:ChatResponse、JaveBean、String
|
.call() // 阻塞等待返回,结果可以是:ChatResponse、JaveBean、String
|
||||||
.content();
|
.content();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 流式传输
|
#### 流式传输
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@GetMapping(value = "chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@GetMapping(value = "chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
@ -187,23 +185,24 @@ public String chat(@RequestParam String prompt) {// 用户输入的prompt
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### ChatMermory
|
#### ChatMermory
|
||||||
|
|
||||||
ChatMermory是一个记录与用户对话的组件,在聊天的模型中将用户与大模型API前几轮对话消息,发送给大模型的API是一个很常见的需求。它本身是一个接口,比如**InMemoryChatMemory**就是一个在JVM内存中记录的实现。可以按照自己的需求实现不同形式的存储,比如Redis、或数据库持久化存储。
|
ChatMermory是一个记录与用户对话的组件,在聊天的模型中将用户与大模型API前几轮对话消息,发送给大模型的API是一个很常见的需求。它本身是一个接口,比如**InMemoryChatMemory**就是一个在JVM内存中记录的实现。可以按照自己的需求实现不同形式的存储,比如Redis、或数据库持久化存储。
|
||||||
|
|
||||||
### MessageChatMemoryAdvisor
|
#### MessageChatMemoryAdvisor
|
||||||
|
|
||||||
ChatMermory仅仅是一个存储和获取历史对话消息的接口,而MessageChatMemoryAdvisor则是ChatClient中的一部分,比如这样做:
|
ChatMermory仅仅是一个存储和获取历史对话消息的接口,而MessageChatMemoryAdvisor则是ChatClient中的一部分,比如这样做:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 这里用InMemoryChatMemory做示例
|
// 这里用InMemoryChatMemory做示例
|
||||||
private static final ChatMemory chatMemory = new InMemoryChatMemory();
|
private static final ChatMemory chatMemory = new InMemoryChatMemory();
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
ChatClient.create(chatModel)
|
ChatClient.create(chatModel)
|
||||||
.prompt()
|
.prompt()
|
||||||
.user(prompt)
|
.user(prompt)
|
||||||
// 从历史记录里取6条对话消息一起发送至模型的API。
|
// 从历史记录里取6条对话消息一起发送至模型的API。历史消息也是算在这一次对话Token消耗,要关注Token膨胀
|
||||||
// 历史消息也是算在这一次对话Token消耗的,要关注Token膨胀
|
|
||||||
.advisors(new MessageChatMemoryAdvisor(chatMemory, sessionId, 6))
|
.advisors(new MessageChatMemoryAdvisor(chatMemory, sessionId, 6))
|
||||||
.stream()
|
.stream()
|
||||||
.content()
|
.content()
|
||||||
@ -212,30 +211,34 @@ ChatClient.create(chatModel)
|
|||||||
|
|
||||||
### ETL
|
### ETL
|
||||||
|
|
||||||
ETL的全称是Extract, Transform, Load,即抽取、转换、加载。我们可以利用ETL框架 [Apache Tika](https://tika.apache.org/2.9.0/formats.html),将文档(.pdf .xlsx .docx .pptx .md .json等)导入至向量数据库,让AI模型能够从向量数据库中检索并生成答案。
|
ETL的全称是Extract, Transform, Load,即抽取、转换、加载。我们可以利用ETL框架 [Apache Tika](https://tika.apache.org/2.9.0/formats.html),将文档(.pdf .xlsx .docx .pptx .md .json等)导入至向量数据库,让AI模型能够从向量数据库中检索并生成答案。整体的流程图:
|
||||||
|
|
||||||
**DocumentReader**负责读取文档:
|
<img width='80%' src='https://www.jarcheng.top/blog/assets/etl-pipeline-tlEpEE9G.jpg'>
|
||||||
|
|
||||||
|
#### DocumentReader读取文档
|
||||||
|
|
||||||
- JsonReader:读取JSON
|
- JsonReader:读取JSON
|
||||||
- TextReader:读取text文档
|
- TextReader:读取text文档
|
||||||
- PagePdfDocumentReader:读取PDF
|
- PagePdfDocumentReader:读取PDF
|
||||||
- TikaDocumentReader:读取各种文件(.pdf .xlsx .docx .pptx .md .json)都支持
|
- TikaDocumentReader:读取各种文件(.pdf .xlsx .docx .pptx .md .json)都支持
|
||||||
|
|
||||||
**DocumentTransformer**用于处理文档:
|
#### DocumentTransformer加工处理
|
||||||
|
|
||||||
- TextSplitter:文档切割成小块
|
- TextSplitter:文档切割成小块
|
||||||
- ContentFormatTransformer:将文档转换成键值对
|
- ContentFormatTransformer:将文档转换成键值对
|
||||||
- SummaryMetadataEnricher:使用大模型总结文档
|
- SummaryMetadataEnricher:使用大模型总结文档
|
||||||
- KeywordMetadataEnricher:使用大模型提取文档关键词
|
- KeywordMetadataEnricher:使用大模型提取文档关键词
|
||||||
|
|
||||||
**DocumentWriter**负责文档写入:
|
#### DocumentWriter负责文档写入
|
||||||
|
|
||||||
- VectorStore:写入到向量数据库
|
- VectorStore:写入到向量数据库
|
||||||
- FileDocumentWriter:写入到文件
|
- FileDocumentWriter:写入到文件
|
||||||
|
|
||||||
<img width='80%' src='https://www.jarcheng.top/blog/assets/etl-pipeline-tlEpEE9G.jpg'>
|
#### 使用方式
|
||||||
|
|
||||||
引入相关依赖
|
Document对象是ETL的核心,它包含了文档的元数据和内容。
|
||||||
|
|
||||||
|
##### 引入相关依赖
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -244,11 +247,7 @@ ETL的全称是Extract, Transform, Load,即抽取、转换、加载。我们
|
|||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
Document对象是ETL的核心,它包含了文档的元数据和内容。
|
##### 从输入流读取
|
||||||
|
|
||||||
#### 读取
|
|
||||||
|
|
||||||
1. 从输入流读取
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 适合前端上传 MultipartFile 的场景
|
// 适合前端上传 MultipartFile 的场景
|
||||||
@ -256,51 +255,49 @@ Resource resource = new InputStreamResource(file.getInputStream());
|
|||||||
List<Document> documents = new TikaDocumentReader(resource).read();
|
List<Document> documents = new TikaDocumentReader(resource).read();
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 从本地文件读取
|
##### 从本地文件读取
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Resource resource = new FileSystemResource("D:\\xxx.pdf");
|
Resource resource = new FileSystemResource("D:\\xxx.pdf");
|
||||||
List<Document> documents = new TikaDocumentReader(resource).read();
|
List<Document> documents = new TikaDocumentReader(resource).read();
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 从URL读取
|
##### 从URL读取
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Resource resource = new UrlResource("http://oss.com/xxx.pdf");
|
Resource resource = new UrlResource("http://oss.com/xxx.pdf");
|
||||||
List<Document> documents = new TikaDocumentReader(resource).read();
|
List<Document> documents = new TikaDocumentReader(resource).read();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 转换
|
##### 内容转换
|
||||||
|
|
||||||
内容转换:
|
|
||||||
|
|
||||||
- TokenTextSplitter 可以把内容切割成更小的块,在RAG的时候可以提升响应速度、节省Token。
|
- TokenTextSplitter 可以把内容切割成更小的块,在RAG的时候可以提升响应速度、节省Token。
|
||||||
- ContentFormatTransformer 可以把元数据的内容变成字符串键值对。
|
- ContentFormatTransformer 可以把元数据的内容变成字符串键值对。
|
||||||
|
|
||||||
元数据转换:
|
|
||||||
|
|
||||||
- SummaryMetadataEnricher 使用大模型总结文档,在元数据里增加一个**summary**字段。
|
|
||||||
- KeywordMetadataEnricher 使用大模型提取文档关键词,在元数据里面增加一个**keywords**字段。
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
List<Document> documents = new TikaDocumentReader(resource).read();
|
List<Document> documents = new TikaDocumentReader(resource).read();
|
||||||
// 这里示例用 TokenTextSplitter 分块
|
// 这里示例用 TokenTextSplitter 分块
|
||||||
List<Document> splitDocuments = new TokenTextSplitter().apply(documents);
|
List<Document> splitDocuments = new TokenTextSplitter().apply(documents);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 存储
|
##### 元数据转换
|
||||||
|
|
||||||
|
- SummaryMetadataEnricher 使用大模型总结文档,在元数据里增加一个**summary**字段。
|
||||||
|
- KeywordMetadataEnricher 使用大模型提取文档关键词,在元数据里面增加一个**keywords**字段。
|
||||||
|
|
||||||
|
##### 存储
|
||||||
|
|
||||||
这里需要引入一个新的组件**向量数据库**(VectorStore),这是AI记忆的核心组件。前面提到的**ChatMemory**属于短期记忆的组件,一般只在聊天对话的上下文中生效。而**VectorStore**是持久化存储的,也就是大家常说的AI知识库。
|
这里需要引入一个新的组件**向量数据库**(VectorStore),这是AI记忆的核心组件。前面提到的**ChatMemory**属于短期记忆的组件,一般只在聊天对话的上下文中生效。而**VectorStore**是持久化存储的,也就是大家常说的AI知识库。
|
||||||
|
|
||||||
什么是向量?我这里贴一段通义千问的回答:
|
什么是向量?我这里贴一段通义千问的回答:
|
||||||
|
|
||||||
> 向量在向量数据库中指的是数学意义上的向量,即一维数组,它可以包含实数或复数。但在计算机科学和信息技术领域,特别是在机器学习、人工智能以及数据检索的上下文中,向量通常是指特征向量。这些向量用来表示数据点或对象的特征,每个元素代表一个特定的特征值。
|
向量在向量数据库中指的是数学意义上的向量,即一维数组,它可以包含实数或复数。但在计算机科学和信息技术领域,特别是在机器学习、人工智能以及数据检索的上下文中,向量通常是指特征向量。这些向量用来表示数据点或对象的特征,每个元素代表一个特定的特征值。
|
||||||
|
|
||||||
例如,在文本处理中,文档可以用词频-逆文档频率(TF-IDF)向量或者词嵌入(如Word2Vec或GloVe模型生成的向量)来表示;在图像识别中,图像可以转换为一个描述其视觉特征的向量;在推荐系统中,用户偏好和物品属性也可以被编码成向量形式。
|
例如,在文本处理中,文档可以用词频-逆文档频率(TF-IDF)向量或者词嵌入(如Word2Vec或GloVe模型生成的向量)来表示;在图像识别中,图像可以转换为一个描述其视觉特征的向量;在推荐系统中,用户偏好和物品属性也可以被编码成向量形式。
|
||||||
|
|
||||||
向量数据库就是专门设计用来存储、索引和查询这些高维度向量数据的数据库系统。它们优化了相似度搜索(比如通过计算向量之间的距离,如欧氏距离、余弦相似度等),使得能够快速找到与给定向量最接近的数据点。这种能力对于实现诸如图像搜索、语音识别、自然语言处理等任务非常有用。
|
向量数据库就是专门设计用来存储、索引和查询这些高维度向量数据的数据库系统。它们优化了相似度搜索(比如通过计算向量之间的距离,如欧氏距离、余弦相似度等),使得能够快速找到与给定向量最接近的数据点。这种能力对于实现诸如图像搜索、语音识别、自然语言处理等任务非常有用。
|
||||||
|
|
||||||
还记得前面提到的**Embedding**(嵌入模型)吗?这个组件就是SpringAI框架中用于把文档、音视频转换成向量的。向量化以后,可以使用向量存储数据库进行存储,下面用**RedisStack**来进行示例。
|
还记得前面提到的**Embedding**(嵌入模型)吗?这个组件就是SpringAI框架中用于把文档、音视频转换成向量的。向量化以后,可以使用向量数据库进行存储,下面用**RedisStack**来进行示例。
|
||||||
|
|
||||||
##### 引入redis相关依赖
|
##### 引入redis相关依赖
|
||||||
|
|
||||||
@ -363,13 +360,19 @@ dash-scope:
|
|||||||
|
|
||||||
##### 使用示例
|
##### 使用示例
|
||||||
|
|
||||||
注入模型:
|
注入模型
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private final EmbeddingModel embeddingModel;
|
private final EmbeddingModel embeddingModel;
|
||||||
```
|
```
|
||||||
|
|
||||||
向量化:
|
注入VectorStore组件
|
||||||
|
|
||||||
|
```java
|
||||||
|
private final VectorStore vectorStore;
|
||||||
|
```
|
||||||
|
|
||||||
|
向量化
|
||||||
|
|
||||||
```
|
```
|
||||||
public void embedding() {
|
public void embedding() {
|
||||||
@ -379,15 +382,10 @@ public void embedding() {
|
|||||||
|
|
||||||
向量化存储文档
|
向量化存储文档
|
||||||
|
|
||||||
注入VectorStore组件:
|
|
||||||
|
|
||||||
```java
|
|
||||||
private final VectorStore vectorStore;
|
|
||||||
```
|
|
||||||
**vectorStore.add**会自动调用embeddingModel完成向量化并存储
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
List<Document> documents = new TikaDocumentReader(resource).read();
|
List<Document> documents = new TikaDocumentReader(resource).read();
|
||||||
List<Document> splitDocuments = new TokenTextSplitter().apply(documents);
|
List<Document> splitDocuments = new TokenTextSplitter().apply(documents);
|
||||||
vectorStore.add(splitDocuments);
|
vectorStore.add(splitDocuments);
|
||||||
```
|
```
|
||||||
|
**vectorStore.add**会自动调用embeddingModel完成向量化并存储。
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user