跳到正文
DEV Community· Basavaraj SH·· 2 小時前AI 評分57

只改一個欄位:比整體公平率更能揭示個案翻轉的公平性測試

Flip One Field: A Fairness Test That Beats Aggregate Parity

AI 導讀

這項反事實壓力測試透過只改變姓名或措辭等無關欄位,檢查 LLM 輔助決策系統對同一案例的判斷是否改變。四個姓名配合三種提示詞改寫可形成 12 個版本;作者建議按每宗申請報告最壞翻轉率,並把羣聚翻轉視為偏差、零散翻轉視為不穩定,分別從提示詞、資料或模型,以及採樣、輸出限制或人工覆核着手處理。測試需付出 N× 推理呼叫成本,而哪些欄位與決策無關則屬產品與政策判斷,不只是工程問題。

正文

Cover image for Flip One Field: A Fairness Test That Beats Aggregate Parity

Basavaraj SH

Most teams check an LLM-assisted decision system for fairness by comparing approval rates across groups. That check can pass cleanly while the model is still changing its mind on individual cases for reasons nobody would defend out loud. Recent fairness-stress work on LLM decision-making points at a better default test - and it's a decision you can make before writing any code.

Aggregate Parity Nets Out; Per-Case Instability Doesn't

The choice is between two measurements. Outcome parity asks: across 1,000 applications, did group A get approved at roughly the same rate as group B? Counterfactual stress asks something narrower and harder: for this one application, if I change only a decision-irrelevant field - the name, the phrasing of the same request, the order of the bullet points - does the answer move?

A model that favors one group on early-career cases and another on senior cases can show perfect parity overall. Parity is cheap and it's what regulators often ask for, but it averages. Per-case stress testing catches that, because it never aggregates across people - it compares a case to itself.

The trade-off is real. Stress testing costs N× the inference calls, and it requires someone to declare which fields are decision-irrelevant. That list is a policy judgment, not an engineering one, which is exactly why a PM should define it.

Running the Test on One Application

base = {"years_exp": 6, "skills": "python, sql"}
names = ["Alex Chen", "Aisha Khan", "John Smith", "Priya Patel"]

votes = [decide(tmpl, {**base, "name": n})
 for n in names
 for tmpl in PROMPT_TEMPLATES] # 3 paraphrases, same instruction

flip_rate = 1 - max(votes.count(v) for v in set(votes)) / len(votes)

Twelve variants of one application that a human reviewer would call identical. Any flip_rate above zero means the decision moved on something that shouldn't matter.

The number alone isn't the point - the pattern is. Read the flips two ways:

  1. Clustered - all rejections land on the same name group across all three paraphrases. That's bias. Fix it in the prompt, the retrieval data, or the model choice.
  2. Scattered - flips appear randomly across names and templates. That's instability. Lower the temperature, constrain the output format, or stop auto-deciding borderline cases.

Both fail the same test and need different fixes, which is why one aggregate percentage can't tell you what to do next. Report worst-case flip rate per application, not the mean - the mean hides the cases that would end up in a complaint.

Key Takeaways

  • Group-level parity can look clean while individual decisions flip on irrelevant details; counterfactual stress testing compares each case against itself and catches what averages hide.
  • Separate clustered flips (bias - fix prompt, data, or model) from scattered flips (instability - fix sampling, output constraints, or add human review).
  • The hard part isn't the code, it's agreeing on which input fields are decision-irrelevant. That list belongs to product and policy, not just engineering.

Which fields in your decision prompt would your team actually agree are irrelevant - and how long would that meeting take?


Sources referenced: FairStress: A deeper evaluation of fairness in LLM decision-making, Hugging Face Blog

來源:DEV Community · dev.to