Skip to content

Latest commit

 

History

History

README.md

LiteRT-LM Chat Templates

This directory contains canonical prompt templates, metadata configurations, and schema definitions for models supported by LiteRT-LM.

LiteRT-LM uses Jinja2 (rendered hermetically via Minijinja) to transform structured conversation turns and tool declarations into model-specific prompt strings.

For the formal JSON Schema specification of all input variables, see chat_template_input_schema.json.

Table of Contents

Input Variables

When rendering a prompt template, LiteRT-LM passes a context dictionary containing the following top-level fields:

Field Type Description
messages array (Required) The conversation history as a list of message objects.
tools array (Optional) Available tools (function declarations) that the model can invoke.
enable_thinking boolean (Optional) Whether the model should produce reasoning thoughts before answering.
add_generation_prompt boolean (Optional) Whether to append the model turn prefix to prompt generation (defaults to true).
bos_token string (Optional) Beginning-of-sequence token (e.g. <bos>, <s>).

Message Structure

Each entry in messages represents a single turn in the dialogue.

Roles

The role string specifies the author of the turn:

  • "system": System instructions, personality, guidelines, and tool schemas.
  • "user": Prompts and queries from the end user.
  • "assistant": Responses generated by the model (text and/or tool calls).
  • "tool": Outputs and return values from executed tools/functions.

Content Types

The content field is strictly a list of multimodal parts. Plain text prompts are wrapped in a text part object:

{
  "role": "user",
  "content": [
    {"type": "text", "text": "What is the capital of France?"}
  ]
}

Multimodal prompts with images, audio, or video include the corresponding part objects alongside text parts:

{
  "role": "user",
  "content": [
    {"type": "text", "text": "What is in this image?"},
    {"type": "image"}
  ]
}

Tool Calls

When the assistant requests one or more function invocations, the message includes a tool_calls list:

{
  "role": "assistant",
  "tool_calls": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": {"location": "San Francisco, CA"}
      }
    }
  ]
}

When multiple tool calls are invoked in parallel within a single turn:

{
  "role": "assistant",
  "tool_calls": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": {"location": "San Francisco, CA"}
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_time",
        "arguments": {"location": "San Francisco, CA"}
      }
    }
  ]
}

Note: arguments can be provided either as a JSON object or as a serialized JSON string. When tool_calls is present, content is optional and may be omitted or empty.

Tool Responses

When a function executes, its result is supplied as a message with role: "tool":

{
  "role": "tool",
  "content": [
    {
      "type": "tool_response",
      "name": "get_weather",
      "response": {"temperature": "18C", "condition": "Sunny"}
    }
  ]
}

When multiple tool calls are executed, their responses are bundled into a single message with multiple tool_response items in content:

{
  "role": "tool",
  "content": [
    {
      "type": "tool_response",
      "name": "get_weather",
      "response": {"temperature": "18C", "condition": "Sunny"}
    },
    {
      "type": "tool_response",
      "name": "get_time",
      "response": {"time": "14:30"}
    }
  ]
}

Tool Definitions

When tools are supplied, each item in the tools array follows the OpenAPI standard:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "Fetch the current weather for a specified location.",
    "parameters": {
      "type": "object",
      "properties": {
        "location": {
          "type": "string",
          "description": "City and state, e.g. San Francisco, CA"
        },
        "unit": {
          "type": "string",
          "enum": ["celsius", "fahrenheit"]
        }
      },
      "required": ["location"]
    }
  }
}

Writing Templates for LiteRT-LM

Chat templates should be placed in the model's directory (e.g. models/<model_name>/chat_template.jinja).

Built-in Filters and Functions

The Minijinja engine provides several built-in utilities:

  • tojson: Serializes a value into formatted JSON string (e.g. {{ tool | tojson }}).
  • lstrip(chars) / rstrip(chars): Trims leading/trailing whitespace or specific characters.
  • strftime_now(format): Formats the current date/time into a string using the given format (e.g. {{ strftime_now("%d %b %Y") }}). Time-aware templates should use this function rather than referencing a raw now variable.
  • raise_exception(message): Raises an error during template rendering if an invariant is violated.
  • is none: Test for undefined or null variables.

Handling Tool Calls

Templates that support function calling typically check if tools is defined and loop through available function signatures:

{%- if tools is defined and tools -%}
<tools>
{%- for tool in tools %}
{{ tool.function | tojson }}
{%- endfor %}
</tools>
{%- endif %}

When rendering an assistant turn with function calls:

{%- if message.tool_calls is defined and message.tool_calls -%}
  {%- for tool_call in message.tool_calls %}
<tool_call>
{"name": "{{ tool_call.function.name }}", "arguments": {{ tool_call.function.arguments | tojson }}}
</tool_call>
  {%- endfor %}
{%- endif -%}

Handling Thinking Mode

If the model supports configurable thinking/reasoning modes, use the default filter:

{%- set thinking = enable_thinking | default(false) -%}
{%- if thinking -%}
<think>
</think>
{%- endif -%}

Examples

Standard Multi-turn Conversation

{
  "messages": [
    {
      "role": "system",
      "content": [
        {"type": "text", "text": "You are a concise, helpful assistant."}
      ]
    },
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "Hello!"}
      ]
    },
    {
      "role": "assistant",
      "content": [
        {"type": "text", "text": "Hi! How can I help you today?"}
      ]
    }
  ],
  "add_generation_prompt": true
}

Multimodal Inputs

{
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "image"},
        {"type": "text", "text": "Describe what is shown in this picture."}
      ]
    }
  ],
  "add_generation_prompt": true
}

Function Calling & Tool Response Turn

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "lookup_stock",
        "description": "Get current stock price for a ticker symbol.",
        "parameters": {
          "type": "object",
          "properties": {
            "symbol": {"type": "string", "description": "Stock ticker symbol, e.g. GOOG"}
          },
          "required": ["symbol"]
        }
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "What is the price of GOOG?"}
      ]
    },
    {
      "role": "assistant",
      "tool_calls": [
        {
          "type": "function",
          "function": {
            "name": "lookup_stock",
            "arguments": {"symbol": "GOOG"}
          }
        }
      ]
    },
    {
      "role": "tool",
      "content": [
        {
          "type": "tool_response",
          "name": "lookup_stock",
          "response": {"price": "180.50", "currency": "USD"}
        }
      ]
    }
  ],
  "add_generation_prompt": true
}

Parallel Tool Calling Turn

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a location.",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {"type": "string", "description": "City name"}
          },
          "required": ["location"]
        }
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "What is the weather in London and Paris?"}
      ]
    },
    {
      "role": "assistant",
      "tool_calls": [
        {
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": {"location": "London"}
          }
        },
        {
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": {"location": "Paris"}
          }
        }
      ]
    },
    {
      "role": "tool",
      "content": [
        {
          "type": "tool_response",
          "name": "get_weather",
          "response": {"location": "London", "temperature": "18C"}
        },
        {
          "type": "tool_response",
          "name": "get_weather",
          "response": {"location": "Paris", "temperature": "22C"}
        }
      ]
    }
  ],
  "add_generation_prompt": true
}

Testing and Validation

All chat template test cases are defined under testdata/input/*.json and validated using the chat_template_test Bazel macro from chat_template_test.bzl.

Rendered outputs are checked against golden reference files under testdata/golden/.

To add a test for a new model family, define in BUILD:

load("//models:chat_template_test.bzl", "chat_template_test")

chat_template_test(
    name = "chat_template_test",
    chat_template = "chat_template.jinja",
    golden_dir = "testdata/golden",
    input_dir = "testdata/input",
    pbtext_files = [":LlmMetadataProto.pbtext"],
)

To run all chat template tests across all models:

bazel test //models/...