CCDV-F · Agents and Workflows
Parallel tool loops, memory and agentic frameworks
A warehouse agent answers slowly when the user asks about three products, and every so often the API returns a 400 that mentions a tool_use without its tool_result. Another agent, for tutoring, starts every session by pasting the student’s previous twenty conversations. And a third team wants to move a simple call onto a graph framework “to be ready”. These are three agent patterns applied badly.
Several tools in one response
Claude can request more than one tool in a single response: this is parallel tool use. The harness has to:
- Go through every
tool_useblock in the response, not just the first one. - Return one
tool_resultfor each, with itstool_use_id, all together in the next user message and before any text. - Run the independent, read-only ones at the same time (in Python, for example, with
asyncio.gather), and run in order the ones that depend on each other or have side effects.
If you process only the first block, the API returns 400 because requests were left without a result; if you run them one after another for no reason, the response takes the sum of all the lookups.
Memory: what lasts and where it is stored
You need to separate two things:
- Short-term memory: the current conversation, inside the context window. It’s lost when the session ends and takes up room while it lasts.
- Long-term memory: what has to survive between sessions (the student’s preferences, decisions, progress). It lives outside the context.
For long-term memory, the API has the memory tool: Claude asks to create, read, edit or delete files inside a /memories directory, and your application runs each operation against storage you control (files, a database, a bucket per user). It’s a client tool, so it’s up to you to validate every path so it never leaves that directory. That way the agent reads only the relevant notes instead of loading the whole history on every request.
Keeping the window from filling up
In a long-running agent, tool outputs pile up. The ways to contain it, covered in detail in the context domain, are three: delegate to subagents that return summaries, remove or compact old outputs (context editing and compaction), and send to external memory whatever has to last. Watch out for a frequent distractor: prompt caching makes things cheaper and faster, but it doesn’t free a single token of the window.
Agentic frameworks
An agentic framework gives you ready-made pieces on top of the API:
| Framework | What it brings |
|---|---|
| LangGraph | Models the flow as a graph of nodes with persistent state and checkpoints: branches, retries and pauses for human approval |
| PydanticAI | Python agents with typed inputs and outputs validated with Pydantic models |
| Strands Agents | A model-driven SDK: you define the prompt and tools and the framework runs the loop |
The recommendation is to start with the API directly and add a framework when it solves a concrete need, such as state that must persist between steps or a flow with many branches. Each abstraction layer hides the actual prompt and response, which makes debugging harder. If you adopt one, it pays to understand what it does underneath.
The typical traps
- Processing only the first
tool_use, or sending the results in separate messages. - Running independent read-only lookups serially.
- Pasting the full history into every session instead of using memory with short notes.
- Implementing the memory tool without validating paths.
- Believing prompt caching fixes a window that fills up.
- Adopting a framework “just in case” for a call with one tool.
On the exam
If a 400 names a tool_use without a result, the answer is to return one tool_result per block, all together. If the agent is also slow with several independent lookups, add concurrent execution. If the agent has to remember between sessions, look for the memory tool with your own storage. And if someone proposes a framework without a problem that calls for it, stick with the direct API.
Quick question
A practice exam question on this domain. It counts towards your progress.
A venture firm's engineering team runs a due-diligence agent built on the Claude API. Given a company name, it researches five areas: financial filings, litigation, press coverage, patents and hiring trends. Each area needs between 15 and 40 tool calls (searches, document fetches, table extraction), and the areas don't depend on each other.
Today a single agent does everything in one conversation. Traces show that by the time it reaches patents and hiring, its context is full of raw filing excerpts and news pages. Findings from the first areas get mixed up with later ones, and twice the final report attributed a lawsuit to the wrong company.
Analysts also complain that a full report takes almost an hour, because the areas are processed one after another.
The team uses TypeScript and already logs every tool call to a tracing backend.
Which architecture best addresses both the accuracy and the latency problems?