Give the model the tools and the guardrails it was missing, without changing the model - #36
Draft
devbadya wants to merge 9 commits into
Draft
Give the model the tools and the guardrails it was missing, without changing the model#36devbadya wants to merge 9 commits into
devbadya wants to merge 9 commits into
Conversation
…aking questions that are not theirs Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
…nor a search Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
…s checking them Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
…put first Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
…re it was already claimed Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
…stion does Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Everything here is a deterministic function over text, so all of it is verified by
pnpm check— 1,066 tests — and none of it needed a GPU. What the model then does with any of it is what/?evalis for; that is stated per change below rather than claimed.The model itself is unchanged, deliberately: no new weights, no sampling change, no strategy change, and nothing added to
SYSTEM_PROMPT, which was measured making tool use worse.1. The calculator refused ten of eighteen expressions a 0.8B model plausibly writes
A refused expression spends the tool round and sends the model back to the mental arithmetic the tool exists to replace.
98,765 * 4,321,18% of 2450,18 Prozent von 2450,(17 * 23) / 4 =,2 x 3,$1200 * 1.19are all read now, because each has exactly one arithmetic meaning. Genuine ambiguity is still refused:18% off 2450is a discount,12 % 5is still modulo, and a unit conversion is not arithmetic. The two failure messages end in a clause the next round can act on.2. Two skills were taking questions that belong elsewhere
Was ist heute für ein Tag? went to a web search, Was bedeutet TLDR? to the page summariser, which asked which page was meant. The first is worth more than the two questions it fixes: a trigger anywhere in the catalogue is matched before any keyword, so
was ist heuteinresearch-questionat priority 10 was beatingwelcher tagincurrent-date's index at priority 25. A German phrasing left to the index is only safe until some other skill writes a trigger over it.3. A conversion had no tool at all
convertis new: length, mass, temperature, volume, speed, area, data and duration, with every spelling either language uses, since the model passes the user's own word through as the argument. It was the one question in the app with nothing behind it —lookup-termexcludes it by hand, the calculator refuses it correctly, so the model did it in its head.What it refuses matters as much as what it converts. Grams to cups depends on what is in the cup; a month and a year are not fixed durations;
MbandMBdiffer by a factor of eight and by one letter's case. Theconvert-unitsskill sits abovearithmetic, and its5 miles in kmtrigger anchors the target on a known unit so 20 minutes to Berlin is not read as a conversion into a city. The answer check follows the tool: a converted number is now held to the same standard as a calculated one.4. A figure, a date and an attribution had nowhere to go
Three quarters of ordinary questions reached no skill. Some belong to nobody, but one group did not — How many people live in Tokyo?, Wie alt ist Angela Merkel?, When was the Eiffel Tower built?, Wer hat die Bundestagswahl 2025 gewonnen? — and it is exactly what this model produces plausibly and unverifiably. All three shapes are
research-questiontriggers now, in both languages, each excluding the version of itself about the user or the assistant, since how old are you and when is my flight are not on the web.Growing that skill cost another one two keywords, which is the mechanism worth remembering:
chance of rainandregenwahrscheinlichkeitwere weather keywords andhow high isis a research trigger, so the forecast question moved to a search engine the moment the trigger was written. Both are weather triggers now.Coverage over the same 32 ordinary questions: 24 reached no skill, now 15.
5.
read_pagehanded over the top of the page, not the part that answersThe cap is 8,000 characters — roughly 2,000 tokens, the largest thing in this model's context — and it used to be the first 8,000, which is a bet that the answer was printed at the top. What is at the top is the navigation, the cookie notice and the related links.
src/tools/extract.tsstrips that furniture and, only if the page is still too long, keeps the passages about the question: blocks with each heading glued to its paragraph, scored by the question's terms weighted by how rare each is in that page, with leftover budget spent on the paragraphs either side of the best match and on the page's own opening. Skipped passages are marked[…].The question comes from the agent loop, not from the model:
runAgentpasses the user's turn to every tool as an optionalToolContext, because asking the model for a fourth argument would spend tool-calling accuracy on something already known. With no question, or one sharing no word with the page, it falls back to the head.Measured against the real Wikipedia article on the Eiffel Tower (44,988 characters), four of five answers were unreachable before and are selected now:
6. Nothing checked that the answer was in the language of the question
The system prompt asks for the user's language and this model drifts back to English. It is the most visible way it is wrong and the one thing settleable without asking the model anything, since the evidence is the user's own message.
wrong-languagejoins the three deterministic checks, and it is as shy as they are: both sides have to be recognisable, so 330 Meter. has no language, a German answer quoting an English sentence is still German, and a question in a third language leaves the check silent. The correction is written in the language it asks for.7. Two caps that were claimed and not enforced
The transcript now has a budget in
toHistory— 8,000 characters, oldest whole turns dropped, the turn being answered kept whatever it costs. Not because the window is full: Qwen3.5 carries 262,144 positions. It is re-prefilled on every round of every turn, twice for the capped strategies, and length dilutes attention.And an MCP result is capped at the same 8,000 characters as a page read. The README already said it was; nothing did it, so one verbose server could take the whole prompt.
This is the least certain change in the set and the one to point the harness at first: a transcript cap trades context for focus, and only measurement can say whether 8,000 is the right side of that trade.
What was not done
A bigger model. It is the only change that raises general reasoning rather than a specific behaviour, and it was ruled out for this branch. For the record, there is no text-only 2B export;
onnx-community/Qwen3.5-2B-ONNXat q4f16 is a 1,039 MiB decoder plus 280 MiB of embeddings against 448 MiB today.skill-coverage-before-after.log
read-page-finds-the-answer.log
converter-and-language-check.log
calculator-and-routing-before-after.log
To show artifacts inline, enable in settings.