llm-cachecheck 0.2.1__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: llm-cachecheck
3
- Version: 0.2.1
4
- Summary: Measure how often the prompt cache changes greedy answers on your LLM server (llama.cpp, plus an experimental two-server mode for vLLM and SGLang)
3
+ Version: 0.2.3
4
+ Summary: Measure how often the prompt cache changes greedy answers on your LLM server (llama.cpp, vLLM and SGLang)
5
5
  Project-URL: Homepage, https://github.com/aditi-p31/cache-divergence-study/tree/main/cachecheck
6
6
  Project-URL: Source, https://github.com/aditi-p31/cache-divergence-study
7
7
  Project-URL: Paper, https://doi.org/10.1109/ACCESS.2026.3749922
@@ -75,23 +75,38 @@ llm-cachecheck --base-url http://127.0.0.1:8080
75
75
 
76
76
  **vLLM, SGLang or another OpenAI-compatible server.** The cache is a server
77
77
  setting, so serve the same model twice, once with prefix caching on and once
78
- with it off. Both servers must report cached tokens. For vLLM on one GPU:
78
+ with it off. Both servers must report cached tokens. For vLLM on one 24 GB GPU
79
+ (a 3B model, so two copies fit):
79
80
 
80
81
  ```bash
81
- vllm serve Qwen/Qwen2.5-7B-Instruct --port 8000 --gpu-memory-utilization 0.45 \
82
+ vllm serve Qwen/Qwen2.5-3B-Instruct --port 8000 --gpu-memory-utilization 0.45 \
82
83
  --generation-config vllm --enable-prompt-tokens-details
83
- vllm serve Qwen/Qwen2.5-7B-Instruct --port 8001 --gpu-memory-utilization 0.45 \
84
+ vllm serve Qwen/Qwen2.5-3B-Instruct --port 8100 --gpu-memory-utilization 0.45 \
84
85
  --generation-config vllm --enable-prompt-tokens-details --no-enable-prefix-caching
85
86
  llm-cachecheck --mode two-servers --base-url http://127.0.0.1:8000 \
86
- --nocache-url http://127.0.0.1:8001 --model Qwen/Qwen2.5-7B-Instruct
87
+ --nocache-url http://127.0.0.1:8100 --model Qwen/Qwen2.5-3B-Instruct
87
88
  ```
88
89
 
89
- For SGLang, add `--enable-cache-report` to both servers and
90
- `--disable-radix-cache` to the second one.
90
+ For SGLang, add `--enable-cache-report` and `--sampling-defaults openai` to
91
+ both servers, and `--disable-radix-cache` to the second one.
91
92
 
92
- The two-server mode is covered by the unit tests against a simulated server.
93
- It has not yet been run against a real vLLM or SGLang server. If you run it,
94
- an [issue](https://github.com/aditi-p31/cache-divergence-study/issues) with what you saw is welcome.
93
+ Make sure each server really started on its own port. If another process
94
+ already holds a port, it can answer for it: RunPod's standard images, for
95
+ example, run an nginx proxy on port 8001 that forwards to port 8000, so both
96
+ URLs would reach the same server.
97
+ The tool then reports the recompute path reusing cached tokens and marks every
98
+ probe invalid, so check the server logs if that happens.
99
+
100
+ Tested on real servers on 2026-11-11 and 11-12 (UTC; one RTX 4090; the tool's 20
101
+ conversations; details in the [currency note](https://github.com/aditi-p31/cache-divergence-study/blob/main/CURRENCY_CHECK_2026-11.md)):
102
+
103
+ | Server | Model | Conversations with a different turn-2 answer | Both caches off |
104
+ |---|---|---|---|
105
+ | vLLM 0.33.0, two servers | Qwen2.5-3B-Instruct, BF16 | 14 of 20, in each of 5 runs | 0 of 20 |
106
+ | SGLang 0.5.23, two servers (CUDA graphs disabled) | Qwen2.5-3B-Instruct, BF16 | 12 of 20, in each of 2 runs | 0 of 20 |
107
+ | llama.cpp v0.9.0 | Qwen2.5-7B-Instruct, Q4_K_M | 11 of 20, in each of 2 runs | |
108
+
109
+ If you run it, an [issue](https://github.com/aditi-p31/cache-divergence-study/issues) with what you saw is welcome.
95
110
 
96
111
  Two server processes can also differ for other reasons. To check that, start
97
112
  both with prefix caching off and run with `--skip-hit-check`. Every probe
@@ -152,6 +167,13 @@ your results:
152
167
  A difference is not a bug in your model. It shows that the answer depends on
153
168
  the server's cache state as well as on the request.
154
169
 
170
+ ## Share your result
171
+
172
+ At the end of a run the tool prints a short result block. It leaves out your
173
+ server URL and any key. If you would like to share it, open a
174
+ [result issue](https://github.com/aditi-p31/cache-divergence-study/issues/new?template=cachecheck-result.yml)
175
+ and paste the block. Results where no probe differed are just as useful.
176
+
155
177
  ## Background and citation
156
178
 
157
179
  `cachecheck` adapts the paired cache-on and cache-off design of the study in
@@ -51,23 +51,38 @@ llm-cachecheck --base-url http://127.0.0.1:8080
51
51
 
52
52
  **vLLM, SGLang or another OpenAI-compatible server.** The cache is a server
53
53
  setting, so serve the same model twice, once with prefix caching on and once
54
- with it off. Both servers must report cached tokens. For vLLM on one GPU:
54
+ with it off. Both servers must report cached tokens. For vLLM on one 24 GB GPU
55
+ (a 3B model, so two copies fit):
55
56
 
56
57
  ```bash
57
- vllm serve Qwen/Qwen2.5-7B-Instruct --port 8000 --gpu-memory-utilization 0.45 \
58
+ vllm serve Qwen/Qwen2.5-3B-Instruct --port 8000 --gpu-memory-utilization 0.45 \
58
59
  --generation-config vllm --enable-prompt-tokens-details
59
- vllm serve Qwen/Qwen2.5-7B-Instruct --port 8001 --gpu-memory-utilization 0.45 \
60
+ vllm serve Qwen/Qwen2.5-3B-Instruct --port 8100 --gpu-memory-utilization 0.45 \
60
61
  --generation-config vllm --enable-prompt-tokens-details --no-enable-prefix-caching
61
62
  llm-cachecheck --mode two-servers --base-url http://127.0.0.1:8000 \
62
- --nocache-url http://127.0.0.1:8001 --model Qwen/Qwen2.5-7B-Instruct
63
+ --nocache-url http://127.0.0.1:8100 --model Qwen/Qwen2.5-3B-Instruct
63
64
  ```
64
65
 
65
- For SGLang, add `--enable-cache-report` to both servers and
66
- `--disable-radix-cache` to the second one.
66
+ For SGLang, add `--enable-cache-report` and `--sampling-defaults openai` to
67
+ both servers, and `--disable-radix-cache` to the second one.
67
68
 
68
- The two-server mode is covered by the unit tests against a simulated server.
69
- It has not yet been run against a real vLLM or SGLang server. If you run it,
70
- an [issue](https://github.com/aditi-p31/cache-divergence-study/issues) with what you saw is welcome.
69
+ Make sure each server really started on its own port. If another process
70
+ already holds a port, it can answer for it: RunPod's standard images, for
71
+ example, run an nginx proxy on port 8001 that forwards to port 8000, so both
72
+ URLs would reach the same server.
73
+ The tool then reports the recompute path reusing cached tokens and marks every
74
+ probe invalid, so check the server logs if that happens.
75
+
76
+ Tested on real servers on 2026-11-11 and 11-12 (UTC; one RTX 4090; the tool's 20
77
+ conversations; details in the [currency note](https://github.com/aditi-p31/cache-divergence-study/blob/main/CURRENCY_CHECK_2026-11.md)):
78
+
79
+ | Server | Model | Conversations with a different turn-2 answer | Both caches off |
80
+ |---|---|---|---|
81
+ | vLLM 0.33.0, two servers | Qwen2.5-3B-Instruct, BF16 | 14 of 20, in each of 5 runs | 0 of 20 |
82
+ | SGLang 0.5.23, two servers (CUDA graphs disabled) | Qwen2.5-3B-Instruct, BF16 | 12 of 20, in each of 2 runs | 0 of 20 |
83
+ | llama.cpp v0.9.0 | Qwen2.5-7B-Instruct, Q4_K_M | 11 of 20, in each of 2 runs | |
84
+
85
+ If you run it, an [issue](https://github.com/aditi-p31/cache-divergence-study/issues) with what you saw is welcome.
71
86
 
72
87
  Two server processes can also differ for other reasons. To check that, start
73
88
  both with prefix caching off and run with `--skip-hit-check`. Every probe
@@ -128,6 +143,13 @@ your results:
128
143
  A difference is not a bug in your model. It shows that the answer depends on
129
144
  the server's cache state as well as on the request.
130
145
 
146
+ ## Share your result
147
+
148
+ At the end of a run the tool prints a short result block. It leaves out your
149
+ server URL and any key. If you would like to share it, open a
150
+ [result issue](https://github.com/aditi-p31/cache-divergence-study/issues/new?template=cachecheck-result.yml)
151
+ and paste the block. Results where no probe differed are just as useful.
152
+
131
153
  ## Background and citation
132
154
 
133
155
  `cachecheck` adapts the paired cache-on and cache-off design of the study in
@@ -22,7 +22,8 @@ Two modes:
22
22
  --mode two-servers vLLM, SGLang or another OpenAI-compatible stack:
23
23
  --base-url serves with prefix caching on, and
24
24
  --nocache-url serves the same model with it off
25
- (tested against a simulated server only)
25
+ (tested on real vLLM 0.33.0 and SGLang 0.5.23
26
+ servers; results in the README)
26
27
 
27
28
  Standard library only. Python 3.8 or newer.
28
29
 
@@ -30,7 +31,7 @@ Usage (from PyPI: pip install llm-cachecheck, then run llm-cachecheck
30
31
  in place of python cachecheck.py):
31
32
  python cachecheck.py --base-url http://127.0.0.1:8080
32
33
  python cachecheck.py --mode two-servers --base-url http://127.0.0.1:8000 \
33
- --nocache-url http://127.0.0.1:8001 --model Qwen/Qwen2.5-7B-Instruct
34
+ --nocache-url http://127.0.0.1:8100 --model Qwen/Qwen2.5-3B-Instruct
34
35
 
35
36
  Exit status: 0 no difference and at least 80% of probes valid, 1 at
36
37
  least one valid probe differs, 2 inconclusive.
@@ -41,10 +42,11 @@ import binascii
41
42
  import json
42
43
  import os
43
44
  import sys
45
+ import time
44
46
  import urllib.error
45
47
  import urllib.request
46
48
 
47
- __version__ = "0.2.1"
49
+ __version__ = "0.2.3"
48
50
 
49
51
  CITATION = (
50
52
  "Patodiya, A. Same Request, Different Answer: Quantization Amplifies "
@@ -54,6 +56,9 @@ CITATION = (
54
56
 
55
57
  MIN_VALID_SHARE = 0.8
56
58
 
59
+ SHARE_URL = ("https://github.com/aditi-p31/cache-divergence-study/issues/new"
60
+ "?template=cachecheck-result.yml")
61
+
57
62
  # Two-turn probes. Turn 1 asks for a worked answer of a few sentences, so
58
63
  # the server writes a useful amount of KV state while generating it.
59
64
  # Turn 2 builds on that answer, so it is processed on top of that state.
@@ -305,6 +310,29 @@ def server_props(args):
305
310
  "model_file": os.path.basename(props.get("model_path") or "")}
306
311
 
307
312
 
313
+ def result_block(args, props, summary, when):
314
+ """A short, copyable summary of the run. It leaves out the server URL
315
+ and any key, so it is safe to paste in public."""
316
+ build = props.get("build_info") or "(fill in engine and version)"
317
+ model = args.model or props.get("model_file") or "(fill in model)"
318
+ lines = [
319
+ "---- llm-cachecheck result ----",
320
+ "tool: llm-cachecheck %s" % __version__,
321
+ "date (UTC): %s" % when,
322
+ "mode: %s" % args.mode,
323
+ "engine build: %s" % build,
324
+ "model: %s" % model,
325
+ "GPU or CPU: (fill in)",
326
+ "probes: %d planned, %d valid, %d differed" % (
327
+ summary["probes_planned"], summary["probes_valid"],
328
+ summary["probes_diverged"]),
329
+ "max tokens: %d, seed: %d, hit check: %s" % (
330
+ args.max_tokens, args.seed, summary["hit_check"]),
331
+ "-------------------------------",
332
+ ]
333
+ return "\n".join(lines)
334
+
335
+
308
336
  def status_line(r):
309
337
  if not r["valid"]:
310
338
  return "inconclusive (%s)" % "; ".join(r["problems"])
@@ -324,8 +352,8 @@ def main(argv=None):
324
352
  default="llamacpp",
325
353
  help="llamacpp (default): one llama.cpp server. "
326
354
  "two-servers: vLLM, SGLang or another OpenAI-"
327
- "compatible stack; tested against a simulated "
328
- "server only, not yet against a real one")
355
+ "compatible stack, with a second server that has "
356
+ "prefix caching off")
329
357
  ap.add_argument("--nocache-url",
330
358
  help="two-servers mode: same model, prefix caching off")
331
359
  ap.add_argument("--model", default=None,
@@ -414,6 +442,10 @@ def main(argv=None):
414
442
  if args.skip_hit_check:
415
443
  print("Cache hits were assumed, not confirmed (--skip-hit-check).")
416
444
  print("Report written to %s" % args.out)
445
+ print()
446
+ print(result_block(args, props, summary,
447
+ time.strftime("%Y-%m-%d %H:%M", time.gmtime())))
448
+ print("To share this result (optional), open: " + SHARE_URL)
417
449
  print("Method: " + CITATION)
418
450
 
419
451
  if diverged:
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "llm-cachecheck"
7
7
  dynamic = ["version"]
8
- description = "Measure how often the prompt cache changes greedy answers on your LLM server (llama.cpp, plus an experimental two-server mode for vLLM and SGLang)"
8
+ description = "Measure how often the prompt cache changes greedy answers on your LLM server (llama.cpp, vLLM and SGLang)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
11
11
  license = "MIT"
@@ -162,6 +162,16 @@ class CacheCheckTests(unittest.TestCase):
162
162
  self.assertIn("DIFFERENT (from character", out)
163
163
  self.assertIn("3 of 3 valid probes gave a different", out)
164
164
 
165
+ def test_result_block_is_printed_and_safe_to_share(self):
166
+ server = self.server(diverge=True)
167
+ code, report, out = self.run_tool(server)
168
+ self.assertIn("---- llm-cachecheck result ----", out)
169
+ self.assertIn("engine build: b-fake", out)
170
+ self.assertIn("probes: 3 planned, 3 valid, 3 differed", out)
171
+ self.assertIn(cachecheck.SHARE_URL, out)
172
+ block = out.split("---- llm-cachecheck result ----")[1]
173
+ self.assertNotIn(server.url, block)
174
+
165
175
  def test_divergence_in_reasoning_only(self):
166
176
  code, report, out = self.run_tool(self.server(diverge_reasoning=True))
167
177
  self.assertEqual(code, 1)
File without changes