File size: 7,844 Bytes
a484e22 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | # SpecMem: Accelerating Agentic Tool Calling via Live Memory Management
[](LICENSE)
[](https://www.python.org/)
[](#citation)
Agents spend much of their latency decoding tool calls token by token, yet the
calls a user needs are highly repetitive across sessions. **SpecMem** turns
that repetition into speed: it keeps a small, per-user, capacity-bounded memory
of past tool calls that is updated *live* as the agent runs, and retrieves the
closest past call as a **draft** for speculative decoding. The served model
verifies the draft, so outputs are exactly those of standard decoding β wrong
drafts cost only compute, never correctness.
The key finding is that **liveness drives the gain**: a store that keeps
ingesting and evicting stays fresh as the query distribution drifts, while a
frozen datastore (built once, then fixed) degrades over sessions.
**Highlights**
- **Live per-user memory as a drafter.** Top-1 cosine retrieval over
lightweight query embeddings (`all-MiniLM-L6-v2`, CPU), per-user
partitioning, LRU eviction at a small fixed capacity, online write-back
after every verified call. No training, no extra GPU.
- **End-to-end wall-clock speedups** of 1.62x / 1.74x / 1.18x / 1.69x over
vanilla autoregressive decoding on API-Bank, ToolAlpaca, BFCL v4, and
ToolBench, matching or exceeding a faithful frozen-datastore
(ToolSpec-style) baseline on all four.
- **Verified across serving stacks and architectures:** `gpt-oss-120b` (MoE)
and `gemma-4-31B-it` (dense) on sglang, `Nemotron-3-Super-120B`
(hybrid-SSM) on vLLM β anything with an OpenAI-compatible endpoint works.
- **Safety-aware speculation:** an idempotency gate defers speculative
*execution* of irreversible tools (payments, deletes), keeping the speedup
while avoiding side effects a verifier cannot undo.
## How it works
```
user query ββ> embed ββ> per-user memory (capacity-bounded, LRU)
β top-1 cosine β₯ Ο
βΌ
drafted tool call ββ> served model verifies
β² (token-level accept)
β
write-back of the verified call (live update)
```
Every query is answered once by the served model with greedy decoding (the
*target*). Each memory policy ("arm") drafts from its own store and is scored
by the token-level longest common prefix between its draft and the target β
the accepted-token count a speculative decoder would realize. The compared
arms:
| Arm (code name) | Description |
|---|---|
| `no_memory` | schema-only draft; lower bound |
| `static_global` | one global store frozen after warmup (ToolSpec-style) |
| `personal_memory` | **SpecMem**: per-user, live-updating, capacity-bounded |
| `toolspec` | faithful ToolSpec reimplementation (frozen kNN-vote + schema FSM) |
## Installation
```bash
git clone <this-repo> specmem && cd specmem
pip install -r requirements.txt
bash scripts/download_data.sh # fetches BFCL, Seal-Tools, ToolAlpaca, API-Bank
```
Benchmark data is downloaded from the official sources, never redistributed
here; two datasets need a small manual step (ToolBench, tau2-bench) β see
[`data/README.md`](data/README.md).
## Quickstart
**1. Serve a tool-calling model** behind any OpenAI-compatible endpoint, e.g.
```bash
python -m sglang.launch_server --model-path openai/gpt-oss-120b --port 30000
```
**2. Run the main acceptance experiment** (3 arms x 40 users x 12 sessions,
3 stream seeds β the paper's headline setting):
```bash
python -m harness.run_accept \
--users 40 --tasks-per-user 15 --sessions 12 --queries-per-session 6 \
--capacity 48 --n-seeds 3 --url http://localhost:30000/v1 --tag main
```
Targets are cached by exact query string, so re-runs and all memory-arm
replays are GPU-free. Results land in `results/main_accept_results.json`
(per-session and overall MAT / accepted fraction / exact rate).
Add `--benchmark sealtools` for Seal-Tools. For other served models, point
`--url`/`--model` at the endpoint and `--model-path` (or the
`SPECMEM_TOKENIZER` env var) at the model's tokenizer so acceptance is
measured in that model's own tokens.
## Reproducing the paper
| Experiment | Command |
|---|---|
| Main acceptance table (BFCL / Seal-Tools) | `python -m harness.run_accept ...` (above) |
| 4-benchmark main table + wall-clock speedups | `python -m harness.phase4_maintable` |
| Freshness-over-sessions curve | `python -m harness.phase4_partb`, then `python -m harness.phase4_freshness_fig` |
| Memory-capacity sweep | `python -m harness.capacity_sweep` |
| Ablations (eviction, sharing, perturbation) | `python -m harness.run_ablation` |
| Warmup-fraction sweep | `python -m harness.review_r1_warmup` |
| Provenance (shared vs per-user) | `python -m harness.review_r2_provenance` |
| Retrieval-threshold sweep | `python -m harness.review_r3_confidence` |
| Reset / TTL memory-policy arms | `python -m harness.reset_arm`, `python -m harness.ttl_arm` |
| Suffix-decoding baseline | `python -m harness.phase4_suffixdecoding_maintable` |
| Throughput / overlap under load | `python -m harness.phase4_throughput`, `python -m harness.phase4_overlap` |
| Speculative-execution safety gate | `python -m harness.safety` |
| Bootstrap confidence intervals | `python -m harness.bootstrap_ci` |
| tau2-bench live traces + scoring | `python -m harness.tau2_live generate / extract / score` |
The tau2-bench `generate` mode runs the served model as the agent against a
live GPT-4.1 user simulator and requires `OPENAI_API_KEY` (and optionally
`OPENAI_BASE_URL`) in the environment, plus a
[tau2-bench](https://github.com/sierra-research/tau2-bench) install
(`TAU2_BIN`, `TAU2_DATA_DIR`). Credentials are read from environment
variables only and a leak check aborts if a key ever appears in an artifact.
## Repository layout
```
harness/ all experiment code (run as python -m harness.<module>)
memory.py memory arms: NoMemory, StaticGlobal, PersonalMemory (SpecMem),
ToolSpecBaseline, suffix-decoding baseline
simulate.py multi-session, multi-user query-stream generator
data.py benchmark loaders (BFCL, Seal-Tools, ToolAlpaca, API-Bank,
ToolBench, tau2)
client.py OpenAI-compatible client + tool-call parsers (harmony, XML)
metrics.py canonicalization + token-LCP acceptance scoring
run_accept.py main 3-arm acceptance experiment
... see the table above for the per-experiment entry points
scripts/ data download
data/ benchmark data (downloaded; see data/README.md)
results/ experiment outputs (created at runtime)
```
## Environment variables
| Variable | Purpose | Default |
|---|---|---|
| `TOOL_SERVER_URL` | served-model endpoint | `http://localhost:30000/v1` |
| `SPECMEM_TOKENIZER` | tokenizer for the accept metric | `openai/gpt-oss-120b` |
| `OPENAI_API_KEY` / `OPENAI_BASE_URL` | tau2 user-simulator credentials | β |
| `TAU2_BIN` / `TAU2_DATA_DIR` | tau2-bench CLI and data locations | `tau2` / β |
## Citation
The paper is currently under review. If you use this code, please cite:
```bibtex
@article{specmem2026,
title = {SpecMem: Accelerating Agentic Tool Calling via Live Memory Management},
author = {Anonymous},
note = {Under review},
year = {2026}
}
```
## License
This repository is released under the [Apache License 2.0](LICENSE).
Benchmark datasets and served models keep their own licenses (see
[`data/README.md`](data/README.md)).
|