กลยุทธ์การแบ่งข้อความยาวเป็นส่วน
แนวทางแบ่งแบบขนาดคงที่ ตามขอบเขตประโยค และตามความหมาย
กลยุทธ์การแบ่งข้อความยาวเป็นส่วน เป็นบทเรียน AI Prompt Engineering ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Prompt Engineering และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดเอกสารยาวจึงเป็นความท้าทาย
LLM มี หน้าต่างบริบท ซึ่งเป็นจำนวนโทเคนสูงสุดที่สามารถประมวลผลได้ในครั้งเดียว GPT-4 รองรับ 128,000 โทเคน และโคลดรองรับ 200,000 โทเคน แต่เอกสารจำนวนมากมีขนาดเกินขีดจำกัดเหล่านี้ ที่สำคัญกว่านั้น งานวิจัยแสดงให้เห็นว่าความแม่นยำของโมเดลมักลดลงเมื่อบริบทยาวมาก การแบ่งเป็นส่วนย่อย คือการแบ่งเอกสารออกเป็นชิ้นเล็กลงก่อนประมวลผล
การแบ่งเป็นส่วนย่อยขนาดคงที่
การแบ่งเป็นส่วนย่อยขนาดคงที่จะแบ่งข้อความทุก ๆ N โทเคน (หรืออักขระ) โดยไม่คำนึงถึงขอบเขตของเนื้อหา นี่เป็นกลยุทธ์ที่ง่ายที่สุดและไม่จำเป็นต้องเข้าใจความหมาย
ขนาดส่วนย่อยที่ใช้โดยทั่วไป: 500–1,000 โทเคน ส่วนย่อยเหล่านี้จัดทำดัชนีและดึงข้อมูลได้ง่าย แต่ประโยคอาจถูกตัดกลางคัน ทำให้ความหมายบริเวณขอบเขตสูญหาย
import tiktoken
def fixed_chunk(text, max_tokens=1000):
enc = tiktoken.get_encoding('cl100k_base')
tokens = enc.encode(text)
chunks = []
for i in range(0, len(tokens), max_tokens):
chunk_tokens = tokens[i:i + max_tokens]
chunks.append(enc.decode(chunk_tokens))
return chunks
chunks = fixed_chunk(long_document)
print(f'Total chunks: {len(chunks)}')ข้อแลกเปลี่ยนของการแบ่งเป็นส่วนย่อยขนาดคงที่
ข้อดี:
- นำไปใช้งานได้ง่าย — ไม่ต้องใช้การประมวลผลภาษาธรรมชาติ
- ขนาดส่วนย่อยคาดการณ์ได้ — จัดการค่าใช้จ่ายของส่วนเชื่อมต่อโปรแกรมได้ง่ายกว่า
- ประมวลผลได้รวดเร็ว
ข้อเสีย:
- ตัดข้ามขอบเขตประโยคและย่อหน้า
- ประโยคที่ถูกแบ่งข้ามส่วนย่อยจะสูญเสียบริบทเมื่อดึงข้อมูล
- ไม่เหมาะกับการสรุป — ส่วนย่อยอาจจบลงกลางข้อโต้แย้ง
การแบ่งเป็นส่วนย่อยตามขอบเขตประโยค
การแบ่งเป็นส่วนย่อยตามขอบเขตประโยคจะแบ่งข้อความตรงจุดสิ้นสุดตามธรรมชาติของประโยคหรือย่อหน้า แต่ละส่วนย่อยจะจบที่จุดสิ้นสุดของประโยค จึงไม่มีประโยคใดถูกตัดครึ่ง วิธีนี้ทำให้ได้ส่วนย่อยที่อ่านง่ายและมีเนื้อหาสอดคล้องกันมากกว่า
ใช้เครื่องตัดแบ่งประโยค (spaCy หรือ NLTK) เพื่อตรวจหาขอบเขต จากนั้นจัดกลุ่มประโยคจนกว่าส่วนย่อยจะมีขนาดถึงเป้าหมาย
import spacy
nlp = spacy.load('en_core_web_sm')
def sentence_chunk(text, max_tokens=1000):
doc = nlp(text)
sentences = [sent.text.strip() for sent in doc.sents]
chunks, current, count = [], [], 0
for sent in sentences:
word_count = len(sent.split())
if count + word_count > max_tokens and current:
chunks.append(' '.join(current))
current, count = [], 0
current.append(sent)
count += word_count
if current:
chunks.append(' '.join(current))
return chunksการแบ่งเป็นส่วนย่อยตามความหมาย
การแบ่งเป็นส่วนย่อยตามความหมายก้าวไปไกลกว่านั้น โดยจะแบ่งข้อความเมื่อ หัวข้อเปลี่ยน ด้วยการแปลงประโยคที่อยู่ติดกันเป็นเวกเตอร์และวัดความคล้ายคลึงแบบโคไซน์ เราสามารถตรวจจับได้ว่าการสนทนาเปลี่ยนไปสู่หัวข้อใหม่เมื่อใด
เมื่อความคล้ายคลึงลดลงต่ำกว่าเกณฑ์ ให้แทรกขอบเขตของส่วนย่อย วิธีนี้ทำให้ได้ส่วนย่อยที่มีเนื้อหาเป็นกลุ่มหัวข้อเดียวกัน เหมาะอย่างยิ่งสำหรับการสร้างแบบเสริมด้วยการดึงข้อมูล (RAG)
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
model = SentenceTransformer('all-MiniLM-L6-v2')
def semantic_chunk(sentences, threshold=0.75):
embeddings = model.encode(sentences)
chunks, current = [], [sentences[0]]
for i in range(1, len(sentences)):
sim = cosine_similarity(
[embeddings[i-1]], [embeddings[i]]
)[0][0]
if sim < threshold:
chunks.append(' '.join(current))
current = []
current.append(sentences[i])
if current:
chunks.append(' '.join(current))
return chunksการเปรียบเทียบกลยุทธ์ทั้งสาม
ต่อไปนี้คือการเปรียบเทียบแบบเคียงข้างกันเพื่อช่วยให้คุณเลือก:
- ขนาดคงที่: เร็วที่สุด แต่ขอบเขตแม่นยำน้อยที่สุด — ใช้กับกระบวนการทำงานแบบง่าย
- ตามขอบเขตประโยค: คงความสมบูรณ์ของประโยค — ใช้เมื่อความสอดคล้องของเนื้อหามีความสำคัญ
- ตามความหมาย: มีความสอดคล้องของหัวข้อดีที่สุด — ใช้กับ RAG ซึ่งการดึงข้อมูลที่แม่นยำเป็นสิ่งสำคัญอย่างยิ่ง
ในทางปฏิบัติ การแบ่งเป็นส่วนย่อยตามความหมายเพิ่มความหน่วงเนื่องจากต้องคำนวณการฝังเวกเตอร์ ให้เลือกตามข้อกำหนดด้านความแม่นยำของการดึงข้อมูล
การแบ่งเป็นส่วนย่อยสำหรับงานดึงข้อมูล
สำหรับ การสร้างแบบเสริมด้วยการดึงข้อมูล (RAG) ส่วนย่อยจะกลายเป็นหน่วยของการค้นหา คำค้นของผู้ใช้จะถูกแปลงเป็นเวกเตอร์ จากนั้นจึงดึงส่วนย่อยที่คล้ายกันมากที่สุดมาใส่ในพรอมต์
ส่วนย่อยขนาดเล็ก (200–400 โทเคน) ช่วยเพิ่มความแม่นยำในการดึงข้อมูล — แต่ละส่วนย่อยมีแนวคิดหลักเพียงหนึ่งเรื่อง ส่วนย่อยขนาดใหญ่ (800–1,000 โทเคน) ให้บริบทมากกว่า แต่อาจมีเนื้อหาที่ไม่เกี่ยวข้องปะปนกับข้อความที่เกี่ยวข้อง
import openai
import numpy as np
client = openai.OpenAI(api_key='sk-...')
def embed(text):
resp = client.embeddings.create(
model='text-embedding-3-small',
input=text
)
return np.array(resp.data[0].embedding)
def retrieve(query, chunks, top_k=3):
q_emb = embed(query)
scores = [(i, np.dot(q_emb, embed(c))) for i, c in enumerate(chunks)]
scores.sort(key=lambda x: x[1], reverse=True)
return [chunks[i] for i, _ in scores[:top_k]]การแบ่งเป็นส่วนย่อยสำหรับงานสรุป
สำหรับ การสรุป ส่วนย่อยควรมีขนาดใหญ่พอที่จะครอบคลุมข้อโต้แย้งหรือส่วนเนื้อหาหนึ่งส่วนได้อย่างครบถ้วน ส่วนย่อยตามขอบเขตประโยคขนาด 600–800 โทเคนทำงานได้ดี
แต่ละส่วนย่อยจะถูกสรุปแยกกัน (ขั้นตอน แมป) จากนั้นจึงรวมบทสรุปเข้าด้วยกันเป็นบทสรุปสุดท้าย (ขั้นตอน ลดรูป) นี่คือรูปแบบ แมป-ลดรูป แบบดั้งเดิม ซึ่งจะกล่าวถึงในบทเรียนถัดไป
การซ้อนทับ: เชื่อมขอบเขตของส่วนย่อย
เทคนิคที่ใช้ได้จริงเพื่อลดข้อผิดพลาดบริเวณขอบเขตคือการเพิ่ม การซ้อนทับ ระหว่างส่วนย่อย โดยทำซ้ำโทเคน 100–200 รายการสุดท้ายของส่วนย่อย N ไว้ที่จุดเริ่มต้นของส่วนย่อย N+1
การซ้อนทับช่วยให้ประโยคที่พาดผ่านขอบเขตปรากฏครบถ้วนในส่วนย่อยอย่างน้อยหนึ่งส่วน วิธีนี้สำคัญอย่างยิ่งสำหรับการดึงข้อมูล เพราะคำค้นเกี่ยวกับหัวข้อที่พาดผ่านขอบเขตจะตรงกับส่วนย่อยที่มีการซ้อนทับ
def fixed_chunk_with_overlap(text, max_tokens=1000, overlap=200):
enc = tiktoken.get_encoding('cl100k_base')
tokens = enc.encode(text)
chunks = []
step = max_tokens - overlap
for i in range(0, len(tokens), step):
chunk_tokens = tokens[i:i + max_tokens]
chunks.append(enc.decode(chunk_tokens))
if i + max_tokens >= len(tokens):
break
return chunksการเพิ่มข้อมูลกำกับให้แต่ละส่วนย่อย
แต่ละส่วนย่อยควรมี ข้อมูลกำกับ เพื่อให้ขั้นตอนถัดไปสามารถอ้างอิงแหล่งที่มาได้:
source: ชื่อไฟล์หรือที่อยู่เว็บpage: หมายเลขหน้าchunk_index: ตำแหน่งในเอกสารsection: บทหรือหัวข้อ
ข้อมูลกำกับนี้จะถูกจัดเก็บไว้พร้อมกับเวกเตอร์ในฐานข้อมูลเวกเตอร์ (ไพน์โคน โครมา และวีเวียต) และส่งกลับมาพร้อมส่วนย่อยที่ดึงมา เพื่อให้ LLM สามารถอ้างอิงแหล่งที่มาได้
def chunk_with_metadata(text, source='doc.pdf', page=1):
chunks = fixed_chunk_with_overlap(text)
return [
{
'text': chunk,
'metadata': {
'source': source,
'page': page,
'chunk_index': i
}
}
for i, chunk in enumerate(chunks)
]การเลือกกลยุทธ์ที่เหมาะสม
แนวทางตัดสินใจอย่างรวดเร็ว:
- ให้ความสำคัญกับความเร็ว และเนื้อหาเป็นร้อยแก้ว: การแบ่งเป็นส่วนย่อยตามขอบเขตประโยค
- ความแม่นยำในการดึงข้อมูลเป็นสิ่งสำคัญอย่างยิ่ง: การแบ่งเป็นส่วนย่อยตามความหมายโดยใช้ส่วนย่อยขนาดเล็ก (300 โทเคน)
- การสรุปหนังสือหรือรายงาน: แบ่งตามขอบเขตประโยค ใช้ส่วนย่อยขนาดใหญ่ (800 โทเคน) และใช้การแมป-ลดรูป
- เอกสารกฎหมายหรือเอกสารทางเทคนิค: แบ่งเป็นส่วนย่อยตามความหมายเพื่อให้ข้อกำหนดอยู่รวมกัน
ให้วัดค่าการเรียกคืนของการดึงข้อมูลกับชุดคำค้นที่เป็นตัวแทนก่อนตัดสินใจใช้กลยุทธ์ใดกลยุทธ์หนึ่งเสมอ
ตรวจสอบความรู้
กลยุทธ์การแบ่งข้อความใดจะแบ่งข้อความเมื่อความคล้ายคลึงแบบโคไซน์ระหว่างเวกเตอร์ฝังตัวของประโยคที่อยู่ติดกันลดลงต่ำกว่าเกณฑ์?
สรุป: กลยุทธ์การแบ่งข้อความ
คุณได้เรียนรู้กลยุทธ์หลักในการแบ่งข้อความสามรูปแบบ:
- ขนาดคงที่: แบ่งทุก ๆ N โทเค็น — รวดเร็ว เรียบง่าย และไม่คำนึงถึงขอบเขต
- ขอบเขตประโยค: แบ่งตรงจุดสิ้นสุดของประโยคตามธรรมชาติ — มีความต่อเนื่องและมีความซับซ้อนปานกลาง
- เชิงความหมาย: แบ่งเมื่อหัวข้อเปลี่ยนโดยใช้ความคล้ายคลึงของเวกเตอร์ฝังตัว — แม่นยำที่สุดและมีต้นทุนสูงที่สุด
เพิ่มการซ้อนทับระหว่างชิ้นข้อความเพื่อลดข้อผิดพลาดที่ขอบเขต และแนบข้อมูลเมตา (แหล่งที่มา หน้า ดัชนี) ไว้เสมอ เพื่อให้สามารถอ้างอิงและตรวจสอบย้อนกลับได้ บทเรียนถัดไปจะครอบคลุมรูปแบบการสรุปแบบแมป-รีดิวซ์
คำถามที่พบบ่อย
บทเรียน “กลยุทธ์การแบ่งข้อความยาวเป็นส่วน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กลยุทธ์การแบ่งข้อความยาวเป็นส่วน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Prompt Engineering ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กลยุทธ์การแบ่งข้อความยาวเป็นส่วน”
แนวทางแบ่งแบบขนาดคงที่ ตามขอบเขตประโยค และตามความหมาย คุณปฏิบัติ AI Prompt Engineering ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Prompt Engineering หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Prompt Engineering บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “กลยุทธ์การแบ่งข้อความยาวเป็นส่วน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Prompt Engineering นี้ได้ไหม
ได้ บทเรียน AI Prompt Engineering ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- กลยุทธ์การแบ่งข้อความยาวเป็นส่วน
- รูปแบบการสรุปแบบ Map-Reduce
- การสรุปแบบลำดับชั้น
- การรักษาบริบทระหว่างส่วนต่าง ๆ