teach-me-ai / sources / HO-6
⟵ กลับหน้าแทร็กเสริม
HO-6 · Hands-On AI Engineering · Capstone 🎯

นำไปใช้จริง — ประกอบ Agentic RAG บน NestJS + pgvector

⏱️ ~40 นาที (ลงมือทำ) 🎯 รวมทุกบท HO เป็นของจริง 1 ชิ้น บนสแตกที่คุณถนัด แบบ end-to-end 📦 ต้นทาง: รวม HO-0 → HO-5 (พิมพ์ agentic_rag_system เป็นแม่แบบ)

ถึงบทสุดท้ายแล้ว — เราจะพิสูจน์ว่า pattern พกพาข้ามภาษาได้จริง โดยหยิบตัวที่ทรงพลังที่สุด ในคลัง (agentic_rag_system — self-reflection RAG) มา ประกอบใหม่ย่อ ๆ บน NestJS + PostgreSQL/pgvector โดยไม่แตะ Python เลย บทนี้เป็น lab — อ่านโครง แล้วลงมือทำตามใน repo ของคุณเอง (ควรผ่าน HO-0 ถึง HO-5 มาก่อน)

สิ่งที่จะสร้าง

"ผู้ช่วยตอบคำถามจากคู่มือภายในบริษัท" — ผู้ใช้ถามภาษาคน ระบบค้นคู่มือจริง เกรดว่า context พอไหม ถ้าไม่พอก็ปรับคำค้นแล้วค้นใหม่ สุดท้ายตอบพร้อม อ้างอิงแหล่งที่มา — ซึ่งก็คือ agentic RAG loop จาก HO-1/HO-2 นั่นเอง แต่คราวนี้เป็น NestJS service จริง

สถาปัตยกรรม (NestJS module)

RagController POST /ask (DTO) RagService orchestrator (agent loop) retrieve→grade→generate MAX_ITERATIONS EmbeddingProvider ข้อความ → เวกเตอร์ ChunkRepository pgvector (PostgreSQL) LlmProvider grade + generate (Claude) 🗄️ Postgres + pgvector
แยกความรับผิดชอบชัด: controller (I/O) · service (loop) · provider (embedding/LLM) · repository (pgvector)

ลงมือทำ 5 ขั้น

ขั้น 1 · ตั้ง pgvector (จาก HO-2)

CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE doc_chunks (
  id         bigserial PRIMARY KEY,
  source     text NOT NULL,       -- ไว้ทำ citation
  content    text NOT NULL,
  embedding  vector(1536)
);

ขั้น 2 · Ingest (chunk → embed → store)

เตรียมคลังล่วงหน้า — ตัดคู่มือเป็น chunk, embed, เก็บลงตาราง (งานนี้ควรเป็น worker/queue ไม่ใช่ใน request):

async ingest(doc: Doc) {
  const chunks = this.chunk(doc.text, { size: 700, overlap: 80 });
  for (const c of chunks) {
    const vec = await this.embedding.embed(c);
    await this.repo.insert({ source: doc.name, content: c, embedding: vec });
  }
}

ขั้น 3 · Retrieve = "tool" ตัวหนึ่ง (จาก HO-2)

// ChunkRepository — top-k ใกล้สุดด้วย cosine (<=>)
async search(queryVec: number[], k = 5) {
  return this.db.query(
    `SELECT source, content FROM doc_chunks ORDER BY embedding <=> $1 LIMIT $2`,
    [queryVec, k],
  );
}

ขั้น 4 · Agent loop: retrieve → grade → rewrite → generate (จาก HO-1)

หัวใจของทั้งหมด — พอร์ต state machine ของ agentic_rag_system มาเป็น TS ตรง ๆ:

async ask(question: string): Promise<Answer> {
  let query = question;
  for (let i = 0; i < MAX_ITERATIONS; i++) {     // กันวนไม่จบ (HO-1)
    const vec     = await this.embedding.embed(query);
    const chunks  = await this.repo.search(vec);       // retrieve
    const verdict = await this.llm.grade(question, chunks); // grade
    if (verdict.ok || i === MAX_ITERATIONS - 1)
      return this.llm.generate(question, chunks);   // generate + citation
    query = verdict.refinedQuery;                       // rewrite → วนใหม่
  }
}

ขั้น 5 · คำตอบเป็น structured output + citation (จาก HO-3)

// บังคับ LLM ตอบตาม schema — validate ก่อนส่งออก (เหมือน HO-3)
const Answer = z.object({
  answer:    z.string(),
  citations: z.array(z.object({ source: z.string(), quote: z.string() })),
});

เห็นไหมว่ามาจากทุกบท

ชิ้นส่วนมาจากบท
agent loop + MAX_ITERATIONS + toolHO-1
retrieve / pgvector / self-reflectionHO-2
structured output + validate ก่อนส่งออกHO-3
เลือก provider Claude (ไม่ fine-tune)HO-5
วิธีอ่าน/พอร์ตโปรเจกต์ต้นทางHO-0
🔗

เรื่อง provider/SDK ของ Claude (Messages API, tool use, structured output, prompt caching) อยู่ในเส้นทางหลัก Lv2 และ Lv3 — เอามาเสียบใน LlmProvider ได้เลย

ก่อนขึ้น production — เช็กลิสต์ (Lv7)

โปรเจกต์ในคลังเป็นเดโม (เตือนไว้ตั้งแต่ HO-0) — ของจริงต้องเติมอีกชั้น:

  • Auth & rate limit ที่ controller (กันใช้เกิน/คนนอก)
  • Cost & observability — log token/รอบ loop/latency ต่อคำถาม (loop = จ่ายเงินหลายเท่า)
  • Error handling & timeout — LLM ล่ม/ช้า ต้อง fallback ไม่ใช่ค้าง
  • Guardrail — จำกัดสิ่งที่ตอบ, กัน prompt injection จากเนื้อคู่มือ
  • Eval — ชุดคำถาม-คำตอบไว้วัดคุณภาพก่อน/หลังแก้ (ไม่วัด = ไม่รู้ว่าดีขึ้น)
🎓

จบแทร็ก HO! คุณอ่านแอป AI จริง ~59 ตัวเป็น แล้วถอด pattern มาประกอบเองบนสแตกที่ถนัดได้ ขั้นต่อไป: ทำ lab นี้ให้รันจริงในโปรเจกต์คุณ แล้วต่อยอดสู่ Lv7 · Production เพื่อทำให้มันพร้อมใช้งานจริง

🎯 แบบฝึกหัด (capstone)
  1. สร้าง NestJS module rag/ ตามสถาปัตยกรรมด้านบน (controller + service + 2 provider + repository) ให้ ingest เอกสารตัวอย่าง 1–2 ไฟล์ลง pgvector ได้
  2. ทำ endpoint POST /ask ให้ตอบได้จริงด้วย loop retrieve→grade→generate พร้อมคืน citations (validate ด้วย schema)
  3. เปิด sources/.../ai_agents/agentic_rag_system/rag_graph.py เทียบกับโค้ด TS ของคุณ แล้วเขียน 3 บรรทัดว่า "pattern ไหนพกพาข้ามภาษาได้ตรง ๆ บ้าง"
  4. เลือก 2 ข้อจากเช็กลิสต์ production มาทำจริง (แนะนำ rate limit + cost logging)

เมื่อทำเสร็จ พิมพ์ /quiz HO-6 เพื่อทดสอบความเข้าใจรวบยอดของทั้งแทร็ก