# Function calling

> Give the model your own tools. It returns calls with JSON arguments, you run them and send the results back.


Declare tools with a JSON Schema. The model may answer with text or with one or more tool calls. You run the tool on your side and send the result in a `tool` message.

```python test
import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.notholy.com/v1", api_key=os.environ["NOTHOLY_API_KEY"])
tools = [{
    "type": "function",
    "function": {
        "name": "get_cvss",
        "description": "Return the CVSS base score of a CVE",
        "parameters": {"type": "object", "properties": {"id": {"type": "string"}}, "required": ["id"]},
    },
}]
messages = [{"role": "user", "content": "What is the CVSS score of CVE-2021-44228?"}]
r = client.chat.completions.create(model="notholy-specter", messages=messages, tools=tools)
msg = r.choices[0].message
if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps({"id": args["id"], "cvss": 10.0})})
    r = client.chat.completions.create(model="notholy-specter", messages=messages, tools=tools)
print(r.choices[0].message.content)
```

```js test
import OpenAI from 'openai';

const client = new OpenAI({ baseURL: 'https://api.notholy.com/v1', apiKey: process.env.NOTHOLY_API_KEY });

const tools = [{
  type: 'function',
  function: { name: 'lookup_port', description: 'Service usually found on a TCP port', parameters: { type: 'object', properties: { port: { type: 'integer' } }, required: ['port'] } },
}];
const r = await client.chat.completions.create({
  model: 'notholy-specter',
  messages: [{ role: 'user', content: 'What usually runs on port 5432?' }],
  tools,
});
const m = r.choices[0].message;
console.log(m.tool_calls ? m.tool_calls.map((c) => `${c.function.name}(${c.function.arguments})`).join('\n') : m.content);
```

## Notes

- Only `function` tools are supported. Built-in server tools are not run.
- `tool_choice` accepts `auto`, `none`, `required` or a named function.
- In Messages, tool calls arrive whole. In the OpenAI formats, arguments stream as deltas.
- Tool results are content you control. Treat what a tool returns from the outside world as data.

## Next

- [Reasoning](/en/guides/reasoning)
