Fine-Tuning Tool-Use Models for AI Agents: Data Preparation and Evaluation Guide



Fine-Tuning Tool-Use Models for AI Agents: Data Preparation and Evaluation Guide

Quick Answer / TL;DR

Fine-tuning tool-use models for AI agents involves preparing structured datasets that map user intents to specific tool calls, fine-tuning a base LLM on this data, and rigorously evaluating its ability to accurately invoke and use tools. This guide provides a step-by-step approach to data preparation, training strategies, and robust evaluation metrics to build highly capable and reliable AI agents.

The advent of large language models (LLMs) has revolutionized AI, enabling sophisticated natural language understanding and generation. However, their true power for AI agents emerges when they can move beyond mere text generation to interact with the real world – fetching real-time data, executing actions, or performing complex computations. This capability is powered by “tool-use models,” which allow LLMs to invoke external functions or APIs. To unlock specialized, highly reliable tool-use behavior, fine-tuning tool-use models for AI agents is often a critical step. This guide will walk you through the essential processes of data preparation and evaluation, equipping you with the knowledge to build more intelligent and effective AI agents.

What You Will Learn

Table of Contents

  1. Understanding Tool-Use Models in AI Agents
  2. The Data Preparation Pipeline for Fine-Tuning Tool-Use Models
  3. Strategies for Fine-Tuning Tool-Use Models
  4. Evaluating Fine-Tuned Tool-Use Models for Performance
  5. Frequently Asked Questions
  6. Further Reading

Understanding Tool-Use Models in AI Agents

At its core, a tool-use model empowers an AI agent to decide when to use a specific function and what arguments to pass to it, based on a user’s natural language request. Imagine an AI assistant that can book flights, check weather, or retrieve stock prices. Each of these actions typically corresponds to an external API call – a “tool.” The LLM, acting as the brain, interprets the user’s intent and generates a structured call to the appropriate tool.

This capability transforms LLMs from mere conversational interfaces into powerful orchestrators of action. Instead of hallucinating information or being limited to their training data, tool-use models allow agents to access real-time, accurate, and dynamic information and perform real-world tasks. The primary goal of fine-tuning these models is to improve their accuracy, reliability, and robustness in selecting and invoking tools, especially in domain-specific or complex scenarios.

This sets the stage for our journey: how do we teach an LLM to become an expert tool user? The answer lies in carefully crafted data and strategic fine-tuning.

The Data Preparation Pipeline for Fine-Tuning Tool-Use Models

The quality of your training data directly dictates the performance of your fine-tuned model. For tool-use models, data preparation is particularly nuanced, as it involves teaching the model to understand intent and translate it into structured function calls.

Data Collection & Annotation

The first step is gathering relevant examples of user queries and their corresponding desired tool actions.

  1. Define Your Tools: Clearly document all the tools (functions/APIs) your agent can access. Each tool needs a descriptive name, a clear purpose, and a schema for its input parameters.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    # Example Tool Definition (simplified OpenAPI/JSON Schema like structure)
    tools:
      - name: get_current_weather
        description: Gets the current weather for a given location.
        parameters:
          type: object
          properties:
            location:
              type: string
              description: The city and state, e.g., "San Francisco, CA"
            unit:
              type: string
              enum: [celsius, fahrenheit]
              description: The unit for temperature.
          required: [location]
      - name: search_flights
        description: Searches for flights between two cities on specific dates.
        parameters:
          type: object
          properties:
            departure_city:
              type: string
            arrival_city:
              type: string
            departure_date:
              type: string
              format: date
            return_date:
              type: string
              format: date
          required: [departure_city, arrival_city, departure_date]
    
  2. Gather Raw User Queries: Collect diverse examples of how users might phrase requests that require tool use.
    • Synthetic Generation: Use an existing LLM to generate user prompts based on your tool definitions. For example, “Generate 10 user queries that would require using get_current_weather.”
    • Real-world Logs: If available, anonymized user interaction logs from similar systems can be invaluable.
    • Manual Creation: Domain experts can craft specific examples covering edge cases.
  3. Annotate Queries with Tool Calls: For each user query, determine which tool (if any) should be called and what arguments should be extracted. This is the most critical step.

    • Single Tool Call:
      • User: “What’s the weather like in Boston?”
      • Tool Call: get_current_weather(location="Boston, MA")
    • Multiple Tool Calls (Sequential/Parallel):
      • User: “Book me a flight from New York to London next Friday and check the weather in London for that day.”
      • Tool Calls:
        1. search_flights(departure_city="New York", arrival_city="London", departure_date="next Friday", return_date=null)
        2. get_current_weather(location="London, UK", unit="celsius") (assuming LLM gets the date for weather after flight search or uses the same date)
    • No Tool Call:
      • User: “Tell me a joke.” (Requires a standard conversational response).

Data Structuring & Formatting

The annotated data needs to be formatted into a consistent structure that your LLM can learn from. A common format mimics the OpenAI function-calling API, often using a “chat completion” like structure with messages and tool calls.

Each training example typically consists of a sequence of messages, where the model’s desired output is a tool_calls message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
  {
    "messages": [
      {"role": "user", "content": "What's the weather in Seattle?"},
      {"role": "assistant", "tool_calls": [{"id": "call_abc123", "function": {"name": "get_current_weather", "arguments": "{\"location\": \"Seattle, WA\"}"}}]}
    ]
  },
  {
    "messages": [
      {"role": "user", "content": "I need to fly from SFO to LAX tomorrow."},
      {"role": "assistant", "tool_calls": [{"id": "call_def456", "function": {"name": "search_flights", "arguments": "{\"departure_city\": \"SFO\", \"arrival_city\": \"LAX\", \"departure_date\": \"tomorrow\"}"}}]}
    ]
  },
  {
    "messages": [
      {"role": "user", "content": "Tell me a story about a dragon."},
      {"role": "assistant", "content": "Once upon a time, in a land far away..."}
    ]
  }
]

Note: The id field in tool_calls is often arbitrary for training but can be useful for tracking during inference. Arguments should be a JSON string.

Handling Edge Cases & Ambiguity

Robust fine-tuning for tool-use models requires addressing challenging scenarios:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import json

def format_for_fine_tuning(user_query, tool_name=None, tool_args=None, response_content=None):
    """
    Formats a single interaction into the OpenAI-like fine-tuning data structure.
    """
    messages = [{"role": "user", "content": user_query}]
    
    if tool_name and tool_args:
        # Assuming tool_args is a dictionary
        tool_call = {
            "id": f"call_{hash(user_query + tool_name + json.dumps(tool_args))}", # Simple unique ID
            "function": {
                "name": tool_name,
                "arguments": json.dumps(tool_args)
            }
        }
        messages.append({"role": "assistant", "tool_calls": [tool_call]})
    elif response_content:
        messages.append({"role": "assistant", "content": response_content})
    else:
        # This case is for when the model should not call a tool and
        # we don't explicitly provide a content response for training.
        # It's better to provide a 'content' response if no tool is called.
        messages.append({"role": "assistant", "content": "I'm not sure how to respond to that."}) # Placeholder

    return {"messages": messages}

# Example Usage
training_data = []
training_data.append(format_for_fine_tuning(
    user_query="What's the weather in Paris?",
    tool_name="get_current_weather",
    tool_args={"location": "Paris, France"}
))
training_data.append(format_for_fine_tuning(
    user_query="Tell me a joke.",
    response_content="Why don't scientists trust atoms? Because they make up everything!"
))

# You'd typically save this list of dictionaries to a JSONL file
# with open("training_data.jsonl", "w") as f:
#    for entry in training_data:
#        f.write(json.dumps(entry) + "\n")

Once your data is meticulously prepared and formatted, you’re ready to teach your chosen LLM the art of tool use.

Strategies for Fine-Tuning Tool-Use Models

With your high-quality dataset ready, the next step is to leverage it to fine-tune tool-use models for AI agents. This involves selecting a base model, choosing an appropriate fine-tuning technique, and potentially refining your prompting strategy.

Base Model Selection

Not all LLMs are created equal when it comes to tool use. Many leading models are pre-trained with some level of function-calling capability.

Fine-Tuning Techniques

The choice of fine-tuning technique depends on your computational resources and desired outcome:

  1. Full Fine-Tuning: Updating all parameters of the LLM. This is resource-intensive but can yield the best performance for highly specialized tasks.
  2. Parameter-Efficient Fine-Tuning (PEFT): Techniques like LoRA (Low-Rank Adaptation) allow you to fine-tune a small number of additional parameters, significantly reducing computational cost and memory footprint while achieving competitive results. This is often the preferred method for tool-use fine-tuning.
  3. Prompt Engineering with Few-Shot Learning: While not strictly “fine-tuning,” providing a few good examples of tool calls directly in the prompt (in-context learning) can often suffice for simpler tool use scenarios without model updates. However, for robustness and accuracy across many tools or complex interactions, dedicated fine-tuning is superior.

During fine-tuning, you’ll feed your structured data (user query + desired tool call) to the model. The model learns to predict the tool_calls message structure given the user message and the available tools schema.

Prompt Engineering for Tool Use

Even with a fine-tuned model, the system prompt plays a crucial role in guiding its behavior, especially when integrating with an agentic framework.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Example of a system prompt structure
SYSTEM_PROMPT = """
You are a helpful AI assistant with access to the following tools:

{tools_json_schema}

You should only respond in the format described below.
If you need to use a tool, respond with a JSON object containing the `tool_calls` field.
If you do not need to use a tool, respond directly to the user.

Example for tool use:
User: What's the weather in London?
Assistant: tool_calls"}} }}] }}

Example for no tool use:
User: Tell me a joke.
Assistant: Why did the computer go to the doctor? Because it had a virus!

If a user's request is ambiguous or requires more information to call a tool, ask for clarification.
"""

# In your application code, you would dynamically insert the tool schemas:
# formatted_system_prompt = SYSTEM_PROMPT.format(tools_json_schema=json.dumps(your_tool_definitions, indent=2))

By combining robust data preparation with strategic fine-tuning and clear prompt engineering, you can significantly enhance your AI agent’s ability to utilize tools effectively. The next crucial step is to verify this performance through rigorous evaluation.

Evaluating Fine-Tuned Tool-Use Models for Performance

After investing in data preparation and fine-tuning, thoroughly evaluating your fine-tuned tool-use models for AI agents is paramount. A robust evaluation framework ensures your agent performs reliably and accurately in real-world scenarios.

Defining Evaluation Metrics

For tool-use models, evaluation goes beyond traditional text generation metrics. We need to assess the model’s ability to:

  1. Tool Selection Accuracy (Precision & Recall):
    • Precision: Out of all tool calls made by the model, how many were correct? (True Positives / (True Positives + False Positives))
    • Recall: Out of all necessary tool calls, how many did the model correctly identify? (True Positives / (True Positives + False Negatives))
    • F1 Score: The harmonic mean of precision and recall, offering a balanced view.
  2. Argument Extraction Accuracy: For each correctly selected tool, how accurately were the parameters extracted? This can be measured by comparing the model’s extracted arguments (JSON) against the ground truth.
    • Exact Match: Does the generated JSON exactly match the target?
    • Partial Match: If arguments are a dictionary, how many key-value pairs match?
  3. No-Tool-Call Accuracy: How often does the model correctly identify when not to call a tool?
  4. Error Handling (Optional but Recommended): How well does the model respond to invalid tool outputs or unexpected scenarios?

Setting Up an Evaluation Framework

  1. Create a Dedicated Test Set: This dataset should be distinct from your training and validation data, ideally reflecting real-world user queries and edge cases. Ensure it includes examples of tool calls, no tool calls, ambiguous requests, and multi-tool scenarios. Each example in the test set must have a “golden” (ground truth) tool call or conversational response.
  2. Run Inference: Pass your test set through the fine-tuned model (and its associated agent logic, if applicable, to get tool outputs).
  3. Compare to Ground Truth: Develop an automated script to compare the model’s generated tool calls/responses against the ground truth labels in your test set.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Simplified Python script for evaluating tool-use predictions
def evaluate_tool_predictions(predictions, ground_truths):
    correct_tool_selections = 0
    correct_arg_extractions = 0
    correct_no_tool_calls = 0
    total_tool_calls_predicted = 0
    total_tool_calls_ground_truth = 0
    total_no_tool_calls_ground_truth = 0

    for i in range(len(predictions)):
        pred = predictions[i]
        gt = ground_truths[i]

        pred_tool = pred.get('tool_calls')
        gt_tool = gt.get('tool_calls')
        
        if gt_tool: # Ground truth expects a tool call
            total_tool_calls_ground_truth += 1
            if pred_tool and len(pred_tool) > 0 and pred_tool[0]['function']['name'] == gt_tool[0]['function']['name']:
                correct_tool_selections += 1
                total_tool_calls_predicted += 1 # Count as a positive prediction
                # Check arguments
                try:
                    pred_args = json.loads(pred_tool[0]['function']['arguments'])
                    gt_args = json.loads(gt_tool[0]['function']['arguments'])
                    if pred_args == gt_args:
                        correct_arg_extractions += 1
                except json.JSONDecodeError:
                    pass # Argument malformation
            elif pred_tool and len(pred_tool) > 0:
                total_tool_calls_predicted += 1 # Incorrect tool predicted
        else: # Ground truth expects no tool call
            total_no_tool_calls_ground_truth += 1
            if not pred_tool or len(pred_tool) == 0:
                correct_no_tool_calls += 1
    
    # Calculate metrics
    precision = correct_tool_selections / total_tool_calls_predicted if total_tool_calls_predicted > 0 else 0
    recall = correct_tool_selections / total_tool_calls_ground_truth if total_tool_calls_ground_truth > 0 else 0
    f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
    no_tool_accuracy = correct_no_tool_calls / total_no_tool_calls_ground_truth if total_no_tool_calls_ground_truth > 0 else 0

    return {
        "precision": precision,
        "recall": recall,
        "f1_score": f1_score,
        "argument_extraction_accuracy": correct_arg_extractions / correct_tool_selections if correct_tool_selections > 0 else 0,
        "no_tool_call_accuracy": no_tool_accuracy
    }

# Example usage (assuming 'predictions' and 'ground_truths' are lists of dictionaries
# formatted like the 'messages' array's assistant response)
# results = evaluate_tool_predictions(model_predictions, golden_test_set_labels)
# print(results)

Automated vs. Human Evaluation

By diligently applying these evaluation techniques, you can confidently assess and iteratively improve the performance of your fine-tuned tool-use models, ensuring your AI agents are both intelligent and reliable.


Frequently Asked Questions

Further Reading

  1. OpenAI’s Function Calling Guide: https://platform.openai.com/docs/guides/function-calling (A foundational resource for understanding the concept and API design.)
  2. Hugging Face PEFT Library Documentation: https://huggingface.co/docs/peft/en/index (Learn more about Parameter-Efficient Fine-Tuning techniques like LoRA for open-source models.)
  3. Llama 3 with Function Calling: Search for recent blog posts or technical reports from Meta AI (e.g., on their developer blog or research paper pages) discussing Llama 3’s enhanced function calling capabilities and fine-tuning examples.

Building highly effective AI agents capable of intelligent tool interaction is a complex but rewarding endeavor. By meticulously preparing your data and applying the strategies outlined in this guide for fine-tuning tool-use models, you can significantly enhance your agents’ capabilities. This meticulous approach ensures that your AI agents not only understand user requests but also translate them into precise and reliable real-world actions.

Want to build robust AI agents with powerful tool-use capabilities but need expert guidance? Explore our AI/ML Consulting Services or check out other advanced AI agent development articles on the CodeCrux blog.