FastGPT 引申:借鉴 FastGPT 基于MySQL + ES 实现知识库(含表结构以及核心代码)

发布于:2025-03-05 ⋅ 阅读:(28) ⋅ 点赞:(0)

FastGPT 引申:借鉴 FastGPT 基于MySQL + ES 实现知识库(含表结构以及核心代码)

一、整体思路

  • 知识库查询能力:引入 Elasticsearch (ES) 提供向量存储和检索能力。
  • 三层逻辑结构
    • 数据集:使用模块 ID 关联应用。
    • 数据:存储具体的知识内容。
    • 索引:提供高效的查询能力。

二、存储结构

2.1 MySQL 表结构

(1) knowledge_base_dataset

存储数据集基本信息

字段名 类型 描述
id BIGINT 主键
type INT 0:手动数据集
name VARCHAR 数据集名称
es_index_name VARCHAR ES 索引名称
extract_qa_prompt TEXT 抽取 QA 问答对 Prompt
extract_summary_prompt TEXT 抽取摘要 Prompt
extract_param_prompt TEXT 抽取参数 Prompt
is_deleted TINYINT 逻辑删除标志
(2) knowledge_base_data

存储具体知识数据项

字段名 类型 描述
id BIGINT 主键
dataset_id BIGINT 关联 dataset
main_content TEXT 主要内容
auxiliary_data TEXT 辅助数据
is_deleted TINYINT 逻辑删除标志
(3) knowledge_base_index

存储索引项

字段名 类型 描述
id BIGINT 主键
data_id BIGINT 关联 data 表主键
index_type INT 0-默认,1-用户指定,3-提取问题,4-相关摘要
index_content TEXT 索引内容
(4) ai_kb_relation

存储数据集与应用关联

字段名 类型 描述
id BIGINT 主键
module_id BIGINT 关联的模块 ID
dataset_id BIGINT 知识库数据集 ID

2.2 Elasticsearch Mapping 结构

(1) ES索引

存储知识数据的向量索引:ai_knowledge

{
  "mappings": {
    "properties": {
      "data_id": {
        "type": "long",
        "index": true
      },
      "index_id": {
        "type": "long",
        "index": true
      },
      "dataset_id": {
        "type": "long",
        "index": true
      },
      "vector_index": {
        "type": "dense_vector",
        "dims": 1024,
        "index": true,
        "similarity": "cosine"
      },
      "text_index": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      }
    }
  }
}
(2) 字段说明
字段名称 类型 说明
data_id long 关联 knowledge_base_data 主键 ID
index_id long 关联 knowledge_base_index 主键 ID
dataset_id long 关联 knowledge_base_dataset 主键 ID
vector_index dense_vector 1024 维度稠密向量,支持余弦相似度计算
text_index text 采用 ik_max_word 分词器进行索引

三、代码实现

3.1 调用 Embedding 服务

public List<Float> getVector(String text) {
    ResponseEntity responseEntity = xxxx;
    if (responseEntity != null && responseEntity.getCode() == 0) {
        List<List<Double>> vectorList = (List<List<Double>>) responseEntity.getData();
        if (vectorList != null && !vectorList.isEmpty()) {
            return vectorList.get(0).stream()
                    .map(Double::floatValue)
                    .collect(Collectors.toList());
        }
    }
    return null;
}

3.2 向量检索(ES KNN 查询)

public List<Knowledge> searchByVector(List<Float> vector) throws IOException {
    log.info("Searching knowledge with vector similarity using KNN");
    try {
        return client.search(s -> s
            .index(INDEX_NAME)
            .knn(k -> k
                .field("vector_index")
                .queryVector(vector)
                .k(DEFAULT_SIZE)
                .numCandidates(100)
            ),
            Knowledge.class
        ).hits().hits().stream()
            .map(Hit::source)
            .collect(Collectors.toList());
    } catch (Exception e) {
        log.error("Error searching knowledge by vector: {}", e.getMessage(), e);
        throw e;
    }
}

3.3 RRF 排序(融合向量检索和文本检索结果)

private Map<String, Double> calculateRRFScores(
        List<Hit<KnowledgeCommon>> vectorHits,
        List<Hit<KnowledgeCommon>> textHits) {

    Map<String, Double> rrfScores = new HashMap<>();
    int rank = 1;
    for (Hit<KnowledgeCommon> hit : vectorHits) {
        String id = hit.id();
        double score = VECTOR_WEIGHT * (1.0 / (rank + RRF_CONSTANT));
        rrfScores.put(id, rrfScores.getOrDefault(id, 0.0) + score);
        rank++;
    }

    rank = 1;
    for (Hit<KnowledgeCommon> hit : textHits) {
        String id = hit.id();
        double score = TEXT_WEIGHT * (1.0 / (rank + RRF_CONSTANT));
        rrfScores.put(id, rrfScores.getOrDefault(id, 0.0) + score);
        rank++;
    }

    return rrfScores;
}

四、总结

  • 采用 MySQL 存储基础数据,ES 存储向量及文本索引
  • ES 结合 KNN 和分词搜索进行知识检索
  • 使用 RRF 算法融合向量和文本搜索结果,提高查询质量

此方案支持灵活的知识管理和高效检索,可扩展至更大规模的知识库应用。


网站公告

今日签到

点亮在社区的每一天
去签到