Do your tool-using agents re-plan the same task every single time ?

I’ve noticed something while building tool-using agents (ReAct, LangGraph, OpenAI tool calling).

Even when the task has essentially the same structure—say:

  • fetch active users

  • filter by condition

  • export CSV

the agent typically regenerates the execution plan from scratch every run.

Existing memory systems (Mem0, Zep, vector memory, etc.) seem focused on remembering facts or conversations rather than successful execution procedures.

I’m curious how people handle this in production.

  • Do your agents always re-plan?

  • Do you cache tool sequences or execution graphs?

  • Have you experimented with reusable “skills” or workflow memories?

  • What approaches worked (or failed)?

If something cut your planning/LLM calls ~30–45% at the same success rate wouldnt it be great .I’d love to hear how others are solving this.

hi @siddhu1716

it shouldn’t be like that. Could you share your code snippets?
Have you attached a checkpointer to your agent?

===

create_agent compiles to a three node graph (start, model, tools), and each node derives the next action from the current message list only. Nothing consults previous runs. A checkpointer restores messages within a thread, a store is cross thread but nothing reads it for you unless you write that middleware. So re-planning is the semantics of the loop, not a bug.

But I would push back on the framing. fetch active users, filter, export CSV has no branch that depends on model judgment. The agent regenerates the same plan every run because there is only one plan. Caching it means paying an LLM to rediscover a constant, then building a cache to hide the cost. That is a workflow, not an agent task.

On caching, four things get conflated and only one cuts planning calls:

  • prompt caching: cuts cost, saves zero calls
  • set_llm_cache: exact match on the full serialized message list, so it hits only your first planning call and misses every step after, because tool results carry live data. That single hit also returns a plan derived from data it never re-read.
  • CachePolicy plus compile(cache=): caches node results keyed on node input. For fetch active users this is actively wrong, you serve stale users.
  • procedure reuse: the only one that actually removes planning calls

Two traps worth knowing. create_agent(cache=…) is currently a no-op: it forwards the backend to compile, but LangGraph only consults the cache when a node carries a cache_policy, and nothing in langchain_v1 sets one. Checked on langchain 1.2.13, all three nodes report cache_policy=None. Also CachePolicy(120) sets key_func, not ttl, since key_func is the first field. Write ttl=120.

On your 30 to 45 percent: it is real and already measured. Agentic Plan Caching (arXiv 2506.14852) is literally this idea. It gets 50.31 percent cost reduction and 27.28 percent latency reduction, but retains 96.61 percent of optimal performance. That is roughly 3.4 percent accuracy loss, not the same success rate. Notably they use exact keyword matching specifically to minimise false positives. Agent Workflow Memory (arXiv 2409.07429, ICML 2025) induces reusable workflows instead, and improves relative success by 24.6 and 51.1 percent on Mind2Web and WebArena while cutting steps. That sign flip is the whole argument: plan caching trades accuracy for cost, workflow induction does not.

What fails: fuzzy or semantic cache keys on plans. Export active users and export users active in the last 30 days embed nearly identically and need different plans. A fuzzy hit replays the wrong procedure and produces a plausible, silently wrong CSV with no error. Exact match or do not ship it. Also never cache non idempotent tools, and note a homegrown plan store has no invalidation when tool signatures drift, whereas LangGraph gets that free by hashing node identity into the cache namespace.

What I would actually do: treat the agent as a compiler, not an interpreter. Let it plan once on a novel task, persist the trajectory, then promote validated ones to a skill or a plain tool behind a human or eval gate. The hot path becomes route to deterministic code, zero planning calls, and success goes up, because WHERE active = true is not a coin flip. Keep the agent for the tail. Deep Agents skills are the packaged version, and the telling detail is that the reusable unit is a tested script the agent executes, not a cached plan. The skill is just a pointer to it.

Use LangSmith to find which task shapes actually repeat before optimising any of them. If fetch/filter/export is 60 percent of your traffic, compiling that one shape captures nearly all the available win and you never need a plan cache.

Hi, @siddhu1716! What you’re talking about is some sort of long-term, procedural memory. I think agent Skills might be the right answer.

Short-term vs. long-term memory

A checkpointer only gives an agent short-term memory: it’s thread-scoped. It restores the message history within a thread, so a resumed conversation remembers what it did. But start a new thread and none of it carries over — the agent re-derives the plan from scratch, every time. (short-term memory docs)

Long-term memory, on the other hand, persists across thread sessions. So the agent carries this knowledge to new threads. (long-term memory docs)

Procedural memory

What you’re describing — “remember how I did this task and reuse it” — is procedural memory: long-term, and persistent across threads. It’s a different memory type from the facts/conversations that Mem0, Zep, and vector stores focus on (that’s semantic/episodic). The memory concept guide lays out the distinction:

  • semantic = facts
  • episodic = past experiences
  • procedural = the rules/instructions for how to do the task.

Agent skills

In practice, the cleanest way to give an agent procedural memory is Skills. You write the steps up once — fetch active users → filter → export CSV — as a skill, and the agent loads it on demand when a task matches instead of re-planning from zero. Skills are discovered by name + description at startup, and the full instructions load only when relevant, so you’re not paying for context you don’t use. (Skills docs)

That’s the reframe I’d suggest: you don’t need to cache plans, you need to write down the procedure once and let the agent reach for it. For a genuinely fixed shape like your example, a skill (or promoting it to a plain tool) gets you the call reduction you’re after — and reliability goes up as a bonus, because the steps aren’t re-guessed each run.