Week of November 11th
Stefan Krawczyk
CEO @ DAGWorks Inc. | Co-creator of Hamilton & Burr | Pipelines & Agents: Data, Data Science, Machine Learning, & LLMs
TL;DR:
Hamilton Release Highlights:
Hamilton Framework == 1.83.1
Minor improvements:
?? Fixes:
Burr Release Highlights
Burr == 0.33.0
Framework level Parallelism
Super excited to ship this highly requested feature. This is to reduce the boilerplate of what you could already do with Burr.
Why might you want this? Well people want fast experiences. Parallelization is one way to do that. For example, if you're doing medical diagnosis and want to try 10 different hypotheses in parallel on the same context (i.e. patient info), or you have a list of 10 items in context you want to run the same action over in parallel (e.g. web scraping), then we've just made doing that much simpler.
How does it work? Well if you're familiar with the "map-reduce" pattern, then what we shipped will look (see below) and sound familiar:
To use this, you need to create a class, that enables you to do one of three things:
Actions here can be a single "Burr action", or itself a whole "Burr subgraph". I'll skip the latter and use the former to explain mapping over actions and over state.
Map over State
To map over state you need to:
from burr.core import action, state
from burr.core.parallelism import MapStates,
from typing import Callable, Generator, List
@action(reads=["prompt"], writes=["llm_output"])
def query_llm(state: State) -> State:
return state.update(llm_output=_query_my_llm(prompt=state["prompt"]))
You then need to define a "wrapper" class that will take the above action and map it over states and reduce the result back to state:
class TestMultiplePromptsAction(MapStates):
def action(self) -> Action | Callable | RunnableGraph:
# make sure to add a name to the action
# This is not necessary for subgraphs, as actions will already have names
return query_llm.with_name("query_llm")
def states(self, state: State) -> Generator[State, None, None]:
# You could easily have a list_prompts upstream action that writes to "prompts" in state
# And loop through those
# This hardcodes for simplicity
for prompt in [
"What is the meaning of life?",
"What is the airspeed velocity of an unladen swallow?",
"What is the best way to cook a steak?",
]:
yield state.update(prompt=prompt)
def reduce(self, states: Generator[State, None, None]) -> State:
# This reduces the result of the map
all_llm_outputs = []
for state in states:
all_llm_outputs.append(state["llm_output"])
return state.update(all_llm_outputs=all_llm_outputs)
def reads() -> List[str]:
return ["prompts"]
def writes() -> List[str]:
return ["all_llm_outputs"]
Then to build an application it would look something like:
app = (
ApplicationBuilder()
.with_action(
prompt_generator=generate_prompts, # skipped
multi_prompt_test=TestMultiplePrompts(), # you instantiate the class
).with_transitions(
("prompt_generator", "multi_prompt_test"),
)
.build()
)
Map over Actions
For mapping over actions, the API is similar, we implement a different class and then return multiple actions:
from burr.core import action, state
from burr.core.parallelism import MapActions, RunnableGraph
from typing import Callable, Generator, List
@action(reads=["prompt", "model"], writes=["llm_output"])
def query_llm(state: State, model: str) -> State:
# we parameterize model and create multiple actions below
llm_output = _query_my_llm(prompt=state["prompt"], model=model)
return state.update(llm_output=llm_output)
We will use the above action to generate multiple of them. In this case they look similar, but they need not be and could be very different Burr actions. Below we show how one would generate multiple actions that would all then be passed the prompt state value in parallel, and the reduce together into a single output.
class TestMultipleModels(MapActions):
# the actions method will actions to map over
def actions(self, state: State) -> Generator[Action | Callable | RunnableGraph, None, None]:
# Make sure to add a name to the action if you use bind() with a function,
# note that these can be different actions, functions, etc...
# in this case we're using `.bind()` to create multiple actions, but we can use some mix of
# subgraphs, functions, action objects, etc...
for action in [
query_llm.bind(model="gpt-4").with_name("gpt_4_answer"),
query_llm.bind(model="o1").with_name("o1_answer"),
query_llm.bind(model="claude").with_name("claude_answer"),
]
yield action
def state(self, state: State) -> State:
# we can set some input state if needed.
return state
def reduce(self, states: Generator[State, None, None]) -> State:
# we reduce the results
all_llm_outputs = []
for state in states:
all_llm_outputs.append(state["llm_output"])
return state.update(all_llm_outputs=all_llm_outputs)
def reads() -> List[str]:
return ["prompt"]
def writes() -> List[str]:
return ["all_llm_outputs"]
This is just the initial rollout, there's a lot more that I didn't cover. See here for details. Otherwise a few things to expect next week and the week after:
Office Hours & Meetup
Hamilton Meet up: Our next meet-up will be December. Want to present? Reach out. Otherwise join/sign-up here.
Hamilton Office Hours: They happen most Tuesday 9:30am PT - 10:30am PT.
Join our slack for the link.
Burr Office Hours: They happen most Wednesdays 9:30am PT - 10:3am PT.
Join our discord for the weekly link.
Running a Maven course on Building GenAI Applications
I’m hosting a #free event with Hugo Bowne-Anderson on Maven about "Building #GenAI from First Principles".
This 30-min session is for #SoftwareEngineers and #DataScientists #MachineLearningEngineers who want to know:
#1 The first principles to know for building with GenAI.
#2 Techniques for wrangling non-determinism.
#3 Components / Processes you'll need to build out for a productive software development cycle (SDLC).
Join LIVE on Tuesday 11/19 4pm PT!
RSVP here ??:
Blog Post: Flashcard generator with Instructor + Burr
We're excited to post this example by Thierry Jean on using both the instructor and Burr libraries to create a small flashcard app. It transcribes youtube videos to create flashcards.
In the Wild:
Hamilton in a capstone RAG project
Hamilton was used as part of a RAG app for a capstone project by Eric Brichetto ! He wrote about it on LinkedIn. Hamilton was core to the scalable and modular architecture he built, and to learn more you can watch his video walkthrough explanation of it.
Burr: powering wingman SQL assistant
Salesteq Inc. continues to build more production use cases with Burr! We're excited to see where they take the platform!
Burr featured by Unwind AI
Super excited Burr was picked up by Unwind AI . They did an excellent job of putting together a video and explaining in plain terms the value and features that Burr provides:
Here's what makes it special:
→ Visual debugging in real-time
→ Built for production from day one
→ Works with any Python code, not just LLMs
→ Simple building blocks, powerful results
→ Complete toolkit for deployment
The magic? State machines.
Instead of adding endless print statements or digging through logs, Burr shows you exactly how your agent thinks through an interactive graph.
Want to know why your chatbot gave that response? Just click on any node to see the exact state and data at that moment.
Need to add safety checks? Draw the logic flow and Burr handles the rest.
Building features like:
? Conversation history
? Complex decision trees
? Streaming responses
? State persistence
? Safety guardrails
All become visual building blocks you can see and debug.
To see the video, check out the post: