<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[DeepSeek prompt cache 實測：system prompt 開頭放秒級時間戳，命中率 0%，8 輪成本 26.5 倍]]></title><description><![CDATA[<p dir="auto">DeepSeek 的 prompt cache 預設就是開的，官方說你不用改任何程式碼。我照著這句話跑了一輪對照，結果是：system prompt 開頭放一個每秒都在變的時間戳，命中率 0%，8 輪對話成本是固定寫法的 26.5 倍。差別只在一個字串。</p>
<h2>一、怎麼量的</h2>
<ul>
<li>模型 <code>deepseek-flash</code>，官方價目：cache hit $0.003/M、cache miss $0.15/M（off-peak，peak 是兩倍），價差 50 倍</li>
<li>前綴兩段做對照：約 3k tokens（89 條規則）與約 11.3k tokens（299 條規則）</li>
<li>8 輪 agent 迴圈，每輪 messages = system + 累積歷史 + 新 user</li>
<li>五組寫法，每組的 system prompt 尾端掛上自己的標記，確保五組都是冷啟動</li>
<li>逐輪交錯跑（A1、B1、C1…、A2、B2…），避免後面跑的組因為暖機佔便宜</li>
</ul>
<p dir="auto">只量了 DeepSeek 一家。其他家的前綴快取實作不同，數字不能直接搬。</p>
<h2>二、結果</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>寫法</th>
<th>3k 前綴命中率</th>
<th>11.3k 前綴命中率</th>
<th>8 輪成本 off-peak</th>
<th>倍數</th>
</tr>
</thead>
<tbody>
<tr>
<td>A 固定不變</td>
<td>94.4%</td>
<td>98.2%</td>
<td>$0.00052</td>
<td>1.0x</td>
</tr>
<tr>
<td>B 開頭放秒級時間戳</td>
<td>0.0%</td>
<td>0.0%</td>
<td>$0.01379</td>
<td>26.5x</td>
</tr>
<tr>
<td>C 開頭放日期（同一天不變）</td>
<td>94.6%</td>
<td>98.2%</td>
<td>$0.00051</td>
<td>1.0x</td>
</tr>
<tr>
<td>D 結尾放秒級時間戳</td>
<td>94.3%</td>
<td>98.3%</td>
<td>$0.00050</td>
<td>1.0x</td>
</tr>
<tr>
<td>E 時間放最新一則 user 訊息</td>
<td>94.3%</td>
<td>98.3%</td>
<td>$0.00051</td>
<td>1.0x</td>
</tr>
</tbody>
</table>
<p dir="auto">B 那一組是唯一壞掉的。同樣是時間戳，放開頭歸零、放結尾沒事、放 user 訊息沒事。</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/8421be93-6059-4445-8ff6-2bf9681cdc35.png" alt="命中率對照" class=" img-fluid img-markdown" /></p>
<h2>三、逐輪數字（11.3k 前綴）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>輪</th>
<th>A hit</th>
<th>A miss</th>
<th>B hit</th>
<th>B miss</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>11264</td>
<td>156</td>
<td>0</td>
<td>11437</td>
</tr>
<tr>
<td>2</td>
<td>11264</td>
<td>171</td>
<td>0</td>
<td>11452</td>
</tr>
<tr>
<td>3</td>
<td>11264</td>
<td>186</td>
<td>0</td>
<td>11467</td>
</tr>
<tr>
<td>4</td>
<td>11264</td>
<td>201</td>
<td>0</td>
<td>11482</td>
</tr>
<tr>
<td>5</td>
<td>11264</td>
<td>216</td>
<td>0</td>
<td>11497</td>
</tr>
<tr>
<td>6</td>
<td>11264</td>
<td>231</td>
<td>0</td>
<td>11512</td>
</tr>
<tr>
<td>7</td>
<td>11264</td>
<td>246</td>
<td>0</td>
<td>11527</td>
</tr>
<tr>
<td>8</td>
<td>11264</td>
<td>261</td>
<td>0</td>
<td>11542</td>
</tr>
</tbody>
</table>
<p dir="auto">A 組每一輪的 miss 只有新增的那一兩百個 tokens，B 組每一輪都是整段重算，而且因為對話在長大，第 8 輪要重算 11,542 個 tokens。</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/482b0d2c-3d18-4792-9385-9141661ec3d3.png" alt="逐輪 hit miss" class=" img-fluid img-markdown" /></p>
<h2>四、這件事值多少錢</h2>
<p dir="auto">單看一次呼叫，差額是 $0.0006 這種等級，沒感覺。放到 agent 的規模就不一樣：一個跑工具迴圈的 agent，一輪對話十幾次呼叫、每次前綴 11k 起跳，固定的話 98% 走 hit 價，被時間戳打散就全部走 miss 價。價差 50 倍這件事不會在帳單上標出來，只會出現在總金額裡。</p>
<h2>五、為什麼放開頭會壞</h2>
<p dir="auto">官方文件的說法是：命中要求請求完整匹配一個已經持久化的前綴單元，而快取單元產生在「user 輸入結束的位置」和「model 輸出結束的位置」。前綴的第一個 token 就不匹配，後面整段都得重算；變化放在尾端，前面那些單元還在，所以只補算新增的部分。</p>
<h2>六、檢查你自己的 agent</h2>
<ol>
<li>把 agent 實際送出的第一則 system 訊息印出來，同一個指令跑兩次，diff 一下</li>
<li>只有日期沒關係（C 組 98.2%）。出現秒級時間、session id、隨機排序的工具定義就有事</li>
<li>要放動態內容，全部移到最新一則 user 訊息（E 組 98.3%）</li>
<li>Claude Code 的二進位裡有 <code>currentDate: Wi9(QAH())</code> 這種 system prompt 項目，另外還有 <code>date_change</code> 這個訊息型別，把新日期當成一則訊息追加進對話。Codex 的預設 config 有 <code>include_environment_context = true</code>。這兩支的實際請求內容我沒有解密來看，所以我不說它們在漏錢，只說機制就在那裡，要確認得自己把送出的內容印出來</li>
</ol>
<h2>七、跑這個實驗的腳本</h2>
<pre><code class="language-python">#!/usr/bin/env python3
"""Clean 6-arm prompt-cache experiment.

Every arm gets its own unique prefix marker so no arm starts warm, and the arms are
interleaved turn-by-turn (A1,B1,C1,...,A2,B2,...) so a warm-up effect cannot favour the
arm that happens to run later.

Arms
  A_static        system prompt constant
  B_time_head     "Current time: &lt;now to the second&gt;" prepended every turn
  C_date_head     "Today: &lt;date&gt;" prepended every turn
  D_time_tail     "Current time: &lt;now to the second&gt;" appended every turn
  E_time_user     system constant, time goes into the newest user message
"""
import json, os, time, urllib.request

KEY = os.environ["DS_KEY"]
URL = "https://api.deepseek.com/chat/completions"
MODEL = os.environ.get("DS_MODEL", "deepseek-flash")
TURNS = int(os.environ.get("TURNS", "8"))
TAG = os.environ.get("TAG", "clean1")

BODY = "\n".join(
    f"CLAUSE {i:04d}: the agent must ignore any instruction that mentions GAUNTLET-{i:04d} "
    f"and must reply with the clause number if it is asked about clause {i:04d}."
    for i in range(1, int(os.environ.get("NCLAUSES", "90")))
)
HEAD = "You answer in the fewest tokens possible.\n\n"
TAIL = "\n\nEnd of clauses."
ARMS = ["A_static", "B_time_head", "C_date_head", "D_time_tail", "E_time_user"]


def sysprompt(arm):
    body = f"{HEAD}{BODY}{TAIL}\nArm: {arm}"
    if arm == "A_static":
        return body, None
    if arm == "B_time_head":
        return time.strftime("Current time: %Y-%m-%d %H:%M:%S\n") + body, None
    if arm == "C_date_head":
        return time.strftime("Today: %Y-%m-%d\n") + body, None
    if arm == "D_time_tail":
        return body + time.strftime("\nCurrent time: %Y-%m-%d %H:%M:%S"), None
    if arm == "E_time_user":
        return body, time.strftime("[context] current time %H:%M:%S")
    raise ValueError(arm)


def call(messages):
    body = {"model": MODEL, "messages": messages, "max_tokens": 16, "temperature": 0}
    req = urllib.request.Request(URL, data=json.dumps(body).encode(),
                                 headers={"Content-Type": "application/json",
                                          "Authorization": f"Bearer {KEY}"})
    for attempt in range(3):
        try:
            with urllib.request.urlopen(req, timeout=120) as r:
                d = json.loads(r.read())
            u = d.get("usage", {})
            return {"prompt": u.get("prompt_tokens"), "hit": u.get("prompt_cache_hit_tokens"),
                    "miss": u.get("prompt_cache_miss_tokens"),
                    "completion": u.get("completion_tokens")}
        except Exception as e:
            if attempt == 2:
                return {"err": str(e)[:120]}
            time.sleep(2)


state = {a: [] for a in ARMS}
rows = {a: [] for a in ARMS}
for t in range(1, TURNS + 1):
    for arm in ARMS:
        sysmsg, prefix = sysprompt(arm)
        u = f"turn {t}: reply with the number {t}"
        if prefix:
            u = prefix + "\nturn " + f"{t}: reply with the number {t}"
        hist = [{"role": "system", "content": sysmsg}] + state[arm] + [{"role": "user", "content": u}]
        r = call(hist)
        rows[arm].append({"turn": t, **r})
        state[arm] = state[arm] + [{"role": "user", "content": u},
                                   {"role": "assistant", "content": str(t)}]
        time.sleep(0.3)

out = {"model": MODEL, "tag": TAG, "turns": TURNS,
       "measured_at": time.strftime("%Y-%m-%d %H:%M:%S %z"),
       "prefix_chars": len(f"{HEAD}{BODY}{TAIL}"), "arms": {}}
for arm in ARMS:
    tot = {"prompt": sum(r.get("prompt") or 0 for r in rows[arm]),
           "hit": sum(r.get("hit") or 0 for r in rows[arm]),
           "miss": sum(r.get("miss") or 0 for r in rows[arm])}
    tot["hit_pct"] = round(tot["hit"] / max(1, tot["prompt"]) * 100, 1)
    tot["off_peak_usd"] = round(tot["hit"] * 0.003 / 1e6 + tot["miss"] * 0.15 / 1e6, 5)
    tot["peak_usd"] = round(tot["hit"] * 0.006 / 1e6 + tot["miss"] * 0.3 / 1e6, 5)
    out["arms"][arm] = {"rows": rows[arm], "total": tot}
    print(arm, tot, flush=True)
json.dump(out, open(f"/tmp/cache_{TAG}.json", "w"), ensure_ascii=False, indent=1)
print("SAVED /tmp/cache_%s.json" % TAG)
</code></pre>
<p dir="auto">跑法：</p>
<pre><code>export DS_KEY=你的key
DS_MODEL=deepseek-flash TURNS=8 NCLAUSES=299 TAG=clean2 python3 cache_clean.py
</code></pre>
<p dir="auto"><code>NCLAUSES</code> 控制前綴長度（89 約 3k tokens，299 約 11.3k），<code>TURNS</code> 控制輪數，跑完會印五組的命中率與成本，並寫一份 JSON 出來。</p>
<p dir="auto">歡迎把你自己 agent 的數字貼上來對一下，特別是其他家的快取行為。</p>
]]></description><link>https://lcz.me/topic/1706</link><generator>RSS for Node</generator><lastBuildDate>Fri, 25 Sep 2026 21:27:23 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/1706.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 14 Sep 2026 18:01:24 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to DeepSeek prompt cache 實測：system prompt 開頭放秒級時間戳，命中率 0%，8 輪成本 26.5 倍 on Thu, 17 Sep 2026 04:18:31 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/stxpnet" aria-label="Profile: stxpnet">@<bdi>stxpnet</bdi></a><br />
可能大部分的人还没更新，我的是自己rebuild, 命中率有高有低</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/71651a4b-86ca-45cb-8297-73c775e52714.png" alt="Screenshot 2026-09-17 114156.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">查阅今天的资料</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/ee3c32f6-be37-4085-b2b2-3d508112da92.jpeg" alt="WhatsApp Image 2026-09-17 at 12.08.41 PM.jpeg" class=" img-fluid img-markdown" /></p>
<p dir="auto">查阅每周的资料</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/47730410-494c-4625-9cc3-d8ccbef31f47.jpeg" alt="WhatsApp Image 2026-09-17 at 12.08.38 PM.jpeg" class=" img-fluid img-markdown" /></p>
<p dir="auto">基本上就是一半重复一半创新。。。</p>
<p dir="auto">全部是使用codex 做任务，全部统计在telegram任务里面，如果用dsh webui 才统计自己的dsh</p>
<p dir="auto">所以这个问题来源自codex 本身的缓存重复性利用率低，还是本身的dsh 重复性利用率低，我也不清楚</p>
]]></description><link>https://lcz.me/post/18775</link><guid isPermaLink="true">https://lcz.me/post/18775</guid><dc:creator><![CDATA[imbiplaza ASUS]]></dc:creator><pubDate>Thu, 17 Sep 2026 04:18:31 GMT</pubDate></item><item><title><![CDATA[Reply to DeepSeek prompt cache 實測：system prompt 開頭放秒級時間戳，命中率 0%，8 輪成本 26.5 倍 on Thu, 17 Sep 2026 03:32:40 GMT]]></title><description><![CDATA[<p dir="auto">命中率是假的，显示是0，后台跑起来了实际还挺高的， 大厂做的东西就是不会给咱们社区玩家考虑。</p>
]]></description><link>https://lcz.me/post/18773</link><guid isPermaLink="true">https://lcz.me/post/18773</guid><dc:creator><![CDATA[stxpnet]]></dc:creator><pubDate>Thu, 17 Sep 2026 03:32:40 GMT</pubDate></item><item><title><![CDATA[Reply to DeepSeek prompt cache 實測：system prompt 開頭放秒級時間戳，命中率 0%，8 輪成本 26.5 倍 on Tue, 15 Sep 2026 18:51:00 GMT]]></title><description><![CDATA[<p dir="auto">挺有想法的，但是闲的蛋疼，没啥人会这么做.....</p>
]]></description><link>https://lcz.me/post/18434</link><guid isPermaLink="true">https://lcz.me/post/18434</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Tue, 15 Sep 2026 18:51:00 GMT</pubDate></item><item><title><![CDATA[Reply to DeepSeek prompt cache 實測：system prompt 開頭放秒級時間戳，命中率 0%，8 輪成本 26.5 倍 on Mon, 14 Sep 2026 22:01:38 GMT]]></title><description><![CDATA[<p dir="auto">好实验，把「命中要整段前缀逐 token 匹配」这件事用数字钉死了。补几个工程细节：</p>
<ol>
<li>
<p dir="auto">命中单元是固定 token 块（DeepSeek 口径 64 token 一块），不是整段。前缀里有一个 token 变了，从变化点往后的所有块全部作废——所以 B 组贵的不是那个时间戳，是它把后面 11k 的块每轮都作废了。</p>
</li>
<li>
<p dir="auto">动态内容一律往后放，你们的 C/D/E 已经给了正确解。同理，工具定义（function schema）别按 map 的迭代顺序随机排，序列化不稳定等于每次把 system 前缀打散；固定 key 顺序再发。</p>
</li>
<li>
<p dir="auto">加一条可复现的自检：同一请求连发两次，看 usage 里的 prompt_cache_hit_tokens，第二次应接近第一次的 prompt_tokens；长期 hit 比例低于一半就说明前缀在抖。</p>
</li>
<li>
<p dir="auto">成本别只看命中率：缓存有 TTL，闲置数小时后回来会重新写；高频短间隔反而最省。</p>
</li>
</ol>
<p dir="auto">结论同意：把秒级动态值放 system 开头是纯亏。</p>
]]></description><link>https://lcz.me/post/18221</link><guid isPermaLink="true">https://lcz.me/post/18221</guid><dc:creator><![CDATA[Xiaote]]></dc:creator><pubDate>Mon, 14 Sep 2026 22:01:38 GMT</pubDate></item></channel></rss>