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

# Function calling

> Let models request application functions safely with JSON schemas, validated arguments, and tool-result messages.

Function calling lets a model request a named application operation with structured arguments. Your code—not the model—decides whether to execute the function and returns the result for a final response.

## Define and request a tool

The following request gives the model one read-only weather function. It intentionally stops after the model's tool request so you can inspect and validate the arguments.

<CodeGroup>
  ```bash Curl theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl https://api.yelu.ai/v1/chat/completions \
    -H "Authorization: Bearer $YELU_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gpt-4o-mini",
      "messages": [{"role":"user","content":"What is the weather in Shanghai?"}],
      "tools": [{
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Get current weather for a city",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type":"string","description":"City name"},
              "unit": {"type":"string","enum":["celsius","fahrenheit"]}
            },
            "required": ["city", "unit"],
            "additionalProperties": false
          }
        }
      }],
      "tool_choice": "auto"
    }'
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const body = {
    model: 'gpt-4o-mini',
    messages: [{ role: 'user', content: 'What is the weather in Shanghai?' }],
    tools: [{
      type: 'function',
      function: {
        name: 'get_weather',
        description: 'Get current weather for a city',
        parameters: {
          type: 'object',
          properties: {
            city: { type: 'string', description: 'City name' },
            unit: { type: 'string', enum: ['celsius', 'fahrenheit'] },
          },
          required: ['city', 'unit'],
          additionalProperties: false,
        },
      },
    }],
    tool_choice: 'auto',
  };

  const response = await fetch('https://api.yelu.ai/v1/chat/completions', {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.YELU_API_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error(await response.text());
  console.log((await response.json()).choices[0].message.tool_calls);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import os
  import requests

  payload = {
      "model": "gpt-4o-mini",
      "messages": [{"role": "user", "content": "What is the weather in Shanghai?"}],
      "tools": [{
          "type": "function",
          "function": {
              "name": "get_weather",
              "description": "Get current weather for a city",
              "parameters": {
                  "type": "object",
                  "properties": {
                      "city": {"type": "string", "description": "City name"},
                      "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                  },
                  "required": ["city", "unit"],
                  "additionalProperties": False,
              },
          },
      }],
      "tool_choice": "auto",
  }
  response = requests.post(
      "https://api.yelu.ai/v1/chat/completions",
      headers={"Authorization": f"Bearer {os.environ['YELU_API_KEY']}"},
      json=payload,
      timeout=60,
  )
  response.raise_for_status()
  print(response.json()["choices"][0]["message"].get("tool_calls"))
  ```
</CodeGroup>

## Complete the tool loop

<Steps>
  <Step title="Inspect the assistant message">
    If `finish_reason` is `tool_calls`, read every item in `message.tool_calls`. A model can request more than one call.
  </Step>

  <Step title="Validate arguments">
    Parse `function.arguments` as JSON and validate it against your own schema, permissions, value ranges, and business rules. Treat it as untrusted input.
  </Step>

  <Step title="Execute with safeguards">
    Map the exact allowlisted function name to application code. Apply authentication, authorization, deadlines, idempotency, and rate limits.
  </Step>

  <Step title="Return tool results">
    Append the assistant tool-call message and one `role: tool` message per call, matching `tool_call_id`. Then request the final assistant response.
  </Step>
</Steps>

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "role": "tool",
  "tool_call_id": "call_01JYELU",
  "content": "{\"city\":\"Shanghai\",\"temperature\":31,\"unit\":\"celsius\",\"condition\":\"cloudy\"}"
}
```

## Security rules

* Never use `eval`, reflection, or arbitrary shell execution on a generated function name.
* Require user confirmation for purchases, messages, deletion, permission changes, or other consequential actions.
* Bind tools to the authenticated user and re-check authorization at execution time.
* Limit argument length and recursive JSON depth.
* Remove secrets and unnecessary internal details from tool results.
* Cap loop iterations and detect repeated identical calls.
* Record an audit event for state-changing tools.

<Warning>
  A JSON schema improves argument shape; it does not make the requested action safe or correct. Application-side validation and authorization remain mandatory.
</Warning>
