FastGPT 源码:混合检索调用链路
主要调用链路如下:
1. 入口函数
在 dispatchDatasetSearch
(packages/service/core/workflow/dispatch/dataset/search.ts):
export async function dispatchDatasetSearch(props: DatasetSearchProps) {
// 1. 获取参数
const {
teamId,
histories,
module,
params: {
datasets,
similarity,
limit,
usingReRank,
searchMode,
userChatInput
}
} = props;
// 2. 问题优化/扩展
const { concatQueries, rewriteQuery } = await datasetSearchQueryExtension({
query: userChatInput,
extensionModel,
extensionBg,
histories
});
// 3. 调用核心搜索函数
const { searchRes } = await searchDatasetData({
teamId,
reRankQuery: rewriteQuery,
queries: concatQueries,
model: vectorModel.model,
similarity,
limit,
datasetIds: datasets.map((item) => item.datasetId),
searchMode,
usingReRank
});
}
2. 核心搜索函数
searchDatasetData
(packages/service/core/dataset/search/controller.ts):
export async function searchDatasetData({
teamId,
reRankQuery,
queries,
model,
similarity,
limit,
searchMode,
usingReRank,
datasetIds
}) {
// 1. 向量检索和全文检索
const { embeddingRecallResults, fullTextRecallResults } = await multiQueryRecall({
embeddingLimit,
fullTextLimit
});
// 2. 第一次RRF合并(向量检索和全文检索结果)
const concatRecallResults = embeddingRecallResults.concat(
fullTextRecallResults.filter((item) => !set.has(item.id))
);
// 3. Rerank二次排序
const reRankResults = await reRankSearchResult({
query: reRankQuery,
data: concatRecallResults
});
// 4. 最终RRF合并(三种结果)
const rrfConcatResults = datasetSearchResultConcat([
{ k: 60, list: embeddingRecallResults },
{ k: 60, list: fullTextRecallResults },
{ k: 58, list: reRankResults }
]);
// 5. 结果过滤和处理
const scoreFilter = filterResults(rrfConcatResults);
return { searchRes: filterResultsByMaxTokens(scoreFilter, maxTokens) };
}
3. RRF合并函数
datasetSearchResultConcat
(packages/global/core/dataset/search/utils.ts):
export const datasetSearchResultConcat = (arr: { k: number; list: SearchDataResponseItemType[] }[]) => {
// 1. 计算每个结果的RRF分数
arr.forEach((item) => {
const k = item.k;
item.list.forEach((data, index) => {
const rank = index + 1;
const score = 1 / (k + rank);
// 合并分数...
});
});
// 2. 根据RRF分数排序
return results.sort((a, b) => b.rrfScore - a.rrfScore);
}
4. Rerank重排序函数
reRankRecall
(packages/service/core/ai/rerank/index.ts):
export function reRankRecall({query, documents}) {
// 调用重排序模型API
return POST(model.requestUrl, {
model: model.model,
query,
documents: documents.map((doc) => doc.text)
}).then(data => {
// 返回重排序结果和分数
return data?.results?.map(item => ({
id: documents[item.index].id,
score: item.relevance_score
}));
});
}
5. 完整流程
dispatchDatasetSearch
作为入口,接收搜索参数- 调用
searchDatasetData
执行核心搜索逻辑 - 在
searchDatasetData
中:- 先执行向量检索和全文检索
- 合并这两种检索结果
- 调用
reRankRecall
进行重排序 - 最后通过
datasetSearchResultConcat
合并所有结果
- 返回最终过滤和处理后的搜索结果
这个调用链路完整实现了:
- Embedding 和 BM25 检索
- 结果合并后的 Rerank
- 最终三路结果的 RRF 合并