FastGPT源码解析 Agent知识库文本资料处理详解和代码分析

发布于:2025-09-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

FastGPT知识库文本处理完整分析

1. 支持的文本输入类型

FastGPT支持多种文本输入类型,定义在 DatasetTypeEnumImportDataSourceEnum 中:

导出数据支持数据集类型

  • folder - 文件夹
  • dataset - 普通数据集
  • websiteDataset - 网站数据集
  • externalFile - 外部文件
  • apiDataset - API数据集
  • feishu - 飞书数据集
  • yuque - 语雀数据集

导入数据源

  • fileLocal - 本地文件上传
  • fileLink - 链接导入
  • fileCustom - 手动输入文本
  • csvTable - CSV表格导入
  • externalFile - 外部文件
  • apiDataset - API数据集
  • reTraining - 重新训练

2. 文件格式支持

支持的文件格式(在 readRawContentByFileBuffer 中处理):

// 支持的文件扩展名
const supportedExtensions = [
  'txt', 'md', 'html', 'pdf', 'docx', 'pptx', 'xlsx', 'csv'
];

3. 文本处理流程

3.1 文件读取阶段

核心文件: packages/service/core/dataset/read.ts

// 根据不同数据源读取原始文本
export const readDatasetSourceRawText = async ({
  teamId,
  type,
  sourceId,
  isQAImport,
  selector,
  externalFileId,
  apiServer,
  feishuServer,
  yuqueServer
}) => {
  if (type === DatasetSourceReadTypeEnum.fileLocal) {
    // 从MongoDB GridFS读取本地文件
    const { rawText } = await readFileContentFromMongo({
      teamId,
      bucketName: BucketNameEnum.dataset,
      fileId: sourceId,
      isQAImport
    });
    return rawText;
  } else if (type === DatasetSourceReadTypeEnum.link) {
    // 网页链接抓取
    const result = await urlsFetch({
      urlList: [sourceId],
      selector
    });
    return result[0]?.content || '';
  } else if (type === DatasetSourceReadTypeEnum.externalFile) {
    // 外部文件URL读取
    const rawText = await readFileRawTextByUrl({
      teamId,
      url: sourceId,
      relatedId: externalFileId
    });
    return rawText;
  } else if (type === DatasetSourceReadTypeEnum.apiFile) {
    // API数据集文件读取
    const rawText = await readApiServerFileContent({
      apiServer,
      feishuServer,
      yuqueServer,
      apiFileId: sourceId,
      teamId
    });
    return rawText;
  }
  return '';
};

3.2 文件内容解析

核心文件: packages/service/worker/readFile/index.ts

// Worker进程处理不同格式文件
const readRawContentByFileBuffer = async (params) => {
  switch (params.extension) {
    case 'txt':
    case 'md':
      return readFileRawText(params);
    case 'html':
      return readHtmlRawText(params);
    case 'pdf':
      return readPdfFile(params);
    case 'docx':
      return readDocsFile(params);
    case 'pptx':
      return readPptxRawText(params);
    case 'xlsx':
      return readXlsxRawText(params);
    case 'csv':
      return readCsvRawText(params);
    default:
      return Promise.reject('不支持的文件格式');
  }
};

3.3 文本分块处理

核心文件: packages/service/core/dataset/read.ts

// 将原始文本转换为训练块
export const rawText2Chunks = ({
  rawText,
  isQAImport,
  chunkLen = 512,
  ...splitProps
}) => {
  if (isQAImport) {
    // CSV QA格式导入
    const { chunks } = parseCsvTable2Chunks(rawText);
    return chunks;
  }

  // 普通文本分块
  const { chunks } = splitText2Chunks({
    text: rawText,
    chunkLen,
    ...splitProps
  });

  return chunks.map((item) => ({
    q: item,
    a: ''
  }));
};

4. 训练模式

核心文件: packages/global/core/dataset/constants.ts

export enum TrainingModeEnum {
  chunk = 'chunk',    // 直接分块
  auto = 'auto',      // 自动处理
  qa = 'qa'          // 问答对
}

export const TrainingTypeMap = {
  [TrainingModeEnum.chunk]: {
    label: '直接分块模式',
    tooltip: '将文本按长度切分成块',
    openSource: true
  },
  [TrainingModeEnum.auto]: {
    label: '自动处理模式', 
    tooltip: 'AI自动优化处理',
    openSource: false
  },
  [TrainingModeEnum.qa]: {
    label: 'QA拆分模式',
    tooltip: '问答对格式导入',
    openSource: true
  }
};

5. 数据存储结构

5.1 数据集Schema

核心文件: packages/service/core/dataset/schema.ts

// 数据集基本信息
const DatasetSchema = new Schema({
  teamId: { type: Schema.Types.ObjectId, required: true },
  name: { type: String, required: true },
  avatar: { type: String, default: '' },
  intro: { type: String, default: '' },
  type: { type: String, required: true },
  status: { type: String, default: DatasetStatusEnum.active },
  vectorModel: { type: String, required: true },
  agentModel: { type: String, required: true },
  // 网站配置
  websiteConfig: {
    url: String,
    selector: String
  },
  // API服务器配置
  apiServer: Object,
  feishuServer: Object,
  yuqueServer: Object,
  autoSync: { type: Boolean, default: false }
});

5.2 集合Schema

核心文件: packages/service/core/dataset/collection/schema.ts

// 数据集合(文件/文档)
const DatasetCollectionSchema = new Schema({
  teamId: { type: Schema.Types.ObjectId, required: true },
  datasetId: { type: Schema.Types.ObjectId, required: true },
  parentId: Schema.Types.ObjectId,
  name: { type: String, required: true },
  type: { type: String, required: true },
  
  // 训练配置
  trainingType: { type: String, default: TrainingModeEnum.chunk },
  chunkSize: { type: Number, default: 512 },
  chunkSplitter: String,
  qaPrompt: String,
  
  // 文件信息
  fileId: String,           // 本地文件ID
  rawLink: String,          // 链接URL
  externalFileId: String,   // 外部文件ID
  apiFileId: String,        // API文件ID
  
  // 文本信息
  rawTextLength: Number,
  hashRawText: String,
  
  // 元数据
  metadata: {
    webPageSelector: String,
    relatedImgId: String,
    type: Object
  },
  
  tags: [String],
  nextSyncTime: Date
});

5.3 数据块Schema

核心文件: packages/service/core/dataset/data/schema.ts

// 训练数据块
const DatasetDataSchema = new Schema({
  teamId: { type: Schema.Types.ObjectId, required: true },
  datasetId: { type: Schema.Types.ObjectId, required: true },
  collectionId: { type: Schema.Types.ObjectId, required: true },
  
  q: { type: String, required: true },  // 问题或文本块
  a: { type: String, default: '' },     // 答案或补充内容
  chunkIndex: { type: Number, default: 0 },
  
  // 向量索引
  indexes: [{
    defaultIndex: { type: Boolean, default: false },
    dataId: { type: String, required: true },
    text: { type: String, required: true }
  }],
  
  updateTime: { type: Date, default: Date.now },
  rebuilding: Boolean
});

6. 向量化处理

核心文件: packages/service/common/vectorStore/controller.ts

// 插入向量数据
export const insertDatasetDataVector = async ({
  model,
  query,
  ...props
}) => {
  // 生成向量
  const { vectors, tokens } = await getVectorsByText({
    model,
    input: query,
    type: 'db'
  });
  
  // 插入向量数据库
  const { insertId } = await Vector.insert({
    ...props,
    vector: vectors[0]
  });

  return { tokens, insertId };
};

7. 搜索检索

核心文件: packages/service/core/dataset/search/controller.ts

支持三种搜索模式:

export enum DatasetSearchModeEnum {
  embedding = 'embedding',        // 向量搜索
  fullTextRecall = 'fullTextRecall', // 全文搜索
  mixedRecall = 'mixedRecall'     // 混合搜索
}

// 主搜索函数
export async function searchDatasetData(props) {
  // 1. 向量召回
  const embeddingRecall = async ({ query, limit }) => {
    const { vectors } = await getVectorsByText({
      model: getEmbeddingModel(model),
      input: query,
      type: 'query'
    });

    const { results } = await recallFromVectorStore({
      teamId,
      datasetIds,
      vector: vectors[0],
      limit
    });
    
    return formatResults(results);
  };

  // 2. 全文召回
  const fullTextRecall = async ({ query, limit }) => {
    const searchResults = await MongoDatasetDataText.aggregate([
      {
        $match: {
          teamId: new Types.ObjectId(teamId),
          datasetId: { $in: datasetIds },
          $text: { $search: jiebaSplit({ text: query }) }
        }
      },
      { $sort: { score: { $meta: 'textScore' } } },
      { $limit: limit }
    ]);
    
    return formatResults(searchResults);
  };

  // 3. 重排序
  const reRankResults = usingReRank 
    ? await datasetDataReRank({ query: reRankQuery, data: concatResults })
    : [];

  // 4. RRF融合多路召回结果
  const rrfConcatResults = datasetSearchResultConcat([
    { k: 60, list: embeddingRecallResults },
    { k: 60, list: fullTextRecallResults },
    { k: 58, list: reRankResults }
  ]);

  return filterAndRankResults(rrfConcatResults);
}

8. 前端导入界面

核心文件: projects/app/src/pageComponents/dataset/detail/Import/

支持多种导入方式的前端组件:

  • FileLocal.tsx - 本地文件上传
  • FileCustomText.tsx - 手动输入文本
  • FileLink.tsx - 网页链接导入
  • TableLocal.tsx - CSV表格导入
  • ExternalFile.tsx - 外部文件导入
  • APIDataset.tsx - API数据集导入

9. 关键代码文件路径

后端核心文件

  • packages/global/core/dataset/constants.ts - 数据集常量定义
  • packages/global/core/dataset/type.d.ts - 数据集类型定义
  • packages/service/core/dataset/read.ts - 文件读取核心逻辑
  • packages/service/core/dataset/training/controller.ts - 训练数据处理
  • packages/service/core/dataset/collection/controller.ts - 集合管理
  • packages/service/core/dataset/search/controller.ts - 搜索检索
  • packages/service/worker/readFile/index.ts - 文件解析Worker
  • packages/service/common/vectorStore/controller.ts - 向量存储

前端核心文件

  • projects/app/src/pageComponents/dataset/detail/Import/ - 导入界面组件
  • projects/app/src/web/core/dataset/ - 数据集相关前端逻辑

数据库Schema

  • packages/service/core/dataset/schema.ts - 数据集Schema
  • packages/service/core/dataset/collection/schema.ts - 集合Schema
  • packages/service/core/dataset/data/schema.ts - 数据块Schema

10. 核心处理流程总结

  1. 文件上传/输入 → 根据类型选择对应的读取方式
  2. 内容解析 → Worker进程解析不同格式文件内容
  3. 文本分块 → 根据训练模式进行文本切分
  4. 向量化 → 生成文本向量并存储到向量数据库
  5. 索引建立 → 建立全文搜索索引
  6. 存储 → 保存到MongoDB数据库
  7. 检索 → 支持向量搜索、全文搜索、混合搜索

这套系统支持从简单的文本输入到复杂的多模态文档处理,提供了完整的知识库构建和检索能力。


网站公告

今日签到

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