一個法務案件不會只有一份文件。典型的組成:
律師要做的事情之一是交叉比對:契約上的保證人跟保證書上的簽名人是不是同一人?陳情書裡說的還款日期跟催收紀錄對不對得上?答辯狀裡提到的第三人有沒有出現在其他文件?
這些都需要跨文件的實體關聯。而去識別化如果做得太徹底,這個能力就沒了。
昨天的結論是「案件內一致,跨案件不可關聯」。這個設計剛好對應了業務需求:
所以 scope_id 應該設成案件編號,而不是 session ID 或文件 ID。
scope_id = f"case:{case_no}"
這樣同一個案件的所有文件共用同一個 Token 空間,模型看到的是:
契約: 立約人林建成,連帶保證人張雅婷
保證書: 保證人張雅婷
起訴狀: 被告林建成、張雅婷
模型能正確地判斷「保證書上的張雅婷跟契約上是同一人」。它不知道真名是誰,但它知道這是同一個人——而這正是法律分析需要的。
scope_id 設得越大,可比對範圍越大,同時可關聯風險也越大。
| scope 粒度 | 可比對範圍 | 風險 |
|---|---|---|
| 單一文件 | 文件內 | 最低 |
| 案件 | 案件內所有文件 | 低 |
| 客戶 | 該客戶所有案件 | 中 |
| 部門 | 全部 | 高 |
「客戶」這一級聽起來合理(律師常需要看同一客戶的歷史案件),但它有一個問題:Token 變成了客戶的穩定識別碼。 一旦某個 Token 在某個案件裡被還原確認,該客戶的所有歷史案件就都被關聯起來了。
我的建議是預設「案件」級,需要跨案件比對時走一個明確的、需授權的合併流程:
def create_merged_scope(case_ids: list, requester: str,
reason: str) -> str:
"""建立跨案件的合併 scope,需授權並留痕"""
require_permission(requester, "scope:merge")
merged_id = f"merged:{uuid4()}"
audit_log.write({
"action": "scope_merge",
"actor": requester,
"cases": case_ids,
"reason": reason,
"merged_scope": merged_id,
"ts": now(),
})
return merged_id
把「擴大可關聯範圍」變成一個需要理由、需要留痕的動作,而不是預設行為。這是最小權限原則在資料關聯上的應用。
就算所有個資都遮乾淨了,文件的結構仍然可能洩漏資訊。
文件長度。 兩份看起來完全去識別化的文件,如果長度、段落數、章節結構完全一致,可以推斷它們來自同一個範本、可能是同一批案件。
日期關聯。 就算日期被概化到年,「文件 A 的日期早於文件 B」這個順序關係仍然保留。結合公開資訊(例如某個新聞事件的日期),可能推回具體時間。
金額。 金額通常不去識別化(D9),但「借款餘額新臺幣 1,234,567 元」這種精確到個位數的數字,本身就是一個很強的準識別碼。如果攻擊者有部分外部資料,這個數字足以定位。
這一項在實務上被低估。我的建議是對高精確度的數值做輕度概化:
def generalize_amount(amount: int) -> str:
if amount < 100_000:
return f"新臺幣 10 萬元以下"
if amount < 1_000_000:
return f"新臺幣 {amount // 100_000 * 10} 萬元級距"
return f"新臺幣 {amount // 1_000_000} 百萬元級距"
但這會影響法律判斷的精確度。所以要看任務——如果 LLM 的任務是「摘要爭點」,概化沒問題;如果任務是「計算利息」,就必須保留原值。
這個取捨應該由業務單位決定,而且要寫進場景設定,不是由工程師預設。 我的作法是把它做成場景層級的設定項,讓場景管理者(D19 的角色之一)自己選。
多份文件合併處理時會遇到衝突:
契約: 保證人 陳美玲,身分證 A223456789
保證書: 保證人 陳美玲,身分證 A223456780 ← 最後一碼不同
這是同一個人打錯字,還是兩個同名的人?
系統不應該猜。正確做法是:
def detect_entity_conflict(entities):
conflicts = []
by_name = defaultdict(list)
for e in entities:
by_name[e["name"]].append(e)
for name, group in by_name.items():
ids = {e.get("tw_id") for e in group if e.get("tw_id")}
if len(ids) > 1:
conflicts.append({
"name_token": group[0]["token"],
"distinct_ids": len(ids),
"note": "同名但識別碼不同,需人工確認",
})
return conflicts
寧可讓下游知道有不確定性,也不要幫它決定。 自動合併兩個實體,可能造成法律判斷的錯誤;自動分開,可能漏掉關聯。兩種錯誤都比「標記出來讓人決定」糟糕。
明天進可控還原:先從 Token 隔離講起。
我是 Fngi,專注在 AI 資安、LLM 紅隊與 AI 治理框架落地。
IG:@aid3fend
有想討論的架構細節或不同意見,留言或私訊都歡迎。