0%

websearch

websearch 是一個結合網頁搜尋與語言模型回答的工具。它會根據使用者的問題在網路上搜尋相關資訊,並使用語言模型整合搜尋結果來回答問題。websearch 支援多種搜尋引擎與語言,並提供詳細的日誌記錄功能。

除了wiki,其他搜尋方法皆需要輸入搜尋引擎的API_KEY到.env檔或環境變數中

  • SERPER: SERPER_API_KEY
  • BRAVE: BRAVE_API_KEY
  • TAVILY: TAVILY_API_KEY

websearch 功能

  1. 網頁搜尋:支援多種搜尋引擎,包括 wikiserpertavilybrave
  2. 日誌保存:支持保存執行過程與結果的日誌,便於後續分析。
  3. 流式輸出:支援流式輸出回答,適合需要即時回應的場景。

websearch 範例

使用 serper 搜尋引擎進行搜尋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import akasha

wb = akasha.websearch(
model="openai:gpt-4o",
language="ch",
search_engine="serper",
search_num=5,
verbose=True,
keep_logs=True,
)

# 使用搜尋引擎回答問題
res = wb("工業4.0是什麼?")

# 保存日誌
wb.save_logs("wb.json")

使用流式輸出回答

1
2
3
4
5
6
# 啟用流式輸出
st = wb("工業4.0是什麼?", stream=True)

# 逐步輸出回答
for s in st:
print(s)

websearch 參數

初始化參數

model: str

使用的語言模型,例如 "openai:gpt-4o""openai:gpt-3.5-turbo"

language: str

搜尋語言與地區,支持 "en"(英文)或 "ch"(中文)。

search_engine: str

使用的搜尋引擎,支持:

  • "wiki":維基百科搜尋。
  • "serper":Google 搜尋 API(需申請 API 金鑰)。
  • "tavily":Tavily 搜尋 API(需申請 API 金鑰)。
  • "brave":Brave 搜尋 API(需申請 API 金鑰)。
search_num: int

搜尋結果的數量。

max_input_tokens: int

單次輸入模型的最大 token 數。

max_output_tokens: int

模型輸出的最大 token 數。

temperature: float

語言模型的隨機性參數,範圍為 0.0 到 1.0。

system_prompt: str

指示語言模型的輸出格式需求。

keep_logs: bool

是否保存執行過程與結果的日誌。

verbose: bool

是否顯示詳細的執行過程。

stream: bool

是否啟用流式輸出。

env_file: str

指定 .env 環境設定檔的路徑。


call 參數

prompt: str

使用者的問題。

stream: bool

是否啟用流式輸出。

search_engine: str

指定搜尋引擎,支持 "wiki""serper""tavily""brave"

search_num: int

搜尋結果的數量。

language: str

搜尋語言與地區,支持 "en""ch"


日誌與結果

  • 搜尋過程與結果會保存到指定的日誌文件中。
  • 日誌包括搜尋引擎、搜尋結果數量、語言模型的輸入輸出 token 數等。

相關連結

gen_image

gen_image 是一個結合語言模型與圖像生成的工具。可根據使用者的提示詞(prompt)生成圖片,或根據現有圖片進行編輯。支援 OpenAI、Azure OpenAI 及 Gemini 圖像模型,並可自訂圖片品質、尺寸與儲存路徑。

目前僅支援 openai/azure openai 及 gemini(如 model=”gemini:gemini-2.0-flash-preview-image-generation”)

  • 若使用 openai 受保護模型(如 “gpt-image-1”),帳號需經過驗證。
  • 若使用 azure openai,請確保 .env 檔案中的 AZURE_API_VERSION 設為 "2025-04-01-preview"

gen_image 功能

  1. 圖片生成:根據提示詞生成圖片,支援多種模型與格式。
  2. 圖片編輯:可根據提示詞對現有圖片進行編輯,支援單張或多張圖片。
  3. 自訂參數:可設定圖片品質(high/medium/low)、尺寸(如 256x256, 512x512, 1024x1024)、儲存路徑等。
  4. 日誌保存:可選擇是否顯示詳細過程與結果。

gen_image 範例

生成圖片

1
2
3
4
5
6
7
8
9
import akasha

# 生成圖片,可選擇模型、品質、尺寸與儲存路徑
save_path = akasha.gen_image(
prompt="一隻可愛的絨毛娃娃,是北海道的長尾山雀,坐在白雪的樹枝上唱歌",
model="gemini:gemini-2.0-flash-preview-image-generation",
save_path="長尾山雀.png",
env_file=".env3",
)

編輯圖片

1
2
3
4
5
6
7
8
9
10
import akasha

# 編輯現有圖片,可為單張或多張
save_path = akasha.edit_image(
model="openai:gpt-image-1",
prompt="增加一隻可愛的鯊魚娃娃在旁邊",
images="長尾山雀.png",
save_path="鯊鯊.png",
env_file=".env3",
)

gen_image 參數

gen_image 初始化參數

prompt: str

生成圖片的提示詞。

save_path: str

圖片儲存路徑,可為 .png、.jpeg、.webp 等格式,預設為 “./image.png”。

model: str

使用的圖像生成模型,例如 "openai:gpt-image-1""gemini:gemini-2.0-flash-preview-image-generation"

size: str

圖片尺寸(如 “256x256”、”512x512”、”1024x1024”),預設為 “auto”。

quality: str

圖片品質,可選 “high”、”medium”、”low”,預設為 “auto”。

verbose: bool

是否顯示詳細過程,預設為 False。

env_file: str

指定 .env 環境設定檔的路徑。


edit_image 初始化參數

prompt: str

編輯圖片的提示詞。

images: list[str] | str | Path

要編輯的圖片路徑,可為單張或多張。

save_path: str

編輯後圖片儲存路徑,預設為 “./image.png”。

model: str

使用的圖像生成模型,預設為 "openai:gpt-image-1"

size: str

圖片尺寸,預設為 “auto”。

quality: str

圖片品質,預設為 “auto”。

verbose: bool

是否顯示詳細過程,預設為 False。

env_file: str

指定 .env 環境設定檔的路徑。


日誌與結果

  • 生成或編輯過程與結果可選擇顯示於終端機。
  • 圖片將儲存於指定路徑。

相關連結

提示格式

根據使用的語言模型不同,使用不同的格式來下指令可以得到更好的結果,akasha目前提供 gpt, llama, chat_gpt, chat_mistral, chat_gemini, auto 等格式
若選擇 auto會根據模型類別來決定提示格式

gpt

1
2
3
4


prompt_format = System: {system_prompt} \n\n {history_messages} \n\n Human: {prompt}

llama

1
2
3
4


prompt_format = [INST] <<SYS>> {system_prompt} \n\n <<SYS>> {history_messages} \n\n {prompt} [\INST]

chat_gpt

1
2
3
4
5
6
7
8
9
10


prompt_format = [{"role":"system", "content": {system_prompt} },
{"role":"user", "content": {history msg1}},
{"role":"assistant", "content": {history msg2}},
.
.
.
{"role":"user", "content": {prompt}}]

chat_mistral

1
2
3
4
5
6
7
8
9
10
11


prompt_format = [{"role":"user", "content": "start conversation" },
{"role":"assistant", "content": {system_prompt}},
{"role":"user", "content": {history msg1}},
{"role":"assistant", "content": {history msg2}},
.
.
.
{"role":"user", "content": {prompt}}]

chat_gemini

1
2
3
4
5
6
7
8
9

prompt_format =[{"role":"model", "parts": [{system_prompt}]},
{"role":"user", "parts": [{history msg1}]},
{"role":"model", "parts": [{history msg2}]},
.
.
.
{"role":"user", "parts": [{prompt}]}]

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import akasha
sys_prompt = "請用中文回答"
prompt = "五軸是甚麼?"
qa = akasha.RAG(
verbose=False,
search_type="svm",
model="openai:gpt-3.5-turbo",
prompt_format_type="chat_gpt")

response = qa(
data_source="docs/mic/",
prompt=prompt,
system_prompt=sys_prompt,
)

Example2

1
2
3
4
5
6
7
8
9
10
11
12
import akasha
import akasha.helper as ah
from akasha.utils.prompts.gen_prompt import format_sys_prompt

sys_prompt = "請用中文回答"
prompt_format = "chat_gpt"
prompt = "五軸是甚麼?"
input_text = format_sys_prompt(sys_prompt,prompt,prompt_format)
model_obj = akasha.handle_model("openai:gpt-3.5-turbo",False,0.0)

response = ah.call_model(model_obj, input_text)

選擇不同的文件搜尋方法

使用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.relevancy_threshold: 保留文檔的相似度閾值。(float)


此函數須回傳相似文檔的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
import akasha

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

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


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

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

qa = akasha.RAG(verbose=True, search_type = cust, embeddings="hf:shibing624/text2vec-base-chinese")
qa(data_source= 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
34
35
36
import akasha
import akasha.helper as ah
import akasha.utils.db as adb
from akasha.utils.search.retrievers.base import get_retrivers
from akasha.utils.search.search_doc import search_docs

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

# 1. get dbs object
db, _ = adb.process_db(data_source="docs/mic", verbose=False, embeddings=emb_obj,
chunk_size=1000)

# 2. get retriver list
retriver_list = get_retrivers(db=db, embeddings=emb_obj,
search_type=search_type)


# 3. get sorted list of Documents by similarity
docs, doc_length, doc_tokens = akasha.search.search_docs(
retriver_list,
query,
model=model_name,
max_input_tokens=max_input_tokens,
search_type=search_type,
language="ch",
)

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
28
29
30
31
import akasha
import akasha.helper as ah
import akasha.utils.db as adb
from akasha.utils.search.retrievers.base import get_retrivers
from akasha.utils.search.search_doc import search_docs

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

# 1. get dbs object
db, _ = adb.process_db(data_source="docs/mic", verbose=False, embeddings=emb_obj,
chunk_size=1000)

# 2. get single retriver object
single_retriver = get_retrivers(db=db, embeddings=emb_obj,
search_type=search_type)[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
30
31
32
33
34
import akasha
import akasha.helper as ah
import akasha.utils.db as adb
from akasha.utils.search.retrievers.base import get_retrivers
from akasha.utils.search.search_doc import retri_docs

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

# 1. get dbs object
db, _ = adb.process_db(data_source="docs/mic", verbose=False, embeddings=emb_obj,
chunk_size=1000)

# 2. get retriver list
retriver_list = get_retrivers(db=db, embeddings=emb_obj,
search_type=search_type)


# 3. get sorted list of Documents by similarity
docs = retri_docs(
db,
retriver_list,
query,
search_type=search_type,
topK=topK
)

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


dbs物件

在akasha中,chromadb建立完之後,會被儲存成dbs物件,會儲存chromadb中的文件內容、metadata、向量資料、unique id,並被使用於後續的vector similarity search。

該物件可以添加多個chromadb資料,也可與其他dbs物件互相結合,也可根據filter抽取出需要的向量資料。

建立向量資料

process_db

process_db可對多個文件集(list of directory)建立chromadb,並回傳dbs物件與建立不成功的檔案list,若文件內容、使用嵌入模型、chunk size相等的chromadb已存在,則不會重新創建而直接讀取。

文件內容改變也會建立新的chromadb,設定參數ignore_check=True則不進行文件內容更改與否的確認,可更快的進行chromadb的讀取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import akasha
import akasha.utils.db as adb
data_source = ["docs/mic", "docs/1.pdf", "https://github.com/iii-org/akasha"]
emb_name = "openai:text-embedding-3-small"
db, ignore_files = adb.process_db(
data_source=data_source,
embeddings=emb_name,
chunk_size=1000
verbose=True,
)

### dbs object is a class that stores all information of the chromadb ###
db.get_docs()
db.get_embeds()
db.get_metadatas
db.get_ids()


使用dbs物件

init

您可以直接宣告akasha.utils.db.dbs()建立空的dbs物件,也可以利用已建立的chromadb建立dbs物件。

dbs物件包含ids(每個文字段落的unique id), embeds(每個文字段落的向量), metadatas(每個文字段落的後設資料), docs(每個文字段落的內容) 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah
db1 = adb.dbs()

### use chromadb to initialize dbs object ###
storage_directory = "chromadb/12345"
emb_obj = ah.handle_embeddings()
docsearch = Chroma(persist_directory=storage_directory,
embedding_function=emb_obj)
db2 = adb.dbs(docsearch)

print(len(db2.get_ids())) # list[str]
print(len(db2.get_embeds())) # list[list[float]]
print(len(db2.get_metadatas())) #list[dict]
print(len(db2.get_docs())) #list[dict]

merge

dbs物件之間可以使用.merge相互結合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)
db1 = adb.dbs(docsearch1)

docsearch2 = Chroma(persist_directory="chromadb/456",
embedding_function=emb_obj)
db2 = adb.dbs(docsearch2)

db2.merge(db1)

print(len(db2.get_ids())) # list[str]
print(len(db2.get_embeds())) # list[list[float]]
print(len(db2.get_metadatas())) #list[dict]
print(len(db2.get_docs())) #list[dict]

add_chromadb

dbs物件可以添加新的chromadb資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)

docsearch2 = Chroma(persist_directory="chromadb/456",
embedding_function=emb_obj)

db = adb.dbs(docsearch1)

db.add_chromadb(docsearch2)

print(len(db.get_ids())) # list[str]
print(len(db.get_embeds())) # list[list[float]]
print(len(db.get_metadatas())) #list[dict]
print(len(db.get_docs())) #list[dict]

get_Documents

使用get_Docuemnts可以得到當前dbs物件中儲存的Documents list (包含page_contents文件內容和metadata後設資料)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)

db = adb.dbs(docsearch1)

docs = db.get_Documents()



print([doc.page_contents for doc in docs]) # list[str]
print([docs.metadata for doc in docs]) # list[dict]



載入chromadb

成功建立chromadb後,若想再載入chromadb,可以使用 get_storage_directory取得chromadb路徑並進行載入,取得dbs物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import akasha.utils.db as adb
data_source = ["docs/mic"]
emb_name = "openai:text-embedding-3-small"
chunk_size = 1000
### create chromadb ###
db, ignore_files = adb.process_db(
data_source=data_source,
embeddings=emb_name,
chunk_size=chunk_size,
verbose=True,
)


### load chromadb ###
embed_type, embed_name = emb_name.split(":")
chromadb_mic_dir = adb.get_storage_directory(
"docs/mic", chunk_size, embed_type, embed_name
)

### after you created the chromadb, you can also load it by chroma_name ###
chroma_list = [chromadb_mic_dir]
db, ignore_files = adb.load_db_by_chroma_name(chroma_name_list=chroma_list)

載入文件

若不想建立向量資料庫,只需要載入文件,可以使用 load_docs_from_info單純載入文件成list of Documents

1
2
3
4
5
6
import akasha.utils.db as adb
data_source = ["docs/mic", "docs/1.pdf", "https://github.com/iii-org/akasha"]
docs = adb.load_docs_from_info(info=data_source, verbose=True)

print(docs[0].page_content)



提取dbs物件

extract_db_by_file

extract_db_by_file可以將檔名符合file_name_list中的所有資料提取出來生成新的dbs物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)

db = adb.dbs(docsearch1)
file_name_list = ['f1.txt', 'f2.docx']

extracted_db = adb.extract_db_by_file(db=db, file_name_list=file_name_list)

print(len(extracted_db.get_ids())) # list[str]
print(len(extracted_db.get_embeds())) # list[list[float]]
print(len(extracted_db.get_metadatas())) #list[dict]
print(len(extracted_db.get_docs())) #list[dict]

extract_db_by_keyword

extract_db_by_keyword可以將文字段落中存在任何keyword_list中keyword的所有資料提取出來生成新的dbs物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)

db = adb.dbs(docsearch1)
keyword_list = ["資訊產業策進會", "AI人工智慧"]

extracted_db = adb.extract_db_by_keyword(db=db, keyword_list=keyword_list)

print(len(extracted_db.get_ids())) # list[str]
print(len(extracted_db.get_embeds())) # list[list[float]]
print(len(extracted_db.get_metadatas())) #list[dict]
print(len(extracted_db.get_docs())) #list[dict]

extract_db_by_ids

extract_db_by_ids可以將存在id_list中的的所有資料提取出來生成新的dbs物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)

db = adb.dbs(docsearch1)
id_list = ['2024-10-21-17_45_21_963065_0', '2024-10-21-17_45_23_601845_0']

extracted_db = adb.extract_db_by_ids(db=db, id_list=id_list)

print(len(extracted_db.get_ids())) # list[str]
print(len(extracted_db.get_embeds())) # list[list[float]]
print(len(extracted_db.get_metadatas())) #list[dict]
print(len(extracted_db.get_docs())) #list[dict]

pop_db_by_ids

pop_db_by_ids會將所選id_list中的的所有資料從dbs物件中移除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

emb_obj = ah.handle_embeddings()

docsearch1 = Chroma(persist_directory="chromadb/123",
embedding_function=emb_obj)

db = adb.dbs(docsearch1)
id_list = ['2024-10-21-17_45_21_963065_0', '2024-10-21-17_45_23_601845_0']

adb.pop_db_by_ids(db=db, id_list=id_list)

print(len(db.get_ids())) # list[str]
print(len(db.get_embeds())) # list[list[float]]
print(len(db.get_metadatas())) #list[dict]
print(len(db.get_docs())) #list[dict]



刪除chromadb內容

在akasha中,同個資料夾內的所有文件會儲存在同一個chromadb資料庫中,若你想刪除整個chromadb資料庫,可以使用 delete_documents_by_directory
若要刪除單一文件,可以使用 delete_documents_by_file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import akasha
from langchain_chroma import Chroma
import akasha.utils.db as adb
import akasha.helper as ah

data_source = ["docs/mic", "docs/1.pdf", "https://github.com/iii-org/akasha"]
emb_name = "openai:text-embedding-3-small"
chunk_size = 1000
### create chromadb ###
db, ignore_files = adb.process_db(
data_source=data_source,
embeddings=emb_name,
chunk_size=chunk_size,
verbose=True,
)

delete_num = adb.delete_documents_by_file(
"docs/1.pdf", emb_name , chunk_size,
)

delete_num = adb.delete_documents_by_directory(
"docs/mic", emb_name, chunk_size
)

MLflow

akasha也可以利用MLflow來保存執行紀錄,您需要自行建立MLflow server。
並將tracking server的url放在程序的同一目錄下的 .env 文件,TRACKING_SERVER_URI= {YOUR_TRACKING_SERVER_URI}。

1
2
3
##.env file

TRACKING_SERVER_URI= YOUR_TRACKING_SERVER_URI

在創建了 .env 文件之後,您可以使用 record_exp 來設置實驗名稱,它將自動記錄實驗指標和結果到 mlflow 服務器。

1
2
3
4
5
6
7
8
9
10
11
12
import akasha
import os
from dotenv import load_dotenv
load_dotenv()

os.environ["OPENAI_API_KEY"] = "your openAI key"

data_source = "doc/"
prompt = "「塞西莉亞花」的花語是什麼? 「失之交臂的感情」 「赤誠的心」 「浪子的真情」 「無法挽回的愛」"
exp_name = "exp_akasha_rag"
ak = akasha.RAG(record_exp=exp_name)
response = ak.(data_source, prompt)


在你指定的實驗名稱中,可以看到不同次實驗的紀錄,每個紀錄的名稱是embedding, search type and model name的組合

upload_experiments



你也可以直接比較不同次實驗的結果

response_comparison



call_model

若要呼叫語言模型,可以使用輔助函數call_model

1
2
3
4
5
6
7
8
9
10
11
12
import akasha
import akasha.helper as ah
from akasha.utils.prompts.gen_prompt import format_sys_prompt

system_prompt = "用中文回答"
prompt = "五軸是什麼?"
model_obj = ah.handle_model("openai:gpt-e3.5-turbo", False, 0.0)
input_text = format_sys_prompt(system_prompt, prompt, "gpt")

response = ah.call_model(model_obj, input_text)




call_stream_model

若要呼叫語言模型即時回答,可以使用輔助函數call_stream_model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import akasha
import akasha.helper as ah
from akasha.utils.prompts.gen_prompt import format_sys_prompt

system_prompt = "用中文回答"
prompt = "五軸是什麼?"
model_obj = ah.handle_model("openai:gpt-e3.5-turbo", False, 0.0)
input_text = format_sys_prompt(system_prompt, prompt, "gpt")

streaming = ah.call_stream_model(model_obj, input_text)

for s in streaming:
print(s)



call_batch_model

如果你有大量不需要連貫的推理需求,可以使用akasha.helper.call_batch_model 來進行批量推理來提升速度。

1
2
def call_batch_model(model: LLM, prompt: List[str], 
system_prompt: Union[List[str], str] = "") -> List[str]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import akasha.helper as ah
from akasha.utils.prompts.gen_prompt import default_doc_grader_prompt
model_obj = ah.handle_model("openai:gpt-3.5-turbo", False, 0.0)
# this prompt ask LLM to response 'yes' or 'no' if the document segment is relevant to the user question or not.
SYSTEM_PROMPT = default_doc_grader_prompt()
documents = ["Doc1...", "Doc2...", "Doc3...", "Doc4..."]
question = "五軸是什麼?"

prompts = ["document: " + doc +"\n\n" + "User Question: "+ question for doc in documents]

response_list = ah.call_batch_model(model_obj, prompt, SYSTEM_PROMPT)

## ["yes", "no", "yes", "yes"]





call_JSON_formatter

如果你想強制使語言模型輸出符合JSON格式的回答,可以使用 call_JSON_formatter,會轉換語言模型的輸出為字典或字典串列。

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.helper as ah
from pydantic import BaseModel


PROMPT3 = """
openai_model = "openai:gpt-3.5-turbo" # need environment variable "OPENAI_API_KEY"
gemini_model="gemini:gemini-1.5-flash" # need environment variable "GEMINI_API_KEY"
anthropic_model = "anthropic:claude-3-5-sonnet-20241022" # need environment variable "ANTHROPIC_API_KEY"
huggingface_model = "hf:meta-llama/Llama-2-7b-chat-hf" #need environment variable "HUGGINGFACEHUB_API_TOKEN" to download meta-llama model
qwen_model = "hf:Qwen/Qwen2.5-7B-Instruct"
quantized_ch_llama_model = "hf:FlagAlpha/Llama2-Chinese-13b-Chat-4bit"
taiwan_llama_gptq = "hf:weiren119/Taiwan-LLaMa-v1.0-4bits-GPTQ"
mistral = "hf:Mistral-7B-Instruct-v0.2"
mediatek_Breeze = "hf:MediaTek-Research/Breeze-7B-Instruct-64k-v0.1"
"""
model_obj = ah.handle_model("openai:gpt-4o", False, 0.0)


## 使用BaseModel 指定輸出的keys
class Model_Type(BaseModel):
model_type: str
model_name: str


json_response = ah.call_JSON_formatter(model_obj, PROMPT3, keys=Model_Type)
print(json_response)
# response: [{'model_type': 'openai', 'model_name': 'gpt-3.5-turbo'}, {'model_type': 'gemini', 'model_name': 'gemini-1.5-flash'}, {'model_type': 'anthropic', 'model_name': 'claude-3-5-sonnet-20241022'},...




計算token數量

Tokenizer.compute_tokens,此函數回傳該語言模型輸入的文字所需要的token數量
get_doc_length,此函數使用jieba計算字串長度
sim_to_trad,此函數將字串簡轉繁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import akasha.helper as ah

text = "你是一個歷史學家詳細介紹札幌的歷史"
model = "openai:gpt-3.5-turbo"
num_tokens = ah.myTokenizer.compute_tokens(
text=text, model_id=model)

print(num_tokens)

### compute the length of the text by jieba ###
doc_length = ah.get_doc_length(TEXT)

### translate simplified chinese to traditional chinese ###
ret = ah.sim_to_trad(TEXT)

從字串中取出dictionary

extract_json將字串中的json格式轉成字典,若找不到則回傳None

1
2
3
4
5
6
7
8
9
10
11
import akasha.helper as ah
TEXT2 = """工業4.0是甚麼?
{
"title": "工業4.0",
"description": "工業4.0是一場製造業的數位轉型,融合了物聯網、人工智慧與自動化技術,提升生產效率與靈活性。"
}
"""

### get the json format dictionary from the text ###
text_dict = ah.extract_json(TEXT2)

相似度分數

此函式利用bert, rouge, llm計算兩字串的相似度分數(0~1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import akasha.helper as ah

DEFAULT_MODEL = "openai:gpt-4o"

rf1 = """工業4.0是指智慧與互聯的生產系統,旨在感知、預測物理世界並與之互動,以便即時做出支持生產的決策。這一概念最早於2011年在漢諾威工業博覽會上提出,並被
納入德國、美國、中國等國家的高科技產業發展策略中。工業4.0的核心在於利用物聯網、人工智慧、大數據等技術,將生產從自動化提升到智慧化,實現更高效的生
產管理和決策。"""

rf2 = """工業 4.0 是一種智慧與互聯的生產系統,旨在感知、預測物理世界並與之互動,以便即時做出支持生產的決策。
簡單來說,它利用像是物聯網、AI、大數據和雲端等技術,讓製造業更加智能化和自動化。
"""

### use bert to get the similarity score ###
bert_score = ah.get_bert_score(rf1, rf2)

### use rouge to get the similarity score ###
rouge_score = ah.get_rouge_score(rf1, rf2)

### use llm to get the similarity score ###
llm_score = ah.get_llm_score(rf1, rf2, DEFAULT_MODEL)


agents

agents 代理可以讓語言模型能夠使用外部工具來回答問題。通過定義工具並將其與 agents 結合,語言模型可以執行複雜的任務,例如計算、網頁搜尋、數據處理等。agents 支援同步與非同步操作,並提供詳細的日誌記錄功能。


agents 功能

  1. 工具整合:支持將自定義工具或內建工具與語言模型結合使用。
  2. 多輪對話:支持多輪對話,並根據上下文進行推理。
  3. 流式輸出:支持流式輸出回答,適合需要即時回應的場景。
  4. 日誌保存:支持保存執行過程與結果的日誌,便於後續分析。
  5. MCP 支援:可以作為 MCP(Model Context Protocol)客戶端,調用 MCP 伺服器上的工具。

agents 範例

定義自訂工具並使用

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
import akasha
from datetime import datetime

# 定義一個工具來獲取今天的日期
def today_f():
now = datetime.now()
return "today's date: " + str(now.strftime("%Y-%m-%d %H:%M:%S"))

# 創建工具
today_tool = akasha.create_tool(
"today_date_tool",
"This is the tool to get today's date, the tool doesn't have any input parameter.",
today_f,
)

# 創建 agent 並使用工具
agent = akasha.agents(
tools=[today_tool],
model="openai:gpt-4o",
temperature=1.0,
verbose=True,
keep_logs=True,
)

# 問問題並使用工具回答
response = agent("今天幾月幾號?")
print(response)

# 保存日誌
agent.save_logs("logs.json")

使用內建工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import akasha.agent.agent_tools as at

# 使用內建的網頁搜尋工具和 JSON 保存工具
tool_list = [at.websearch_tool(search_engine="brave"), at.saveJSON_tool()]

agent = akasha.agents(
tools=tool_list,
model="openai:gpt-4o",
temperature=1.0,
max_input_tokens=8000,
verbose=True,
keep_logs=True,
)

# 問問題並使用工具回答
response = agent("用網頁搜尋工業4.0,並將資訊存成json檔iii.json")
print(response)

# 保存日誌
agent.save_logs("logs.json")

使用 MCP 伺服器上的工具

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
import asyncio
import akasha
from langchain_mcp_adapters.client import MultiServerMCPClient

MODEL = "openai:gpt-4o"

# 定義 MCP 伺服器連接資訊
connection_info = {
"math": {
"command": "python",
"args": ["cal_server.py"],
"transport": "stdio",
},
"weather": {
"url": "http://localhost:8000/sse",
"transport": "sse",
},
}
prompt = "tell me the weather in Taipei"

# 使用 MCP 工具
agent = akasha.agents(
model=MODEL,
temperature=1.0,
verbose=True,
keep_logs=True,
)
# 問問題並使用 MCP 工具回答
response = agent.mcp_agent(connection_info, prompt)
# 保存日誌
agent.save_logs("logs_agent.json")


agents 參數

初始化參數

tools: List[BaseTool]

工具列表,可以是自定義工具或內建工具。

model: str

使用的語言模型,例如 "openai:gpt-4o""openai:gpt-3.5-turbo"

temperature: float

語言模型的隨機性參數,範圍為 0.0 到 1.0。

max_input_tokens: int

單次輸入模型的最大 token 數。

max_output_tokens: int

模型輸出的最大 token 數。

max_round: int

多輪對話的最大輪數。

max_past_observation: int

發送給模型的過去觀察數量。

prompt_format_type: str

提示格式類型,例如 "auto""gpt""llama"

retri_observation: bool

是否啟用觀察檢索。

keep_logs: bool

是否保存執行過程與結果的日誌。

verbose: bool

是否顯示詳細的執行過程。

stream: bool

是否啟用流式輸出。


call 參數

question: str

使用者的問題。

messages: List[dict]

需要一併提供給語言模型的對話紀錄。


日誌與結果

  • 執行過程與結果會保存到指定的日誌文件中。
  • 日誌包括工具使用情況、語言模型的輸入輸出 token 數等。

相關連結

call_stream_model

在輔助函數中,若LLM模型為若為openai, huggingface, remote, gemini, anthropic類模型,可以使用akasha.call_stream_model()來得到流輸出

1
2
3
4
5
6
7
8
9
10

import akasha
import akasha.helper as ah
prompt = "say something."
model_obj = ah.handle_model("openai:gpt-3.5-turbo", False, 0.0)
streaming = ah.call_stream_model(model_obj, prompt)

for s in streaming:
print(s)

RAG stream

RAG, ask, summary class的函式皆可使用參數stream=True來得到流輸出

1
2
3
4
5
6
7
8
import akasha

ak = akasha.RAG(stream=True)

streaming = ak("docs/mic", "say something")

for s in streaming:
print(s)

Stream Output

要在網頁上或API中使用流輸出(及時一個字一個字輸出語言模型回答)時,若為openai, huggingface, remote, gemini, anthropic 類模型,可以使用model_obj.stream(prompt),以下為streamlit write_stream在網頁上即時輸出回答為範例

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
34
35
36
37
import streamlit as st
import akasha
import akasha.helper as ah
import gc, torch

if "pre" not in st.session_state:
st.session_state.pre = ""
if "model_obj" not in st.session_state:
st.session_state.model_obj = None

def clean():
try:
gc.collect()
torch.cuda.ipc_collect()
torch.cuda.empty_cache()
except:
pass



def stream_response(prompt:str, model_name:str="openai:gpt-3.5-turbo"):
# Mistral-7B-Instruct-v0.3 Llama3-8B-Chinese-Chat
streaming = ah.call_stream_model(st.session_state.model_obj, prompt)
yield from streaming

model = st.selectbox("select model", ["openai:gpt-3.5-turbo","hf:model/Mistral-7B-Instruct-v0.3"])
prompt = st.chat_input("Say something")
if st.session_state.pre != model:
st.session_state.model_obj = None
clean()
st.session_state.model_obj = akasha.helper.handle_model(model, False, 0.0)
st.session_state.pre = model

if prompt:
st.write("question: " + prompt)
st.write_stream(stream_response(prompt, model))

使用model_obj = akasha.helper.handle_model(model, False, 0.0)建立模型物件,當要使用推論時,使用akasha.helper.call_stream_model(model_obj, prompt)進行推論,可使用yield讓stream_response函式回傳generator, 便可即時輸出回答。

API 使用手冊

akasha 提供了一個 RESTful API 伺服器,允許使用者通過 HTTP 請求來調用其核心功能,包括摘要 (summary)、文件檢索與生成 (RAG)、提問 (ask)、以及網頁搜尋 (websearch)。


啟動 API 伺服器

在終端啟動 API 伺服器:

1
akasha api -p 8000 -h 127.0.0.1
  • -p:指定伺服器的埠號(預設為 8000)。
  • -h:指定伺服器的主機地址(預設為 127.0.0.1)。

API 功能

1. 提問 (/ask)

使用語言模型回答問題,並可基於提供的內容進行回答。

範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests

ask_data = {
"prompt": "太陽能電池技術?",
"info": "太陽能電池技術5塊錢",
"model": "openai:gpt-3.5-turbo",
"system_prompt": "",
"temperature": 0.0,
"env_config": {
"OPENAI_API_KEY": "your_openai_key",
},
}

response = requests.post("http://127.0.0.1:8000/ask", json=ask_data).json()
print(response)
請求參數
  • prompt: 使用者的問題。
  • info: 提供的內容,可以是文字、文件路徑或網址。
  • model: 使用的語言模型,例如 "openai:gpt-3.5-turbo"
  • system_prompt: 指示語言模型的輸出格式需求。
  • temperature: 語言模型的隨機性參數。
  • env_config: 環境變數配置,例如 API 金鑰。

2. 文件檢索與生成 (/RAG)

基於提供的文件資料來源,檢索相關內容並生成回答。

範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
rag_data = {
"data_source": "docs/mic/",
"prompt": "工業4.0",
"chunk_size": 1000,
"model": "openai:gpt-3.5-turbo",
"embedding_model": "openai:text-embedding-ada-002",
"threshold": 0.1,
"search_type": "auto",
"system_prompt": "",
"max_input_tokens": 3000,
"temperature": 0.0,
"env_config": {
"OPENAI_API_KEY": "your_openai_key",
},
}

response = requests.post("http://127.0.0.1:8000/RAG", json=rag_data).json()
print(response)
請求參數
  • data_source: 文件資料來源,可以是目錄或文件路徑。
  • prompt: 使用者的問題。
  • chunk_size: 文件分塊大小。
  • model: 使用的語言模型。
  • embedding_model: 使用的嵌入模型。
  • threshold: 檢索的相似性閾值。
  • search_type: 檢索類型,例如 "auto"
  • system_prompt: 指示語言模型的輸出格式需求。
  • max_input_tokens: 單次輸入的最大 token 數。
  • temperature: 語言模型的隨機性參數。
  • env_config: 環境變數配置。

3. 摘要 (/summary)

對提供的內容進行摘要,支援多種摘要方法。

範例
1
2
3
4
5
6
7
8
9
10
11
12
13
summary_data = {
"content": "docs/2.pdf",
"model": "openai:gpt-3.5-turbo",
"summary_type": "reduce_map",
"summary_len": 500,
"system_prompt": "用中文做500字摘要",
"env_config": {
"OPENAI_API_KEY": "your_openai_key",
},
}

response = requests.post("http://127.0.0.1:8000/summary", json=summary_data).json()
print(response)
請求參數
  • content: 需要摘要的內容,可以是文件路徑、網址或純文字。
  • summary_type: 摘要方法,例如 "map_reduce""refine"
  • summary_len: 摘要的建議長度。
  • model: 使用的語言模型。
  • system_prompt: 指示語言模型的輸出格式需求。
  • env_config: 環境變數配置。

4. 網頁搜尋 (/websearch)

使用搜尋引擎搜尋問題相關的資訊,並使用語言模型整合回答。

範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
websearch_data = {
"prompt": "太陽能電池技術?",
"model": "openai:gpt-3.5-turbo",
"system_prompt": "",
"temperature": 0.0,
"env_config": {
"SERPER_API_KEY": "your_serper_key",
},
"search_engine": "serper",
"search_num": 5,
}

response = requests.post("http://127.0.0.1:8000/websearch", json=websearch_data).json()
print(response)
請求參數
  • prompt: 使用者的問題。
  • model: 使用的語言模型。
  • system_prompt: 指示語言模型的輸出格式需求。
  • temperature: 語言模型的隨機性參數。
  • search_engine: 搜尋引擎,例如 "serper""brave""wiki"
  • search_num: 搜尋結果的數量。
  • env_config: 環境變數配置。

環境變數配置

在請求中可以通過 env_config 傳遞環境變數,例如:

1
2
3
4
5
{
"OPENAI_API_KEY": "your_openai_key",
"SERPER_API_KEY": "your_serper_key",
"BRAVE_API_KEY": "your_brave_key"
}

API 返回格式

所有 API 返回的 JSON 格式如下:

1
2
3
4
5
6
7
8
9
{
"response": "回答內容或摘要",
"status": "success 或 fail",
"logs": {
"執行過程的詳細日誌"
},
"timestamp": "執行時間戳",
"warnings": ["警告信息"]
}

相關連結

  • 文件搜尋
  • 設定語言模型

自查詢(Self Query)

自查詢是指能夠自我查詢的檢索問題方法。透過結構化、包含metadata的文件集,能將使用者的問題先透過metadata進行篩選,再藉由向量來查詢語意相似的文檔,比起直接做向量查詢能更精確的找到需要的文件。

流程

自查詢的流程為

0. create metadata

添加結構化資料到文件集與向量資料庫中

1. query constructor

將使用者問題轉換成 query(用來做向量查詢的字串)與filter(用來篩選文件集的metatada keywords)
例如,使用者問題為: A公司在2024年對電動車的銷售量為多少?

透過語言模型 將其轉換為

1
2
3
4
{
"query": "電動車的銷售量",
"filter": "and(eq(\"公司名稱\", \"A公司\"), eq(\"日期年\", \"2024\"))"
}

2. filter translator

將filter處理為程式可執行的dictionary

3. filter docs

根據filter篩選需要的文件集

1
2
3
{'filter': {'$and': [{'拜訪年': {'$eq': '2024'}}, {'公司名稱': {'$eq': 'A公司'}}]}}


從篩選出來的文件集做向量相似度搜尋



範例

1. load db from data source and add metadata to db

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

import akasha.utils.db as adb
import akasha.helper as ah
data_source = ["docs/pns_query_small"]
embed_name = "openai:text-embedding-3-small"
chunk_size = 1000
db, ignore_files = adb.process_db(
data_source=data_source, embeddings=embed_name, chunk_size=chunk_size, verbose=True
)


### you should create your own metadata function to add metadata for every text chunks in the db ###
### in this example, we use the source(file name) of the text chunk to map text chunks and metadatas ###
def add_metadata(db: adb.dbs):
"""this function is used to add metadata to the old_db object.

Args:
old_db (adb.dbs):

Returns:
(adb.dbs):
"""
import json
from pathlib import Path

for metadata in db.metadatas:
file_path = metadata["source"] # source is the file path
try:
with Path(file_path).open("r", encoding="utf-8") as file:
dictionary = json.load(file)

# dictionary = helper.extract_json(text)
metadata["課別"] = dictionary["課別"]
metadata["業務擔當"] = dictionary["業務擔當"]
ddate = dictionary["拜訪日期"]
metadata["拜訪年"] = int(ddate.split("-")[0])
metadata["拜訪月"] = int(ddate.split("-")[1])
metadata["產品"] = dictionary["產品"]
metadata["公司名稱"] = dictionary["公司名稱"]
metadata["大分類"] = dictionary["大分類"]
metadata["中分類"] = dictionary["中分類"]
except Exception as e:
print(f"JSONDecodeError: {e}")
return


add_metadata(db)
adb.update_db(db, data_source, embed_name, chunk_size=chunk_size)


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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import akasha.utils.db as adb
import akasha.helper as ah
from akasha.utils.search.retrievers.base import get_retrivers
import akasha

db, ignore_files = adb.process_db(
data_source=data_source, embeddings=embed_name, chunk_size=chunk_size, verbose=True
)
prompt = "A公司在2024年對電動車的銷售量為多少?"
search_type = "knn"
model_obj = ah.handle_model("openai:gpt-4o", True)


## each metadata attribute should include name, description and type(integer, float, string) ##
metadata_field_info = [
{"name": "拜訪年", "description": "此訪談紀錄的拜訪年份", "type": "integer"},
{"name": "拜訪月", "description": "此訪談紀錄的拜訪月份", "type": "integer"},
{"name": "業務擔當", "description": "業務的名稱", "type": "string"},
{"name": "中分類", "description": "訪談產品的中等分類", "type": "string"},
{"name": "公司名稱", "description": "訪談對象的公司名稱", "type": "string"},
{"name": "大分類", "description": "訪談產品的大分類", "type": "string"},
{"name": "產品", "description": "訪談的產品名稱/型號", "type": "string"},
{"name": "課別", "description": "公司部門的課別名稱或代號", "type": "string"},
]

document_content_description = "業務與客戶的訪談紀錄"

####################


### use self-query to filter docs
new_dbs, query, matched_fields = ah.self_query(
prompt, model_obj, db, metadata_field_info, document_content_description
)

### option1 use knn similarity search to sort docs from filtered docs

retriver = get_retrivers(new_dbs, embed_name, threshold=0.0, search_type=search_type)[0]

docs, scores = retriver.get_relevant_documents_and_scores(query)
print(docs)

### option2 use new_dbs(filtered docs) to run other akasha functions


ak = akasha.RAG(
model=model_obj,
embeddings=embed_name,
)
resposne = ak(data_source=new_dbs, prompt=prompt)



自訂parser函式

若您使用的語言模型回答無法使用預設的parser找出query與filter,可以自訂一個parser函式,輸入為語言模型的回答(string),輸出為[query(string), filter(dictionary)]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import akasha.utils.db as adb
import akasha.helper as ah
import json
def just_an_example(input_text: str):
# input_text :
#```json
#{
# "query": "產品疑慮",
# "filter": "and(eq(\"公司名稱\", \"a公司\"), eq(\"拜訪年\", \"2024\"))"
#}
#```

jstr = '{"$and": [{"公司名稱": {"$eq": "a公司"}}, {"拜訪年": {"$eq": "2024"}}]}'
dic = json.loads(jstr)
return "產品疑慮", dic

### use self-query to filter docs
new_dbs, query, matched_fields = ah.self_query(
prompt, model_obj, db, metadata_field_info,
document_content_description, just_an_example)



loose filter

使用參數 loose_filter=True會將filter中的$and替換成$or,只要文件有符合任意attribute便會選取

1
2
3
4
5
6
7
8
import akasha.utils.db as adb
import akasha.helper as ah
### use self-query to filter docs
## filter become '{"$or": [{"公司名稱": {"$eq": "a公司"}}, {"拜訪年": {"$eq": "2024"}}]}'
new_dbs, query, matched_fields = ah.self_query(
prompt, model_obj, db, metadata_field_info,
document_content_description, loose_filter = True)