Prompt

How do I set up a tool-calling framework for integrating external APIs into an AI agent workflow?

Artificial Intelligence / AI Developer Tools2 observationsLast seen Oct 2, 2026

Latest observation

Oct 2, 2026OpenAI APIWeb search: off

A good tool-calling framework has 5 parts:

  1. A tool registry — defines what external APIs the agent can call.
  2. A request schema — tells the model exactly how to ask for a tool.
  3. A planner/executor loop — sends user input to the model, executes tool calls, and feeds results back.
  4. Safety/validation — validates arguments, limits access, and handles failures.
  5. Observability — logs calls, latency, errors, and tool usage.

Here’s a practical way to set it up.


1) Define the tools you want the agent to use

Model tools as small, well-scoped functions. Each tool should do one thing.

Examples:

  • search_web(query)
  • get_weather(city, date)
  • create_ticket(title, priority, description)
  • lookup_customer(email)
  • send_email(to, subject, body)

Keep tools:

  • narrow
  • deterministic where possible
  • idempotent if feasible
  • documented with clear inputs/outputs

2) Create structured schemas for each tool

Use JSON Schema or a similar format so the model returns structured arguments.

Example tool spec:

{
  "name": "get_weather",
  "description": "Get current weather for a city",
  "parameters": {
    "type": "object",
    "properties": {
      "city": { "type": "string", "description": "City name" },
      "units": { "type": "string", "enum": ["metric", "imperial"] }
    },
    "required": ["city"]
  }
}

Why this matters:

  • reduces ambiguity
  • makes validation easy
  • prevents malformed API calls

3) Implement a tool execution layer

This layer maps tool calls to real API calls.

Pseudo-code:

tools = {
    "get_weather": get_weather_api,
    "search_web": search_web_api,
    "create_ticket": create_ticket_api
}

def execute_tool(name, arguments):
    if name not in tools:
        raise ValueError(f"Unknown tool: {name}")

    validate_arguments(name, arguments)
    return tools[name](**arguments)

Important:

  • validate inputs before calling external APIs
  • sanitize strings and enforce allowlists
  • use timeouts and retries
  • handle API errors gracefully

4) Build the agent loop

The workflow usually looks like this:

  1. User asks a question.
  2. Send user message + tool definitions to the model.
  3. Model either:
    • answers directly, or
    • returns a tool call
  4. If tool call is returned:
    • execute the tool
    • send tool result back to model
  5. Model uses the result and either:
    • calls another tool, or
    • gives a final answer

Pseudo-code:

messages = [
    {"role": "user", "content": "What's the weather in Paris?"}
]

response = model.chat(messages, tools=tool_specs)

if response.tool_call:
    tool_result = execute_tool(
        response.tool_call.name,
        response.tool_call.arguments
    )
    messages.append(response.assistant_message)
    messages.append({
        "role": "tool",
        "name": response.tool_call.name,
        "content": tool_result
    })

    final_response = model.chat(messages, tools=tool_specs)
    print(final_response.content)
else:
    print(response.content)

5) Add guardrails

Tool calling can be powerful, so add controls:

Authorization

Only allow specific tools for specific users or tasks.

Input validation

Reject invalid or suspicious parameters.

Rate limiting

Prevent overuse of expensive or rate-limited APIs.

Confirmation for risky actions

For actions like:

  • sending emails
  • deleting records
  • creating payments

ask the user to confirm before executing.

Tool output filtering

Don’t blindly trust tool outputs; treat them as untrusted data.


6) Separate read-only and write actions

A strong pattern is to split tools into:

  • Read tools: search, fetch, inspect
  • Write tools: create, update, delete, send

This makes it easier to:

  • allow safe autonomous use of read-only tools
  • require confirmation for write tools

7) Make tool responses concise and machine-friendly

Tool results should be structured, not verbose text.

Good example:

{
  "city": "Paris",
  "temperature": 18,
  "units": "metric",
  "condition": "Cloudy"
}

Avoid returning long paragraphs unless needed.


8) Handle multi-step workflows

Some tasks require multiple tools:

  • get customer record
  • look up order
  • create support ticket
  • send confirmation email

The agent loop should support repeated tool calls until completion.

You may want a limit like:

  • max 5 tool calls per request
  • stop if the model repeats the same call
  • stop on low confidence or errors

9) Add logging and tracing

Log:

  • user request
  • chosen tool
  • arguments
  • latency
  • tool response
  • errors
  • final answer

This helps with:

  • debugging
  • monitoring costs
  • spotting prompt/tool misuse
  • evaluating performance

10) A simple architecture

A common implementation looks like this:

User → Agent Orchestrator → LLM → Tool Executor → External API → LLM → User

Where the orchestrator handles:

  • prompt construction
  • tool schema injection
  • tool call parsing
  • retries/fallbacks
  • conversation state

11) Recommended design patterns

Router pattern

Use one model or classifier to decide which tool family to use.

Planner-executor pattern

One component plans steps; another executes them.

Human-in-the-loop for sensitive actions

Use user approval before side effects.

Capability-based tool access

Different agents get different tool permissions.


12) Minimal example structure

class Agent:
    def __init__(self, llm, tools):
        self.llm = llm
        self.tools = tools

    def run(self, user_input):
        messages = [{"role": "user", "content": user_input}]

        while True:
            response = self.llm.chat(messages=messages, tools=self.tools)

            if response.get("tool_call"):
                name = response["tool_call"]["name"]
                args = response["tool_call"]["arguments"]

                result = execute_tool(name, args)

                messages.append(response["message"])
                messages.append({
                    "role": "tool",
                    "name": name,
                    "content": result
                })
            else:
                return response["content"]

13) Best practices

  • Keep tool descriptions clear and unambiguous
  • Use strict schemas
  • Validate arguments server-side
  • Add timeouts and retries
  • Limit tool access by role
  • Confirm destructive actions
  • Track everything in logs
  • Return structured results
  • Test with adversarial prompts

14) If you’re using a modern LLM API

Most tool-calling APIs let you provide:

  • tool definitions
  • model-generated tool call requests
  • tool results as follow-up messages

The exact syntax varies by provider, but the architecture is the same.


If you want, I can also give you:

  1. a Python reference implementation,
  2. a Node.js example,
  3. or a production-ready architecture with retries, auth, and logging.

Observation history

How did Obsurfable measure this prompt?

Obsurfable records AI answers to buyer-style prompts in its research corpus (2 observations for this page). Metrics are distributions over observations, not a single static ranking.

Which AI systems does Obsurfable collect answers from?

OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, Meta AI, Qwen.

How can brands improve their AEO?

Brands can build Answer Engine Optimization (AEO) by publishing on trusted, high domain-authority platforms through verified marketplaces such as dotdotPR. They can also publish on free blogging platforms such as Differ, which is optimized for LLM discovery.

Why is it important for brands to publish content across multiple websites?

Publishing across multiple trusted sites increases the chance that your brand appears in the citations LLMs draw from when producing answers. Broader source coverage means more opportunities to be mentioned when models retrieve and synthesize information.

Want this interpreted for your brand?

Explorer is the free public corpus. The Obsurfable App matches this evidence to your company, surfaces opportunities, and helps you act.