国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

從零到一帶你實戰(zhàn)RAG混合檢索 原創(chuàng)

發(fā)布于 2024-12-3 08:44
瀏覽
0收藏

在之前的文章中,我們探討了混合檢索的概念以及其后續(xù)的重新排序(rerank)和重組(reorder)操作。今天,我們將從實踐角度解析如何執(zhí)行混合檢索。下圖是混合檢索的流程:

從零到一帶你實戰(zhàn)RAG混合檢索-AI.x社區(qū)

BM25

眾所周知,混合檢索主要通過關(guān)鍵詞匹配來確定可能的答案,接著結(jié)合語義匹配以進一步提升答案的精確度。BM25就是其中一種常見的關(guān)鍵詞搜索技術(shù)。

BM25就像一個智能的匹配工具,在我們使用搜索系統(tǒng)時,它能幫助我們找到最相關(guān)的信息。BM25如何做到這一點呢?它主要看兩個方面:首先,它會檢查我們的查詢詞在某份文檔中出現(xiàn)了多少次;其次,它還會看這個詞在所有文檔中出現(xiàn)的頻率。如果一個詞在特定文檔中經(jīng)常出現(xiàn),但在其他地方很少見,那么這個詞對這篇文檔來說就非常重要,BM25會認(rèn)為這篇文檔與我們的查詢非常匹配。此外,BM25模型對于長文檔和短文檔有一個平衡處理,防止因文檔長度不同,而導(dǎo)致的詞頻偏差。

讓我們通過一個搜索引擎的簡單例子來揭示BM25的運作原理。假設(shè)你在一個搜索引擎中輸入了"香蕉面包",并且有三篇文章與這個查詢相關(guān):

  1. 文章A標(biāo)題為 "如何制作香蕉面包",全文1000字,并且"香蕉面包"一詞在其中出現(xiàn)10次。
  2. 文章B標(biāo)題為 "面包的種類",全文500字,在其中"香蕉面包"一詞出現(xiàn)5次。
  3. 文章C標(biāo)題為 "水果和烘焙",全文2000字,其中"香蕉面包"一詞出現(xiàn)10次。

首先,BM25會考慮查詢詞(即"香蕉面包")在每篇文章中出現(xiàn)的頻率。在文章A和C中,"香蕉面包"都出現(xiàn)了10次,而在文章B中出現(xiàn)了5次。因此,就頻率而言,文章A和C可能比文章B更相關(guān)。

然后,BM25會考慮文檔的長度。盡管文章A和C中"香蕉面包"的出現(xiàn)次數(shù)相同,但文章A只有1000字,而文章C有2000字。這意味著,在文章A中,"香蕉面包"占據(jù)了更大比例,因此可能更相關(guān)。

因此,綜合考慮以上因素,搜索引擎可能會認(rèn)為文章A是對"香蕉面包"這個查詢最相關(guān)的結(jié)果,其次是文章B,再次是文章C。

langchain中封裝了BM25對應(yīng)的retriever的實現(xiàn),我們來看下:

from langchain.retrievers.bm25 import BM25Retriever

doc_list_1 = [
    "I like apples",
    "I like oranges",
    "Apples and oranges are fruits",
]

# initialize the bm25 retriever and chroma retriever
bm25_retriever = BM25Retriever.from_texts(
    doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1)
)
bm25_retriever.k = 2
# [Document(page_cnotallow='I like apples', metadata={'source': 1}), Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1})]
print(bm25_retriever.invoke("apples"))
# [Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1}), Document(page_cnotallow='I like oranges', metadata={'source': 1})]
print(bm25_retriever.invoke("apple"))

上述代碼演示了我們在查詢"apples"時,BM25根據(jù)詞頻能成功返回包含"apples"的兩句話。但是,當(dāng)我們將查詢改為"apple"時,意外地得到了'I like oranges'這一結(jié)果。看起來BM25對單詞的單復(fù)數(shù)形式十分"敏感",這也暴露出BM25的一個限制。而同樣是基于詞頻的elasticsearch卻能有效改善這一問題。在使用elasticsearch替換bm25之前,我們先湊合著用bm25看下在langchain中如何做混合檢索。

from langchain.retrievers import EnsembleRetriever
from langchain.retrievers.bm25 import BM25Retriever
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

doc_list_1 = [
    "I like apples",
    "I like oranges",
    "Apples and oranges are fruits",
]

# initialize the bm25 retriever and chroma retriever
bm25_retriever = BM25Retriever.from_texts(
    doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1)
)
bm25_retriever.k = 2

embedding = OpenAIEmbeddings()
chroma_vectorstore = Chroma.from_texts(
    doc_list_1, embedding, metadatas=[{"source": 2}] * len(doc_list_1)
)
chroma_retriever = chroma_vectorstore.as_retriever(search_kwargs={"k": 2})

# initialize the ensemble retriever
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, chroma_retriever], weights=[0.5, 0.5]
)

在上面的代碼中,我們使用了基于關(guān)鍵詞搜索的BM25 retriever和基于向量檢索的chroma retriever, 然后使用了一個EnsembleRetriever對這兩個retriever搜索到的結(jié)果使用RFF算法進行整合,整合后我們先來看看查詢"apples"的結(jié)果:

# [Document(page_cnotallow='I like apples', metadata={'source': 1}), Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1})]
print(ensemble_retriever.invoke("apples"))

我們再來搜索一下"apple", 結(jié)果如下:

# [Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1}), Document(page_cnotallow='I like oranges', metadata={'source': 1})]
print(bm25_retriever.invoke("apple"))
# [Document(page_cnotallow='I like apples', metadata={'source': 2}), Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 2})]
print(chroma_retriever.invoke("apple"))
# [Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1}), Document(page_cnotallow='I like apples', metadata={'source': 2}), Document(page_cnotallow='I like oranges', metadata={'source': 1})]
print(ensemble_retriever.invoke("apple"))

可以看出,基于語義的搜索對單復(fù)數(shù)形式并不敏感,'I like apples'仍然被檢索到。整合后的EnsembleRetriever返回了更優(yōu)質(zhì)的結(jié)果,前兩個都是與"蘋果"相關(guān)的文檔。這也證明了,我們通過使用向量檢索成功地彌補了BM25這種關(guān)鍵詞搜索可能存在的短板。

RRF算法

RFF 是一種數(shù)據(jù)融合方法,常用于元搜索。元搜索是將來自多個不同源或檢索系統(tǒng)的搜索結(jié)果進行融合的過程。RRF通過考慮每個列表中項目的排名和各個列表本身的可靠性進行結(jié)果合并。

RRF算法的公式如下:

RRF(S) = Σ(1 / (60 + rank))

其中,S是待融合的集合,rank表示每一個條目在其列表中的排名。

以一個具體例子說明:

假設(shè)我們有三個搜索系統(tǒng)A、B、C,它們分別產(chǎn)生以下排名:

  • 系統(tǒng)A:[物品1, 物品2, 物品3]
  • 系統(tǒng)B:[物品2, 物品1, 物品3]
  • 系統(tǒng)C:[物品3, 物品1, 物品2]

針對物品1,它在系統(tǒng)A、B、C中的排名分別為1、2、2。其在RRF算法中的得分為:

1/(60+1) + 1/(60+2) + 1/(60+2) = 0.016129 + 0.016393 + 0.016393 = 0.048915

同樣地,我們可以計算物品2和物品3的RRF分?jǐn)?shù)。然后比較這些得分,得分最高的物品就被看作是綜合最優(yōu)的選擇。

下面是EnsembleRetriever中對數(shù)據(jù)融合的RRF算法核心實現(xiàn):

rrf_score: Dict[str, float] = defaultdict(float)
for doc_list, weight in zip(doc_lists, self.weights):
    for rank, doc in enumerate(doc_list, start=1):
        # self.c = 60
        rrf_score[doc.page_content] += weight / (rank + self.c)

使用elasticsearch替換BM25模型

我們先通過下面的docker-compose.yml安裝elasticsearch

version: "2.3"
services:
  elasticsearch:
    image: elasticsearch:8.9.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - xpack.security.enabled=false
    volumes:
      - ./es_data:/usr/share/elasticsearch/data
      - ./plugins:/usr/share/elasticsearch/plugins
    ports:
      - 9200:9200
    networks:
      - elastic
 
  kibana:
    image: kibana:8.6.0
    container_name: kibana
    ports:
      - 5601:5601
    depends_on:
      - elasticsearch
    networks:
      - elastic      
 
networks:
  elastic:
    name: elastic
    driver: bridge

這里我們只是做演示示例,所以安裝比較簡單,沒有安裝證書和映射分詞器等等,elasticsearch安裝完之后,我們就可以往里面插入數(shù)據(jù)并進行查詢了。在插入數(shù)據(jù)之前,我們先建好index, 這個index可以理解成向量庫的collection、mysql的table:

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "analysis": {
      "analyzer": {
        "english": {
          "tokenizer": "standard",
          "filter": ["lowercase", "english_stemmer"]
        }
      },
      "filter": {
        "english_stemmer": {
          "type": "stemmer",
          "language": "english"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "text": {
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}
'

索引創(chuàng)建好之后,我們可以開始插入數(shù)據(jù)。下面是一個 Python 示例,展示了如何使用 ??langchain_elasticsearch?? 模塊向 Elasticsearch 插入數(shù)據(jù),并進行查詢:

from langchain_elasticsearch import ElasticsearchStore,  BM25Strategy


doc_list_1 = [
    "I like apples",
    "You like Apples",
    "I like oranges",
    "Apples and oranges are fruits",
]

db = ElasticsearchStore(
    es_url="http://localhost:9200",
    index_name="my_index",
    strategy=BM25Strategy(),
)

# initialize the bm25 retriever and chroma retriever
db.add_texts(doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1))
elasticsearch_retriever = db.as_retriever(search_kwargs={"k": 4})
# [Document(metadata={'source': 1}, page_cnotallow='I like apples'), Document(metadata={'source': 1}, page_cnotallow='You like Apples'), Document(metadata={'source': 1}, page_cnotallow='Apples and oranges are fruits')]
print(elasticsearch_retriever.invoke("apple"))

你會看到,當(dāng)我們查詢 "apple" 時,Elasticsearch 能夠返回所有包含 "apple" 的文檔。這展示了 Elasticsearch 相比單獨使用 BM25 算法的優(yōu)勢。此外,elasticsearch還支持模糊匹配和自動補全功能,即使用戶輸入有誤,也能提供相關(guān)的搜索結(jié)果,感興趣的可以自行去研究,這里我們不做重點講解。

現(xiàn)在我們可以使用elasticsearch和chromadb來做混合檢索了,具體代碼如下:

from langchain_community.vectorstores import Chroma
from langchain.retrievers import EnsembleRetriever
from langchain_openai import OpenAIEmbeddings
from langchain_elasticsearch import ElasticsearchStore, BM25Strategy

doc_list_1 = [
    "I like apples",
    "You like Apples",
    "I like oranges",
    "Apples and oranges are fruits",
]

db = ElasticsearchStore(
    es_url="http://localhost:9200",
    index_name="my_index",
    strategy=BM25Strategy(),
)

db.add_texts(doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1))
elasticsearch_retriever = db.as_retriever(search_kwargs={"k": 4})
# elasticsearch_retriever:  [Document(page_cnotallow='I like apples', metadata={'source': 1}), Document(page_cnotallow='You like Apples', metadata={'source': 1}), Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1})]
print("elasticsearch_retriever: ", elasticsearch_retriever.invoke("apple"))
# initialize the bm25 retriever and chroma retriever

embedding = OpenAIEmbeddings()
chroma_vectorstore = Chroma.from_texts(
    doc_list_1, embedding, metadatas=[{"source": 2}] * len(doc_list_1)
)
chroma_retriever = chroma_vectorstore.as_retriever(search_kwargs={"k": 4})
# chroma_retriever:  [Document(page_cnotallow='I like apples', metadata={'source': 2}), Document(page_cnotallow='You like Apples', metadata={'source': 2}), Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 2}), Document(page_cnotallow='I like oranges', metadata={'source': 2})]
print("chroma_retriever: ", chroma_retriever.invoke("apple"))
# initialize the ensemble retriever
ensemble_retriever = EnsembleRetriever(
    retrievers=[elasticsearch_retriever, chroma_retriever], weights=[0.5, 0.5]
)
# ensemble_retriever:  [Document(page_cnotallow='I like apples', metadata={'source': 1}), Document(page_cnotallow='You like Apples', metadata={'source': 1}), Document(page_cnotallow='Apples and oranges are fruits', metadata={'source': 1}), Document(page_cnotallow='I like oranges', metadata={'source': 2})]
print("ensemble_retriever: ", ensemble_retriever.invoke("apple"))

實際上,Elasticsearch已經(jīng)提供了混合檢索功能。它允許在存儲文檔時同時存儲對應(yīng)的文本向量,在進行搜索時只需指定為混合搜索模式即可啟用這項功能。但需注意,該功能屬于付費服務(wù)。以下是相關(guān)示例代碼:

from langchain_openai import OpenAIEmbeddings
from langchain_elasticsearch import ElasticsearchStore, BM25Strategy, DenseVectorStrategy


doc_list_1 = [
    "I like apples",
    "You like Apples",
    "I like oranges",
    "Apples and oranges are fruits",
]

db = ElasticsearchStore(
    es_url="http://localhost:9200",
    index_name="my_index_1",
    embedding = OpenAIEmbeddings(),
    strategy=DenseVectorStrategy(hybrid=True),
)

db.add_texts(doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1))
elasticsearch_retriever = db.as_retriever(search_kwargs={"k": 4})
print("elasticsearch_retriever: ", elasticsearch_retriever.invoke("apple"))

在這個例子中,我們設(shè)置了DenseVectorStrategy策略并開啟了混合檢索模式(hybrid=True)。然而,此時我們遇到了一個報錯:

elasticsearch.AuthorizationException: AuthorizationException(403, 'security_exception', 'current license is non-compliant for [Reciprocal Rank Fusion (RRF)]')

這個錯誤表示當(dāng)前的許可證并不包含“Reciprocal Rank Fusion (RRF)”功能,即Elasticsearch的混合檢索功能。如果我們只設(shè)置hybrid=False,那么就會使用Elasticsearch的基礎(chǔ)向量檢索功能,而不涉及任何付費服務(wù)。


本文轉(zhuǎn)載自公眾號AI 博物院 作者:longyunfeigu

原文鏈接:??https://mp.weixin.qq.com/s/F2Ffb2rsCam_6BVDSak-GQ??

?著作權(quán)歸作者所有,如需轉(zhuǎn)載,請注明出處,否則將追究法律責(zé)任
標(biāo)簽
收藏
回復(fù)
舉報
回復(fù)
相關(guān)推薦
乱小说综合网站| 欧美色图第一页| 亚洲欧美日韩国产综合| 亚洲人成电影网站| 国产精品看片资源| 黄色网址在线免费| 久久综合99re88久久爱| 成人羞羞视频免费| 在线一区二区三区视频| 国产成人午夜电影网| 国产色综合天天综合网| 热三久草你在线| 一本到不卡精品视频在线观看| 精品国产av无码一区二区三区| 97人人爽人人澡人人精品| 一级女性全黄久久生活片免费| 久久久综合av| 久草在线新免费首页资源站| 美女国产一区| 国产日韩欧美视频| theporn国产在线精品| 中文字幕欧美激情一区| 欧美精品aaa| www.综合网.com| 欧美日韩精品国产| 秋霞在线观看av| jiujiure精品视频播放| 国产欧美在线观看一区| 亚洲综合激情五月| 日本欧美一区| 精品久久久久久久久久久院品网| 色视频在线播放| 国产精品视频一二三区| 欧美国产日韩激情| 极品销魂美女一区二区三区| 久久av一区二区三区亚洲| 色婷婷热久久| 欧美精品免费视频| 欧美在线观看在线观看| 一卡二卡欧美日韩| 久久mv成人精品亚洲动漫| 中文字幕精品一区 | 成人免费高清| 欧美中文字幕一区| 亚洲综合激情五月| 日韩精品1区2区3区| 亚洲色图综合久久| 国产蜜臀在线| 91麻豆免费看片| 欧美午夜小视频| 日本一本不卡| 国产成人综合av| 精品久久成人| 国产欧美va欧美va香蕉在线| 欧美国产一区二区三区激情无套| 国产精品日韩欧美| 综合久久婷婷| 女女同性女同一区二区三区91| 久久精品国产清高在天天线| 亚洲欧美日韩国产成人综合一二三区| 日韩精品视频网站| 国产日韩亚洲欧美在线| 26uuu久久综合| 欧美xxxx18| 色综合久久久久综合体桃花网| 成人亚洲性情网站www在线观看| 欧美日韩精品电影| 免费电影视频在线看| 在线日韩欧美视频| 水莓100在线视频| 欧美午夜精品在线| 九一国产精品视频| 亚洲色图网站| 久久久水蜜桃| 成人手机电影网| 91精品国产高久久久久久五月天| 一二三区精品视频| 黄色免费在线观看| 最近2019好看的中文字幕免费| 黄色片在线免费观看| 欧美人与禽zozo性伦| а√在线中文网新版地址在线| 玉米视频成人免费看| 中文字幕一区二区中文字幕| 国产一区二区精品久| 91观看网站| 久草精品在线观看| 奇米影视亚洲狠狠色| 久久国产精品黑丝| 国产一区二区三区四区福利| 超碰成人免费在线| 国产精品久久久久影视| 亚洲高清福利| 国产亚洲精品综合一区91| 久久99精品国产自在现线| 久久99精品国产99久久| 91免费国产在线| av大片在线播放| 中文字幕一区二区三区色视频 | 久久av一区二区三区亚洲| 国产精品白丝jk黑袜喷水| 777免费视频| 欧美成人激情免费网| 在线播放一区二区精品视频| 国产精品美女久久久久av福利| 成人av网址在线观看| 日本在线播放一区| 中文字幕免费在线观看视频一区| 风间由美一区| 亚洲成在人线在线播放| xxxx视频在线| 国产欧美一区二区三区在线看 | 欧美日韩国产激情| 爱情电影社保片一区| 欧美日韩国产在线观看| 亚洲伊人精品酒店| 精品久久久久久乱码天堂| 女人色偷偷aa久久天堂| 欧美一区在线直播| 不卡的国产精品| 自拍偷拍亚洲欧美| 欧美精品大片| 国产一区免费在线| 国产精品色哟哟网站| 91麻豆国产福利在线观看宅福利| 欧美激情伊人电影| 国产在线看一区| 成人好色电影| 秋霞av国产精品一区| 国产一区二区不卡| 蜜芽在线免费观看| 91精品久久久久久久久久另类 | 91国内揄拍国内精品对白| 久久成人免费网| 中文字幕日本在线观看| 欧美亚洲成人xxx| 99久久精品国产毛片| 成 年 人 黄 色 大 片大 全| 色综合久久中文综合久久97| 加勒比视频一区| 国产亚洲综合视频| 亚洲男人天堂2024| 蜜桃视频第一区免费观看| 免费在线午夜视频| 欧美色综合影院| 亚洲free性xxxx护士hd| 国产视频一区二区不卡| 中文字幕欧美日韩一区二区| 欧美精品久久久| 国产精品美女免费看| 国产69精品久久久久9| 亚洲国产精品麻豆| 在线观看三级视频欧美| 色综合久久66| 91精品免费在线观看| 亚洲香肠在线观看| 国产精品久久占久久| 成人午夜国产| 风间由美性色一区二区三区| 国产精品午夜电影| 久久一夜天堂av一区二区三区 | 国产精品久久久久久久app| 午夜成人在线视频| 日韩欧美国产免费播放| 欧美精品久久99久久在免费线| 国产精品久久久久久久午夜片 | 国产精品久久久久久久久晋中 | 日韩av播放器| 在线播放一区二区三区| 久久精品视频亚洲| 亚洲欧美精品| 欧美卡一卡二| 亚洲盗摄视频| 亚洲成人高清在线| 亚洲第一精品福利| 亚洲精品日韩丝袜精品| 亚洲视频专区在线| 中文字幕亚洲激情| 日韩精品在线影院| 欧美大胆人体bbbb| 日韩欧美一区二区视频| 久久亚洲电影天堂| 成人高h视频在线| 高清hd写真福利在线播放| 精品中文一区| 国产一区二区三区av电影| 一本色道久久加勒比精品| 欧美久久一二三四区| 国产富婆一区二区三区| 日韩精品福利| 日本成a人片在线观看| 香蕉久久一区| 公共露出暴露狂另类av| 亚洲国产精品久久久久爰色欲| 国外成人在线视频网站| 91久久精品www人人做人人爽| 久久精品国产精品国产精品污| 国产资源在线免费观看| 性欧美18一19sex性欧美| 亚洲欧美成人综合|