RAG & Vector Database·

AI Agent ที่ขับเคลื่อนด้วย RAG: การสร้างระบบอัตโนมัติที่เน้นความรู้ด้วย n8n, Vector Database และ GPT-5.5

เชี่ยวชาญ Retrieval-Augmented Generation (RAG) สำหรับการสร้าง AI Agent ที่เน้นความรู้ด้วย n8n เรียนรู้การผสานรวม Qdrant, Pinecone และ Weaviate Vector Database การใช้กลยุทธ์การแบ่งข้อความ (chunking) ที่ชาญฉลาด และการสร้าง RAG workflow ที่พร้อมใช้งานจริงด้วยโมเดล GPT-5.5 พร้อมตัวอย่างเชิงปฏิบัติกว่า 25 ตัวอย่างและรูปแบบสถาปัตยกรรม

AI Agent ที่ขับเคลื่อนด้วย RAG: การสร้างระบบอัตโนมัติที่เน้นความรู้ด้วย n8n, Vector Database และ GPT-5.5

การเปิดตัว GPT-5.5 ของ OpenAI เมื่อวันที่ 5 พฤษภาคม 2026 นับเป็นจุดเปลี่ยนสำคัญสำหรับแอปพลิเคชัน AI ที่เน้นความรู้ ด้วยความสามารถในการให้เหตุผลที่ดีขึ้นอย่างมากและการลดการใช้ token ลง 40% เมื่อเทียบกับ GPT-5.4 GPT-5.5 ได้รับการออกแบบมาโดยเฉพาะสำหรับงานองค์กรแบบ agent และการเข้าใจเอกสารที่ซับซ้อน - ซึ่งเป็นพื้นฐานที่สมบูรณ์แบบสำหรับระบบ Retrieval-Augmented Generation (RAG)

องค์กรที่นำ workflow ที่ขับเคลื่อนด้วย RAG ไปใช้กำลังเห็นผลลัพธ์ที่เปลี่ยนแปลงเกม: การลดอัตราการหลอนจาก AI (hallucination) ลง 73% การปรับปรุงความแม่นยำในการค้นหาเอกสาร 4.2 เท่า และการดึงความรู้ที่เร็วขึ้น 67% เมื่อเทียบกับการค้นหาแบบ keyword แบบดั้งเดิม การสำรวจล่าสุดพบว่า 57.3% ของผู้สร้าง AI agent ตอนนี้มี agent ที่ใช้ RAG ในระบบ production เพิ่มขึ้นจากเพียง 23% ในต้นปี 2025

คู่มือที่ครอบคลุมนี้จะสำรวจวิธีการสร้างระบบ RAG ที่พร้อมใช้งานจริงด้วย n8n, vector database และ GPT-5.5 ตั้งแต่การออกแบบ ingestion pipeline ไปจนถึงการใช้กลยุทธ์การค้นหาแบบไฮบริด จากการปรับแต่งอัลกอริทึมการแบ่งข้อความ (chunking) ไปจนถึงการสร้าง agent ที่สามารถสนทนาและเข้าใจความรู้ของธุรกิจได้จริง - เราจะครอบคลุมทุกอย่างที่คุณต้องการเพื่อสร้างระบบอัตโนมัติที่เน้นความรู้พร้อม ROI ที่วัดได้

การเข้าใจสถาปัตยกรรม RAG: มากกว่าแค่ Chatbot ธรรมดา

รูปแบบ RAG อธิบาย

Retrieval-Augmented Generation สะพานช่องว่างระหว่าง Large Language Model และความรู้ส่วนตัว ไม่เหมือนกับ fine-tuning ที่ฝังความรู้ถาวรลงใน weights ของโมเดล RAG จะดึง context ที่เกี่ยวข้องแบบไดนามิกตอน query - ทำให้ AI ตอบสนองได้ทันสมัย ตรวจสอบได้ และลดอาการหลอน

┌─────────────────────────────────────────────────────────────────────────────┐
│                         กระแสข้อมูลสถาปัตยกรรม RAG                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────┐ │
│  │   เอกสาร     │───▶│  แบ่ง &      │───▶│   Vector     │───▶│  Vector  │ │
│  │   แหล่งที่มา   │    │  Embed       │    │   Database   │    │  เก็บข้อมูล│ │
│  └──────────────┘    └──────────────┘    └──────────────┘    └──────────┘ │
│        │                    │                    │                  │       │
│        │                    │                    │                  │       │
│        ▼                    ▼                    ▼                  ▼       │
│   PDFs, URLs,        การแบ่งข้อความ,     Pinecone,            การค้นหา   │
│   Database,          OpenAI/GPT-5.5       Qdrant,              เชิงความหมาย│
│   APIs               Embeddings           Weaviate              แบบเรียลไทม์│
│                                                                             │
│                              เวลา QUERY                                    │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────┐ │
│  │   คำถาม      │───▶│   ดึง         │───▶│   สร้าง       │───▶│ คำตอบ    │ │
│  │   ผู้ใช้      │    │   Context    │    │   คำตอบ       │    │          │ │
│  └──────────────┘    └──────────────┘    └──────────────┘    └──────────┘ │
│                            │                                                │
│                            ▼                                                │
│                    การค้นหาความคล้ายคลึง +                                    │
│                    การจัดอันดับใหม่ (Re-ranking)                              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

ข้อดีหลักของ RAG เทียบกับ Fine-Tuning:

ด้านFine-TuningRAG
ความทันสมัยของข้อมูลต้องเทรนใหม่ทันสมัยเสมอ
การระบุแหล่งที่มายากมีมาในตัว
อัตราการหลอนของ AIสูงกว่าลดลง 73%
เวลาดำเนินการสัปดาห์ถึงเดือนวันถึงสัปดาห์
ต้นทุนต่อการอัปเดตสูง (ต้องเทรนใหม่)ต่ำ (จัดทำดัชนีใหม่)
การเปลี่ยนโดเมนต้องใช้โมเดลใหม่ไดนามิกตอน query

ข้อดีของ GPT-5.5 สำหรับ RAG

GPT-5.5 นำการปรับปรุงเฉพาะที่ทำให้เหมาะสมกับ RAG workflow:

1. การติดตาม Context ที่ดีขึ้น

// GPT-5.5 เข้าใจดีขึ้นว่าเมื่อใดควรใช้ context ที่ดึงมากับความรู้ทั่วไป
const systemPrompt = `
คุณเป็นผู้ช่วยที่มีประโยชน์พร้อมเข้าถึงความรู้ของบริษัทต่อไปนี้:

<context_ที่ดึงมา>
{{ $json.retrievedDocuments }}
</context_ที่ดึงมา>

คำสั่งสำคัญ:
- หาก context ที่ดึงมามีคำตอบ ใช้เฉพาะข้อมูลนั้นเท่านั้น
- หาก context ไม่เพียงพอ ระบุชัดเจนว่าต้องการข้อมูลเพิ่มเติมใด
- อย่าสร้างข้อมูลที่ไม่มีอยู่ใน context
- อ้างอิงแหล่งที่มาของเอกสารเฉพาะเมื่อให้คำตอบ
`;

// GPT-5.5 แสดงความแม่นยำ 89% ในการปฏิบัติตามคำสั่งเหล่านี้ เทียบกับ 67% ของ GPT-4

2. การใช้ Token ที่ลดลง

// ด้วยการปรับปรุงประสิทธิภาพ token 40% ของ GPT-5.5:
// ก่อน: 15,000 token ต่อ RAG query = $0.45 (GPT-4)
// GPT-5.5: 9,000 token ต่อ RAG query = $0.27 (ประหยัด 40%)
// การประหยัดรายเดือนสำหรับ 10,000 query: $1,800

const costComparison = {
  model: 'gpt-5.5',
  inputCostPer1k: 5.00,  // $5 ต่อล้าน token
  outputCostPer1k: 30.00, // $30 ต่อล้าน token
  averageInputTokens: 6000,
  averageOutputTokens: 3000,
  costPerQuery: (6000 * 5 + 3000 * 30) / 1000000, // $0.12
  gpt4CostPerQuery: 0.20, // ต้นทุนก่อนหน้า
  savings: '40%'
};

3. Output ที่มีโครงสร้างดีขึ้น

// GPT-5.5 มีจุดแข็งในการส่งคืนข้อมูลที่มีโครงสร้างจาก RAG query
const structuredOutputExample = {
  answer: "บริษัทก่อตั้งขึ้นในปี 2018 โดย Jane Smith และ John Doe",
  sources: [
    {
      document_id: "company-history-2024.pdf",
      page: 3,
      confidence: 0.94,
      excerpt: "ก่อตั้งในปี 2018 Tropical Media เริ่มต้นเป็นที่ปรึกษาด้านระบบอัตโนมัติขนาดเล็ก..."
    },
    {
      document_id: "founder-bios.docx",
      page: 1,
      confidence: 0.91,
      excerpt: "Jane Smith (CEO) และ John Doe (CTO) ก่อตั้งบริษัทด้วยวิสัยทัศน์..."
    }
  ],
  confidence_score: 0.92,
  additional_info_needed: null
};

การตั้งค่า Vector Database ใน n8n

ตัวเลือกที่ 1: Qdrant (แนะนำสำหรับ Self-Hosted)

Qdrant กลายเป็นตัวเลือกที่นิยมสำหรับระบบ RAG production เนื่องจากความสามารถในการค้นหาแบบไฮบริด re-ranking ที่มีมาในตัว และการผสานรวมกับ n8n ที่ยอดเยี่ยม

ขั้นตอนที่ 1: Deploy Qdrant

# docker-compose.yml สำหรับ Qdrant
version: '3.8'
services:
  qdrant:
    image: qdrant/qdrant:latest
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_storage:/qdrant/storage
    environment:
      QDRANT__LOG_LEVEL: INFO
      QDRANT__SERVICE__MAX_REQUEST_SIZE_MB: 32
    # เปิดใช้งาน GPU acceleration สำหรับการ deploy ขนาดใหญ่
    # deploy:
    #   resources:
    #     reservations:
    #       devices:
    #         - driver: nvidia
    #           count: 1
    #           capabilities: [gpu]

volumes:
  qdrant_storage:

ขั้นตอนที่ 2: n8n Qdrant Integration

// สร้าง collection ด้วยการตั้งค่าที่เหมาะสมสำหรับ RAG
const createCollection = {
  url: 'http://localhost:6333',
  collectionName: 'company-knowledge-base',
  vectorSize: 1536,  // OpenAI embedding dimension
  distance: 'Cosine', // เหมาะที่สุดสำหรับความคล้ายคลึงเชิงความหมาย
  optimizersConfig: {
    defaultSegmentNumber: 2,
    maxSegmentSize: 100000,
    memmapThreshold: 20000
  },
  hnswConfig: {
    m: 16,              // สูงกว่า = recall ดีขึ้น, หน่วยความจำมากขึ้น
    efConstruct: 100,   // สูงกว่า = คุณภาพการสร้างดีขึ้น
    fullScanThreshold: 10000
  },
  quantizationConfig: {
    scalar: {
      type: 'int8',
      quantile: 0.99,
      alwaysRam: true
    }
  }
};

// Response: Collection สร้างเสร็จพร้อมการลดหน่วยความจำ 90% ผ่าน quantization

ขั้นตอนที่ 3: Document Ingestion Pipeline

// n8n workflow แบบสมบูรณ์สำหรับการนำเข้าเอกสาร
// Trigger: Manual หรือ Scheduled (sync รายวัน)

// Node 1: ดึงเอกสาร (HTTP Request หรือ File Read)
const fetchDocuments = {
  url: 'https://company-docs.s3.amazonaws.com/knowledge-base/',
  options: {
    headers: {
      'Authorization': 'Bearer {{ $env.S3_ACCESS_TOKEN }}'
    }
  }
};

// Node 2: แยกวิเคราะห์เอกสาร (หลายรูปแบบ)
const parseDocuments = {
  // PDF
  pdf: {
    operation: 'Extract',
    options: {
      metadata: true,
      pageNumbers: true
    }
  },
  // Word documents
  docx: {
    operation: 'Extract Text',
    includeHeaders: true,
    includeFooters: true
  },
  // Web pages
  html: {
    operation: 'Extract Content',
    selector: 'article, .content, main', // เน้นที่เนื้อหา
    removeSelectors: 'nav, footer, .ads, .sidebar'
  }
};

// Node 3: Chunking ที่ชาญฉลาด
const chunkingStrategy = {
  method: 'Recursive Character',
  chunkSize: 512,        // เหมาะสมสำหรับ context window ของ GPT-5.5
  chunkOverlap: 128,     // ซ้อนทับ 25% รักษา context
  separators: [
    '\n\n',              // ย่อหน้า
    '\n',                 // บรรทัด
    '. ',                 // ประโยค
    ' '                   // คำ (fallback)
  ],
  // รักษาขอบเขตทางความหมาย
  preserveContext: true,
  // เพิ่ม metadata ให้แต่ละ chunk
  metadata: {
    source: '{{ $json.sourceUrl }}',
    title: '{{ $json.title }}',
    category: '{{ $json.category }}',
    created_at: '{{ $json.date }}',
    author: '{{ $json.author }}',
    file_type: '{{ $json.fileType }}'
  }
};

// Node 4: สร้าง Embeddings ด้วย GPT-5.5
const embeddingConfig = {
  model: 'text-embedding-3-large',  // 3072 dimensions, คุณภาพดีกว่า
  // หรือ 'text-embedding-3-small' สำหรับการประหยัดต้นทุน
  
  // GPT-5.5 ยังสามารถสร้าง embeddings แบบกำหนดเองผ่าน API
  customModel: 'gpt-5.5-embedding',
  input: '{{ $json.chunkText }}',
  
  // ประมวลผลเป็นชุดเพื่อประสิทธิภาพ
  batchSize: 100,
  
  // Retry logic สำหรับ rate limits
  retry: {
    maxRetries: 3,
    backoffMultiplier: 2,
    initialDelay: 1000
  }
};

// Node 5: Upsert ไปยัง Qdrant
const upsertConfig = {
  collection: 'company-knowledge-base',
  points: {
    id: '{{ $json.uuid }}',  // สร้าง UUID ต่อ chunk
    vector: '{{ $json.embedding }}',
    payload: {
      text: '{{ $json.chunkText }}',
      metadata: '{{ $json.metadata }}',
      // เพิ่ม timestamp สำหรับ versioning
      indexed_at: '{{ new Date().toISOString() }}'
    }
  },
  // Batch upsert เพื่อประสิทธิภาพ
  batchSize: 50
};

ตัวเลือกที่ 2: Pinecone (Cloud-Native)

Pinecone นำเสนอ vector search แบบ serverless พร้อมลักษณะการ scale ที่ยอดเยี่ยม

// Pinecone setup สำหรับ n8n RAG workflows

// Node: Pinecone Vector Store
const pineconeConfig = {
  apiKey: '{{ $env.PINECONE_API_KEY }}',
  environment: 'us-east-1',
  
  // Serverless index configuration
  serverless: {
    cloud: 'aws',
    region: 'us-east-1'
  },
  
  // Index specifications
  indexName: 'rag-knowledge-base',
  dimension: 1536,
  metric: 'cosine',
  
  // Pod-based สำหรับ high-throughput (optional)
  // pods: 2,
  // podType: 'p1.x1',
  
  // Metadata configuration
  metadataConfig: {
    indexed: [
      'category',
      'source',
      'created_at',
      'author'
    ]
  }
};

// Query พร้อม metadata filtering
const queryConfig = {
  index: 'rag-knowledge-base',
  vector: '{{ $json.queryEmbedding }}',
  topK: 10,
  includeMetadata: true,
  includeValues: false,  // ลดขนาด payload
  filter: {
    category: { $eq: '{{ $json.category }}' },
    created_at: { $gte: '{{ $json.sinceDate }}' }
  },
  // Hybrid search configuration
  query: '{{ $json.queryText }}',  // สำหรับ sparse-dense fusion
  searchType: 'hybrid'  // ผสม semantic + keyword search
};

ตัวเลือกที่ 3: Weaviate (Graph + Vector Hybrid)

Weaviate โดดเด่นเมื่อคุณต้องการความสัมพันธ์แบบกราฟควบคู่กับ vector search

// Weaviate schema สำหรับ RAG พร้อมความสัมพันธ์
const weaviateSchema = {
  class: 'DocumentChunk',
  description: 'Chunk ของความรู้บริษัทพร้อมความสัมพันธ์',
  vectorizer: 'text2vec-openai',
  moduleConfig: {
    'text2vec-openai': {
      model: 'ada',
      modelVersion: '002',
      type: 'text'
    }
  },
  properties: [
    {
      name: 'content',
      dataType: ['text'],
      moduleConfig: {
        'text2vec-openai': { skip: false, vectorizePropertyName: false }
      }
    },
    {
      name: 'source',
      dataType: ['text'],
      tokenization: 'word'
    },
    {
      name: 'category',
      dataType: ['text'],
      tokenization: 'field'  // กรองแบบ exact match
    },
    {
      name: 'relatedChunks',
      dataType: ['DocumentChunk'],  // ความสัมพันธ์แบบกราฟ
      description: 'Chunks ที่มีความหมายใกล้เคียง'
    },
    {
      name: 'parentDocument',
      dataType: ['Document'],  // เชื่อมโยงกับแม่
    }
  ],
  // Hybrid search settings
  vectorIndexConfig: {
    ef: 256,
    efConstruction: 128,
    maxConnections: 64,
    dynamicEfFactor: 8
  }
};

// Graph query สำหรับ contextual retrieval
const graphQuery = `
  {
    Get {
      DocumentChunk(
        nearText: {
          concepts: ["{{ $json.query }}"]
          certainty: 0.7
        }
        limit: 5
      ) {
        content
        source
        category
        // Traverse ความสัมพันธ์
        relatedChunks {
          content
          source
        }
        parentDocument {
          title
          author
          publishDate
        }
      }
    }
  }
`;

กลยุทธ์การแบ่งข้อความ (Chunking) ขั้นสูง

วิทยาศาสตร์ของการแบ่งข้อความ

Chunking เป็นปัจจัยที่สำคัญที่สุดในการสร้างคุณภาพ RAG การแบ่งข้อความที่แย่นำไปสู่การสูญเสีย context ในขณะที่การแบ่งข้อความที่เหมาะสมที่สุดสามารถปรับปรุงความแม่นยำในการดึงข้อมูลได้ 40%+

┌──────────────────────────────────────────────────────────────────────────────┐
│                        การเปรียบเทียบกลยุทธ์การแบ่งข้อความ                      │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│  เอกสาร: "บริษัทก่อตั้งขึ้นในปี 2018 รายได้เติบโต 300% ในปี 2024"               │
│                                                                               │
│  ขนาดคงที่ (ไม่ดี):                                                           │
│  ┌─────────────────┬─────────────────┬─────────────────┐                    │
│  │บริษัทก่อตั้งขึ้น  │้ปี 2018 รายได้  │เติบโต 300% ใน   │                    │
│  └─────────────────┴─────────────────┴─────────────────┘                    │
│  └─ "บริษัทก่อตั้งขึ้นปีไหน?" → Query ตรงกับ chunk กลางเท่านั้น               │
│     แต่ chunk แบ่ง "ก่อตั้งขึ้นปี 2018" → สูญเสียข้อมูล!                      │
│                                                                               │
│  เชิงความหมาย (ดีกว่า):                                                        │
│  ┌──────────────────────────────────┬──────────────────────────────────┐     │
│  │บริษัทก่อตั้งขึ้นในปี 2018         │ รายได้เติบโต 300% ในปี 2024       │     │
│  └──────────────────────────────────┴──────────────────────────────────┘     │
│                                                                               │
│  แบบ recursive พร้อมซ้อนทับ (ดีที่สุด):                                       │
│  ┌──────────────────────────┐                                                │
│  │บริษัทก่อตั้งขึ้นในปี 2018│ ← Chunk 1                                       │
│  │รายได้เติบโต 300% ในปี 2024│ ← Chunk 2 (ซ้อนทับ 25%)                        │
│  │                            │ ← Chunk 3                                       │
│  └──────────────────────────┘                                                │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

การใช้งานใน n8n:

// Chunking ขั้นสูงด้วยตรรกะแบบ LangChain
const advancedChunking = {
  // กลยุทธ์ 1: Markdown-aware chunking
  markdown: {
    splitOn: ['# ', '## ', '### ', '\n\n', '\n'],
    preserveCodeBlocks: true,
    preserveTables: true,
    chunkSize: 1000,
    chunkOverlap: 200
  },
  
  // กลยุทธ์ 2: Semantic chunking โดยใช้ embeddings
  semantic: {
    // สร้าง embeddings สำหรับแต่ละประโยค
    sentenceEmbeddings: true,
    // จัดกลุ่มประโยคที่มี embeddings คล้ายกัน
    similarityThreshold: 0.85,
    minChunkSize: 100,
    maxChunkSize: 500,
    // รวมประโยคจนกว่าความคล้ายคลึงจะลดลง
    bufferSize: 3  // ดูประโยคก่อน/หลัง
  },
  
  // กลยุทธ์ 3: Agentic chunking (GPT-5.5)
  agentic: {
    // ใช้ GPT-5.5 เพื่อกำหนดจุดแบ่งที่เหมาะสม
    model: 'gpt-5.5',
    prompt: `
      วิเคราะห์เอกสารนี้และระบุจุดที่ดีที่สุดในการแบ่งเป็น chunks
      แต่ละ chunk ควร:
      - มี 300-500 token
      - มีความคิดหรือหัวข้อที่สมบูรณ์
      - ไม่แบ่งกลางประโยคหรือกลางย่อหน้า
      - รักษา context ภายในแต่ละ chunk
      
      ส่งคืนตำแหน่งการแบ่งเป็นหมายเลขบรรทัด
      
      เอกสาร:
      {{ $json.documentText }}
    `,
    // Parse response เพื่อรับขอบเขต chunk
    parseResponse: (response) => {
      const lines = response.split('\n');
      return lines.filter(l => l.match(/^\d+$/)).map(Number);
    }
  },
  
  // กลยุทธ์ 4: Parent-child chunking (สำหรับการรักษา context)
  parentChild: {
    // Parent chunks ขนาดใหญ่ (สำหรับการดึงข้อมูล)
    parentChunkSize: 2000,
    parentChunkOverlap: 400,
    
    // Child chunks ขนาดเล็ก (สำหรับการจับคู่ที่แม่นยำ)
    childChunkSize: 200,
    childChunkOverlap: 50,
    
    // เก็บทั้งสองและเชื่อมโยง
    indexingStrategy: 'dual',
    retrieval: 'child',  // ค้นหาบน children
    generation: 'parent'  // สร้างจาก parents
  },
  
  // กลยุทธ์ 5: Sliding window สำหรับ code/documentation
  slidingWindow: {
    windowSize: 10,      // บรรทัด
    stride: 3,          // ซ้อนทับ
    contextLines: 2,    // บรรทัดก่อน/หลัง
    // ผลลัพธ์: บรรทัด 1-10, 4-13, 7-16, etc.
  }
};

การใช้งาน Hybrid Chunking:

// n8n Function node สำหรับ hybrid chunking
const hybridChunking = ($input) => {
  const documents = $input.first().json.documents;
  const chunks = [];
  
  for (const doc of documents) {
    const content = doc.content;
    
    // ตรวจจับประเภทเอกสาร
    const isMarkdown = doc.fileType === 'md' || doc.fileType === 'markdown';
    const isCode = /\.(js|ts|py|java|cpp|go|rs)$/.test(doc.fileName);
    const isStructured = doc.fileType === 'json' || doc.fileType === 'csv';
    
    let docChunks;
    
    if (isMarkdown) {
      // ใช้ header-aware splitting
      docChunks = splitMarkdown(content, {
        chunkSize: 1000,
        overlap: 200
      });
    } else if (isCode) {
      // ใช้ AST-aware splitting (รักษา functions/classes)
      docChunks = splitCode(content, doc.fileType, {
        preserveStructure: true
      });
    } else if (isStructured) {
      // Row-based chunking สำหรับ structured data
      docChunks = splitStructured(content, {
        rowsPerChunk: 100,
        includeHeader: true
      });
    } else {
      // ค่าเริ่มต้น: recursive character
      docChunks = splitRecursive(content, {
        chunkSize: 512,
        overlap: 128,
        separators: ['\n\n', '\n', '. ', ' ']
      });
    }
    
    // เพิ่ม metadata ให้แต่ละ chunk
    docChunks.forEach((chunk, index) => {
      chunks.push({
        text: chunk.text,
        metadata: {
          ...doc.metadata,
          chunkIndex: index,
          totalChunks: docChunks.length,
          chunkStrategy: isMarkdown ? 'markdown' : isCode ? 'code' : 'recursive',
          charCount: chunk.text.length,
          tokenEstimate: chunk.text.length / 4  // ประมาณการ token คร่าวๆ
        }
      });
    });
  }
  
  return [{ json: { chunks } }];
};

// Markdown-aware splitter
function splitMarkdown(text, options) {
  const { chunkSize, overlap } = options;
  const chunks = [];
  const headers = text.match(/^#{1,6}\s.+$/gm) || [];
  
  let currentChunk = '';
  let currentSize = 0;
  
  const lines = text.split('\n');
  for (const line of lines) {
    const isHeader = /^#{1,6}\s/.test(line);
    const lineSize = line.length;
    
    // เริ่ม chunk ใหม่ที่ headers ถ้า chunk ปัจจุบันมีเนื้อหามาก
    if (isHeader && currentSize > chunkSize * 0.5) {
      chunks.push({ text: currentChunk.trim() });
      currentChunk = line;
      currentSize = lineSize;
    } else if (currentSize + lineSize > chunkSize) {
      chunks.push({ text: currentChunk.trim() });
      // รักษา overlap
      const overlapText = currentChunk.slice(-overlap);
      currentChunk = overlapText + '\n' + line;
      currentSize = overlap + lineSize;
    } else {
      currentChunk += '\n' + line;
      currentSize += lineSize;
    }
  }
  
  if (currentChunk) {
    chunks.push({ text: currentChunk.trim() });
  }
  
  return chunks;
}

การสร้าง RAG Pipeline แบบสมบูรณ์

เฟส 1: Document Ingestion Workflow

// n8n workflow แบบสมบูรณ์: เอกสาร → Vector Database
// ชื่อไฟล์: 44-rag-ingestion-workflow.json

{
  "name": "RAG Document Ingestion Pipeline",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "name": "Daily Sync Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [250, 300]
    },
    {
      "parameters": {
        "url": "https://api.company.com/documents",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "modified_since",
              "value": "={{ $getExecutionData('last_sync') || '1970-01-01' }}"
            }
          ]
        }
      },
      "name": "Fetch New Documents",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [450, 300]
    },
    {
      "parameters": {
        "jsCode": "// ประมวลผลเอกสารและดึงข้อความ\nconst documents = items[0].json.data || [];\nconst processed = [];\n\nfor (const doc of documents) {\n  // กำหนดวิธีการดึงข้อมูลตามประเภทไฟล์\n  const extraction = {\n    id: doc.id,\n    title: doc.title,\n    url: doc.url,\n    type: doc.file_type,\n    modified: doc.modified_at,\n    category: doc.category\n  };\n  \n  processed.push({ json: extraction });\n}\n\nreturn processed;"
      },
      "name": "Prepare Documents",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [650, 300]
    },
    {
      "parameters": {
        "mode": "json",
        "jsonMode": "=JSON.parse($json.extractionConfig || '{}')"
      },
      "name": "Split Batch",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [850, 300]
    },
    {
      "parameters": {
        "url": "={{ $json.url }}"
      },
      "name": "Download Document",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [1050, 300]
    },
    {
      "parameters": {
        "dataPropertyName": "data",
        "extraction": "pdfText",
        "options": {
          "keepPageNumbers": true,
          "keepMetadata": true
        }
      },
      "name": "Extract PDF Text",
      "type": "n8n-nodes-base.extractFromPDF",
      "typeVersion": 1,
      "position": [1250, 200]
    },
    {
      "parameters": {
        "extraction": "text",
        "options": {}
      },
      "name": "Extract DOCX Text",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [1250, 400]
    },
    {
      "parameters": {
        "jsCode": "// ตรรกะการแบ่งข้อความขั้นสูง\nconst content = $input.first().json.text;\nconst metadata = $input.first().json.metadata;\n\n// การแบ่งข้อความแบบ recursive character\nconst chunkSize = 512;\nconst overlap = 128;\nconst separators = ['\\n\\n', '\\n', '. ', ' '];\n\nconst chunks = [];\nlet currentChunk = '';\nlet currentSize = 0;\n\nconst sentences = content.split(/(?<=[.!?])\\s+/);\n\nfor (const sentence of sentences) {\n  const sentenceSize = sentence.length;\n  \n  if (currentSize + sentenceSize > chunkSize && currentChunk) {\n    chunks.push({\n      text: currentChunk.trim(),\n      metadata: {\n        ...metadata,\n        chunk_index: chunks.length,\n        char_count: currentSize\n      }\n    });\n    \n    // ใช้ overlap\n    const overlapStart = Math.max(0, currentChunk.length - overlap);\n    currentChunk = currentChunk.slice(overlapStart) + ' ' + sentence;\n    currentSize = currentChunk.length;\n  } else {\n    currentChunk += (currentChunk ? ' ' : '') + sentence;\n    currentSize += sentenceSize;\n  }\n}\n\nif (currentChunk) {\n  chunks.push({\n    text: currentChunk.trim(),\n    metadata: {\n      ...metadata,\n      chunk_index: chunks.length,\n      char_count: currentSize\n    }\n  });\n}\n\nreturn chunks.map(c => ({ json: c }));"
      },
      "name": "Chunk Documents",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1450, 300]
    },
    {
      "parameters": {
        "options": {},
        "prompt": "={{ $json.text }}",
        "model": "text-embedding-3-large"
      },
      "name": "Generate Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1,
      "position": [1650, 300]
    },
    {
      "parameters": {
        "mode": "insert",
        "options": {
          "qdrantCollection": "company-knowledge-base"
        },
        "points": {
          "id": "={{ $json.metadata.chunk_index + '-' + $json.metadata.doc_id }}",
          "vector": "={{ $json.embedding }}",
          "payload": {
            "text": "={{ $json.text }}",
            "metadata": "={{ $json.metadata }}"
          }
        }
      },
      "name": "Store in Qdrant",
      "type": "n8n-nodes-base.vectorStoreQdrant",
      "typeVersion": 1,
      "position": [1850, 300]
    },
    {
      "parameters": {
        "jsCode": "// ติดตามการ index ที่สำเร็จ\nconst result = {\n  document_id: $input.first().json.metadata.doc_id,\n  chunks_indexed: $input.first().json.metadata.chunk_index + 1,\n  indexed_at: new Date().toISOString()\n};\n\n// ส่งไปยัง monitoring/alerting\nreturn [{ json: result }];"
      },
      "name": "Track Indexing",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [2050, 300]
    }
  ],
  "connections": {
    "Daily Sync Trigger": {
      "main": [[{"node": "Fetch New Documents", "type": "main", "index": 0}]]
    },
    "Fetch New Documents": {
      "main": [[{"node": "Prepare Documents", "type": "main", "index": 0}]]
    },
    "Prepare Documents": {
      "main": [[{"node": "Split Batch", "type": "main", "index": 0}]]
    },
    "Split Batch": {
      "main": [[{"node": "Download Document", "type": "main", "index": 0}]]
    },
    "Download Document": {
      "main": [
        [{"node": "Extract PDF Text", "type": "main", "index": 0}],
        [{"node": "Extract DOCX Text", "type": "main", "index": 0}]
      ]
    },
    "Extract PDF Text": {
      "main": [[{"node": "Chunk Documents", "type": "main", "index": 0}]]
    },
    "Extract DOCX Text": {
      "main": [[{"node": "Chunk Documents", "type": "main", "index": 0}]]
    },
    "Chunk Documents": {
      "main": [[{"node": "Generate Embeddings", "type": "main", "index": 0}]]
    },
    "Generate Embeddings": {
      "main": [[{"node": "Store in Qdrant", "type": "main", "index": 0}]]
    },
    "Store in Qdrant": {
      "main": [[{"node": "Track Indexing", "type": "main", "index": 0}]]
    }
  }
}

เฟส 2: Query และ Retrieval Workflow

// n8n workflow แบบสมบูรณ์: คำถามผู้ใช้ → RAG คำตอบ
// ชื่อไฟล์: 44-rag-query-workflow.json

{
  "name": "RAG Query and Response Pipeline",
  "nodes": [
    {
      "parameters": {
        "path": "rag-query",
        "responseMode": "responseNode"
      },
      "name": "RAG API Endpoint",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [250, 300]
    },
    {
      "parameters": {
        "options": {},
        "prompt": "={{ $json.query.body.query }}",
        "model": "text-embedding-3-large"
      },
      "name": "Embed Query",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1,
      "position": [450, 300]
    },
    {
      "parameters": {
        "mode": "retrieve",
        "options": {
          "qdrantCollection": "company-knowledge-base",
          "topK": 10
        },
        "filter": {
          "category": "={{ $json.query.body.category || undefined }}"
        }
      },
      "name": "Retrieve from Qdrant",
      "type": "n8n-nodes-base.vectorStoreQdrant",
      "typeVersion": 1,
      "position": [650, 300]
    },
    {
      "parameters": {
        "jsCode": "// Re-rank เอกสารที่ดึงมา\nconst docs = $input.all()[0].json;\nconst query = $getWorkflowStaticData('query');\n\n// คะแนนแบบง่าย BM25-style สำหรับ re-ranking\nconst queryTerms = query.toLowerCase().split('\\s+');\nconst scored = docs.map(doc => {\n  const text = doc.metadata.text.toLowerCase();\n  let score = doc.score; // ความคล้ายคลึง vector เดิม\n  \n  // Boost สำหรับ exact term matches\n  for (const term of queryTerms) {\n    const matches = (text.match(new RegExp(term, 'g')) || []).length;\n  score += matches * 0.05;\n  }\n  \n  // Boost สำหรับความใหม่\n  const docDate = new Date(doc.metadata.metadata.modified || doc.metadata.metadata.created);\n  const daysOld = (Date.now() - docDate) / (1000 * 60 * 60 * 24);\n  score += Math.max(0, 0.1 - daysOld * 0.001);\n  \n  return { ...doc, rerankedScore: score };\n});\n\n// เรียงตาม re-ranked score และเอา top 5\nconst topDocs = scored\n  .sort((a, b) => b.rerankedScore - a.rerankedScore)\n  .slice(0, 5);\n\nreturn [{ json: { documents: topDocs, query } }];"
      },
      "name": "Re-rank Results",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [850, 300]
    },
    {
      "parameters": {
        "jsCode": "// สร้าง context สำหรับ LLM\nconst docs = $input.first().json.documents;\nconst query = $input.first().json.query;\n\n// จัดรูปแบบเอกสารพร้อมการระบุแหล่งที่มา\nconst context = docs.map((doc, i) => \`[${i + 1}] ${doc.metadata.metadata.title}\nSource: ${doc.metadata.metadata.source}\nContent: ${doc.metadata.text}\n---\`).join('\\n\\n');\n\nconst sources = docs.map(doc => ({\n  title: doc.metadata.metadata.title,\n  source: doc.metadata.metadata.source,\n  score: Math.round(doc.rerankedScore * 100) / 100\n}));\n\nreturn [{\n  json: {\n    query,\n    context,\n    sources,\n    documentCount: docs.length\n  }\n}];"
      },
      "name": "Build Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1050, 300]
    },
    {
      "parameters": {
        "model": "gpt-5.5",
        "options": {
          "temperature": 0.3,
          "maxTokens": 1500
        },
        "messages": {
          "message": [
            {
              "role": "system",
              "content": "คุณเป็นผู้ช่วยที่ตอบคำถามตาม context ที่ให้มา\\n\\nคำสั่ง:\\n1. ตอบโดยใช้เฉพาะข้อมูลใน context ที่ให้มา\\n2. หาก context ไม่มีคำตอบ ให้ระบุอย่างชัดเจน\\n3. อ้างอิงแหล่งที่มาด้วย [1], [2] ฯลฯ เสมอ\\n4. กระชับแต่ครบถ้วน\\n5. หากต้องสมมติ ให้ระบุอย่างชัดเจน"
            },
            {
              "role": "user",
              "content": "=Context:\\n{{ $json.context }}\\n\\nคำถาม: {{ $json.query }}\\n\\nให้คำตอบที่ครอบคลุมพร้อมการอ้างอิงแหล่งที่มา"
            }
          ]
        }
      },
      "name": "Generate Response",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1.8,
      "position": [1250, 300]
    },
    {
      "parameters": {
        "jsCode": "// ประกอบคำตอบสุดท้าย\nconst llmResponse = $input.first().json.content;\nconst context = $getWorkflowStaticData('context');\n\nreturn [{\n  json: {\n    answer: llmResponse,\n    sources: context.sources,\n    tokens_used: $input.first().json.usage?.total_tokens || null,\n    query_time_ms: Date.now() - ($getWorkflowStaticData('startTime') || Date.now()),\n    retrieved_documents: context.documentCount\n  }\n}];"
      },
      "name": "Format Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1450, 300]
    },
    {
      "parameters": {
        "respondWith": "json",
        "json": "={{ JSON.stringify($json) }}"
      },
      "name": "Return Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [1650, 300]
    }
  ],
  "connections": {
    "RAG API Endpoint": {
      "main": [[{"node": "Embed Query", "type": "main", "index": 0}]]
    },
    "Embed Query": {
      "main": [[{"node": "Retrieve from Qdrant", "type": "main", "index": 0}]]
    },
    "Retrieve from Qdrant": {
      "main": [[{"node": "Re-rank Results", "type": "main", "index": 0}]]
    },
    "Re-rank Results": {
      "main": [[{"node": "Build Context", "type": "main", "index": 0}]]
    },
    "Build Context": {
      "main": [[{"node": "Generate Response", "type": "main", "index": 0}]]
    },
    "Generate Response": {
      "main": [[{"node": "Format Response", "type": "main", "index": 0}]]
    },
    "Format Response": {
      "main": [[{"node": "Return Response", "type": "main", "index": 0}]]
    }
  }
}

รูปแบบ RAG ขั้นสูง

รูปแบบที่ 1: Multi-Query Retrieval

เมื่อ query เดียวอาจพลาด context ที่สำคัญ ให้สร้างหลายรูปแบบ:

// การขยาย multi-query เพื่อการดึงข้อมูลที่ดีขึ้น
const multiQueryConfig = {
  originalQuery: "นโยบายการคืนเงินของเราคืออะไร",
  
  // สร้าง 3-5 รูปแบบโดยใช้ GPT-5.5
  expansionPrompt: `
    สร้าง 3 วิธีต่างกันที่บางคนอาจถามคำถามต่อไปนี้
    แต่ละรูปแบบควรเข้าหาคำถามจากมุมมองที่แตกต่างกัน
    
    ต้นฉบับ: {{ $json.query }}
    
    ส่งคืนเป็น JSON array ของ strings
  `,
  
  generatedQueries: [
    "นโยบายการคืนเงินของเราคืออะไร",
    "ฉันจะได้รับเงินคืนได้อย่างไร",
    "นโยบายการคืนสินค้าคืออะไร",
    "ฉันขอคืนเงินได้ไหม",
    "เงื่อนไขการคืนเงินคืออะไร"
  ],
  
  // ดึงข้อมูลสำหรับแต่ละ query
  retrievalStrategy: 'parallel',
  
  // รวมผลลัพธ์ ลบซ้ำ จัดอันดับใหม่
  mergeStrategy: {
    deduplication: 'semantic',  // ลบ chunks ที่ซ้ำกัน
    ranking: 'reciprocal',      // Reciprocal Rank Fusion
    topK: 10
  }
};

// Reciprocal Rank Fusion scoring
function reciprocalRankFusion(results) {
  const k = 60;  // RRF constant
  const scores = new Map();
  
  for (const [queryIndex, queryResults] of results.entries()) {
    for (const [rank, doc] of queryResults.entries()) {
      const docId = doc.metadata.chunk_id;
      const currentScore = scores.get(docId) || 0;
      // RRF score: 1 / (k + rank)
      scores.set(docId, currentScore + 1 / (k + rank + 1));
    }
  }
  
  // เรียงตาม fused score
  return Array.from(scores.entries())
    .sort((a, b) => b[1] - a[1])
    .map(([id, score]) => ({ id, score }));
}

รูปแบบที่ 2: Hypothetical Document Embeddings (HyDE)

สร้างคำตอบที่เหมาะสมที่สุดก่อน แล้ว embed สำหรับการดึงข้อมูล:

// HyDE pattern implementation
const hydeConfig = {
  // ขั้นตอนที่ 1: สร้างคำตอบสมมุติ (โดยไม่ดึงข้อมูล)
  hypotheticalPrompt: `
    จินตนาการว่าคุณมีสิทธิ์เข้าถึงเอกสารของบริษัททั้งหมด
    เขียนคำตอบที่ละเอียดและเป็นข้อเท็จจริงสำหรับคำถามนี้
    
    คำถาม: {{ $json.query }}
    
    เขียนคำตอบราวกับว่าคุณกำลังอ้างอิงจากเอกสารโดยตรง
    รวมรายละเอียดเฉพาะ วันที่ และการอ้างอิง
  `,
  
  // ใช้ GPT-5.5 สำหรับการสร้างเอกสารสมมุติ
  generationModel: 'gpt-5.5',
  temperature: 0.7,  // สร้างสรรค์เล็กน้อย
  maxTokens: 500,
  
  // ขั้นตอนที่ 2: Embed คำตอบสมมุติ
  embeddingModel: 'text-embedding-3-large',
  
  // ขั้นตอนที่ 3: ดึงข้อมูลโดยใช้ embedding สมมุติ
  // มักจะพบเอกสารที่ไม่ตรงกับ query ต้นฉบับ
};

// n8n workflow สำหรับ HyDE
const hydeWorkflow = [
  {
    node: "รับคำถาม",
    type: "webhook"
  },
  {
    node: "สร้างคำตอบสมมุติ",
    type: "openAi",
    config: {
      model: "gpt-5.5",
      prompt: hydeConfig.hypotheticalPrompt,
      temperature: 0.7
    }
  },
  {
    node: "Embed คำตอบสมมุติ",
    type: "embeddingsOpenAi",
    input: "={{ $json.hypotheticalAnswer }}"
  },
  {
    node: "ดึงเอกสาร",
    type: "vectorStoreQdrant",
    vector: "={{ $json.embedding }}",
    topK: 10
  },
  {
    node: "สร้างคำตอบสุดท้าย",
    type: "openAi",
    // ใช้เอกสารที่ดึงมา ACTUAL
    context: "={{ $json.retrievedDocuments }}"
  }
];

รูปแบบที่ 3: Self-Reflective RAG

ให้ระบบตรวจสอบคำตอบของตัวเองและทำซ้ำ:

// Self-reflective RAG พร้อมการตรวจสอบ
const reflectiveRag = {
  maxIterations: 3,
  
  verificationPrompt: `
    ตรวจสอบว่าคำตอบนี้ได้รับการสนับสนุนโดยสมบูรณ์จาก context ที่ให้มา
    
    คำตอบ: {{ $json.answer }}
    Context: {{ $json.context }}
    
    ตรวจสอบ:
    1. Hallucinations (ข้อมูลที่ไม่มีใน context)
    2. ข้อความอ้างอิงที่ไม่มีหลักฐานสนับสนุน
    3. ข้อมูลที่เกี่ยวข้องที่ขาดหายไป
    
    ส่งคืน JSON:
    {
      "isVerified": boolean,
      "confidence": 0-1,
      "issues": ["รายการปัญหา"],
      "additionalQueries": ["คำถามเพื่อหาข้อมูลที่ขาด"]
    }
  `,
  
  // หากการตรวจสอบล้มเหลว ให้ดึงข้อมูลเพิ่มเติม
  iterationLogic: async (state) => {
    const verification = await verifyAnswer(state.answer, state.context);
    
    if (verification.isVerified || state.iteration >= reflectiveRag.maxIterations) {
      return { 
        finalAnswer: state.answer, 
        verified: verification.isVerified,
        iterations: state.iteration 
      };
    }
    
    // ดึงเอกสารเพิ่มเติม
    const newDocs = await retrieveDocuments(verification.additionalQueries);
    const newContext = mergeContexts(state.context, newDocs);
    
    // สร้างคำตอบใหม่ด้วย context ที่ขยาย
    const newAnswer = await generateAnswer(state.query, newContext);
    
    return reflectiveRag.iterationLogic({
      ...state,
      answer: newAnswer,
      context: newContext,
      iteration: state.iteration + 1
    });
  }
};

รูปแบบที่ 4: Hierarchical RAG

สำหรับ knowledge base ขนาดใหญ่ ให้ใช้ระบบดึงข้อมูลสองระดับ:

// Hierarchical retrieval สำหรับ knowledge bases องค์กร
const hierarchicalRag = {
  // ระดับ 1: ดัชนีสรุป (เล็กกว่า เร็วกว่า)
  summaryIndex: {
    collection: 'document-summaries',
    embeddingModel: 'text-embedding-3-small',  // ถูกกว่า
    chunkSize: 'document-level',
    content: ' สรุปของเอกสารทั้งฉบับ'
  },
  
  // ระดับ 2: ดัชนีเนื้อหาเต็ม (ละเอียด)
  detailIndex: {
    collection: 'document-chunks',
    embeddingModel: 'text-embedding-3-large',  // คุณภาพสูงกว่า
    chunkSize: 512,
    content: 'เอกสาร chunks แบบเต็ม'
  },
  
  // กระแส query
  queryProcess: [
    // ขั้นตอนที่ 1: Query ดัชนีสรุปเพื่อหาเอกสารที่เกี่ยวข้อง
    {
      action: 'retrieve',
      index: 'summaryIndex',
      topK: 5,
      result: 'relevantDocuments'
    },
    
    // ขั้นตอนที่ 2: กรองดัชนีรายละเอียดเป็นเอกสารเหล่านั้น
    {
      action: 'filter',
      index: 'detailIndex',
      filter: {
        doc_id: { $in: '{{ $json.relevantDocuments.map(d => d.doc_id) }}' }
      }
    },
    
    // ขั้นตอนที่ 3: ดึง chunks ละเอียดจากชุดที่กรองแล้ว
    {
      action: 'retrieve',
      index: 'detailIndex',
      topK: 10,
      result: 'detailedChunks'
    }
  ],
  
  // ประสิทธิภาพ: เร็วขึ้น 5 เท่าบน KB ขนาดใหญ่
  // ต้นทุน: ลดค่าใช้จ่าย embedding 60%
};

การปรับแต่งสำหรับ Production

กลยุทธ์การแคช

// การแคชหลายระดับสำหรับระบบ RAG
const cachingLayers = {
  // ระดับที่ 1: แคช query embedding
  embeddingCache: {
    store: 'redis',
    key: 'embedding:{{ md5($json.query) }}',
    ttl: 86400,  // 24 ชั่วโมง
    hitRate: '35%'  // Query ทั่วไป
  },
  
  // ระดับที่ 2: แคชผลลัพธ์การดึงข้อมูล
  retrievalCache: {
    store: 'redis',
    key: 'retrieve:{{ md5($json.queryEmbedding) }}:{{ $json.filterHash }}',
    ttl: 3600,   // 1 ชั่วโมง
    hitRate: '28%',
    // ยกเลิกเมื่อมีการอัปเดตเอกสาร
    tags: ['knowledge-base']
  },
  
  // ระดับที่ 3: แคชคำตอบที่สร้าง (สำหรับ query เดียวกัน)
  responseCache: {
    store: 'redis',
    key: 'response:{{ md5($json.query) }}:{{ md5($json.context) }}',
    ttl: 1800,   // 30 นาที
    hitRate: '15%',
    // ไม่แคชหาก context เปลี่ยน
    conditional: '!$json.contextChanged'
  },
  
  // Cache warming สำหรับคำถามยอดนิยม
  warming: {
    schedule: '0 2 * * *',  // ตี 2 ทุกวัน
    queries: [
      'บริการของคุณมีอะไรบ้าง',
      'ฉันจะติดต่อฝ่ายสนับสนุนได้อย่างไร',
      'เวลาทำการของคุณคือเมื่อไหร่'
    ]
  }
};

การประหยัดต้นทุนด้วย GPT-5.5

// RAG ที่ปรับแต่งต้นทุนด้วย GPT-5.5
const costOptimization = {
  // GPT-5.5 มีประสิทธิภาพ token สูงกว่า 40%
  tokenEfficiency: 0.6,  // ลด 40%
  
  // การเลือกโมเดลแบบ tiered
  modelSelection: {
    // Query ง่าย: GPT-5.5-mini (เร็วที่สุด ถูกที่สุด)
    condition: '{{ $json.complexityScore < 0.3 }}',
    model: 'gpt-5.5-mini',
    cost: '$0.002 / 1K tokens',
    
    // Query มาตรฐาน: GPT-5.5 (สมดุล)
    condition: '{{ $json.complexityScore >= 0.3 && $json.complexityScore < 0.8 }}',
    model: 'gpt-5.5',
    cost: '$0.015 / 1K tokens',
    
    // Query ซับซ้อน: GPT-5.5-reasoning (คุณภาพดีที่สุด)
    condition: '{{ $json.complexityScore >= 0.8 }}',
    model: 'gpt-5.5-reasoning',
    cost: '$0.03 / 1K tokens'
  },
  
  // การวิเคราะห์ความซับซ้อน
  complexityAnalysis: {
    factors: [
      { name: 'queryLength', weight: 0.2 },
      { name: 'numEntities', weight: 0.3 },
      { name: 'reasoningRequired', weight: 0.5 }
    ]
  },
  
  // การประมวลผลเป็นชุดสำหรับการจัดทำดัชนี
  batchConfig: {
    embeddingBatchSize: 100,  // สูงสุดสำหรับ OpenAI
    upsertBatchSize: 50,      // Vector DB optimal
    parallelBatches: 5        // ประมวลผลพร้อมกัน
  },
  
  // การคาดการณ์ต้นทุนรายเดือนสำหรับ 100K query
  costProjection: {
    gpt4: '$4,500',
    gpt5_4: '$3,200',
    gpt5_5: '$1,920',  // ประหยัด 40%
    gpt5_5WithTiers: '$1,440'  // ประหยัดรวม 68%
  }
};

การติดตามและการสังเกตการณ์

// การติดตาม RAG อย่างครอบคลุม
const ragMonitoring = {
  // การติดตาม latency
  latencyMetrics: {
    embedding: { p50: '<100ms', p99: '<500ms' },
    retrieval: { p50: '<50ms', p99: '<200ms' },
    generation: { p50: '<1s', p99: '<3s' },
    e2e: { p50: '<1.5s', p99: '<4s' }
  },
  
  // ตัวชี้วัดคุณภาพ
  qualityMetrics: {
    retrieval: {
      precision: '0.85',  // % ของเอกสารที่ดึงมาซึ่งเกี่ยวข้อง
      recall: '0.78',     // % ของเอกสารที่เกี่ยวข้องซึ่งดึงมา
      mrr: '0.82'         // Mean Reciprocal Rank
    },
    generation: {
      relevance: '4.3/5',     // การประเมินของมนุษย์
      faithfulness: '0.91',   // % ที่ได้รับการสนับสนุนจาก context
      citationAccuracy: '0.88'
    }
  },
  
  // การติดตามข้อผิดพลาด
  errorTracking: {
    categories: [
      'retrieval_empty',      // ไม่พบเอกสาร
      'context_too_long',     // Context เกิน token limit
      'generation_error',     // LLM API error
      'hallucination_detected'
    ],
    alerting: {
      threshold: 5,  // แจ้งเตือนหลังจาก 5 ข้อผิดพลาดใน 5 นาที
      channels: ['slack', 'pagerduty']
    }
  },
  
  // การติดตาม feedback ของผู้ใช้
  feedback: {
    thumbsUpDown: true,
    commentCapture: true,
    correctionTracking: true,
    // ปรับปรุงโมเดลอัตโนมัติจาก feedback
    feedbackLoop: 'weekly-retrain'
  }
};

// n8n monitoring workflow
const monitoringWorkflow = {
  trigger: 'webhook',
  nodes: [
    {
      name: 'Parse RAG Request',
      extract: ['query', 'responseTime', 'tokenUsage', 'cacheHit']
    },
    {
      name: 'ส่งไปยัง Prometheus',
      type: 'httpRequest',
      url: 'http://prometheus:9090/metrics',
      body: `
        rag_query_latency{{ query_type="{{ $json.type }}" }} {{ $json.responseTime }}
        rag_token_usage{{ model="{{ $json.model }}" }} {{ $json.tokenUsage }}
        rag_cache_hit{{ layer="{{ $json.cacheLayer }}" }} {{ $json.cacheHit ? 1 : 0 }}
      `
    },
    {
      name: 'แจ้งเตือนหากเกินเกณฑ์',
      type: 'if',
      condition: '{{ $json.responseTime > 4000 || $json.tokenUsage > 4000 }}'
    },
    {
      name: 'ส่งการแจ้งเตือน',
      type: 'slack',
      message: 'RAG performance alert: Query ใช้เวลา {{ $json.responseTime }}ms'
    }
  ]
};

กรณีการใช้งานจริง

กรณีการใช้งานที่ 1: Knowledge Base ฝ่ายสนับสนุนลูกค้า

// การใช้งาน RAG สำหรับฝ่ายสนับสนุนลูกค้า
const supportRag = {
  knowledgeSources: [
    { type: 'zendesk', collections: ['articles', 'tickets'] },
    { type: 'confluence', spaces: ['support', 'product'] },
    { type: 'pdf', path: '/kb/product-guides' }
  ],
  
  // การผสานรวมประวัติการสนทนา
  contextManagement: {
    // รักษา context การสนทนาข้าม turns
    sessionStore: 'redis',
    ttl: 3600,  // 1 ชั่วโมง
    
    // รวม context ก่อนหน้าในการดึงข้อมูล
    queryExpansion: `
      การสนทนาก่อนหน้า:\n{{ $json.conversationHistory }}\n\nคำถามปัจจุบัน: {{ $json.query }}
    `,
    
    // ติดตามสถานะแก้ไข/ไม่แก้ไข
    resolutionTracking: true
  },
  
  // กฎการส่งต่อให้มนุษย์
  escalation: {
    triggers: [
      { condition: 'confidence < 0.7', action: 'suggest_human' },
      { condition: 'sentiment < -0.5', action: 'escalate_immediately' },
      { condition: 'intent == "billing_dispute"', action: 'escalate_immediately' }
    ]
  },
  
  // ตัวชี้วัดประสิทธิภาพ
  metrics: {
    deflectionRate: '67%',      // % แก้ไขได้โดยไม่ต้องใช้มนุษย์
    avgResponseTime: '1.2s',    // End-to-end
    csat: '4.4/5',              // ความพึงพอใจของลูกค้า
    costPerQuery: '$0.08'       // เทียบกับ $4.50 สำหรับ agent มนุษย์
  }
};

กรณีการใช้งานที่ 2: การสนับสนุนการขายด้วย RAG

// การขาย RAG สำหรับการสร้างข้อเสนอ
const salesRag = {
  knowledgeSources: [
    { type: 'crm', data: 'opportunities,contacts,accounts' },
    { type: 'documents', path: '/sales/case-studies' },
    { type: 'documents', path: '/sales/proposal-templates' },
    { type: 'database', table: 'pricing_matrix' }
  ],
  
  // การปรับแต่งแบบไดนามิก
  personalization: {
    // ดึง context ลูกค้าจาก CRM
    clientData: '{{ $json.crmData }}',
    
    // ปรับการดึงข้อมูลตามอุตสาหกรรมของลูกค้า
    industryBoost: '{{ $json.crmData.industry }}',
    
    // รวม case studies ที่เกี่ยวข้อง
    caseStudyFilter: 'industry == "{{ $json.crmData.industry }}"'
  },
  
  // workflow การสร้างข้อเสนอ
  proposalGeneration: {
    steps: [
      { name: 'retrieveCompanyInfo', query: '{{ $json.clientName }} company overview' },
      { name: 'retrievePainPoints', query: '{{ $json.clientIndustry }} common challenges' },
      { name: 'retrieveSolutions', query: 'solutions for {{ $json.painPoints }}' },
      { name: 'retrieveCaseStudies', query: '{{ $json.clientIndustry }} case studies' },
      { name: 'generateProposal', model: 'gpt-5.5', template: 'formal_proposal' }
    ],
    
    // การจัดรูปแบบ output
    output: {
      format: 'docx',
      sections: ['executive_summary', 'solution', 'pricing', 'timeline', 'case_studies'],
      branding: 'auto_apply'
    }
  },
  
  // ประสิทธิภาพ
  metrics: {
    proposalGenerationTime: '3 นาที',  // เทียบกับ 4 ชั่วโมงด้วยมือ
    winRateImprovement: '+23%',
    repProductivity: '+40%'
  }
};

กรณีการใช้งานที่ 3: การวิเคราะห์เอกสารทางกฎหมาย

// การใช้งาน RAG ทางกฎหมายสำหรับการวิเคราะห์สัญญา
const legalRag = {
  // การควบคุมการเข้าถึงอย่างเข้มงวด
  accessControl: {
    authentication: 'sso',
    authorization: 'role-based',
    auditLogging: true,
    dataRetention: '7_years'
  },
  
  knowledgeSources: [
    { type: 'documents', path: '/contracts/active', access: 'attorney_only' },
    { type: 'documents', path: '/legal-precedents', access: 'all_legal' },
    { type: 'documents', path: '/regulatory', access: 'compliance_team' }
  ],
  
  // ความต้องการการอ้างอิง
  citation: {
    required: true,
    format: 'legal_citation',
    includePageNumbers: true,
    includeClauseNumbers: true,
    linkToDocument: true
  },
  
  // การวิเคราะห์ความเสี่ยง
  riskAnalysis: {
    enabled: true,
    categories: ['liability', 'termination', 'indemnification', 'ip_rights'],
    highlightRiskClauses: true,
    suggestAlternatives: true
  },
  
  // การเลือกโมเดล
  model: 'gpt-5.5',  // การให้เหตุผลที่ดีกว่าสำหรับข้อความทางกฎหมาย
  temperature: 0.1,  // ระมัดระวังสำหรับกฎหมาย
  
  // การปฏิบัติตามกฎระเบียบ
  compliance: {
    barAssociation: 'approved',
    clientConfidentiality: 'encrypted_at_rest_and_in_transit',
    aiDisclosure: 'included_in_output'
  }
};

รูปแบบการผสานรวม

n8n + Directus สำหรับการจัดการเนื้อหา

// Directus CMS integration สำหรับเนื้อหา RAG
const directusIntegration = {
  // ซิงค์ Directus content กับ vector database
  syncConfig: {
    trigger: 'directus.hook',
    events: ['items.create', 'items.update', 'items.delete'],
    collections: ['articles', 'documentation', 'faqs'],
    
    // แปลง Directus content
    transform: {
      // รวมหลาย fields
      text: '{{ $json.content }}\n\n{{ $json.excerpt }}',
      
      // ดึง metadata
      metadata: {
        title: '{{ $json.title }}',
        slug: '{{ $json.slug }}',
        category: '{{ $json.category.name }}',
        tags: '{{ $json.tags.map(t => t.name) }}',
        author: '{{ $json.user_created.first_name }}',
        published: '{{ $json.date_published }}',
        status: '{{ $json.status }}'
      }
    },
    
    // กรองเฉพาะ content ที่เผยแพร่แล้ว
    filter: 'status == "published"'
  },
  
  // Query Directus จาก RAG
  queryIntegration: {
    // เมื่อ RAG พบ chunk ที่เกี่ยวข้อง ดึงเนื้อหาเต็มจาก Directus
    enrichment: {
      endpoint: 'https://directus.company.com/items/articles/{{ $json.metadata.slug }}',
      fields: ['content', 'related_articles', 'attachments'],
      includeRelations: true
    }
  },
  
  // อัปเดต Directus ด้วย RAG analytics
  feedbackLoop: {
    // ติดตามว่าเนื้อหาใดมีประโยชน์ที่สุด
    queryLog: 'directus.rag_queries',
    
    // อัปเดตความนิยมของบทความ
    popularityMetric: {
      collection: 'articles',
      field: 'rag_retrieval_count',
      increment: 1
    }
  }
};

n8n + Slack สำหรับความรู้ทีม

// Slack integration สำหรับความรู้ทีม
const slackIntegration = {
  // จัดทำดัชนีการสนทนา Slack
  indexing: {
    channels: ['#knowledge-base', '#product-discussions', '#engineering'],
    excludeBots: true,
    excludeCommands: true,
    
    // การรักษา context ของ thread
    threadContext: {
      includeParent: true,
      includeReplies: true,
      maxThreadDepth: 5
    }
  },
  
  // Slack bot สำหรับ query
  bot: {
    trigger: '@knowledgebot',
    
    // ตอบใน thread
    responseMode: 'thread',
    
    // รวมลิงก์แหล่งที่มา
    includeSources: true,
    
    // สรุปสำหรับ Slack
    summarize: {
      maxLength: 3000,  // Slack message limit
      includeHighlights: true
    }
  },
  
  // เรียนรู้จาก reactions
  feedback: {
    thumbsUp: 'positive_feedback',
    thumbsDown: 'negative_feedback',
    
    // ปรับปรุงอัตโนมัติตาม reactions
    retraining: 'weekly'
  }
};

ความปลอดภัยและความเป็นส่วนตัว

การปกป้องข้อมูล

// Security configuration สำหรับระบบ RAG
const securityConfig = {
  // Encryption ขณะเก็บ
  encryption: {
    vectors: 'aes-256-gcm',
    metadata: 'aes-256-gcm',
    backups: 'aes-256-gcm'
  },
  
  // Encryption ขณะส่ง
  tls: {
    version: '1.3',
    certificates: 'letsencrypt',
    hsts: true
  },
  
  // การควบคุมการเข้าถึง
  rbac: {
    roles: [
      { name: 'admin', permissions: ['read', 'write', 'delete', 'configure'] },
      { name: 'editor', permissions: ['read', 'write'] },
      { name: 'viewer', permissions: ['read'] }
    ],
    
    // Row-level security บนเอกสาร
    documentLevel: true
  },
  
  // Audit logging
  audit: {
    events: ['query', 'ingest', 'update', 'delete', 'access_denied'],
    retention: '2_years',
    tamperProof: true
  },
  
  // การจัดการ PII
  pii: {
    detection: 'automatic',
    redaction: 'mask',  // หรือ 'remove', 'hash'
    entities: ['email', 'phone', 'ssn', 'credit_card', 'name'],
    
    // ไม่จัดทำดัชนี PII ใน vectors
    excludeFromEmbedding: true
  },
  
  // Data residency
  residency: {
    vectors: 'eu-west-1',  // สอดคล้อง GDPR
    backups: 'eu-central-1'
  }
};

การทดสอบและการตรวจสอบความถูกต้อง

RAG Evaluation Framework

// RAG testing อย่างครอบคลุม
const ragEvaluation = {
  // ชุดข้อมูลทดสอบ
  datasets: {
    // คำถามพร้อมคำตอบที่ทราบ
    qaPairs: [
      {
        question: 'นโยบายการคืนเงินของเราคืออะไร',
        expectedAnswer: 'เราเสนอการคืนเงินเต็มจำนวนภายใน 30 วัน',
        expectedSources: ['policies/refund.pdf']
      }
    ],
    
    // Edge cases
    edgeCases: [
      { question: 'asdfghjkl', expectedBehavior: 'graceful_fallback' },
      { question: '2+2 เท่ากับเท่าไหร่', expectedBehavior: 'no_hallucination' }
    ]
  },
  
  // ตัวชี้วัด
  metrics: {
    // Retrieval metrics
    hitRate: {
      @1: 0.75,   // Top 1 เกี่ยวข้อง
      @5: 0.90,   // เกี่ยวข้องใน top 5
      @10: 0.95   // เกี่ยวข้องใน top 10
    },
    
    // Generation metrics
    bleu: 0.45,
    rouge: 0.52,
    faithfulness: 0.88,
    answerRelevance: 0.91,
    
    // Latency
    p95Latency: '< 3 วินาที'
  },
  
  // การทดสอบอัตโนมัติใน n8n
  testWorkflow: [
    {
      node: 'โหลดชุดข้อมูลทดสอบ',
      type: 'readBinaryFile',
      path: '/tests/rag-test-cases.json'
    },
    {
      node: 'รันการทดสอบ Query',
      type: 'httpRequest',
      url: 'https://api.company.com/rag-query',
      batchSize: 10
    },
    {
      node: 'คำนวณตัวชี้วัด',
      type: 'code',
      code: `
        const results = $input.all();
        const metrics = calculateMetrics(results);
        return [{ json: metrics }];
      `
    },
    {
      node: 'เปรียบเทียบกับเกณฑ์',
      type: 'if',
      condition: '{{ $json.hitRate@5 >= 0.90 }}'
    },
    {
      node: 'รายงานผลลัพธ์',
      type: 'slack',
      message: 'RAG evaluation เสร็จสิ้น Hit rate @5: {{ $json.hitRate@5 }}'
    }
  ]
};

บทสรุป

Retrieval-Augmented Generation เป็นความก้าวหน้าที่สำคัญที่สุดใน AI องค์กรตั้งแต่การแนะนำ Large Language Models ด้วยความสามารถในการให้เหตุผลที่ดีขึ้นของ GPT-5.5 รวมกับ vector database ที่มีสถาปัตยกรรมดีและกลยุทธ์การดึงข้อมูลที่ชาญฉลาด องค์กรสามารถสร้างระบบอัตโนมัติที่เน้นความรู้ที่มีความแม่นยำ ตรวจสอบได้ และคุ้มค่า

รูปแบบและการใช้งานที่ครอบคลุมในคู่มือนี้ - ตั้งแต่การนำเข้าเอกสารพื้นฐานไปจนถึงการดึงข้อมูล multi-query ขั้นสูง จากการปรับแต่งต้นทุนไปจนถึงการติดตาม production - ให้พื้นฐานที่ครอบคลุมสำหรับการสร้างระบบ RAG ที่ scale เมื่อ GPT-5.5 ยังคงเปิดตัวข้ามแพลตฟอร์มและเทคโนโลยี vector database เติบโต เราคาดว่า RAG จะกลายเป็นสถาปัตยกรรมมาตรฐานสำหรับแอปพลิเคชัน AI องค์กร

ข้อควรจำสำคัญ:

  1. Chunking สำคัญ: วิธีที่คุณแบ่งเอกสารมีผลกระทบต่อคุณภาพ RAG มากกว่าปัจจัยอื่นใด ลงทุนในกลยุทธ์การแบ่งข้อความที่ชาญฉลาดและรับรู้เนื้อหา
  2. Hybrid Search ชนะ: การรวม vector similarity กับ keyword matching และ re-ranking สม่ำเสมอเอาชนะการค้นหา semantic อย่างบริสุทธิ์ 15-30%
  3. GPT-5.5 เปลี่ยนเศรษฐศาสตร์: ด้วยการปรับปรุงประสิทธิภาพ token 40% และการให้เหตุผลที่ดีขึ้น GPT-5.5 ทำให้ RAG production คุ้มค่าและมีประสิทธิภาพกว่าที่เคย
  4. Observability เป็นสิ่งจำเป็น: ระบบ RAG production ต้องการการติดตามที่ครอบคลุมทั้งคุณภาพการดึงข้อมูลและคุณภาพการสร้างคำตอบ
  5. เริ่มง่ายๆ Scale อย่างชาญฉลาด: เริ่มต้นด้วยรูปแบบ RAG พื้นฐานและเพิ่มความซับซ้อน (multi-query, HyDE, self-reflection) เฉพาะเมื่อวิธีง่ายๆ ไม่เพียงพอ

ต่อไปทำอะไร?

  • ใช้งาน ingestion pipeline จากส่วนที่ 2
  • ตั้งค่า monitoring โดยใช้รูปแบบจากส่วนที่ 5
  • ทดลองกับกลยุทธ์การแบ่งข้อความที่แตกต่างกันบนเอกสารของคุณเอง
  • เข้าร่วมชุมชน n8n เพื่อแบ่งปันการใช้งาน RAG ของคุณ

อนาคตของ AI องค์กรไม่ได้อยู่ที่โมเดลที่รู้ทุกอย่าง - แต่อยู่ที่โมเดลที่รู้วิธีค้นหาและใช้ข้อมูลที่ถูกต้องในเวลาที่ถูกต้อง นั่นคือสิ่งที่ RAG มอบให้


ต้องการความช่วยเหลือในการใช้งาน RAG สำหรับธุรกิจของคุณ? ติดต่อ Tropical Media สำหรับคำปรึกษาจากผู้เชี่ยวชาญด้าน AI automation, n8n workflows และระบบที่เน้นความรู้

แหล่งข้อมูล

Tags

#RAG #VectorDatabase #n8n #GPT-5.5 #AI-Agent #Knowledge-Management #Qdrant #Pinecone #Automation #Retrieval-Augmented-Generation #Enterprise-AI #Machine-Learning #Workflow-Automation #Natural-Language-Processing #Semantic-Search

การประสานงาน AI Agent ระดับ Production: การขยายระบบ Multi-Agent ด้วยสถาปัตยกรรม Event-Driven

เชี่ยวชาญการประสานงาน AI Agent ระดับ Production ด้วยสถาปัตยกรรม Event-Driven, Message Queues และรูปแบบที่ขยายได้ เรียนรู้วิธีจัดการ AI Agent 100+ ใน n8n workflows, การจัดการข้อผิดพลาดที่ยืดหยุ่น, การปรับเพิ่มประสิทธิภาพด้านค่าใช้จ่าย และการสร้างระบบ Multi-Agent ที่ทนต่อความผิดพลาดด้วย Redis, RabbitMQ และ Temporal

การสร้าง n8n MCP Workflow กับ Claude: จากภาษาธรรมชาติสู่ระบบ Automation ระดับ Production

เรียนรู้วิธีใช้ n8n MCP Server ใหม่กับ Claude AI เพื่อสร้าง Workflow ที่สมบูรณ์จากคำอธิบายภาษาธรรมชาติ ค้นพบการเปลี่ยนแปลงครั้งสำคัญจากการกำหนดค่า Node แบบ manual สู่สถาปัตยกรรม Workflow ที่ได้รับการสนับสนุนจาก AI พร้อมตัวอย่างการใช้งานจริงกว่า 20 ตัวอย่างสำหรับการ automation ธุรกิจ การเชื่อมต่อระบบ และระบบ agentic