



如何用一段话去数据库查找数据?答案是向量求相似度。在高中的时候我们学过可以用cos求两个向量之间的夹角,cos值越大,夹角越小,夹角越小,相似度越高。
所以第一件事情需要将句子向量化,然后和向量数据库中的向量进行比较,找到最相似的向量。
嵌入模型就可以帮我们做到这件事情。
使用嵌入模型
请参考基础配置。本例使用的是阿里嵌入模型。
选择模型
# 阿里灵积
dash-scope:
api-key: xxx
chat:
options:
model: qwen-max
embedding:
options:
model: text-embedding-v2
ETL是提取、转换、加载的缩写,从原始的文档到数据库需要经历提取(.doc、.ppt、.xlsx等)、转换(数据结构化、清理数据、数据分块)、写入向量数据库。这个过程可以进行多种处理,确保最后的数据适合AI问答。
SpringAI提供了ETL框架。它是搭建知识库框架的基石。
框架介绍
- DocumentReader:文档读取器,读取文档,比如PDF、Word、Excel等。如:
JsonReader
(读取JSON),TextReader
(读取文本),PagePdfDocumentReader
(读取PDF),TikaDocumentReader
(读取各种文件,大部分都可以支持.pdf,.xlsx,.docx,.pptx,.md,.json等)。上诉的这些reader都是DocumentReader
的实现类。 - DocumentTransformer:文档转换器,处理文档。
TextSplitter
(文档切割成小块),ContentFormatTransformer
(将文档变成键值对),SummaryMetadataEnricher
(使用大模型总结文档),KeywordMetadataEnricher
(使用大模型提取文档关键词)。 - DocumentWriter: 文档写入器,将文档写入向量数据库或者本地文件。
VectorStore
(向量数据库写入器),FileDocumentWriter
(文件写入器)。
本节的内容是:编写文档解析函数来学习SpringAi
风格的Function Call
我们知道 AI 的能力是文本生成,但是遇到一些复杂的需求时如何让 ai 可以回答出用户的提问。比如我想让 ai 读取本地的某个文件然后回答文件里面的内容,那读取文件这个操作 ai 明显不会。因此我们可以编写函数来拓展 ai 的能力。
结构描述
下面是一个简单的函数描述,把我们代码里面已有的函数转化成这种格式的描述。这样 ai 就可以知道什么时候去调用函数,以及调用函数时需要填哪些参数。
更加详细的结构请参考JSON Scheme reference
为了让AI记住你和它的对话,需要把对话信息存储起来。当你N+1次和AI聊天的时候,需要把之前的N次对话都带上这样AI才能记住你和它的对话。
不过有时候为了节省Token
,并不一定把所有的对话都带上,可以只携带前面几条对话。
基础模型的接入
本案例使用的是阿里的灵积AI服务请参考灵积接入。
MessageChatMemoryAdvisor
MessageChatMemoryAdvisor
会读取会话id对应的消息列表,并把消息列表拼接到历史的消息中。
要搭建自己的知识库除了文档嵌入到向量数据库之外,就是RAG了。当用户提问的时候先从想来数据库搜索相关的资料,再把相关的资料拼接到用户的提问中,再让模型生成答案。
文档嵌入
请参考文档嵌入,向数据库中插入一些自己的文档。
QuestionAnswerAdvisor
QuestionAnswerAdvisor
可以在用户发起的提问时,先向数据库查询相关的文档,再把相关的文档拼接到用户的提问中,再让模型生成答案。那就是RAG
的实现了。
向量数据库是AI记忆的核心组件,AI记忆除了历史的对话信息之外就是向量数据库中存储文档了,也就是大家常说的知识库。本节内容介绍如何向量数据库中存储文档和检索文档。为接下来的知识库(RAG)搭建做铺垫
基础模型的接入
本案例使用的是阿里的灵积AI服务请参考灵积接入。
安装RedisStack
需要先禁用掉自己原本的redis,防止端口冲突。访问localhost:8001
查看数据库的信息。用户名:default
,密码:123456
。
我原来的版本是和GitLab
做集成,从GitLab
上拉取代码,分析提交。但是考虑到国内调用GitHub
不方便,需要配代理我删除了分析提交的部分。不过不影响核心的代码评审逻辑的学习。
当用户提问:
请你帮我分析一下这个文件:src/main/java/io/github/qifan777/knowledge/user/UserController.java
我主要对代码中的类引用关系(imports
),类中拥有的方法关系(owns
),方法中调用的方法关系(uses
),三种关系进行构建
实体设计
类节点
@Node
@Data
@Accessors(chain = true)
public class ClassNode {
@Id
private String id;
private String name;
private String content;
// 类中的方法
@Relationship(direction = Relationship.Direction.OUTGOING, type = "OWNS")
private List<MethodNode> ownsMethodNodes;
// 类中导入的其他类
@Relationship(direction = Relationship.Direction.OUTGOING, type = "IMPORTS")
private List<ClassNode> importNodes;
}