fix: OCR fidelity scoring reform — prevent false fail from language-mismatched field names
Root cause (from review): field_coverage compared English JRXML field names against Chinese OCR field names with set intersection — always zero. Combined with 0.5 weight in score formula, caused valid JRXML (XSD pass, 82% element coverage) to score 0.41 < 0.5 → fail → correction loop → progressive destruction. Changes: - Scoring weight: element_coverage 0.8 + field_coverage 0.2 (was 0.5+0.5) - Validate node: only fail on fidelity when BOTH score<0.5 AND element_coverage<0.4 - Field name regex: \w+ → [^"]+ to support non-ASCII field names - Field matching: also try _sanitize_field_name conversion (Chinese→_uXXXX_) - correction.md: namespace check always active, not conditional on error keywords
This commit is contained in:
+16
-9
@@ -1207,8 +1207,8 @@ def _check_ocr_fidelity(jrxml: str, state: dict) -> dict:
|
||||
else:
|
||||
element_coverage = 1.0
|
||||
|
||||
# 2. 字段名覆盖
|
||||
jrxml_fields = set(re.findall(r'<field name="(\w+)"', jrxml))
|
||||
# 2. 字段名覆盖(英文字段名 vs OCR 中文字段名天然不匹配,权重降低)
|
||||
jrxml_fields = set(re.findall(r'<field name="([^"]+)"', jrxml))
|
||||
ocr_field_names = set()
|
||||
ocr_fields = ocr_result.get("fields", []) if isinstance(ocr_result, dict) else []
|
||||
for f in ocr_fields:
|
||||
@@ -1219,10 +1219,15 @@ def _check_ocr_fidelity(jrxml: str, state: dict) -> dict:
|
||||
|
||||
if ocr_field_names and jrxml_fields:
|
||||
matched = jrxml_fields & ocr_field_names
|
||||
field_coverage = len(matched) / max(len(ocr_field_names), 1)
|
||||
unmatched = ocr_field_names - jrxml_fields
|
||||
if unmatched:
|
||||
sample = list(unmatched)[:8]
|
||||
# 尝试通过 _sanitize_field_name 转义后匹配(中文→_uXXXX_)
|
||||
sanitized_ocr = {_sanitize_field_name(n) for n in ocr_field_names}
|
||||
matched_via_sanitize = jrxml_fields & sanitized_ocr
|
||||
all_matched = matched | matched_via_sanitize
|
||||
field_coverage = len(all_matched) / max(len(ocr_field_names), 1)
|
||||
still_unmatched = {n for n in ocr_field_names
|
||||
if n not in jrxml_fields and _sanitize_field_name(n) not in jrxml_fields}
|
||||
if still_unmatched:
|
||||
sample = list(still_unmatched)[:8]
|
||||
issues.append(f"OCR 字段未在 JRXML 中声明: {', '.join(sample)}")
|
||||
elif ocr_field_names and not jrxml_fields:
|
||||
field_coverage = 0.0
|
||||
@@ -1247,8 +1252,9 @@ def _check_ocr_fidelity(jrxml: str, state: dict) -> dict:
|
||||
f"OCR 布局分析有 {ocr_columns} 列"
|
||||
)
|
||||
|
||||
# 综合评分
|
||||
score = round(field_coverage * 0.5 + element_coverage * 0.5, 3)
|
||||
# 综合评分(元素覆盖为主权重 0.8,字段覆盖为辅助 0.2)
|
||||
# 英文字段名 vs 中文 OCR 字段名天然不匹配是预期行为,字段覆盖仅作参考
|
||||
score = round(element_coverage * 0.8 + field_coverage * 0.2, 3)
|
||||
return {
|
||||
"score": score,
|
||||
"field_coverage": round(field_coverage, 3),
|
||||
@@ -1291,7 +1297,8 @@ def validate(state: AgentState) -> Dict:
|
||||
if fidelity["issues"]:
|
||||
if state["status"] == "pass":
|
||||
# XSD 通过但内容保真度不足 → 降级为 fail
|
||||
if fidelity["score"] < 0.5:
|
||||
# 需要 score < 0.5 且 element_coverage < 0.4(字段名语言不匹配不应单独导致 fail)
|
||||
if fidelity["score"] < 0.5 and fidelity.get("element_coverage", 0) < 0.4:
|
||||
state["status"] = "fail"
|
||||
state["error_msg"] = (
|
||||
f"[内容保真度不足] 得分 {fidelity['score']:.2f}/1.0。"
|
||||
|
||||
Reference in New Issue
Block a user