> ## Documentation Index
> Fetch the complete documentation index at: https://docs.together.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Function calling & tool use

> The model plans, your code runs the tool. How structured tool calls and agent loops actually work.

export const ToolLoopDiagram = () => {
  const CSS = `
  .learn-diagram .loop { display: grid; gap: var(--space-md); }
  .learn-diagram .loop__phases {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
  }
  .learn-diagram .loop__phase {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 6px 10px;
    border-radius: var(--radius-sm);
    background: var(--color-paper-3);
    color: var(--color-ink-faint);
    border: 1px solid transparent;
    transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
    white-space: nowrap;
  }
  .learn-diagram .loop__phase.is-done { color: var(--color-ink-soft); }
  .learn-diagram .loop__phase.is-now {
    background: var(--tg-orange);
    border-color: var(--tg-orange);
    color: #fff;
  }
  .learn-diagram .loop__arrow { color: var(--color-rule); font-size: 12px; }
  .learn-diagram .loop__hint {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.04em;
    color: var(--color-ink-faint);
  }
  .learn-diagram .loop__steps { display: grid; gap: var(--space-2xs); }
  .learn-diagram .loop__step {
    background: var(--color-paper-2);
    border: 1px solid var(--color-rule-soft);
    border-left: 3px solid var(--color-rule);
    border-radius: var(--radius-md);
    padding: var(--space-xs) var(--space-sm);
    transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
    animation: learn-loop-in var(--dur-base) var(--ease-out);
  }
  @keyframes learn-loop-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
  .learn-diagram .loop__step.is-user { border-left-color: var(--tg-slate); }
  .learn-diagram .loop__step.is-model { border-left-color: var(--tg-orange); }
  .learn-diagram .loop__step.is-code { border-left-color: var(--tg-purple); }
  .learn-diagram .loop__step.is-tool { border-left-color: var(--tg-blue); }
  .learn-diagram .loop__step.is-active { background: var(--color-paper); box-shadow: 0 1px 3px rgba(9,9,9,0.06); }
  .learn-diagram .loop__role {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-ink-mute);
    margin-bottom: 4px;
    display: flex;
    justify-content: space-between;
    gap: var(--space-2xs);
  }
  .learn-diagram .loop__who { color: var(--color-ink-faint); }
  .learn-diagram .loop__body {
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--color-ink);
    white-space: pre-wrap;
    word-break: break-word;
  }
  .learn-diagram .loop__back {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.04em;
    color: var(--tg-orange-dark);
    background: var(--tg-orange-soft);
    border-radius: var(--radius-sm);
    padding: 6px 10px;
  }
  `;
  const STEPS = [{
    phase: "user asks",
    role: "user",
    kind: "user",
    who: "your app",
    body: "What's the weather in Tokyo right now?"
  }, {
    phase: "model calls a tool",
    role: "assistant",
    kind: "model",
    who: "the model",
    body: 'tool_calls: [\n  {\n    name: "get_weather",\n    arguments: { "city": "Tokyo", "units": "celsius" }\n  }\n]'
  }, {
    phase: "you run it",
    role: "tool execution",
    kind: "code",
    who: "your code; the model never runs anything",
    body: '→ GET https://api.weather.example/v1/Tokyo\n← 200 { "temp": 12, "conditions": "cloudy" }'
  }, {
    phase: "result goes back",
    role: "tool",
    kind: "tool",
    who: "appended to the conversation",
    body: 'tool_result: { "temp": 12, "conditions": "cloudy" }'
  }, {
    phase: "model answers",
    role: "assistant",
    kind: "model",
    who: "the model, now with the fact it needed",
    body: "It's 12°C and cloudy in Tokyo right now."
  }];
  const [active, setActive] = useState(0);
  const [playing, setPlaying] = useState(false);
  const timer = useRef(null);
  const stop = () => {
    clearInterval(timer.current);
    timer.current = null;
    setPlaying(false);
  };
  useEffect(() => () => clearInterval(timer.current), []);
  const play = () => {
    if (playing) return stop();
    setActive(0);
    setPlaying(true);
    timer.current = setInterval(() => {
      setActive(a => {
        if (a >= STEPS.length - 1) {
          clearInterval(timer.current);
          timer.current = null;
          setPlaying(false);
          return a;
        }
        return a + 1;
      });
    }, 1100);
  };
  const go = fn => () => {
    stop();
    setActive(fn);
  };
  return <DiagramFrame eyebrow="Tool use" title="The model asks, your code answers" caption="A tool call is not the model reaching out to the internet. It is the model emitting a structured request and stopping. Your code executes it, appends the result to the conversation, and calls the model again. Steps two to four repeat until the model replies without asking for a tool." css={CSS} controls={<div className="btn-row">
          <button className="btn" onClick={go(a => Math.max(0, a - 1))} disabled={active === 0}>
            Back
          </button>
          <button className="btn btn--accent" onClick={go(a => Math.min(STEPS.length - 1, a + 1))} disabled={active >= STEPS.length - 1}>
            Next step
          </button>
          <button className={"btn" + (playing ? " btn--on" : "")} onClick={play}>
            {playing ? "Stop" : "Play"}
          </button>
          <button className="btn" onClick={go(0)} disabled={active === 0}>
            Reset
          </button>
        </div>} readout={<span>
          step <strong>{active + 1}</strong> / {STEPS.length}
        </span>}>
      <div className="loop">
        <div>
          <div className="loop__phases">
            {STEPS.map((s, i) => <span key={i} style={{
    display: "contents"
  }}>
                {i > 0 && <span className="loop__arrow">→</span>}
                <span className={"loop__phase" + (i === active ? " is-now" : i < active ? " is-done" : "")}>
                  {s.phase}
                </span>
              </span>)}
          </div>
          <div className="loop__hint" style={{
    marginTop: 8
  }}>
            steps 2–4 repeat for every tool the model wants
          </div>
        </div>

        <div className="loop__steps">
          {STEPS.slice(0, active + 1).map((s, i) => <div key={i} className={"loop__step is-" + s.kind + (i === active ? " is-active" : "")}>
              <div className="loop__role">
                <span>{s.role}</span>
                <span className="loop__who">{s.who}</span>
              </div>
              <div className="loop__body">{s.body}</div>
            </div>)}
          {active >= 3 && active < STEPS.length - 1 && <div className="loop__back">↩ conversation goes back to the model, one turn longer</div>}
        </div>
      </div>
    </DiagramFrame>;
};

export const Legend = ({items}) => <ul className="legend">
    {items.map((it, i) => <li className="legend__item" key={i}>
        <span className="legend__sw" style={it.style || ({
  background: it.color
})} />
        {it.label}
      </li>)}
  </ul>;

export const Slider = ({label, value, display, min, max, step = 1, onChange}) => <label className="slider-group">
    <span className="slider-group__label">
      {label}
      <span className="slider-group__value">{display === undefined ? value : display}</span>
    </span>
    <input type="range" min={min} max={max} step={step} value={value} onChange={e => onChange(parseFloat(e.target.value))} />
  </label>;

export const DiagramFrame = ({eyebrow, title, caption, css, controls, readout, children}) => {
  const BASE_CSS = `
.learn-diagram {
  /* ── Together AI brand palette ── */
  --tg-orange: #FC4C02;
  --tg-orange-dark: #972E02;
  --tg-orange-soft: #FEE8DF;
  --tg-orange-tint: #FFDCCD;
  --tg-pink: #EF2CC1;
  --tg-pink-soft: #FDE3F6;
  --tg-purple: #A373ED;
  --tg-purple-mid: #CAAEF5;
  --tg-purple-soft: #EDE4FC;
  --tg-blue: #3D99F5;
  --tg-blue-mid: #A3D1FF;
  --tg-blue-soft: #E5F3FF;
  --tg-slate: #5E86AE;
  --tg-slate-soft: #EEF3F6;
  --tg-navy: #010120;

  /* ── Surfaces ── */
  --color-paper:   #FFFFFF;
  --color-paper-2: #F7F8FA;
  --color-paper-3: #F0F1F4;
  --color-paper-4: #E2E4E9;
  /* ── Ink ── */
  --color-ink:       #090909;
  --color-ink-soft:  #414B58;
  --color-ink-mute:  #626B84;
  --color-ink-faint: #98A0B3;
  /* ── Lines ── */
  --color-rule:        #C4C9D4;
  --color-rule-soft:   #E2E4E9;
  --color-rule-strong: #98A0B3;
  /* ── Accent ── */
  --color-accent:      var(--tg-orange);
  --color-accent-soft: var(--tg-orange-soft);
  --color-empty:       #F0F1F4;

  /* ── Type ── */
  --font-display: 'Jost', 'Helvetica Neue', Arial, sans-serif;
  --font-body:    'The Future', 'Jost', 'Helvetica Neue', Arial, sans-serif;
  --font-mono:    'The Future Mono', ui-monospace, 'SFMono-Regular', 'Courier New', monospace;

  /* ── Spacing (4px base) ── */
  --space-3xs: 4px;
  --space-2xs: 8px;
  --space-xs:  12px;
  --space-sm:  16px;
  --space-md:  24px;
  --space-lg:  32px;

  /* ── Radius ── */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;

  /* ── Motion ── */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-slow: 360ms;
  --focus-ring: 0 0 0 3px rgba(252, 76, 2, 0.35);

  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.65;
  font-weight: 400;
  color: var(--color-ink);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
  margin: 24px 0;
}
.learn-diagram, .learn-diagram * { box-sizing: border-box; }

/* ============ SHELL ============ */
.learn-diagram .diagram {
  margin: 0;
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg);
  padding: var(--space-md);
  box-shadow: 0 1px 2px rgba(9, 9, 9, 0.04), 0 2px 10px rgba(9, 9, 9, 0.03);
}
.learn-diagram .diagram__head { margin-bottom: var(--space-md); }
.learn-diagram .diagram__eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tg-orange);
  margin-bottom: 6px;
}
.learn-diagram .diagram__title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--color-ink);
  margin: 0;
}
.learn-diagram .diagram__caption {
  font-size: 13px;
  line-height: 1.55;
  color: var(--color-ink-mute);
  margin: 6px 0 0;
  max-width: 68ch;
}
.learn-diagram .diagram__controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
  align-items: center;
  margin-top: var(--space-md);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-rule-soft);
}
.learn-diagram .diagram__readout {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-mute);
  margin-left: auto;
}
.learn-diagram .diagram__readout strong {
  color: var(--tg-orange);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ============ BUTTONS ============ */
.learn-diagram .btn {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  padding: 9px 14px;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-paper);
  color: var(--color-ink);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-fast) ease, border-color var(--dur-fast) ease,
              color var(--dur-fast) ease;
}
.learn-diagram .btn:hover:not([disabled]) { background: var(--color-paper-3); }
.learn-diagram .btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.learn-diagram .btn[disabled] { opacity: 0.4; cursor: not-allowed; }
.learn-diagram .btn--accent {
  background: var(--tg-orange);
  border-color: var(--tg-orange);
  color: #fff;
}
.learn-diagram .btn--accent:hover:not([disabled]) {
  background: var(--tg-orange-dark);
  border-color: var(--tg-orange-dark);
}
.learn-diagram .btn--on {
  background: var(--tg-orange-soft);
  border-color: var(--tg-orange);
  color: var(--tg-orange-dark);
}
.learn-diagram .btn-row { display: flex; flex-wrap: wrap; gap: var(--space-2xs); flex: 0 0 auto; }

/* ============ SLIDERS ============ */
.learn-diagram .slider-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 190px;
  flex: 1 1 190px;
}
.learn-diagram .slider-group__label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-mute);
  display: flex;
  justify-content: space-between;
  gap: var(--space-2xs);
}
.learn-diagram .slider-group__value {
  color: var(--tg-orange);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  text-transform: none;
}
.learn-diagram input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 2px;
  background: var(--color-rule);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
  margin: 8px 0 2px;
}
.learn-diagram input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  background: var(--tg-orange);
  border-radius: 50%;
  border: 2px solid var(--color-paper);
  box-shadow: 0 1px 3px rgba(9, 9, 9, 0.18);
}
.learn-diagram input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  background: var(--tg-orange);
  border-radius: 50%;
  border: 2px solid var(--color-paper);
}
.learn-diagram input[type="range"]:focus-visible { box-shadow: var(--focus-ring); }

/* ============ PANELS · STATS · LEGEND ============ */
.learn-diagram .panel {
  background: var(--color-paper-2);
  border: 1px solid var(--color-rule-soft);
  border-radius: var(--radius-md);
  padding: var(--space-sm);
}
.learn-diagram .panel__head {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-mute);
  margin-bottom: var(--space-2xs);
}
.learn-diagram .stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs) var(--space-md);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-ink-mute);
}
.learn-diagram .stats strong {
  color: var(--tg-orange);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.learn-diagram .legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs) var(--space-md);
  list-style: none;
  margin: var(--space-sm) 0 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--color-ink-soft);
}
.learn-diagram .legend__item { display: flex; align-items: center; gap: 6px; }
.learn-diagram .legend__sw {
  width: 12px;
  height: 12px;
  border-radius: 2px;
  flex: none;
  display: inline-block;
}
.learn-diagram .tag {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  background: var(--color-paper-3);
  color: var(--color-ink-soft);
  white-space: nowrap;
}
.learn-diagram .tag--accent { background: var(--tg-orange-soft); color: var(--tg-orange-dark); }
.learn-diagram .tag--muted { background: transparent; border: 1px dashed var(--color-rule); color: var(--color-ink-faint); }
.learn-diagram .note {
  font-size: 13px;
  line-height: 1.55;
  color: var(--color-ink-mute);
}
.learn-diagram code, .learn-diagram .mono { font-family: var(--font-mono); font-size: 13px; }

@media (prefers-reduced-motion: reduce) {
  .learn-diagram *, .learn-diagram *::before, .learn-diagram *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }
}
`;
  return <div className="learn-diagram">
    <style>{BASE_CSS}</style>
    {css ? <style>{css}</style> : null}
    <figure className="diagram">
      {(eyebrow || title || caption) && <div className="diagram__head">
          {eyebrow && <div className="diagram__eyebrow">{eyebrow}</div>}
          {title && <h3 className="diagram__title">{title}</h3>}
          {caption && <p className="diagram__caption">{caption}</p>}
        </div>}
      <div className="diagram__inner">{children}</div>
      {(controls || readout) && <div className="diagram__controls">
          {controls}
          {readout && <span className="diagram__readout">{readout}</span>}
        </div>}
    </figure>
  </div>;
};

**TL;DR:** A model can't actually call functions or APIs to do things in the real world, only output tokens. Instead, you ask the model to output a structured message that says "I want to call this function with these arguments." The software around the LLM is the part that actually runs the call, gets the result, and feeds it back to the model as the next message in the conversation. The model picks things back up from there. Function calling is a structured multi-turn conversation where some of the turns happen to be machine-readable JSON or executable functions instead of natural language. This is the mechanism that every coding agent (Claude Code, Cursor, Codex) and agentic workflow is built on top of.

## The model plans, your code runs the tool

"Function calling" is one of those names that slightly exaggerates: the model can't *actually* execute functions. The model itself has no internet, no shell, no file system, and no way to execute code. It can't run Python, query a database, or call an API on its own. The only thing the model can produce is text.

The cleanest way to think about what's going on is in terms of roles:

* **The model is the planner.** It looks at the conversation, reasons about what should happen next, and either writes a reply to the user or asks for a tool to be run. The model itself can't actually run anything.
* **Your code is the worker.** It sees the model's request, decides whether to honor it, and if so, runs the function, handing the result back as the next message in the conversation.

Completing long, complex tasks takes many turns of reasoning and function calls.

## The loop

One complete tool-using interaction usually looks something like this:

```text theme={null}
USER:       What's the weather in Tokyo right now?

MODEL:      tool_calls: [
              { name: "get_weather",
                arguments: {"city":"Tokyo","units":"celsius"} }
            ]

YOUR CODE:  → fetch https://api.weather.example/v1/Tokyo
            ← { "temp": 12, "conditions": "cloudy" }

TOOL MSG:   { "temp": 12, "conditions": "cloudy" }

MODEL:      It's 12°C and cloudy in Tokyo right now.
```

The model never runs the weather API itself. It asks your code to run it, then waits. Your code runs the API call, and the result becomes a new message in the conversation. The model sees that result and picks up from there to write the final reply.

<ToolLoopDiagram />

## How to tell the model what tools are available

Tools are declared in the API request alongside the messages. Each tool has a name, a description, and a JSON schema for its arguments:

```json theme={null}
[
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get the current weather in a city.",
      "parameters": {
        "type": "object",
        "properties": {
          "city":  { "type": "string", "description": "City name" },
          "units": { "type": "string", "enum": ["celsius","fahrenheit"] }
        },
        "required": ["city"]
      }
    }
  }
]
```

The model sees these declarations as part of its prompt. The descriptions you write matter quite a bit, because they are how the model decides which tool is right for a given question. A description like "Get the current weather" is much more useful to the model than something like "Weather function". A useful rule of thumb is to write the description as if you were writing a one-line manual page for another developer.

You can declare as many tools as you want, but more is not always better. With dozens of tools available, the model often starts picking the wrong one or stalling. If you have a lot of capabilities, it usually helps to group them. One `search` tool that takes a query argument tends to work better than twenty narrow tools that each cover a single search type.

<Tip>
  See [Function calling](/docs/inference/function-calling/overview) for the request format and the list of models that support tool calls on Together AI.
</Tip>

## What the model emits

When the model wants to call a tool, the API response includes a `tool_calls` field instead of (or in addition to) a text answer:

```json theme={null}
{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_abc123",
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": "{\"city\":\"Tokyo\",\"units\":\"celsius\"}"
      }
    }
  ]
}
```

Two things worth noticing here. The arguments come back as a JSON string, not as an already-parsed object. You parse the string yourself, and you should also validate it, because the model can hallucinate fields or incorrect types. Each call also has an `id`. When you send the results back to the model, you include the same `id` so the model knows which call the result belongs to. This matters when the model emits multiple parallel tool calls in a single turn.

After your code has run the tool, you send the result back as a new message with `role: "tool"`:

```json theme={null}
{
  "role": "tool",
  "tool_call_id": "call_abc123",
  "content": "{\"temp\":12,\"conditions\":\"cloudy\"}"
}
```

Then you call the model again with the full message history. The model sees the tool result and produces the next message, which is either another tool call or the final answer to the user.

## Multi-step agent loops

Real tasks can rarely be completed with a single tool call. A coding agent task like "fix the failing test in `auth.py`" unfolds across many rounds:

1. The model calls `read_file("auth.py")` and `read_file("test_auth.py")`.
2. Your code returns the file contents.
3. The model calls `run_tests("test_auth.py")` to see the failure.
4. Your code returns the failure output.
5. The model reasons about the bug, then calls `edit_file("auth.py", ...)`.
6. Your code applies the edit and returns confirmation.
7. The model re-runs the tests to verify.
8. Your code returns the passing test output.
9. The model writes a final summary message to the user.

This sequence is what people typically call an **agent loop,** and is the basic underlying process for coding agents like Claude Code. Your application keeps calling the model in a loop, and each time it does, it passes in the full message history plus any new tool results. The loop continues until the model decides it is done, which is the point at which it produces a normal text reply with no tool calls in it.

There are two important guardrails for any agent loop:

* **Step limit:** Cap the number of times the loop will iterate before giving up. Models can sometimes spiral into tool-call loops if they get confused. A ceiling of 20–50 steps is reasonable for most tasks, but coding agents often go higher.
* **Tool authorization:** A tool request is not authorization. Even when the model asks for a tool to be run, your code does not have to comply. For anything irreversible (sending money, deleting data, force-pushing to main), your code should require human confirmation before honoring the call.

<Info>
  The **Model Context Protocol (MCP)** has emerged as the standard way to expose tools to any compatible model without redeclaring them per-provider. Tools live as standalone MCP servers, and any MCP-aware model can pick them up via a single connection. Most production coding agents and chat clients now speak MCP, which means you can write a tool once and use it from Claude, ChatGPT, Cursor, and others without changes.
</Info>

## How it goes wrong

There are five common ways tool use breaks in practice:

* **Hallucinated arguments:** The model produces arguments that do not match the schema. There might be a missing field, a wrong type, or a city that does not actually exist. You should always validate the arguments before executing the call, rather than blindly trusting what the model produces.
* **Tool-call loops:** The model keeps calling the same tool with slightly different arguments and getting back the same kind of answer. The common cause is a tool result that is vague or unhelpful, which leads the model to think it didn't get what it asked for. The fix is to make tool outputs explicit ("Found 0 results matching 'cat photos' uploaded after 2024-01-01") or to set a step limit on the loop.
* **Picked the wrong tool:** Two tools have overlapping descriptions and the model picks the wrong one. The fix is to disambiguate the descriptions or merge the two tools into one.
* **Skipped a tool when it should have used one:** The model answers from its training knowledge when fresh data was needed. The fix is to strengthen the system prompt with something like "Always use `lookup_price` before quoting a price".
* **Parallel calls when serial was intended:** Modern models often emit multiple tool calls in a single turn. Make sure your executor can handle them in parallel and that it matches results back to calls using the `id` field.

## Next steps

<CardGroup cols={3}>
  <Card title="Structured outputs & JSON mode" icon="braces" href="/learn/structured-outputs">
    The same constrained-decoding plumbing, but for non-tool outputs.
  </Card>

  <Card title="Context engineering" icon="messages" href="/learn/prompt-engineering">
    How the system prompt steers tool selection.
  </Card>

  <Card title="Context windows" icon="layout-board" href="/learn/context-windows">
    Agent loops grow the message history fast.
  </Card>
</CardGroup>
