如果一份文件前半段說明適用條件,後半段才提出做法,切塊後只取回後半段,讀者還能知道那些條件嗎?這是我接著整理「從心出發」檢索設計時,要先回答的問題。向量資料庫能保存片段,卻不能替切割時遺失的上下文負責。
第八天談的是檢索介面,以及來源撤回後如何停止取用。往資料進入系統的方向再走一步,會遇到三件事:chunking 把文件切成片段;embedding 把文字轉成供比較的向量;metadata 則保存來源、版本與使用條件等描述資料。這三件事若各做各的,最後可能剩下一段很像答案、卻難以追問來歷的文字。
今天整理的是既有離線契約與參考程式。正式語意切塊、模型 embedding 與生產資料管線仍屬於 Planned。本日尚未完成此部分,以下先整理目前設計與下一步;現有程式能檢查的結構問題,與尚待驗證的檢索品質,必須分開看。
目前的切塊規則很保守:以 UTF-8 位元組數為上限,盡量取出能容納的完整 Unicode 碼位。UTF-8 用不同長度的位元組表示字元;如果切點落在同一個碼位的編碼中間,程式就把切點往前退,再解碼成文字。
這套規則沒有改寫句子,也沒有把空白、換行或組合字元整理成另一種形式。切片保存原文的起訖位元組位置,依順序接回去,應能還原輸入。對現在的契約而言,先保留「切片對應到哪一段原文」這件事,才有辦法檢查後續資料是否被換掉。
但碼位完整只是很低的一層要求。使用者眼中的一個字形,可能由多個碼位組成;Unicode 的文字分段標準,也把字素群集、詞與句子的邊界分開定義。Unicode UAX #29 因此,即使每一片都能正常解碼,仍可能拆開一個組合字形,更不用說把一句話切成兩半。現有演算法沒有做到字素或語意分段。
目前片段之間也沒有重疊;設定非零重疊會被拒絕。重疊是讓相鄰片段保留部分相同內容的方式,但這裡不能只加一個參數就宣稱改善了上下文。片段的位置、身分與重建規則都會跟著改變,需要重新定義與驗證。我也沒有測量不同大小的檢索效果,因此不會把預設切塊大小寫成最佳值。
只保存文字與向量,日後遇到來源更新時,就很難確認哪些片段仍屬於舊版本。現有 Chunk 資料結構把這條關係直接放進欄位。以下節錄自 src/psychological_support/conversation/ingestion_chunking.py,是離線契約的原始欄位,不是正式服務的操作範例:
content_hash: Digest
namespace: Namespace
source_version: Token
provenance: Provenance
withdrawn_with: Token
policy: ChunkPolicy
content_hash 是內容指紋,用來核對切片內容;namespace 指出它所屬的資料範圍;source_version 保留來源版本;provenance 保存來源追溯資訊;withdrawn_with 指向撤回時必須跟著停止取用的父紀錄;policy 則保存切割規則。完整結構另有父紀錄身分、順序與原文位置。
我在這裡想保留的,是「為什麼這一片仍然可以被使用」的查核線索。字串一樣,不代表資料身分一樣:相同內容可能來自不同來源,也可能具有不同使用權限。現有片段識別的計算包含父紀錄指紋、切割規則、順序、範圍與內容指紋,避免只看文字就把這些差異丟掉。
這也說明為什麼 metadata 不能只是任意填寫的備註。不過,欄位齊全仍不等於來源可信。內容指紋可以協助檢查內容是否改變,無法證明作者身分、授權真實性或論述正確性;現有來源鏈檢查處理的是內部資料一致性,外部來源資格仍需要另外查證。
語意 embedding 通常把文字編碼成向量,再透過相似度函式比較;Sentence Transformers 的官方範例便將編碼與向量比較分成兩步。Semantic Textual Similarity 但專案裡出現一個名叫 embedding 的介面,不代表已經接上這類模型。
「從心出發」目前的 ReferenceEmbedding 使用文字雜湊產生固定的測試向量。它讓同一份合成資料可以重複走過契約流程,卻沒有語意理解能力。用它測試資料綁定是合理的,用它證明「意思相近的句子會更靠近」就超出了證據。
因此,現有回傳檢查先處理更基本的錯誤:向量是否對應原本那個片段?內容指紋有沒有對上?供應端版本與向量維度是否符合請求?數值是否有限,而且不是整組零?這些檢查能拒絕部分錯配或不合法回應;即使全部符合,也只能說回傳符合契約,不能說檢索結果有用。
同樣地,供應端版本欄位的前後一致,也不是模型身分的外部證明。之後若換成真實模型,還需要保存可核對的模型與版本依據,並驗證索引端與查詢端的相容性。目前缺少明確提供的離線 embedding 供應端時,流程會回報不可用,沒有自動尋找外部服務來補上。
這次重新核對的離線測試涵蓋混合文字重建、位元組範圍、空白保留、切割規則身分,以及 embedding 回傳錯配等情況。它們使用合成資料,能支持的結論限於這些案例下的契約行為。我沒有因此取得真實語料的召回率、最佳重疊量或心理支持效果。
若要往正式管線前進,我會把驗證分成兩層。第一層檢查資料是否忠實:切片能否回到正確原文、版本是否保留、來源失效後是否仍被取用。第二層才檢查內容是否足夠:片段有沒有帶上必要條件,能不能支持特定回答。前一層通過,不會自動讓後一層成立。
開場的例子也可以成為後續測試設計:用清楚標示的合成文件,把條件與說明放在切點兩側,觀察取回結果是否保留理解所需的資訊。這是待驗證方案,還不是已完成的實驗。對心理支持內容尤其不能把片段當成對個人的診斷或治療依據;可追溯性讓人有機會查核,並不提供臨床適用性的保證。
寫到這裡,我想帶走的方法是:替每個切片保留可回溯的身分,替每個向量保留可核對的綁定,再用另外的證據評估內容品質。接下來真正要處理的 RAG,也就是先檢索資料再輔助生成回答的流程,還有一個問題:即使片段來源正確,系統要如何確認它足以支持準備說出口的那一句話?