recon-driven sql composer; pick → compose → execute; llm out of structural sql
This commit is contained in:
@@ -10,13 +10,15 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
from api import langfuse_client as lf
|
||||
from api.analyses._pick import pick_for_question
|
||||
from api.analyses.base import Analysis
|
||||
from api.analyses.types import Finding
|
||||
from api.composer import compose
|
||||
from api.llm import chat
|
||||
from api.prompts import load, render
|
||||
from api.recon import load_recon
|
||||
from api.runtime import events
|
||||
from api.tools.execute_sql import execute_sql
|
||||
from api.tools.text_to_sql import text_to_sql
|
||||
|
||||
logger = logging.getLogger("nvi.analyses.direct_answer")
|
||||
|
||||
@@ -29,23 +31,39 @@ class DirectAnswer(Analysis):
|
||||
)
|
||||
args_schema = {
|
||||
"question": {"type": "string", "description": "Refined question this Analysis should answer."},
|
||||
"hint_tables": {"type": "array", "items": "string", "description": "Tables the planner thinks are relevant (optional)."},
|
||||
"allowed_metrics": {"type": "array", "items": "string", "description": "Metrics the planner judged relevant (optional; defaults to all)."},
|
||||
}
|
||||
|
||||
async def run(self, args: dict[str, Any], question: str) -> Finding:
|
||||
sub_q = args.get("question") or question
|
||||
hint_tables = args.get("hint_tables")
|
||||
allowed_metrics = args.get("allowed_metrics")
|
||||
|
||||
with lf.span("analysis.direct_answer", input={"question": sub_q}) as span:
|
||||
try:
|
||||
await events.publish_current(events.tool_call_start("text_to_sql", input={"question": sub_q}))
|
||||
t2s = text_to_sql(sub_q, hint_tables=hint_tables)
|
||||
recon = load_recon()
|
||||
|
||||
await events.publish_current(events.tool_call_start(
|
||||
"pick_for_question", input={"question": sub_q},
|
||||
))
|
||||
outcome = pick_for_question(
|
||||
sub_q, recon=recon, allowed_metrics=allowed_metrics,
|
||||
span_name="direct_answer.pick",
|
||||
)
|
||||
await events.publish_current(events.tool_call_end(
|
||||
"text_to_sql", output={"sql": t2s.sql, "tables": t2s.used_tables},
|
||||
"pick_for_question", output={"pick": outcome.pick.to_dict()},
|
||||
))
|
||||
|
||||
await events.publish_current(events.tool_call_start("execute_sql", input={"sql": t2s.sql}))
|
||||
result = execute_sql(t2s.sql)
|
||||
await events.publish_current(events.tool_call_start(
|
||||
"compose_sql", input={"pick": outcome.pick.to_dict()},
|
||||
))
|
||||
composed = compose(outcome.pick, recon)
|
||||
await events.publish_current(events.tool_call_end(
|
||||
"compose_sql",
|
||||
output={"sql": composed.sql, "tables": composed.used_tables},
|
||||
))
|
||||
|
||||
await events.publish_current(events.tool_call_start("execute_sql", input={"sql": composed.sql}))
|
||||
result = execute_sql(composed.sql)
|
||||
await events.publish_current(events.tool_call_end(
|
||||
"execute_sql",
|
||||
output={"row_count": result.row_count, "truncated": result.truncated,
|
||||
@@ -56,7 +74,7 @@ class DirectAnswer(Analysis):
|
||||
interpret_user = render(
|
||||
"direct_answer.interpret.user",
|
||||
question=sub_q,
|
||||
sql=t2s.sql,
|
||||
sql=composed.sql,
|
||||
rows=repr(result.as_dicts()[:20]),
|
||||
)
|
||||
await events.publish_current(events.llm_call(
|
||||
@@ -64,7 +82,10 @@ class DirectAnswer(Analysis):
|
||||
system_len=len(interpret_system),
|
||||
user_len=len(interpret_user),
|
||||
))
|
||||
summary = chat(system=interpret_system, user=interpret_user, max_tokens=512)
|
||||
summary = chat(
|
||||
system=interpret_system, user=interpret_user, max_tokens=512,
|
||||
span_name="direct_answer.interpret",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception("direct_answer failed")
|
||||
await events.publish_current(events.tool_call_end("direct_answer", error=str(e)))
|
||||
@@ -76,6 +97,10 @@ class DirectAnswer(Analysis):
|
||||
analysis=self.name,
|
||||
summary=summary,
|
||||
rows=result.as_dicts()[:20],
|
||||
sql=[t2s.sql],
|
||||
metadata={"row_count": result.row_count, "truncated": result.truncated},
|
||||
sql=[composed.sql],
|
||||
metadata={
|
||||
"row_count": result.row_count,
|
||||
"truncated": result.truncated,
|
||||
"metric": outcome.pick.metric,
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user