Back to Blog

The Three Agent Patterns Every Team Needs

Research, workflow, and coding agents — when to use each, and how they share infrastructure.


The Three Agent Patterns Every Team Needs

After building agents for a dozen different use cases, we noticed something: every agent we built was a variation on one of three patterns. The domain changed. The tools changed. The prompts changed. But the underlying architecture was always one of three shapes.

We call them the workflow agent, the research agent, and the extraction agent. Understanding when to use each one — and how they share infrastructure — is the fastest way to go from “I want to build an agent” to “I have an agent in production.”

Pattern 1: The workflow agent

The workflow agent handles multi-turn conversations with a user, follows a semi-structured process, and takes actions on their behalf. Customer support is the canonical example, but this pattern shows up everywhere: onboarding flows, IT helpdesks, scheduling assistants, order management.

The defining characteristic is that the workflow agent reacts to user input. It does not go off on its own — it waits for the user to say something, decides what to do, does it, and responds. The loop is always human-in-the-loop.

How it works

The agent has access to a set of tools that represent the actions it can take: search a knowledge base, look up an order, update a ticket, send an email. The system prompt defines the agent’s role, tone, and escalation rules. The agentic loop is straightforward:

while True:
    response = client.messages.create(
        model=MODEL,
        system=SYSTEM_PROMPT,
        tools=TOOLS,
        messages=conversation_history,
    )

    if response.stop_reason == "end_turn":
        return response.content[0].text

    # Execute tool calls and continue
    tool_results = execute_tools(response.content)
    conversation_history.append(...)

The complexity is not in the loop. It is in the tool design and the system prompt. A well-designed workflow agent has tools that are narrow and well-described, so the model picks the right one reliably. It has a system prompt that defines when to search, when to act, and when to escalate to a human.

When to use it

Use the workflow pattern when:

  • A human is in the loop and driving the conversation
  • The agent needs to take actions in external systems (databases, APIs, ticketing systems)
  • Conversations are multi-turn and context-dependent
  • You need clear escalation paths for cases the agent cannot handle

In the StartToAgent kit, the customer support agent demonstrates this pattern. It searches a knowledge base, holds multi-turn conversations, and includes escalation logic. The interesting parts to study are the tool descriptions (which guide Claude’s tool selection) and the conversation trimming (which keeps long conversations within context limits).

Pattern 2: The research agent

The research agent takes a question or topic, breaks it into sub-tasks, gathers information from multiple sources, and produces a synthesized output. It works autonomously — you give it a prompt and come back when it is done.

This is the pattern you see in deep research tools, competitive analysis bots, literature review assistants, and due diligence automation. The key difference from the workflow agent is that nobody is guiding the research agent turn by turn. It needs to plan, execute, evaluate its own progress, and iterate.

How it works

The research agent has two phases: planning and execution. In the planning phase, it takes the user’s question and breaks it into a set of research sub-tasks. In the execution phase, it works through each sub-task, gathering information and synthesizing as it goes.

# Phase 1: Plan
plan = generate_research_plan(question)

# Phase 2: Execute each step
findings = []
for step in plan.steps:
    result = execute_research_step(step, findings_so_far=findings)
    findings.append(result)

    # Optionally: revise the plan based on what we've learned
    if result.suggests_new_direction:
        plan = revise_plan(plan, findings)

# Phase 3: Synthesize
report = synthesize_findings(question, findings)

The tool set for a research agent is different from a workflow agent. Instead of action-oriented tools (update a ticket, send an email), research agents have information-gathering tools: web search, document retrieval, database queries, API lookups. Often the agent calls the same tool many times with different queries.

The tricky part is managing the context window. A research agent can easily accumulate tens of thousands of tokens of findings across multiple research steps. You need a strategy for summarizing intermediate findings so the model can fit everything in context when it synthesizes the final output.

When to use it

Use the research pattern when:

  • The task requires gathering information from multiple sources
  • The answer needs synthesis, not just retrieval
  • The process benefits from planning and iteration
  • The output is a document or report, not a conversational response

In the kit, the research agent demonstrates this pattern. It plans its research strategy, searches multiple sources, tracks findings across steps, and produces a structured report. Pay attention to how it manages context — intermediate findings are summarized to keep the full context window available for synthesis.

Pattern 3: The extraction agent

The extraction agent takes unstructured input — documents, emails, images, web pages — and produces structured output conforming to a schema. It is the most constrained of the three patterns, and often the most immediately useful in business contexts.

Think of everything your team does with copy-paste and spreadsheets: extracting line items from invoices, pulling key dates from contracts, parsing resumes into structured records, converting support emails into ticket fields. The extraction agent automates all of this.

How it works

The extraction agent’s loop has a unique feature: validation. After the model produces structured output, you validate it against your schema. If validation fails, you send the errors back to the model and ask it to fix them. This retry loop is what makes extraction reliable enough for production.

for attempt in range(max_retries):
    response = client.messages.create(
        model=MODEL,
        system=EXTRACTION_PROMPT,
        messages=messages,
    )

    raw_output = extract_json(response.content[0].text)

    try:
        validated = OutputSchema.model_validate(raw_output)
        return validated
    except ValidationError as e:
        # Send validation errors back to Claude
        messages.append({"role": "assistant", "content": response.content})
        messages.append({
            "role": "user",
            "content": f"Validation failed: {e}. Fix the output."
        })

The key design decision is your output schema. Pydantic models work well for this because they give you both the JSON schema (which you include in the prompt) and runtime validation (which powers the retry loop). Claude is very good at producing valid JSON when given a clear schema, and the retry loop catches the remaining edge cases.

When to use it

Use the extraction pattern when:

  • Input is unstructured text or documents
  • Output must conform to a strict schema
  • Accuracy matters more than speed (the retry loop adds latency)
  • You need to process high volumes of similar documents

The document extraction agent in the kit demonstrates this pattern. It uses Pydantic for schema definition and validation, includes the retry loop, and handles common edge cases like partial JSON in responses and nested object validation.

How the three patterns share infrastructure

Here is the insight that shaped StartToAgent: while the three patterns have different architectures, they share the same infrastructure needs. Every agent needs:

  • Tool management. Workflow agents have many tools. Research agents reuse a few tools heavily. Extraction agents might not use tools at all, or might use them for document loading. But the tool registry — schema generation, input validation, dispatch — is the same code.

  • Conversation management. Workflow agents manage long conversations. Research agents manage growing context across steps. Extraction agents manage retry sequences. The message handling, trimming, and formatting is shared.

  • Cost tracking. This is the most universal need. Every API call costs money. A research agent doing 20 searches can cost 10x what a single workflow turn costs. You need visibility into cost at the per-call, per-conversation, and per-day level regardless of which pattern you are using.

  • Error handling. Rate limits, API errors, malformed responses — these happen to every agent. The retry logic, backoff strategy, and graceful degradation code is identical across patterns.

This is why StartToAgent is structured as a set of shared modules plus separate agent implementations. The agents are different. The infrastructure is not. When you improve the cost tracker, every agent gets better. When you add a new retry strategy, every agent benefits.

Start with one, expand to three

If you are just getting started with agents, do not try to build all three patterns at once. Pick the one that matches your most pressing use case and build that well.

Most teams start with the workflow agent because it is the most intuitive — it looks like a chatbot with superpowers. The feedback loop is fast because a human is in the loop validating every response.

Once your first agent is in production and you understand the infrastructure, adding a second pattern is much faster. The tool registry is already built. Cost tracking is already working. Error handling is already battle-tested. You are adding a new agent architecture on top of a proven foundation, not starting from scratch.

The goal is not to have three agents. The goal is to have a shared infrastructure that makes building any agent fast and reliable. The three patterns are starting points, not endpoints. Your production agents will evolve into something unique to your domain. But they will still use the same tool registry, the same cost tracker, and the same error handler.

That is the real value of starting from patterns instead of starting from a blank file.

Keep reading

Browse all posts