-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrag.py
More file actions
126 lines (106 loc) · 6.98 KB
/
Copy pathrag.py
File metadata and controls
126 lines (106 loc) · 6.98 KB
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# ============================================================
# RAG (Retrieval-Augmented Generation) — Step by Step
# ============================================================
# pip install langchain langchain-community langchain-openai chromadb
from dotenv import load_dotenv
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
load_dotenv() # โหลด .env file
from langchain_community.vectorstores import Chroma
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# ────────────────────────────────────────────
# 0. Config
# ────────────────────────────────────────────
# API key โหลดจาก .env อัตโนมัติ (ห้าม hardcode ใน code!)
# ────────────────────────────────────────────
# 1. เอกสารตัวอย่าง (แทน PDF หรือ database)
# ────────────────────────────────────────────
raw_documents = [
Document(page_content="""
LangChain คือ framework สำหรับสร้าง application ที่ใช้ LLM
รองรับการเชื่อมต่อกับ OpenAI, Anthropic, Google และอื่นๆ
มี component หลักคือ Chain, Agent, Memory และ Tool
""", metadata={"source": "langchain_intro"}),
Document(page_content="""
RAG ย่อมาจาก Retrieval-Augmented Generation
เป็นเทคนิคที่ช่วยให้ LLM ตอบคำถามจากเอกสารของเราได้
ขั้นตอนคือ: โหลดเอกสาร → แบ่ง chunks → embed → เก็บ → ค้นหา → ตอบ
""", metadata={"source": "rag_intro"}),
Document(page_content="""
Vector Database คือฐานข้อมูลที่เก็บข้อมูลในรูปแบบ vector (ตัวเลข)
ใช้สำหรับค้นหาเนื้อหาที่ "ความหมายใกล้เคียง" กับ query
ตัวอย่างเช่น Chroma, Pinecone, Weaviate, FAISS
""", metadata={"source": "vector_db_intro"}),
]
# ────────────────────────────────────────────
# 2. แบ่งเอกสารเป็น Chunks
# ────────────────────────────────────────────
# chunk_size = ขนาด chunk (ตัวอักษร)
# chunk_overlap = ส่วนที่ทับซ้อนกัน เพื่อไม่ให้ตัดประโยคกลาง
splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=20,
)
chunks = splitter.split_documents(raw_documents)
print(f"แบ่งได้ {len(chunks)} chunks")
for i, chunk in enumerate(chunks):
print(f" chunk[{i}]: {chunk.page_content[:60].strip()}...")
# ────────────────────────────────────────────
# 3. สร้าง Embeddings และเก็บใน Vector Store
# ────────────────────────────────────────────
# Embedding = แปลงข้อความเป็น vector ตัวเลข เพื่อเปรียบเทียบความหมาย
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db", # เก็บลง disk ใช้ซ้ำได้
)
# ────────────────────────────────────────────
# 4. สร้าง Retriever
# ────────────────────────────────────────────
# retriever จะค้นหา chunks ที่ใกล้เคียงกับ query มากที่สุด
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 2}, # ดึงมา 2 chunks
)
# ────────────────────────────────────────────
# 5. สร้าง Prompt Template
# ────────────────────────────────────────────
template = """ตอบคำถามโดยใช้ข้อมูลจาก context ที่ให้มาเท่านั้น
ถ้าไม่มีข้อมูลใน context ให้บอกว่า "ไม่มีข้อมูลในเอกสาร"
Context:
{context}
คำถาม: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
# ────────────────────────────────────────────
# 6. สร้าง LLM
# ────────────────────────────────────────────
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# ────────────────────────────────────────────
# 7. ประกอบ RAG Chain
# ────────────────────────────────────────────
def format_docs(docs):
"""รวม chunks ทั้งหมดเป็น string เดียว"""
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# ────────────────────────────────────────────
# 8. ทดสอบถามคำถาม
# ────────────────────────────────────────────
questions = [
"RAG คืออะไร?",
"Vector Database ใช้ทำอะไร?",
"LangChain มี component อะไรบ้าง?",
]
for q in questions:
print(f"\nQ: {q}")
answer = rag_chain.invoke(q)
print(f"A: {answer}")