Deep Agents · Lesson 8 of 9 · 5 min read

Testing & Debugging Deep Agents

How to verify a deep agent's planning, filesystem and memory actually work — inspect the state, stream the run, trace with LangSmith and unit-test tools.

By the ToolsHub team · Updated September 14, 2026

A deep agent's pillars — planning, the virtual filesystem, memory — don't show up by reading the code; they only happen when the agent runs. So you test them the same way: run the agent, then inspect the state it returns and the steps it streamed. Here's how to verify each one.

Testing planning (write_todos)

The planning middleware keeps a todo list in the agent's state and calls write_todosas it works. Watch it happen by streaming, or assert on the result:

# Watch the plan form, step by step
for chunk in agent.stream({"messages": "Plan and research X"}):
    print(chunk)          # you'll see write_todos calls + the todo list updating

# Or check the final state
result = agent.invoke({"messages": "Plan and research X"})
# look for write_todos in the tool calls, and a todos entry in the state
print(result.get("todos"))

If a multi-step task produces no todos, your system prompt isn't pushing the agent to plan first.

Testing the filesystem

By default the virtual filesystem is in-memory and stored in state (swap in a real backend for disk). Force the agent to use it, then read the files back:

result = agent.invoke({"messages": "Save your findings to notes.md, then summarize from it."})
print(result.get("files"))     # the virtual files the agent wrote
# with a real filesystem backend, just check the folder on disk instead

Seeing the expected file written (with content) is your proof the context-offload pillar works.

Testing memory (across runs)

Long-term memory persists between runs, so test it with a checkpointer/store and the same thread id — same thread should remember, a new one should not:

config = {"configurable": {"thread_id": "user-123"}}
agent.invoke({"messages": "My name is Sam."}, config=config)
r = agent.invoke({"messages": "What's my name?"}, config=config)   # should recall "Sam"
print(r["messages"][-1].content)

See all three at once: LangSmith + streaming

  • LangSmith tracing — the standard way to debug an agent. One trace shows the todos, the files written, every tool call and every subagent delegation, in order. Set your LangSmith env vars and open the run.
  • Streamingagent.stream(...) lets you watch the loop live without any extra setup, which is often enough to spot where a run goes wrong.

Unit-test the deterministic parts

The LLM's wording changes run to run, so don't assert on prose. Do assert on the parts you control:

  • Tools — they're plain functions; test internet_search("x") directly.
  • Structure & state — assert the expected tool-call sequence, that a file was written, or that a todo list exists — not the exact summary text.
  • Use a cheap model in tests to keep them fast and affordable.

Design and regenerate the agent you're testing with theDeep Agent Scaffold Generator — then run it and check the state as above. (State keys can shift in a fast-moving preview, so verify against your installed version.)

Frequently asked questions

How do I know the planning/filesystem/memory pillars are actually working?
Run the agent, then inspect its state and stream. Planning shows up as write_todos tool calls and a todos entry in state; the filesystem shows up as files the agent wrote; memory shows up as recall across two runs on the same thread_id. LangSmith tracing shows all three in one view.
Can I write deterministic tests for an agent?
Test the deterministic parts: unit-test your tools directly (they're plain functions), and assert on tool-call sequences and final state rather than the exact wording of the model's prose, which varies run to run.

Try the tool