Files
Mutual_Fund/service/nl2sql/answer_render.py
T

54 lines
2.1 KiB
Python

"""NL2SQL 查询结果 → 客服口吻回复的渲染器。
不调用 LLM:自然语言摘要由 execute_query 的 summary_llm 生成(result.summary),
这里只负责把摘要 + Markdown 表格组装成客服回复,保证确定性降级。
"""
from __future__ import annotations
from typing import Any
from nl2sql.contracts import DataQueryResult
# 表格最多渲染的行数:超出部分提示"仅展示前 N 条",避免回复过长
_MAX_TABLE_ROWS = 20
_EMPTY_ANSWER = "暂时没有查到相关数据,您可以换个问法,或者问我基金知识、开户流程~"
def render_markdown_table(columns: list[str], rows: list[dict[str, Any]]) -> str:
"""把结果行列渲染为 Markdown 表格;无数据返回空串。"""
if not columns or not rows:
return ""
shown = rows[:_MAX_TABLE_ROWS]
header = "| " + " | ".join(str(column) for column in columns) + " |"
separator = "| " + " | ".join("---" for _ in columns) + " |"
lines = [header, separator]
for row in shown:
cells = [str(row.get(column, "")) for column in columns]
lines.append("| " + " | ".join(cells) + " |")
return "\n".join(lines)
def render_query_answer(result: DataQueryResult) -> str:
"""组装最终客服回复:摘要开头 + 数据表格 + 截断/收尾提示。"""
if result.row_count == 0 or not result.rows:
return _EMPTY_ANSWER
parts: list[str] = []
summary = (result.summary or "").strip()
if summary:
parts.append(summary)
table = render_markdown_table(result.columns, result.rows)
if table:
parts.append(table)
if result.truncated or result.row_count > len(result.rows):
shown = min(len(result.rows), _MAX_TABLE_ROWS)
parts.append(f"结果较多,本次为您展示 {shown} 条(共 {result.row_count} 条),您可以缩小查询范围再看。")
if not summary and len(result.rows) <= _MAX_TABLE_ROWS:
parts.append(f"共为您查到 {result.row_count} 条记录。")
return "\n\n".join(part for part in parts if part).strip() or _EMPTY_ANSWER