-
Notifications
You must be signed in to change notification settings - Fork 251
feat(server): split tools from chat so PFlash works on agent turns #492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
davidmroth
wants to merge
20
commits into
Luce-Org:main
Choose a base branch
from
davidmroth:feat/tool-split-agent-cache
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
07535cc
Align server_tools.py with server.py dual-GPU daemon flags
davidmroth e201061
Accept --daemon in server_tools.py for Compose parity with server.py
davidmroth 129f11e
Improve OpenAI tool parity: tool_choice, max_completion_tokens, ignor…
davidmroth aad5576
Fix tool use: default enable_thinking off, force off with tools, fix …
davidmroth dda4321
Merge branch 'feature/dual-gpu-dflash-safe-p2p-port' into feature/dua…
davidmroth 766c6ee
fix(dflash): multi-turn tool-split cache restore and usage timings
davidmroth 802059b
fix(dflash): tool-split VRAM budget and ship tool_split package
davidmroth acc3ea3
fix(dflash): reject stale prefix-cache lookups after in-place slot re…
davidmroth 7304e3e
Merge branch 'feature/dual-gpu-dflash-safe-p2p-tool-use' into main
davidmroth e2ee1b5
feat(server): tool-split KV cache for multi-turn agent tool use
davidmroth 16fda18
fix(tool-split): address Copilot review on slot LRU and snap failure
davidmroth ca96b57
Merge main into feat/tool-split-agent-cache
davidmroth f1a4583
docs: reframe tool-split goal around PFlash-friendly tool isolation
davidmroth f04356f
fix(tool-split): stop encoding system-only prompts for Qwen3.6 tools
davidmroth 82629a9
fix(test_dflash): store prefix snapshots in system RAM via snapshot b…
davidmroth 25e0226
fix(tool-split): legacy daemon opt-in + dict tool_call arguments coer…
davidmroth ebf2b4d
test(tool-split): Qwen-shaped tokenizer stub for split boundary tests
davidmroth 87dc291
fix(tool-split): drop 1-slot prefix-cache VRAM clamp
davidmroth 14a0f42
feat(server): expose spec-decode telemetry in API usage timings
davidmroth 44d2ac2
fix(tool-split): address PR review — cache eviction, abort wiring, an…
davidmroth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| # Tool-split — project goal | ||
|
|
||
| ## The idea | ||
|
|
||
| Agents that use tools (read a file, run a command, search code) should feel **fast after the first turn** — not like every message is starting from scratch. | ||
|
|
||
| Today, tool definitions get mixed into the same prompt as the conversation. That hurts **PFlash**, the system that compresses and speeds up long chat history. When tools and chat share one blob of text, PFlash has to fight through tool JSON it was never meant to optimize. You pay for the tools again and again, and the conversation speedups never fully kick in. | ||
|
|
||
| **Tool-split** is the fix: **pull tools out of the conversation path.** | ||
|
|
||
| - Tool schemas live in their own pinned memory (thin KV slots). | ||
| - The chat history stays clean for PFlash and prefix cache. | ||
| - Tools no longer drag down the algorithm that makes multi-turn chat fast. | ||
|
|
||
| Pay the full cost once. After that — especially after a tool result comes back — the agent should feel snappy. | ||
|
|
||
| ## What users should feel | ||
|
|
||
| - **Turn 1 (cold)** — full cost once (tools + first message). Expected. | ||
| - **Later turns with a little new text** — a few seconds, not another cold start. | ||
| - **After a tool result** — the common “continue” path must be fast and reliable. | ||
|
|
||
| If the cache is “working” but people still wait 15 seconds per message, we have not succeeded. | ||
|
|
||
| ## How it works (short version) | ||
|
|
||
| 1. **Pin tools separately** — tool schemas sit in thin snapshot slots (`SNAPSHOT_THIN`). No re-prefill of hundreds of tool tokens every turn. | ||
| 2. **Cache conversation alone** — chat history uses `RESTORE_CHAIN` + prefix cache so PFlash can focus on what it does best. | ||
| 3. **Respect VRAM** — one conversation prefix slot, updated in place (`DFLASH_PREFIX_CACHE_SLOTS=1` on 2×24GB). Extra thick snapshots can OOM and **silently kill every speedup**. | ||
|
|
||
| Stack: `model-runner-v4` → lucebox (:8080) → ai-platform proxy (:8000) | ||
|
|
||
| ## Practical success criteria | ||
|
|
||
| | What users care about | Target | How we measure | | ||
| |----------------------|--------|----------------| | ||
| | Incremental turn latency | **Wall-clock ≪ turn 1** when only a few new tokens are added | `elapsed_s` on benchmark turn 3 / agent-after-tool | | ||
| | Time to start generating | **Prefill ≪ cold** on cached turns | `usage.timings.prefill_ms` | | ||
| | Reliability | Speedup works every session, not 1-in-3 after OOM | `inline-snap committed` ≥ 1, no `inline snap failed` in logs | | ||
| | Agent hot path | **After tool result**, response in **< 4s** typical | `agent_after_tool` benchmark phase | | ||
| | Correctness | Multi-turn tools complete, no `bad thick slot` | 3+ turn session completes | | ||
|
|
||
| ### Validated on ai.local (when cache is active) | ||
|
|
||
| | Turn | elapsed | prefill_ms | Notes | | ||
| |------|---------|------------|-------| | ||
| | 1 cold | ~8s | ~2570 | full prompt + tool pin | | ||
| | 2 (bigger delta) | ~6s | ~2240 | still prefills new messages — **not the main win** | | ||
| | 3 (tiny delta) | **~3.7s** | **~120** | **21× prefill speedup** — this is the usable win | | ||
|
|
||
| **Key insight:** Speedup tracks **how many new prompt tokens** you add. Small follow-ups feel fast; huge new user messages still cost prefill. That is expected — agents usually add short tool results or short replies between turns. | ||
|
|
||
| ## What “done” is not | ||
|
|
||
| - Faster decode tok/s on tool turns (decode is short; **prefill** is what we cache). | ||
| - Benchmark-only wins that do not show up as lower `elapsed_s` for incremental turns. | ||
| - Production-ready without soak tests, baked image, and CI gate. | ||
|
|
||
| ## One-line summary | ||
|
|
||
| **Split tools out so PFlash can speed up the conversation — pay full prefill once; every small follow-up (especially after tool results) should feel snappy.** | ||
|
|
||
| ## Infrastructure reference | ||
|
|
||
| | Item | Path / detail | | ||
| |------|----------------| | ||
| | Server | `david@192.168.87.153`, `/media/data/projects/` | | ||
| | Patch scripts | `model-runner-v4/lucebox-patch/dflash/scripts/` | | ||
| | Daemon binary | `lucebox-hub-src/dflash/build/test_dflash` | | ||
| | Benchmark | `model-runner-v4/scripts/benchmark-tool-split.py` | | ||
| | Goal doc | `server/docs/tool-split-goal.md` | | ||
|
|
||
| ## Key env | ||
|
|
||
| ```bash | ||
| DFLASH_TOOL_SPLIT_ENABLED=1 | ||
| DFLASH_PREFIX_CACHE_SLOTS=1 # required for reliable cache on 2×24GB | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
|
||
| DFLASH_TOOL_SPLIT_PINNED_SLOTS=2 | ||
| DFLASH_LAYER_SPLIT=0 | ||
| ``` | ||
|
|
||
| ## How to verify practical speed | ||
|
|
||
| 1. Use **`tools`** in the request (tool-split is off without them). | ||
| 2. **Restart lucebox** after deploy (clears stale GPU snapshot slots). | ||
| 3. Run `benchmark-tool-split.py` — check **elapsed_s** and **prefill_ms**, not decode tok/s. | ||
| 4. Logs must show `thick=0`, `inline-snap committed`, and **no** `inline snap failed`. | ||
| 5. Compare **turn 3** or **agent_after_tool** to turn 1 — that is the user-visible win. | ||
|
|
||
| ## Remaining work for production-grade practical speed | ||
|
|
||
| - [x] Agent-realistic benchmark phase (user → tool_call → tool result → continue) | ||
| - [ ] Bake patch + binary into image (no host-mount drift) | ||
| - [ ] CI gate: incremental turn `elapsed_s` < 4s, `prefill_ms` < 500ms | ||
| - [ ] Soak test: 50 sessions without daemon death or OOM | ||
| - [ ] Merge `lucebox-hub` PR and sync `model-runner-v4` defaults | ||
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.