blob: f6ae9ba3b1479cf6ae46101ce7d4cf0223e36684 [file] [log] [blame]
.. _simpleexample:
=================
Simple Example
=================
This simple example is just to learn the basics of the library. The application we're building is not particularly interesting,
but it will get you powerful. If you want to skip ahead to the cool stuff (chatbots,
ML training, simulations, etc...) feel free to jump into the deep end and start with the :ref:`examples <examples>`.
We will go over enough of the concepts to help you understand the code, but there is a much more in-depth set of
explanations in the :ref:`concepts <concepts>` section.
🤔 For an alternative example to get started with, you can also check out
`this video walkthrough <https://www.youtube.com/watch?v=rEZ4oDN0GdU>`_
using `this notebook <https://github.com/DAGWorks-Inc/burr/blob/main/examples/conversational-rag/notebook.ipynb>`_.
------------------
Build a Counter
------------------
We're going to build a counter application. This counter will count to 10 and then stop.
Let's start by defining some actions, the building-block of Burr. You can think of actions as a function that
computes a result and modifies state. They declare what they read and write.
Let's define two actions:
1. A counter action that increments the counter
2. A printer action that prints the counter
.. code-block:: python
@action(reads=["counter"], writes=["counter"])
def count(state: State) -> Tuple[dict, State]:
current = state["counter"] + 1
result = {"counter": current}
print("counted to ", current)
return result, state.update(**result) # return both the intermediate
@action(reads=["counter"], writes=[])
def done(state: State) -> Tuple[dict, State]:
print("Bob's your uncle")
return {}, state
This is an action that reads the "counter" from the state, increments it by 1, and then writes the new value back to the state.
It returns both the intermediate result (``result``) and the updated state.
Next, let's put together our application. To do this, we'll use an ``ApplicationBuilder``
.. code-block:: python
from burr.core import ApplicationBuilder, default, expr
app = (
ApplicationBuilder()
.with_state(counter=0) # initialize the count to zero
.with_actions(
count=count, # add the counter action with the name "counter"
done=done # add the printer action with the name "printer"
).with_transitions(
("count", "count", expr("counter < 10")), # Keep counting if the counter is less than 10
("count", "done", default) # Otherwise, we're done
).with_entrypoint("count") # we have to start somewhere
.with_tracker(project="my_first_app")
.build()
)
We can visualize the application (note you need ``burr[graphviz]`` installed):
.. code-block:: python
app.visualize("./graph", format="png", include_conditions=True, include_state=True)
.. image:: ../_static/counter.png
:align: center
As you can see, we have:
1. The action ``count`` that reads and writes the ``counter`` state field
2. The action ``done`` that reads the ``counter`` state field
3. A transition from ``count`` to ``count`` if ``counter < 10``
4. A transition from ``count`` to ``done`` otherwise
Finally, we can run the application:
.. code-block:: python
app.run(halt_after=["printer"])
If you want to copy/paste, you can open up the following code block and add to a file called ``run.py``:
.. collapse:: <code>run.py</code>
.. code-block:: python
from typing import Tuple
from burr.core import (
action,
State,
ApplicationBuilder,
default,
expr
)
@action(reads=["counter"], writes=["counter"])
def count(state: State) -> Tuple[dict, State]:
current = state["counter"] + 1
result = {"counter": current}
print("counted to ", current)
return result, state.update(**result) # return both the intermediate
@action(reads=["counter"], writes=[])
def done(state: State) -> Tuple[dict, State]:
print("Bob's your uncle")
return {}, state
if __name__ == '__main__':
app = (
ApplicationBuilder()
.with_state(counter=0) # initialize the count to zero
.with_actions(
count=count, # add the counter action with the name "counter"
done=done # add the printer action with the name "printer"
).with_transitions(
("count", "count", expr("counter < 10")), # Keep counting if the counter is less than 10
("count", "done", default) # Otherwise, we're done
).with_entrypoint("count") # we have to start somewhere
.with_tracker(project="my_first_app")
.build()
)
app.visualize("./graph", format="png", include_conditions=True, include_state=True)
app.run(halt_after=["done"])
And the output looks exactly as we expect!
.. code-block:: text
$ python run.py
counted to 1
counted to 2
counted to 3
counted to 4
counted to 5
counted to 6
counted to 7
counted to 8
counted to 9
counted to 10
Bob's your uncle
Finally, let's open up the UI and see what it looks like (note, that if you have not installed ``burr[learn]`` now is a good time...).
.. code-block:: bash
burr
You'll see the UI pop up with projects. Navigate to `the UI <http://localhost:7241/project/my_first_app>`_ and explore!
All this to increment? Well, if all you want to do is count to 10, this might not be for you. But we imagine most of you want to do more exciting things
than count to 10...