Commit 8e56b81a3a73de6e6d2d4d2e8da9b1285ef69df8

Authored by YunaiV
1 parent 0b1d9ce2

【代码评审】AI 大模型:知识库的逻辑

Showing 14 changed files with 25 additions and 17 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeCreateMyReqVO.java
... ... @@ -32,4 +32,5 @@ public class AiKnowledgeCreateMyReqVO {
32 32 @Schema(description = "topK", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
33 33 @NotNull(message = "topK 不能为空")
34 34 private Integer topK;
  35 +
35 36 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeDocumentCreateReqVO.java
... ... @@ -42,4 +42,5 @@ public class AiKnowledgeDocumentCreateReqVO {
42 42 @Schema(description = "分块是否保留分隔符", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
43 43 @NotNull(message = "分块是否保留分隔符不能为空")
44 44 private Boolean keepSeparator;
  45 +
45 46 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java
... ... @@ -57,17 +57,16 @@ public class AiKnowledgeDO extends BaseDO {
57 57 * topK
58 58 */
59 59 private Integer topK;
60   -
61 60 /**
62 61 * 相似度阈值
63 62 */
64 63 private Double similarityThreshold;
65 64  
66   -
67 65 /**
68 66 * 状态
69 67 * <p>
70 68 * 枚举 {@link CommonStatusEnum}
71 69 */
72 70 private Integer status;
  71 +
73 72 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java
... ... @@ -47,10 +47,12 @@ public class AiKnowledgeDocumentDO extends BaseDO {
47 47 * 字符数
48 48 */
49 49 private Integer wordCount;
  50 + // TODO @新:chunk 1)是不是 segment,这样命名保持一致会好点哈?2)Size 是不是改成 Tokens 会统一点;3)defaultChunkSize、defaultChunkSize、minChunkSizeChars、maxNumChunks 这几个字段的命名,可能要微信一起讨论下。尽量命名保持风格统一哈。
50 51 /**
51 52 * 每个文本块的目标 token 数
52 53 */
53 54 private Integer defaultChunkSize;
  55 + // TODO @xin:SizeChars 和 wordCount 好像是一个意思,是不是也要统一哈。
54 56 /**
55 57 * 每个文本块的最小字符数
56 58 */
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java
... ... @@ -27,7 +27,7 @@ public class AiKnowledgeSegmentDO extends BaseDO {
27 27 /**
28 28 * 向量库的编号
29 29 */
30   - @TableField(updateStrategy = FieldStrategy.ALWAYS)
  30 + @TableField(updateStrategy = FieldStrategy.ALWAYS) // TODO @新:尽量规避要这个注解。万一后面加个 status 单独更新,可能会踩坑。
31 31 private String vectorId;
32 32 /**
33 33 * 知识库编号
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java
... ... @@ -25,9 +25,11 @@ public interface AiKnowledgeSegmentMapper extends BaseMapperX&lt;AiKnowledgeSegment
25 25 .orderByDesc(AiKnowledgeSegmentDO::getId));
26 26 }
27 27  
  28 + // TODO @新:selectListByXXX 哈
28 29 default List<AiKnowledgeSegmentDO> selectList(List<String> vectorIdList) {
29 30 return selectList(new LambdaQueryWrapperX<AiKnowledgeSegmentDO>()
30 31 .in(AiKnowledgeSegmentDO::getVectorId, vectorIdList)
31 32 .orderByDesc(AiKnowledgeSegmentDO::getId));
32 33 }
  34 +
33 35 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java
... ... @@ -83,7 +83,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
83 83 .setStatus(CommonStatusEnum.ENABLE.getStatus()));
84 84 segmentMapper.insertBatch(segmentDOList);
85 85  
86   - // 3.2 向量化并存储
  86 + // 3. 向量化并存储
87 87 segments.forEach(segment -> segment.getMetadata().put(AiKnowledgeSegmentDO.FIELD_KNOWLEDGE_ID, createReqVO.getKnowledgeId()));
88 88 vectorStore.add(segments);
89 89 return documentId;
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java
... ... @@ -38,9 +38,8 @@ public interface AiKnowledgeSegmentService {
38 38 */
39 39 void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO);
40 40  
41   -
42 41 /**
43   - * 段落召回
  42 + * 召回段落
44 43 *
45 44 * @param reqVO 召回请求信息
46 45 * @return 召回的段落
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
... ... @@ -55,19 +55,19 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
55 55  
56 56 @Override
57 57 public void updateKnowledgeSegment(AiKnowledgeSegmentUpdateReqVO reqVO) {
58   - // 0 校验
  58 + // 1. 校验
59 59 AiKnowledgeSegmentDO oldKnowledgeSegment = validateKnowledgeSegmentExists(reqVO.getId());
  60 +
60 61 // 2.1 获取知识库向量实例
61 62 VectorStore vectorStore = knowledgeService.getVectorStoreById(oldKnowledgeSegment.getKnowledgeId());
62 63 // 2.2 删除原向量
63 64 vectorStore.delete(List.of(oldKnowledgeSegment.getVectorId()));
64   -
65 65 // 2.3 重新向量化
66 66 Document document = new Document(reqVO.getContent());
67 67 document.getMetadata().put(AiKnowledgeSegmentDO.FIELD_KNOWLEDGE_ID, oldKnowledgeSegment.getKnowledgeId());
68 68 vectorStore.add(List.of(document));
69 69  
70   - // 2.1 更新段落内容
  70 + // 3. 更新段落内容
71 71 AiKnowledgeSegmentDO knowledgeSegment = BeanUtils.toBean(reqVO, AiKnowledgeSegmentDO.class);
72 72 knowledgeSegment.setVectorId(document.getId());
73 73 segmentMapper.updateById(knowledgeSegment);
... ... @@ -98,14 +98,14 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
98 98  
99 99 @Override
100 100 public List<AiKnowledgeSegmentDO> similaritySearch(AiKnowledgeSegmentSearchReqVO reqVO) {
101   - // 0. 校验
  101 + // 1. 校验
102 102 AiKnowledgeDO knowledge = knowledgeService.validateKnowledgeExists(reqVO.getKnowledgeId());
103 103 AiChatModelDO model = chatModelService.validateChatModel(knowledge.getModelId());
104 104  
105   - // 1.1 获取向量存储实例
  105 + // 2. 获取向量存储实例
106 106 VectorStore vectorStore = apiKeyService.getOrCreateVectorStore(model.getKeyId());
107 107  
108   - // 1.2 向量检索
  108 + // 3.1 向量检索
109 109 List<Document> documentList = vectorStore.similaritySearch(SearchRequest.query(reqVO.getContent())
110 110 .withTopK(knowledge.getTopK())
111 111 .withSimilarityThreshold(knowledge.getSimilarityThreshold())
... ... @@ -113,11 +113,10 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
113 113 if (CollUtil.isEmpty(documentList)) {
114 114 return ListUtil.empty();
115 115 }
116   - // 2.1 段落召回
  116 + // 3.2 段落召回
117 117 return segmentMapper.selectList(CollUtil.getFieldValues(documentList, "id", String.class));
118 118 }
119 119  
120   -
121 120 /**
122 121 * 校验段落是否存在
123 122 *
... ... @@ -131,4 +130,5 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
131 130 }
132 131 return knowledgeSegment;
133 132 }
  133 +
134 134 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeService.java
... ... @@ -23,7 +23,6 @@ public interface AiKnowledgeService {
23 23 */
24 24 Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId);
25 25  
26   -
27 26 /**
28 27 * 创建【我的】知识库
29 28 *
... ... @@ -32,7 +31,6 @@ public interface AiKnowledgeService {
32 31 */
33 32 void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId);
34 33  
35   -
36 34 /**
37 35 * 校验知识库是否存在
38 36 *
... ... @@ -49,6 +47,7 @@ public interface AiKnowledgeService {
49 47 */
50 48 PageResult<AiKnowledgeDO> getKnowledgePageMy(Long userId, PageParam pageReqVO);
51 49  
  50 + // TODO @新:knowledgeId 和 validateKnowledgeExists 的 id 是同一个么?如果是的话,建议变量也用 id 哈,然后两边的 id 注释,保持一致
52 51 /**
53 52 * 根据知识库编号获取向量存储实例
54 53 *
... ... @@ -56,4 +55,5 @@ public interface AiKnowledgeService {
56 55 * @return 向量存储实例
57 56 */
58 57 VectorStore getVectorStoreById(Long knowledgeId);
  58 +
59 59 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeServiceImpl.java
... ... @@ -38,6 +38,7 @@ public class AiKnowledgeServiceImpl implements AiKnowledgeService {
38 38 private AiChatModelService chatModelService;
39 39 @Resource
40 40 private AiApiKeyService apiKeyService;
  41 + // TODO @新:chatModelService 和 apiKeyService 可以放到 33 行的 chatModalService 后面。尽量保持,想通类型的变量在一块。例如说,Service 一块,Mapper 一块。
41 42  
42 43 @Override
43 44 public Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId) {
... ... @@ -85,6 +86,7 @@ public class AiKnowledgeServiceImpl implements AiKnowledgeService {
85 86 public VectorStore getVectorStoreById(Long knowledgeId) {
86 87 AiKnowledgeDO knowledge = validateKnowledgeExists(knowledgeId);
87 88 AiChatModelDO model = chatModelService.validateChatModel(knowledge.getModelId());
  89 + // 创建或获取 VectorStore 对象
88 90 return apiKeyService.getOrCreateVectorStore(model.getKeyId());
89 91 }
90 92  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java
... ... @@ -146,6 +146,7 @@ public class AiApiKeyServiceImpl implements AiApiKeyService {
146 146 public VectorStore getOrCreateVectorStore(Long id) {
147 147 AiApiKeyDO apiKey = validateApiKey(id);
148 148 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
  149 + // 创建或获取 VectorStore 对象
149 150 return modelFactory.getOrCreateVectorStore(getEmbeddingModel(id), platform, apiKey.getApiKey(), apiKey.getUrl());
150 151 }
151 152  
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
... ... @@ -47,7 +47,7 @@
47 47  
48 48 <!-- 向量化,基于 Redis 存储,Tika 解析内容 -->
49 49  
50   - <!-- 暂不做经济型,先注释 -->
  50 + <!-- 暂不做经济型,先注释 TODO 经济型是啥呀? -->
51 51 <!-- <dependency>-->
52 52 <!-- <groupId>${spring-ai.groupId}</groupId>-->
53 53 <!-- <artifactId>spring-ai-transformers-spring-boot-starter</artifactId>-->
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
... ... @@ -197,6 +197,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
197 197 });
198 198 }
199 199  
  200 + // TODO @新:貌似可以创建一个大的 VectorStore。然后搜的时候,通过 Filter.Expression 过滤对应的数据。
200 201 @Override
201 202 public VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url) {
202 203 String cacheKey = buildClientCacheKey(VectorStore.class, platform, apiKey, url);
... ...