Skip to main content
Functions in BAML define the contract between your application and AI models, providing type-safe interfaces for AI operations.

Overview

A BAML function consists of:
  • Input parameters with explicit types
  • A return type specification
  • An LLM client reference
  • A prompt template (as a block string)

Syntax

function FunctionName(param1: Type1, param2: Type2) -> ReturnType {
  client ClientName
  prompt #"
    Template content with {{ param1 }} and {{ param2 }}
  "#
}

Components

function
required
The function keyword begins the declaration.
FunctionName
identifier
required
Function name must start with a capital letter and follow PascalCase convention.
function ExtractEmail() -> string { }
function ParsePerson() -> Person { }
parameters
(name: Type, ...)
required
One or more typed parameters, comma-separated.
function Analyze(text: string) -> Result { }
function Compare(doc1: string, doc2: string) -> Comparison { }
function Process(data: CustomType, options: Options?) -> Output { }
->
required
Arrow operator separates parameters from return type.
ReturnType
type
required
The type that the function guarantees to return. Can be any BAML type including unions.
-> string
-> Person
-> string | Person
-> string[]
-> map<string, int>
client
required
Specifies which LLM client to use. Can be a client name or inline provider/model.
client GPT4Turbo
client "openai/gpt-4o"
client Claude
prompt
required
The prompt template using Jinja syntax. Must be a block string (#"..."#).
prompt #"
  Extract the email from: {{ text }}
  {{ ctx.output_format }}
"#

Type System

Functions leverage BAML’s strong type system for both inputs and outputs.

Primitive Types

TypeDescriptionExample
stringText datatext: string
intInteger numberscount: int
floatDecimal numbersscore: float
boolBoolean valuesisValid: bool

Complex Types

TypeDescriptionExample
ClassCustom classesperson: Person
EnumEnumerationsstatus: Status
Type[]Arraysitems: string[]
Type?Optionalage: int?
Type1 | Type2Unions-> string | Error
map<K,V>Mapsdata: map<string, int>

Multimodal Types

TypeDescriptionExample
imageImage inputsphoto: image
audioAudio inputsrecording: audio
videoVideo inputsclip: video
pdfPDF documentsdoc: pdf

Examples

Basic Function

function ExtractEmail(text: string) -> string {
  client GPT4Turbo
  prompt #"
    Extract the email address from the following text:
    {{ text }}
    
    {{ ctx.output_format }}
  "#
}

Multiple Parameters

function CompareDocuments(doc1: string, doc2: string) -> Comparison {
  client "openai/gpt-4o"
  prompt #"
    Compare these two documents and identify key differences:
    
    Document 1:
    {{ doc1 }}
    
    Document 2:
    {{ doc2 }}
    
    {{ ctx.output_format }}
  "#
}

Complex Return Types

class Person {
  name string
  age int?
  contacts Contact[]
}

class Contact {
  type "email" | "phone"
  value string
}

function ParsePerson(data: string) -> Person {
  client GPT4
  prompt #"
    {{ ctx.output_format }}
    
    {{ _.role('user') }}
    Extract person information from: {{ data }}
  "#
}

Union Return Types

class Success {
  data string
}

class Error {
  message string
  code int
}

function ProcessRequest(input: string) -> Success | Error {
  client GPT4Turbo
  prompt #"
    Process this request and return either success or error:
    {{ input }}
    
    {{ ctx.output_format }}
  "#
}

Multimodal Input

function DescribeImage(img: image, detail_level: string) -> string {
  client "openai/gpt-4o"
  prompt #"
    {{ _.role('user') }}
    Describe this image with {{ detail_level }} level of detail:
    {{ img }}
  "#
}

Literal Return Types

function ClassifyIssue(description: string) -> "bug" | "feature" | "question" {
  client GPT4Turbo
  prompt #"
    Classify this issue based on the description:
    {{ ctx.output_format }}
    
    {{ _.role('user') }}
    {{ description }}
  "#
}

Prompt Templates

Jinja Syntax

BAML uses Jinja for dynamic prompt generation:
prompt #"
  {{ ctx.output_format }}
  
  {% if condition %}
    Conditional content
  {% endif %}
  
  {% for item in items %}
    - {{ item }}
  {% endfor %}
  
  {{ _.role('user') }}
  {{ input_data }}
"#

Special Variables

ctx.output_format
Automatically generates format instructions based on the function’s return type.
prompt #"
  {{ ctx.output_format }}
  Extract data from: {{ text }}
"#
ctx.client
Contains the selected client and model name.
prompt #"
  Using model: {{ ctx.client }}
"#
_.role(role_name)
Defines the role for the message chunk in chat-based models.
prompt #"
  {{ _.role('system') }}
  You are a helpful assistant.
  
  {{ _.role('user') }}
  {{ user_input }}
"#

Client Specification

Named Client

Reference a client defined elsewhere:
client<llm> GPT4 {
  provider openai
  options {
    model gpt-4o
    api_key env.OPENAI_API_KEY
  }
}

function MyFunction(input: string) -> string {
  client GPT4
  prompt #"..."#
}

Inline Client

Use provider/model shorthand:
function MyFunction(input: string) -> string {
  client "openai/gpt-4o"
  prompt #"..."#
}
This is equivalent to:
client<llm> AutoClient {
  provider openai
  options {
    model gpt-4o
    api_key env.OPENAI_API_KEY  // Uses default env var
  }
}

Generated Code Integration

Functions generate type-safe code in your target language:
from baml_client import b
from baml_client.types import Person

async def example():
    result = await b.ParsePerson("John Doe, 30 years old")
    print(result.name)  # Type-safe access
    print(result.age)   # Optional[int]

Error Handling

Functions automatically handle common AI model errors:
  • JSON parsing errors: Automatically corrected when possible
  • Type mismatches: Detected and reported with detailed error messages
  • Network errors: Propagated to caller with retry support (via client retry policies)
  • Rate limits: Handled according to client retry policy

Runtime Client Selection

To select which client to use at runtime, use the client registry:
from baml_client import b

result = await b.MyFunction(
    "input",
    baml_options={"client": "GPT4Turbo"}
)
This is useful for:
  • A/B testing different models
  • Gradual rollouts
  • Fallback scenarios
  • Cost optimization

Best Practices

  1. Naming: Use descriptive PascalCase names starting with capital letters
  2. Parameters: Keep parameter lists focused and well-typed
  3. Return Types: Use specific types rather than unions when possible
  4. Prompts: Include {{ ctx.output_format }} for structured outputs
  5. Documentation: Add docstrings to explain function purpose
  6. Testing: Create tests for each function variation
  7. Client Selection: Use named clients for reusability

Build docs developers (and LLMs) love