File size: 4,854 Bytes
0e6887b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | """InformationExtractor + BackReferenceValidator 测试(任务 6)。
覆盖 Property 1(无捏造)/ 需求 4.1、4.2、4.5、9.5。
"""
from __future__ import annotations
from kernel.task_sheet import DocumentProfile, Intent
from kernel.understanding import BackReferenceValidator, InformationExtractor
SOURCE = "有关物质检测结果 总杂% 0.00 含量 99.19 限度 总杂≤2.0%"
def test_extractor_skips_header_label_as_value():
llm_out = {
"items": [
{"field": "value", "value": "样品名称", "source_ref": "样品名称"}, # 表头,应剔除
{"field": "value", "value": "0.00", "source_ref": "总杂% 0.00",
"group": {"attribute": "总杂"}},
]
}
items = InformationExtractor(llm=None).extract(SOURCE, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
values = [it.value for it in items]
assert "样品名称" not in values
assert "0.00" in values
def test_extractor_empty_without_llm_and_no_cache():
items = InformationExtractor(llm=None).extract(SOURCE, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY)
assert items == []
def test_validator_drops_unlocatable_items():
llm_out = {
"items": [
{"field": "value", "value": "0.00", "source_ref": "总杂% 0.00"}, # 可定位
{"field": "value", "value": "-10", "source_ref": "降解 -10%"}, # 原文不存在
]
}
items = InformationExtractor(llm=None).extract(SOURCE, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
kept, missing = BackReferenceValidator.validate(items, SOURCE)
kept_vals = [it.value for it in kept]
assert "0.00" in kept_vals
assert "-10" not in kept_vals
assert "value" in missing
def test_validator_whitespace_insensitive_match():
llm_out = {"items": [{"field": "spec_limit", "value": "总杂≤2.0%", "source_ref": "总杂 ≤ 2.0%"}]}
items = InformationExtractor(llm=None).extract(SOURCE, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
kept, missing = BackReferenceValidator.validate(items, SOURCE)
assert len(kept) == 1
assert missing == []
def test_validator_no_fabrication_property():
# Property 1:保留项要么数值存在于原文,要么引文为原文子串;捏造项被丢弃。
import re
llm_out = {
"items": [
{"field": "value", "value": "0.00", "source_ref": "总杂% 0.00"},
{"field": "value", "value": "fake", "source_ref": "不存在的内容xyz"},
]
}
items = InformationExtractor(llm=None).extract(SOURCE, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
kept, _ = BackReferenceValidator.validate(items, SOURCE)
norm_hay = re.sub(r"\s+", "", SOURCE)
assert all(it.value != "fake" for it in kept) # 捏造文字项被丢弃
for it in kept:
nums = re.findall(r"-?\d+(?:\.\d+)?", it.value)
grounded = (all(n in SOURCE or any(float(n) == float(m) for m in
re.findall(r"-?\d+(?:\.\d+)?", SOURCE)) for n in nums)
if nums else re.sub(r"\s+", "", it.source_ref) in norm_hay)
assert grounded
def test_validator_value_centric_keeps_when_number_present():
"""逐属性提示词下,source_ref 非连续子串但数值在原文 → 应保留(回归修复)。"""
source = "涂布厚度/mm 膜厚/mm 溶化时限/s 0.5 0.05 60"
llm_out = {
"items": [
{"field": "膜厚", "value": "0.05", "source_ref": "膜厚 0.05",
"group": {"attribute": "膜厚"}},
]
}
items = InformationExtractor(llm=None).extract(source, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
kept, missing = BackReferenceValidator.validate(items, source)
assert len(kept) == 1
assert kept[0].value == "0.05"
assert missing == []
def test_validator_drops_fabricated_number_not_in_source():
source = "涂布厚度/mm 膜厚/mm 0.5 0.05 60"
llm_out = {
"items": [
{"field": "膜厚", "value": "99.99", "source_ref": "膜厚 99.99",
"group": {"attribute": "膜厚"}},
]
}
items = InformationExtractor(llm=None).extract(source, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
kept, missing = BackReferenceValidator.validate(items, source)
assert kept == []
assert "膜厚" in missing
def test_validator_tolerates_float_format_difference():
source = "含量 99.50 %"
llm_out = {"items": [{"field": "含量", "value": "99.5", "source_ref": "含量 99.5"}]}
items = InformationExtractor(llm=None).extract(source, DocumentProfile(), Intent.DESCRIPTIVE_SUMMARY, llm_out=llm_out)
kept, _ = BackReferenceValidator.validate(items, source)
assert len(kept) == 1 # 99.5 ↔ 99.50 视为同值
|