使用本地大語言模型和Langchain手搓免費的AI搜尋問答助手

Steven.Luo發表於2024-05-23

1 概述

大語言模型雖然已經有了很多的背景知識,但針對模型訓練之後新產生的內容,或者領域內的知識進行提問,大模型本身通常無法準確給出回應,一個常用的解決方法是,藉助檢索增強生成(RAG),將能夠用於回答問題的相關上下文給到大模型,利用大模型強大的理解和生成能力,來緩解這個問題。

本文主要介紹如何藉助搜尋引擎,獲取比較新的內容,並對這部分內容的問題進行回答。首先會簡單介紹原理,然後是環境準備,程式碼介紹,最後會透過Chainlit,構造一個完整的AI搜尋問答助手,完全免費。

本文所介紹方法,不需要使用付費大語言模型API,整個流程可以在一臺膝上型電腦上執行。

程式碼已開源,地址在:https://github.com/Steven-Luo/AISearchQA

最終效果如下:

可以看出,問到一些比較新的內容時,大模型也能結合網路搜尋結果給出準確的回答。

2 基本原理

本文所介紹內容,總體依然是RAG,下面是總體處理流程,此流程圖參考此處修改而來。

AI搜尋問答並非現去網際網路爬取資料,這樣會來不及處理,通常都是藉助搜尋引擎。從搜過引擎獲取到相關文件後,後續的所有流程,就跟一般的RAG完全一致了。

3 環境準備

3.1 作業系統

本文使用的所有元件、庫,在Windows、Linux、macOS上都可以安裝,理論上在這三個系統上都可以正常執行,但沒有對所有系統做相容性測試,下文以macOS 14.4 Sonoma系統,ARM系列晶片膝上型電腦的環境為例進行介紹。

3.2 Python環境準備

推薦使用Anaconda或者Miniconda準備Python環境,具體相容的Python版本沒有做完整測試,本文所使用的是Python 3.11.4。Python安裝完成後,安裝如下依賴包:

pip install -r requirements.txt

3.3 Ollama安裝及模型下載

Ollama是一個能夠在本地執行大語言模型的應用,可以直接在命令列中進行問答互動、或者使用相應的API(本文要用到的方式),以及使用第三方GUI工具,如Lobechat等。

Ollama官網下載並安裝對應作業系統的Ollama,Ollama詳細的安裝配置,請參考Ollama官網

3.3.1 模型下載

Ollama安裝好之後,在命令列中,執行如下兩條命令,下載相應的大語言模型和向量模型:

ollama pull qwen:7b
ollama pull znbang/bge:large-zh-v1.5-q8_0

在Ollama官方的Models頁面,提供了非常多支援的模型,如果對相關模型比較熟,可以根據機器的配置選擇更大或更小的模型。

下載完成後,執行如下命令,進行二次確認,確保下圖中框選的部分在列表中:

ollama list

使用如下命令,檢查大語言模型是否可以正常工作:

ollama run qwen:7b

如果輸出如上圖所示內容,則說明大語言模型工作正常。輸入/exit退出問答介面。

3.3.2 使用API

3.3.2.1 大語言模型

如果是依照本文,在本機安裝Ollama,執行如下Python程式碼:

from langchain_community.llms.ollama import Ollama

model_name = 'qwen:7b'
model = Ollama(base_url='http://localhost:11434', model=model_name)

print(model('你是誰'))

如果輸出如下內容,則表示API呼叫正常:

我是阿里雲研發的大規模語言模型,我叫通義千問。

如果Ollama安裝在其他機器,替換上述程式碼中的base_url

3.3.2.2 向量模型

類似大語言模型的部分,執行如下Python程式碼:

from langchain_community.embeddings import OllamaEmbeddings

embedding_model = OllamaEmbeddings(
    base_url='http://localhost:11434',
    model='znbang/bge:large-zh-v1.5-q8_0'
)
print(embedding_model.embed_query('你是誰'))

如果輸出類似如下內容,則表明向量模型API呼叫正常:

[0.8701383471488953, 0.926769495010376, ...

3.4 搜尋引擎API準備

許多搜尋引擎都有專門的API,只需要兩三行程式碼即可獲取結果,但有些需要複雜的申請流程,有些則不合規,本文使用Bing中文版網頁請求地址,藉助BeautifulSoup庫解析結果的方式,獲取Bing搜尋結果。

執行如下程式碼:

def search_with_bing(query):
    import requests
    from bs4 import BeautifulSoup
    from urllib.parse import quote 
    url = f'https://cn.bing.com/search?q={quote(query)}'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
    }
    resp = requests.get(url, headers=headers)
    soup = BeautifulSoup(resp.text, 'html.parser')
    
    result_elements = soup.select('#b_results > li')
    data = []

    for parent in result_elements:
        if parent.select_one('h2') is None:
            continue
        data.append({
            'title': parent.select_one('h2').text,
            'abstract': parent.select_one('div.b_caption > p').text.replace('\u2002', ' '),
            'link': parent.select_one('div.b_tpcn > a').get('href')
        })
    return data

search_with_bing('大語言模型')

如果結果類似如下所示,則表明執行成功:

[{'title': '什麼是LLM大語言模型?Large Language Model,從量變到質變',
  'abstract': '網頁2023年4月17日 · 大語言模型(英文:Large Language Model,縮寫LLM),也稱大型語言模型,是一種人工智慧模型,旨在理解和生成人類語言。. 它們在大量的文字資料上進行訓練,可以執行廣泛的任務,包括文字總結、翻譯、情感分析等等。. LLM的特點是 規模龐大,包含數十億的引數 ...',
  'link': 'https://zhuanlan.zhihu.com/p/622518771'},
 {'title': '什麼是大模型(LLMs)?一文讀懂大型語言模型(Large ...',
  'abstract': '網頁2 天之前 · 大模型是指具有大規模引數和複雜計算結構的機器學習模型。 這些模型通常由 深度神經網路 構建而成,擁有數十億甚至數千億個引數。 大模型的設計目的是為了提高模型的表達能力和預測效能,能夠處理更加複雜的任務和資料。 大模型在各種領域都有廣泛的應用,包括自然語言處理、計算機視覺、語音識別和 推薦系統 等。 大模型透過訓練海量資料 …',
  'link': 'https://www.aigc.cn/large-models'},
 {'title': '一文讀懂“大語言模型” - 知乎',
  'abstract': '網頁2023年7月17日 · 谷歌的 Gen AI 開發工具介紹. 2、大語言模型介紹. 2.1 大語言模型的定義. 大語言模型是深度學習的分支. 深度學習是機器學習的分支,大語言模型是深度學習的分支。 機器學習是人工智慧(AI)的一個子領域,它的核心是讓計算機系統能夠透過對資料的學習來提高效能。 在機器學習中,我們不是直接程式設計告訴計算機如何完成任務,而是提供大量 …',
  'link': 'https://zhuanlan.zhihu.com/p/644183721'},
...

4 主要流程

4.1 使用搜尋引擎檢索網際網路內容

使用上文提到的search_with_bing函式,直接呼叫即可

...
search_results = search_with_bing('大語言模型')
...

4.2 獲取網頁全文

此處簡潔起見,使用requests庫傳送GET請求,獲取網頁全文。

4.3 文件解析、切片、向量化及檢索

本文使用BeautifulSoup解析上文獲取到原始HTML對應的文字html。通常使用這種方式解析的HTML效果比較差,可以使用Jina Reader、Firecrawl等庫,獲得更高質量的解析結果。

...

soup = BeautifulSoup(html, 'html.parser')
item['body'] = soup.get_text()

...

下方的程式碼,會對文字進行切片,進行向量化,並使用query獲取檢索結果:

...
text_splitter = RecursiveCharacterTextSplitter(
    ["\n\n\n", "\n\n", "\n"],
    chunk_size=400,
    chunk_overlap=50
)
documents = [Document(
    item['body'],
    metadata={'href': item['href'], 'title': item['title']}
) for item in search_results.values()]
split_docs = text_splitter.split_documents(documents)
vectorstore = Chroma.from_documents(split_docs, embedding_model)
retriever = vectorstore.as_retriever(search_args={'k': 6})
retrieved_docs = retriever.get_relevant_documents(query)
context = '\n\n'.join([doc.page_content for doc in retrieved_docs])

4.4 Prompt構造

使用Prompt如下:

prompt = """請使用下方的上下文(<<<context>>><<</context>>>之間的部分)回答使用者問題,如果所提供的上下文不足以回答問題,請回答“我無法回答這個問題”
<<<context>>>
{context}
<<</context>>>

使用者提問:{query}
請回答:
""".format(query=query, context=context)

5執行

完整程式碼訪問https://github.com/Steven-Luo/AISearchQA獲取。

首先完成第3節中的環境準備,然後執行如下命令:

sh start.sh

出現類似如下的介面,表明啟動成功

相關文章