Problem
We have no cheap first-pass check on generated text, so the two things we do run
are all-or-nothing: either an expensive LLM pass, or nothing at all.
Concrete evidence, found while preparing the EuroCALL talk. A production A1
simplification of a dr.dk article (article 4894028) opens:
"Sommeren var meget varm i Europa. En dyrpark i Frankrig havde ti
krokodilleæg."
dyrpark is not a Danish word — it should be dyrepark. It shipped, in the
version served to A1 learners, who are precisely the readers least able to spot
it. A plain spellchecker catches that in under a millisecond.
Why this is the "Escalate to the LLM" pattern
The pattern is in our own catalogue
(https://llm-patterns.mircealungu.com/) and we have not applied it here:
run something cheap over everything, and spend the expensive check only on the
residue.
Today the grammar-correction pass is the only instrument, and it is an LLM call
per article. That is why it was added, disabled, and re-argued about
(7cafb9b7 Disable Haiku grammar correction pass after simplification) - the
cost is per-article regardless of whether anything is wrong.
Compare zeeguu/core/language/language_check.py, which gets this right for a
different question: lingua is nearly free, answers a closed question ("is this
plausibly Danish?"), and only the ambiguous cases need more. Spelling should
work the same way.
Do we have a multilingual spellchecker?
No. Nothing in requirements.txt and no spellcheck code in zeeguu/.
Coverage is not a problem. We offer 11 languages - da, nl, fr, de, it, sv,
pt, es, ro, en, el - and every one of them has a mature Hunspell dictionary.
(The language table holds 31 rows, but most are not live; do not size this
against that list.)
Hunspell via spylls (pure Python, no build step) or cyhunspell is the
obvious choice. pyspellchecker bundles only ~7 languages and would leave gaps;
symspellpy is faster but needs a frequency list built per language, which is
work we do not need to do given the dictionaries already exist.
Design notes
- The goal is triage, not correction. We are not trying to fix the text; we
are deciding whether it is worth an LLM call. So false positives are cheap
(one wasted call) and false negatives ship a typo. Tune accordingly.
- Proper nouns will dominate the noise. News text is full of Bjørnøya,
place names, brands. A raw "any unknown token" trigger fires on everything, so
the signal has to be a share of unknown tokens over a threshold, and probably
ignore capitalised tokens mid-sentence.
- Where to run it: after simplification, before the article is stored -
the same place the grammar pass sits.
- Worth measuring first: run hunspell over a sample of stored simplifications
per language and see what the unknown-token rate actually looks like before
picking a threshold.
Not scheduled
Filed for later; no work planned right now.
Problem
We have no cheap first-pass check on generated text, so the two things we do run
are all-or-nothing: either an expensive LLM pass, or nothing at all.
Concrete evidence, found while preparing the EuroCALL talk. A production A1
simplification of a dr.dk article (article 4894028) opens:
dyrparkis not a Danish word — it should be dyrepark. It shipped, in theversion served to A1 learners, who are precisely the readers least able to spot
it. A plain spellchecker catches that in under a millisecond.
Why this is the "Escalate to the LLM" pattern
The pattern is in our own catalogue
(https://llm-patterns.mircealungu.com/) and we have not applied it here:
run something cheap over everything, and spend the expensive check only on the
residue.
Today the grammar-correction pass is the only instrument, and it is an LLM call
per article. That is why it was added, disabled, and re-argued about
(
7cafb9b7 Disable Haiku grammar correction pass after simplification) - thecost is per-article regardless of whether anything is wrong.
Compare
zeeguu/core/language/language_check.py, which gets this right for adifferent question: lingua is nearly free, answers a closed question ("is this
plausibly Danish?"), and only the ambiguous cases need more. Spelling should
work the same way.
Do we have a multilingual spellchecker?
No. Nothing in
requirements.txtand no spellcheck code inzeeguu/.Coverage is not a problem. We offer 11 languages - da, nl, fr, de, it, sv,
pt, es, ro, en, el - and every one of them has a mature Hunspell dictionary.
(The
languagetable holds 31 rows, but most are not live; do not size thisagainst that list.)
Hunspell via
spylls(pure Python, no build step) orcyhunspellis theobvious choice.
pyspellcheckerbundles only ~7 languages and would leave gaps;symspellpyis faster but needs a frequency list built per language, which iswork we do not need to do given the dictionaries already exist.
Design notes
are deciding whether it is worth an LLM call. So false positives are cheap
(one wasted call) and false negatives ship a typo. Tune accordingly.
place names, brands. A raw "any unknown token" trigger fires on everything, so
the signal has to be a share of unknown tokens over a threshold, and probably
ignore capitalised tokens mid-sentence.
the same place the grammar pass sits.
per language and see what the unknown-token rate actually looks like before
picking a threshold.
Not scheduled
Filed for later; no work planned right now.