文件搜尋

選擇不同的文件搜尋方法

使用search_type參數可選擇不同的文件搜尋方法去找出與問題相關的文件段落,可使用svm, mmr, tfidf, knn。另可使用merge,為前三者的合併。

  1. 支持向量機(svm) 使用輸入提示和文件向量來訓練svm模型,訓練後,svm可用於基於其與訓練數據的相似性對新向量進行評分。

  2. Max Marginal Relevance(mmr) 通過余弦相似度選擇相似的文件,但它也考慮多樣性,因此它還會懲罰與已選擇文件的接近。

  3. 詞頻-逆文檔頻率(tfidf) 是信息檢索和文本挖掘中常用的權重技術。TF-IDF是一種統計方法,用於評估詞語在一個文檔集合或語料庫中相對於該集合中的一個特定文檔的重要性。

  4. K-最近鄰居(KNN) 是一種機器學習算法,用於分類和回歸問題。對於新數據點,它計算其與已知數據點的距離,然後基於最近的 k 個鄰居來預測類別或數值。在分類中,以多數票決定類別,而在回歸中則計算鄰居的平均值。

  5. ***Okapi BM25(bm25)***(BM 是最佳匹配的縮寫)是一種基於查詢詞出現在每個文檔中的檢索功能,而不考慮它們在文檔中的相鄰關系的排名一組文檔的方法。它是一系列具有略有不同組件和參數的評分函數。

  6. rerank 使用bge-reranker模型對文檔進行相似度排序,速度較慢。 (rerank/rerank:bge-reranker-large)



自動選擇搜尋方法

auto/ audo_rerank 是另一種可以選擇的文件搜尋策略,使用 bm25 來搜尋相同詞語的文件,並用 svm 搜尋近似詞意的文件,若為 audo_rerank 且兩者皆沒有找到,則使用rerank模型去遍歷文件,但會相當緩慢。

自訂搜尋方法

如果你希望設計自己的方法找尋最相似的文檔,可以建立search_type函數,並將此函數作為search_type參數

此函數輸入包含:

1.query_embeds: 查詢的嵌入。(numpy array)
2.docs_embeds: 所有文檔的嵌入。(表示文檔嵌入的 numpy 數組的list)
3.k: 所要選擇的最相關文檔的數量。(integer)
4.log: 一個字典,可用於記錄任何您希望記錄的其他信息。(dictionary)


此函數須回傳相似文檔的index順序(list)



example

如範例,我們使用歐幾里得距離度量來識別最相關的文檔。它返回一個表示距離小於指定閾值的查詢和文檔嵌入之間的前 k 個文檔的索引列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import akasha

def cust(query_embeds, docs_embeds, k:int, relevancy_threshold:float, log:dict):

from scipy.spatial.distance import euclidean
import numpy as np
distance = [[euclidean(query_embeds, docs_embeds[idx]),idx] for idx in range(len(docs_embeds))]
distance = sorted(distance, key=lambda x: x[0])


## change dist if embeddings not between 0~1
max_dist = 1
while max_dist < distance[-1][0]:
max_dist *= 10
relevancy_threshold *= 10


## add log para
log['dd'] = "miao"


return [idx for dist,idx in distance[:k] if (max_dist - dist) >= relevancy_threshold]

doc_path = "./mic/"
prompt = "五軸是什麼?"

qa = akasha.Doc_QA(verbose=True, search_type = cust, embeddings="hf:shibing624/text2vec-base-chinese")
qa.get_response(doc_path= doc_path, prompt = prompt)


Document 物件

在akasha中,文件搜尋的結果會以list of Document的形式回傳,Docuement為一個儲存文件內容(page_content)和後設資料(metadata)的物件,可以以此進行宣告和取用。

1
2
3
4
5
6
7
8
9
10
from langchain.schema import Document

text = "這是一個測試文件段落,這是一個測試文件段落,這是一個測試文件段落。"
metadata = {'page':0, 'source':'docs/test1/f1.txt'}

doc1 = Document(page_content=text, metadata=metadata)

print(doc1.page_content)
print(doc1.metadata)



Retriver

若您想自行進行文件搜尋,在akasha中,文件搜尋是以以下流程進行:

  1. 從文件資料夾中建立chromadb,讀取為dbs物件
  2. 根據搜尋方法取得retriever物件
  3. 利用retriever進行文件搜尋,並根據語言模型和設定的文件token上限回傳不超過token上限的文件內容,與文件的排序(list of Document)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import akasha

emb_name = "openai:text-embedding-ada-002"
emb_obj = akasha.handle_embeddings(emb_name)
search_type = "auto"
query = "五軸是甚麼?"
model_name = "openai:gpt-3.5-turbo"
max_input_tokens = 3000
# 1. get dbs object
db, _ = akasha.db.processMultiDB(doc_path_list="docs/mic", verbose=False, embeddings=emb_obj,
chunk_size=1000, ignore_check=True)

# 2. get retriver list
retriver_list = akasha.search.get_retrivers(db=db, embeddings=emb_obj,
search_type=search_type, log={})


# 3. get sorted list of Documents by similarity
docs, doc_length, doc_tokens = akasha.search.get_docs(
db,
retrivers_list,
query,
language="ch",
search_type=search_type,
verbose=False,
model=model_name,
max_input_tokens=max_input_tokens
)

print(docs[0].page_content) # docs is list of Documents
print(doc_length) # integer
print(doc_tokens) # integer

get_relevant_documents_and_scores

若您只想使用單一的搜尋方法(如 mmr, svm, knn, tfidf, bm25),且不想限制文件的總token數量,可以使用 get_relevant_documents_and_scores取得文件排序結果(list of Documents)與相似度的分數(list of float)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import akasha

emb_name = "openai:text-embedding-ada-002"
emb_obj = akasha.handle_embeddings(emb_name)
search_type = "svm"
query = "五軸是甚麼?"
model_name = "openai:gpt-3.5-turbo"


# 1. get dbs object
db, _ = akasha.db.processMultiDB(doc_path_list="docs/mic", verbose=False, embeddings=emb_obj,
chunk_size=1000, ignore_check=True)

# 2. get retriver list
single_retriver = akasha.search.get_retrivers(db=db, embeddings=emb_obj,
search_type=search_type, log={})[0]


# 3. get sorted list of Documents and scores by similarity
### this method is only for single search method, not for 'merge' and 'auto' ###
docs, scores = single_retriver.get_relevant_documents_and_scores(query)


print(docs[0].page_content) # docs is list of Document
print(scores[0]) # float
print(len(docs), len(scores))

retri_docs

若您不想限制文件的總token數量,可以使用 retri_docs取得文件排序結果(list of Documents)
可根據參數 topK指定回傳的文件片段數量上限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import akasha

emb_name = "openai:text-embedding-ada-002"
emb_obj = akasha.handle_embeddings(emb_name)
search_type = "auto"
query = "五軸是甚麼?"
topK = 100
# 1. get dbs object
db, _ = akasha.db.processMultiDB(doc_path_list="docs/mic", verbose=False, embeddings=emb_obj,
chunk_size=1000, ignore_check=True)

# 2. get retriver list
retriver_list = akasha.search.get_retrivers(db=db, embeddings=emb_obj,
search_type=search_type, log={})


# 3. get sorted list of Documents by similarity
docs = akasha.search.retri_docs(
db,
retrivers_list,
query,
search_type=search_type,
topK=topK
verbose=False,
)

print(docs[0].page_content) # docs is list of Document