สร้าง RAG pipeline ด้วย langchain ใน 5 ขั้นตอน–ตัวอย่างการสร้างบ๊อตตอบคำถามเกี่ยวกับนโยบาย HR

RAG (Retrieval-Augmented Generation) เป็นเทคนิคที่ช่วยให้ LLM (large language model) ตอบคำถามได้แม่นยำขึ้น และไม่ถูกจำกัดด้วย knowledge cutoff หรือความรู้ที่จำกัดจากตอน train model

RAG ทำงานใน 2 ขั้นตอน:

  1. Retrieve: ดึงเอกสารที่เกี่ยวข้อง
  2. Generate: สร้างคำตอบจากเอกสารที่ได้มา

RAG มีข้อดี 3 ข้อ:

  1. คำตอบมีความแม่นยำมากขึ้น
  2. คำตอบมีความเกี่ยวข้องกับคำถามมากขึ้น
  3. ช่วยอัปเดตความรู้ให้กับ LLM ได้โดยไม่ต้อง train model ใหม่

ในบทความนี้ เราจะมาดูวิธีการสร้าง RAG pipeline ด้วย langchain ซึ่งเป็น framework ในการพัฒนาแอปพลิเคชัน LLM กัน

ถ้าพร้อมแล้ว ไปเริ่มกันเลย


  1. 🔆 High-Level View
  2. 📑 Step 1. Load Documents
  3. 📚 Step 2. Split Text
  4. 💾 Step 3. Embed & Store Chunks
  5. 🔎 Step 4. Create a Retriever
  6. 🤖 Step 5. Generate a Response
  7. 💪 Summary
  8. 😺 GitHub
  9. 📃 References

🔆 High-Level View

เราใช้ langchain สร้าง RAG pipeline ได้ใน 5 ขั้นตอน

  1. Load documents
  2. Split text
  3. Embed and store chunks
  4. Create a retriever
  5. Generate a response

เราไปดูการสร้าง RAG pipeline กับตัวอย่างบ็อตตอบคำถามเกี่ยวกับนโยบาย HR เช่น การลาและสวัสดิ กัน


📑 Step 1. Load Documents

ในขั้นแรก เราจะโหลดเอกสารที่เป็นข้อมูลของ RAG pipeline ก่อน

langchain มีหลาย functions สำหรับโหลดเอกสาร เช่น:

FunctionDocument
TextLoader()Text file
UnstructuredMarkdownLoader()Markdown file
CSVLoader()CSV file
JSONLoader()JSON file
PyPDFLoader()PDF file
DirectoryLoader()ไฟล์จากในโฟลเดอร์

ในตัวอย่าง เราจะใช้ DirectoryLoader() เพราะเราเก็บเอกสารไว้ในโฟลเดอร์ชื่อ documents:

documents/
├── benefits_policy.txt
├── compensation_policy.txt
├── leave_policy.txt
└── remote_work_policy.txt

ตัวอย่างข้อมูลในเอกสาร benefits_policy.txt:

DataWise Co. Benefits Policy
Full-time employees receive health insurance after completing probation.
The company provides annual health checkups once per year.
Employees can claim up to 2,000 THB per month for wellness activities such as fitness memberships, yoga classes, or mental health support.
Employees are also eligible for learning support. The company reimburses up to 10,000 THB per year for approved online courses, books, or professional certificates.

วิธีใช้ DirectoryLoader():

# Import packages
from langchain_community.document_loaders import DirectoryLoader
from langchain_community.document_loaders import TextLoader
# Initialise loader
loader = DirectoryLoader(
path="documents",
glob="*.txt",
loader_cls=TextLoader,
loader_kwargs={"encoding": "utf-8"}
)
# Load documents
docs = loader.load()

การใช้งาน DirectoryLoader():

  • path = โฟลเดอร์ที่ต้องการโหลด
  • glob = pattern ชื่อไฟล์ที่ต้องการโหลด (เช่น "*.txt" หมายถึง ไฟล์ที่ลงชื่อด้วย .txt ทั้งหมด)
  • loader_cls = function ที่จะใช้โหลด (เช่น TextLoader())
  • loader_kwargs = argument เพิ่มเติมสำหรับ function ที่จะใช้โหลด

เราสามารถดูตัวอย่างเอกสารที่โหลดแล้วได้แบบนี้:

# View loaded documents
for doc in docs:
print("=" * 50)
print(doc.metadata["source"])
print("=" * 50)
print(doc.page_content[:200])

ผลลัพธ์:

==================================================
documents/remote_work_policy.txt
==================================================
DataWise Co. Remote Work Policy
Employees may work from home up to 2 days per week.
Remote work must be approved by the employee's direct manager.
Employees must be reachable on Slack during core w
==================================================
documents/benefits_policy.txt
==================================================
DataWise Co. Benefits Policy
Full-time employees receive health insurance after completing probation.
The company provides annual health checkups once per year.
Employees can claim up to 2,000 THB
==================================================
documents/compensation_policy.txt
==================================================
DataWise Co. Compensation Policy
Salary is paid on the last working day of each month.
Performance bonuses are reviewed once per year in December.
Employees may receive an annual salary adjustment
==================================================
documents/leave_policy.txt
==================================================
DataWise Co. Leave Policy
Full-time employees receive 10 days of annual leave per year after completing probation.
Employees receive 15 days of paid sick leave per year.
Sick leave of 3 consecutive

📚 Step 2. Split Text

ในขั้นที่ 2 เราจะแบ่ง text ในเอกสารออกเป็นก้อน ๆ หรือ chunk เพราะการแบ่ง text จะช่วยให้การค้นหาข้อมูลง่ายขึ้น

langchain มี 3 functions หลักในการแบ่ง text:

FunctionMethod
CharacterTextSplitter()แบ่งตามจำนวน character ที่กำหนด
TokenTextSplitter()แบ่งตามจำนวน token ที่กำหนด
RecursiveCharacterTextSplitter()แบ่งตามย่อหน้า บรรทัด และประโยค

ในตัวอย่าง เราจะใช้ RecursiveCharacterTextSplitter() เพราะเป็นวิธีที่เก็บรักษาความหมายของ text ได้ดีกว่าวิธีอื่น:

วิธีใช้ RecursiveCharacterTextSplitter():

# Import package
from langchain_text_splitters import RecursiveCharacterTextSplitter
# Create splitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=100
)
# Split documents
chunks = text_splitter.split_documents(docs)

ดูตัวอย่าง text ที่แบ่งแล้วได้ตามนี้:

# View results
for i, chunk in enumerate(chunks[:5]):
print(f"Chunk {i+1}")
print("Source:", chunk.metadata["source"])
print(chunk.page_content)
print("-" * 50)

ผลลัพธ์:

Chunk 1
Source: documents/remote_work_policy.txt
DataWise Co. Remote Work Policy
Employees may work from home up to 2 days per week.
Remote work must be approved by the employee's direct manager.
Employees must be reachable on Slack during core working hours from 10:00 AM to 4:00 PM.
Employees working remotely are responsible for maintaining a stable internet connection and a quiet work environment.
New employees may request remote work only after completing their first month.
--------------------------------------------------
Chunk 2
Source: documents/benefits_policy.txt
DataWise Co. Benefits Policy
Full-time employees receive health insurance after completing probation.
The company provides annual health checkups once per year.
Employees can claim up to 2,000 THB per month for wellness activities such as fitness memberships, yoga classes, or mental health support.
Employees are also eligible for learning support. The company reimburses up to 10,000 THB per year for approved online courses, books, or professional certificates.
--------------------------------------------------
Chunk 3
Source: documents/compensation_policy.txt
DataWise Co. Compensation Policy
Salary is paid on the last working day of each month.
Performance bonuses are reviewed once per year in December.
Employees may receive an annual salary adjustment based on company performance, individual performance, and market benchmarks.
Overtime pay is available only for non-managerial employees and must be approved by a manager before the overtime work begins.
--------------------------------------------------
Chunk 4
Source: documents/leave_policy.txt
DataWise Co. Leave Policy
Full-time employees receive 10 days of annual leave per year after completing probation.
Employees receive 15 days of paid sick leave per year.
Sick leave of 3 consecutive days or more requires a medical certificate.
Employees should submit annual leave requests at least 7 days in advance through the HR system.
Unused annual leave can be carried over for up to 5 days into the next calendar year.
--------------------------------------------------

สังเกตว่า text ถูกแบ่งย่อหน้า ทำให้ chunk ที่ได้มีความหมายที่ครบถ้วนในตัวเอง


💾 Step 3. Embed & Store Chunks

ในขั้นที่ 3 เราจะ embed และเก็บข้อมูลลงใน vector database

Embedding คือ การแปลง chunk ให้กลายเป็น vector คือ ชุดตัวเลขที่เป็นตัวแทนของ chunk

ตัวอย่าง chunk:

"Employees can work from home up to two days per week."

ตัวอย่าง vector:

[
0.021,
-0.184,
0.736,
0.094,
-0.511,
0.302,
0.087,
-0.624
]

Vector เป็นสิ่งที่ระบบจะใช้ในการค้นหาเอกสารที่เกี่ยวข้อง โดย vector ที่มีความหมายใกล้เคียงกัน จะมีตัวเลขที่ใกล้เคียงกัน เมื่อเราต้องการหาเอกสาร ระบบจะดึงเอกสารที่มี vector ใกล้เคียงกับคำถามของเราขึ้นมาให้

ใน langchain เราสามารถเลือก model ที่จะใช้ embedding ได้ ในตัวอย่าง เราจะใช้ Gemini กัน:

# Import packages
import os
from langchain_google_genai import GoogleGenerativeAIEmbeddings
# Get API key
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
# Create embedder
document_embedder = GoogleGenerativeAIEmbeddings(
model="gemini-embedding-001",
task_type="retrieval_document",
google_api_key=GEMINI_API_KEY
)

หลังจากได้ embedding model แล้ว เราจะสร้าง vector database เพื่อเก็บ vector โดยในตัวอย่างเราจะใช้ FAISS database:

# Import package
from langchain_community.vectorstores import FAISS
# Build vector DB
vectorstore = FAISS.from_documents(
documents=chunks,
embedding=document_embedder
)

สังเกตว่า เราใส่ document_embedder ไปใน vector database ด้วย เพื่อแปลง chunk เป็น vector และเก็บลงใน database


🔎 Step 4. Create a Retriever

ในขั้นที่ 4 เราจะสร้าง retriever ที่ทำหน้าที่ค้นหา vector โดยใช้ .as_retriever() แบบนี้:

# Creater retriever
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 2}
)

เราสามารถทดสอบ retriever เพื่อดูว่า จะได้เอกสารอะไรกลับมา ได้แบบนี้:

# Test retriever
question = "Do I need a medical certificate for sick leave?"
relevant_docs = retriever.invoke(question)
for i, doc in enumerate(relevant_docs, start=1):
print(f"Retrieved chunk {i}")
print("Source:", doc.metadata["source"])
print(doc.page_content)
print("-" * 60)

ผลลัพธ์:

Retrieved chunk 1
Source: documents/leave_policy.txt
DataWise Co. Leave Policy
Full-time employees receive 10 days of annual leave per year after completing probation.
Employees receive 15 days of paid sick leave per year.
Sick leave of 3 consecutive days or more requires a medical certificate.
Employees should submit annual leave requests at least 7 days in advance through the HR system.
Unused annual leave can be carried over for up to 5 days into the next calendar year.
------------------------------------------------------------
Retrieved chunk 2
Source: documents/compensation_policy.txt
DataWise Co. Compensation Policy
Salary is paid on the last working day of each month.
Performance bonuses are reviewed once per year in December.
Employees may receive an annual salary adjustment based on company performance, individual performance, and market benchmarks.
Overtime pay is available only for non-managerial employees and must be approved by a manager before the overtime work begins.
------------------------------------------------------------

🤖 Step 5. Generate a Response

ในขั้นสุดท้าย เราจะให้ LLM สร้างคำตอบโดยใช้ข้อมูลใน vector database

ในตัวอย่างเราจะลองใช้ Gemini ช่วยคิดคำตอบให้กับเรา

เราจะเริ่มจากเชื่อมต่อกับ Gemini และสร้าง prompt ก่อน:

# Import packages
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.prompts import ChatPromptTemplate
# Initialise Gemini
llm = ChatGoogleGenerativeAI(
model="gemini-2.5-flash",
temperature=0,
google_api_key=GEMINI_API_KEY
)
# Create prompt template
prompt = ChatPromptTemplate.from_template("""
You are an HR policy assistant.
Answer the user's question using only the policy context below.
Rules:
- Do not use outside knowledge.
- If the answer is not in the context, say:
"I could not find this information in the available company policies."
- Keep the answer concise.
- Mention the source policy file when possible.
Policy context:
{context}
User question:
{question}
""")

จากนั้น กำหนดคำถามและดึงเอกสารที่เกี่ยวข้องจาก vector database

# Ask a question
question = "Do I need a medical certificate for sick leave?"
# Retrieve relevant document chunks
relevant_docs = retriever.invoke(question)
# Combine retrieved chunks into one context string
context = "\n\n".join(
[
f"Source: {doc.metadata['source']}\n"
f"{doc.page_content}"
for doc in relevant_docs
]
)
# Inspect retrieved context before sending it to Gemini
print("Retrieved context:")
print(context)

ผลลัพธ์:

Retrieved context:
Source: documents/leave_policy.txt
DataWise Co. Leave Policy
Full-time employees receive 10 days of annual leave per year after completing probation.
Employees receive 15 days of paid sick leave per year.
Sick leave of 3 consecutive days or more requires a medical certificate.
Employees should submit annual leave requests at least 7 days in advance through the HR system.
Unused annual leave can be carried over for up to 5 days into the next calendar year.
Source: documents/compensation_policy.txt
DataWise Co. Compensation Policy
Salary is paid on the last working day of each month.
Performance bonuses are reviewed once per year in December.
Employees may receive an annual salary adjustment based on company performance, individual performance, and market benchmarks.
Overtime pay is available only for non-managerial employees and must be approved by a manager before the overtime work begins.

แล้วส่งข้อมูลคำถามและเอกสารให้กับ Gemini:

# Add context and question to prompt template
messages = prompt.invoke(
{
"context": context,
"question": question
}
)
# Send prompt to Gemini
response = llm.invoke(messages)
# Print Gemini's answer
print(response.content)

ผลลัพธ์:

Yes, sick leave of 3 consecutive days or more requires a medical certificate. (Source: documents/leave_policy.txt)

เพื่อให้เราใช้งาน RAG pipeline ได้ง่าย เราสามารถแปลงโค้ดชุดนี้ให้เป็น function ได้:

# Convert to function
def ask_policy_question(question: str) -> str:
"""
Retrieve relevant policy chunks, send them to Gemini,
and return Gemini's answer.
"""
# Retrieve relevant chunks
relevant_docs = retriever.invoke(question)
# Combine retrieved chunks into context
context = "\n\n".join(
[
f"Source: {doc.metadata['source']}\n"
f"{doc.page_content}"
for doc in relevant_docs
]
)
# Add context and question to prompt template
messages = prompt.invoke(
{
"context": context,
"question": question
}
)
# Send completed prompt to Gemini
response = llm.invoke(messages)
# Return answer text
return response.content

เพื่อที่เราจะเขียนโค้ดสั้นลงในครั้งถัด ๆ ไป:

# Test function
answer = ask_policy_question("Who is eligible for health insurance?")
print(answer)

ผลลัพธ์:

Full-time employees receive health insurance after completing probation. (Source: documents/benefits_policy.txt)

💪 Summary

ในบทความนี้ เราได้เรียนรู้การสร้าง RAG pipeline ด้วย langchain ใน 5 ขั้นตอน:

  1. Load documents: โหลดเอกสารสำหรับ RAG pipeline
  2. Split text: แบ่ง text ในเอกสารเป็น chunk
  3. Embed and store chunks: แปลง chunk เป็น vector และเก็บลงใน database
  4. Create a retriever: สร้างตัวค้นหาเอกสารจาก vector database
  5. Generate a response: สร้างคำตอบจากเอกสาร

😺 GitHub

ดูตัวอย่าง code และเอกสารทั้งหมดได้ที่ GitHub


📃 References

Comments

Leave a comment