<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kyle Ma</title>
    <description>The latest articles on DEV Community by Kyle Ma (@pomereneio).</description>
    <link>https://dev.to/pomereneio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4201490%2F67edee1a-c055-40fd-af43-c4801d9848e7.png</url>
      <title>DEV Community: Kyle Ma</title>
      <link>https://dev.to/pomereneio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pomereneio"/>
    <language>en</language>
    <item>
      <title>How much of your agent traffic actually repeats? Measure before you cache</title>
      <dc:creator>Kyle Ma</dc:creator>
      <pubDate>Sun, 25 Oct 2026 02:36:07 +0000</pubDate>
      <link>https://dev.to/pomereneio/how-much-of-your-agent-traffic-actually-repeats-measure-before-you-cache-2anp</link>
      <guid>https://dev.to/pomereneio/how-much-of-your-agent-traffic-actually-repeats-measure-before-you-cache-2anp</guid>
      <description>&lt;h1&gt;
  
  
  How much of your agent traffic actually repeats? Measure before you cache
&lt;/h1&gt;

&lt;p&gt;Trajectory caching only pays when your agent keeps solving the same problems. So before adopting it — ours or anyone's — measure whether your traffic actually repeats. This post is the checklist we'd want an engineer to run first, including the cases where the honest answer is "don't bother."&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the uncomfortable case
&lt;/h2&gt;

&lt;p&gt;Pomerene saves little when every task is unique. If your agents do one-off bug fixing, where each ticket is a novel investigation, or bespoke per-customer work that never recurs in recognizable form, there is nothing stable to replay. A cache over unique traffic is a lookup table that always misses: you've added infrastructure, storage, and a matching step to every request in exchange for a hit rate near zero. We'd rather say that plainly than sell you a kit that can't help.&lt;/p&gt;

&lt;p&gt;The workloads where trajectory caching earns its keep are the opposite shape: support agents fielding the same intents, booking flows, FAQ agents, scheduled jobs — anywhere the &lt;em&gt;goal&lt;/em&gt; recurs even when the wording doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to measure
&lt;/h2&gt;

&lt;p&gt;You don't need new tooling to get a first read. Your existing traces and logs are enough for four numbers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Goal repeat rate.&lt;/strong&gt; Group completed runs by the goal they were trying to achieve — not the literal prompt, the intent. What fraction of this week's runs had a goal that also appeared last week? This is your ceiling. No cache can hit more often than your goals repeat, and if the repeat rate is under roughly a fifth of traffic, the economics get thin fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Paraphrase clustering.&lt;/strong&gt; Raw string deduplication will lie to you. "Where's my refund?" and "I need an update on the money you owe me" are the same goal with zero tokens in common. Cluster requests by embedding similarity and look at cluster sizes: a long tail of singletons means unique work; a few fat clusters mean a small set of goals dominates your traffic, which is exactly the shape a trajectory cache exploits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cost per run.&lt;/strong&gt; Sum tokens across &lt;em&gt;all&lt;/em&gt; steps of a run, not just the final call — agent costs hide in the intermediate tool-use and reasoning steps. Multiply by your repeat rate and you have an upper bound on savings, in dollars, before you build anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Latency distribution.&lt;/strong&gt; Record end-to-end run latency, p50 and p95. Long multi-step runs are where replay helps most: a fully replayed trajectory skips the entire step sequence, so the longer and more repetitive your runs, the bigger the latency win per hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Pomerene reports once it's running
&lt;/h2&gt;

&lt;p&gt;If you do deploy it, Pomerene ships diagnostics views so you can verify the cache is doing what the back-of-envelope math promised:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hit rates per tenant and global&lt;/strong&gt; — whether the repeat rate you measured in traces shows up as actual hits, and whether one tenant's traffic behaves differently from another's.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L1 / L2 / miss breakdown&lt;/strong&gt; — full replays, partial replays (where your agent resumed at the step the cached plan stopped matching), and clean misses. A healthy deployment isn't all L1; a meaningful L2 share means the cache is absorbing the common prefix of your work even when goals partially diverge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency percentiles&lt;/strong&gt; on the hit path versus live runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dollars and tokens saved&lt;/strong&gt;, with accounting that matches how replay actually works: an L1 hit counts &lt;em&gt;all&lt;/em&gt; of the trajectory's tokens (the whole run was skipped), while an L2 hit counts only the replayed fraction. No double-counting the steps your agent still executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quality is monitored, not assumed. A &lt;code&gt;/v1/feedback&lt;/code&gt; loop lets outcomes feed back into the cache: entries whose replay quality drops get evicted rather than served forever on the strength of one good run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest limits
&lt;/h2&gt;

&lt;p&gt;Two constraints worth knowing before you design around it. Pomerene currently runs as a &lt;strong&gt;single-writer instance&lt;/strong&gt; with an &lt;strong&gt;in-memory vector index&lt;/strong&gt; — simple and fast, but it's one process owning the cache, not a distributed store. And because stored trajectories are indexed by embedding, &lt;strong&gt;changing the embedding model invalidates stored vectors&lt;/strong&gt;: swap models and the index has to be rebuilt rather than migrated in place. Neither is hidden in fine print; both should factor into whether this fits your deployment today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision rule
&lt;/h2&gt;

&lt;p&gt;Measure goal repeat rate and paraphrase clustering first. If a third or more of your traffic is goals you've already solved, trajectory caching will very likely pay for itself in tokens and latency — and you'll be able to prove it from the diagnostics within a week. If your traffic is genuinely one-of-a-kind work, skip the cache and spend the effort elsewhere. Either way, you'll have made the call from your own numbers instead of a vendor's benchmark.&lt;/p&gt;




&lt;p&gt;Pomerene's self-hosted Starter Kit — Indie $99 / Pro $249, one-time, source included — comes with the diagnostics views described above, so the measurement doesn't stop at adoption. See &lt;a href="https://pomerene.io/starter-kit" rel="noopener noreferrer"&gt;pomerene.io/starter-kit&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Your semantic cache will happily replay the wrong command</title>
      <dc:creator>Kyle Ma</dc:creator>
      <pubDate>Fri, 23 Oct 2026 22:50:48 +0000</pubDate>
      <link>https://dev.to/pomereneio/your-semantic-cache-will-happily-replay-the-wrong-command-4pg5</link>
      <guid>https://dev.to/pomereneio/your-semantic-cache-will-happily-replay-the-wrong-command-4pg5</guid>
      <description>&lt;h1&gt;
  
  
  Your semantic cache will happily replay the wrong command
&lt;/h1&gt;

&lt;p&gt;Semantic caching works well for LLM responses because a near-match is usually good enough. Ask a slightly different question, get the cached answer, save a call. The failure mode is a mediocre answer.&lt;/p&gt;

&lt;p&gt;Trajectory caching — caching the sequence of tool calls an agent makes, not just its final text — has a different failure mode. The cache doesn't store prose. It stores actions. And a near-match on actions can be the &lt;em&gt;opposite&lt;/em&gt; operation.&lt;/p&gt;

&lt;p&gt;Concrete example. An agent runs the goal "deactivate user 4471" and the trajectory gets cached. Later, a request comes in: "activate user 4471". With text-embedding-3-small, those two goals score &lt;strong&gt;0.853 cosine similarity&lt;/strong&gt;. A plain semantic cache running a 0.85 threshold — a common default — scores that as a hit and replays the deactivation trajectory in response to an activation request.&lt;/p&gt;

&lt;p&gt;The embedding didn't fail. The two sentences are on the same topic, mention the same entity, and have the same structure. Embeddings are good at topic. The token that flips the operation — the polarity — barely moves the vector. If your cache decides hits on vector distance alone, it will eventually serve a write it shouldn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The asymmetry that matters
&lt;/h2&gt;

&lt;p&gt;For agent trajectories there are two directions a fuzzy match can go wrong, and they are not equivalent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A cached write trajectory fuzzy-matches a different request.&lt;/strong&gt; This is the dangerous direction. The system serves actions the requester never asked for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A cached read trajectory fuzzy-matches a write request.&lt;/strong&gt; This returns a wrong answer — but not a destructive one, because in Pomerene cached steps are never re-executed. A hit returns the recorded results of the stored steps. Nothing runs. No tool is called. The user gets stale read data presented as an answer, which is a quality bug, not an unwanted write.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We call the first case an &lt;strong&gt;operational false positive&lt;/strong&gt;: a fuzzy hit that would serve a trajectory whose effect differs from what was requested. That's the metric a trajectory cache should be designed around — not raw hit rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate: writes are exact-only
&lt;/h2&gt;

&lt;p&gt;Pomerene is a deterministic trajectory cache, and its matching rule is built around that asymmetry:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Every stored tool step declares its side effect.&lt;/strong&gt; Each step in a trajectory is tagged &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;replay_safe_write&lt;/code&gt;, or &lt;code&gt;external_write&lt;/code&gt;. If a step doesn't declare one, the store API rejects the trajectory. You can't opt out of the classification by forgetting to annotate; unclassified trajectories don't get stored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Any trajectory containing a write step is served only on an exact goal+context repeat.&lt;/strong&gt; Fuzzy (embedding-based) matching still applies to read-only trajectories, where a near-match costs you a suboptimal answer. The moment a trajectory writes, it leaves the fuzzy path entirely. A paraphrase of a write goal is a miss, full stop — the agent runs live.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Illustrative store call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST localhost:8080/v1/store &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "goal": "deactivate user 4471",
    "steps": [
      { "tool": "users.get",        "side_effect": "read",
        "args": { "id": 4471 } },
      { "tool": "users.deactivate", "side_effect": "external_write",
        "args": { "id": 4471 } }
    ]
  }'&lt;/span&gt;
&lt;span class="c"&gt;# This trajectory now serves ONLY on an exact repeat of goal + context.&lt;/span&gt;
&lt;span class="c"&gt;# "activate user 4471" — 0.853 similar — is a miss, and runs live.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What the eval shows
&lt;/h2&gt;

&lt;p&gt;We ran an adversarial eval of 18 near-opposite command pairs — activate/deactivate-style goals designed to sit close together in embedding space — using text-embedding-3-small at a 0.85 threshold:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Operational false positives&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Threshold-only semantic cache&lt;/td&gt;
&lt;td&gt;1 / 18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pomerene (side-effect gate)&lt;/td&gt;
&lt;td&gt;0 / 18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One in eighteen sounds small until you price it: that's one wrong write served, silently, out of every eighteen similar command pairs that pass through the cache. Writes are exactly the operations you can't undo with an apology.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest tradeoff
&lt;/h2&gt;

&lt;p&gt;The gate is not free, and we won't pretend otherwise. On these same deliberately short commands, the gated cache's paraphrase recall was &lt;strong&gt;1/18&lt;/strong&gt; — low. That's partly the test being adversarial (two-to-four-word commands carry almost no signal beyond the verb, and the verb is exactly what the gate refuses to guess at), but the direction of the tradeoff is real and deliberate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;miss&lt;/strong&gt; costs you one live agent run — the thing you were trying to cache in the first place.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;wrong write&lt;/strong&gt; costs you an incorrect mutation that may not surface until much later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pomerene is tuned to pay the first cost and never the second. If your workload is read-heavy research and summarization, a looser cache may serve you better. If your agents mutate state, the recall you lose to the gate is the price of being able to trust a hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it sits
&lt;/h2&gt;

&lt;p&gt;Pomerene wraps your agent function, not your model client, and never touches your prompts. On the hit path there is no LLM involved at all — matching is hashing plus vector geometry. Three outcomes per lookup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1 — full replay:&lt;/strong&gt; the whole trajectory serves from cache. A 14-step trajectory replays in 47ms vs. 3.9s live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 — partial replay:&lt;/strong&gt; a prefix matches; when the trajectory drifts, control hands back to the agent to finish live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Miss:&lt;/strong&gt; the agent runs normally, and the new trajectory can be stored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because it wraps the agent rather than a framework's internals, it works with LangGraph, Vercel AI SDK, Mastra, or a custom loop. Quickstart is Node 20+ and Postgres; &lt;code&gt;npm run setup&lt;/code&gt; gets you running in about five minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Pomerene ships as a self-hosted Starter Kit — Indie $99 / Pro $249, one-time, source included. If your agents perform writes, run the near-opposite test against your current cache before you trust it in production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pomerene.io/starter-kit" rel="noopener noreferrer"&gt;pomerene.io/starter-kit&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>typescript</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
