DEV Community

Cover image for My agent wasn’t forgetting things — I just couldn’t see what it decided 3 steps earlier
Lars Winstand
Lars Winstand

Posted on Originally published at standardcompute.com

My agent wasn’t forgetting things — I just couldn’t see what it decided 3 steps earlier

I hit one of those agent bugs that makes you blame everything in the wrong order.

The final answer looked polished. Good structure. Confident tone. Totally wrong.

So I did the usual loop:

  • blamed GPT-5
  • blamed retrieval
  • blamed the summary step
  • started tweaking prompts like that would somehow fix a state bug

It didn’t.

The real failure happened earlier in the workflow. The agent didn’t “forget” anything. It inherited bad state from a previous step, and I had no visibility into it.

That changed how I think about memory in agent systems.

The useful part of memory logging is not personalization. It’s observability.

If you can’t inspect retrieval, summaries, tool outputs, and state mutations between steps, you’re not debugging an agent. You’re guessing.

Most “memory bugs” are really state bugs

A lot of people say:

the agent forgot

Sometimes that’s true. A lot of the time it isn’t.

What actually happened is closer to state drift:

  • a retrieval step returned stale docs
  • a summary collapsed two entities into one
  • a tool returned the wrong JSON shape
  • a handoff dropped a key constraint
  • a memory backend re-injected old context

Then every later step treated that bad intermediate output as fact.

That’s not model flakiness. That’s bad application state.

Once I started framing it that way, my debugging questions got better:

  • What state did this step receive?
  • What got retrieved?
  • What got summarized away?
  • What tool output mutated the thread?
  • Which step wrote the bad memory?

Those questions are a lot more useful than “should I rewrite the system prompt again?”

Why traces matter more than prompt tweaks

For multi-step agents, the bug usually lives in the boring middle.

Not the final response.

The middle.

That’s why tracing is so valuable. You need a record of:

  • model generations
  • tool calls
  • handoffs
  • guardrail decisions
  • memory/state updates
  • custom events

If you only inspect the final answer, the crime scene is already cleaned up.

This is one reason I like that OpenAI Agents SDK treats tracing as normal behavior instead of some enterprise-only add-on.

Tracing is enabled by default, and you can turn it off with:

export OPENAI_AGENTS_DISABLE_TRACING=1
Enter fullscreen mode Exit fullscreen mode

That detail matters. It means the SDK assumes you’ll need visibility into the workflow, not just the final completion.

And honestly, that assumption is correct.

If you’re building agents without traces, prompt tweaking becomes superstition pretty fast.

The 5-step workflow that fooled me

The bug that made this click for me was in a simple pipeline:

  1. Retrieve documents
  2. Summarize them
  3. Make a decision from the summary
  4. Call a function
  5. Write the final response

The final response looked fine.

But the trace showed the actual failure chain:

  • retrieval returned a mixed set of documents
  • the summary merged two distinct entities
  • the decision step treated the merged summary as truth
  • the function call executed against the wrong assumption
  • the final answer confidently repeated the mistake

If I had only looked at the last step, I would have blamed the model.

The model was not the root cause.

The workflow was.

That’s why I think “automatic memory logging” is undersold. The value is not that your assistant remembers your preferences. The value is that you can inspect where the workflow drifted.

Long-running agents get worse before they fail

This gets more obvious in long threads.

A lot of teams think the only problem is context windows. But long-running agents usually degrade before they hit the hard limit.

They start to:

  • get distracted by stale context
  • carry forward outdated assumptions
  • slow down
  • cost more
  • make worse decisions over time

So teams add:

  • trimming
  • summarization
  • retrieval backfills
  • external memory stores

That helps, but it also creates new failure modes.

A summary drops one critical constraint.
A trim removes a message that looked unimportant.
A retrieval step pulls in stale context.
A memory backend injects the wrong history.

Without logs, this looks random.

With logs, you can inspect the timeline and find the exact mutation that broke the run.

The n8n version of this problem is very real

If you build AI workflows in n8n, you’ve probably already seen this.

n8n supports multiple memory options for AI workflows, including:

  • Simple Memory
  • Motorhead
  • Redis Chat Memory
  • Postgres Chat Memory
  • Xata
  • Zep

It also has Chat Memory Manager for inspecting or adjusting what gets passed into context.

That alone tells you memory is not some magical feature. It’s an input pipeline.

And input pipelines need inspection.

The practical debugging question in n8n is not:

does my AI Agent node have memory?

It’s:

what exact messages got injected into the Agent node, and how is that different from the conversation state I thought I had?

Same pattern shows up elsewhere too:

  • In Make, one stale mapped field can poison the next module.
  • In Zapier, a formatter step can quietly rewrite a field your agent treats as canonical.
  • In OpenClaw, a handoff can preserve the wrong intermediate state longer than you expect.

Different tooling. Same bug class.

The agent didn’t forget. Your workflow passed along a bad decision.

What I actually log now

I used to think “log everything” was the safe answer.

It isn’t.

You just end up with expensive noise.

What I want is enough information to answer one question:

where did the workflow drift?

My default checklist now is:

  1. Retrieved document IDs or snippets
  2. Intermediate summaries
  3. Tool inputs and outputs
  4. Memory before and after each step
  5. Checkpointed thread state
  6. Guardrail decisions
  7. Agent handoffs

That’s usually enough to reconstruct the bad branch without drowning in spans.

LangSmith and OpenAI tracing: the practical setup

If I’m debugging a custom Python agent, I want tracing on immediately.

LangSmith

Minimal setup:

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="<your-langsmith-api-key>"
export OPENAI_API_KEY="<your-openai-api-key>"
Enter fullscreen mode Exit fullscreen mode

That gets you end-to-end traces fast.

OpenAI Agents SDK tracing

You can also tune tracing behavior per run:

from agents import RunConfig, Runner

result = await Runner.run(
    agent,
    "Hello",
    run_config=RunConfig(
        tracing={"include_task_and_turn_spans": False}
    ),
)
Enter fullscreen mode Exit fullscreen mode

That kind of config matters more than people think.

Most teams skip it while moving fast, then spend a week reverse-engineering a bad run from vibes and partial logs.

Which logging approach is useful for what?

Here’s the rough split I use:

Option What it’s best at
LangSmith End-to-end traces for LLM apps, project/workspace organization, and fast setup
OpenAI Agents SDK tracing Default tracing for generations, tool calls, handoffs, guardrails, and custom events in multi-step runs
n8n memory + Chat Memory Manager Workflow-level inspection of memory injection, backend choices, and context-size control

My rule of thumb:

  • custom runtime: use LangSmith or OpenAI tracing
  • n8n workflow: inspect memory injection directly
  • long-lived agent threads: make checkpointed state visible

If you’re still trying to debug multi-step failures from final outputs alone, stop.

That approach does not scale.

A tiny example: the bug is usually one step earlier than you think

Here’s a toy pattern I see all the time:

state = {
    "customer_id": "cus_123",
    "plan": "pro",
    "docs": [],
    "summary": None,
}

# step 1: retrieval
state["docs"] = retrieve_docs(query="refund policy for enterprise")

# step 2: summarization
state["summary"] = summarize_docs(state["docs"])

# step 3: decision
if "refund allowed" in state["summary"].lower():
    action = "approve_refund"
else:
    action = "deny_refund"
Enter fullscreen mode Exit fullscreen mode

If retrieval returns mixed docs, or the summary merges enterprise and pro rules, step 3 makes the wrong decision.

Then every later step looks broken even though the actual corruption happened upstream.

That’s why logging only the final answer is nearly useless.

You need to see the state transitions.

Yes, there’s a privacy tradeoff

This is the strongest argument against aggressive tracing.

And it’s a real one.

Logs can capture:

  • prompts
  • retrieved documents
  • tool inputs
  • internal data
  • user content

If your workflow touches contracts, support tickets, health data, or internal research, you can’t just dump everything into traces forever and call it observability.

So the answer is not “log literally everything.”

The answer is:

  • define which state transitions matter
  • redact sensitive fields
  • keep retention sane
  • avoid collecting junk nobody uses

Bad logging is expensive.

No logging is worse.

The part nobody says out loud: observability increases usage

Once a team gets serious about traces, they run more experiments.

More replays.
More branch testing.
More long-lived agent threads.
More debugging sessions.

That’s good engineering.

But it also changes your compute profile.

This is exactly where per-token billing starts to feel annoying. The more seriously you debug agents, the more you rerun workflows, compare traces, inspect summaries, and let automations loop longer.

That’s one reason flat-rate compute is so appealing for agent-heavy teams.

If your stack runs in n8n, Make, Zapier, OpenClaw, or custom Python services, you want people debugging aggressively instead of hesitating because every experiment feels billable.

That’s the practical appeal of Standard Compute: it’s a drop-in OpenAI-compatible API with flat monthly pricing, so teams can run and debug agent workflows without staring at token meters all day.

For agent builders, that matters more than people admit.

The takeaway

Stop treating memory like a UX feature.

Treat it like application state.

And once you do that, log it like application state:

  • what came in
  • what changed
  • what got summarized
  • what got retrieved
  • what got handed off
  • what the next step inherited

A lot of “AI bugs” stop looking mysterious once you can see the timeline.

Because the agent usually didn’t forget anything.

It made a bad decision three steps earlier, and nobody was watching.

Top comments (0)