RAG กับ hy4: การต่อโมเดล 4B เข้ากับฐานความรู้และการค้นหาแบบเวกเตอร์
RAG กับ hy4: การต่อโมเดล 4B เข้ากับฐานความรู้และการค้นหาแบบเวกเตอร์
คำถามที่ว่า "โมเดล 4B ทำ RAG ได้ไหม" จะมีคำตอบจริงก็ต่อเมื่อคุณระบุให้ชัดว่าให้โมเดล 4B ทำอะไร คำตอบคือ: ทำส่วนที่เบาๆ ในไปป์ไลน์ได้อย่างเพียงพอ แต่สังเคราะห์เนื้อหายาวแบบรวมฉบับมักล้มเหลว hy4 เหมาะกับบทบาทแรกมาก: โมเดล dense 4.22 พันล้านพารามิเตอร์ บริบทเนิร์ซ 256K และ Q4_K_M ที่มีขนาดเพียง 2.6GB รันบนเครื่องส่วนใหญ่ได้ บทความนี้ให้ชุดที่สมบูรณ์: vector store ในเครื่อง, embedding แบบ bge-m3, และ hy4 ทำหน้าที่เขียนคำค้นใหม่และสร้างคำตอบ พร้อมห้าข้อผิดพลาดที่คุณจะเจอจริง
สรุปใน 30 วินาที
hy4 มีบทบาทที่มีคุณค่าสูงสามบทใน RAG: การเขียนคำค้นใหม่ (เปลี่ยนคำถาบภาษาพูดให้เป็นคำหลักสำหรับค้นหา), การกำหนดเส้นทางความตั้งใจ (ตัดสินว่าจะไปที่ฐานความรู้ส่วนไหน) และ การสร้างคำตอบสั้น (ตอบไม่เกิน 300 คำจากชิ้นส่วนที่ดึงมา) การสังเคราะห์หลายเอกสารและการให้เหตุผลหลายขั้นให้โมเดลขนาดใหญ่บนคลาวด์ ส่วนฝั่งเวกเตอร์ให้ใช้ embedding แบบเปิดอย่าง bge-m3 เพราะแคตตาล็อกคลาวด์ของ EXAIV ยังไม่มีโมเดล embedding ใดเลย
กำหนดบทบาทก่อน: 4B ควรทำอะไร และไม่ควรทำอะไร
ไปป์ไลน์ RAG มีอย่างน้อยสองบทบาท: ฝั่งการเรียกค้น "หาเนื้อหา" และฝั่งการสร้าง "จัดระเบียบคำตอบ" งานสองอย่างนี้ต้องการความสามารถต่างกันอย่างมาก:
| ขั้นตอน | สิ่งที่ต้องการจากโมเดล | hy4 เหมาะหรือไม่ |
|---|---|---|
| การเขียนคำค้นใหม่และขยาย | เข้าใจคำถาบและสร้างคำหลัก | เหมาะมาก |
| การจำแนกความตั้งใจและการกำหนดเส้นทาง | ต้องการเพียงตัวอักษรของป้าย | เหมาะมาก แม้แต่ 0.5B ก็ทำได้ |
| การสรุปและสกัด | ต้องครอบคลุมประเด็นสำคัญของต้นฉบับ | เหมาะ |
| การตอบคำถามสั้นโดยมีพื้นฐาน | ต้องซื่อสัตย์และไม่แต่ง | เหมาะเมื่อมี prompt ที่เข้มงวด |
| การสังเคราะห์เนื้อหายาวจากหลายแหล่ง | ต้องให้เหตุผลระยะไกลและคงเส้นคงที่ | ไม่เหมาะ ให้ใช้โมเดลขนาดใหญ่ |
| การให้เหตุผลหลายขั้น | ต้องมีขั้นตอนกลาง | ไม่เหมาะ |
ทำไมโมเดลขนาดเล็กเหมาะกับครึ่งแรกของไปป์ไลน์
ครึ่งแรกผลิต ข้อความสั้นหรือป้าย ซึ่งข้อผิดพลาดราคาถูกและตรวจสอบได้ ขณะที่ครึ่งหลังผลิต ข้อความยาว ซึ่งข้อผิดพลาดราคาแพงและยากที่จะตามย้อน การวาง 4B ไว้ด้านหน้าหมายความว่าแม้การเขียนใหม่จะไม่ดีนัก ก็ยังมีการเรียกค้นมาชดเชย แต่ถ้าวาง 4B ไว้ด้านหลัง ทุกประโยคที่แต่งขึ้นมาจะมาสู่หน้าผู้ใช้โดยตรง
ชุดที่สมบูรณ์และรันได้จริง
ขั้นที่ 1: เริ่มเซิร์ฟเวอร์การ infer ในเครื่อง
./llama-server -m ./hunyuan4b/Q4_K_M.gguf \
--host 127.0.0.1 --port 8080 \
--ctx-size 32768 --jinja
endpoint ที่เปิดออกมาคือ OpenAI-compatible มาตรฐาน ส่วนด้านล่างชี้ตรงไปที่ http://127.0.0.1:8080/v1
ขั้นที่ 2: แบ่งเอกสาร
from pathlib import Path
import re
def load_docs(folder: str) -> list[str]:
chunks = []
for p in sorted(Path(folder).glob("**/*.md")):
text = p.read_text(encoding="utf-8")
sections = re.split(r"\n(?=#{1,3} )", text)
for sec in sections:
if len(sec) < 200:
continue
for i in range(0, len(sec), 1200):
piece = sec[i:i + 1200]
if len(piece.strip()) > 50:
chunks.append(sec.split("\n")[0] + "\n" + piece)
return chunks
chunks = load_docs("./docs")
print(len(chunks))
กฎข้อแรกของการแบ่ง: ห้ามตัดจนขาดหน่วยความหมาย
การตัดตามจำนวนอักขระคงที่จะแบ่งตารางหรือคำอธิบาย API ครึ่งหนึ่ง ทำให้ชิ้นที่เรียกค้นได้อ่านแล้วขาดและโมเดลต้องมักไปเดา ให้แบ่งตามลำดับหัวข้อก่อน แล้วจึงตัดตามความยาว และคงหัวข้อไว้เป็นส่วนนำ เพราะหัวข้อคือจุดยึดสำหรับการเรียกค้นที่ดีที่สุด
ขั้นที่ 3: ฝังเข้าเวกเตอร์ (ใช้ embedding ในเครื่อง)
from sentence_transformers import SentenceTransformer
embed_model = SentenceTransformer("BAAI/bge-m3")
vectors = embed_model.encode(chunks, normalize_embeddings=True, batch_size=32)
bge-m3 เป็นหนึ่งใน embedding แบบเปิดหลายภาษาที่มียอดดาวน์โหลดสูงที่สุดในชุมชน รองรับการใช้ภาษาจีนและอังกฤษปนกันรวมถึงข้อความยาว
ทำไมไม่ใช้บริการ embedding บนคลาวด์
ข้อแรก แคตตาล็อกคลาวด์ของ EXAIV ยังไม่มีโมเดลประเภท embedding ข้อสอง ปริมาณคำขอ embedding มากแต่มูลค่าต่อคำขอต่ำ การส่งขึ้นคลาวด์จึงกลายเป็นส่วนที่แพงที่สุด ข้อสาม โมเดล embedding มีขนาดเพียงไม่กี่ร้อย MB ถึงมากกว่าหนึ่ง GB รันในเครื่องแทบไม่มีต้นทุนการเดินเรือและยังเร็วกว่า
ขั้นที่ 4: เรียกค้นและจัดอันดับใหม่
import numpy as np
query_vec = embed_model.encode([query], normalize_embeddings=True)[0]
scores = np.dot(vectors, query_vec)
top_idx = np.argsort(-scores)[:20]
from sentence_transformers import CrossEncoder
reranker = CrossEncoder("BAAI/bge-reranker-v2-m3")
pairs = [[query, chunks[i]] for i in top_idx]
rerank_scores = reranker.predict(pairs)
final_idx = [top_idx[i] for i in np.argsort(-rerank_scores)[:4]]
การจัดอันดับใหม่คือขั้นที่คุ้มค่าที่สุดต่อราคา
การเรียกค้นด้วยเวกเตอร์คือการกรองคร่าวๆ (ถูก เร็ว และครอบคลุม) ขณะที่การจัดอันดับใหม่ด้วย cross-encoder คือการกรองละเอียด (ช้ากว่า แพงกว่า แต่เรียงลำดับได้แม่นยำกว่ามาก) ระบ RAG หลายระบติดตัวตรง การเรียงลำดับการเรียกค้น ไม่ใช่โมเดลสร้าง การทุ่มเทให้เปลี่ยน top-20 ให้เป็น top-4 ที่เนียนมักได้ผลดีกว่าการเปลี่ยนโมเดลสร้างจาก 4B เป็น 7B
ขั้นที่ 5: ใช้ hy4 เขียนคำค้นใหม่และสร้างคำตอบ
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8080/v1", api_key="local")
def rewrite(query: str) -> str:
r = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content": "เขียนคำถามของผู้ใช้ใหม่เป็น 3 กลุ่มคำสำหรับค้นหาแบบเวกเตอร์ บรรทัดละกลุ่ม ไม่ต้องอธิบาย"},
{"role": "user", "content": query},
],
temperature=0.1,
)
return r.choices[0].message.content
def answer(query: str, context_chunks: list[str]) -> str:
context = "\n\n---\n\n".join(context_chunks)
r = client.chat.completions.create(
model="local-model",
messages=[
{"role": "system", "content":
"คุณคือผู้ช่วยฐานความรู้ ตอบเฉพาะจากเอกสารที่ให้มาเท่านั้น "
"หากเอกสารไม่ได้กล่าวถึง ให้ตอบชัดว่ายังไม่มีในเอกสาร อย่าเดา "
"ตอบไม่เกิน 300 คำ และระบุที่มาเป็น [ชิ้น N] ตอนท้ายประโยค"},
{"role": "user", "content": f"เอกสาร:\n{context}\n\nคำถาม: {query}"},
],
temperature=0.2,
)
return r.choices[0].message.content
rewritten = rewrite(query)
print(answer(query, [chunks[i] for i in final_idx]))
ตรึงสามข้อจำกัดไว้ใน prompt
ตอบเฉพาะจากเอกสาร บอกชัดเมื่อเอกสารไม่กล่าวถึง และระบุหมายเลขชิ้น สามบรรทัดนี้ลดอัตราการแต่งข้อความของโมเดล 4B ได้อย่างเห็นได้ชัด โมเดล 4B ไม่ได้ตัดสินเองว่าควรแต่งหรือไม่ แต่ สามารถถูกบังคับด้วยคำสั่งได้
ห้าข้อผิดพลาดที่คุณจะเจอ
ข้อผิดพลาดที่หนึ่ง: การแบ่งตัดหน่วยความหมาย
อาการคือชิ้นที่เรียกค้นมาอ่านแล้วขาดครึ่งประโยค วิธีแก้คือแบ่งตามลำดับหัวข้อและคงหัวข้อไว้เป็นส่วนนำ แล้วจึงตัดใหม่ตามขอบเขตประโยค
ข้อผิดพลาดที่สอง: เรียกค้นอย่างเดียวโดยไม่จัดอันดับใหม่
อาการคือเอกสารที่ถูกต้องถูกดึงกลับมาแต่อยู่ในอันดับที่ 12 และถูกตัดออกด้วยตัวกรอง top-4 วิธีแก้คือเพิ่มจำนวนการเรียกค้นและเพิ่มตัวจัดอันดับใหม่ หรือใช้หลายเวอร์ชันของการเขียนคำค้นใหม่แล้วค้นแยกกันแล้วรวมผล
ข้อผิดพลาดที่สาม: prompt ไม่มีข้อจำกัด
อาการคือโมเดลเติมเต็มด้วยความรู้จากการฝึก ตอบด้วยความมั่นใจแม้เอกสารไม่มีเนื้อหานั้น วิธีแก้คือเพิ่มคำสั่งว่าถ้าไม่มีในเอกสารก็บอกชัด ระบุหมายเลขชิ้น และลด temperature ใต้ 0.2
ข้อผิดพลาดที่สี่: มองการเรียกค้นเหมือนการถามตอบ
อาการคือผู้ใช้ถามว่า "ฟีเจอร์นี้ใช้อย่างไร" แล้วโมเดลตอบด้วยย่อหน้าแนะนำผลิตภัณฑ์ว่ามันทำหน้าที่อะไร วิธีแก้คือจำแนกคำถามก่อน (ค้นความจริง, ขั้นตอนการใช้, การแก้ปัญหา) แล้วใช้ต้นแบบ prompt ต่างกันสำหรับแต่ละประเภท
ข้อผิดพลาดที่ห้า: ยัดเยียดบริบทจนเกิน
อาการคือ hy4 ไม่พบประโยคสำคัญท่ามกลางเนื้อหาจำนวนมากและเริ่มทำซ้ำ hy4 รองรับบริบท 256K ในรูปเนิร์ซ แต่ การใส่ได้ไม่ได้หมายความว่าใช้ได้ดี ควรให้ครั้งละ 4 ถึง 8 ชิ้น ถ้าเกินกว่านั้นให้บีบอัดก่อนแล้วจึงส่ง
เมื่อไหร่ที่ไม่ควรใช้โมเดล 4B ในการสร้าง
| สถานการณ์ | ทางเลือกที่ดีกว่า |
|---|---|
| ต้องสังเคราะห์บนมากกว่า 5 แหล่ง | โมเดลขนาดใหญ่บนคลาวด์ |
| ผลลัพธ์คือรายงานยาวหรือเอกสาร | โมเดลขนาดใหญ่บนคลาวด์ |
| การเรียกค้นไม่ดีและหาเอกสารไม่เจอ | แก้ฝั่งการเรียกค้น อย่าเปลี่ยนโมเดลสร้าง |
| การถามตอบปริมาณมากที่ต้องการความหน่วงต่ำ | hy4 หรือโมเดลเบาระดับเดียวกัน |
| เอกสารต้นฉบับยาวและต้องการสรุปยาว | โมเดลที่แข็งแรงด้านบริบทมากกว่า หรือสรุปเป็นชั้นก่อน |
FAQ
โมเดล 4B ทำ RAG ได้เพียงพอหรือไม่?
hy4 รองรับบริบทได้นานแค่ไหน?
ควรใช้โมเดล embedding ตัวไหน?
จำเป็นต้องมีการจัดอันดับใหม่หรือไม่?
จะลดการแต่งข้อความของโมเดลได้อย่างไร?
จะต่อ endpoint hy4 ในเครื่องเข้ากับแอปที่มีอยู่ได้อย่างไร?
อ่านต่อ
- หน้าโมเดล hy4 — สเปก เมทริกซ์ quantization และการคำนวณหน่วยความจำ
- คำอธิบายช่องทาง hy4-preview — ช่องทางบริบท 1M
- hy4 GGUF local deployment — ขั้นตอนเต็มสำหรับการเริ่มเซิร์ฟเวอร์
- การเชื่อมต่อ hy4 กับ Ollama — การนำ endpoint ในเครื่องเข้ากับเครื่องมือพัฒนา
- Open WebUI กับ Hunyuan ในเครื่อง — ส่วนติดต่อสนทนาแบบ self-hosted
- คู่มือวิศวกรรมบริบท — การจัดระเบียบข้อมูลในงบประมาณของหน้าต่าง
- คู่มือการเลือกโมเดล embedding — bge, gte, jina และ e5 ต่างกันอย่างไร
- คู่มือเลือกโมเดล hy4 — ขนาดต่างๆ และการแบ่งงานกับ A13B
แหล่งข้อมูล
ตัวเลขการดาวน์โหลดและข้อกำหนดเป็นไปตามคลังทางการในเวลาจริง เก็บตัวอย่างเมื่อเดือนพฤศจิกายน 2026