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

# Function calling data

> Generate function calls, with different tools and generation parameters for each row.

This recipe generates function calls for user requests. It also shows how to give each row of a dataset its own generation parameters, so that each request can see a different set of tools.

The full code is in the [function calling example](https://github.com/bespokelabsai/curator/tree/main/examples/function-calling) on GitHub.

<Steps>
  <Step title="Import the libraries">
    ```python theme={null}
    # pip install bespokelabs-curator
    import json
    from typing import Dict

    from datasets import Dataset

    from bespokelabs import curator
    ```
  </Step>

  <Step title="Define the function call generator">
    Set `return_completions_object = True` so that `parse` gets the full API response. The model may return a tool call or a plain message, so `parse` handles both.

    ```python theme={null}
    class FunctionCallGenerator(curator.LLM):
        """A simple function calling generator."""

        return_completions_object = True

        def prompt(self, input: Dict) -> str:
            return f"""You are a function calling expert. Given the user request:
            {input['user_request']}.
            Generate a function call that can be used to satisfy the user request.
            """

        def parse(self, input: Dict, response) -> Dict:
            message = response["choices"][0]["message"]
            if message.get("tool_calls"):
                input["function_call"] = str([tool_call["function"] for tool_call in message["tool_calls"]])
            else:
                # The model returned a message instead of a function call.
                input["function_call"] = message["content"]
            return input
    ```
  </Step>

  <Step title="Define the tools">
    This list defines two tools. The first gets the weather for a location, and the second gets the local time.

    ```python theme={null}
    function_docs = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "Retrieves current weather for the given location.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {"type": "string", "description": "City and country e.g. Bogotá, Colombia"},
                        "units": {
                            "type": "string",
                            "enum": ["celsius", "fahrenheit"],
                            "description": "Units the temperature will be returned in.",
                        },
                    },
                    "required": ["location", "units"],
                    "additionalProperties": False,
                },
                "strict": True,
            },
        },
        {
            "type": "function",
            "function": {
                "name": "get_local_time",
                "description": "Get the local time of a given location",
                "strict": True,
                "parameters": {
                    "type": "object",
                    "required": ["location", "timezone"],
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The name or coordinates of the location for which to get the local time",
                        },
                        "timezone": {
                            "type": "string",
                            "description": "The timezone of the location, defaults to the location's timezone if not provided",
                        },
                    },
                    "additionalProperties": False,
                },
            },
        },
    ]
    ```
  </Step>

  <Step title="Create the generator with default parameters">
    By default, every request can use both tools.

    ```python theme={null}
    llm = FunctionCallGenerator(
        model_name="gpt-4o-mini",
        generation_params={"tools": function_docs},
        backend_params={"max_retries": 1, "require_all_responses": False},
    )
    ```
  </Step>

  <Step title="Set generation parameters for each row">
    Add a `generation_params` column to the dataset. For each row, Curator starts from the default generation parameters and replaces the keys that the row sets.

    ```python theme={null}
    dataset = Dataset.from_dict(
        {
            "user_request": ["What's the current temperature in New York?", "What time is it in Tokyo?"],
            "generation_params": [
                json.dumps({"tools": [function_docs[0]]}),
                json.dumps({"tools": [function_docs[1]]}),
            ],
        }
    )
    ```

    Here the first row can use only the weather tool, and the second row can use only the time tool.

    <Warning>
      Store `generation_params` as a JSON string. If you store a dictionary, the `datasets` library splits its keys into separate columns. See [issue 325](https://github.com/bespokelabsai/curator/issues/325) for details.
    </Warning>
  </Step>

  <Step title="Run the generator">
    ```python theme={null}
    function_calls = llm(dataset)
    print(function_calls.dataset.to_pandas())
    ```

    Curator sends each row with its own tools, and the model returns a function call for each request.
  </Step>
</Steps>

You can use row-level parameters whenever different rows need different settings, e.g., to give each type of request only the tools it needs. In `parse`, always handle both tool calls and plain messages.
