[LangChain-01] RAG實戰第一站

ChunJen Wang
jimmy-wang
Published in
7 min readFeb 24, 2024

透過製作筆記過程,加深學習記憶。

適合閱讀此篇筆記的人:沒有接觸過RAG或LLM的開發人員。

Source: https://python.langchain.com/docs/use_cases/question_answering/

RAG 檢索增強生成

RAG是利用額外資料來增強 LLM 知識的技術。
額外資料可以是:

  1. 公司內部的文件、手冊。
  2. 外部公開的資料庫,如法規條文、財報資訊。
  3. Google搜尋結果 (透過API)。
  4. DB Schema

金融業使用RAG原因,通常為資安、個資與機密資料保護,而採取的解決方式
RAG檢索的資料可以留存於地端。

RAG的步驟(官方文件說明):

  • RAG主要步驟左圖,進行檢索(查詢),將檢索到的資料,連同一開始的問題一起丟給LLM進行回答。
  • 右圖檢索資料前處理,讀取各種格式資料,將讀取的資料切成一小段一小段的文本資料,進行embedding,儲存到向量資料庫。

動手試試

官方sample code

import os

# for LLM model
os.environ["OPENAI_API_KEY"] = "填入你的OpenAI API KEY"

# for langSmith (可以不使用)
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "填入你的LangSmith API KEY(非必要)"

import bs4
from langchain import hub
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

# 讀取資料,轉為向量儲存
loader = WebBaseLoader(
web_path=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
bs_kwargs=dict(
parse_only=bs4.SoupStrainer(
class_=("post-content", "post-title", "post-header")
)
)
)

docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
print('完成向量化')


# 進行檢索與生成
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
print("完成建立RAG")

result = rag_chain.invoke("What is Task Decomposition? 請用繁體中文回答。")
print(result)

Output:

如有設定LangSmith,可以更容易檢視背後運作的資料流與耗時成本

其中map:key:context為在這個input問題下,
參考了哪一段文字來讓LLM思考如何回答問題。

而我們可以看最後丟給OpenAI處理的Prompt有完整的格式,
請GPT扮演QA助手,要依據參考資料(Context)來回答問題(Question)。

嗯? 這個prompt格式從哪裡來的?
Ans: https://smith.langchain.com/hub/rlm/rag-prompt?organizationId=ab4ba6d8-e630-52fc-9341-901fea3e9907

一個在資料前處理的重點回顧:

當要檢索的文本太長怎麼辦?

切分資料!

我們在使用gpt-3.5的API目前仍需要考量文本長度,因此會需要在前處理時分割文本成等長的文字段落。完整的解答可以參考官網的步驟解說:

以上是一個最小的RAG使用範例。感謝閱讀~

--

--

ChunJen Wang
jimmy-wang

嗨,歡迎你的到來,我目前在銀行擔任DS。過去曾做過銀行大型專案BA,也曾在轉職科技業DE中踢了鐵板,相信每一個人都有自己要走的路,而努力的過程,可以讓我們離心中理想更接近,如果我的文章能帶給你一些啟發與幫助,別忘了幫我在文章底下按下拍手~^^