Skip to content

Commit

Permalink
Merge branch 'canary' into orchestration_graph
Browse files Browse the repository at this point in the history
  • Loading branch information
hellovai authored Aug 4, 2024
2 parents f631b15 + 5ef7f3d commit 64e3557
Show file tree
Hide file tree
Showing 65 changed files with 4,745 additions and 665 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
<a href="https://boundaryml.com?utm_source=github" target="_blank" rel="noopener noreferrer">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://www.boundaryml.com/gloo-ai-square-256.png">
<img src="https://www.boundaryml.com/gloo-ai-square-256.png" height="64">
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/baml-lamb-white.png">
<img src="docs/assets/baml-lamb-white.png" height="64">
</picture>

</a>

# BAML

**BAML is a domain-specific-language to write and test LLM functions.**
BAML is a domain-specific-language to write and test LLM functions.

An LLM function is a prompt template with some defined input variables, and a specific output type like a class, enum, union, optional string, etc.
With BAML you can write and test a complex LLM function in 1/10 of the time it takes to setup a python LLM testing environment.

BAML LLM functions plug into python, TS, and other languages, which makes it easy to focus more on engineering and less on prompting.

BAML outperforms all other current methods of getting structured data, even when using it with GPT3.5. It also outperforms models fine-tuned for tool-use. See the [Berkeley Function Calling Benchmark](https://gorilla.cs.berkeley.edu/leaderboard.html) results. [Read more on our Schema-Aligned Parser](https://www.boundaryml.com/blog/schema-aligned-parsing).

<img src="docs/assets/bfcl-baml.png" width="80%" alt="Boundary Studio">

## Try it out in the playground -- [PromptFiddle.com](https://promptfiddle.com)

Expand Down Expand Up @@ -186,7 +191,7 @@ Showcase of applications using BAML

Analyze, label, and trace each request in [Boundary Studio](https://app.boundaryml.com).

<img src="docs/images/v3/pipeline_view.png" width="80%" alt="Boundary Studio">
<img src="docs/assets/images/v3/pipeline_view.png" width="80%" alt="Boundary Studio">

## Why not just use an existing Python framework?

Expand Down
Binary file added docs/assets/baml-lamb-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/bfcl-baml.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/favicon.ico
Binary file not shown.
4 changes: 2 additions & 2 deletions docs/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,10 @@ colors:
light: "#fefefe"
# dark: "#14191f"
logo:
light: assets/favicon.png
light: assets/favicon.ico
# dark: assets/favicon.png
height: 40
favicon: assets/favicon.png
favicon: assets/favicon.ico
css: assets/styles.css
layout:
page-width: full
Expand Down
33 changes: 29 additions & 4 deletions docs/docs/calling-baml/client-registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
title: Client Registry
slug: docs/calling-baml/client-registry
---

{/* TODO: use fern Group elements instead of CodeBlock elements for Python/TS/Ruby */}

If you need to modify the model / parameters for an LLM client at runtime, you can modify the `ClientRegistry` for any specified function.

<CodeBlocks>

```python Python
import os
from baml_py import ClientRegistry

async def run():
Expand All @@ -17,7 +18,7 @@ async def run():
cr.add_llm_client(name='MyAmazingClient', provider='openai', options={
"model": "gpt-4o",
"temperature": 0.7,
"api_key": "sk-..."
"api_key": os.environ.get('OPENAI_API_KEY')
})
# Sets MyAmazingClient as the primary client
cr.set_primary('MyAmazingClient')
Expand All @@ -35,7 +36,7 @@ async function run() {
cr.addLlmClient({ name: 'MyAmazingClient', provider: 'openai', options: {
model: "gpt-4o",
temperature: 0.7,
api_key: "sk-..."
api_key: process.env.OPENAI_API_KEY
}})
// Sets MyAmazingClient as the primary client
cr.setPrimary('MyAmazingClient')
Expand All @@ -46,7 +47,31 @@ async function run() {
```

```ruby Ruby
Not available yet
require_relative "baml_client/client"

def run
cr = Baml::ClientRegistry.new

# Creates a new client
cr.add_llm_client(
name: 'MyAmazingClient',
provider: 'openai',
options: {
model: 'gpt-4o',
temperature: 0.7,
api_key: ENV['OPENAI_API_KEY']
}
)

# Sets MyAmazingClient as the primary client
cr.set_primary('MyAmazingClient')

# ExtractResume will now use MyAmazingClient as the calling client
res = Baml.Client.extract_resume(input: '...', baml_options: { client_registry: cr })
end

# Call the asynchronous function
run
```

</CodeBlocks>
Expand Down
88 changes: 75 additions & 13 deletions docs/docs/calling-baml/dynamic-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
slug: docs/calling-baml/dynamic-types
---

Sometimes you have a **output schemas that change at runtime** -- for example if
you have a list of Categories that you need to classify that come from a
database, or your schema is user-provided.


Sometimes you have a **output schemas that change at runtime** -- for example if you have a list of Categories that you need to classify that come from a database, or your schema is user-provided.


**Dynamic types are types that can be modified at runtime**, which means you can change the output schema of a function at runtime.
**Dynamic types are types that can be modified at runtime**, which means you can
change the output schema of a function at runtime.

Here are the steps to make this work:
1. Add `@@dynamic` to the class or enum definition to mark it as dynamic
Expand All @@ -31,11 +31,14 @@ function DynamicCategorizer(input: string) -> Category {

```

2. Create a TypeBuilder and modify the existing type. All dynamic types you define in BAML will be available as properties of `TypeBuilder`. Think of the typebuilder as a registry of modified runtime types that the baml function will read from when building the output schema in the prompt.
2. Create a TypeBuilder and modify the existing type. All dynamic types you
define in BAML will be available as properties of `TypeBuilder`. Think of the
typebuilder as a registry of modified runtime types that the baml function will
read from when building the output schema in the prompt.

<CodeBlocks>

```python python
```python Python
from baml_client.type_builder import TypeBuilder
from baml_client import b

Expand Down Expand Up @@ -66,9 +69,17 @@ async function run() {
}
```

```ruby Ruby
require_relative '../baml_client'

```ruby Ruby (beta)
Not available yet
def run
tb = Baml::TypeBuilder.new
tb.Category.add_value('VALUE3')
tb.Category.add_value('VALUE4')
res = Baml.Client.dynamic_categorizer(input: "some input", baml_options: {tb: tb})
# Now res can be VALUE1, VALUE2, VALUE3, or VALUE4
puts res
end
```
</CodeBlocks>

Expand Down Expand Up @@ -97,7 +108,7 @@ Modify the `User` schema at runtime:

<CodeBlocks>

```python python
```python Python
from baml_client.type_builder import TypeBuilder
from baml_client import b

Expand Down Expand Up @@ -126,6 +137,20 @@ async function run() {
console.log(res)
}
```

```ruby Ruby
require_relative 'baml_client/client'

def run
tb = Baml::TypeBuilder.new
tb.User.add_property('email', tb.string)
tb.User.add_property('address', tb.string)

res = Baml.Client.dynamic_user_creator(input: "some user info", baml_options: {tb: tb})
# Now res can have email and address fields
puts res
end
```
</CodeBlocks>

### Creating new dynamic classes or enums not in BAML
Expand All @@ -134,7 +159,7 @@ Here we create a new `Hobbies` enum, and a new class called `Address`.

<CodeBlocks>

```python python
```python Python
from baml_client.type_builder import TypeBuilder
from baml_client import b

Expand Down Expand Up @@ -176,13 +201,34 @@ async function run() {
console.log(res)
}
```

```ruby Ruby
require_relative 'baml_client/client'

def run
tb = Baml::TypeBuilder.new
hobbies_enum = tb.add_enum('Hobbies')
hobbies_enum.add_value('Soccer')
hobbies_enum.add_value('Reading')

address_class = tb.add_class('Address')
address_class.add_property('street', tb.string)

tb.User.add_property('hobby', hobbies_enum.type.optional)
tb.User.add_property('address', address_class.type.optional)

res = Baml::Client.dynamic_user_creator(input: "some user info", baml_options: { tb: tb })
# Now res might have the hobby property, which can be Soccer or Reading
puts res
end
```
</CodeBlocks>

### Adding descriptions to dynamic types

<CodeBlocks>

```python python
```python Python
tb = TypeBuilder()
tb.User.add_property("email", tb.string()).description("The user's email")
```
Expand All @@ -192,6 +238,11 @@ const tb = new TypeBuilder()
tb.User.addProperty("email", tb.string()).description("The user's email")
```

```ruby Ruby
tb = Baml::TypeBuilder.new
tb.User.add_property("email", tb.string).description("The user's email")
```

</CodeBlocks>

### Building dynamic types from JSON schema
Expand All @@ -202,7 +253,7 @@ something you'd like to use.

<CodeBlocks>

```python python
```python Python
import pydantic
from baml_client import b

Expand Down Expand Up @@ -241,4 +292,15 @@ const res = await b.ExtractPeople(
)
```

```ruby Ruby
tb = Baml::TypeBuilder.new
tb.unstable_features.add_json_schema(...)

res = Baml::Client.extract_people(
input: "My name is Harrison. My hair is black and I'm 6 feet tall. I'm pretty good around the hoop. I like giraffes.",
baml_options: { tb: tb }
)

puts res
```
</CodeBlocks>
2 changes: 1 addition & 1 deletion docs/docs/get-started/quickstart/ruby.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To set up BAML in ruby do the following:
### Install baml
```bash
bundle init
bundle add baml sorbet-runtime sorbet-struct-comparable
bundle add baml sorbet-runtime
```

### Add some starter code
Expand Down
42 changes: 37 additions & 5 deletions docs/docs/snippets/supported-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ from baml_client import b
async def test_image_input():
# from URL
res = await b.TestImageInput(
img=Image.from_url(
"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png"
)
img=Image.from_url("https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png")
)

# Base64 image
Expand All @@ -73,7 +71,23 @@ import { Image } from "@boundaryml/baml"
```

```ruby Ruby
(we're working on it!)
require_relative "baml_client/client"

b = Baml.Client
Image = Baml::Image

def test_image_input
# from URL
res = b.TestImageInput(
img: Image.from_url("https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png")
)

# Base64 image
image_b64 = "iVBORw0K...."
res = b.TestImageInput(
img: Image.from_base64("image/png", image_b64)
)
end
```
</CodeBlocks>

Expand Down Expand Up @@ -131,7 +145,25 @@ import { Audio } from "@boundaryml/baml"
```

```ruby Ruby
we're working on it!
require_relative "baml_client/client"

b = Baml.Client
Audio = Baml::Audio

def test_audio_input
# from URL
res = b.TestAudioInput(
audio: Audio.from_url(
"https://actions.google.com/sounds/v1/emergency/beeper_emergency_call.ogg"
)
)

# Base64 image
audio_b64 = "iVBORw0K...."
res = b.TestAudioInput(
audio: Audio.from_base64("audio/mp3", audio_b64)
)
end
```
</CodeBlocks>

Expand Down
Loading

0 comments on commit 64e3557

Please sign in to comment.