Repository navigation
bloomery 0.3.5 serves DeepSeek V4.1 Flash 1017 to DeepSeek Harness (dsh) with no shim: tool calls in the
spelling the model writes, tool-call arguments that stream as they are written, --chat-template-file on every seat,
and thinking from reasoning_effort.
Install
Linux x86-64 with AVX2 (glibc 2.34+), an NVIDIA GPU of compute capability 8.6+ and driver R580 or newer (CUDA 13).
On Windows, run inside WSL2. Docker and Homebrew as in the README.
curl -fsSL https://raw.githubusercontent.com/midagedev/bloomery/main/tools/release/install.sh | sh
bloomery-serve -m PATH/DeepSeek-V4.1-Flash-1017-Q3_K_M-00001-of-00010.gguf --port 8080Use it with dsh
The setup the release clip ran (dsh @deepseek-ai/dsh 0.2.0-rc.2, one RTX 3090).
-
Start the server with a model id for dsh to name:
bloomery-serve -m PATH/DeepSeek-V4.1-Flash-1017-Q3_K_M-00001-of-00010.gguf \ --host 127.0.0.1 --port 8080 --alias deepseek-v4.1-flash-1017
The server picks the context from the card's room (262,144 tokens on a 3090 for this model) and prints it in its
ctx … ctx=Nlog line;--ctx-size Nsets it.--chat-template-file FILEis optional: the model file's own template
already gives tool calls and thinking. -
Install dsh (
npm install @deepseek-ai/dsh) and add a provider to the profile you run. Write this into
$DSH_HOME/profiles/<profile>/cordis.patch.yml(webfordsh web,headlessfordsh --profile headless):- id: llm-pi-ai config: providers: bloomery: apiKeyEnv: BLOOMERY_DSH_KEY api: openai-completions baseURL: http://127.0.0.1:8080/v1 reasoning: high models: - id: deepseek-v4.1-flash-1017 contextWindow: 262144 # the server's ctx=N maxTokens: 65536 reasoningEfforts: off: none high: high max: max - id: agent-default-model config: provider: bloomery model: deepseek-v4.1-flash-1017
-
Set the key variable and start dsh:
export BLOOMERY_DSH_KEY=none(any value: the server checks no key unless it
was started with--api-key, and then the value must be that key), thendsh web.
No compat block and no proxy are needed. The server parses V4.1's tool-call spelling itself and streams the arguments
as they are written. reasoning picks dsh's default thinking level; off sends reasoning_effort: none, which turns
thinking off. The first ~400 decode steps after a load are slower (Known limits).
New
- DeepSeek V4.1 Flash 1017 with dsh: V4.1 DSML tool calls are parsed in the spelling the model writes, and
thinking followsreasoning_effort(#471). Tool-call arguments stream as the model writes them, on every seat that
parses tool calls; a call whose sent text the parser would have to revise is a named error, never a silent rewrite
(#477). --chat-template-fileworks on every seat: DeepSeek V4.1, GLM, Qwen3.8, Qwen3, MiMo and Nemotron (#477).reasoning_effortoutsidenone,minimal,low,medium,high,xhigh,maxis a named 400 (#477).- Structured output:
json_schemaresponse formats and forced tool calls are held by a program over the
vocabulary (#467). - Qwen3.8-27B dense generation, and Qwen XML tool calls with the think span on every Qwen3.5-family variant (#472,
#475). Ornith-1.5-35B-A3B runs on the Qwen3 seat (#425). - Quant types: a generic host dot serves a type that has a host activation and no hand kernel (#450); a card quant
type's expert-select entries are one macro line (#460).
Changed
- Lightning's ungated relu² experts run on the card (#437). The host tier's card leg runs its host list while the
step's arena fills are in flight (#424). - Multi-node (by @juliankang4): a tier node may sit on a back-to-back link in 198.18.0.0/15 (#440), and a tier's done
over a mirrored link posts only the columns its chain uses (#443, closes #421).
Fixed
- Named faults instead of silent values in rope_neox, the DS41 kernels, the fused rope tail and the NVMe split (#435).
- Reference writers, ptx-scan and the nightly runner stop on a failed read or a TERM instead of reporting success
(#444, #446, #451, by @juliankang4). - Developer tooling and gates: see the merged pull requests since v0.3.4.
Known limits
- V4.1 on two cards (
--place bp) is not faster than one card (a). In 0.3.5 two cards decode at about the speed of one. Unset--placepicksa. - V4.1's first ~400 decode steps after a load run at 25–40 tok/s while adaptive residency lands experts on the card
(24 experts every 4 steps); after that, the dsh run onbpdecoded at 45–49 tok/s. - From 0.3.4: Bolt needs a 24 GB card and refuses
--place bp. From 0.3.3: Qwen3.6 has no DSpark draft; V4.1 DSpark
serves one slot and refuses images; Nemotron 3 Nano 4B serves one slot on one card with no prompt cache.
Checked before the tag
Release head 1ef252d13 (f9b380607 and the README status). The release batch ran 199 gates on the fixture tier (3 red, none in code this release changed:
gate-gpu-nemotron-serve was red on main before the cut, from card room; gate-qdot's IQ4_XS clause compares with an
ik reference dump the box rewrote on the day of the cut, and the IQ4_XS code is unchanged since v0.3.4;
gate-gpu-qwen38-nodes-remote needs a second tier node this machine does not have), then the 75 gates that
run on the real model files (all green).
Every needs-gpu pull request since v0.3.4 is covered by those gates.
The tarball's bloomery-serve with DeepSeek V4.1 Flash 1017 Q3_K_M at the serving defaults (every lever unset,
--ctx-size 32768), one load per placement, on an RTX A6000 + RTX 3090 (250 W) machine, the box quiet (no other
process on either card). These are each load's first requests, not a timing lease; they run while adaptive
residency is still landing experts on the card (below):
| Request | unset (picks a): first token, decode |
bp: first token, decode |
|---|---|---|
| Short chat (20 tokens) | 0.49 s, 25.5 tok/s | 0.57 s, 24.9 tok/s |
| Long prompt (4,108 tokens) | 11.20 s (367 tok/s prefill), 31.3 tok/s | 10.47 s (393 tok/s prefill), 35.6 tok/s |
| One tool call | 2.07 s, 32.4 tok/s, tool_calls, arguments parse |
1.94 s, 35.9 tok/s, tool_calls, arguments parse |
reasoning_effort: high |
0.28 s, 29.1 tok/s, thinking in reasoning_content |
0.25 s, 34.0 tok/s, thinking in reasoning_content |
The dsh run in the clip (--place bp, 46 requests, 50 tool calls, 96,829 tokens in 45 minutes): all 50 tool calls
parsed, the arguments of 49 of 50 streamed as written, and its median decode was 45.4 tok/s.
Thanks
- @juliankang4 for the multi-node link and column fixes, and the reference-writer, ptx-scan and nightly-runner fixes.