Building a Knowledge Base from Scratch, EP07. The paradigm arc continues, and the bill from EP06 finally gets audited.
Where EP06 left off
I ended EP06 with a confession. The "compile once, break even after about 6 questions" math only works if the cache keeps hitting. When it doesn't, the compiled side costs 44% more per question than retrieval. And I had no idea when the cache expired. That's entirely up to the server.
There was a loose thread too. Bailian offers an explicit cache. You mark the knowledge-base prefix yourself, pay ¥15 per million tokens to create it, ¥1 on a hit. On paper that hit price beats the implicit one, ¥1.5. But the rules are completely different, and I wanted to know how.
So this episode runs both caches against each other. Same assets as EP06: the compiled artifact (a 7,929-token prompt prefix), qwen3.8-max, the same system message, the same four questions. Eleven paid calls, ¥0.93 total.
The headline finding first: the explicit cache doesn't hit the way I assumed. It doesn't match on prefix. That changes the final answer.
The price table, including a TTL hiding in a type name
bl model list --model qwen3.8-max needs no authentication. Prices pulled on the spot:
| Tier | Price | Relative to input |
|---|---|---|
| Input | ¥12 / M | 100% |
| Output | ¥36 / M | n/a |
| Implicit hit | ¥1.5 / M | 12.5% |
| Explicit creation | ¥15 / M | 125% |
| Explicit hit | ¥1 / M | 8.33% |
One detail deserves its own paragraph. The billing type name for explicit creation is input_token_cache_creation_5m. The 5-minute TTL is right there in the field name. Didn't have to guess from documentation; the price list confessed on its own.
That 5 minutes comes back repeatedly. It's one of the explicit cache's structural weaknesses.
Was last episode's cache still alive
The first test group answers EP06's open question: how long does the implicit cache actually live?
Method: rerun the exact message assembly from EP06. Same artifact as the user message, question appended, four different questions, controlled intervals.
| Call | Time | Since last hit | Hit tokens | Cost |
|---|---|---|---|---|
| A1 | 13:25:39 | two days | 0 | ¥0.1075 |
| A2 | 13:25:59 | 20 seconds | 7,168 | ¥0.0345 |
| A3 | 13:35:31 | 9m 32s | 7,168 | ¥0.0285 |
| A4 | 13:49:30 | 13m 59s | 7,168 | ¥0.0419 |
Three findings.
After two days, the cache was gone. A1's 7,929 input tokens billed at full price. EP06's warning about low-frequency usage getting a cold start every time now has its own data.
Twenty seconds apart, it hit, and the hit count, 7,168, matches EP06's five calls digit for digit. The two episodes' data line up.
A3 and A4 were the surprise. A hit 9.5 minutes later, another 14 minutes after that. By A4, the cache had survived 23.5 minutes since first being hit. The implicit cache lives at least 14 minutes, dies within two days, and the exact boundary in between is opaque. Far longer than my intuition. I'd assumed an automatic cache would last minutes at best.
The CLI has no cache command, but it has one pathway
I grepped bailian-cli's entire reference documentation for "cache" and "缓存". Zero hits. No dedicated cache command.
But the official API's explicit cache works through structure markers inside the messages array, and bl text chat has a --messages-file flag that forwards whatever structure you give it. The pathway already exists. Pass it through.
The implicit group is the old shape, user as a single string:
[
{"role": "system", "content": "You are the customer service assistant for Nuannu Home Furnishing."},
{"role": "user", "content": "(full compiled artifact)\n\n---\nThe above is the company knowledge base. User question: How do I submit reimbursement invoices?"}
]
The explicit group splits user into an array and hangs cache_control on the knowledge-base block:
[
{"role": "system", "content": "You are the customer service assistant for Nuannu Home Furnishing."},
{"role": "user", "content": [
{"type": "text", "text": "(full compiled artifact)\n\n---\nThe above is the company knowledge base.",
"cache_control": {"type": "ephemeral"}},
{"type": "text", "text": "User question: How do I submit reimbursement invoices?"}
]}
]
Both expand to identical text, same model, same parameters. The only difference is the marker. Single variable.
Whether the pass-through worked can't be left to vibes. I fixed the criterion in advance: the explicit group's usage must contain fields the implicit group never showed. A change in cached_tokens alone doesn't count; that could just be an implicit hit.
B0, the explicit group's first call, returned:
"prompt_tokens_details": {
"cache_creation": {"ephemeral_5m_input_tokens": 7923},
"cache_creation_input_tokens": 7923,
"cache_type": "ephemeral",
"cached_tokens": 0
}
Three new fields, all present. ephemeral_5m_input_tokens even matches the billing type name from the price list. Pass-through confirmed: 7,923 tokens went through explicit creation. The answer itself was normal, 291 characters, correctly based on the 2026 reimbursement policy.
And a bonus observation running the other direction: B0 came 31 seconds after A4, which had just hit the implicit cache for 7,168. Yet B0's cached_tokens was 0. Hang the marker, and you're no longer an implicit player.
Change the question, pay for creation again
Next came what I expected to be the main event: B0 creates, B1 asks a different question immediately after, hits the knowledge prefix, pays the ¥1 hit price.
That's not what happened.
| Call | Question | Interval | Created | Hit | Cost |
|---|---|---|---|---|---|
| B0 | q1 reimbursement | n/a | 7,923 | 0 | ¥0.1305 |
| B1 | q2 free shipping | 12 seconds | 7,929 | 0 | ¥0.1365 |
| B2 | q4 Xinjiang sofa | 15 seconds | 7,936 | 0 | ¥0.1418 |
B1 came 12 seconds after B0, sharing a 7,900-token common prefix. No hit. Full-price creation all over again.
If the explicit cache matched on prefix, B1 would have hit the knowledge block B0 created. It didn't. For "one fixed knowledge prefix plus ever-changing questions," the most standard shape of knowledge-base Q&A, the explicit cache pays the 125% creation price every single time.
How hits are actually judged: a nine-second controlled experiment
Three steps, each 9 seconds apart.
B3: byte-identical messages to B0, sent 8 minutes later. B0's cache was created at 13:50:01. The official TTL is 5 minutes. B3 went out at 13:58:14, 8m 13s after creation. Result: re-created 7,923, no hit. The 5-minute TTL is real. When it expires, it's gone, and the 125% creation premium evaporates with it.
B4: byte-identical to B3 (same question), sent 9 seconds later. Hit. 7,923 tokens, zero creation, ¥0.0202 total. The cheapest single call of the entire episode, 29% below even the implicit group's best.
B5: differs from B4 only in the question text, sent 9 seconds later. No hit. Re-created 7,926.
Five data points, all pointing one way:
Bailian's explicit cache judges hits by "entire request identical," not "common prefix." The whole messages array must match byte for byte. Differ by one question and you miss.
This is a different semantic from Anthropic's prefix caching, where everything before the marker counts as long as the prefix matches. The standard pattern there is exactly "fixed knowledge base, varying questions." Port that intuition over and every question pays 125%, six times the implicit steady state.
The explicit cache's niche narrows to one thing: repeating an identical request. Multiple agents running the same prompt in parallel, batch retries, evaluation-set reruns. Outside those, it can't help.
Two channels, two separate ledgers
The experiment matrix planted a cross-check: after explicit caches had been created, send an unmarked request in the implicit style and see whether the two channels connect.
D1 ran 9 seconds after B0 and B1, two explicit creations. Implicit assembly, question q3. It hit, for 7,168, the implicit count, not the 7,923 that had just been explicitly created.
That number is itself the evidence. If the channels shared cache, D1 would have picked up the 7,923 entry, which covers more of the prompt. What it actually got was the implicit ledger's 1,024-aligned 7,168.
Add B0's finding that marked requests can't ride the implicit cache, and all four directions are tested: explicit doesn't eat implicit, implicit doesn't eat explicit, explicit creation doesn't break the implicit chain, and the two channels keep entirely separate books.
Practical corollary: running explicit-cache experiments leaves the implicit cache untouched. The two workloads can coexist without interfering.
The quirk in implicit hits: 1,024-token alignment
One more pattern in the A-group data, easy to miss at first.
A2, A3, A4 and D1 all hit for exactly 7,168. Their prompt totals ranged from 7,929 to 7,942 depending on question length. The hit count never moved.
7,168 = 7 × 1,024. The implicit cache stores in 1,024-token blocks, and the tail of the common prefix that doesn't fill a block never enters the cache. Every call leaves about 767 tokens billed at full price, forever ineligible for the discount.
Priced out properly, the implicit discount isn't as deep as advertised. The effective input rate is ¥2.515 per million, 21% of list, not the headline 12.5%. That percentage only holds for the tokens that actually make it into cache.
The explicit cache has no such truncation. Its created and hit counts are 7,923, covering 99.9% of the prompt. Explicit hits are not only cheaper per token (¥1 vs ¥1.5), they cover more of the prompt. A genuine hidden advantage, locked away behind "change the question and you miss."
The cost account: when does explicit pay off
Four steady states side by side, effective input rates:
| Steady state | Effective input price | Relative | Source |
|---|---|---|---|
| Full-price cold start | ¥12.00 / M | 100% | A1 |
| Implicit steady state | ¥2.515 / M | 21.0% | A2 |
| Explicit creation | ¥15.00 / M | 125% | B0-B5 |
| Explicit hit | ¥1.008 / M | 8.4% | B4 |
First, the standard shape of knowledge-base Q&A: one prefix, five different questions in a row. Implicit total ¥0.1750, explicit total ¥0.5946. That's 3.4×, and per-question steady state is worse: 0.1189 ÷ 0.0200 = 5.96×. In this scenario explicit is pure downside.
Now explicit's sweet spot: the same messages resent verbatim, within 5 minutes.
| Repeats | Implicit total | Explicit total | Gap |
|---|---|---|---|
| 3 | ¥0.1349 | ¥0.1349 | break even |
| 5 | ¥0.1747 | ¥0.1509 | explicit saves 13.6% |
| 10 | ¥0.2741 | ¥0.1909 | explicit saves 30.4% |
Ask the identical question 3 times within 5 minutes and explicit starts winning; the more repeats, the more it saves, up to 60% at the limit. Change the question even once and it snaps back to 6× more expensive per call. And the TTL doesn't forgive: if no hit comes within 5 minutes, the 125% creation premium evaporates entirely.
Wrapping up: how to place this compiled artifact
Eleven calls done, and EP06's question gets a straight answer.
| Your workload | How to place it |
|---|---|
| Customer-service Q&A: fixed prefix, ever-changing questions | Implicit. Configure nothing. |
| Identical-request reruns: eval sets, batch retries, parallel agents on one prompt | Explicit marker, breaks even at call 3 |
| Low-frequency, a few queries a day | Neither cache saves you; consider going back to retrieval |
| Getting more implicit hits | Control the cadence: follow-ups within 14 minutes land |
My own artifact lands in row one: configure nothing, rely on implicit. Customer-service questions always vary; the explicit 125% premium can't be dodged there. The one thing worth doing is pacing: keep questions inside the expiry boundary so that 7,168-token prefix stays warm.
A note for later: when batch evaluations or multi-agent runs show up, come back and hang the marker. That's the one arena where explicit wins.
What's next
One problem in the paradigms arc is still untouched. Everything through EP06 shared a default: everyone can read the whole library. Real companies don't work that way. Reimbursement policies are for finance and travelers; customer data belongs to the service team only. Compilation kneads the whole library into one artifact, and permissions are the first gate it has to survive. Next episode: cut the same library into two permission views and see what compiled artifacts, retrieval-side metadata filtering, and agent prompts can each defend.
Everything here was measured with Model Studio's CLI (bl). Full usage figures, reasoning traces and compiled artifacts from all 11 calls are archived in the project repo. Command signatures may shift between versions, so check the official docs. API keys are free to obtain, with a free tier for new accounts.




Top comments (0)