Skip to content

Tool calling

Let the model call your functions. Works with both the OpenAI SDK and the Anthropic SDK.

POST/v1/chat/completions

Tool calling (function calling) lets the model return structured arguments to invoke functions you declare, instead of answering directly. Your code can run things the model can't — external API lookups, database queries, calculations — and feed the result back. PleumRouter accepts OpenAI-format tools, and when a request is routed to an Anthropic (Claude) model the router automatically translates them to Anthropic's tool format — you don't change the request shape.

Request#

ParameterTypeRequiredDescription
toolsarrayOptionalList of functions the model may call. Use OpenAI format [{"type": "function", "function": {"name", "description", "parameters"}}], where parameters is a JSON Schema.
tool_choicestring | objectOptional"auto" (model decides) · "required" (must call a tool) · "none" (no tools), or {"type": "function", "function": {"name": "..."}} to force a specific function.
parallel_tool_callsbooleanOptionalWhether the model may call multiple tools in one response. Applies to OpenAI-compatible providers only; it is not translated for Anthropic.

Call POST /v1/chat/completions with tools and (optionally) tool_choice in the request body. Authenticate with your plm_ API key via the Authorization: Bearer or x-api-key header.

request
curl https://apirouter.pleum.ai/v1/chat/completions \
  -H "Authorization: Bearer $PLEUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o",
    "messages": [
      {"role": "user", "content": "What is the weather in Seoul?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Get the current weather for a city.",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string", "description": "City name, e.g. Seoul"},
              "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["city"]
          }
        }
      }
    ],
    "tool_choice": "auto"
  }'

Response#

When the model decides to call a tool, choices[0].message.content is null and the message.tool_calls array holds the function(s) and arguments. arguments is a JSON string, so parse it before use. In this case finish_reason is "tool_calls". Every chat response also includes the PleumRouter extensions cost (KRW cost, FX rate, markup) and request_id.

200 OK (tool_calls)
{
  "id": "chatcmpl-gpt-4o-612ms",
  "object": "chat.completion",
  "model": "gpt-4o",
  "provider": "openai",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\": \"Seoul\", \"unit\": \"celsius\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 78,
    "completion_tokens": 21,
    "total_tokens": 99
  },
  "cost": {
    "usd": 0.000396,
    "krw": 1,
    "fx_rate": 1525.0,
    "markup_rate": 0.0
  },
  "request_id": "req_01J9X2Qm7..."
}

Multi-turn loop#

After receiving tool_calls, run the function(s) in your code, then call again with the same messagesarray extended with the model's assistant message (including tool_calls) and the result as a role: "tool" message. The tool message carries tool_call_id, name, and the result in content. Repeat this loop until the model produces a final answer.

follow-up request body
{
  "model": "gpt-4o",
  "messages": [
    {"role": "user", "content": "What is the weather in Seoul?"},
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"city\": \"Seoul\", \"unit\": \"celsius\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_abc123",
      "name": "get_weather",
      "content": "{\"temp\": 21, \"unit\": \"celsius\", \"sky\": \"clear\"}"
    }
  ],
  "tools": [
    {"type": "function", "function": {"name": "get_weather", "description": "Get the current weather for a city.", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}}, "required": ["city"]}}}
  ]
}
parallel_tool_callsis OpenAI-compatible providers only. Anthropic (Claude) models are handled automatically — the router translates the tool format for you, so you don't change the request — but this flag is not forwarded to Anthropic.