เอเจนต์ในโครงงานวิทยาการข้อมูลแตกต่างจาก Chatbot ทั่วไป :
RAG (Retrieval-Augmented Generation) คือการดึงข้อมูลจากแหล่งภายนอกมาประกอบการตอบของ LLM
# การแปลงข้อความเป็นตัวเลขหลายมิติ
"Amazon" → [0.011, -0.023, 0.026, ...]
# การวัดความใกล้เคียง (Semantic Similarity)
distance(Amazon, Brazil) < distance(Amazon, Food)
เราใช้ Embeddings เพื่อให้ AI เข้าใจบริบท แม้ผู้ใช้จะใช้คำที่ต่างจากในเอกสาร (เช่น ถาม "Wide feet" แต่ระบบพบคำว่า "Extra wide")
ทำไมต้องใช้ pgvector ใน PostgreSQL?
VectorField ในโปรเจกต์นี้ เอเจนต์ของเราจะสวมบทบาทเป็น "Expert Document Assistant"
ชื่อ: doc_specialist_agent, ความสามารถ: วิเคราะห์และสรุปเนื้อหาจากเอกสารภายในองค์กร
"คุณคือนักจัดการความรู้ หน้าที่ของคุณคือสืบค้นข้อมูลจากเอกสารที่กำหนด และตอบคำถามอย่างถูกต้อง หากไม่มีข้อมูลให้ตอบว่าไม่ทราบ"
ใช้ระบบ Auth และ Admin ของ Django เพื่อจัดการสิทธิ์การอัปโหลดไฟล์ (PDF/Text)
เขียน Service Layer เพื่อเชื่อมต่อกับ Ollama/Gemini และ pgvector เพื่อทำ RAG
Django ช่วยจัดการ User Session และการจัดเก็บข้อมูลที่มีโครงสร้างได้อย่างปลอดภัย
ในโปรเจกต์ระดับองค์กร เราสามารถแบ่งงานให้หลายเอเจนต์ผ่านโปรโตคอล Agent2Agent (A2A)
สรุปเอกสารที่ Admin เพิ่งอัปโหลด
สืบค้นข้อมูลเชิงลึกจากฐานข้อมูล Vector
ตรวจสอบความถูกต้องและ Bias ของคำตอบ
"สร้างระบบจัดการเอกสารอัจฉริยะที่สามารถแชทโต้ตอบได้"
"พร้อมแล้วไปเริ่มต้นขั้นตอนแรกในสไลด์ถัดไป!"
เพื่อให้ AI สามารถประมวลผลเอกสารขนาดใหญ่ได้ เราต้องแบ่งเนื้อหาเป็นส่วนย่อย:
# ตัวอย่างการระบุมิติใน Django Model
embedding = VectorField(dimensions=768)
มิติ (Dimensions) ต้องตรงกับโมเดลที่ใช้เสมอ
Hierarchical Navigable Small Worlds (HNSW):
*ช่วยให้เอเจนต์สามารถสืบค้นเอกสารนับล้านได้ในเวลาไม่กี่มิลลิวินาที *
class Document(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
embedding = VectorField(dimensions=768) # สำหรับ pgvector
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Message(models.Model):
conversation = models.ForeignKey(Conversation, ...)
user_prompt = models.TextField()
ai_response = models.TextField()
embedding = VectorField(dimensions=768) # สำหรับค้นหาประวัติ
"ในฐานะผู้เชี่ยวชาญ จงตอบคำถามโดยใช้บริบท (Context) ที่ให้มาเท่านั้น หากไม่มีข้อมูลในบริบทให้ตอบว่า 'ขออภัย ฉันไม่พบข้อมูลนี้ในเอกสาร' โดยไม่ต้องพยายามเดา"
Context: {retrieved_chunks_from_db}
User Question: {user_input}
เมื่อประวัติการสนทนายาวเกินขีดจำกัดของโมเดล (Context Window):
Admin อัปโหลดไฟล์ (PDF/Text) ผ่าน Django Admin Interface.
ระบบรันฟังก์ชัน `PyMuPDFLoader` เพื่อสกัดข้อความออกจากไฟล์
ข้อความถูกส่งไปยัง Embedding Service เพื่อแปลงเป็น Vector และบันทึกลงฐานข้อมูล
เอเจนต์จะไม่ค้นหาทันที แต่จะ "เรียบเรียงคำถามใหม่" โดยพิจารณาจากประวัติการแชท (เช่น ถ้าผู้ใช้ถาม 'แล้วอันนี้ล่ะ?' เอเจนต์จะเปลี่ยนเป็น 'แล้วสวัสดิการพนักงานล่ะ?')
เราวัดความสำเร็จของระบบแชทอัจฉริยะผ่านเกณฑ์มาตรฐาน
"สไลด์ถัดไป: เริ่มต้นภาคปฏิบัติสร้างแชทบอทตัวแรกของคุณ!"
เป้าหมาย: สร้างระบบแชทอัจฉริยะที่ Admin สามารถอัปโหลด PDF และตั้งค่าโมเดลได้:
ใช้ docker-compose.yml เพื่อติดตั้ง Ollama และ Database ที่พร้อมใช้งาน pgvector
services:
db:
image: ankane/pgvector:latest # Postgres พร้อม pgvector
environment: [POSTGRES_PASSWORD: 'password']
ollama:
image: ollama/ollama
volumes: ['ollama_data:/root/.ollama']
ตั้งค่า settings.py เพื่อเชื่อมต่อฐานข้อมูลและเปิดใช้งาน Extension
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'vector_db', ...
}
}
สร้าง Migration พิเศษเพื่อเปิด Extension:
# models.py
class ChatConfig(models.Model): # สำหรับ Admin ตั้งค่า
default_model = models.CharField(max_length=100, default="llama3")
system_prompt = models.TextField()
class Document(models.Model):
file = models.FileField(upload_to='pdfs/')
content = models.TextField()
embedding = VectorField(dimensions=768) # nomic-embed มิติ=768
ใช้ PyMuPDFLoader เพื่อสกัดข้อความจากไฟล์ที่ Admin อัปโหลด
from langchain_community.document_loaders import PyMuPDFLoader
def process_pdf(file_path):
loader = PyMuPDFLoader(file_path)
documents = loader.load()
full_text = "\n".join([doc.page_content for doc in documents])
return full_text
Personal Learning: ลองถาม AI ว่า "How to split text into chunks with 500 characters overlap in Python?" เพื่อปรับปรุงความแม่นยำ
แปลงข้อความเป็น Vector และบันทึกลงฐานข้อมูล
import ollama
def save_vector(text, doc_instance):
response = ollama.embed(model='nomic-embed-text', input=text)
doc_instance.embedding = response['embeddings']
doc_instance.save()
ใช้ CosineDistance ค้นหาเนื้อหาที่ใกล้เคียงกับคำถามผู้ใช้ที่สุด
from pgvector.django import CosineDistance
def get_context(query_text):
query_vec = ollama.embed(model='nomic-embed-text', input=query_text)['embeddings']
similar_docs = Document.objects.annotate(
distance=CosineDistance('embedding', query_vec)
).order_by('distance')[:3] # ดึง 3 ชิ้นที่ใกล้ที่สุด
return "\n".join([d.content for d in similar_docs])
รวม Context เข้ากับ Prompt และส่งให้ LLM ตามที่ Admin กำหนด
@router.post("/chat")
def chat_endpoint(request, user_query: str):
config = ChatConfig.objects.first()
context = get_context(user_query)
full_prompt = f"{config.system_prompt}\nContext: {context}\nQuestion: {user_query}"
response = ollama.chat(model=config.default_model,
messages=[{'role': 'user', 'content': full_prompt}])
return {"answer": response['message']['content']}
สร้างโปรเจกต์ React และติดตั้งเครื่องมือจัดการแชท:
const handleSend = async () => {
const res = await axios.post('/api/chat', { user_query: input });
setMessages([...messages, { role: 'user', text: input }, { role: 'ai', text: res.data.answer }]);
};
Tip: ใช้ StreamingHttpResponse จากฝั่ง Django เพื่อให้ Chatbot แสดงผลทีละคำเหมือน ChatGPT
อนุญาตให้ Admin เปลี่ยนโมเดลและ Tokenizer ผ่าน UI:
Dropdown สำหรับเลือก llama3, gemma, หรือ mistral ที่ติดตั้งใน Ollama.
Textarea สำหรับแก้ไข Persona ของ AI (เช่น "ตอบเฉพาะภาษาไทยเท่านั้น")
สร้างสภาพแวดล้อมจริงโดยการรวม Frontend และ Backend
npm run build แล้วให้ Django Serve ไฟล์ Static.*คำเตือน: อย่าลืมตั้งค่า ALLOWED_HOSTS และ DEBUG=False ใน Production.*
"ยินดีด้วย! คุณได้สร้างระบบ RAG Full-stack ที่ใช้งานได้จริงแล้ว"