體消歧:替換原文之前先保護(hù)字符偏移)
同一份長文檔里出現(xiàn)兩個(gè)“張偉”可能是同一個(gè)人的不同描述也可能是兩家公司的人。給它們加命名空間有助于檢索但在討論聚類模型之前有一個(gè)更樸素的錯(cuò)誤值得先排除替換后的字符串還能不能對(duì)上原始位置假設(shè)第一處姓名被擴(kuò)展成“張偉【甲公司】”后面的字符位置都會(huì)移動(dòng)。只在每個(gè)實(shí)體簇里倒序替換還不夠不同簇之間也共享同一條字符串必須把全部編輯按原始位置統(tǒng)一處理。編輯計(jì)劃先于字符串修改把消歧器的輸出表示為起點(diǎn)、終點(diǎn)、替代文本、實(shí)體ID先檢查范圍和重疊再從右向左應(yīng)用。原文保持不變修改后的文本另行保存。這樣語義模型即使產(chǎn)生壞位置執(zhí)行層也能拒絕而不是悄悄污染其他實(shí)體。from dataclasses import dataclass dataclass(frozenTrue) class Edit: start: int end: int replacement: str def apply_edits(text, edits): ordered sorted(edits, keylambda e: (e.start, e.end)) previous_end 0 for e in ordered: if not (0 e.start e.end len(text)): raise ValueError(invalid span) if e.start previous_end: raise ValueError(overlapping edits) previous_end e.end result text for e in reversed(ordered): result result[:e.start] e.replacement result[e.end:] return result original 張偉審閱李明復(fù)核張偉簽字。 edits [Edit(0, 2, 張偉【甲】), Edit(11, 13, 張偉【乙】)] # Obtain the second span from the untouched original, never from edited text. pos original.rindex(張偉) edits[1] Edit(pos, pos 2, 張偉【乙】) result apply_edits(original, edits) assert result 張偉【甲】審閱李明復(fù)核張偉【乙】簽字。 assert original 張偉審閱李明復(fù)核張偉簽字。 try: apply_edits(original, [Edit(0, 3, x), Edit(2, 4, y)]) except ValueError: pass else: raise AssertionError(overlap was accepted) print(global reverse edits, unchanged source, overlap rejection: PASS)別讓命名空間制造新的事實(shí)圖里的ID只表示區(qū)分不證明兩次出現(xiàn)一定屬于不同的人。真正的消歧還需要文檔身份、段落、所屬組織和時(shí)間。相似度閾值只能生成候選證據(jù)不足時(shí)保留“尚未確認(rèn)是否同人”比強(qiáng)行拆成兩個(gè)實(shí)體可靠。10 月21日的Kimi Code更新把插件Skill調(diào)用改成限定名避免同名技能互相遮蔽。這是另一個(gè)層面的命名空間問題不能當(dāng)作文本消歧算法但它說明名字相同不意味著身份相同。官方更新這個(gè)例子已在本地驗(yàn)證跨位置擴(kuò)長、原文不變和重疊拒絕。它沒有運(yùn)行NER、嵌入聚類或共指模型也沒有得出消歧準(zhǔn)確率。若要測效果應(yīng)該分別標(biāo)注“同名不同人”和“異名同一人”并檢查重寫是否引入錯(cuò)誤歸屬。只統(tǒng)計(jì)字符串替換成功不等于語義消歧成功。