fix(llm): code-cited sources ranked per code; early return on no codes; log resolved replica path (refs P48)
This commit is contained in:
@@ -98,10 +98,11 @@ def valuation_evidence(question: str, cfg: LlmConfig) -> ValuationEvidence | Non
|
|||||||
det = detect_codes(question)
|
det = detect_codes(question)
|
||||||
if not det.codes:
|
if not det.codes:
|
||||||
return None
|
return None
|
||||||
|
path = _replica_path(cfg)
|
||||||
try:
|
try:
|
||||||
con = duckdb.connect(_replica_path(cfg), read_only=True)
|
con = duckdb.connect(path, read_only=True)
|
||||||
except Exception as e: # noqa: BLE001 — duckdb raises several types
|
except Exception as e: # noqa: BLE001 — duckdb raises several types
|
||||||
log.warning("valuation evidence skipped (%s): %s", cfg.duckdb_replica, e)
|
log.warning("valuation evidence skipped (%s): %s", path, e)
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
rows, unpriced = valuation(con, list(det.codes), years=cfg.valuation_years)
|
rows, unpriced = valuation(con, list(det.codes), years=cfg.valuation_years)
|
||||||
@@ -114,12 +115,20 @@ def valuation_evidence(question: str, cfg: LlmConfig) -> ValuationEvidence | Non
|
|||||||
|
|
||||||
|
|
||||||
_CITED_SQL = text(
|
_CITED_SQL = text(
|
||||||
"SELECT e.document, e.cmetadata FROM langchain_pg_embedding e "
|
"SELECT document, cmetadata FROM ( "
|
||||||
"JOIN langchain_pg_collection c ON c.uuid = e.collection_id "
|
"SELECT e.document, e.cmetadata, "
|
||||||
"WHERE c.name = :collection "
|
"row_number() OVER ( "
|
||||||
"AND string_to_array(COALESCE(e.cmetadata->>'codes', ''), ' ') && CAST(:codes AS text[]) "
|
"PARTITION BY w.code "
|
||||||
"ORDER BY e.cmetadata->>'date' DESC NULLS LAST, e.cmetadata->>'item_key', e.cmetadata->>'p_id' "
|
"ORDER BY e.cmetadata->>'date' DESC NULLS LAST, e.cmetadata->>'item_key', e.cmetadata->>'p_id' "
|
||||||
"LIMIT :lim"
|
") AS rn "
|
||||||
|
"FROM langchain_pg_embedding e "
|
||||||
|
"JOIN langchain_pg_collection c ON c.uuid = e.collection_id "
|
||||||
|
"JOIN unnest(CAST(:codes AS text[])) AS w(code) "
|
||||||
|
"ON w.code = ANY(string_to_array(COALESCE(e.cmetadata->>'codes', ''), ' ')) "
|
||||||
|
"WHERE c.name = :collection "
|
||||||
|
") t "
|
||||||
|
"WHERE rn <= :window "
|
||||||
|
"ORDER BY cmetadata->>'date' DESC NULLS LAST, cmetadata->>'item_key', cmetadata->>'p_id'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -130,6 +139,8 @@ def code_cited_sources(
|
|||||||
*codes* — at most *per_code* per code, newest rule first, deduped on
|
*codes* — at most *per_code* per code, newest rule first, deduped on
|
||||||
(item_key, p_id). Scores are 0.0: these are additive, not ranked."""
|
(item_key, p_id). Scores are 0.0: these are additive, not ranked."""
|
||||||
wanted = [c.upper() for c in codes]
|
wanted = [c.upper() for c in codes]
|
||||||
|
if not wanted:
|
||||||
|
return []
|
||||||
try:
|
try:
|
||||||
with engine.begin() as conn:
|
with engine.begin() as conn:
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
@@ -137,7 +148,7 @@ def code_cited_sources(
|
|||||||
{
|
{
|
||||||
"collection": collection,
|
"collection": collection,
|
||||||
"codes": wanted,
|
"codes": wanted,
|
||||||
"lim": per_code * len(wanted) * 4,
|
"window": per_code * 2,
|
||||||
},
|
},
|
||||||
).fetchall()
|
).fetchall()
|
||||||
except Exception as e: # noqa: BLE001
|
except Exception as e: # noqa: BLE001
|
||||||
|
|||||||
@@ -202,8 +202,10 @@ class TestCodeCitedSources:
|
|||||||
out = code_cited_sources(engine, ["G0556", "G0557"], per_code=2)
|
out = code_cited_sources(engine, ["G0556", "G0557"], per_code=2)
|
||||||
sql = str(conn.execute.call_args.args[0])
|
sql = str(conn.execute.call_args.args[0])
|
||||||
assert "string_to_array" in sql and "langchain_pg_collection" in sql
|
assert "string_to_array" in sql and "langchain_pg_collection" in sql
|
||||||
|
assert "PARTITION BY" in sql
|
||||||
assert conn.execute.call_args.args[1]["collection"] == "rules"
|
assert conn.execute.call_args.args[1]["collection"] == "rules"
|
||||||
assert conn.execute.call_args.args[1]["codes"] == ["G0556", "G0557"]
|
assert conn.execute.call_args.args[1]["codes"] == ["G0556", "G0557"]
|
||||||
|
assert conn.execute.call_args.args[1]["window"] == 4
|
||||||
assert [s["snippet"] for s in out] == [
|
assert [s["snippet"] for s in out] == [
|
||||||
"para one G0556",
|
"para one G0556",
|
||||||
"para two G0556",
|
"para two G0556",
|
||||||
@@ -217,6 +219,11 @@ class TestCodeCitedSources:
|
|||||||
assert code_cited_sources(engine, ["G0556"], per_code=2) == []
|
assert code_cited_sources(engine, ["G0556"], per_code=2) == []
|
||||||
assert "code-cited sources skipped" in caplog.text
|
assert "code-cited sources skipped" in caplog.text
|
||||||
|
|
||||||
|
def test_no_codes_returns_empty_without_querying(self):
|
||||||
|
engine = MagicMock()
|
||||||
|
assert code_cited_sources(engine, [], per_code=2) == []
|
||||||
|
engine.begin.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
class TestMergeSources:
|
class TestMergeSources:
|
||||||
def test_keeps_order_and_dedupes_by_label(self):
|
def test_keeps_order_and_dedupes_by_label(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user