feat(llm): theme filter pushed into the vector store — theme_1..theme_N rank keys beside themes, $or equality filter; stamp threshold 0.60
Some checks failed
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / notebooks-smoke (push) Has been cancelled
Deploy / notebooks (push) Has been cancelled
Deploy / zotero (push) Has been cancelled
Deploy / docs (push) Has been cancelled
Deploy / api (push) Has been cancelled
Deploy / llm (push) Has been cancelled
Deploy / mc (push) Has been cancelled
Deploy / report (push) Has been cancelled
Infra CI / notebooks (push) Has been cancelled
Infra CI / zotero (push) Has been cancelled
Infra CI / docs (push) Has been cancelled
Infra CI / api (push) Has been cancelled
Infra CI / llm (push) Has been cancelled
Infra CI / mc (push) Has been cancelled
Some checks failed
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / notebooks-smoke (push) Has been cancelled
Deploy / notebooks (push) Has been cancelled
Deploy / zotero (push) Has been cancelled
Deploy / docs (push) Has been cancelled
Deploy / api (push) Has been cancelled
Deploy / llm (push) Has been cancelled
Deploy / mc (push) Has been cancelled
Deploy / report (push) Has been cancelled
Infra CI / notebooks (push) Has been cancelled
Infra CI / zotero (push) Has been cancelled
Infra CI / docs (push) Has been cancelled
Infra CI / api (push) Has been cancelled
Infra CI / llm (push) Has been cancelled
Infra CI / mc (push) Has been cancelled
/search?theme= used to filter in Python after the k-limited fetch, so a narrow theme on a broad doctype came back empty. llm.themes now also writes one scalar key per rank (theme_1, theme_2, …) and _store_filter turns a theme into an $or of equalities over them, so the store's overfetch is spent on on-theme chunks. Default min score raised to 0.60 (the knee the tagging sweep found); 24,555 manual chunks re-stamped: top first themes enrollment-program-integrity 7,081, evaluation-management 2,142, coverage-policy 2,064, telehealth 960.
This commit is contained in:
@@ -21,7 +21,7 @@ Usage: stack llm stamp-themes [OPTIONS]
|
||||
│ --key TEXT Only this item key. │
|
||||
│ --top INTEGER Themes kept per chunk. [default: 2] │
|
||||
│ --min-score FLOAT Cosine similarity a theme must reach. │
|
||||
│ [default: 0.55] │
|
||||
│ [default: 0.6] │
|
||||
│ --force Re-stamp chunks already on the current │
|
||||
│ vocabulary version. │
|
||||
│ --help Show this message and exit. │
|
||||
|
||||
@@ -489,7 +489,7 @@ def stamp_themes(
|
||||
key: str = typer.Option("", "--key", help="Only this item key."),
|
||||
top: int = typer.Option(2, "--top", help="Themes kept per chunk."),
|
||||
min_score: float = typer.Option(
|
||||
0.55, "--min-score", help="Cosine similarity a theme must reach."
|
||||
0.60, "--min-score", help="Cosine similarity a theme must reach."
|
||||
),
|
||||
force: bool = typer.Option(
|
||||
False,
|
||||
|
||||
@@ -54,13 +54,16 @@ def _collections_for(collection: str) -> tuple[str, ...]:
|
||||
return (collection,)
|
||||
|
||||
|
||||
def _store_filter(filters: dict[str, str]) -> dict[str, str]:
|
||||
def _store_filter(filters: dict[str, str]) -> dict[str, Any]:
|
||||
"""The langchain PGVector ``filter=`` metadata dict for *filters* —
|
||||
docket/item_key/kind and the manual coordinates (doctype, manual,
|
||||
chapter, iom_section) are pushed down to the store; ``year`` is
|
||||
applied in Python (:func:`_year_ok`) since it's a prefix of the
|
||||
``date`` field, not its own metadata key."""
|
||||
return {
|
||||
``date`` field, not its own metadata key. A ``theme`` becomes an
|
||||
``$or`` of equalities over the ``theme_1..theme_3`` rank keys
|
||||
``llm.themes`` writes, so the overfetch is not spent on off-theme
|
||||
chunks (the comma-joined ``themes`` is re-checked in Python)."""
|
||||
out: dict[str, Any] = {
|
||||
key: filters[key]
|
||||
for key in (
|
||||
"docket",
|
||||
@@ -73,6 +76,10 @@ def _store_filter(filters: dict[str, str]) -> dict[str, str]:
|
||||
)
|
||||
if filters.get(key)
|
||||
}
|
||||
theme = str(filters.get("theme") or "")
|
||||
if theme:
|
||||
out["$or"] = [{f"theme_{i}": theme} for i in range(1, 4)]
|
||||
return out
|
||||
|
||||
|
||||
def _year_ok(md: dict[str, Any], year: str) -> bool:
|
||||
|
||||
@@ -93,7 +93,7 @@ def stamp(
|
||||
doctype: str = "manual",
|
||||
item_key: str = "",
|
||||
top: int = 2,
|
||||
min_score: float = 0.55,
|
||||
min_score: float = 0.60,
|
||||
batch: int = 1000,
|
||||
force: bool = False,
|
||||
) -> dict[str, int]:
|
||||
@@ -136,6 +136,12 @@ def stamp(
|
||||
"themes": ",".join(s for s, _ in chosen),
|
||||
"theme_scores": ",".join(f"{s}:{sc}" for s, sc in chosen),
|
||||
"themes_vocab": version,
|
||||
# one scalar key per rank so the store can filter with an
|
||||
# equality ($or over theme_1..theme_N) instead of a LIKE
|
||||
**{
|
||||
f"theme_{i}": (chosen[i - 1][0] if i <= len(chosen) else "")
|
||||
for i in range(1, top + 1)
|
||||
},
|
||||
}
|
||||
patches.append({"id": cid, "patch": json.dumps(patch)})
|
||||
if patches:
|
||||
|
||||
@@ -391,3 +391,12 @@ class TestThemeFilter:
|
||||
assert not _theme_ok({"themes": "telehealth,supervision"}, "drugs")
|
||||
assert not _theme_ok({}, "drugs")
|
||||
assert _theme_ok({}, "")
|
||||
|
||||
def test_theme_is_pushed_down_as_an_or_of_rank_keys(self):
|
||||
out = _store_filter({"theme": "telehealth", "doctype": "manual"})
|
||||
assert out["doctype"] == "manual"
|
||||
assert out["$or"] == [
|
||||
{"theme_1": "telehealth"},
|
||||
{"theme_2": "telehealth"},
|
||||
{"theme_3": "telehealth"},
|
||||
]
|
||||
|
||||
@@ -64,7 +64,14 @@ class TestStamp:
|
||||
by["a"]["themes"] == "telehealth,mixed" and by["a"]["themes_vocab"] == "2"
|
||||
)
|
||||
assert by["a"]["theme_scores"].startswith("telehealth:1.0,mixed:0.7071")
|
||||
assert by["c"] == {"themes": "", "theme_scores": "", "themes_vocab": "2"}
|
||||
assert by["a"]["theme_1"] == "telehealth" and by["a"]["theme_2"] == "mixed"
|
||||
assert by["c"] == {
|
||||
"themes": "",
|
||||
"theme_scores": "",
|
||||
"themes_vocab": "2",
|
||||
"theme_1": "",
|
||||
"theme_2": "",
|
||||
}
|
||||
assert "b" not in by
|
||||
|
||||
def test_force_restamps_everything_and_pages_by_id(self):
|
||||
|
||||
Reference in New Issue
Block a user