feat(evidence): contribute to semantic stages (#42)
This commit is contained in:
@@ -14,6 +14,14 @@ KIND_MAP = {
|
||||
"formula": [], # solo formula store (D14b), niente LSH/vector
|
||||
}
|
||||
|
||||
_STAGE_PURPOSES = {
|
||||
"clarification": "disambiguation",
|
||||
"rewriting": "rewriting",
|
||||
"schema_linking": "schema_linking",
|
||||
"cte": "sql_generation",
|
||||
"final_sql": "sql_generation",
|
||||
}
|
||||
|
||||
# Default di `--top` per le famiglie diverse da `schema` (numero di risultati). Per `schema`
|
||||
# `--top` indica il numero di TABELLE candidate ed e' configurabile via `search.top_schema_tables`
|
||||
# (recupero ancorato alle tabelle: di ognuna si rendono tutte le colonne + FK).
|
||||
@@ -31,6 +39,79 @@ def _leased_dwh_snapshot(cfg, context: typer.Context):
|
||||
return snapshot
|
||||
|
||||
|
||||
@search_app.command("evidence")
|
||||
def evidence_search_cmd(
|
||||
ctx: typer.Context,
|
||||
query: str = typer.Argument(..., help="Domanda o contesto dello stage."),
|
||||
stage: str = typer.Option(..., "--stage", help="Stage semantico chiamante."),
|
||||
config: Path = CONFIG_OPT,
|
||||
session: str | None = typer.Option(None, "--session", help="Sessione per la ricevuta minima."),
|
||||
concept: list[str] = typer.Option([], "--concept"),
|
||||
table: list[str] = typer.Option([], "--table"),
|
||||
column: list[str] = typer.Option([], "--column"),
|
||||
require_kind: list[str] = typer.Option([], "--require-kind"),
|
||||
require_concept: list[str] = typer.Option([], "--require-concept"),
|
||||
require_table: list[str] = typer.Option([], "--require-table"),
|
||||
require_column: list[str] = typer.Option([], "--require-column"),
|
||||
top: int = typer.Option(10, "--top"),
|
||||
json_out: bool = typer.Option(False, "--json"),
|
||||
) -> None:
|
||||
"""Run one typed, purpose-bound Evidence search for a semantic workflow stage."""
|
||||
from tht.cli.vector_cmd import make_embedder, open_searcher, require_vector_cfg
|
||||
from tht.evidence import (
|
||||
EvidenceReceipt,
|
||||
EvidenceSearchContext,
|
||||
active_searcher,
|
||||
replace_evidence_receipt,
|
||||
search_evidence,
|
||||
validate_corpus_workspace,
|
||||
)
|
||||
|
||||
purpose = _STAGE_PURPOSES.get(stage)
|
||||
if purpose is None:
|
||||
raise typer.BadParameter("stage must be clarification, rewriting, schema_linking, cte, or final_sql")
|
||||
cfg = _load_config_or_exit(config)
|
||||
workspace_id = workspace_id_for_config(cfg, config)
|
||||
validate_corpus_workspace(cfg, workspace_id)
|
||||
require_vector_cfg(cfg)
|
||||
outcome = search_evidence(
|
||||
query, purpose,
|
||||
EvidenceSearchContext(
|
||||
concepts=tuple(concept), tables=tuple(table), columns=tuple(column),
|
||||
required_kinds=tuple(require_kind), required_concepts=tuple(require_concept),
|
||||
required_tables=tuple(require_table), required_columns=tuple(require_column),
|
||||
),
|
||||
searcher=active_searcher(cfg, open_searcher(cfg), workspace_id=workspace_id),
|
||||
embedder=make_embedder(cfg.embeddings), top_n=top,
|
||||
)
|
||||
if outcome.status == "unavailable":
|
||||
payload = {"status": outcome.status, "code": outcome.code, "message": outcome.message}
|
||||
if json_out:
|
||||
typer.echo(json.dumps(payload, ensure_ascii=False))
|
||||
else:
|
||||
typer.secho(f"ERRORE: {outcome.message}", fg=typer.colors.RED, err=True)
|
||||
raise typer.Exit(1)
|
||||
if session:
|
||||
from tht.cli.session_cmd import load_session_or_exit, session_repository
|
||||
|
||||
load_session_or_exit(cfg, session)
|
||||
replace_evidence_receipt(session_repository(cfg), session, EvidenceReceipt(
|
||||
stage=stage, purpose=purpose, vector_generation=outcome.vector_generation or "",
|
||||
evidence_ids=tuple(result.evidence_id for result in outcome.results),
|
||||
))
|
||||
payload = {
|
||||
"status": "available", "vector_generation": outcome.vector_generation,
|
||||
"results": [
|
||||
{"evidence_id": result.evidence_id, "title": result.title, "kind": result.kind,
|
||||
"excerpts": list(result.excerpts), "provenance": result.provenance,
|
||||
"citation": result.citation, "document_id": result.document_id}
|
||||
for result in outcome.results
|
||||
],
|
||||
}
|
||||
if json_out:
|
||||
typer.echo(json.dumps(payload, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
@search_app.command("find")
|
||||
def search_cmd(
|
||||
ctx: typer.Context,
|
||||
@@ -254,8 +335,10 @@ def pack_cmd(
|
||||
|
||||
from tht.cli.vector_cmd import make_embedder, open_searcher, require_vector_cfg
|
||||
from tht.evidence import (
|
||||
EvidenceSearchContext,
|
||||
active_searcher,
|
||||
build_retrieval_entries,
|
||||
search_evidence,
|
||||
validate_corpus_workspace,
|
||||
)
|
||||
from tht.memory import SOLVED_KIND
|
||||
@@ -274,6 +357,7 @@ def pack_cmd(
|
||||
evidence: list[dict] = []
|
||||
solved: list[dict] = []
|
||||
warnings: list[str] = []
|
||||
evidence_outcome = None
|
||||
degrade = (VectorStoreError, VectorReadUnavailable, EmbeddingsError, OperationalError)
|
||||
|
||||
vec = None
|
||||
@@ -309,12 +393,19 @@ def pack_cmd(
|
||||
except degrade as e:
|
||||
warnings.append(f"ricerca schema fallita ({e})")
|
||||
try:
|
||||
ev = combined_search(
|
||||
keyword=question, lsh_hits=None, store=searcher, embedder=embedder,
|
||||
top=PACK_EVIDENCE_TOP, rrf_k=cfg.search.rrf_k,
|
||||
kinds=KIND_MAP["evidence"], query_vec=vec,
|
||||
evidence_outcome = search_evidence(
|
||||
question, "disambiguation", EvidenceSearchContext(), searcher=searcher,
|
||||
embedder=embedder, top_n=PACK_EVIDENCE_TOP,
|
||||
)
|
||||
evidence = build_retrieval_entries(ev, excerpt_chars=PACK_EXCERPT_CHARS)
|
||||
if evidence_outcome.status == "available":
|
||||
evidence = build_retrieval_entries(evidence_outcome.results, excerpt_chars=PACK_EXCERPT_CHARS)
|
||||
else:
|
||||
typer.secho(
|
||||
f"ERRORE: Evidence non disponibile ({evidence_outcome.code})",
|
||||
fg=typer.colors.RED,
|
||||
err=True,
|
||||
)
|
||||
raise typer.Exit(code=1)
|
||||
except degrade as e:
|
||||
warnings.append(f"ricerca evidence fallita ({e})")
|
||||
try:
|
||||
@@ -367,9 +458,17 @@ def pack_cmd(
|
||||
|
||||
if session:
|
||||
from tht.cli.session_cmd import load_session_or_exit, session_repository
|
||||
from tht.evidence import EvidenceReceipt, replace_evidence_receipt
|
||||
|
||||
load_session_or_exit(cfg, session)
|
||||
session_repository(cfg).write_artifact(session, "retrieval_pack", md)
|
||||
repository = session_repository(cfg)
|
||||
repository.write_artifact(session, "retrieval_pack", md)
|
||||
if evidence_outcome is not None and evidence_outcome.status == "available":
|
||||
replace_evidence_receipt(repository, session, EvidenceReceipt(
|
||||
stage="clarification", purpose="disambiguation",
|
||||
vector_generation=evidence_outcome.vector_generation or "",
|
||||
evidence_ids=tuple(result.evidence_id for result in evidence_outcome.results),
|
||||
))
|
||||
if not json_out:
|
||||
typer.secho(
|
||||
"OK: retrieval pack scritto "
|
||||
|
||||
Reference in New Issue
Block a user