Tool Use Patterns

Summary: Tool use patterns are reusable architectures for how LLM agents interact with external functions (tools). Well-designed patterns improve reliability, reduce hallucination, and enable complex multi-step workflows. Core patterns: Sequential, Parallel, Conditional, Recursive, and Human-in-the-loop.

Tool Definition Schema

Every tool needs a JSON Schema for reliable invocation:

{
  "name": "read_file",
  "description": "Read contents of a file",
  "parameters": {
    "type": "object",
    "properties": {
      "path": {"type": "string", "description": "Absolute path to file"},
      "offset": {"type": "integer", "default": 0},
      "limit": {"type": "integer", "default": 2000}
    },
    "required": ["path"]
  }
}
Field Purpose
name Unique identifier (snake_case)
description When to use — critical for LLM selection
parameters JSON Schema — validates args before execution

Tool-Use Patterns

SEQUENTIAL (Pipeline)

User Request
      │
      ▼
┌─────────────┐
│ Tool A      │ ──→ Result A
└─────────────┘
      │
      ▼
┌─────────────┐
│ Tool B      │ ──→ Result B  (uses Result A)
└─────────────┘
      │
      ▼
┌─────────────┐
│ Tool C      │ ──→ Final Answer
└─────────────┘

Use case: Dependent operations (read → edit → test) Risk: Single failure breaks chain


2. PARALLEL (Fan-out)

User Request
      │
      ├──→ Tool A ──→ Result A
      ├──→ Tool B ──→ Result B
      └──→ Tool C ──→ Result C
            │
            ▼
      Aggregate → Final Answer

Use case: Independent queries (search web + read file + run shell) Benefit: Latency = max(tool latency), not sum


3. CONDITIONAL (Branching)

Diagram: (Mermaid diagram - view source for diagram code)

graph TD
    A[Analyze Request] --> B{Decision}
    B -->|Path 1| C[Tool Set A]
    B -->|Path 2| D[Tool Set B]
    B -->|Path 3| E[Ask Clarification]
    C --> F[Synthesize]
    D --> F
    E --> F

Use case: Routing based on query type (code vs. research vs. creative) Implementation: LLM classifies, then invokes appropriate tool subset


4. RECURSIVE (Self-Correction)

Attempt 1: Tool → Result → Evaluate
                    │
                    ├── Success → Done
                    └── Failure → Reflect → Adjust → Attempt 2

Use case: Code generation with test feedback, web search refinement Key: Max iterations cap (typically 3-5)


5. HUMAN-IN-THE-LOOP (Approval Gates)

Diagram: (Mermaid diagram - view source for diagram code)

sequenceDiagram
    Agent->>Tool: Propose action (high-risk)
    Tool-->>Human: Present for approval
    Human->>Tool: Approve / Modify / Reject
    Tool->>Agent: Execute / Abort

Use case: Irreversible actions (deploy, delete, purchase, merge PR) Pattern: tool.requires_approval = true


Execution Patterns

Structured Output Enforcement

# Pydantic model for tool result
class FileReadResult(BaseModel):
    content: str
    lines_read: int
    truncated: bool

# Forces LLM to produce valid JSON matching schema
tool_result = FileReadResult.model_validate_json(llm_output)

Tool Result Formatting for LLM Consumption

Format Best For Token Cost
Raw JSON Structured data, stacking Low
Markdown Human-readable, code blocks Medium
Summary + Key Excerpts Large outputs (logs, files) Low
Error Object Uniform error handling Low
{
  "success": false,
  "error": {
    "code": "FILE_NOT_FOUND",
    "message": "Path '/tmp/x' does not exist",
    "recoverable": true,
    "suggestion": "Check path or list directory first"
  }
}

Common Tool Categories for Coding Agents

Category Tools Purpose
File System read_file, write_file, edit_file, list_dir, glob Code navigation & editing
Shell run_command, run_background Build, test, lint, git
Search grep, web_search, semantic_search Finding code/docs
Git git_status, git_diff, git_commit, git_push Version control
Browser visit_url, extract_content Documentation, APIs
Analysis ast_parse, type_check, lint Code understanding

Reliability Patterns

1. Idempotency Keys

# Every tool call gets unique ID; safe to retry
tool_call_id = f"{tool_name}_{hash(args)}_{timestamp}"

2. Timeout & Retry Policy

tool_config:
  default_timeout: 30s
  max_retries: 3
  backoff: exponential
  retry_on: [timeout, network_error, rate_limit]

3. Sandbox Isolation

  • Filesystem: Chroot / container / VM
  • Network: Allowlist only
  • Process: No fork bombs, resource limits

4. Observation Compression

def compress_observation(result, max_tokens=2000):
    if estimate_tokens(result) > max_tokens:
        return summarize_with_llm(result, target_tokens=max_tokens)
    return result

Anti-Patterns to Avoid

Anti-Pattern Problem Fix
Overloaded tools One tool does too much → LLM confused Split into focused tools
Vague descriptions LLM picks wrong tool Be specific: "Use for X, not Y"
No error schema LLM can't handle failures Standard error object
Unbounded loops Infinite recursion Max iterations + progress check
Raw output dumping Context explosion Summarize/compress results

Codex-Specific Patterns (OpenAI Codex)

Goals as Persistent Context

{
  "goal": "Refactor auth module to use JWT",
  "acceptance_criteria": [
    "All tests pass",
    "No plaintext passwords in code",
    "JWT refresh token rotation implemented"
  ]
}
  • Injected as system reminder each turn
  • Survives session restart
  • Progress tracked automatically

Specialized Tool Set

Tool Purpose
apply_patch Unified diff application
run_tests Test suite execution with summary
search_codebase Semantic + lexical code search
create_pr GitHub PR creation with description

Evaluation Checklist

  • Each tool has clear, unique purpose
  • Descriptions include "when to use" and "when NOT to use"
  • Schemas are strict (no additionalProperties: true)
  • Error objects are uniform and actionable
  • Results are compressed for context efficiency
  • Idempotent tools marked for safe retry
  • Approval gates on irreversible actions
  • Observability: every call logged with latency, tokens, success

Related Concepts

Sources