主页 > 开源代码  > 

FastGPT源码:如何实现“问题优化“

FastGPT源码:如何实现“问题优化“

文章目录 FastGPT 源码:如何实现 "问题优化"一、前言二、源码分析2.1 queryExtension.ts 提示词2.2 queryExtension.ts 核心逻辑2.3 queryExtension 引用位置 三、流程总结

FastGPT 源码:如何实现 “问题优化” 一、前言 问题优化的背景和目的 在 RAG (检索增强生成) 系统中,用户的问题需要去数据库中执行向量搜索来找到相关内容但在连续对话中,用户的后续问题往往是不完整的,比如"第二点是什么"这样的问题如果直接用这样的问题去搜索,由于缺乏上下文,很难找到相关内容因此需要问题优化模块来补全用户的问题,使其变得完整和明确 核心实现方式 FastGPT 主要通过 queryExtension 函数来实现问题优化,核心代码在 packages/service/core/ai/functions/queryExtension.ts 中:

输入参数包括:

chatBg: 对话背景query: 用户当前问题histories: 历史对话记录model: 使用的模型

实现流程:

构建提示词模板,包含示例和要求结合历史记录和当前问题生成完整的提示词调用 AI 模型生成多个检索词返回原始问题和扩展后的问题列表 提示词设计 FastGPT 使用了精心设计的提示词模板来引导 AI 模型生成高质量的检索词: const defaultPrompt = `作为一个向量检索助手,你的任务是结合历史记录,从不同角度,为"原问题"生成个不同版本的"检索词",从而提高向量检索的语义丰富度,提高向量检索的精度。生成的问题要求指向对象清晰明确,并与"原问题语言相同"。`; 实际效果 原问题:“第二点是什么”历史记录中包含了 “FastGPT 的优势” 的上下文优化后的检索词会变成: “介绍下 FastGPT 简便的优势”“FastGPT 为什么使用起来简便?”“FastGPT的有哪些简便的功能?” 搜索结果处理 优化后的问题会用于知识库搜索,搜索结果还会经过重排序(ReRank)来进一步提高相关性: const reRankSearchResult = async ({ data, query }: { data: SearchDataResponseItemType[]; query: string; }) => { // 使用 rerank 模型对搜索结果重新排序 const results = await reRankRecall({ query, documents: data.map((item) => ({ id: item.id, text: `${item.q}\n${item.a}` })) }); };

这样的问题优化机制确保了即使在用户提出不完整或指代性问题时,系统也能准确理解用户意图并找到相关的知识库内容。

二、源码分析 2.1 queryExtension.ts 提示词 作为一个向量检索助手,你的任务是结合历史记录,从不同角度,为“原问题”生成个不同版本的“检索词”,从而提高向量检索的语义丰富度,提高向量检索的精度。生成的问题要求指向对象清晰明确,并与“原问题语言相同”。例如: 历史记录: """ """ 原问题: 介绍下剧情。 检索词: ["介绍下故事的背景和主要人物。","故事的主题是什么?","剧情是是如何发展的?"] ---------------- 历史记录: """ Q: 对话背景。 A: 当前对话是关于 Nginx 的介绍和使用等。 """ 原问题: 怎么下载 检索词: ["Nginx 如何下载?","下载 Nginx 需要什么条件?","有哪些渠道可以下载 Nginx?"] ---------------- 历史记录: """ Q: 对话背景。 A: 当前对话是关于 Nginx 的介绍和使用等。 Q: 报错 "no connection" A: 报错"no connection"可能是因为…… """ 原问题: 怎么解决 检索词: ["Nginx报错"no connection"如何解决?","造成'no connection'报错的原因。","Nginx提示'no connection',要怎么办?"] ---------------- 历史记录: """ Q: 护产假多少天? A: 护产假的天数根据员工所在的城市而定。请提供您所在的城市,以便我回答您的问题。 """ 原问题: 沈阳 检索词: ["沈阳的护产假多少天?"] ---------------- 历史记录: """ Q: 作者是谁? A: FastGPT 的作者是 labring。 """ 原问题: Tell me about him 检索词: ["Introduce labring, the author of FastGPT." ," Background information on author labring." "," Why does labring do FastGPT?"] ---------------- 历史记录: """ Q: 对话背景。 A: 关于 FatGPT 的介绍和使用等问题。 """ 原问题: 你好。 检索词: ["你好"] ---------------- 历史记录: """ Q: FastGPT 如何收费? A: FastGPT 收费可以参考…… """ 原问题: 你知道 laf 么? 检索词: ["laf是什么?","如何使用laf?","laf的介绍。"] ---------------- 历史记录: """ Q: FastGPT 的优势 A: 1. 开源 2. 简便 3. 扩展性强 """ 原问题: 介绍下第2点。 检索词: ["介绍下 FastGPT 简便的优势", "FastGPT 为什么使用起来简便?","FastGPT的有哪些简便的功能?"]。 ---------------- 历史记录: """ Q: 什么是 FastGPT? A: FastGPT 是一个 RAG 平台。 Q: 什么是 Laf? A: Laf 是一个云函数开发平台。 """ 原问题: 它们有什么关系? 检索词: ["FastGPT和Laf有什么关系?","FastGPT的RAG是用Laf实现的么?"] ---------------- 历史记录: """ {{histories}} """ 原问题: {{query}} 检索词: ` 2.2 queryExtension.ts 核心逻辑

好的,我来帮您逐行分析 queryExtension.ts 的代码实现:

导入依赖 import { replaceVariable } from '@fastgpt/global/common/string/tools'; // 用于替换字符串中的变量 import { getAIApi } from '../config'; // 获取 AI API 配置 import { ChatItemType } from '@fastgpt/global/core/chat/type'; // 聊天项类型定义 import { countGptMessagesTokens } from '@fastgpt/global/common/string/tiktoken'; // 计算 token 数量 import { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type'; // OpenAI 聊天参数类型 import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt'; // 聊天内容转换为运行时提示词 提示词模板定义 const defaultPrompt = `作为一个向量检索助手...`;

这是一个很长的提示词模板,包含了多个示例。每个示例都遵循相同的格式:

历史记录: 展示对话上下文原问题: 用户当前的问题检索词: 生成的扩展问题数组 主函数定义 export const queryExtension = async ({ chatBg, // 对话背景 query, // 用户当前问题 histories = [], // 历史对话记录 model // 使用的模型 }) => { 构建系统提示词 const systemFewShot = chatBg ? `Q: 对话背景。 A: ${chatBg} ` : '';

如果有对话背景,则添加到提示词中

构建历史对话 const historyFewShot = histories .map((item) => { const role = item.obj === 'Human' ? 'Q' : 'A'; return `${role}: ${chatValue2RuntimePrompt(item.value).text}`; }) .join('\n');

将历史对话记录转换为 Q/A 格式的文本

合并提示词 const concatFewShot = `${systemFewShot}${historyFewShot}`.trim(); 初始化 AI API const ai = getAIApi({ timeout: 480000 // 8分钟超时 }); 构建请求消息 const messages = [ { role: 'user', content: replaceVariable(defaultPrompt, { query: `${query}`, histories: concatFewShot }) } ] as ChatCompletionMessageParam[];

将用户问题和历史记录替换到提示词模板中

调用 AI 接口 const result = await ai.chat pletions.create({ model: model, temperature: 0.01, // 温度很低,保证输出稳定性 messages, stream: false }); 处理返回结果 let answer = result.choices?.[0]?.message?.content || ''; if (!answer) { return { rawQuery: query, extensionQueries: [], model, tokens: 0 }; } 解析结果 answer = answer.replace(/\\"/g, '"'); // 处理转义字符 try { const queries = JSON.parse(answer) as string[]; // 解析为字符串数组 return { rawQuery: query, // 原始问题 extensionQueries: Array.isArray(queries) ? queries : [], // 扩展后的问题列表 model, // 使用的模型 tokens: countGptMessagesTokens(messages) // token 数量 }; } catch (error) { // 解析失败时返回空结果 console.log(error); return { rawQuery: query, extensionQueries: [], model, tokens: 0 }; }

这个函数的主要作用是:

接收用户问题和历史对话使用精心设计的提示词引导 AI 生成多个检索词返回原始问题和扩展后的问题列表通过低温度参数(0.01)确保输出的稳定性完整的错误处理确保函数的健壮性

这样的设计使得即使用户提出不完整的问题,系统也能通过上下文理解用户意图并生成合适的检索词。

2.3 queryExtension 引用位置 知识库搜索中的使用 // packages/service/core/dataset/search/utils.ts export const datasetSearchQueryExtension = async ({ model, query, histories, chatBg }) => { const result = await queryExtension({ model, query, histories, chatBg }); }

这是最主要的使用场景,在知识库搜索前对用户问题进行优化。

工作流节点中的使用 // packages/service/core/workflow/dispatch/tools/queryExternsion.ts export const dispatchQueryExtension = async ({ model, params, histories, chatBg }) => { const queryExtensionModel = getLLMModel(model); const { extensionQueries, tokens } = await queryExtension({ chatBg, query: params.userChatInput, histories, model: queryExtensionModel.model }); }

作为工作流中的一个独立节点使用,可以在对话流程中进行问题优化。

搜索测试中的使用 // projects/app/src/pages/api/core/dataset/searchTest.ts const { concatQueries, rewriteQuery, aiExtensionResult } = await datasetSearchQueryExtension({ model: body.model, query: body.searchParams.query, histories: body.searchParams.histories || [], chatBg: body.searchParams.chatBg });

在知识库的搜索测试功能中使用,用于测试问题优化的效果。

配置相关 在多个配置文件中,我们可以看到 usedInQueryExtension 的配置: { "usedInQueryExtension": true // 标记模型是否可用于问题优化 } UI 组件中的使用 // projects/app/src/components/core/module/DatasetParamsModal.tsx const queryExtensionModel = watch('datasetSearchExtensionModel');

在界面上提供问题优化相关的配置选项。

三、流程总结 用户发起问题如果启用了问题优化功能: 系统会调用 queryExtension 生成多个检索词这些检索词会与原始问题一起用于知识库搜索搜索结果会经过重排序和合并 最终返回最相关的知识库内容

这种设计让系统能够:

更好地理解用户的意图处理不完整或指代性的问题提高知识库搜索的准确性支持连续对话中的上下文理解
标签:

FastGPT源码:如何实现“问题优化“由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“FastGPT源码:如何实现“问题优化“