Files
AgentLab/backend/tests/test_copilot_sql_alias.py
T

74 lines
3.7 KiB
Python
Raw 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 时给结果列起中文别名,报告里的表格表头直接可读。
真实运行里:报告节点用 [[table:…]] 把查询结果原样生成表格,表头就是 Agent 写的 SQL 里的列名——一串英文缩写的
原始列名,读报告的人得猜。结果列起中文别名(AS 月份、AS 曝光量)以后,表头、单元格引用、口径卡的
cell() 都直接用中文名。
中文别名要按方言加标识符引号:MySQL / MariaDB 用反引号,PostgreSQL、Oracle、SQLite 用双引号;单引号是字符串。
这组守的是:
- 节点手册里 Agent 查库的说明、写 SQL 的硬性要求(搭查库节点时的规则)都有这一条,按方言给出示例;写 SQL 的
硬性要求说的是「照查看结果写、没看过先 look」,不再让助手先放一个 db_schema 节点去猜(look 文档 D3)
- 加了引号的中文别名不让自查放弃列名核对:以前 SQL 里只要有带引号的标识符就整条不判,照这条规矩写的 SQL
会把猜错的英文列名一起放过去
"""
from __future__ import annotations
from types import SimpleNamespace
import pytest
from app.api.copilot import NODE_REFERENCE, sql_unknown_columns
from app.api.copilot_context import SQL_RULES_PROMPT
def _agent_rule() -> str:
start = NODE_REFERENCE.index("- agent:带工具循环的 agent")
return NODE_REFERENCE[start:NODE_REFERENCE.index("\n- supervisor:", start)]
@pytest.mark.parametrize("text", [_agent_rule(), SQL_RULES_PROMPT], ids=["agent", "sql-rules"])
def test_guidance_asks_for_chinese_aliases_with_dialect_quotes(text):
assert "中文别名" in text
assert "AS `月份`" in text and "MySQL" in text # MySQL / MariaDB:反引号
assert 'AS "月份"' in text and "PostgreSQL" in text and "Oracle" in text and "SQLite" in text
assert "单引号" in text # 单引号是字符串,不是别名
def test_sql_rules_point_at_look_not_at_guessing():
assert "look" in SQL_RULES_PROMPT and "查看结果" in SQL_RULES_PROMPT
assert "图里先放一个 db_schema 工具节点" not in SQL_RULES_PROMPT
def _source(**tables):
return SimpleNamespace(name="shop", schema_cache={"tables": {
name: {"qualified": name, "columns": [{"name": c} for c in cols]} for name, cols in tables.items()}})
SHOP = _source(daily_stats=["id", "stat_date", "impressions", "clicks", "region"])
@pytest.mark.parametrize("sql", [
'SELECT stat_date AS "日期", SUM(impressions) AS "曝光量" FROM daily_stats GROUP BY stat_date ORDER BY "日期"',
"SELECT stat_date AS `日期`, SUM(impressions) AS `曝光量` FROM daily_stats GROUP BY stat_date ORDER BY `曝光量` DESC",
"SELECT stat_date AS 日期, SUM(clicks) AS 点击量 FROM daily_stats GROUP BY stat_date",
'SELECT region AS "区域", COUNT(*) AS "天数" FROM daily_stats WHERE region = \'华东\' GROUP BY region',
])
def test_quoted_chinese_aliases_are_fine(sql):
assert sql_unknown_columns(sql, SHOP) is None, sql_unknown_columns(sql, SHOP)
@pytest.mark.parametrize("sql, unknown", [
('SELECT stat_date AS "日期", SUM(impresions) AS "曝光量" FROM daily_stats GROUP BY stat_date', ["impresions"]),
("SELECT stat_month AS `月份`, SUM(impressions) AS `曝光量` FROM daily_stats GROUP BY stat_month",
["stat_month"]),
])
def test_guessed_columns_next_to_quoted_chinese_aliases_are_still_caught(sql, unknown):
found = sql_unknown_columns(sql, SHOP)
assert found is not None and found[0] == unknown, found
def test_quoted_ascii_identifiers_are_still_not_guessed():
# 带引号的英文标识符:大小写、空格都可能,照旧不判
assert sql_unknown_columns('SELECT "StatDate", impresions FROM daily_stats', SHOP) is None