Configuration¶
Every setting is an environment variable. The common ones also have CLI flags —
run needle-openai --help (or python -m needle_openai --help) to list them.
CLI flags win over environment variables.
The repository ships a
.env.example
you can copy to .env for Docker Compose.
Reference¶
| Variable | Flag | Default | Purpose |
|---|---|---|---|
NEEDLE_HOST |
--host |
0.0.0.0 |
Bind address. |
NEEDLE_PORT |
--port |
8000 |
Bind port. |
NEEDLE_API_KEY |
--api-key |
unset | Require Authorization: Bearer <key>. Unset serves openly. |
NEEDLE_WEIGHTS |
--weights |
unset | Serve a tuned .cact instead of base needle-2. |
NEEDLE_MODEL_ID |
--model-id |
needle-2 |
Id advertised by /v1/models. |
NEEDLE_STRICT_MODEL |
--strict-model |
false |
404 on other model names. |
NEEDLE_MAX_NEW_TOKENS |
--max-new-tokens |
256 |
Generation cap when the request omits max_tokens. |
NEEDLE_MAX_QUEUE_DEPTH |
--max-queue-depth |
32 |
Reject with 429 past this backlog. |
NEEDLE_REQUEST_TIMEOUT |
--request-timeout |
120 |
Per-request deadline, seconds. |
NEEDLE_MAX_REPLAY_STEPS |
— | 32 |
Cap on engine calls used to replay one conversation. |
NEEDLE_EXPOSE_EXTRAS |
--no-extras |
true |
Include the x_needle block on responses. |
NEEDLE_EXACT_TOKEN_COUNTS |
— | true |
Use the sentencepiece tokenizer for usage when available. |
NEEDLE_BUFFER_SIZE |
— | 1048576 |
Output buffer handed to the native engine. |
NEEDLE_ALLOWED_ORIGINS |
— | * |
CORS origins, comma-separated. |
HF_TOKEN |
— | unset | Avoids anonymous HuggingFace rate limits on first download. |
Notes on specific settings¶
NEEDLE_STRICT_MODEL¶
Off by default. Many OpenAI clients and frameworks hard-code model names like
gpt-4o-mini, and rejecting them would break drop-in use for no benefit — there
is only one model being served either way. Turn it on when you want an explicit
error instead of silent substitution.
NEEDLE_MAX_QUEUE_DEPTH¶
Requests serialize through a single engine thread, so an unbounded queue converts
load into timeouts. Past this depth the server returns 429 with
code: engine_busy, which a client can back off on. Watch queue_depth on
/health and x_needle.queue_wait_seconds on responses to size it.
NEEDLE_BUFFER_SIZE¶
The native engine writes its JSON response into a fixed buffer and truncates silently when it is too small, which surfaces as a JSON decode error rather than anything diagnostic. The 1MB default is generous; raise it only if you declare very large tool sets and see decode failures.
NEEDLE_EXACT_TOKEN_COUNTS¶
Requires sentencepiece, which the full image target includes and the base
target does not. When unavailable the server falls back to a character heuristic
and flags usage.estimated: true. See
fidelity notes.
Tuned weights¶
Fine-tune with needle finetune / needle build from the upstream
cactus-needle package, then serve the
result:
With Compose, ./weights is mounted read-only at /weights.
.cact archives are engine-version-locked
An archive exported by a different cactus-needle version will not load, and
fails loudly at startup rather than serving a broken model. Re-run
needle build on your checkpoint with the matching package version.
Deployment¶
The server runs one uvicorn worker by design — the native engine is a single global session (see Architecture). Scale horizontally:
services:
needle:
image: ghcr.io/sirmmo/needle-openai:latest
deploy:
replicas: 4
volumes:
- needle-cache:/cache
Each replica holds its own copy of the model, which is the cheap thing about a 14MB model. Put any load balancer in front; requests are independent apart from the session-reuse optimization, which is a latency nicety rather than a correctness requirement — sticky routing improves agent-loop performance but nothing breaks without it.
Resource sizing: the model reported 31–103MB peak RAM across the requests tested. The Compose file sets a 1GB limit, which is generous headroom for Python and the HTTP stack.