大模型应用:搜索的智能革命:大模型如何重塑传统搜索算法构建新一代智能检索.110

一、前言

搜索早已不是简单敲几个关键词、翻几页链接的工具,而是我们每天工作、学习、生活里最离不开的信息入口。从最早的目录检索,到关键词匹配,再到后来的精准排序,搜索算法迭代了十几年,核心目标一直没变:更快、更准、更懂我们想要什么。

但传统搜索始终有个绕不开的瓶颈,只认文字,不认意思。同样一句话,换个说法、换个语气,结果就天差地别。直到大语言模型出现,才真正打破了这个天花板。它不只是提升效率,而是从底层逻辑上重构了搜索:从关键词匹配,升级成语义理解 + 意图推理。在真实业务里,不管是企业知识库、电商检索、客服问答,还是内容推荐,只要和找信息相关,大模型 + 搜索的组合都能带来肉眼可见的提升。今天我们结合实际详细的分析分析搜索的智能化突破,传统搜索的神奇质变。

二、核心基础

1. 搜索算法的定义

搜索算法是一套用于从海量数据中快速定位目标信息的规则集合,核心目标是"高效、精准"。小到手机通讯录检索,大到全网搜索引擎,本质都是搜索算法的落地。传统搜索算法的核心诉求可概括为三点:

  • **召回:**从数据集中找出所有可能匹配的结果,要求尽可能全;
  • **排序:**将召回的结果按匹配度从高到低排列,要求尽可能准;
  • **效率:**在毫秒级完成上述过程,要求尽可能快。

2. 传统搜索的核心技术

2.1 倒排索引

倒排索引是传统搜索的基石,也是理解搜索算法的第一个核心概念。

  • 正排索引:以"文档"为核心,记录每个文档包含的内容,如文档 ID: 1,内容:人工智能入门;
  • 倒排索引:以"关键词"为核心,记录每个关键词出现在哪些文档中,如关键词:人工智能,文档 ID 列表: [1,3,5]。

举个通俗例子:正排索引像一本书的"目录"(章节→内容),倒排索引像一本书的"索引表"(关键词→页码)。当用户搜索"人工智能"时,算法只需查倒排索引,就能快速找到所有包含该关键词的文档,而非逐篇扫描,这是搜索效率的核心保障。

2.2 TF-IDF 算法

TF-IDF 是传统搜索中最经典的"相关性评分"算法,用于衡量"关键词与文档的匹配程度",公式如下:

  • **TF(词频):**关键词在文档中出现的频率 = 关键词出现次数/文档总词数;
  • **IDF(逆文档频率):**关键词的"稀缺性"= log(总文档数/包含该关键词的文档数);
  • TF-IDF = TF × IDF。

通俗理解:TF越高,说明关键词在文档中越重要;IDF越高,说明关键词越"独特",比如"的"这类停用词IDF接近 0,而"大模型"这类专业词IDF更高。TF-IDF得分越高,文档与搜索词的匹配度越高。

2.3 BM25 算法

BM25 是 TF-IDF 的优化版,也是目前主流搜索引擎仍在使用的基础排序算法。它解决了 TF-IDF 的两个核心问题:

  • TF-IDF 中词频无上限,导致长文档中高频词得分过高;
  • BM25 引入"饱和度系数",让词频增长到一定程度后趋于平缓。

核心公式:

其中:

  • k1:词频饱和度参数,通常取1.2;
  • b:文档长度调整参数,通常取0.75;
  • ∣D∣:当前文档长度;
  • avgdl:所有文档的平均长度。

通俗理解:BM25既考虑了关键词的频率和稀缺性,又兼顾了文档长度的影响,让短文档和长文档的评分更公平。

3. 大模型搜索的核心能力

对于搜索场景,大模型的核心价值集中在以下 4 点:

  • **1. 语义理解:**能理解搜索词的真实意图,而非仅匹配关键词,比如用户搜"怎么缓解熬夜后的头痛",大模型能理解核心需求是"熬夜头痛的缓解方法",而非仅匹配"熬夜"、"头痛"等关键词;
  • **2. 文本向量化:**将文本(搜索词、文档)转化为高维向量(Embedding),向量间的余弦相似度可衡量文本的语义相似度,而非字面相似度;
  • **3. 意图推理:**能推理用户未明确表达的需求,比如用户搜"北京周末适合带孩子去的地方",大模型能推理出"亲子、室内或室外、性价比"等潜在需求;
  • **4. 结果生成:**能将搜索结果重新整理、总结,生成符合用户阅读习惯的答案,而非简单罗列链接。

4. 核心 Embedding 嵌入

Embedding 是大模型与搜索算法融合的桥梁,也是理解语义搜索的关键。

  • **定义:**将文本、图片等非结构化数据转化为计算机可理解的高维向量,向量的空间距离代表语义相似度,余弦相似度越接近 1,语义越相似;
  • **传统向量表示:**One-hot 编码,如"苹果"=[1,0,0],"香蕉"=[0,1,0],无法体现语义关联;
  • **大模型 Embedding:**基于上下文的向量表示,如"苹果手机"和"iPhone"的向量距离极近,而"苹果水果"和"iPhone"的向量距离较远。

5. 大模型+搜索算法的融合价值

传统搜索算法的核心痛点是只能匹配字面,无法理解语义,比如:

  • 用户搜"如何让猫咪不拆家",传统算法只能召回包含"猫咪"、"拆家"的文档,但若文档写"解决猫主子破坏家具的方法",因关键词不匹配会被遗漏;
  • 用户搜"感冒和流感的区别",传统算法无法理解区别这一意图,只能召回包含所有关键词的文档,排序结果杂乱。

而大模型的融入,能从根本上解决这些问题:

    1. 提升召回率:通过语义向量匹配,召回字面不同但语义相关的文档;
    1. 提升排序精准度:基于大模型的意图理解,对召回结果做更精准的相关性排序;
    1. 优化用户体验:通过大模型的生成能力,将搜索结果转化为自然语言答案,而非单纯罗列。

三、执行流程

1. 传统搜索算法的执行流程

先明确传统搜索的完整流程,才能理解大模型的融入节点。传统搜索的核心流程分为 5 步:

  • **步骤 1:搜索词预处理:**比如用户输入"如何学习人工智能的算法",分词后得到"如何 学习 人工智能 算法",去除"如何"等停用词,最终保留"学习 人工智能 算法";
  • **步骤 2:倒排索引召回:**查倒排索引,找到所有包含"人工智能"或"算法"的文档;
  • **步骤 3:排序:**对召回的文档计算TF-IDF和BM25得分,按得分从高到低排序;
  • **步骤 4:结果展示:**返回前10或20条结果。

传统流程的核心局限:所有步骤都基于"关键词",无法处理语义层面的匹配。

2. 大模型融入搜索算法的流程

大模型并非替代传统搜索算法,而是赋能,在传统流程的关键节点融入大模型能力,形成"传统召回 + 大模型重排 + 大模型生成"的新流程:

步骤 1:搜索词预处理(大模型赋能)

传统预处理仅做分词、去停用词,大模型在此阶段的核心作用是:

  • **意图识别:**判断用户搜索意图,比如是"信息查询"、"问题求解"、"导航"还是"购物";
  • **搜索词改写:**将模糊或口语化的搜索词转化为更精准的表达,比如用户说"猫总挠沙发咋办",大模型改写为"猫咪抓挠家具的解决方法";
  • **多轮意图理解:**处理上下文相关的搜索,比如用户先搜"北京亲子餐厅",再搜"性价比高的",大模型能理解"性价比高的北京亲子餐厅"。

实现细节:此阶段通常使用轻量级大模型,如BERT-base、ChatGLM-6B ,输入是用户搜索词,输出是"意图标签 + 改写后的搜索词"。比如输入"怎么让狗不叫",输出:

  • 意图标签:问题求解 - 宠物行为矫正;
  • 改写搜索词:狗狗乱叫的原因及解决方法。

步骤 2:混合召回(倒排索引 + 向量召回)

召回是搜索的第一步筛选,核心是"不漏掉相关文档"。大模型在此阶段的核心贡献是向量召回:

  • **1. 预先生成文档 Embedding:**将所有文档通过大模型转化为 Embedding 向量,存入向量数据库,如FAISS;
  • **2. 生成搜索词 Embedding:**将用户改写后的搜索词也转化为 Embedding 向量;
  • **3. 向量召回:**计算搜索词向量与文档向量的余弦相似度,召回相似度 Top N 的文档;
  • **4. 混合召回:**将向量召回的结果与倒排索引召回的结果合并,得到更全面的候选文档集。

实现细节:

  • 余弦相似度公式:similarity(A,B)= A⋅B/(∣∣A∣∣×∣∣B∣∣),取值范围 [-1,1],越接近 1 语义越相似;
  • 向量数据库的作用:传统数据库无法高效计算向量相似度,向量数据库通过"索引算法,如IVF_FLAT、HNSW" 将向量检索的时间复杂度从 O(n) 降到 O(log n),保证召回效率;
  • 选择 Embedding 模型的原则:优先选择中文优化的模型,如text2vec-large-chines),参数量适中,兼顾效果和速度。

步骤 3:大模型重排(语义排序)

传统排序(BM25)仅基于关键词匹配,大模型重排则基于语义相关性,核心是对混合召回的候选文档做二次排序,提升精准度。

  • **重排模型:**通常使用跨语言理解模型,如 BERT,输入是"搜索词 + 文档"对,输出是0-1之间的相关性得分;
  • 重排流程:
      1. 对混合召回的候选文档,通常是100-200条,逐一与搜索词拼接成输入对;
      1. 输入重排模型,得到每个文档的语义相关性得分;
      1. 应用加权求和结合BM25得分和语义得分,得到最终排序得分;
      1. 按最终得分排序,保留前20-50条文档。

步骤 4:大模型生成(答案总结)

这是提升用户体验的核心环节,大模型将排序后的文档内容整合、总结,生成自然语言答案,而非单纯罗列文档链接。

  • 生成模型:可选择开源大模型,如ChatGLM-4、Llama3,输入是"用户搜索词 + 排序后的文档内容",输出是结构化的答案;
  • 提示词(Prompt)设计:关键是引导大模型"基于文档内容总结,不编造信息",比如:

请基于以下文档内容,回答用户的问题:{用户搜索词}

文档内容:{文档1内容}\n{文档2内容}\n...

要求:

  1. 答案必须基于文档内容,不得添加无关信息;

  2. 语言简洁易懂,分点说明;

  3. 标注信息来源(文档编号)。

四、完整示例

我们将搭建一个"本地文档语义搜索系统",核心功能:用户输入搜索词,系统返回语义最相关的文档,并生成总结答案。

步骤 1:数据准备

首先准备一批测试文档,比如5篇关于"大模型应用"的短文,保存为 txt 文件,或直接在代码中定义:

python 复制代码
# 测试文档集
documents = [
    {
        "id": 1,
        "content": "大语言模型(LLM)在搜索领域的应用主要体现在语义理解和向量召回。通过将文本转化为Embedding向量,大模型能突破传统关键词匹配的局限,找到语义相关的文档。比如用户搜索'AI如何提升搜索效率',大模型能理解核心需求是'人工智能对搜索算法的优化',而非仅匹配关键词。"
    },
    {
        "id": 2,
        "content": "向量数据库是大模型搜索的核心组件之一。FAISS是Facebook开源的向量数据库,支持高效的向量相似度检索,能处理百万级甚至亿级的向量数据。与传统数据库不同,向量数据库的核心索引算法如HNSW,能大幅提升向量检索的速度,满足实时搜索的需求。"
    },
    {
        "id": 3,
        "content": "传统搜索算法的核心是倒排索引和BM25排序。倒排索引负责快速召回包含关键词的文档,BM25则通过词频和逆文档频率计算相关性得分。但传统算法无法处理语义差异,比如'猫咪拆家'和'猫主子破坏家具'会被判定为不相关,这也是大模型需要补充的环节。"
    },
    {
        "id": 4,
        "content": "大模型重排是提升搜索精准度的关键步骤。在召回阶段得到候选文档后,使用BERT类模型计算'搜索词-文档'的语义相似度,再结合BM25得分进行加权排序,能让排序结果更符合用户的语义需求。重排模型通常选择轻量级版本,以保证推理速度。"
    },
    {
        "id": 5,
        "content": "大模型生成能力能优化搜索结果展示。将排序后的文档内容输入ChatGLM等开源大模型,通过合理的提示词设计,让模型总结出简洁的答案,而非让用户逐个阅读文档。这一过程需要控制模型的幻觉问题,确保答案基于文档内容,不编造信息。"
    }
]

步骤 2:文档预处理与 Embedding 生成

核心是将文档转化为 Embedding 向量,这里选择开源的中文 Embedding 模型,我们使用本地路径已有的paraphrase-multilingual-MiniLM-L12-v2模型;

python 复制代码
import jieba
import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

# 1. 加载Embedding模型(中文优化版)
model = SentenceTransformer("D:\\modelscope\\hub\\sentence-transformers\\paraphrase-multilingual-MiniLM-L12-v2")

# 2. 文档预处理函数:分词、去停用词
def preprocess_text(text):
    # 停用词列表(基础版)
    stop_words = {'的', '了', '是', '在', '有', '能', '都', '就', '及', '与', '对', '为'}
    # 分词
    words = jieba.lcut(text)
    # 去停用词和空字符
    filtered_words = [word for word in words if word not in stop_words and word.strip() != '']
    # 拼接为字符串(用于Embedding生成)
    return ' '.join(filtered_words)

# 3. 为每个文档生成Embedding
document_embeddings = []
processed_documents = []
for doc in documents:
    # 预处理文档内容
    processed_content = preprocess_text(doc['content'])
    processed_documents.append({
        'id': doc['id'],
        'content': doc['content'],
        'processed_content': processed_content
    })
    # 生成Embedding向量(shape: (1, 1024))
    embedding = model.encode(processed_content)
    document_embeddings.append(embedding)

# 转换为numpy数组,方便后续计算(shape: (5, 1024))
document_embeddings = np.vstack(document_embeddings)

步骤 3:混合召回(倒排索引 + 向量召回)

3.1 简易倒排索引实现

python 复制代码
# 构建倒排索引:key=关键词,value=文档ID列表
inverted_index = {}
for doc in processed_documents:
    doc_id = doc['id']
    # 拆分预处理后的关键词
    keywords = doc['processed_content'].split()
    for keyword in keywords:
        if keyword not in inverted_index:
            inverted_index[keyword] = []
        if doc_id not in inverted_index[keyword]:
            inverted_index[keyword].append(doc_id)

# 倒排索引召回函数
def inverted_index_retrieval(query, inverted_index, processed_documents):
    # 预处理查询词
    processed_query = preprocess_text(query)
    query_keywords = processed_query.split()
    # 收集包含任意关键词的文档ID
    candidate_doc_ids = set()
    for keyword in query_keywords:
        if keyword in inverted_index:
            candidate_doc_ids.update(inverted_index[keyword])
    # 返回候选文档
    candidate_docs = [doc for doc in processed_documents if doc['id'] in candidate_doc_ids]
    return candidate_docs

3.2 向量召回实现

python 复制代码
# 向量召回函数
def vector_retrieval(query, model, document_embeddings, processed_documents, top_k=3):
    # 预处理并生成查询词Embedding
    processed_query = preprocess_text(query)
    query_embedding = model.encode(processed_query).reshape(1, -1)
    # 计算余弦相似度
    similarities = cosine_similarity(query_embedding, document_embeddings)[0]
    # 按相似度排序,取Top K
    top_indices = similarities.argsort()[::-1][:top_k]
    # 返回Top K文档
    top_docs = [processed_documents[i] for i in top_indices]
    return top_docs

# 混合召回函数:合并倒排索引和向量召回结果,去重
def hybrid_retrieval(query, inverted_index, model, document_embeddings, processed_documents):
    # 倒排索引召回
    inverted_docs = inverted_index_retrieval(query, inverted_index, processed_documents)
    # 向量召回
    vector_docs = vector_retrieval(query, model, document_embeddings, processed_documents)
    # 合并结果,按文档ID去重
    doc_id_set = set()
    hybrid_docs = []
    # 先加向量召回的结果(优先级更高)
    for doc in vector_docs:
        if doc['id'] not in doc_id_set:
            doc_id_set.add(doc['id'])
            hybrid_docs.append(doc)
    # 再加倒排索引召回的结果(补充)
    for doc in inverted_docs:
        if doc['id'] not in doc_id_set:
            doc_id_set.add(doc['id'])
            hybrid_docs.append(doc)
    return hybrid_docs

步骤 4:大模型重排

这里使用轻量级 BERT 模型做语义重排,也可直接用 Embedding 的相似度得分简化实现:

python 复制代码
# 简化版重排:基于语义相似度排序
def rerank_docs(query, docs, model):
    # 生成查询词Embedding
    processed_query = preprocess_text(query)
    query_embedding = model.encode(processed_query).reshape(1, -1)
    # 计算每个文档与查询词的相似度
    doc_scores = []
    for doc in docs:
        doc_embedding = model.encode(doc['processed_content']).reshape(1, -1)
        similarity = cosine_similarity(query_embedding, doc_embedding)[0][0]
        doc_scores.append({
            'id': doc['id'],
            'content': doc['content'],
            'similarity': similarity
        })
    # 按相似度从高到低排序
    reranked_docs = sorted(doc_scores, key=lambda x: x['similarity'], reverse=True)
    return reranked_docs

步骤 5:大模型生成答案

这里使用开源的qwen模型,我们已经经常使用到,今天继续复用,也可替换为其他开源大模型或在线的API模型;

python 复制代码
from modelscope import AutoModelForCausalLM, AutoTokenizer

# 加载Qwen1.5-0.5B-Chat本地模型(使用完整路径)
model_path = "D:\\modelscope\\hub\\models\\qwen\\Qwen1___5-0___5B-Chat"
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model_chat = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)

# 答案生成函数
def generate_answer(query, reranked_docs):
    # 拼接文档内容
    doc_content = ""
    for i, doc in enumerate(reranked_docs[:3]):  # 取前3篇最相关的文档
        doc_content += f"文档{i+1}:{doc['content']}\n"
    
    # 构建Prompt(使用Qwen的聊天格式)
    messages = [
        {"role": "system", "content": "你是一个专业的搜索助手,请基于给定的文档内容回答用户问题。"},
        {"role": "user", "content": f"请基于以下文档内容,回答用户的问题:{query}\n\n文档内容:\n{doc_content}\n\n要求:\n1. 答案必须基于上述文档内容,不得添加无关信息;\n2. 语言简洁易懂,分点说明;\n3. 标注信息来源(文档编号)。"}
    ]
    
    # 调用大模型生成答案
    text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
    inputs = tokenizer(text, return_tensors="pt")
    outputs = model_chat.generate(**inputs, max_new_tokens=512)
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return response

步骤 6:完整搜索流程调用

python 复制代码
# 主函数:完整搜索流程
def semantic_search(query):
    print(f"用户搜索词:{query}")
    print("="*50)
    
    # 1. 混合召回
    hybrid_docs = hybrid_retrieval(query, inverted_index, model, document_embeddings, processed_documents)
    print(f"混合召回文档数:{len(hybrid_docs)}")
    
    # 2. 大模型重排
    reranked_docs = rerank_docs(query, hybrid_docs, model)
    print("重排后前3篇文档相似度:")
    for doc in reranked_docs[:3]:
        print(f"文档ID:{doc['id']},相似度:{doc['similarity']:.4f}")
    print("="*50)
    
    # 3. 生成答案
    answer = generate_answer(query, reranked_docs)
    print("大模型生成的答案:")
    print(answer)

# 测试搜索
if __name__ == "__main__":
    # 用户输入搜索词
    user_query = "大模型如何提升搜索算法的效果"
    # 执行搜索
    semantic_search(user_query)

输出结果:

用户搜索词:大模型如何提升搜索算法的效果

==================================================

混合召回文档数:5

重排后前3篇文档相似度:

文档ID:1,相似度:0.7248

文档ID:4,相似度:0.7093

文档ID:5,相似度:0.6887

==================================================

大模型生成的答案:

system

你是一个专业的搜索助手,请基于给定的文档内容回答用户问题。

user

请基于以下文档内容,回答用户的问题:大模型如何提升搜索算法的效果

文档内容:

文档1:大语言模型(LLM)在搜索领域的应用主要体现在语义理解和向量召回。通过将文本转化为Embedding向量,大模型能突破传统关键词匹配的局限,找到语义 相关的文档。比如用户搜索'AI如何提升搜索效率',大模型能理解核心需求是'人工智能对搜索算法的优化',而非仅匹配关键词。

文档2:大模型重排是提升搜索精准度的关键步骤。在召回阶段得到候选文档后,使用BERT类模型计算'搜索词-文档'的语义相似度,再结合BM25得分进行加权排序,能让排序结果更符合用户的语义需求。重排模型通常选择轻量级版本,以保证推理速度。

文档3:大模型生成能力能优化搜索结果展示。将排序后的文档内容输入ChatGLM等开源大模型,通过合理的提示词设计,让模型总结出简洁的答案,而非让用户逐个阅读文档。这一过程需要控制模型的幻觉问题,确保答案基于文档内容,不编造信息。

要求:

  1. 答案必须基于上述文档内容,不得添加无关信息;

  2. 语言简洁易懂,分点说明;

  3. 标注信息来源(文档编号)。

assistant

  1. 大模型是如何提升搜索算法效果的?
  • 将文本转化为Embedding向量,大模型能突破传统关键词匹配的局限,找到语义相关的文档。

  • 通过BERT类模型计算'搜索词-文档'的语义相似度,再结合BM25得分进行加权排序,能让排序结果更符合用户的语义需求。

  • 重排模型通常选择轻量级版本,以保证推理速度。

  • 在处理重排任务时,需要控制模型的幻觉问题,确保答案基于文档内容,不编造信息。

  1. 大模型重排是提升搜索精准度的关键步骤。
  • 在召回阶段得到候选文档后,使用BERT类模型计算'搜索词-文档'的语义相似度,再结合BM25得分进行加权排序,能让排序结果更符合用户的语义需求。

  • 重排模型通常选择轻量级版本,以保证推理速度。

  1. 大模型生成能力能优化搜索结果展示。
  • 将排序后的文档内容输入ChatGLM等开源大模型,通过合理的提示词设计,让模型总结出简洁的答案,而非让用户逐个阅读文档。

  • 这一步需要注意控制模型的幻觉问题,确保答案基于文档内容,不编造信息。

五、总结

整体来说,今天的核心就是把 大模型 + 搜索算法"的融合逻辑讲清道明。传统搜索靠倒排索引、TF-IDF、BM25 这些技术,核心就是认关键词,虽然快,但容易错过语义相关的内容,体验不够好。而大模型的加入,不是替代传统算法,而是给它赋能升级。核心逻辑就是先靠大模型理解用户搜索词的真实意图,再用"倒排索引 + 向量召回"的混合方式,把相关文档都找出来,接着用大模型做语义重排,让最贴合需求的文档排前面,最后再用大模型把结果总结成通俗易懂的答案。

附录:完整示例代码

python 复制代码
import jieba
import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

# 1. 加载Embedding模型(中文优化版)
model = SentenceTransformer("D:\\modelscope\\hub\\sentence-transformers\\paraphrase-multilingual-MiniLM-L12-v2")

# 测试文档集
documents = [
    {
        "id": 1,
        "content": "大语言模型(LLM)在搜索领域的应用主要体现在语义理解和向量召回。通过将文本转化为Embedding向量,大模型能突破传统关键词匹配的局限,找到语义相关的文档。比如用户搜索'AI如何提升搜索效率',大模型能理解核心需求是'人工智能对搜索算法的优化',而非仅匹配关键词。"
    },
    {
        "id": 2,
        "content": "向量数据库是大模型搜索的核心组件之一。FAISS是Facebook开源的向量数据库,支持高效的向量相似度检索,能处理百万级甚至亿级的向量数据。与传统数据库不同,向量数据库的核心索引算法如HNSW,能大幅提升向量检索的速度,满足实时搜索的需求。"
    },
    {
        "id": 3,
        "content": "传统搜索算法的核心是倒排索引和BM25排序。倒排索引负责快速召回包含关键词的文档,BM25则通过词频和逆文档频率计算相关性得分。但传统算法无法处理语义差异,比如'猫咪拆家'和'猫主子破坏家具'会被判定为不相关,这也是大模型需要补充的环节。"
    },
    {
        "id": 4,
        "content": "大模型重排是提升搜索精准度的关键步骤。在召回阶段得到候选文档后,使用BERT类模型计算'搜索词-文档'的语义相似度,再结合BM25得分进行加权排序,能让排序结果更符合用户的语义需求。重排模型通常选择轻量级版本,以保证推理速度。"
    },
    {
        "id": 5,
        "content": "大模型生成能力能优化搜索结果展示。将排序后的文档内容输入ChatGLM等开源大模型,通过合理的提示词设计,让模型总结出简洁的答案,而非让用户逐个阅读文档。这一过程需要控制模型的幻觉问题,确保答案基于文档内容,不编造信息。"
    }
]

# 2. 文档预处理函数:分词、去停用词
def preprocess_text(text):
    # 停用词列表(基础版)
    stop_words = {'的', '了', '是', '在', '有', '能', '都', '就', '及', '与', '对', '为'}
    # 分词
    words = jieba.lcut(text)
    # 去停用词和空字符
    filtered_words = [word for word in words if word not in stop_words and word.strip() != '']
    # 拼接为字符串(用于Embedding生成)
    return ' '.join(filtered_words)

# 3. 为每个文档生成Embedding
document_embeddings = []
processed_documents = []
for doc in documents:
    # 预处理文档内容
    processed_content = preprocess_text(doc['content'])
    processed_documents.append({
        'id': doc['id'],
        'content': doc['content'],
        'processed_content': processed_content
    })
    # 生成Embedding向量(shape: (1, 1024))
    embedding = model.encode(processed_content)
    document_embeddings.append(embedding)

# 转换为numpy数组,方便后续计算(shape: (5, 1024))
document_embeddings = np.vstack(document_embeddings)

# 构建倒排索引:key=关键词,value=文档ID列表
inverted_index = {}
for doc in processed_documents:
    doc_id = doc['id']
    # 拆分预处理后的关键词
    keywords = doc['processed_content'].split()
    for keyword in keywords:
        if keyword not in inverted_index:
            inverted_index[keyword] = []
        if doc_id not in inverted_index[keyword]:
            inverted_index[keyword].append(doc_id)

# 倒排索引召回函数
def inverted_index_retrieval(query, inverted_index, processed_documents):
    # 预处理查询词
    processed_query = preprocess_text(query)
    query_keywords = processed_query.split()
    # 收集包含任意关键词的文档ID
    candidate_doc_ids = set()
    for keyword in query_keywords:
        if keyword in inverted_index:
            candidate_doc_ids.update(inverted_index[keyword])
    # 返回候选文档
    candidate_docs = [doc for doc in processed_documents if doc['id'] in candidate_doc_ids]
    return candidate_docs

# 向量召回函数
def vector_retrieval(query, model, document_embeddings, processed_documents, top_k=3):
    # 预处理并生成查询词Embedding
    processed_query = preprocess_text(query)
    query_embedding = model.encode(processed_query).reshape(1, -1)
    # 计算余弦相似度
    similarities = cosine_similarity(query_embedding, document_embeddings)[0]
    # 按相似度排序,取Top K
    top_indices = similarities.argsort()[::-1][:top_k]
    # 返回Top K文档
    top_docs = [processed_documents[i] for i in top_indices]
    return top_docs

# 混合召回函数:合并倒排索引和向量召回结果,去重
def hybrid_retrieval(query, inverted_index, model, document_embeddings, processed_documents):
    # 倒排索引召回
    inverted_docs = inverted_index_retrieval(query, inverted_index, processed_documents)
    # 向量召回
    vector_docs = vector_retrieval(query, model, document_embeddings, processed_documents)
    # 合并结果,按文档ID去重
    doc_id_set = set()
    hybrid_docs = []
    # 先加向量召回的结果(优先级更高)
    for doc in vector_docs:
        if doc['id'] not in doc_id_set:
            doc_id_set.add(doc['id'])
            hybrid_docs.append(doc)
    # 再加倒排索引召回的结果(补充)
    for doc in inverted_docs:
        if doc['id'] not in doc_id_set:
            doc_id_set.add(doc['id'])
            hybrid_docs.append(doc)
    return hybrid_docs

# 简化版重排:基于语义相似度排序
def rerank_docs(query, docs, model):
    # 生成查询词Embedding
    processed_query = preprocess_text(query)
    query_embedding = model.encode(processed_query).reshape(1, -1)
    # 计算每个文档与查询词的相似度
    doc_scores = []
    for doc in docs:
        doc_embedding = model.encode(doc['processed_content']).reshape(1, -1)
        similarity = cosine_similarity(query_embedding, doc_embedding)[0][0]
        doc_scores.append({
            'id': doc['id'],
            'content': doc['content'],
            'similarity': similarity
        })
    # 按相似度从高到低排序
    reranked_docs = sorted(doc_scores, key=lambda x: x['similarity'], reverse=True)
    return reranked_docs

from modelscope import AutoModelForCausalLM, AutoTokenizer

# 加载Qwen1.5-0.5B-Chat本地模型(使用完整路径)
model_path = "D:\\modelscope\\hub\\models\\qwen\\Qwen1___5-0___5B-Chat"
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model_chat = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)

# 答案生成函数
def generate_answer(query, reranked_docs):
    # 拼接文档内容
    doc_content = ""
    for i, doc in enumerate(reranked_docs[:3]):  # 取前3篇最相关的文档
        doc_content += f"文档{i+1}:{doc['content']}\n"
    
    # 构建Prompt(使用Qwen的聊天格式)
    messages = [
        {"role": "system", "content": "你是一个专业的搜索助手,请基于给定的文档内容回答用户问题。"},
        {"role": "user", "content": f"请基于以下文档内容,回答用户的问题:{query}\n\n文档内容:\n{doc_content}\n\n要求:\n1. 答案必须基于上述文档内容,不得添加无关信息;\n2. 语言简洁易懂,分点说明;\n3. 标注信息来源(文档编号)。"}
    ]
    
    # 调用大模型生成答案
    text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
    inputs = tokenizer(text, return_tensors="pt")
    outputs = model_chat.generate(**inputs, max_new_tokens=512)
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return response

# 主函数:完整搜索流程
def semantic_search(query):
    print(f"用户搜索词:{query}")
    print("="*50)
    
    # 1. 混合召回
    hybrid_docs = hybrid_retrieval(query, inverted_index, model, document_embeddings, processed_documents)
    print(f"混合召回文档数:{len(hybrid_docs)}")
    
    # 2. 大模型重排
    reranked_docs = rerank_docs(query, hybrid_docs, model)
    print("重排后前3篇文档相似度:")
    for doc in reranked_docs[:3]:
        print(f"文档ID:{doc['id']},相似度:{doc['similarity']:.4f}")
    print("="*50)
    
    # 3. 生成答案
    answer = generate_answer(query, reranked_docs)
    print("大模型生成的答案:")
    print(answer)

# 测试搜索
if __name__ == "__main__":
    # 用户输入搜索词
    user_query = "大模型如何提升搜索算法的效果"
    # 执行搜索
    semantic_search(user_query)
相关推荐
wuxi_joe2 小时前
企业 AI 专家系统架构
人工智能
羊羊小栈2 小时前
基于「YOLO目标检测 + 多模态AI分析」的植物番茄病害检测分析系统
人工智能·yolo·目标检测·计算机视觉·毕业设计·大作业
格林威2 小时前
工业相机图像高速存储(C#版):先存内存,后批量转存方法,附 Basler 相机实战代码!
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
dajun1811234562 小时前
音乐制作从创作到发行完整流程图表怎么画
大数据·运维·人工智能·信息可视化·架构·流程图·能源
云边云科技_云网融合2 小时前
云原生全球广域网架构深度科普:从单点集中到全域互联
大数据·人工智能·科技·云计算
小卓(friendhan2005)2 小时前
Boost搜索引擎项目【C++】
c++·搜索引擎
輕華2 小时前
OpenCV 实战封神榜(下):轮廓检测 + 模板匹配,从特征提取到精准匹配
人工智能·opencv·计算机视觉
听风吹等浪起2 小时前
基于深度学习的医学图像分割系统:架构设计、实现与优化分析
人工智能·深度学习
人工智能AI技术2 小时前
火山引擎ArkClaw深度体验:云端SaaS版OpenClaw在企微自动办公的完整实践
人工智能