fix(llm): cap generation (num_predict 1200) and ask for concise answers; take years from the Lineage line (refs #691)
Some checks failed
CI / lint (push) Successful in 32s
CI / notebooks-smoke (push) Successful in 1m28s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / llm (push) Has been skipped
Deploy / mc (push) Has been skipped
Infra CI / notebooks (push) Successful in 52s
Infra CI / zotero (push) Successful in 13s
Infra CI / docs (push) Successful in 17s
Infra CI / api (push) Successful in 1m3s
Infra CI / llm (push) Successful in 1m1s
Infra CI / mc (push) Successful in 16s
Deploy / report (push) Successful in 12s
CI / test (push) Failing after 12m40s
Notebooks Integration / notebooks-integration (push) Successful in 8m52s
LLM Golden / llm-golden (push) Successful in 4m14s
Zotero Sync / zotero-sync (push) Failing after 42s
Package Supply Chain / pkg-supply-chain (push) Successful in 1m7s

This commit is contained in:
kert
2026-09-10 18:49:45 -04:00
parent 2de806de32
commit d98f6105eb
4 changed files with 13 additions and 2 deletions

View File

@@ -39,6 +39,7 @@ class LlmConfig:
large_min_vram_gb: float = 20.0 large_min_vram_gb: float = 20.0
chat_num_ctx: int = 8192 chat_num_ctx: int = 8192
chat_temperature: float = 0.2 chat_temperature: float = 0.2
chat_max_tokens: int = 1200
recency_half_life_days: float = 365.0 recency_half_life_days: float = 365.0
recency_weight: float = 0.3 recency_weight: float = 0.3
k_per_kind: dict[str, int] = field( k_per_kind: dict[str, int] = field(
@@ -117,6 +118,7 @@ def load() -> LlmConfig:
large_min_vram_gb=float(_opt(section, "large_min_vram_gb", 20.0)), large_min_vram_gb=float(_opt(section, "large_min_vram_gb", 20.0)),
chat_num_ctx=int(_opt(section, "chat_num_ctx", 8192)), chat_num_ctx=int(_opt(section, "chat_num_ctx", 8192)),
chat_temperature=float(_opt(section, "chat_temperature", 0.2)), chat_temperature=float(_opt(section, "chat_temperature", 0.2)),
chat_max_tokens=int(_opt(section, "chat_max_tokens", 1200)),
recency_half_life_days=float(_opt(section, "recency_half_life_days", 365.0)), recency_half_life_days=float(_opt(section, "recency_half_life_days", 365.0)),
recency_weight=float(_opt(section, "recency_weight", 0.3)), recency_weight=float(_opt(section, "recency_weight", 0.3)),
k_per_kind=k_per_kind, k_per_kind=k_per_kind,

View File

@@ -237,7 +237,10 @@ _CITE_REMINDER = (
"or a commenter said MUST end with the bracketed label of the Lineage " "or a commenter said MUST end with the bracketed label of the Lineage "
"line, Valuation row or excerpt it comes from, copied exactly — for " "line, Valuation row or excerpt it comes from, copied exactly — for "
'example: "G2058 was replaced by CPT 99439 for CY2021 [CY2021 PFS final ' 'example: "G2058 was replaced by CPT 99439 for CY2021 [CY2021 PFS final '
'85 FR 84547 ¶686]." Do not write such a sentence without its label.' '85 FR 84547 ¶686]." Do not write such a sentence without its label. '
"Take the year of each fact from its Lineage line, never from a "
"neighbouring excerpt. Be concise: answer in at most about 400 words "
"unless the question asks for a full listing."
) )
_SYSTEM = ( _SYSTEM = (
@@ -736,6 +739,7 @@ def stream_answer(
"options": { "options": {
"num_ctx": cfg.chat_num_ctx, "num_ctx": cfg.chat_num_ctx,
"temperature": cfg.chat_temperature, "temperature": cfg.chat_temperature,
"num_predict": cfg.chat_max_tokens,
}, },
}, },
) as resp: ) as resp:

View File

@@ -112,6 +112,7 @@ instruct_model_large = "qwen2.5:32b" # used when the chosen host declares >= l
large_min_vram_gb = 20 large_min_vram_gb = 20
chat_num_ctx = 8192 # passed per request; no Modelfile ctx variants chat_num_ctx = 8192 # passed per request; no Modelfile ctx variants
chat_temperature = 0.2 # grounded answers cite labels verbatim; low temperature keeps them literal chat_temperature = 0.2 # grounded answers cite labels verbatim; low temperature keeps them literal
chat_max_tokens = 1200 # num_predict: a history answer ran to 5,000 tokens (3 min) without a cap
embed_dim = 768 embed_dim = 768
# HNSW index build. Safe since the postgres image ships an AVX-512-free # HNSW index build. Safe since the postgres image ships an AVX-512-free
# pgvector rebuild (infra/images/postgresql.Dockerfile, #580); before that it # pgvector rebuild (infra/images/postgresql.Dockerfile, #580); before that it

View File

@@ -778,7 +778,11 @@ class TestStreamAnswer:
assert events[-1] == {"type": "done"} assert events[-1] == {"type": "done"}
body = client.stream.call_args.kwargs["json"] body = client.stream.call_args.kwargs["json"]
assert body["model"] == "big" assert body["model"] == "big"
assert body["options"] == {"num_ctx": 8192, "temperature": CFG.chat_temperature} assert body["options"] == {
"num_ctx": 8192,
"temperature": CFG.chat_temperature,
"num_predict": CFG.chat_max_tokens,
}
assert client.stream.call_args.args[1] == "http://h1:11434/api/chat" assert client.stream.call_args.args[1] == "http://h1:11434/api/chat"
@patch("llm.rag.valuation_evidence", return_value=None) @patch("llm.rag.valuation_evidence", return_value=None)