DEV Community

How I Built a Zero-Copy Rust Proxy to Stop Runaway LLM API Bills (and Survived the Docker Loopback Trap)

ยชญ์ศรัณย์ ผิวผ่อง on July 08, 2026

If you are building applications on top of foundational models like OpenAI or Anthropic, you already know the existential dread of waking up to a s...
Collapse
 
max_quimby profile image
Max Quimby

The "wake up to a spiked bill" dread is painfully real — for us it's almost never a rogue while-loop, it's an autonomous agent that gets into a retry loop and cheerfully burns tokens looking productive. A global circuit breaker at the proxy layer is exactly the right primitive, and doing it zero-copy in Rust so you're not adding p99 latency to every completion is a nice touch.

The thing I'd want next is attribution: when Kilovolt trips, do you know which caller or which agent burned the budget, or just that the aggregate breached? In a multi-agent setup the global cap protects your wallet, but a single misbehaving sub-agent can starve everyone else once it's the one holding the connection. Have you considered per-key or per-route budgets so one runaway loop trips its own breaker instead of the whole fleet's? And how do you handle a hard-cut mid-stream — do downstream clients get a clean 429-style signal, or a dropped connection they have to interpret?

Collapse
 
yodsran profile image
ยชญ์ศรัณย์ ผิวผ่อง

Following up on this, Max! Your point about multi-agent attribution was completely aligned with where the architecture needs to go. I pushed a midnight sprint to operationalize the first phase of this.

I just shipped v1.2.0, which now includes an embedded, zero-dependency telemetry dashboard served directly from the Rust binary. It gives you a real-time ledger of active users/agents burning the budget, token counts, and exact transaction costs, all while maintaining that 15MB memory footprint.

True per-route circuit breaking is next on the sprint block, but having this "single pane of glass" for observability was the critical first step. Would love your thoughts on the telemetry metrics if you end up pulling the latest container!

Collapse
 
yodsran profile image
ยชญ์ศรัณย์ ผิวผ่อง

Thanks, Max! You hit the nail on the head. That exact scenario—one misbehaving sub-agent starving the whole fleet—is exactly why the global cap is just the MVP.

To answer your questions:

Attribution & Granular Routing: Right now, the global cap is the primary defense, but per-key and per-route budgeting is currently the top priority for v1.2. The architecture is designed to support custom header ingestion (e.g., X-Agent-ID), which will allow the proxy to track and isolate specific agent runaways without punishing the entire fleet.

Mid-Stream Hard Cuts: When a budget is breached mid-stream, Kilovolt doesn't just sever the TCP connection blindly (which, as you noted, leaves downstream clients hanging). It injects a clean 429 Too Many Requests response back to the client, along with a custom payload indicating a budget breach rather than a provider rate limit. This allows your downstream orchestration to handle the failure gracefully.

Really appreciate the feedback—handling multi-agent attribution is exactly where this needs to go next.

Collapse
 
alexshev profile image
Alex Shev

The runaway-bill problem is one of the least glamorous but most important parts of LLM infrastructure. A proxy becomes useful when it can enforce budgets, normalize retries, expose per-route cost, and fail closed before one bad loop turns into a surprise invoice. The Docker networking trap is exactly the kind of detail that makes this real engineering.

Collapse
 
yodsran profile image
ยชญ์ศรัณย์ ผิวผ่อง

Spot on. It’s exactly that "un-glamorous" layer that separates a prototype from production-ready infrastructure. I’ve realized recently that building the AI is often the "easy" part—managing the financial and operational risk is where the real engineering challenge lives.

That Docker network trap was definitely a "baptism by fire" moment for me, but solving it forced me to really understand how traffic flows through container bridges. I’m glad you appreciate the "fail-closed" philosophy—that’s the core of the Bankruptcy Shield.

If you get a chance to poke around the codebase, I’d love to hear your take on the stream-piping performance in src/proxy.rs. Always looking for a second set of eyes on the implementation.

Collapse
 
alexshev profile image
Alex Shev

From the article-level view, I would inspect backpressure, cancellation, and byte accounting first. A stream proxy can look efficient while still leaking work on client disconnects or retries. For a real code take, I’d want to read the specific proxy path and test how it behaves when the upstream stalls.

Thread Thread
 
yodsran profile image
ยชญ์ศรัณย์ ผิวผ่อง

You’re dead on. Those are the exact pain points I’m battle-testing.

I’m currently using tokio::select! to ensure client drops trigger immediate upstream abort() calls, preventing orphaned work. Backpressure and stall-handling are definitely the next frontiers.

If you have a second, I’d love a gut-check on the implementation in src/proxy.rs. I'm specifically looking for edge cases in how we handle upstream timeouts—would appreciate your eyes on it.

Collapse
 
reneza profile image
René Zander

The mid-stream question points at the real limit of a stream-level cut: by the time you hard-kill the socket, the prompt tokens and part of the completion are already committed upstream, so you have detected the overage rather than prevented it. The cheaper backstop is a pre-flight gate: estimate the request's token cost, check it against a per-key daily and per-minute budget, and reject before the upstream call ever opens. Keep the mid-stream kill as the last resort for the requests whose real cost only shows up while streaming. Enforcing per-key rather than one global cap also stops a single runaway agent from eating the budget the rest of the fleet needs. Here is the per-step, per-pipeline, per-day token budget model I use for the pre-flight side: gist.github.com/renezander030/a7d9...

Collapse
 
yodsran profile image
ยชญ์ศรัณย์ ผิวผ่อง

Hey Rene, thanks so much for dropping this here and linking to your guide—it's an incredible write-up.

You hit the nail on the head regarding the limitations of a purely mid-stream kill. While it is a great "circuit breaker" of last resort for runaway output streams, catching the overage pre-flight via a strict per-key budget is absolutely the smarter, cheaper first line of defense.

I really love the three-tiered (per-step, per-pipeline, per-day) model you outlined. It perfectly solves the exact problem you mentioned: preventing a single rogue agent from draining the budget for the rest of the fleet.

In fact, your comment just influenced the roadmap. Because of your article, I am actively building per-key daily and per-minute budget tracking into the latest upcoming release of Kilovolt. I'm going to integrate this exact pre-flight gating logic so users can define tiered limits.

Thanks again for sharing this level of production insight. I'll be sure to shout out your methodology in the release notes when the feature drops!

Collapse
 
valentynkit profile image
Valentyn Kit

What happens when the budget trips mid-stream? Does Kilovolt let the current SSE frame finish or hard-kill the socket right there?

Collapse
 
yodsran profile image
ยชญ์ศรัณย์ ผิวผ่อง

Great question! Hard-killing the socket mid-stream is dangerous because the client's EventSource will just auto-reconnect and hammer the proxy.

Instead, Kilovolt injects a final, synthetic SSE frame (event: error\ndata: {"error": "budget_exceeded"}\n\n) right before cleanly closing both sockets. This gives the frontend SDK a clear signal to stop polling and handle the cut gracefully.