Skip to content

BAML is a language that helps you get structured data from LLMs, with the best DX possible. Works with all languages. Check out the promptfiddle.com playground

License

Notifications You must be signed in to change notification settings

BoundaryML/baml

Repository files navigation

BAML: Basically a Made-up Language

or "Basic-Ass Machine Learning" if your boss isn't around

GitHub Repo stars License: Apache-2 BAML Version

Try BAML: Prompt FiddleExamplesExample Source Code

5 minute quickstarts PythonTypescriptNextJSRubyOthers (Go, Java, C++, Rust, PHP, etc)

What is BAML? BAML is a new programming language for builing AI applications.
Do I need to write my whole app in BAML? Nope, only the AI parts, you can then use BAML with any existing language of your choice! python, typescript, and more.
Is BAML stable? We are still not 1.0, and we ship updates weekly. We rarely, if at all do breaking changes
Why a new language? Jump to section
Why a lamb? Baaaaa-ml. LAMB == BAML

The core BAML principle: LLM Prompts are functions

The fundamental building block in BAML is a function. Every prompt is a function that takes in parameters and returns a type.

function ChatAgent(message: Message[], tone: "happy" | "sad") -> string

Every function additionally defines which models it uses and what its prompt is.

function ChatAgent(message: Message[], tone: "happy" | "sad") -> StopTool | ReplyTool {
    client "openai/gpt-4o-mini"

    prompt #"
        Be a {{ tone }} bot.

        {{ ctx.output_format }}

        {% for m in message %}
        {{ _.role(m.role) }}
        {{ m.content }}
        {% endfor %}
    "#
}

class Message {
    role string
    content string
}

class ReplyTool {
  response string
}

class StopTool {
  action "stop" @description(#"
    when it might be a good time to end the conversation
  "#)
}

Then in any language of your choice you can do the following:

from baml_client import b
from baml_client.types import Message, StopTool

messages = [Message(role="assistant", content="How can I help?")]

while True:
  print(messages[-1].content)
  user_reply = input()
  messages.append(Message(role="user", content=user_reply))
  tool = b.ChatAgent(messages, "happy")
  if isinstance(tool, StopTool):
    print("Goodbye!")
    break
  else:
    messages.append(Message(role="assistant", content=tool.reply))

Making prompts easy to find and read

Since every prompt is a function, we can build tools to find every prompt you've written. But we've taken BAML one step further and built native tooling for VSCode (jetbrains + neovim coming soon).

  1. You can see the full prompt (including any multi-modal assets) Multi Modal
  2. You can see the exact network request we are making Token Preview
  3. You can see every function you've ever written

Functions

Swapping models: 1-line change

It's just 1 line (ok, maybe 2). Docs Sorry Sam

Retry policiesfallbacksmodel rotations. All statically defined. Fallback Retry

Want to do pick models at runtime? Check out Client Registry.

We currently support: OpenAIAnthropicGeminiVertexBedrockAzure OpenAIAnything OpenAI Compatible (Ollama, OpenRouter, VLLM, LMStudio, TogetherAI, and more)

Hot-reloading for prompts

Using AI is all about iteration speed.

If testing your pipeline takes 2 minutes, in 20 minutes, you can only test 10 ideas.

If testing your pipeline took 5 seconds, in 20 minutes, you can test 240 ideas.

Introducing testing, for prompts.

Hot Reload

Structured outputs with any LLM

JSON is amazing for REST APIs, but way too strict and verbose for LLMs. LLMs need something flexible. We created the SAP (schema-aligned parsing) algorithm to support the flexible outputs LLMs can provide, like markdown within a json blob or chain-of-thought prior to answering.

Chain of Thought

SAP works with any model on day-1, without depending on tool-use or function-calling APIs.

To learn more about SAP you can read this post: Schema Aligned Parsing.

See it in action with: Deepseek-R1 and OpenAI O1.

Streaming (when it's a first class citizen)

Streaming is way harder than it should be. With our [python/typescript/ruby] generated code, streaming becomes natural and type-safe.

Streaming

No strings attached

  • 100% open-source (Apache 2)
  • 100% private. AGI will not require an internet connection, neither will BAML
    • No network requests beyond model calls you explicitly set
    • Not stored or used for any training data
  • BAML files can be saved locally on your machine and checked into Github for easy diffs.
  • Built in Rust. So fast, you can't even tell its there.

BAML's Design Philosophy

Everything is fair game when making new syntax. If you can code it, it can be yours. This is our design philosophy to help restrict ideas:

  • 1: Avoid invention when possible
    • Yes, prompts need versioning — we have a great versioning tool: git
    • Yes, you need to save prompts — we have a great storage tool: filesystems
  • 2: Any file editor and any terminal should be enough to use it
  • 3: Be fast
  • 4: A first year university student should be able to understand it

Why a new programming language

We used to write websites like this:

def home():
    return "<button onclick=\"() => alert(\\\"hello!\\\")\">Click</button>"

And now we do this:

function Home() {
  return <button onClick={() => setCount(prev => prev + 1)}>
          {count} clicks!
         </button>
}

New syntax can be incredible at expressing new ideas. Plus the idea of mainting hundreds of f-strings for prompts kind of disgusts us 🤮. Strings are bad for maintable codebases. We prefer structured strings.

The goal of BAML is to give you the expressiveness of English, but the structure of code.

Full blog post by us.

Conclusion

As models get better, we'll continue expecting even more out of them. But what will never change is that we'll want a way to write maintainable code that uses those models. The current way we all just assemble strings is very reminiscent of the early days PHP/HTML soup in web development. We hope some of the ideas we shared today can make a tiny dent in helping us all shape the way we all code tomorrow.

Contributing

Checkout our guide on getting started


Made with ❤️ by Boundary

HQ in Seattle, WA

P.S. We're hiring for software engineers that love rust. Email us or reach out on discord!