Chapter 9. Tool calling through Distributed Inference with llm-d


Tool calling enables a large language model to request the execution of external functions during an inference conversation. Agent frameworks such as LangChain, CrewAI, and AutoGen rely on tool calling to build multi-step workflows where the model selects tools, generates structured arguments, and processes tool results across multiple turns.

The Distributed Inference with llm-d serving stack preserves tool calling parameters transparently. When a request includes tool definitions, the stack passes them through every layer, from the Gateway to the Endpoint Picker (EPP) to vLLM, without requiring any llm-d-specific configuration. The following Chat Completions API parameters pass through the stack unaltered:

  • tools: Function definitions including name, description, and JSON Schema parameters
  • tool_choice: Tool selection mode, such as auto, required, none, or a named function
  • parallel_tool_calls: Boolean that controls whether the model can generate multiple tool calls in a single response
  • response_format: Structured output schema for JSON mode or JSON Schema constrained decoding

Tool call response objects, including tool_calls arrays with function.name and function.arguments, return to the client with the same fidelity. Streaming tool call deltas also pass through every stack layer without modification. This passthrough behavior works in both non-disaggregated and disaggregated prefill-decode deployments. Non-tool-calling requests are not affected in latency or throughput.

To use tool calling through Distributed Inference with llm-d, set the appropriate vLLM tool calling arguments on the LLMInferenceService custom resource.

The tool_choice request parameter controls how the model handles tool definitions. When a request includes tools but omits tool_choice, vLLM defaults to auto. The auto mode and the required and named function modes use different enforcement mechanisms. In auto mode, the model generates free-form output and the configured tool-call parser extracts tool calls from the result. In required and named function modes, vLLM uses guided decoding to constrain generation to the tool schemas, which produces structurally valid tool call arguments without relying on the parser. Use auto for agent workflows where the model needs to decide whether to call a tool. Use required or a named function when you need guaranteed tool call output with schema-valid arguments. For the full list of tool_choice values and their runtime requirements, see Supported tool calling parameters for Distributed Inference with llm-d.

Important

Tool calling has not been validated with speculative decoding or Multi-Token Prediction (MTP). These features can interfere with the token generation process that vLLM uses to construct tool call objects. Known failure modes include corrupted function.arguments JSON in streaming responses and incomplete tool call parsing when multiple tool calls span a single streaming chunk. Non-streaming requests might succeed while streaming responses exhibit corruption. If you experience issues with tool calling while using speculative decoding or MTP, disable them for workloads that require tool calling.

9.1. Tool calling component responsibilities

The Distributed Inference with llm-d serving stack is responsible for preserving tool calling parameters in transit. The vLLM runtime, not llm-d, handles the following concerns:

  • Model-specific tool calling support and generation quality
  • Chat template processing of tool definitions and tool-call history
  • Tool call parser selection and model-specific output parsing
  • tool_choice behavior
  • Parallel tool call response handling
  • Structured output enforcement for required, named, and strict automatic tool calls

For model-specific tool calling configuration, see the vLLM tool calling documentation and the Red Hat AI Inference tool calling guide.

You can enable tool calling for models served through Distributed Inference with llm-d by adding vLLM tool calling arguments to the LLMInferenceService custom resource. The Distributed Inference with llm-d serving stack forwards tool calling parameters to vLLM without modification, so no Distributed Inference with llm-d-specific configuration is required.

Prerequisites

  • You have deployed a model using Distributed Inference with llm-d.
  • The model you deployed supports tool calling. For supported models and parser values, see vLLM tool calling documentation.
  • You have access to the OpenShift CLI (oc).

Procedure

  1. Identify the correct --tool-call-parser value for your model.

    The parser must match the chat template format used by the model. For the list of supported parsers by model, see vLLM tool calling documentation. Most supported models provide a compatible chat template, but some models also require an explicit --chat-template.

  2. Create or edit the LLMInferenceService custom resource to include the tool calling arguments.

    Add --enable-auto-tool-choice and --tool-call-parser to the VLLM_ADDITIONAL_ARGS environment variable under spec.template.containers for the container named main. Save the following YAML to a file named llminferenceservice.yaml:

    apiVersion: serving.kserve.io/v1alpha2
    kind: LLMInferenceService
    metadata:
      name: my-tool-calling-service
      namespace: <my_namespace>
    spec:
      replicas: 1
      model:
        uri: hf://RedHatAI/Qwen3.5-9B-FP8-dynamic
        name: RedHatAI/Qwen3.5-9B-FP8-dynamic
      router:
        route: {}
        gateway: {}
        scheduler: {}
      template:
        containers:
        - name: main
          env:
          - name: VLLM_ADDITIONAL_ARGS
            value: >-
              --enable-auto-tool-choice
              --tool-call-parser=qwen3_coder
              --reasoning-parser=qwen3
          resources:
            limits:
              cpu: '4'
              memory: 32Gi
              nvidia.com/gpu: "1"
            requests:
              cpu: '2'
              memory: 16Gi
              nvidia.com/gpu: "1"

    where:

    --enable-auto-tool-choice
    Enables automatic tool choice for supported models. When a request uses tool_choice="auto", the model can decide whether to return a text response or generate one or more tool calls. Automatic tool choice requires a compatible --tool-call-parser for the model. This flag defaults to false in vLLM, so it must be set explicitly.
    --tool-call-parser
    Specifies the parser that vLLM uses to extract tool calls from the model’s output. This value must match the chat template format of the model.
    --reasoning-parser
    Specifies the parser that vLLM uses to separate the model’s internal reasoning from its generated content. This flag does not enable reasoning in the model but tells the engine to treat reasoning and output separately. The reasoning parser is unrelated to tool calling but is recommended for this model.
  3. Apply the custom resource:

    $ oc apply -f llminferenceservice.yaml -n <my_namespace>
  4. Wait for the deployment to become ready:

    $ oc get llminferenceservice my-tool-calling-service -n <my_namespace> -w

    Example output

    NAME                      READY   AGE
    my-tool-calling-service   True    3m

    The READY column shows True when the deployment is ready to serve requests.

Verification

  1. Get the route URL for your model endpoint:

    $ ROUTE_URL=$(oc get llmisvc -n <my_namespace> my-tool-calling-service -o jsonpath='{.status.url}')
  2. Send a tool calling request to verify the configuration:

    $ curl -s -X POST "${ROUTE_URL}/v1/chat/completions" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $(oc whoami -t)" \
      -d { "model": "RedHatAI/Qwen3.5-9B-FP8-dynamic", "temperature": 0, "messages": [ { "role": "system", "content": "You are a helpful assistant with access to tools. Use the get_weather tool when asked about weather." }, { "role": "user", "content": "What is the weather in San Francisco?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Get the current weather in a given location.", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "City and state." }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] } }, "required": ["location"] } } } ], "tool_choice": "auto" } | python3 -m json.tool

    The | python3 -m json.tool part of the command is optional and formats the JSON output for readability.

    Setting "tool_choice": "auto" in the request lets the model automatically decide whether to call a tool based on the request content. For the full list of tool_choice values, see Supported tool calling parameters for Distributed Inference with llm-d.

  3. Verify the response contains a tool_calls array with function.name set to get_weather and function.arguments containing a location value.

    Example output

    {
        "id": "chatcmpl-abc123",
        "object": "chat.completion",
        "model": "RedHatAI/Qwen3.5-9B-FP8-dynamic",
        "choices": [
            {
                "index": 0,
                "message": {
                    "role": "assistant",
                    "content": null,
                    "tool_calls": [
                        {
                            "id": "call_abc123",
                            "type": "function",
                            "function": {
                                "name": "get_weather",
                                "arguments": "{\"location\": \"San Francisco, CA\"}"
                            }
                        }
                    ]
                },
                "finish_reason": "tool_calls"
            }
        ]
    }

    If the response contains plain text in the content field instead of a tool_calls array, see Tool calling troubleshooting for Distributed Inference with llm-d.

    To complete a multi-turn tool calling loop, send the tool execution result back to the model in a follow-up message with role set to tool. The Distributed Inference with llm-d stack preserves tool result messages in the same way as tool call requests. For the complete multi-turn pattern, see Extending Red Hat AI Inference with Tool Calling Capabilities.

You can use the following Chat Completions API tool calling parameters with models served through Distributed Inference with llm-d. The Distributed Inference with llm-d serving stack preserves these parameters in both request and response paths, passing them through the Gateway, Endpoint Picker (EPP), and vLLM layers without modification.

9.3.1. Tool calling request parameters

The following request parameters pass through the Distributed Inference with llm-d stack to the vLLM runtime. The response_format parameter is a general Chat Completions parameter, not specific to tool calling, but is included here because it is commonly used alongside tool definitions in agentic workflows.

Table 9.1. Tool calling request parameters
ParameterTypeDescription

tools

Array of objects

Function definitions that the model can call. Each tool object contains a type field set to function and a function object with name, description, and parameters fields. The parameters field uses JSON Schema to define the function’s input arguments.

tools[].function.strict

Boolean

Controls whether vLLM enforces the function’s argument schema when generating a tool call. For tool_choice="auto", set strict: true to require generated tool arguments to match the schema defined for the function. Strict enforcement for automatic tool calling is enabled by default and can be disabled globally on the vLLM runtime by setting VLLM_ENFORCE_STRICT_TOOL_CALLING=false.

tool_choice

String or object

Controls whether the model can generate tool calls and, when applicable, which tools it can select. Supported values are auto, required, and none. You can also specify a particular function by using {"type": "function", "function": {"name": "<function_name>"}}. If tools is specified and tool_choice is omitted, vLLM defaults to auto.

parallel_tool_calls

Boolean

Controls whether a response can contain multiple tool calls. The default is true, which allows vLLM to return more than one tool call when the model and tool-calling format support it. Setting the parameter to false limits the response to zero or one tool call.

response_format

Object

Specifies the output format for the model response. You can use {"type": "json_object"} for JSON mode or {"type": "json_schema", "json_schema": {...}} for JSON Schema constrained decoding. This parameter applies to all responses, including responses that contain tool calls. This parameter is not the mechanism used to validate tool arguments. Tool argument constraints are derived from the JSON Schema in the tool definition and the selected tool_choice mode.

9.3.2. Tool choice behavior in vLLM

The tool_choice request parameter controls how the model handles tool definitions in a request. The behavior varies by mode, and some modes require specific vLLM runtime flags. When a request includes tools but omits tool_choice, vLLM defaults to auto. This means that any deployment serving tool calling requests requires --enable-auto-tool-choice and a compatible --tool-call-parser unless every request explicitly sets tool_choice to required, a named function, or none. For an overview of how these modes differ, see Tool calling through Distributed Inference with llm-d.

Table 9.2. Tool choice behavior
tool_choiceTool selectionSchema enforcementRuntime requirements

auto

The model decides whether to return normal content or generate one or more calls to the available tools.

By default, generation is unconstrained and the configured tool-call parser extracts tool calls from the generated output. If a tool specifies strict: true, vLLM can constrain tool call generation to the tool schema when the configured parser supports structural tags.

Requires the vLLM runtime to be started with --enable-auto-tool-choice and a compatible --tool-call-parser.

required

The model must generate one or more tool calls and selects from the tools supplied in the request.

vLLM uses structured output constraints derived from the supplied tool schemas.

Supported by default. --enable-auto-tool-choice is not required.

Named function

The request specifies the function that the model must call by using {"type": "function", "function": {"name": "<function_name>"}}.

vLLM uses structured output constraints derived from the selected function’s parameter schema.

Supported by default. --enable-auto-tool-choice is not required.

none

The model does not generate tool calls and returns normal response content.

Not applicable.

Supported by default. By default, vLLM still provides the tool definitions to the chat template. You can start vLLM with --exclude-tools-when-tool-choice-none to omit them when this mode is used.

9.3.3. Tool calling response objects

The following response objects pass through the Distributed Inference with llm-d stack from the vLLM runtime to the client.

Table 9.3. Tool calling response objects
ObjectTypeDescription

tool_calls

Array of objects

An array of tool call objects in the response choices[].message.tool_calls field. Each object contains id with a unique identifier, type set to function, and a function object with name and arguments fields. The arguments field contains a JSON string of the function arguments generated by the model.

tool_calls streaming deltas

Array of objects

In streaming responses, tool call data arrives incrementally in choices[].delta.tool_calls. Each delta contains an index field that identifies which tool call the chunk belongs to and a function object with partial arguments data. Each tool call includes an index that identifies the call to which the delta belongs. Function arguments can be split across multiple deltas, so clients must concatenate the arguments values for each index before parsing the completed JSON value.

Note

When a request includes multiple tools, the tool_calls array in the response might not contain all of them. The number of tool calls returned depends on the model, the tool-call parser, and the prompt. Some models generate tool calls one at a time across multiple conversation turns rather than returning all calls in a single response. If you expect multiple tool calls but receive fewer, verify that the model and --tool-call-parser support parallel tool calling for your use case.

These parameters are specific to what the Distributed Inference with llm-d serving stack preserves in transit. The vLLM runtime handles the following aspects of tool calling:

  • Model-specific tool calling support and generation quality
  • Chat template processing of tool definitions and tool-call history
  • Tool call parser selection and model-specific output parsing
  • tool_choice behavior
  • Parallel tool call response handling
  • Structured output enforcement for required, named, and strict automatic tool calls

For information about which models support tool calling and which --tool-call-parser values to use, see vLLM tool calling documentation.

Diagnose and resolve issues with tool calling through the Distributed Inference with llm-d serving stack. The Distributed Inference with llm-d stack passes tool calling parameters through transparently, so tool calling failures are almost always caused by the vLLM runtime configuration, not the stack itself.

Model returns text instead of tool calls

Symptoms:

  • Agent frameworks receive plain text where tool_calls objects are expected
  • The response content field contains text and tool_calls is absent or empty
  • Application workflows stall because the agent framework cannot determine a next action
  • The HTTP response status is 200 OK with no error

Diagnosis:

  1. Verify the LLMInferenceService has vLLM tool calling arguments configured:

    $ oc get llmisvc <service_name> -n <my_namespace> -o yaml | grep -A 2 "VLLM_ADDITIONAL_ARGS"

    The VLLM_ADDITIONAL_ARGS value must include both --enable-auto-tool-choice and --tool-call-parser=<parser>. Missing flags are the most common cause: the model does not process tool definitions without them.

  2. Verify the --tool-call-parser value matches the model.

    The parser must match the chat template format of the deployed model. An incorrect parser causes the model to generate tool calls that vLLM cannot extract, resulting in plain text responses. For the correct parser value, see vLLM tool calling documentation.

  3. Verify the request includes a tools array with valid function definitions.

    Inspect the request body sent by the agent framework or test client. The request must include a tools array with at least one tool definition containing name, description, and parameters.

Resolution:

Tool calls are corrupted or incomplete in streaming responses

Symptoms:

  • The function.arguments field in tool_calls contains malformed or truncated JSON
  • Multi-tool streaming responses are missing one or more expected tool_calls entries
  • The issue occurs only in streaming mode; non-streaming requests return correct tool calls
  • Agent frameworks fail to parse tool call arguments or receive fewer tool calls than expected

Diagnosis:

  1. Verify whether speculative decoding or Multi-Token Prediction (MTP) is enabled on the deployment.

    Check the LLMInferenceService for arguments such as --speculative-model, --num-speculative-tokens, or MTP-related flags:

    $ oc get llmisvc <service_name> -n <my_namespace> -o yaml | grep -A 2 "VLLM_ADDITIONAL_ARGS"
  2. Test the same request with speculative decoding or MTP disabled.

    Remove the speculative decoding or MTP arguments from the VLLM_ADDITIONAL_ARGS environment variable in the LLMInferenceService custom resource and reapply it. If tool calling works correctly after removing these arguments, the issue is caused by the interaction between speculative decoding or MTP and tool call token generation.

  3. Test with non-streaming mode to confirm the issue is specific to streaming.

    Set "stream": false in the request body and verify that the response contains correct tool_calls objects.

Resolution:

  • Disable speculative decoding or MTP for workloads that require tool calling. These features have not been validated with tool calling and can interfere with the token generation process that vLLM uses to construct streaming tool call deltas.

    For more information, see Tool calling through Distributed Inference with llm-d.

Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top