打造客製化的 Chatbot:從 RAG 到 Langchain Agent 的實作

更新於 2024/08/22閱讀時間約 2 分鐘

自從 ChatGPT 開始熱門以來,許多企業也都開始想打造自己的chatbot 來服務客戶,求職市場上也開始多了像是LLM engineer 甚至 chatbot engineer/trainer/manager 等等的職位。



透過LLM 打造chatbot 並且讓LLM 能回覆一些自己公司內部的資訊,其實除了insert資訊以及呼叫 LLM API 之外還有很多其他 preprocess, postprocess的配套措施需要客製化開發,比如insert的資料有大量影像甚至影片或是database裡很多張的table、LLM output 的回應如何客製化產品資訊連結、圖像說明,等等的

不過撇除那些繁雜的前、後處理,打造客製化且能隨時更新資訊的chatbot 基本上可以透過 RAG 以及 agent 來達成。

以下介紹如何透過Langchain agent打造一個有檢索功能以及search功能的chatbot




Retrieval Augmented Generation(RAG)


當我們希望LLM額外學會的資訊(e.g. 企業內部資訊、FAQ,...) 的文本長度太長時,我們沒辦法把他們全部寫進去prompt裡(input token limit),這時我們需要透過 RAG 來讓LLM 進行檢索。

我覺得下面這張圖說明的很清楚

Gao, Yunfan et al. “Retrieval-Augmented Generation for Large Language Models: A Survey.” (2023).

Gao, Yunfan et al. “Retrieval-Augmented Generation for Large Language Models: A Survey.” (2023).

我們從右上角的 indexing 區塊開始看,首先我們準備好要讓LLM 額外具備的知識的文本 Documents,然後把這份長文本切成很多chunks後轉換成embeddings存放在vectorstore。

接下來當 User Query的句子進來之後,我們一樣把query 給embedding,然後在vectorstore裡進行向量相似度計算找到最接近的k個chunks,然後我們將這些chunks的原文 insert 進去 prompt 裡讓LLM具備相關知識來回答 User 的問題。


概念蠻好理解的,但實際上其實還有很多可以改進的做法,在 Retrieval-Augmented Generation for Large Language Models: A Survey 這篇論文裡有講到很多做法,如果基本的RAG沒有辦法滿足需求,可以參考看看。


接下來來看一下如何在Langchain 上搞出一個RAG。假設我要檢索的文本是這份中華民國民法的PDF,總共有171頁。

廢話不多說 直接上code (我是用 langchain 0.2.11)

from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.chains import RetrievalQA, create_retrieval_chain
from langchain.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain


system_prompt = (
"You are an assistant for question-answering tasks. "
"Use the following pieces of retrieved context to answer "
"the question. If you don't know the answer, say that you "
"don't know. Use three sentences maximum and keep the "
"answer concise."
"\n\n"
"{context}"
)

rag_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", "{input}"),
]
)

def get_qa_chain(pdf_path):
# read file
loader = PyPDFLoader(pdf_path)
documents = loader.load()

# split your docs into texts chunks
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
texts = text_splitter.split_documents(documents)

# embed the chunks into vectorstore (FAISS)
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(texts, embeddings)

# create retriever and rag chain
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
question_answer_chain = create_stuff_documents_chain(llm=ChatOpenAI(model_name='gpt-4o-mini', temperature=0),
prompt=rag_prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)

return rag_chain

rag_chain = get_qa_chain('民法.pdf')

基本上只是按照官方的 tutorials 複製貼上而已XD

可以看到langchain已經包裝好很多東西了,包含 load pdf, embedding, vectorstore, vector search, 串接LLM,光想到這些要自己刻就累了💦

這邊我使用openAI的 gpt-4o, 所以也要記得把你的 token設定到環境變數。

那就來看看rag_chain的對話狀況吧:

raw-image

看起來還行,另外我們也看以查看 result['context'] 來看 rag 檢索到的最相近的k個chunk的內容為何。


你會發現,不論你問什麼問題,他都會去檢索然後產生回應,即使你只是打聲招呼。這時我們會想,如果他可以自己判斷該問題要不要檢索,根據不同問題執行不同的功能,這就是agent的概念了。



Agent


我們現在有個目標是讓 LLM 自己判斷該client的問題要不要檢索,並且根據不同問題執行不同的功能。

我們可以自己另外架一個LLM來完成這件事,也就是像下面這張圖,用兩個LLM來達成,綠色的LLM來判斷 client question要用哪個tool(RAG, google search or no need),然後執行tool取得資訊,再把資訊塞進去藍色LLM的prompt裡叫他要利用這些資訊來產生回覆給 client

自行實作出 agent 可能的流程

自行實作出 agent 可能的流程


我們也可以透過Langchain的agent 來完成這件事

這部分我覺得各有好壞,自己刻不複雜,就透過prompt engineer來讓LLM判斷使用哪個tool,而透過langchian agent 可以用更少的力氣完成,但缺點就是會變得比較複雜一點不容易debug而且 langchain 版本不斷更新還有指令的應用也一直在修正。


但我有點懶得寫太多,所以還是直接用langchain來實作 agent吧XD


這邊設我除了上一段檢索的 rag_chain 外,我還想給agent google search的能力,也就是說我會給agent兩個tools: rag 來檢索民法、google search。

rag_chain我們在上一段一經完成了,而google search的功能我們透過searchAPI 來完成,這邊我使用 Serper,到 Serper官網 註冊就能取得token,且有 2500次 free queries。而langchain也有GoogleSerperAPIWrapper 來協助我們只用一行實現他XD

from langchain_community.utilities import GoogleSerperAPIWrapper
search = GoogleSerperAPIWrapper()


簡單來測試看看search的功能:

raw-image

好的 search 可以幫我們進行google search並把查到的內容已字串方式給我們

把 rag_chain 和 search 一起包成tool

from langchain.agents import Tool, AgentExecutor, create_react_agent

tools = [
Tool(
name="RAG Legal",
func=rag_chain.invoke,
description="Useful when you're asked legal-related questions"
),
Tool(
name="Google Search",
description="For answering questions that are not related to legal or when you don't know the answer, use Google search to find the answer",
func=search.run,
)
]

這邊 tool 的 description 就是LLM 判斷問題要使用哪個tool的依據,所以依照你的需求盡量把description描述清楚。


接著我們設計一個prompt 來限制 agent的思考方式,最終產出我們要的回覆:

character_prompt = """Answer the following questions as best you can. You have access to the following tools:
{tools}

For any questions requiring tools, you should first search the provided knowledge base. If you don't find relevant information from provided knowledge base, then use Google search to find related information.

To use a tool, you MUST use the following format:
1. Thought: Do I need to use a tool? Yes
2. Action: the action to take, should be one of [{tool_names}]
3. Action Input: the input to the action
4. Observation: the result of the action

When you have a response to say to the Human, or if you do not need to use a tool, you MUST use the following format:
1. Thought: Do I need to use a tool? No
2. Final Answer: [your response here]

It's very important to always include the 'Thought' before any 'Action' or 'Final Answer'. Ensure your output strictly follows the formats above.

Begin!

Previous conversation history:
{chat_history}

Question: {input}
Thought: {agent_scratchpad}
"""


大家可能會想說我怎麼生出上面這段 prompt的,你可以在 langchain的 prompt hub 找到一些範例然後來進行一些修改:

from langchain import hub
hub.pull("hwchase17/react")


接著就使用 create_react_agent 把tool, prompt 包成agent,然後使用AgentExecutor 來執行agent產生回覆吧,這邊我也順手把memory的功能也加進去:

from langchain.prompts.prompt import PromptTemplate
from langchain.chains.conversation.memory import ConversationBufferWindowMemory

chat_model = ChatOpenAI(model_name='gpt-4',
temperature=0,
streaming=True,
verbose=True,
max_tokens=1024,
)

prompt = PromptTemplate.from_template(character_prompt)
agent = create_react_agent(chat_model, tools, prompt)

memory = ConversationBufferWindowMemory(memory_key='chat_history', k=5, return_messages=True, output_key="output")
agent_chain = AgentExecutor(agent=agent,
tools=tools,
memory=memory,
max_iterations=5,
handle_parsing_errors=True,
verbose=True,
)


這個agent_chain 就可以拿來進行對話啦,當user input question後,他會去判斷是否要用tool,要用哪個tool,執行action 得到tool的回應後觀察看是否有足夠的資訊了,如果有,就根據蒐集到的資訊產生回覆,如果沒有,就會繼續執行action直到max_iteration。

這邊其實很容易遭遇到一個問題,就是LLM沒有按照我們prompt裡要求他回應的格式來產生回覆,就會產生 LLM parse error,你就會發現他明明已經搜集到足以回答問題的資訊了,卻沒辦法拿來回答,這裡我嘗試用prompt engineering來減緩,可以看到上面我在prompt裡不斷強調 you MUST use the following formatIt's very important to always include the 'Thought' before any 'Action' or 'Final Answer'. Ensure your output strictly follows the formats above.

然後我也使用到了 gpt-4,因為我發現越大的模型越能夠follow我們的 prompt instruct。

那最後就來看看agent_chain的對話結果吧

raw-image
raw-image
raw-image
raw-image
raw-image


看起來回應的還不錯~套上一些前端的開發就能在網頁上跟這個聊天機器人互動了

最後我把這個 agent 整理成以下的流程圖,相信是一個在很多地方能使用到的chatbot架構,只要把RAG檢索的知識庫換成你自己的東西就好。

raw-image



Reference


RAG (Retrieval Augmented Generation): 為自然語言處理揭開新篇章

Develop a large language model application using Langchain

Retrieval-Augmented Generation for Large Language Models: A Survey





avatar-img
1會員
3內容數
hello
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Henry的沙龍 的其他內容
sorry 這是一篇廢文💩
Use BERT to get sentence embedding and fine-tune downstream tasks, as well as discussing sentence similarity for clustering or intention matching.
sorry 這是一篇廢文💩
Use BERT to get sentence embedding and fine-tune downstream tasks, as well as discussing sentence similarity for clustering or intention matching.
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
「台速生科企業有限公司」的總經理陳鴻鳴先生,在創業初期的主要挑戰是在植物領域知識方面;而客戶的質疑成為他學習的動力,進而開始深入研究農業行業和肥料技術。透過不懈的努力和與農民的互動,他逐漸掌握了專業知識,並開發了專注於不同作物需求的精確肥料配方。
Thumbnail
「好睡王家居」獨家代理比利時百年名床「NILL SPRING尼絲普林」,就連歐洲皇室貴族也喜歡!多款設計款床架、沙發、茶几、床頭櫃、枕頭任您體驗,舒服到不想回家!為確保居家健康安全,產品皆通過多項品質安全檢驗認證,不含甲醛、重金屬等有害成份。專業的設計師一同規劃全屋裝潢需求,打造理想的家居空間!
住宜蘭的親戚想為自家打造個漂亮的庭院,問我有沒有好評價的宜蘭園藝推薦?幫忙問了一些和建築設計有淵源的朋友,友人推薦宜蘭國瑞園藝景觀設計工程,服務範圍涵蓋宜蘭的三星、羅東、五結、冬山、大同、員山和壯圍等地,深耕在地的宜蘭園藝專家在網路上獲得許多乘作客戶的五星好評,提供庭園景觀設計施工、園藝造景造園
Thumbnail
本文將深入探討店面裝潢設計,花卉藝術的奧妙,藝術裝飾品的應用,以及婚紗禮服的華麗巧思和實用攻略,如靈活運用婚紗禮服。新人可從中獲得豐富靈感,為婚禮打造獨特空間饗宴,展現個性美學。
Thumbnail
在現今競爭激烈的市場環境中,舉辦一個成功的活動對於企業和組織來說至關重要。然而,每個活動的目標、風格和需求都是獨特的。為了確保活動能夠真正擄獲目標受眾的心,客製化活動策劃服務應運而生。這種服務不僅能夠根據客戶的需求量身打造獨特活動,還能提供專業的建議和全方位的支持。本文將深入探討客製化活動策劃服務的
客製化衣服,這個概念近年來在時尚界備受關注,成為越來越多人的首選。無論是團體服、工作服、班服,或是西裝,客製化衣服都為我們提供了一個獨特的方式來表現個人風格和滿足特定需求。讓我們深入探討客製化衣服的魅力,以及它們在不同場合的應用。 客製化衣服最吸引人的一點在於其獨特性。當我們走進傳統的衣物店,
Thumbnail
【李婉如/ 報導】少子化海嘯中111學年度台北城市科大企管系逆勢成長,在雙北私立科大企管系中註冊率為第二名,在112學年度技職統測「甄選入學」一階篩選公告前,台北城市科技大學企管系有別於其他學校制式化、固定化的新生說明會,特別為每位新生舉辦客製化、專屬化的新生說明會,即日起到八月十五日止,周一到周日
Thumbnail
辦公室是現代人生活中不可或缺的一部分,而辦公椅則是辦公室中最重要的工具之一,一張好的辦公椅能夠為你提供良好的工作體驗,提高工作效率,然而,市場上的辦公椅大多是標準化設計,可能無法完全滿足你的個性化需求,台灣好椅提供客製化改裝服務,為你打造一張專屬的辦公椅,讓你的工作空間更舒適、更健康。
Thumbnail
文、圖/開必拓(Kapito)提供   智慧製造 AI 新創開必拓(Kapito)今(6)日宣布,旗下的軟硬整合AI 品檢解決方案 fastable.ai,已完成電極鋁箔產線的客製化,且協助電蝕與化成箔大廠立敦科技完成台灣全產線佈署,運用 AI 影像辨識技術,有效提升立敦科技產線的品質與效率,
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
「台速生科企業有限公司」的總經理陳鴻鳴先生,在創業初期的主要挑戰是在植物領域知識方面;而客戶的質疑成為他學習的動力,進而開始深入研究農業行業和肥料技術。透過不懈的努力和與農民的互動,他逐漸掌握了專業知識,並開發了專注於不同作物需求的精確肥料配方。
Thumbnail
「好睡王家居」獨家代理比利時百年名床「NILL SPRING尼絲普林」,就連歐洲皇室貴族也喜歡!多款設計款床架、沙發、茶几、床頭櫃、枕頭任您體驗,舒服到不想回家!為確保居家健康安全,產品皆通過多項品質安全檢驗認證,不含甲醛、重金屬等有害成份。專業的設計師一同規劃全屋裝潢需求,打造理想的家居空間!
住宜蘭的親戚想為自家打造個漂亮的庭院,問我有沒有好評價的宜蘭園藝推薦?幫忙問了一些和建築設計有淵源的朋友,友人推薦宜蘭國瑞園藝景觀設計工程,服務範圍涵蓋宜蘭的三星、羅東、五結、冬山、大同、員山和壯圍等地,深耕在地的宜蘭園藝專家在網路上獲得許多乘作客戶的五星好評,提供庭園景觀設計施工、園藝造景造園
Thumbnail
本文將深入探討店面裝潢設計,花卉藝術的奧妙,藝術裝飾品的應用,以及婚紗禮服的華麗巧思和實用攻略,如靈活運用婚紗禮服。新人可從中獲得豐富靈感,為婚禮打造獨特空間饗宴,展現個性美學。
Thumbnail
在現今競爭激烈的市場環境中,舉辦一個成功的活動對於企業和組織來說至關重要。然而,每個活動的目標、風格和需求都是獨特的。為了確保活動能夠真正擄獲目標受眾的心,客製化活動策劃服務應運而生。這種服務不僅能夠根據客戶的需求量身打造獨特活動,還能提供專業的建議和全方位的支持。本文將深入探討客製化活動策劃服務的
客製化衣服,這個概念近年來在時尚界備受關注,成為越來越多人的首選。無論是團體服、工作服、班服,或是西裝,客製化衣服都為我們提供了一個獨特的方式來表現個人風格和滿足特定需求。讓我們深入探討客製化衣服的魅力,以及它們在不同場合的應用。 客製化衣服最吸引人的一點在於其獨特性。當我們走進傳統的衣物店,
Thumbnail
【李婉如/ 報導】少子化海嘯中111學年度台北城市科大企管系逆勢成長,在雙北私立科大企管系中註冊率為第二名,在112學年度技職統測「甄選入學」一階篩選公告前,台北城市科技大學企管系有別於其他學校制式化、固定化的新生說明會,特別為每位新生舉辦客製化、專屬化的新生說明會,即日起到八月十五日止,周一到周日
Thumbnail
辦公室是現代人生活中不可或缺的一部分,而辦公椅則是辦公室中最重要的工具之一,一張好的辦公椅能夠為你提供良好的工作體驗,提高工作效率,然而,市場上的辦公椅大多是標準化設計,可能無法完全滿足你的個性化需求,台灣好椅提供客製化改裝服務,為你打造一張專屬的辦公椅,讓你的工作空間更舒適、更健康。
Thumbnail
文、圖/開必拓(Kapito)提供   智慧製造 AI 新創開必拓(Kapito)今(6)日宣布,旗下的軟硬整合AI 品檢解決方案 fastable.ai,已完成電極鋁箔產線的客製化,且協助電蝕與化成箔大廠立敦科技完成台灣全產線佈署,運用 AI 影像辨識技術,有效提升立敦科技產線的品質與效率,