Skip to main content

Overview

The tool use workflow follows four steps:
  1. Define tools by passing them to .apply_chat_template() with tools=.... The template places them in the system prompt between <tools> and </tools>.
  2. Generate a response where the model writes each call between <tool_call> and </tool_call>, with the function name in a <function=...> tag and each argument in a <parameter=...> tag.
  3. Execute the function and return results as a tool role message.
  4. Regenerate to let the model interpret results and respond to the user.
LFM3’s tool call format has changed from the custom LFM2/LFM2.5 format to a superset of qwen3_coder. Using LFM2 or LFM2.5? See LFM2 and LFM2.5.

Complete Example

Start by loading the model and defining your tools and conversation:
Generate the first response. The model may decide to call a tool:
After its reasoning, the model outputs a tool call in XML:
Parse the tool call and execute the function in your application. Add the parsed assistant call to history as a tool_calls entry, then append the result as a tool message. function.arguments must be a Python mapping, so decode JSON strings with json.loads() before applying the template.
Generate again, passing the same tool schemas, so the model can interpret the tool result and respond to the user. Keep the assistant’s content and reasoning from the current tool-use turn in the history.
The full conversation now looks like this:
Every tool definition in <tools> is part of the prompt. With a few tools that’s fine, but an agent on a phone, in a car, or in a smart home may have hundreds or thousands of tools, far more than fit in the context window. LFM3 solves this with deferred tools and tool search:
  • Defer loading: mark a tool with "defer_loading": True. The chat template leaves its definition out of the system prompt, but the tool stays in your tools list, so your application still knows its schema.
  • Tool search: give the model one tool that is always loaded. We recommend naming it search_tools. When none of its loaded tools fit a request, the model calls the search tool. Your application runs the search and returns the matching tools as tool_reference parts. The chat template adds their definitions to the tool response inside <additional_tools>, and the model can call them from then on.
This has two benefits:
  • Shorter prompts: only the always-loaded tools are in the system prompt. Deferred tools enter the context only when the model needs them.
  • Stable prompt prefix: discovered tools arrive in the tool response, so the system prompt never changes. Inference engines can keep reusing the cached prefix as the conversation grows.

How it works

  1. Pass all tools, deferred or not, in tools on every request. The chat template raises an error if a tool_reference names a tool that isn’t in tools.
  2. In the system prompt, tell the model when to search.
  3. When the model calls the search tool, run your search and return a tool message with one tool_reference part per matching tool.
  4. The model calls the discovered tool. Run it and return the result as usual.

Returning search results as tool_reference

When the model calls search_tools, return the matching tool names as tool_reference content parts. You can put text before them:
The chat template looks up each referenced name in tools and writes the full definitions into an <additional_tools> block inside the tool response:
The model can now call get_weather like any other tool, in this turn and in later ones, without searching again.

Complete Example

This example uses a keyword search over a small catalog. In production, replace search_catalog() with your own search, for example over tool descriptions with an embedding model.
The system prompt lists only search_tools. After the search, the definition of get_weather appears in the tool response, and the model calls it:
If your search returns full tool definitions instead of names, pass them in the tool message’s additional_tools field, for example {"role": "tool", "additional_tools": [weather_schema]}. The chat template renders them the same way. Defer loading works with vLLM, SGLang, and LFM3-compatible llama.cpp builds. For llama.cpp, use a GGUF with the current chat template or load it with --chat-template-file.

Vision, Audio, and Omni Models

LFM3-VL-2B, LFM3-Audio-2B, and LFM3-Omni-2B use the same tool call format. Pass the tool list to the processor’s .apply_chat_template() with tools=.... With LFM3-Audio-2B and LFM3-Omni-2B, the user can ask in text or in speech, and the model can also respond with text or speech alongside its tool calls:

Best Practices

Tool definitions consume context tokens since they’re inserted as text. For large tool lists (100+ tools), this can use significant portions of your context window. To manage this effectively, only include tools relevant to the current request. Write clear, concise descriptions. Group related tools and remove unused ones when they’re not needed. With LFM3, use defer loading and tool search for large tool catalogs, so only the tools the model needs enter the context.

LFM2 and LFM2.5

The tool use workflow follows four steps:
  1. Define tools as JSON in the system prompt or via .apply_chat_template()
  2. Generate a response where the model outputs function calls between special tokens
  3. Execute the function and return results as a tool role message
  4. Regenerate to let the model interpret results and respond to the user
LFM2.5 wraps tool calls in <|tool_call_start|> and <|tool_call_end|> tokens. LFM2 additionally wraps tool definitions in <|tool_list_start|>/<|tool_list_end|> and responses in <|tool_response_start|>/<|tool_response_end|>. By default, models generate Pythonic function calls. Add “Output function calls as JSON” to your system prompt for JSON format.

LFM2 Defining Tools

You have two options for providing tool definitions. Option 1: JSON in the system prompt (recommended)
Option 2: Python functions via .apply_chat_template()

LFM2 Complete Example

Start by loading the model and defining your tools and conversation:
Generate the first response. The model may decide to call a tool:
The model outputs a tool call wrapped in special tokens:
Parse the tool call and execute the function externally. Here we use a mock function that simulates what would typically be an API call to your recruitment system:
Generate again so the model can interpret the tool result and respond to the user:
The full conversation now looks like this:

LFM2 Vision Models

LFM2-VL and LFM2.5-VL vision models support text-only function calling. Use the tokenizer from the processor: