向量检索
核心功能
已经完成:
- 数据库设计:确保片段数据高效存储与管理。
- 用户登录:保障数据安全,防止未经授权的访问。
- 知识库管理:支持知识库的创建、更新和删除,便于用户维护内容。
- 文件拆分:将上传的文档拆分为片段,便于精细化管理。
- 片段向量化:通过向量化技术将片段转换为可计算的形式,便于相似度计算。
- 命中率测试:评估用户查询与片段的匹配效果。
- 文档与片段管理:支持对多个文档及其片段的高效管理。
- 问题管理:支持用户问题的增删改查操作。
- 应用管理:对应用及其参数进行管理和设置。
本节完成:
- 向量检索:从数据库中检索出语义相似的向量片段。
- 推理问答:基于搜索片段及用户问题生成自动化回答。
片段搜索功能
数据传输对象 (VO)
ParagraphSearchResultVo
package com.litongjava.maxkb.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class ParagraphSearchResultVo {
private Long id;
private String content, title;
private Long dataset_id;
private String dataset_name;
private Long document_id;
private String document_name;
private Boolean active;
private Integer hit_num;
private String status;
}
- 封装了片段搜索的结果,包括片段的基本信息及所属文档和数据集的相关信息。
- 使用 Lombok 注解简化代码。
搜索服务实现
MaxKbParagraphSearchService
package com.litongjava.maxkb.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.litongjava.db.activerecord.Db;
import com.litongjava.db.activerecord.Record;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.maxkb.vo.ParagraphSearchResultVo;
import com.litongjava.openai.constants.OpenAiModels;
import com.litongjava.template.SqlTemplates;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MaxKbParagraphSearchService {
public List<ParagraphSearchResultVo> search(Long[] datasetIdArray, Float similarity, Integer top_n, String question) {
Long vectorId = Aop.get(MaxKbEmbeddingService.class).getVectorId(question, OpenAiModels.text_embedding_3_large);
String sql = SqlTemplates.get("kb.search_paragraph_with_dataset_ids");
log.info("search_paragraph:{},{},{},{}", vectorId, Arrays.toString(datasetIdArray), similarity, top_n);
List<Record> records = Db.find(sql, vectorId, datasetIdArray, similarity, top_n);
List<ParagraphSearchResultVo> results = new ArrayList<>();
for (Record record : records) {
ParagraphSearchResultVo vo = record.toBean(ParagraphSearchResultVo.class);
results.add(vo);
}
return results;
}
}
- 向量生成:调用
MaxKbEmbeddingService
生成问题向量。 - SQL 查询:从
SqlTemplates
加载查询模板并执行搜索。 - 结果封装:将查询结果转换为
ParagraphSearchResultVo
列表,供前端使用。
单元测试
MaxKbParagraphSearchServiceTest
package com.litongjava.maxkb.service;
import java.util.List;
import org.junit.Test;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.maxkb.config.DbConfig;
import com.litongjava.maxkb.vo.ParagraphSearchResultVo;
import com.litongjava.tio.boot.testing.TioBootTest;
import com.litongjava.tio.utils.json.JsonUtils;
public class MaxKbParagraphSearchServiceTest {
@Test
public void test() {
TioBootTest.runWith(DbConfig.class);
Long[] datasetIdArray = { 446225135519784960L };
Float similarity = 0.2f;
Integer top_n = 3;
String question = "office hour";
List<ParagraphSearchResultVo> result = Aop.get(MaxKbParagraphSearchService.class).search(datasetIdArray, similarity, top_n, question);
System.out.println(JsonUtils.toJson(result));
}
}
- 验证搜索功能的正确性。
- 定义测试用例参数并输出搜索结果的 JSON 表示。
搜索逻辑与 SQL 解析
搜索逻辑
- 接收用户查询并向量化。
- 构建 SQL 查询以获取相关片段。
- 根据相似度排序结果并限制返回数量。
- 返回封装后的结果。
SQL 查询模板
--# kb.search_paragraph_with_dataset_ids
SELECT
sub.id,
sub.content,
sub.title,
sub.status,
sub.hit_num,
sub.is_active,
sub.dataset_id,
sub.document_id,
sub.dataset_name,
sub.document_name,
sub.similarity,
sub.similarity AS comprehensive_score
FROM (
SELECT
d.name AS document_name,
ds.name AS dataset_name,
p.id,
p.content,
p.title,
p.status,
p.hit_num,
p.is_active,
p.dataset_id,
p.document_id,
(1 - (p.embedding <=> c.v)) AS similarity
FROM
max_kb_paragraph p
JOIN
max_kb_document d ON p.document_id = d.id
JOIN
max_kb_dataset ds ON p.dataset_id = ds.id
JOIN
max_kb_embedding_cache c ON c.id = ?
WHERE
p.is_active = TRUE
AND p.deleted = 0
AND ds.deleted = 0
AND p.dataset_id = ANY (?)
) sub
WHERE
sub.similarity > ?
ORDER BY
sub.similarity DESC
LIMIT ?;
- 子查询:通过关联片段、文档、数据集及向量缓存表计算相似度。
- 过滤:只返回激活且未删除的片段。
- 排序与限制:按相似度降序排列,并限制返回数量。
结果解析示例
[
{
"id": "446228832295108608",
"content": "I reserve the right to be offline after 6 pm and on Saturdays...",
"dataset_name": "ICS 111",
"document_name": "ICS111_31391_Miller_Syllabus_F24.pdf",
"similarity": 0.85
},
...
]
- 字段:
id
:片段 ID。content
:片段内容。similarity
:片段与问题的相似度。dataset_name
和document_name
:片段所属数据集和文档。
推理功能实现
数据交互流程
- 获取用户问题。
- 搜索相关片段。
- 构造提示词并请求大语言模型。
- 返回问答结果。
示例提示词模板
用户问题:{question}
相关片段:
1. {content1}
2. {content2}
...
请根据以上信息生成回答:
大语言模型处理
调用模型接口,传入用户问题和片段信息,生成回答。下一节将获详细介绍
总结
通过实现片段搜索与推理问答,系统能够提供高效且智能的问答服务。未来可扩展功能包括:
- 增强多语言支持。
- 提高嵌入模型的准确性。
- 实现更复杂的上下文推理能力。