Measured first, by the ped-ai session, fifteen runs of five prompts with the gateway cache bypassed. Retrieval was already deterministic: identical shortlist and identical scores every time, and the citation checker stripped none of the 45 markers written — invented citations are not the problem here. Generation was the whole variance. At temperature 0.3 the same sources and the same prompt gave answers differing by 15-70% of their text; one differential swung between a 35-word uncited paraphrase and a 180-word cited list. So temperature 0 and a seed. Temperature 0 alone was not enough — three runs still differed — and temperature 0 with a fixed seed came back byte-identical. The seed is derived from the question, normalised for case and spacing, so two people asking the same thing get the same answer and a different question is not pinned to the same sample. An empty reply is asked once more before it becomes a 502. One in fifteen came back empty from a healthy model in 4.9 seconds — not a refusal, not an error, just nothing. A short query that finds almost nothing is retried against the nearest article title. "kawasaki criteria" finds fourteen sources; "kawasaki critera" found none — the lexical ranker cannot match a token that is in no index, and the embedding of a misspelling is not near the embedding of the word. Trigrams do not care: that typo scores 0.36 against "Kawasaki disease" with the next article at 0.11, and the gap is what makes it safe to act on. pg_trgm is created at startup beside vector, with a migration for the record. And an answer drawn from the library must cite it. Not a hallucination guard — nothing was stripped in fifteen runs — but one answer used the sources and cited none of them, which leaves the learner an assertion and nowhere to check it. Also, article drafts are weighted towards mechanism, in the wording the ped-ai rewriter is using, so the two lanes read alike: why the body does what it does, with features and management explained through it rather than listed. Figure lines and cross-references survive a refine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
27 lines
844 B
Python
27 lines
844 B
Python
"""pg_trgm, for the spelling fallback in AI Mode.
|
|
|
|
"kawasaki criteria" finds fourteen sources; "kawasaki critera" finds none.
|
|
Neither ranker can catch the second — lexical because the token is in no
|
|
index, semantic because the embedding of a misspelling is not near the
|
|
embedding of the word. Trigram similarity puts "Kawasaki disease" at 0.36 with
|
|
the next article at 0.11, and the gap is what makes it safe to act on.
|
|
|
|
Revision ID: s8c9d0e1f2a3
|
|
Revises: r7b8c9d0e1f2
|
|
"""
|
|
from alembic import op
|
|
|
|
revision = "s8c9d0e1f2a3"
|
|
down_revision = "r7b8c9d0e1f2"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
op.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm")
|
|
|
|
|
|
def downgrade():
|
|
# Left in place. Dropping an extension another query may since have come
|
|
# to rely on is a worse outcome than an unused one sitting there.
|
|
pass
|