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

# Function calling across GPT, Gemini, and Grok

> Two-turn function calling examples for Chat Completions and Responses, which endpoint each model needs, and the GPT-6 and multi-turn rules.

With function calling, the model replies with the function it wants to call and the arguments. Your code runs the function and sends the result back, and the model writes the final answer. LaoZhang API's OpenAI-compatible endpoints use the same `tools` format for most text models, so switching models only means changing `model`.

| Item | Details |
| - | - |
| Base URL | `https://api.laozhang.ai/v1` |
| Endpoints | Chat Completions `/v1/chat/completions`; Responses `/v1/responses` |
| Billing | Model token prices; each of the two requests is billed. There is no separate function-calling fee. |
| Model prices | [Models and pricing](/en/models) |

## Which endpoint each model needs

Results from October 14, 2026, running the same weather function through a full call → result → final answer round trip:

| Model | Chat Completions | Responses |
| - | - | - |
| `gpt-6.1-sol` | No tools | Works |
| `gpt-6-sol` | Needs `reasoning_effort: "none"` | Works |
| `gpt-5.6-luna`, `gpt-5.4-mini` | Works | Works, with the [multi-turn pattern](#send-history-back-to-responses) below |
| `grok-4.5` | Works | Works |
| `gemini-4-argon`, `gemini-3.8-flash` | Works | Not supported |
| `deepseek-v4-pro`, `deepseek-v4-flash` | Works | Not supported |
| `qwen3.7-max`, `glm-5.2`, `kimi-k2.5`, `MiniMax-M2.5` | Works | — |

Use Chat Completions for models marked "—", and whenever you're unsure. Use Responses for the GPT-6 family. Gemini also supports `functionDeclarations` in native `generateContent`; see the [Gemini protocol](/en/api-reference/gemini).

## Chat Completions example

Install the SDK (`python -m pip install openai`) and set the `LAOZHANG_API_KEY` environment variable first.

```python theme={null}
import json
import os

from openai import OpenAI

client = OpenAI(api_key=os.environ["LAOZHANG_API_KEY"], base_url="https://api.laozhang.ai/v1")
MODEL = "gpt-5.4-mini"

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]


def get_weather(city):
    return {"city": city, "temp_c": 18, "sky": "cloudy"}  # replace with your implementation


messages = [{"role": "user", "content": "What's the weather in Paris right now?"}]
first = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = first.choices[0].message

if message.tool_calls:
    messages.append(message)
    for call in message.tool_calls:
        args = json.loads(call.function.arguments)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(get_weather(**args)),
        })
    second = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
    print(second.choices[0].message.content)
else:
    print(message.content)
```

`message.tool_calls` in the first reply holds the function name and its arguments as a JSON string. The second request sends back the model's message plus one `tool` message per call, and each `tool_call_id` must match the `id` of its call.

To use another model from the Chat Completions column, change `MODEL`; nothing else changes. For `gpt-6-sol`, also pass `reasoning_effort="none"` in both requests, or the API returns 400.

## Responses example

In Responses, a tool definition drops the nested `function` object, and results go back as `function_call_output` items:

```python theme={null}
import json
import os

from openai import OpenAI

client = OpenAI(api_key=os.environ["LAOZHANG_API_KEY"], base_url="https://api.laozhang.ai/v1")
MODEL = "gpt-6.1-sol"

tools = [{
    "type": "function",
    "name": "get_weather",
    "description": "Get the current weather for a city",
    "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
        "additionalProperties": False,
    },
    "strict": True,
}]

question = {"role": "user", "content": "What's the weather in Paris right now?"}
first = client.responses.create(model=MODEL, input=[question], tools=tools)

history = [question]
for item in first.output:
    if item.type != "function_call":
        continue
    args = json.loads(item.arguments)
    result = {"city": args["city"], "temp_c": 18, "sky": "cloudy"}  # replace with your implementation
    history.append({"type": "function_call", "call_id": item.call_id,
                    "name": item.name, "arguments": item.arguments})
    history.append({"type": "function_call_output", "call_id": item.call_id,
                    "output": json.dumps(result)})

second = client.responses.create(model=MODEL, input=history, tools=tools)
print(second.output_text)
```

### Send history back to Responses

Rebuild each `function_call` item from its `call_id`, `name`, and `arguments`, as the example does. Don't rely on conversation state stored on the server:

* Don't continue with `previous_response_id`.
* Don't paste the first response's `output` back into `input` unchanged.

On LaoZhang API, a model can be served by more than one official route, and two consecutive requests may land on different routes. Both patterns above point to objects stored on the earlier route, so they fail with HTTP 400 when the route changes:

* `The requested item was created under a different Azure OpenAI resource`
* `Previous response with id '...' not found`

Sending the content without item IDs avoids the problem.

## FAQ

### Why does `gpt-6.1-sol` return 400 when I pass tools?

OpenAI doesn't allow function tools together with reasoning in Chat Completions for `gpt-6.1-sol`, and this model doesn't accept `reasoning_effort: "none"`. Call it through Responses as shown above.

### What if the model returns several function calls at once?

Run each one and send each result back with its own `tool_call_id` (Chat Completions) or `call_id` (Responses). Both examples above already loop over every call.

### What if the arguments aren't valid JSON?

Validate them with `json.loads`. If parsing fails, send the error back as the function result so the model can try again. In Responses, `"strict": true` on the tool plus `"additionalProperties": false` in `parameters` keeps arguments within the schema.

### Is function calling billed separately?

No. Tool definitions and function results count as input tokens, and the generated arguments count as output tokens, at the model's price. Server-side tools such as [web search](/en/api-capabilities/web-search) add a per-search fee.

## Related documentation

* Let the model search the web and cite sources: [Web search](/en/api-capabilities/web-search)
* Choosing between Chat Completions and Responses, and GPT-6 parameter rules: [OpenAI models](/en/api-reference/openai#chat-completions-or-responses)
* Function calling in the native Gemini format: [Gemini protocol](/en/api-reference/gemini)

## References

* OpenAI: [Function calling](https://developers.openai.com/api/docs/guides/function-calling)
* Google: [Function calling with the Gemini API](https://ai.google.dev/gemini-api/docs/function-calling)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.