Recap: 履歷進得來了,也拆成欄位了,今天開始拿它跟職缺對照
職缺的每一條要求,去履歷裡找有沒有對應的證據
找到就附上原句,找不到就說找不到
分兩段做。模型負責判定並給出引用,程式負責確認那段引用真的存在
schema 也照這條線切開:
# --- 以下由模型填 ---
requirement: str
verdict: MatchVerdict
quote: str | None
# --- 以下由程式驗證後補上,模型不得填寫 ---
quote_verified: bool | None = None
quote_start: int | None = None
quote_end: int | None = None
模型可以說它引用了某句話,但那句話存不存在由程式決定
判定三態:direct 明確寫到、indirect 可推得但沒直說、not_found 沒有相關內容
not_found 的語意在 prompt 裡寫死:
履歷沒寫到不等於求職者不會。not_found 的意思是「履歷沒有證據」,不是「這個人沒有這個能力」
差別在下游。Day 12 排學習計畫時,如果把 not_found 讀成「不會」,會叫一個其實會的人去從頭學
還有一條:寧可判 not_found,也不要為了湊證據而引用不相干的句子
quote in source第一版就是這樣寫的,然後發現誠實引用會被判成捏造
pypdf 抽出來的文字帶著 PDF 的換行跟多重空格,模型複述時會把它正規化掉
實測一句 180 字的引用,原樣比對 False,空白正規化後 True —— 模型其實照抄了,是空白害的
所以比對前先壓平空白、統一全半形(NFKC)、casefold,而且要留一張索引表,
否則比對成功也指不出位置,UI 標不亮原文
連字號還有個坑:PDF 常把 end-to-end 這種詞斷在連字號後換行
只吃掉換行、保留連字號,不然多出來的空格會讓誠實引用被判成「改過字」
找不到完全相符時,要分辨「改了兩個字」跟「整句捏造」
不能用最長連續片段當分數 —— 在句子中間插一個詞(模型最常見的動手腳方式)會把字串切成兩半,
最長片段只剩一半,誠實引用會被打成捏造
similarity = sum(b.size for b in blocks) / len(n_q)
這個分數的意思是「模型宣稱引用的內容,有多少比例真的照順序出現在原文裡」
判定也是三態,altered 不算通過:
| 判定 | 意思 |
|---|---|
exact |
正規化後完全相符,引用可信 |
altered |
找得到很接近的原句,但模型改過字 —— 警訊 |
not_found |
原文裡沒有這句話 |
誤判的成本不對稱:把誠實引用判成捏造,使用者會不信任系統;把捏造判成照抄,系統就沒有存在意義了
_NEAR_MISS_THRESHOLD = 0.85 沒有任何根據,就是試出來的起點
Day 25 建評估規準時要拿資料集重新校準,先記在這裡
另外模型偶爾會自相矛盾:判了 not_found 卻附上引用
這種清掉引用並記一句 判定為 not_found 卻附上引用,已忽略該引用,不是靜默吞掉
版本:Python 3.12.10,比對只用標準庫的 difflib 與 unicodedata
證據對得起來了,接下來是改寫
明天要讓它只能重組既有事實,不能長出新的