更新 SpringAI/0_使用SpringAI接入AI模型.md
This commit is contained in:
parent
df203924c3
commit
97b90ff0e2
@ -206,7 +206,7 @@ ChatClient.create(chatModel)
|
||||
.advisors(new MessageChatMemoryAdvisor(chatMemory, sessionId, 6))
|
||||
.stream()
|
||||
.content()
|
||||
.map(chatResponse -> ServerSentEvent.builder(chatResponse).event("message").build());
|
||||
.map(chatResponse -> ServerSentEvent.builder(JSONUtil.toJsonStr(chatResponse)).event("message").build());
|
||||
```
|
||||
|
||||
### ETL
|
||||
@ -394,4 +394,127 @@ vectorStore.add(splitDocuments);
|
||||
```java
|
||||
// query可以是用户输入的文本字符串
|
||||
List<Document> list = vectorStore.similaritySearch(query);
|
||||
```
|
||||
```
|
||||
|
||||
### RAG
|
||||
|
||||
RAG就是当文档等数据ETL到向量数据库以后,用户提问时拿用户的prompt检索向量数据库里的相关资料,然后跟用户的prompt合并提交给大模型,再让大模型生成答案给用户。
|
||||
|
||||
#### QuestionAnswerAdvisor
|
||||
|
||||
在SpringAI中,QuestionAnswerAdvisor这一组件实现了上述的能力。我们可以定义一个prompt模板,来做这件事:
|
||||
|
||||
```
|
||||
下面是上下文信息
|
||||
---------------------
|
||||
{question_answer_context}
|
||||
---------------------
|
||||
给定的上下文和提供的历史信息,而不是事先的知识,回复用户的意见。如果答案不在上下文中,告诉用户你不能回答这个问题。
|
||||
```
|
||||
|
||||
这个模板的内容可以从数据库、Redis、配置文件加载,**{question_answer_context}**是一个模板的变量占位符。
|
||||
|
||||
```java
|
||||
ChatClient.create(chatModel)
|
||||
.prompt()
|
||||
.user(prompt)
|
||||
// 会自动从向量数据库查询资料,并替换到 question_answer_context 变量,结合用户的 prompt 一起发送给大模型API
|
||||
// 假设 promptTemplate 这个字符串就是上面的模板
|
||||
.advisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults(), promptTemplate))
|
||||
.stream()
|
||||
.content()
|
||||
.map(chatResponse -> ServerSentEvent.builder(JSONUtil.toJsonStr(chatResponse)).event("message").build());
|
||||
```
|
||||
|
||||
### FunctionCall
|
||||
|
||||
Function Call旨在解决一些复杂场景的需求,比如我希望AI读取本机某个文件,然后回答文件里面的内容,读取文件这个操作就可以通过FunctionCall来实现。
|
||||
|
||||
#### 读取文档可以通过tika实现
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-tika-document-reader</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### 使用JSON描述Function
|
||||
|
||||
AI模型是不知道你代码里的Function位置在哪儿的,我们需要用JSON声明Function的结构,让AI去找并调用,简单示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "documentAnalyzer", // 这个是 spring bean 的名称
|
||||
"description": "文档解析", // 描述函数的用途
|
||||
"parameters": { // 这个函数要传递的参数
|
||||
"properties": {
|
||||
"path": { // 参数的名称
|
||||
"type": "string", // 参数的类型
|
||||
"description": "被解析的文档路径" // 参数的描述
|
||||
},
|
||||
},
|
||||
"required":["path"], // 必传的参数
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 编写函数
|
||||
|
||||
我们需要实现**java.util.function.Function**接口里的**apply**方法,并将其注入到spring bean中就可以实现自动调用。
|
||||
|
||||
```java
|
||||
@Description("文档解析")
|
||||
@Service
|
||||
public class DocumentAnalyzer implements Function<DocumentAnalyzer.Request, DocumentAnalyzer.Response> {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Request {
|
||||
// 这2个jackson注解的目的是让 spring ai 提取参数和描述
|
||||
@JsonPropertyDescription(value = "需要解析的文档路径")
|
||||
@JsonProperty(value = "path", required = true)
|
||||
private String path;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Response {
|
||||
private String result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response apply(Request request) {
|
||||
var resource = new FileSystemResource(request.path);
|
||||
TikaDocumentReader reader = new TikaDocumentReader(resource);
|
||||
return new Response(reader.read().get(0).getContent());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用函数
|
||||
|
||||
```java
|
||||
ChatClient.create(chatModel)
|
||||
.prompt()
|
||||
.messages(new UserMessage(prompt))
|
||||
// spring ai会根据beanName查找fucntion
|
||||
.functions(functionName)
|
||||
.stream()
|
||||
.chatResponse()
|
||||
.map(chatResponse -> ServerSentEvent.builder(JSONUtil.toJsonStr(chatResponse)).event("message").build());
|
||||
```
|
||||
|
||||
可以用封装一个http接口,接收`prompt`和`functionName`完成函数调用。
|
||||
|
||||
## 总结
|
||||
|
||||
Spring AI框架帮助我们实现了各大主流AI大模型的API封装和常用的一些工具组件,依托spring强大的生态,各大主流的AI大模型供应商也在积极适配中。它简化了我们的开发工作量,同类型的框架还有LangChain4J。
|
Loading…
Reference in New Issue
Block a user