[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-th-1-1-all-golang-document-ingestion-pipeline-pdf-word-rag-all--*":3,"academy-blog-translations-ytqbhupna4e0zox":81},{"data":4,"page":67,"perPage":67,"totalItems":67,"totalPages":67},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"created":12,"created_by":13,"expand":14,"id":75,"keywords":76,"locale":47,"published_at":77,"scheduled_at":63,"school_blog":71,"short_description":78,"status":69,"title":79,"updated":80,"updated_by":13,"slug":72,"views":74},"ภาพสถาปัตยกรรม Document Ingestion Pipeline สกัดข้อความจากไฟล์ PDF และ Word ด้วยภาษา Golang ส่งเข้า Qdrant Database สำหรับระบบ RAG","sclblg987654321","school_blog_translations","\u003Cp>ยินดีต้อนรับเข้าสู่ EP.157 ครับ! จากตอนที่แล้วที่เราได้สัมผัสพลังของ Semantic Search ในการค้นหาข้อมูลตามความหมายกันไปแล้ว แต่ในชีวิตจริง คลังความรู้ขององค์กรคงไม่ได้มาเป็น Text สั้นๆ ที่พร้อมใช้งานเสมอไป แต่มักจะซ่อนอยู่ในไฟล์เอกสารอย่าง PDF หรือ Microsoft Word (.docx) ที่มีความยาวหลายสิบหน้า\u003C\u002Fp>\u003Cp>ดังนั้น ภารกิจของชาว Gopher สาย Backend ในวันนี้ คือการสร้าง \u003Cstrong>Document Ingestion Pipeline\u003C\u002Fstrong> หรือระบบท่อส่งข้อมูลอัตโนมัติ เพื่อจัดการกระบวนการทั้งหมดตั้งแต่ \u003Cem>\"อ่านไฟล์เอกสาร ➡️ สกัดข้อความดิบ ➡️ ตัดแบ่งเป็น Chunk ➡️ แปลงเป็น Vector ➡️ และบันทึกลงฐานข้อมูล Qdrant\"\u003C\u002Fem> ให้ทำงานร่วมกันอย่างไร้รอยต่อ เตรียม Editor ให้พร้อม แล้วมาลุยกันเลยครับ!\u003C\u002Fp>\u003Ch2>สถาปัตยกรรมของ Document Ingestion Pipeline\u003C\u002Fh2>\u003Cp>เพื่อความยืดหยุ่นในการรองรับไฟล์หลากหลายประเภท เราจะออกแบบระบบให้แยกออกเป็น 4 ส่วนหลักๆ (Modular Architecture) เพื่อให้ง่ายต่อการบำรุงรักษาและการขยายระบบในอนาคต:\u003C\u002Fp>\u003Cp>Plaintext\u003C\u002Fp>\u003Cpre>\u003Ccode>[ไฟล์ PDF \u002F Word] ──&gt; 1. Text Extractor (สกัดเฉพาะข้อความดิบออกมา)\n                                │\n                                ▼\n                      2. Chunking Engine (หั่นเป็นชิ้นย่อย พร้อมกำหนดระยะคาบเกี่ยว หรือ Overlap)\n                                │\n                                ▼\n                      3. Embedding Client (ส่ง API ไปแปลงความหมายเป็น []float32)\n                                │\n                                ▼\n                      4. Vector DB Client (บันทึกพิกัด Vector และ Metadata ลง Qdrant)\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>การเลือกใช้ Library ในภาษา Go สำหรับอ่าน PDF และ Word\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>สำหรับไฟล์ PDF:\u003C\u002Fstrong> แนะนำไลบรารีอย่าง \u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fgithub.com\u002Fdslipak\u002Fpdf\">github.com\u002Fdslipak\u002Fpdf\u003C\u002Fa> ซึ่งทำงานได้เร็ว น้ำหนักเบา และสามารถสกัดข้อความภาษาไทย (รวมถึงสระและวรรณยุกต์ลอย) ออกมาได้ค่อนข้างดีเมื่อเทียบกับตัวอื่น \u003Cem>(ข้อควรระวัง: ความแม่นยำอาจขึ้นอยู่กับฟอนต์และวิธีการ Export ไฟล์ PDF นั้นๆ ด้วย)\u003C\u002Fem>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>สำหรับไฟล์ Word (.docx):\u003C\u002Fstrong> แนะนำ \u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fgithub.com\u002Fnguyenthenguyen\u002Fdocx\">github.com\u002Fnguyenthenguyen\u002Fdocx\u003C\u002Fa> ซึ่งใช้อ่านโครงสร้าง XML ของไฟล์ Word ได้อย่างรวดเร็ว โดยไม่ต้องพึ่งพาซอฟต์แวร์ภายนอกหรือ Microsoft Office เลย\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>ตัวอย่างการสร้าง Ingestion Pipeline ด้วย Go\u003C\u002Fh2>\u003Cp>มาดูตัวอย่างการเขียน Pipeline สำหรับสกัดข้อมูลจากไฟล์ PDF เพื่อนำเข้าสู่กระบวนการเตรียมทำระบบ RAG (Retrieval-Augmented Generation) กันครับ\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com\u002Fdslipak\u002Fpdf\"\n\t\"github.com\u002Fgoogle\u002Fuuid\"\n\t\"github.com\u002Fqdrant\u002Fgo-client\u002Fqdrant\"\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tpdfPath := \"company_policy.pdf\"\n\n\t\u002F\u002F 1. Text Extraction: สกัดข้อความจาก PDF\n\tfmt.Println(\"⏳ กำลังสกัดข้อความจากไฟล์ PDF...\")\n\ttext, err := extractTextFromPDF(pdfPath)\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to extract text: %v\", err)\n\t}\n\n\t\u002F\u002F 2. Chunking: หั่นข้อความ (ใช้ฟังก์ชันตัดแบ่งที่เราเคยเขียนไว้ใน EP.155)\n\t\u002F\u002F หั่นชิ้นละ 500 ตัวอักษร และตั้ง Overlap ไว้ที่ 100 ตัวอักษร\n\tchunks := ChunkText(text, 500, 100)\n\tfmt.Printf(\"🧩 หั่นข้อความออกมาได้ทั้งหมด %d Chunks\\n\", len(chunks))\n\n\t\u002F\u002F เริ่มต้น Client สำหรับยิง API (ดึงค่าจาก Environment Variables เพื่อความปลอดภัย)\n\tapiKey := os.Getenv(\"OPENAI_API_KEY\")\n\tif apiKey == \"\" {\n\t\tlog.Fatal(\"Please set your OPENAI_API_KEY environment variable\")\n\t}\n\topenaiClient := openai.NewClient(apiKey)\n\n\t\u002F\u002F เชื่อมต่อฐานข้อมูล Qdrant\n\tqdrantClient, err := qdrant.NewClient(&amp;qdrant.Config{\n\t\tHost: \"localhost\",\n\t\tPort: 6334, \u002F\u002F ใช้พอร์ต 6334 สำหรับการสื่อสารผ่าน gRPC ของ Go Client\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"Qdrant connection failed: %v\", err)\n\t}\n\tdefer qdrantClient.Close()\n\n\t\u002F\u002F 3 &amp; 4. Loop ทำ Embedding และ Upsert ลง Qdrant\n\tfmt.Println(\"🚀 กำลังแปลงเป็นเวกเตอร์ และบันทึกลงฐานข้อมูล Qdrant...\")\n\tfor i, chunk := range chunks {\n\t\t\u002F\u002F แปลงข้อความของ Chunk นี้ให้เป็น Vector\n\t\tembReq := openai.EmbeddingRequest{\n\t\t\tInput: []string{chunk},\n\t\t\tModel: openai.SmallEmbedding3Small, \u002F\u002F ใช้โมเดลมาตรฐาน 1,536 มิติ\n\t\t}\n\t\tembResp, err := openaiClient.CreateEmbeddings(ctx, embReq)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error embedding chunk %d: %v\", i, err)\n\t\t\tcontinue\n\t\t}\n\t\tvector := embResp.Data[0].Embedding\n\n\t\t\u002F\u002F เตรียมสร้าง Point สำหรับบันทึกลง Qdrant พร้อมกำหนด Metadata Payload\n\t\tpointID := uuid.New().String()\n\t\tpayload := map[string]interface{}{\n\t\t\t\"content\":   chunk,\n\t\t\t\"source\":    pdfPath,\n\t\t\t\"chunk_idx\": i,\n\t\t}\n\n\t\t\u002F\u002F สั่ง Upsert ข้อมูลเข้า Collection\n\t\t_, err = qdrantClient.Upsert(ctx, &amp;qdrant.UpsertPoints{\n\t\t\tCollectionName: \"ai_knowledge_base\",\n\t\t\tPoints: []*qdrant.PointStruct{\n\t\t\t\t{\n\t\t\t\t\tId:      qdrant.NewIDUUID(pointID),\n\t\t\t\t\tVectors: qdrant.NewVectorsDense(vector),\n\t\t\t\t\tPayload: qdrant.NewValueMap(payload),\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error upserting chunk %d to Qdrant: %v\", i, err)\n\t\t}\n\t}\n\n\tfmt.Println(\"✅ สิ้นสุดกระบวนการ! คลังข้อมูล AI จาก PDF พร้อมใช้งานแล้ว\")\n}\n\n\u002F\u002F ฟังก์ชันช่วยอ่านข้อความดิบจากไฟล์ PDF\nfunc extractTextFromPDF(path string) (string, error) {\n\tr, err := pdf.Open(path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t\n\tvar buf bytes.Buffer\n\tb, err := r.GetPlainText()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t\n\t_, err = buf.ReadFrom(b)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t\n\treturn buf.String(), nil\n}\n\n\u002F\u002F ChunkText (อ้างอิงจาก EP.155) - หั่นข้อความโดยอิงตามรูน (Rune) เพื่อรองรับภาษาไทย\nfunc ChunkText(text string, chunkSize int, overlap int) []string {\n\trunes := []rune(text)\n\tvar chunks []string\n\t\n\tif len(runes) == 0 {\n\t\treturn chunks\n\t}\n\t\n\tfor i := 0; i &lt; len(runes); {\n\t\tend := i + chunkSize\n\t\tif end &gt; len(runes) {\n\t\t\tend = len(runes)\n\t\t}\n\t\t\n\t\tchunks = append(chunks, string(runes[i:end]))\n\t\tif end == len(runes) {\n\t\t\tbreak\n\t\t}\n\t\t\n\t\ti += (chunkSize - overlap)\n\t}\n\treturn chunks\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>พลัง Concurrency ของ Go กับการสเกล Ingestion Pipeline\u003C\u002Fh2>\u003Cp>เมื่อระบบของคุณขยายตัวไปจนถึงจุดที่มีการอัปโหลดไฟล์พร้อมกันจำนวนมาก (เช่น เอกสารคู่มือองค์กรหรือไฟล์บัญชีนับพันไฟล์) โค้ดแบบวนลูป \u003Ccode>for\u003C\u002Fcode> ธรรมดาจะกลายเป็นคอขวดทันที เพราะต้องรอให้ API ของ OpenAI และ Qdrant ตอบกลับทีละตัวเรียงกันไป\u003C\u002Fp>\u003Cp>นี่คือจุดที่ภาษา Go เฉิดฉายที่สุดครับ! เราสามารถปรับปรุงโค้ดด้านบนให้ทำงานแบบ \u003Cstrong>Worker Pool Pattern\u003C\u002Fstrong> โดยใช้ \u003Ccode>Goroutines\u003C\u002Fcode> และ \u003Ccode>Channels\u003C\u002Fcode> เพื่อสั่งให้เครื่องสกัด Text, ยิงทำ Embedding และ Upsert ลงฐานข้อมูลขนานกัน (Parallel) ได้หลายๆ ไฟล์หรือหลายๆ Chunk พร้อมกัน ช่วยประหยัดเวลาการทำ Data Pipeline จากระดับนาทีให้เหลือเพียงไม่กี่วินาทีเท่านั้น!\u003C\u002Fp>\u003Ch2>🎯 ท้าให้ลอง (Daily Mission)\u003C\u002Fh2>\u003Cp>ลองสร้างไฟล์ PDF ขึ้นมาหนึ่งไฟล์ (อาจจะเป็นข้อความกฎระเบียบบริษัทหรือคู่มือการทำงานสั้นๆ) จากนั้นนำมาวางในโปรเจกต์และรันโค้ดตัวอย่างด้านบนดูครับ\u003C\u002Fp>\u003Cp>\u003Cstrong>การบ้านชวนอัปเกรดโค้ด:\u003C\u002Fstrong> ลองแก้ไขโค้ดด้านบนโดยนำกลไก \u003Cem>Goroutine\u003C\u002Fem> มาแยกส่วนงานแปลง Embedding ให้ทำงานแบบ Concurrency (เช่น ใช้ \u003Ccode>sync.WaitGroup\u003C\u002Fcode> ช่วยควบคุม) เพื่อให้ระบบทำงานได้เร็วขึ้น และเมื่อรันเสร็จแล้ว \u003Cstrong>อย่าลืมเปิดเบราว์เซอร์ไปที่ Qdrant Web UI (ผ่านพอร์ต HTTP: \u003C\u002Fstrong>\u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Flocalhost:6333\u002Fdashboard\">\u003Cstrong>\u003Ccode>http:\u002F\u002Flocalhost:6333\u002Fdashboard\u003C\u002Fcode>\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong>)\u003C\u002Fstrong> เพื่อตรวจสอบดูว่า Points และ Payload จากไฟล์ PDF ของเราไหลเข้าไปจัดเก็บได้อย่างถูกต้องหรือไม่!\u003C\u002Fp>\u003Ch2>FAQ (คำถามที่พบบ่อยประจำตอน)\u003C\u002Fh2>\u003Ch3>ถ้าไฟล์ PDF มีรูปภาพหรือตารางอยู่ข้างใน ไลบรารีที่สกัด Text ธรรมดาจะอ่านรู้เรื่องไหม?\u003C\u002Fh3>\u003Cp>ตัวสกัด Text ทั่วไปจะมองเห็นเฉพาะตัวอักษรดิบครับ หากเจอโครงสร้างตาราง ข้อมูลอาจจะเบี้ยวหรือสลับแถวได้ และจะไม่เห็นข้อมูลในรูปภาพเลย หากระบบบน Production จำเป็นต้องอ่านรูปภาพหรือตารางที่ซับซ้อนอย่างแม่นยำ แนะนำให้เปลี่ยนไปใช้บริการกลุ่ม \u003Cstrong>Document Intelligence API\u003C\u002Fstrong> (เช่น Azure Document Intelligence หรือ Google Document AI) หรือใช้โมเดลประเภท Vision ช่วยอ่านแทนครับ\u003C\u002Fp>\u003Ch3>ทำไมเราต้องเก็บคีย์ \"source\" และ \"chunk_idx\" ไว้ใน Payload ของ Qdrant ด้วย?\u003C\u002Fh3>\u003Cp>สำคัญมากครับ! เพราะเวลาที่ AI ดึงคำตอบมาแสดงผลให้ผู้ใช้ (หรือส่งให้ LLM สรุป) เรามักจะต้องการทำ \u003Cstrong>Citation (การอ้างอิงแหล่งที่มา)\u003C\u002Fstrong> เพื่อบอกผู้ใช้ว่าข้อมูลนี้มาจากหน้าไหน เล่มใด การเก็บข้อมูล \u003Ccode>source\u003C\u002Fcode> และลำดับ \u003Ccode>idx\u003C\u002Fcode> ไว้ จะช่วยให้เราย้อนกลับไปตรวจสอบ หรือแสดงลิงก์เอกสารต้นฉบับให้ผู้ใช้เช็กความถูกต้องได้ง่ายขึ้นครับ\u003C\u002Fp>\u003Cdiv data-type=\"horizontalRule\">\u003Chr>\u003C\u002Fdiv>\u003Ch2>สรุปและเตรียมพบกับ EP.158\u003C\u002Fh2>\u003Cp>ยอดเยี่ยมมากครับ! ตอนนี้เราสามารถสกัดความรู้จากเอกสารในโลกภายนอก เข้ามาเก็บเป็น \"สมองจำ\" ในเครื่องได้แบบอัตโนมัติแล้ว\u003C\u002Fp>\u003Cp>สเต็ปต่อไปคือการปิดลูปกระบวนการ RAG ที่สมบูรณ์แบบ นั่นคือการทำ \u003Cstrong>\"Context Injection: การนำข้อมูลที่ค้นหาได้มาสร้างเป็นบริบทให้ AI\"\u003C\u002Fstrong> เราจะเอาชิ้นส่วนความรู้ที่สกัดและค้นเจอจาก Vector DB ไปป้อนใส่ปาก LLM อย่างไร เพื่อบังคับให้มันตอบคำถามลูกค้าได้อย่างแม่นยำและไม่มั่ว (Hallucination)?\u003C\u002Fp>\u003Cp>เตรียมตัวให้พร้อม แล้วเจอกันตอนหน้าครับ Gophers!\u003C\u002Fp>\u003Cp>\u003Cstrong>ฝากกดติดตามพวกเราได้ที่ Superdev Academy\u003C\u002Fstrong> ในทุกช่องทางนะครับ!\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>🔵 Facebook: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.academy.th\">\u003Cstrong>Superdev Academy Thailand\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(อัปเดตข่าวสารและบทความใหม่)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 YouTube: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.youtube.com\u002F@SuperdevAcademy\">\u003Cstrong>Superdev Academy Channel\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(ติวเข้มแบบวิดีโอ)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>📸 Instagram: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.instagram.com\u002Fsuperdevacademy\u002F\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(เกร็ดความรู้สั้นๆ และเบื้องหลังการทำงาน)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 TikTok: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.tiktok.com\u002F@superdevacademy?lang=th-TH\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(Tips &amp; Tricks ฉบับย่อยง่าย)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🌐 Website: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fsuperdevacademy.com\">\u003Cstrong>superdevacademy.com\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(คลังบทความและคอร์สเรียนฉบับเต็ม)\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>","3342soq2rnvk_1hktugg5b2.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Ftai7yrjthxbasxc\u002F3342soq2rnvk_1hktugg5b2.png","2026-07-05 13:45:30.566Z","76qprkevbgfdps8",{"keywords":15,"locale":41,"school_blog":51},[16,23,28,32,36],{"collectionId":17,"collectionName":18,"created":19,"created_by":13,"id":20,"name":21,"updated":22,"updated_by":13},"sclkey987654321","school_keywords","2026-03-04 08:20:14.253Z","ah6lvy4x8qe08l5","Golang","2026-06-07 06:45:08.193Z",{"collectionId":17,"collectionName":18,"created":24,"created_by":13,"id":25,"name":26,"updated":27,"updated_by":13},"2026-03-04 08:20:11.547Z","ey3puyme01a9bsw","Go","2026-06-07 06:45:07.798Z",{"collectionId":17,"collectionName":18,"created":29,"created_by":13,"id":30,"name":31,"updated":29,"updated_by":13},"2026-07-05 13:45:03.865Z","4kfwr0tzqe7y1ux","Document Ingestion Pipeline",{"collectionId":17,"collectionName":18,"created":33,"created_by":13,"id":34,"name":35,"updated":33,"updated_by":13},"2026-06-11 16:14:22.575Z","gluay8aj98wheus","RAG",{"collectionId":17,"collectionName":18,"created":37,"created_by":13,"id":38,"name":39,"updated":40,"updated_by":13},"2026-03-04 08:44:53.062Z","puutdnxuitnxxgq","Backend","2026-06-07 06:46:40.599Z",{"code":42,"collectionId":43,"collectionName":44,"created":45,"flag":46,"id":47,"is_default":48,"label":49,"updated":50},"th","pbc_1989393366","locales","2026-01-22 10:59:55.832Z","twemoji:flag-thailand","s8wri3bt4vgg2ji",true,"Thai","2026-04-10 15:42:46.614Z",{"category":52,"collectionId":53,"collectionName":54,"created":55,"expand":56,"id":71,"slug":72,"updated":73,"views":74},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs","2026-07-05 13:45:30.326Z",{"category":57},{"blogIds":58,"collectionId":59,"collectionName":60,"created":61,"created_by":13,"id":52,"image":62,"image_alt":63,"image_path":64,"label":65,"name":66,"priority":67,"publish_at":68,"scheduled_at":63,"status":69,"updated":70,"updated_by":13},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw.png","","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw.png",{"en":66,"th":66},"Golang The Series",1,"2026-03-16 04:39:38.440Z","published","2026-06-07 06:45:03.856Z","ytqbhupna4e0zox","golang-document-ingestion-pipeline-pdf-word-rag","2026-07-06 06:41:05.333Z",124,"tai7yrjthxbasxc",[20,25,30,34,38],"2026-07-06 04:39:11.522Z","เรียนรู้การสร้าง Document Ingestion Pipeline ด้วยภาษา Go (Golang) เพื่ออ่าน สกัด และแปลงไฟล์เอกสาร PDF\u002FWord เป็นเวกเตอร์เข้า Qdrant เตรียมพร้อมสำหรับระบบ RAG","Golang The Series EP.157: สร้าง Document Ingestion Pipeline สกัด PDF\u002FWord ทำ RAG","2026-07-06 04:39:11.545Z",{"th":72,"en":72}]