BAML Python Bindings
BAML (Basically a Made-up Language) is a domain-specific language and toolchain designed to build reliable AI workflows and agents by transforming prompt engineering into schema engineering. It generates type-safe client code for Python (and other languages like TypeScript, Ruby, Go), enabling structured outputs from Large Language Models with built-in features like streaming, retries, and broad model support. The library is actively maintained with frequent releases, currently at version 0.220.0.
Warnings
- breaking Maintain consistent versions across BAML components. The `baml-py` package, `baml-cli` (installed globally or via `uv`/`poetry`), the VSCode BAML extension, and the `generator` version specified in your `generators.baml` file must all be in sync. Mismatched versions can lead to code generation errors or runtime issues.
- gotcha The `baml_client` directory and its contents are entirely auto-generated. Do not manually edit files within `baml_client`, as changes will be overwritten the next time `baml-cli generate` (or the VSCode extension on save) runs.
- gotcha API keys for LLM providers (e.g., OpenAI, Anthropic, Google) are typically configured in `baml_src/clients.baml` and usually rely on environment variables (e.g., `env.OPENAI_API_KEY`). If these variables are not correctly set, BAML client calls will fail.
- gotcha When using BAML in Jupyter Notebooks, the standard `from baml_client.sync_client import b` import pattern does not work well with the `%autoreload` extension. Changes in `.baml` files might not be reflected without a kernel restart.
- gotcha All BAML function prompts intended for structured output **must** include `{{ ctx.output_format }}` in the prompt template. Omitting this Jinja filter will prevent the final structured output step from occurring, leading to parsing failures or unexpected plain text output.
Install
-
pip install baml-py -
baml-cli init -
baml-cli generate
Imports
- b
import baml_py
from baml_client.sync_client import b
- GeneratedTypes
from baml_py.types import ...
from baml_client.types import YourSchemaName
- AbortController
from baml_py import AbortController
Quickstart
import os
# NOTE: This example assumes you have run 'baml-cli init' and 'baml-cli generate'.
# A 'baml_src' directory with a BAML function (e.g., ExtractResume) and a 'baml_client'
# directory with generated code must exist in your project.
# Example BAML function definition (e.g., in baml_src/main.baml):
# class Resume {
# name string
# title string
# }
# function ExtractResume(resume_text: string) -> Resume {
# client "openai/gpt-4o"
# prompt """
# Parse the following resume and return structured data.
# {{ resume_text }}
# {{ ctx.output_format }}
# """
# }
# Ensure your OpenAI API key is set as an environment variable
os.environ['OPENAI_API_KEY'] = os.environ.get('OPENAI_API_KEY', 'sk-fake-key-for-test')
from baml_client.sync_client import b
from baml_client.types import Resume
def process_resume(resume_text: str) -> Resume:
print(f"Processing resume: {resume_text[:50]}...")
try:
# Call your BAML function, which is now a Python method on 'b'
response = b.ExtractResume(resume_text=resume_text)
print("Successfully extracted resume data:")
print(f" Name: {response.name}")
print(f" Title: {response.title}")
return response
except Exception as e:
print(f"An error occurred: {e}")
# In a real application, you'd handle specific BAML errors like BamlValidationError
raise
if __name__ == "__main__":
sample_resume = (
"Name: Alice Wonderland\n"
"Title: Software Engineer\n"
"Experience: 5 years at ExampleCorp, developing scalable backend services.\n"
"Education: M.S. Computer Science, University of XYZ"
)
# This call would only succeed if a baml_src/main.baml with ExtractResume is defined
# and baml-cli generate has been run.
# mock_resume_data = process_resume(sample_resume)
print("To run this, ensure baml-cli init and baml-cli generate have been executed.")
print("And OPENAI_API_KEY is set in your environment.")