拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Langchain-Chatchat 搜索引擎问答(search_engine_chat)全解析:搜索引擎接入、结果处理与生成链路

Langchain-Chatchat 搜索引擎问答search_engine_chat全解析搜索引擎接入、结果处理与生成链路【免费下载链接】Langchain-ChatchatLangchain-Chatchat原Langchain-ChatGLM基于 Langchain 与 ChatGLM, Qwen 与 Llama 等语言模型的 RAG 与 Agent 应用 | Langchain-Chatchat (formerly langchain-ChatGLM), local knowledge based LLM (like ChatGLM, Qwen and Llama) RAG and Agent app with langchain项目地址: https://gitcode.com/GitHub_Trending/la/Langchain-Chatchat本文围绕 Langchain-Chatchat 的搜索引擎问答能力展开系统梳理项目中互联网搜索的引擎接入方式Bing / DuckDuckGo / Metaphor / Searx、搜索结果到 LangChainDocument的转换逻辑以及检索 → 拼装 Prompt → LLM 生成 → 流式输出的完整调用链。阅读本文后你将能理解并配置搜索引擎问答功能、在 API 与 WebUI 中使用该能力并可对照源码定位每个环节的实现。主体说明来自仓库文档 search_engine_chat.md实现细节均可在当前仓库源码中得到印证。功能定位给 LLM 装上联网检索的眼睛Langchain-Chatchat 原本以知识库 RAG 问答见长而搜索引擎问答search_engine_chat解决的是另一类需求当用户提问超出本地知识库范围、或者需要实时/最新信息时系统先用搜索引擎在互联网上检索再把检索到的网页摘要作为上下文交给 LLM 生成带出处的回答。它与知识库问答共用同一套检索增强生成范式只是召回源从向量库换成了搜索引擎。从当前仓库代码看搜索引擎的底层实现各引擎封装、结果转换、统一入口search_engine集中在 search_internet.py隶属于 agent 工具工厂目录而对外服务化通过 kb_chat.py 中modesearch_engine的分支与 OpenAI 兼容端点完成。文档中记载的bing_search、duckduckgo_search、metaphor_search、search_result2docs等函数在当前代码中均有直接对应实现。统一调度SEARCH_ENGINES 注册表文档描述的核心调度方式是维护一张引擎名 → 搜索引擎函数的字典再按名称分发。当前源码 search_internet.py 中的注册表如下SEARCH_ENGINES { bing: bing_search, duckduckgo: duckduckgo_search, metaphor: metaphor_search, searx: searx_search, }从源码结构看除了文档记载的 Bing、DuckDuckGo、Metaphor 三个引擎外当前实现还补充了Searx自托管元搜索引擎作为第四种选择。配置侧与之对应的类型约束可以在 settings.py 中看到DEFAULT_SEARCH_ENGINE: t.Literal[bing, duckduckgo, metaphor, searx] duckduckgo SEARCH_ENGINE_TOP_K: int 3其中DEFAULT_SEARCH_ENGINE决定默认使用哪个引擎SEARCH_ENGINE_TOP_K是搜索结果数量默认值文档中多个函数的result_len/top_k缺省都指向这个常量。代码库中还在 kb_chat.py 里用它初始化 WebUI 的搜索引擎问答结果条数默认值st.session_state[se_top_k]。引擎函数实际调用时采用了统一的注入式签名——搜索引擎配置由外部config字典传入而不是靠函数内部读取环境变量便于同一个函数既服务 Agent 工具、又服务知识库聊天的搜索引擎问答模式详见下文调度与生成链路。各搜索引擎实现逐个解析bing_search微软必应 Web 搜索bing_search通过 LangChain 的BingSearchAPIWrapper封装调用微软必应搜索 API核心逻辑见 search_internet.pydef bing_search(text, config, top_k: int): search BingSearchAPIWrapper( bing_subscription_keyconfig[bing_key], bing_search_urlconfig[bing_search_url], ) return search.results(text, top_k)text要搜索的文本。top_k返回结果条数。配置要求bing_key订阅密钥与bing_search_urlAPI 端点缺一不可二者对应的默认配置键见 settings.py其中 URL 默认值为https://api.bing.microsoft.com/v7.0/search。在早期实现中这两个配置对应环境变量BING_SUBSCRIPTION_KEY与BING_SEARCH_URL未设置时函数会返回包含提示信息 标题 帮助文档链接的错误字典当前版本则直接按config字典取值若填入空密钥则实际搜索会失败因此配置完整性由部署者保证。成功时的返回结果是列表每项包含snippet摘要、title标题、link链接形如文档中给出的输出示例[ { snippet: 这是搜索结果的摘要, title: 搜索结果标题, link: https://example.com/search-result }, ]需要注意result_len/top_k只是期望返回数量实际结果仍受 Bing API 配额与命中的限制。duckduckgo_search免密钥的隐私搜索引擎duckduckgo_search是唯一无需 API Key的开箱即用引擎通过 LangChain 的DuckDuckGoSearchAPIWrapper实现search_internet.pydef duckduckgo_search(text, config, top_k: int): search DuckDuckGoSearchAPIWrapper() return search.results(text, top_k)这也是DEFAULT_SEARCH_ENGINE默认值取duckduckgo的原因——刚部署、尚未配置任何付费/自建引擎密钥时系统仍能立即跑通。它的返回结构为含title、snippet、url的字典列表文档输出示例中以url作为链接键名经过统一转换后会映射到结果文档的source元数据。由于该引擎对外网连通性有要求在国内网络环境下访问可能不稳定这也是配置注释中建议推荐自己部署 searx 搜索引擎国内使用最方便见 settings.py的出发点。metaphor_search带正文抓取与智能切分的进阶引擎metaphor_search是最复杂的一个引擎除搜索外还负责抓取正文内容并支持对长正文做二次切分。实现见 search_internet.py其流程可分为四步搜索以config[metaphor_api_key]创建 Metaphor 客户端client.search(text, num_resultstop_k, use_autopromptTrue)——use_autopromptTrue表示由 Metaphor 自动优化查询语句文档中记为默认启用自动提示。抓取正文search.get_contents().contents拉取每个结果的正文内容并通过markdownify把 HTML 正文转成干净的 Markdown 文本便于后续喂给 LLM。可选切分当config[split_result]为 True 时将每个结果构造成Document再交给RecursiveCharacterTextSplitter按[\n\n, \n, ., ]的优先级、以chunk_size默认 500 字符、chunk_overlap进行切块。切出的文本块若超过top_k会基于NormalizedLevenshtein计算每个块与原始查询的归一化编辑距离相似度按相似度降序保留最相关的top_k块——这解决了检索结果页面很长、直接塞进上下文浪费 token的问题。可选返回原始摘要split_resultFalse时直接返回每个结果的摘要、链接与标题即文档展示的snippet/link/title结构。相关配置项集中定义于 settings.pymetaphor_api_key、split_result、chunk_size默认 500、chunk_overlap默认 0。文档中特别提示未配置METAPHOR_API_KEY时函数应直接返回空结果避免流程报错。searx_search自托管聚合搜索现行版本新增searx_search使用SearxSearchWrapper连接自部署的 Searx 实例见 search_internet.py支持自定义搜索引擎集合engines、分类categories以及语言默认zh-CNdef searx_search(text ,config, top_k: int): search SearxSearchWrapper( searx_hostconfig[host], enginesconfig[engines], categoriesconfig[categories], ) search.params[language] config.get(language, zh-CN) return search.results(text, top_k)配置项包括host默认https://metasearx.com、engines、categories、language见 settings.py。由于 Searx 本身聚合多家上游引擎、可自建可控适合对检索源有定制需求的部署。结果归一化search_result2docs 转 Document不同引擎返回的字段命名并不统一Bing 用linkDuckDuckGo 用url为了让下游Agent 工具与知识库聊天统一消费search_result2docs把原始结果规整为 LangChain 的Document列表search_internet.pydef search_result2docs(search_results) - List[Document]: docs [] for result in search_results: doc Document( page_contentresult[snippet] if snippet in result.keys() else , metadata{ source: result[link] if link in result.keys() else , filename: result[title] if title in result.keys() else , }, ) docs.append(doc) return docs映射规则非常直白Document 字段来源键缺省值含义page_contentsnippet页面摘要/正文片段作为 LLM 上下文metadata[source]link来源 URL用于回答末尾的引用跳转metadata[filename]title标题用作引用文案也就是文档中每个结果至少包含 snippet、link、title 三个键的约定。在search_engine统一入口中还会多做一步空内容过滤search_internet.py丢弃page_content为空或纯空白的无效条目避免把无意义结果喂给 LLM。调度与生成链路从检索到回答的完整闭环统一入口 search_engine文档中的旧架构用lookup_search_engine(query, search_engine_name, top_k, split_result)做异步查表分发、再交search_engine_chat_iterator拼上下文生成回答。当前版本把这两步收敛为一个同步统一入口search_internet.pydef search_engine(query: str, top_k: int 0, engine_name: str , config: dict {}): config config or get_tool_config(search_internet) if top_k 0: top_k config.get(top_k, Settings.kb_settings.SEARCH_ENGINE_TOP_K) engine_name engine_name or config.get(search_engine_name) search_engine_use SEARCH_ENGINES[engine_name] results search_engine_use( textquery, configconfig[search_engine_config][engine_name], top_ktop_k ) docs [x for x in search_result2docs(results) if x.page_content and x.page_content.strip()] return {docs: docs, search_engine: engine_name}该函数的行为与文档描述一一对应engine_name缺省时取工具配置里的search_engine_name显式传入引擎名则直接按SEARCH_ENGINES查表——对应文档先通过search_engine_name从SEARCH_ENGINES字典获取搜索引擎函数的描述top_k 0即文档中的缺省回退到Settings.kb_settings.SEARCH_ENGINE_TOP_K返回体{docs: [Document, ...], search_engine: engine_name}中的docs即由search_result2docs产出该函数同时注册为 Agent 工具search_internet标题互联网搜索见 search_internet.py因此Agent 自主上网搜索与WebUI 搜索引擎问答底层调用的是同一套检索逻辑。服务端对话入口 kb_chatmodesearch_engine对话服务端的实现位于 kb_chat.py。kb_chat用mode: Literal[local_kb, temp_kb, search_engine]统一三种问答来源其中搜索引擎分支正是文档search_engine_chat在现网形态的对应物elif mode search_engine: result await run_in_threadpool(search_engine, query, top_k, kb_name) docs [x.dict() for x in result.get(docs, [])] source_documents [f出处 [{i 1}] [{d[metadata][filename]}]({d[metadata][source]}) \n\n{d[page_content]}\n\n for i, d in enumerate(docs)]逐点对照文档描述的search_engine_chat行为异步执行检索run_in_threadpool(search_engine, query, top_k, kb_name)把同步的搜索引擎函数塞进线程池异步执行对应文档中lookup_search_engine的异步化处理此时kb_name参数承载的就是搜索引擎名称文档引用拼接检索得到的Document列表被格式化为出处 [i] 标题 正文的引用串对应文档输出示例中的docs数组结构[i]序号内链、链接、上下文内容查不到文档时会输出未找到相关文档类提示文档中专门提到这一分支LLM 生成上下文、历史history由History对象列表承载与 Prompt 模板拼装后送入 ChatOpenAI 兼容模型采样参数由temperature默认取自Settings.model_settings.TEMPERATURE、max_tokenskb_routes.py中会兜底为Settings.model_settings.MAX_TOKENS见 kb_routes.py等控制流式输出streamTrue时按 Token/文档列表逐段推送SSE 形式streamFalse时拼接完整回答一次性返回同时附上文档列表。这正是文档结尾EventSourceResponse 异步迭代器语义在 OpenAI 兼容端点上的体现。API 路由OpenAI 兼容的知识库/搜索引擎端点对外暴露的 HTTP 层位于 kb_routes.pykb_router.post( /{mode}/{param}/chat/completions, summary知识库对话openai 兼容参数与 /chat/kb_chat 一致 ) async def kb_chat_endpoint( mode: Literal[local_kb, temp_kb, search_engine], param: str, body: OpenAIChatInput, request: Request, ):也就是说搜索引擎问答的完整 URL 为POST /knowledge_base/search_engine/{engine}/chat/completions其中{engine}是bing/duckduckgo/metaphor/searx之一请求体遵循 OpenAIchat/completions格式messages最后一条的content即querytop_k等扩展参数经body.model_extra透传max_tokens为0或缺失时由服务端填充默认值。WebUI 中的搜索引擎问答在 WebUI 端kb_chat.py 的侧边栏提供三种对话模式知识库问答、文件对话、搜索引擎问答。选择搜索引擎问答后webui_pages/kb_chat.pysearch_engine_list list(Settings.tool_settings.search_internet[search_engine_config]) search_engine st.selectbox( label请选择搜索引擎, optionssearch_engine_list, keysearch_engine, )下拉框候选正是工具配置search_internet[search_engine_config]中已定义密钥/参数的引擎集合如未配置bing_key、metaphor_api_key对应引擎配置仍存在但实际调用会失败。发送消息时以 OpenAI 客户端指向搜索引擎端点webui_pages/kb_chat.pyclient openai.Client(base_urlf{api_url}/knowledge_base/search_engine/{search_engine}, api_keyNONE) ... chat_box.ai_say([ Markdown(..., in_expanderTrue, title知识库匹配结果, staterunning, expandedreturn_direct), f正在执行 {search_engine} 搜索..., ])随后循环消费流式响应第一帧的docs渲染在知识库匹配结果折叠区内展示引用出处后续帧的delta.content逐字刷新回答气泡。该文件第 234 行还留下一条TODO: 搜索未配置API KEY时产生报错注释提示读者若所选引擎密钥未配置此处会进入异常分支并以st.error提示——部署时应先在配置中把要使用的引擎密钥填好。配置指南从零启用联网搜索搜索引擎问答涉及两类配置都集中在 settings.py① 知识库/检索通用设置kb_settingsDEFAULT_SEARCH_ENGINE duckduckgo # 默认搜索引擎bing/duckduckgo/metaphor/searx SEARCH_ENGINE_TOP_K 3 # 默认返回搜索结果条数② 工具配置tool_settings.search_internetsettings.pysearch_internet: dict { use: False, # Agent 侧是否启用互联网搜索工具 search_engine_name: duckduckgo, # 引擎默认名search_engine 入口的兜底值 search_engine_config: { bing: { bing_search_url: https://api.bing.microsoft.com/v7.0/search, bing_key: , # 填入必应订阅密钥后 bing 才可用 }, metaphor: { metaphor_api_key: , split_result: False, # True 时对正文切块并按相似度取 top_k chunk_size: 500, chunk_overlap: 0, }, duckduckgo: {}, # 免密钥开箱即用 searx: { host: https://metasearx.com, engines: [], categories: [], language: zh-CN, }, }, }实操建议结合源码语义场景推荐配置快速验证功能保持默认duckduckgo无需任何密钥但需保证服务器能访问 DuckDuckGo需要稳定商业 API申请必应订阅密钥填入bing.bing_key并核对bing_search_url与地域端点一致需要抓取网页正文做深度问答配置metaphor.metaphor_api_key并按需打开split_result、调整chunk_size/chunk_overlap以控制上下文长度国内网络/私有化定制自建 Searx 实例并填入searx.host可选限定engines、categories语言默认zh-CN仅使用 WebUI 搜索引擎问答、不用 Agentuse保持False即可问答端点不依赖该开关top_k的合理取值需要权衡太小则上下文信息不足太大则可能超出模型窗口或引入噪声metaphor开启切分后可部分缓解SEARCH_ENGINE_TOP_K默认 3 与知识库检索的常见档位1–20见 WebUI 的匹配知识条数滑条保持一致可按问答质量上下调整。参数速查与 FAQ以下参数语义来自文档search_engine_chat/search_engine_chat_iterator的函数签名均可映射到现行端点参数类型默认语义现行端点中的落点querystr必填用户查询messages[-1].contentsearch_engine_namestr必填搜索引擎名URL 路径{engine}或工具配置search_engine_nametop_kintSEARCH_ENGINE_TOP_K结果条数请求体top_k扩展字段historyList[History][]历史对话messages中除最后一条外的历史消息streambool-是否流式返回stream字段model_namestrLLM_MODELS[0]使用的 LLMmodel字段temperaturefloat模型配置默认采样温度temperature字段max_tokensint/None配置默认生成上限非正整数视为不限制max_tokens0/None 时兜底MAX_TOKENSprompt_namestr模板名Prompt 模板请求体扩展字段split_resultboolFalse是否切分结果主要影响 metaphormetaphor 引擎的config[split_result]常见问题选好引擎后提示报错/无结果先检查该引擎密钥/地址是否已在tool_settings.search_internet[search_engine_config][engine]填好WebUI 的下拉项来自配置字典并不代表已可调用源码注释TODO: 搜索未配置API KEY时产生报错与此对应。搜索引擎问答与 Agent 的互联网搜索有什么区别二者共用search_engine与SEARCH_ENGINES区别在于编排方式问答模式由用户显式指定引擎、固定走检索→引用生成Agent 模式则由模型自主决定是否调用search_internet工具工具元数据见 search_internet.py。想换默认引擎怎么办修改kb_settings.DEFAULT_SEARCH_ENGINE影响 WebUI 下拉默认项与工具配置中的search_engine_name影响search_engine入口的兜底选择同时保证对应引擎的密钥配置完整。Metaphor 切分后为何返回的块可能与原文不完全对应这是设计使然切块后按与查询的编辑距离相似度重排取 Top-K优先保证与问题最相关而非原文顺序适合把长篇网页正文提炼成高密度上下文。小结一份可直接上手的实现地图搜索引擎问答链路可用一句话概括SEARCH_ENGINES注册表分发 → 引擎函数各自检索 →search_result2docs统一转Document→ 空内容过滤 → 拼装引用与 Prompt → LLM 流式生成。对照本文可沿如下路径继续深读源码引擎封装与注册表、统一入口 libs/chatchat-server/chatchat/server/agent/tools_factory/search_internet.py引擎默认值与工具配置 libs/chatchat-server/chatchat/settings.pykb_settings与tool_settings.search_internet服务端对话入口modesearch_engine分支 libs/chatchat-server/chatchat/server/chat/kb_chat.pyOpenAI 兼容端点定义 libs/chatchat-server/chatchat/server/api_server/kb_routes.pyWebUI搜索引擎问答界面与客户端调用 libs/chatchat-server/chatchat/webui_pages/kb_chat.py本文所依据的原始文档 markdown_docs/server/chat/search_engine_chat.md配置完成后启动 chatchat 服务并保持外网可达即可在 WebUI 选择搜索引擎问答体验带实时检索与引用的对话或直接以 OpenAI 兼容协议调用/knowledge_base/search_engine/{engine}/chat/completions将其接入自有应用。【免费下载链接】Langchain-ChatchatLangchain-Chatchat原Langchain-ChatGLM基于 Langchain 与 ChatGLM, Qwen 与 Llama 等语言模型的 RAG 与 Agent 应用 | Langchain-Chatchat (formerly langchain-ChatGLM), local knowledge based LLM (like ChatGLM, Qwen and Llama) RAG and Agent app with langchain项目地址: https://gitcode.com/GitHub_Trending/la/Langchain-Chatchat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门