Repository navigation
Replies: 3 comments
|
A useful design principle here is to keep the tool definitions stable across requests whenever the provider's prompt-caching behavior benefits from a stable prefix. If adding a tool changes the serialized I'd consider three approaches:
One caution: removing schemas entirely is not automatically a good optimization. The model still needs accurate parameter names, required fields, and behavioral constraints. A smaller prompt can become more expensive if it causes invalid tool calls and additional retries. I'd evaluate the optimization using total cost per successful task, not just the number of tokens saved in the tool definitions. Hope this helps! If this addresses the question, would you consider marking the answer as accepted? |
|
Thanks for reading it closely — the three points are, in order, the three things the post measures, so I think we're saying the same thing:
On cost per successful task: agreed, and it is why we took neither byte-saving option — dropping the parameter text was worth ~23 full-price-equivalent tokens per request, while one extra round caused by a mis-called tool costs thousands of those. One thing I can't do: this thread is filed under Ideas, which has no accepted-answer feature (it is also our own post), so there is nothing to mark there. If a specific number would be useful to you — the probe recipes behind either table, for instance — just ask and I will post them. Same setup as the post: |
|
A follow-up to §2 — what the failure profile looks like in real use, and where the parameter knowledge actually matters. We re-ran the question against our own session corpus (939 sessions, 95,235 tool results) instead of a synthetic arm:
The dominant failure modes are world-state, not argument shape: "read the file before editing it" ( Two adjustments to §2's framing follow from that:
Boundary: one deployment, one fork, one corpus — those rates are ours, not universal, and we have not yet tested removing a schema from a high-frequency tool. That A/B is the next thing we would run. Same setup as the post: |
Uh oh!
There was an error while loading. Please reload this page.
Two findings from measuring a local
dshdeployment (2026-10-09) against the official Messages endpoint — a follow-up to our earlier startup-tax post, on the same question of which bytes cost what. Both are cheap to reproduce.Versions and scope:
@deepseek-ai/dsh-tools0.1.0-rc.5 (a fork ofdeepseek-ai/deepseek-harness); 17 always-on tools on the wire after the fix below (20 before it — 3 lazily loaded tools had re-joined the field). The cache-order result is a property of the provider's prefix cache, so it applies to any client; the "constanttoolsarray" fix is a config we added in our fork — the upstream on-demand loading path still appends a loaded tool's schema to the field.1.
toolsis cached beforemessages, so a load costs the whole context — not the delta.It is tempting to reason from the wire order (the request body serializes
messagesbeforesystemandtools). The cached prefix is not in that order. Same system, same message, one change per request:cache_readtoolstoolsThe break lands at the start of the messages in every case: the cached prefix is
system→tools→messages. So any change inside thetoolsfield re-prices the entire retained history on the next request. Scaled to a session with a ~1 MB prompt: the schema being added is a few hundred tokens, while the history that gets re-priced is ~375k tokens — three orders of magnitude apart.That matters for every on-demand / deferred tool-loading scheme: if loading a tool appends its schema to
tools, the load is billed as a full context re-read. We made the array constant per session instead — a loaded tool stays off the wire, and its parameter detail arrives in the loading call's own result text. After the change:toolswent from 20 entries / 13,580 B to 17 / 10,553 B, the wholetoolssection is byte-identical across a load, and 16 consecutive requests showcache_readclimbing 179,072 -> 193,792 with 164-875 uncached — no break.2. You can drop the JSON schema, but you cannot drop the parameter knowledge.
Four arms x 10 realistic one-call tasks, same model (
deepseek-flash), same 17 tools, only the parameter presentation changed:systemTypical failures in the last arm:
readcalled withpathinstead offile_path;pwshmissing its requireddescription. Tool choice was unaffected across all four arms (the same tasks were missed in each).Byte math on our 17 always-on tools: JSON schemas plus structure = 10,553 B; moving the parameters into a text signature with descriptions untouched = 9,647 B (-8.6%); also collapsing the descriptions to one line = 4,838 B (-54%). We took neither: the first saves about 23 full-price-equivalent tokens per request, and the second buys ~5.7 KB by dropping the operative text in those descriptions (how to run long jobs, exit-code semantics, spill files, sandbox denials) — while one extra round caused by a mis-called tool costs thousands of those tokens. The load-path fix above is worth roughly 2,300 requests of that byte-saving.
Happy to share the probe scripts and raw numbers.
All reactions