Show HN: Burr – A framework for building and debugging GenAI apps faster (github.com)
Burr is a lightweight library that can integrate with your favorite tools and comes with a debugging UI. If you prefer a video introduction, you can watch me build a chatbot here: https://www.youtube.com/watch?v=rEZ4oDN0GdU.
Common friction points we’ve seen with GenAI applications include logically modeling application flow, debugging and recreating error cases, and curating data for testing/evaluation (see https://hamel.dev/blog/posts/evals/). Burr aims to make these easier. You can run Burr locally – see instructions in the repo.
We talked to many companies about the pains they felt in building applications on top of LLMs and were surprised how many built bespoke state management layers and used printlines to debug.
We found that everyone wanted the ability to pull up the state of an application at a given point, poke at it to debug/tweak code, and use for later testing/evaluation. People integrating with LLMOps tools fared slightly better, but these tend to focus solely on API calls to test & evaluate prompts, and left the problem of logically modeling/checkpointing unsolved.
Having platform tooling backgrounds, we felt that a good abstraction would help improve the experience. These problems all got easier to think about when we modeled applications a state machines composed of “actions” designed for introspection (for more read https://blog.dagworks.io/p/burr-develop-stateful-ai-applicat...). We don’t want to limit what people can write, but we do want to constrain it just enough that the framework provides value and doesn’t get in the way. This led us to design Burr with the following core functionalities:
1. BYOF. Burr allows you to bring your own frameworks/delegate to any python code, like LangChain, LlamaIndex, Hamilton, etc. inside of “actions”. This provides you with the flexibility to mix and match so you’re not limited.
2. Pluggability. Burr comes with APIs to allow you to save/load (i.e. checkpoint) application state, run custom code before/after action execution, and add in your own telemetry provider (e.g. langfuse, datadog, DAGWorks, etc.).
3. UI. Burr comes with its own UI (following the python batteries included ethos) that you can run locally, with the intent to connect with your development/debugging workflow. You can see your application as it progresses and inspect its state at any given point.
The above functionalities lend themselves well to building many types of applications quickly and flexibly using the tools you want. E.g. conversational RAG bots, text based games, human in the loop workflows, text to SQL bots, etc. Start with LangChain and then easily transition to your custom code or another framework without having to rewrite much of your application. Side note: we also see Burr as useful outside of interactive GenAI/LLMs applications, e.g. building hyper-parameter optimization routines for chunking and embeddings & orchestrating simulations.
We have a swath of improvements planned. We would love feedback, contributions, & help prioritizing. Typescript support, more ergonomic UX + APIs for annotation and test/eval curation, as well as integrations with common telemetry frameworks and capture of finer grained information from frameworks like LangChain, LlamaIndex, Hamilton, etc…
Re: the name Burr, you may recognize us as the authors of Hamilton (github.com/dagworks-inc/hamilton), named after Alexander Hamilton (the creator of the federal reserve). While Aaron Burr ki...
24 comments
[ 9.1 ms ] story [ 108 ms ] threadTechnical details follow:
You can define an action like this:
Then you would call `application.stream_result()` function, which would give you back a container object that you can stream to the user: Its nice in a web-server or a streamlit app where you can use streaming responses to connect to the frontend. Here's how we use it in a streamlit app -- we plan for a streaming web server soon: https://github.com/DAGWorks-Inc/burr/blob/main/examples/stre....If I'm getting started with LLMs or have 1-2 POC deployed at my company what's the benefit of adding burr to my stack?
If you're getting started with LLMs, the first step is an API call to OpenAI (or some other foundational model) to get a feel for it, then think about how you want to integrate with your application. Burr can help standardize the structure, allowing you to think less about it at any given point (as logic is encapsulated into actions). Furthermore, the UI can help you debug.
With a few POCs at your company (assuming you want to iterate and get into production), Burr can help abstract some complex parts away (state management and telemetry), and make your code cleaner and more extensible, which can help you iterate quickly and explain what you're doing (you can always draw a picture of your app).
We think that it buys companies something they really want -- the ability to swap out implementations/vendors as it decouples the logic from application concerns.
So, if you have logic that's starting to get complicated (and might get more-so), I think Burr is good. If all you're doing is a single wrapper over a GPT-call, it might be overkill (or not! things tend to grow in complexity).
One project was to create a layer between external APIs (OpenAI, Gemini, Claude) and our team. This way we can manage the cost of API calls, try different providers, and log API usage to find out what works / what doesn't.
How does burr scale with an application and support multiple users?
It's just a library so it depends on what could be the bottlenecks. Standard ones are: 1. Compute -- just scale horizontally 2. DB -- scale horizontally (and vertically), use intelligent partitioning
(1) is generally easy with autoscaling, (2) is where your queries/data modeling matter, and this is why we made persistence entirely pluggable, figuring we wouldn't know the best usage patterns yet. More reading: https://burr.dagworks.io/concepts/state-persistence/.
One more thing to think about -- Burr isn't opinionated about how you build your app -- E.G. up to you to think about what happens if you have your webapp open in, say, two tabs. You'll need to manage situations like this, but Burr's plugin capabilities should make that easier to iterate on. We're looking to add more examples on this -- also reach out if you have any specific questions/find anything missing/have suggestions.
That said, logging stuff and using regexes (which is the common way to productionize printlines for live/post-hoc debugging) has a lot of challenges, and this is where we've seen a framework become useful.
There's an obvious trade-off between adopting a framework and rolling your own -- we've seen both work in various contexts (we've been in MLOps for quite a while). Our hope is that this will make people more productive by constraining the space they need to think about and allow more mental room for application logic.
The main concern I have with frameworks is the inversion of control of the code logic, the lack of composition, the complexity of handling edge cases outside the scope of the framework. Frankly writing apps is not my thing typically. PyTorch is moderately unobtrusive, but other tools on top make tons of assumptions and break more often than they help in the long term. Of course with the current zoo of LLM and APIs and the coming popularity of agents, a lot of people will need some help to get started so I wish you the best of luck in your endeavors. Here is some unsolicited advice: as the LLMs get better, you might want to focus on detailed documentation so that the future AIs can master your framework and help your users. Maybe measure the power of your documentation by finetuning in-house LLMs on it and then evaluate known test cases or create new ones with the finetuned models.
100%; lived that story. In my experience this is usually the result of some poor design assumptions on part of the framework. Other times people want to use something for which it wasn't designed for. In the case of Burr, we still have a few things to iron out, but given our platform backgrounds, we're trying to be cognizant of things that have annoyed us in the past, e.g. two big ones: ability to customize parts given esoteric deployment needs (e.g. persistence layer); adding in observability without it coupling you/getting in the way of logic.
> the LLMs get better, you might want to focus on detailed documentation so that the future AIs can master your framework and help your users
Even without LLMs I think this is required ;)
And good point re: good docs for LLMs! On a meta-level there's something very funny about having to write better human-facing docs for the use of computers. Who would have thought that some of our most powerful computing systems emulate how we think!
Which is the right thing anyway. If your target are interactive users a log is a terrible thing to do as they won't know where it ends up. And if the target is not interactive users you should have error codes not log messages.
I think that is partly because today is hard to just attach a debugger to things and see the state of a program so people try to serialise the program state to english strings with a timestamp and work backwards from that to understand what the program was doing, but then what we need is a differentiable single stack core dump not an english approximation of it.
And especially not one that gets stolen by systemd and hidden away.
Sorry for the rant but just printing infos and core dumping errors was the best thing ever and it was taken away from me.
No lol, that's not simple, that's just looking at the defaults that unix systems provide. If you've been hacking this long then you're familiar with all the fun issues like:
* Are you writing to stdout as a buffered or unbuffered stream?
* What happens if your writing process crashes before flushing its buffers if you're using a buffered stream.
* Are you redirecting your log stream into a file on a slow volume?
* Are collected log files being rotated? What happens if the target volume runs out of space before rotation kicks in?
* If you are logging to a file does an error writing to this file block stdout streaming? If so, what happens to your process?
These are hard problems which have a variety of solutions. There are more unix-y solutions such as runit's `svlogd` up to more involved solutions like systemd's `journald`, but problems they are nonetheless. I've hit each and every one of these in a system before, though most in non-prod environments.
That's not to knock println debugging, which continues to be very popular, it's just that logging is actually a hard problem and pretending like it's not as some appeal to systems of yore isn't helpful. But by definition when you're debugging a system you're not in a production environment anyway so you can definitely deal with the log noise that comes with println debugging.
The repo has a mermaid diagram, but the code doesn't really reflect that (which is typical of most agent-ic apps we've found!). So I went about refactoring to add Burr since with Burr we should be able to get close to having code that reflects the desired flow. You can see my Burr version in the following PR; it's could be a little cleaner, but I think I'm leaving it in a better place if you had to figure out what was going on and trying to iterate/debug a response - https://github.com/AgentOps-AI/Jaiqu/pull/5/files.