Files
AgentLab/backend/tests/test_judge_entity_sql.py
ThearchyHelios e859c13433 结论句裁判看得到表名、字段名出现过的 SQL;讲算法的句子挂到那次查询上
- 以前裁判给表名、字段名的证据只有一行名字。「这个数由某表按某字段去重计数得出」这种讲算法的句子,
  证据在 SQL 里(COUNT(DISTINCT …)),裁判看不到,只能判「证据不支持」——面板上明明写着「出现在查询 Q1」
- 现在摘录里附上名字出现过的查询的 SQL(每条截 300 字,最多 3 条,只读封存范围内的工件):
  表用它自己记的查询;只在 SQL 里出现、不是结果列的字段,从它所在的表用到的查询里找,
  文档目录里没有这张表时看全部查询,SQL 里要写了字段名(允许 t.字段 这种前缀)和表名才算
- 写作提示:有表结构时多一句——说明一个数是怎么算出来的(按哪个字段去重、怎么汇总、筛了什么条件),
  句末挂 [[see:Qn]] 指向算出它的那次查询;只挂表名、字段名指不出是哪一次查询算出的
2026-09-29 16:07:19 +08:00

127 lines
6.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""裁判看引用表名、字段名的句子时,要看得到这些名字出现过的那几次查询的 SQL。
「这个数由 orders 按 orders.member_no 去重计数得出」这种讲算法的句子,证据在 SQL 里
(COUNT(DISTINCT member_no))。以前表名、字段名的摘录只有一行名字,裁判只能判「证据不支持」——
面板上明明写着「出现在查询 Q1」,这层关联却没交给裁判。
"""
from __future__ import annotations
from app.engine.evidence import build_catalog, compose_doc
from app.engine.judge import ENTITY_QUERIES, SQL_CHARS, prepare
SOURCE = "warehouse"
SCHEMA_ART, Q1_ART, Q2_ART, Q3_ART = "5" * 64, "a" * 64, "b" * 64, "c" * 64
SQL1 = "SELECT COUNT(DISTINCT member_no) AS active_users FROM orders WHERE created_at >= '2026-09-01'"
SQL2 = "SELECT region, SUM(amount) AS gmv FROM orders GROUP BY region"
SQL3 = "SELECT COUNT(*) AS refund_cnt FROM refunds"
SNAPS = {
Q1_ART: {"columns": ["active_users"], "rows": [[321]], "sql": SQL1, "source": SOURCE},
Q2_ART: {"columns": ["region", "gmv"], "rows": [["华东", 100.0]], "sql": SQL2, "source": SOURCE},
Q3_ART: {"columns": ["refund_cnt"], "rows": [[4]], "sql": SQL3, "source": SOURCE},
}
def query(art: str, columns: list[str], tables: list[str]) -> dict:
return {"kind": "query", "node_id": "fetch", "exec": 1, "artifact": art, "tool": f"db_query__{SOURCE}",
"source": SOURCE, "columns": columns, "rows": 1, "truncated": False, "schema_artifact": SCHEMA_ART,
"tables": tables}
SCHEMA = {"kind": "schema", "node_id": "fetch", "exec": 1, "artifact": SCHEMA_ART, "source": SOURCE,
"tables": {"orders": ["id", "member_no", "region", "amount", "created_at"], "refunds": ["id", "amount"]}}
def catalog():
return build_catalog(nodes={}, ledger=[query(Q1_ART, ["active_users"], ["orders"]),
query(Q2_ART, ["region", "gmv"], ["orders"]),
query(Q3_ART, ["refund_cnt"], ["refunds"]), SCHEMA])
def excerpts_for(text: str) -> dict[str, str]:
cat = catalog()
doc = compose_doc(text, cat)
return prepare(doc, cat, loader=SNAPS.get).excerpts
def test_a_table_excerpt_carries_the_sql_of_the_queries_it_appears_in():
ex = excerpts_for("活跃用户数由 [[t:orders]] 按 [[c:orders.member_no]] 去重计数得出。")
table = ex["t:orders"]
assert table.startswith("【t:orders】表 orders")
assert "COUNT(DISTINCT member_no)" in table and "Q1" in table
assert "SUM(amount)" in table and "Q2" in table # 用到这张表的查询都给
assert "refunds" not in table # 没用到这张表的不给
def test_a_column_only_in_the_sql_falls_back_to_queries_that_mention_it():
# member_no 不是任何查询的结果列,条目自己没记查询:按所在的表找、只留 SQL 里写了它的
ex = excerpts_for("活跃用户数按 [[c:orders.member_no]] 去重计数得出。")
column = ex["c:orders.member_no"]
assert "COUNT(DISTINCT member_no)" in column and "Q1" in column
assert "SUM(amount)" not in column # Q2 用了 orders 但没写 member_no
def test_a_result_column_uses_the_queries_it_came_from():
ex = excerpts_for("各区的销售额按 [[c:orders.region]] 汇总。")
assert "GROUP BY region" in ex["c:orders.region"] and "Q2" in ex["c:orders.region"]
def test_entity_sql_is_capped():
long_sql = "SELECT COUNT(DISTINCT member_no) AS n FROM orders WHERE " + " AND ".join(f"f{i} = 1" for i in range(200))
snaps = {art: {**SNAPS[Q1_ART], "sql": long_sql} for art in "defgh"}
ledger = [query(art * 64, ["n"], ["orders"]) for art in "defgh"] + [SCHEMA]
cat = build_catalog(nodes={}, ledger=ledger)
doc = compose_doc("活跃用户数由 [[t:orders]] 去重计数得出。", cat)
table = prepare(doc, cat, loader=lambda a: snaps.get(a[0])).excerpts["t:orders"]
assert table.count("SELECT") == ENTITY_QUERIES
assert all(len(line) < SQL_CHARS + 40 for line in table.splitlines())
def test_an_unsealed_snapshot_is_simply_left_out():
# loader 只认封存范围内的工件:取不到的查询不给 SQL,名字那一行照样在
cat = catalog()
doc = compose_doc("活跃用户数由 [[t:orders]] 去重计数得出。", cat)
table = prepare(doc, cat, loader=lambda a: None).excerpts["t:orders"]
assert table.startswith("【t:orders】表 orders") and "SELECT" not in table
def test_a_qualified_column_in_the_sql_still_counts():
# SQL 里写成 o.member_no(表别名前缀)也算写了这个字段;只沾了边的 member_no_hash 不算
snaps = {Q1_ART: {**SNAPS[Q1_ART], "sql": "SELECT COUNT(DISTINCT o.member_no) AS n FROM orders o"},
Q2_ART: {**SNAPS[Q2_ART], "sql": "SELECT COUNT(DISTINCT member_no_hash) AS n FROM orders"}}
cat = build_catalog(nodes={}, ledger=[query(Q1_ART, ["n"], ["orders"]), query(Q2_ART, ["n"], ["orders"]), SCHEMA])
doc = compose_doc("活跃用户数按 [[c:orders.member_no]] 去重计数得出。", cat)
column = prepare(doc, cat, loader=snaps.get).excerpts["c:orders.member_no"]
assert "o.member_no" in column and "member_no_hash" not in column
def test_the_same_column_name_in_another_tables_query_is_not_evidence():
# 只引了字段、没引表(文档目录里没有 t:orders):看全部查询时,别的表上写了同名字段的不算
snaps = {**SNAPS, Q3_ART: {**SNAPS[Q3_ART], "sql": "SELECT COUNT(DISTINCT member_no) AS n FROM refunds"}}
cat = catalog()
doc = compose_doc("活跃用户数按 [[c:orders.member_no]] 去重计数得出。", cat)
assert "t:orders" not in doc["catalog"]
column = prepare(doc, doc["catalog"], loader=snaps.get).excerpts["c:orders.member_no"]
assert "FROM orders" in column and "FROM refunds" not in column
# --------------------------------------------------------------------------
# 写作提示:讲算法的句子挂 [[see:Qn]],别只写表名、字段名
# --------------------------------------------------------------------------
def test_the_writer_is_told_to_point_method_sentences_at_the_query():
from app.engine.evidence import catalog_prompt
prompt = catalog_prompt(catalog())
[rule] = [line for line in prompt.splitlines() if "算出来" in line]
assert "[[see:Q" in rule and "去重" in rule
assert "[[t:" in rule and "[[c:" in rule # 点明只挂表名、字段名说明不了算法
def test_a_catalog_without_tables_does_not_carry_the_method_rule():
from app.engine.evidence import catalog_prompt
ledger = [{"kind": "query", "node_id": "fetch", "exec": 1, "artifact": Q1_ART, "tool": f"db_query__{SOURCE}",
"source": SOURCE, "columns": ["active_users"], "rows": 1, "truncated": False}]
assert "算出来" not in catalog_prompt(build_catalog(nodes={}, ledger=ledger))