Commit 8e56b81a3a73de6e6d2d4d2e8da9b1285ef69df8
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
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeDocumentCreateReqVO.java
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<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
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); | ... | ... |