父子片段:檢索用小段落,生成給大段落
小片段檢索準,大片段回答完整。父子結構讓你兩者兼得。
切塊有個難解的矛盾:片段小則檢索精準但缺乏上下文,片段大則上下文完整但相似度被稀釋。父子片段是繞開這個矛盾的標準做法。
結構設計
- 子片段:200–300 字,用來計算向量與檢索。
- 父片段:1000–1500 字,或整個章節,實際餵給模型。
- 子片段記錄
parent_id,檢索命中後改取父片段。
hits = vector_search(q, top_k=10) # 命中的是子片段
parent_ids = list(dict.fromkeys(h.parent_id for h in hits)) # 去重且保序
ctx = [store.get_parent(pid) for pid in parent_ids[:4]]去重是關鍵
同一個父片段底下可能有多個子片段被命中,若不去重就會重複塞入相同內容,白白浪費上下文。用 dict.fromkeys 去重可同時保留排名順序。
變形:上下文窗口擴展
更輕量的做法是不建父片段,而是命中子片段後,把它前後各一段一起取出來拼成上下文。實作更簡單,效果在多數情況下接近。
def expand(hit, store, window=1):
idx = hit.chunk_index
ids = range(max(0, idx - window), idx + window + 1)
return '\n'.join(store.get(hit.doc_id, i) for i in ids)父片段別設太大。塞四個 1500 字的父片段就是 6000 字,接近多數線上場景的上下文預算上限了。