From 7e2ee912b3fd08b6b571fcd1e7a1d582d32a2cf4 Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Wed, 21 Oct 2026 15:37:41 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=93=E8=AE=BA=E5=8F=A5=E7=9A=84=E5=88=A4?= =?UTF-8?q?=E5=AE=9A=E5=9B=9E=E5=88=B0=E5=8E=9F=E6=9D=A5=E7=9A=84=E6=96=B9?= =?UTF-8?q?=E5=90=91=E8=AF=8D=E3=80=81=E5=9B=A0=E6=9E=9C=E8=AF=8D=EF=BC=88?= =?UTF-8?q?evidence.=5FDIRECTIONAL=20=E7=85=A7=20main=20=E5=8E=9F=E6=A0=B7?= =?UTF-8?q?=EF=BC=89=EF=BC=9AW1-d=20=E4=B8=BA=E4=BA=86=E8=AE=A9=E8=A3=81?= =?UTF-8?q?=E5=88=A4=E4=BC=98=E5=85=88=E5=88=A4=E5=88=A4=E6=96=AD=E5=8F=A5?= =?UTF-8?q?=E6=8A=8A=E3=80=8C=E4=B8=BB=E8=A6=81=E3=80=81=E9=9B=86=E4=B8=AD?= =?UTF-8?q?=E3=80=81=E5=BC=82=E5=B8=B8=E3=80=81=E5=81=8F=E7=A6=BB=E3=80=81?= =?UTF-8?q?=E6=8C=81=E7=BB=AD=E3=80=81=E8=B6=8B=E5=8A=BF=E3=80=81=E6=98=BE?= =?UTF-8?q?=E8=91=97=E3=80=81=E5=A4=A7=E5=B9=85=E3=80=81=E6=96=B0=E9=AB=98?= =?UTF-8?q?=E3=80=81=E6=96=B0=E4=BD=8E=E3=80=81=E6=8A=B5=E6=B6=88=E3=80=81?= =?UTF-8?q?=E5=88=86=E6=95=A3=E3=80=8D=E7=AD=89=E5=8A=A0=E8=BF=9B=E4=BA=86?= =?UTF-8?q?=20=5FDIRECTIONAL=EF=BC=8C=E5=8F=AF=20=5Fclassify=20=E7=94=A8?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E4=B8=AA=E6=AD=A3=E5=88=99=E8=AE=A4=E7=BB=93?= =?UTF-8?q?=E8=AE=BA=E5=8F=A5=EF=BC=8C=E6=B2=A1=E6=9C=89=E6=95=B0=E5=AD=97?= =?UTF-8?q?=E3=80=81=E6=B2=A1=E6=9C=89=E5=BC=95=E7=94=A8=E7=9A=84=E3=80=8C?= =?UTF-8?q?=E4=B8=8B=E9=9D=A2=E6=98=AF=E4=B8=BB=E8=A6=81=E6=B8=A0=E9=81=93?= =?UTF-8?q?=E7=9A=84=E8=A1=A8=E7=8E=B0=E3=80=82=E3=80=8D=E3=80=8C=E4=BF=83?= =?UTF-8?q?=E9=94=80=E6=9C=9F=E9=97=B4=E6=B4=BB=E5=8A=A8=E6=95=88=E6=9E=9C?= =?UTF-8?q?=E6=98=BE=E8=91=97=E3=80=82=E3=80=8D=E3=80=8C=E6=95=B4=E4=BD=93?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E5=B9=B3=E7=A8=B3=EF=BC=8C=E6=9C=AA=E8=A7=81?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E3=80=82=E3=80=8D=E5=B0=B1=E6=88=90=E4=BA=86?= =?UTF-8?q?=E7=BB=93=E8=AE=BA=E5=8F=A5=EF=BC=8C=E7=BB=93=E8=AE=BA=E5=8F=A5?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E8=A6=81=E6=B1=82=E6=8C=82=E4=BE=9D=E6=8D=AE?= =?UTF-8?q?=EF=BC=88=E6=A8=A1=E6=9D=BF=20=E2=91=A8=20=E5=92=8C=E5=B7=B2?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E7=9A=84=E5=8F=97=E7=AE=A1=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E9=83=BD=E8=BF=99=E4=B9=88=E5=86=99=EF=BC=89=E6=97=B6=E8=AE=A1?= =?UTF-8?q?=E5=85=A5=E7=BC=BA=E5=8F=A3=E3=80=81=E5=87=BA=E5=85=B7=E9=99=8D?= =?UTF-8?q?=E6=A1=A3=EF=BC=8C=E6=94=B9=E4=BA=86=E5=B7=B2=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=9A=84=E6=A1=A3=E4=BD=8D=EF=BC=9B=E5=87=BA?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=20io.=5Fconcluding=20=E4=B9=9F=E7=85=A7?= =?UTF-8?q?=E5=AE=83=E8=AE=A4=E4=BB=A3=E7=A0=81=E5=9D=97=E9=87=8C=E7=9A=84?= =?UTF-8?q?=E6=AD=A3=E6=96=87=E3=80=82=E6=89=A9=E5=85=85=E7=9A=84=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E8=AF=8D=E6=8C=AA=E5=88=B0=20judge.=5FJUDGEMENT?= =?UTF-8?q?=EF=BC=8C=E5=8F=AA=E7=BB=99=20claim=5Fpriority=20=E6=8E=92?= =?UTF-8?q?=E9=80=81=E5=88=A4=E7=9A=84=E5=85=88=E5=90=8E=EF=BC=88=E7=BB=93?= =?UTF-8?q?=E8=AE=BA=E5=8F=A5=E9=87=8C=E6=9C=89=E5=AE=83=E4=BB=AC=E7=9A=84?= =?UTF-8?q?=E6=8E=92=E7=AC=AC=E4=BA=8C=EF=BC=89=E3=80=82=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=9A=E5=88=A4=E6=96=AD=E8=AF=8D=E8=AE=A9=E7=BB=93=E8=AE=BA?= =?UTF-8?q?=E5=8F=A5=E5=85=88=E9=80=81=E5=88=A4=E3=80=81=E4=B8=8D=E8=AE=A9?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E6=80=A7=E7=9A=84=E8=AF=9D=E5=8F=98=E6=88=90?= =?UTF-8?q?=E7=BB=93=E8=AE=BA=E5=8F=A5=EF=BC=9B=E7=BB=93=E8=AE=BA=E5=8F=A5?= =?UTF-8?q?=E8=A6=81=E6=8C=82=E4=BE=9D=E6=8D=AE=E3=80=81=E5=87=BA=E5=8F=A3?= =?UTF-8?q?=E5=B8=A6=E5=A5=91=E7=BA=A6=E7=9A=84=E5=91=A8=E6=8A=A5=E5=A4=9A?= =?UTF-8?q?=E5=86=99=E8=BF=99=E4=B8=89=E5=8F=A5=EF=BC=8C=E6=A1=A3=E4=BD=8D?= =?UTF-8?q?=E7=85=A7=E6=97=A7=20formal=E3=80=81=E6=B2=A1=E6=8C=82=E4=BE=9D?= =?UTF-8?q?=E6=8D=AE=E7=9A=84=E7=BB=93=E8=AE=BA=200=20=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/engine/evidence.py | 9 ++------- backend/app/engine/judge.py | 18 ++++++++++++++---- backend/tests/test_analysis_claims.py | 16 +++++++++++----- backend/tests/test_report_analysis_claims.py | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/backend/app/engine/evidence.py b/backend/app/engine/evidence.py index c77667e0..638d2d17 100644 --- a/backend/app/engine/evidence.py +++ b/backend/app/engine/evidence.py @@ -2870,16 +2870,11 @@ def _context(text: str, start: int, end: int) -> str: _BOLD = re.compile(r"(\*\*|__)(?P(?:\[\[" + _MARKER_GUARD + r"[^\[\]\n]*?\]\]|(?!\1)[^\n])+?)\1") #: 方向词、因果词:没有数字也没有引用的句子,含这些词才算结论。「同比」「环比」不在里面:它们只说明 #: 跟谁比,本身不是涨跌;真正的比较结论还会带「增长」「下降」或者数字。 -#: 分析判断词(分析能力一轮,engine/analysis_claims 的说法表)也算:「主要来自」「集中在」「异常」「持续下降」「趋势」 -#: 「显著」,裁判优先判这类句子(judge.claim_priority)。「主要」后面是「包括、内容、分为、有、看」这类的是在列提纲, -#: 「持续关注」「持续跟进」是建议,「趋势图」「趋势如下」是在引出图表,「集中采购」「分散风险」说的不是数据,都不算 +#: 分析判断词(「主要」「异常」「趋势」「显著」……)不在这里:一句话算不算结论决定了结论句策略要不要它挂依据、出具缺口 +#: 怎么数,已发布的版本按这份词表定了档位,扩了就变;裁判优先判判断句另用 judge._JUDGEMENT 排序,只影响送判的先后 _DIRECTIONAL = re.compile( r"增长|增加|上升|提升|提高|上涨|下降|下滑|减少|降低|回落|下跌|反弹|超过|高于|低于|领先|落后|最高|最低" r"|最多|最少|来自|导致|因为|由于|带动|拉动|拖累|驱动|原因|归因|贡献|占比|翻倍|持平|波动" - r"|主要(?!包括|内容|分为|分成|有|看|从|是指|指|结论|发现|观点|工作|任务|目的|目标|问题|方面)" - r"|集中(?!采购|管理|处理|展示|讨论|培训)|异常|偏离" - r"|持续(?!关注|跟踪|跟进|观察|监控|推进|优化|改进|更新)|趋势(?![图表线如::])|显著|明显高于|明显低于|大幅|激增" - r"|骤降|暴跌|飙升|新高|新低|抵消|分散(?!注意|精力|风险|投资|采购)" r"|(?= SHORT_CHARS: return 3 diff --git a/backend/tests/test_analysis_claims.py b/backend/tests/test_analysis_claims.py index 5a5b9a8c..18c9f7f1 100644 --- a/backend/tests/test_analysis_claims.py +++ b/backend/tests/test_analysis_claims.py @@ -454,12 +454,18 @@ def test_the_prompt_rules_depend_on_whether_there_are_conclusions(): assert "[[a:A1]]" in ac.ANALYSIS_RULES_PROMPT -def test_judgement_words_make_a_sentence_a_claim_for_the_judge(): +def test_judgement_words_rank_claims_for_the_judge_but_do_not_make_sentences_claims(): + """判断词只管裁判送判的先后(judge._JUDGEMENT):一句话算不算结论仍按原来的方向词、因果词(evidence._DIRECTIONAL), + 结论句策略要求挂依据、出具缺口照它数——扩了就改了已发布版本的档位。""" from app.engine.judge import claim_priority - doc = compose_doc("华东异常。\n\n下面主要看三个方面。\n\n建议持续关注。\n\n近 8 周的趋势图如下:", catalog()) + doc = compose_doc("华东异常。\n\n华东异常,退款 12 单。\n\n下面是主要渠道的表现。\n\n促销期间活动效果显著。\n\n" + "整体运行平稳,未见异常。\n\n建议持续关注。\n\n近 8 周的趋势图如下:\n\n华东退款 12 单。", catalog()) kinds = {doc["markdown"][slice(*u["span"])]: (u["kind"], claim_priority(u, b, doc["markdown"])) for b, u in evidence.iter_units(doc)} - assert kinds["华东异常。"] == ("claim", 2) - assert kinds["下面主要看三个方面。"][0] == "connective" and kinds["建议持续关注。"][0] == "connective" - assert kinds["近 8 周的趋势图如下:"][0] == "connective", "引出图表的话不算判断" + for text in ("华东异常。", "下面是主要渠道的表现。", "促销期间活动效果显著。", "整体运行平稳,未见异常。", "建议持续关注。", + "近 8 周的趋势图如下:"): + assert kinds[text] == ("connective", None), text + assert doc["stats"]["uncited_claims"] == 2, "只有两句带数字的算结论" + assert kinds["华东异常,退款 12 单。"] == ("claim", 2), "结论句里的判断词让裁判先判它" + assert kinds["华东退款 12 单。"] == ("claim", 3) diff --git a/backend/tests/test_report_analysis_claims.py b/backend/tests/test_report_analysis_claims.py index 7c72ddfe..c22eef74 100644 --- a/backend/tests/test_report_analysis_claims.py +++ b/backend/tests/test_report_analysis_claims.py @@ -265,6 +265,24 @@ async def test_the_scope_is_written_only_when_there_are_conclusions(monkeypatch, assert "analysis_scope" not in doc +# -------------------------------------------------------------------------- +# 判断词不改一句话算不算结论:已发布版本的档位不变 +# -------------------------------------------------------------------------- + + +@pytest.mark.parametrize("extra", ["整体运行平稳,未见异常。", "下面是主要渠道的表现。", "促销期间活动效果显著。"]) +async def test_judgement_words_do_not_turn_connective_sentences_into_uncited_claims(monkeypatch, extra): + """已发布的受管版本(结论句要挂依据、出口带契约):没有数字、没有引用的话照旧是连接性的话,不因为带了「主要」「异常」 + 「显著」就算没挂依据的结论、记缺口降档(判断词只给裁判排送判的先后,judge._JUDGEMENT)。""" + graph = weekly(numbers="strict", on_violation="flag", claims="require_citation") + graph["nodes"][-1]["data"]["config"]["contract"] = { + "report_from": "write", "metrics_from": ["caliber"], "required": ["gmv"], "strict": True} + script(monkeypatch, f"{PLAIN}\n\n{extra}") + issuance = (await finish(graph)).output["_issuance"] + assert issuance["tier"] == "formal" and issuance["gaps"] == [] + assert issuance["claims"] == {"policy": "require_citation", "uncited_claims": 0, "uncited": []} + + # -------------------------------------------------------------------------- # 取值写错 # --------------------------------------------------------------------------