You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/dbos.md
+31-47Lines changed: 31 additions & 47 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,41 +1,22 @@
1
1
# Durable Execution with DBOS
2
2
3
-
!!! note
4
-
Durable execution support is in beta and the public interface is subject to change based on user feedback. We expect it to be stable by the release of Pydantic AI v1 at the end of August. Questions and feedback are welcome in [GitHub issues](https://github.com/pydantic/pydantic-ai/issues) and the [`#pydantic-ai` Slack channel](https://logfire.pydantic.dev/docs/join-slack/).
5
-
6
3
Pydantic AI allows you to build durable agents that can preserve their progress across transient API failures and application errors or restarts, and handle long-running, asynchronous, and human-in-the-loop workflows with production-grade reliability. Durable agents have full support for [streaming](agents.md#streaming-all-events) and [MCP](mcp/client.md), with the added benefit of fault tolerance.
7
4
8
-
[DBOS](https://www.dbos.dev/) is a lightweight [durable execution](https://docs.dbos.dev/architecture) library that's natively supported by Pydantic AI.
9
-
The integration only uses Pydantic AI's public interface, so it can also serve as a reference for how to integrate with other durable execution systems.
5
+
[DBOS](https://www.dbos.dev/) is a lightweight [durable execution](https://docs.dbos.dev/architecture) library natively integrated with Pydantic AI. The integration only uses Pydantic AI's public interface, so it also serves as a reference for integrating with other durable systems.
10
6
11
7
### Durable Execution
12
8
13
-
In DBOS's durable execution implementation, a program that crashes or encounters an exception while interacting with a model or API will retry until it can successfully complete.
14
-
15
-
DBOS relies primarily on a replay mechanism to recover from failures.
16
-
As the program makes progress, DBOS saves key inputs and decisions, allowing a re-started program to pick up right where it left off.
17
-
18
-
The key to making this work is to separate the application's repeatable (deterministic) and non-repeatable (non-deterministic) parts:
19
-
20
-
1. Deterministic pieces, termed [**workflows**](https://docs.dbos.dev/python/tutorials/workflow-tutorial), execute the same way when re-run with the same inputs.
21
-
2. Non-deterministic pieces, termed [**steps**](https://docs.dbos.dev/python/tutorials/step-tutorial), can run arbitrary code, performing I/O and any other operations.
22
-
23
-
Workflow code can run for extended periods and, if interrupted, resume exactly where it left off.
24
-
Critically, workflow code generally _cannot_ include any kind of I/O, over the network, disk, etc.
25
-
Step code faces no restrictions on I/O or external interactions, but if a step fails part-way through it is restarted from the beginning.
26
-
27
-
28
-
!!! note
9
+
DBOS workflows make your program **durable** by checkpointing its state in a database. If your program ever fails, when it restarts all your workflows will automatically resume from the last completed step.
29
10
30
-
If you are familiar with celery, it may be helpful to think of DBOS steps as similar to celery tasks, but where you wait for the task to complete and obtain its result before proceeding to the next step in the workflow.
31
-
However, DBOS workflows and steps offer a great deal more flexibility and functionality than celery tasks.
11
+
***Workflows** must be deterministic and generally cannot include I/O.
12
+
***Steps** may perform I/O (network, disk, API calls). If a step fails, it restarts from the beginning.
32
13
33
-
See the [DBOS documentation](https://docs.dbos.dev/architecture) for more information.
14
+
Every workflow input and step output is durably stored in the system database. When workflow execution fails, whether from crashes, network issues, or server restarts, DBOS leverages these checkpoints to recover workflows from their last completed step.
34
15
35
-
In the case of Pydantic AI agents, integration with DBOS means that [model requests](models/index.md), [tool calls](tools.md) that may require I/O, and [MCP server communication](mcp/client.md) all need to be offloaded to DBOS steps due to their I/O requirements, while the logic that coordinates them (i.e. the agent run) lives in the workflow. Code that handles a scheduled job or web request can then execute the workflow, which will in turn execute the steps as needed.
16
+
DBOS **queues** provide durable, database-backed alternatives to systems like Celery or BullMQ, supporting features such as concurrency limits, rate limits, timeouts, and prioritization. See the [DBOS docs](https://docs.dbos.dev/architecture) for details.
36
17
37
18
The diagram below shows the overall architecture of an agentic application in DBOS.
38
-
DBOS is lightweight because it runs entirely in-process as a library, so your workflows and steps remain normal functions within your application that you can call from other application code. DBOS instruments them to checkpoint their state into a database (i.e., possibly replicated across cloud regions).
19
+
DBOS runs fully in-process as a library. Functions remain normal Python functions but are checkpointed into a database (Postgres or SQLite).
39
20
40
21
```text
41
22
Clients
@@ -66,18 +47,20 @@ See the [DBOS documentation](https://docs.dbos.dev/architecture) for more inform
66
47
67
48
## Durable Agent
68
49
69
-
Any agent can be wrapped in a [`DBOSAgent`][pydantic_ai.durable_exec.dbos.DBOSAgent] to get a durable agent, by automatically wrapping the agent run loop as a deterministic DBOS workflow and offloading work that requires I/O (namely model requests and MCP server communication) to non-deterministic steps. To make it flexible, `DBOSAgent`doesn't automatically wrap other tool functions, so you can decorate them as either DBOS workflows or steps as needed.
50
+
Any agent can be wrapped in a [`DBOSAgent`][pydantic_ai.durable_exec.dbos.DBOSAgent] to get durable execution. `DBOSAgent` automatically:,
70
51
71
-
At the time of wrapping, the agent's [model](models/index.md) and [MCP server communication](mcp/client.md) are wrapped as DBOS steps instead of directly invoking the original functions inside the workflow. The original agent can still be used as normal outside the DBOS workflow.
52
+
* Wraps `Agent.run` and `Agent.run_sync` as DBOS workflows.
53
+
* Wraps [model requests](models/index.md) and [MCP communication](mcp/client.md) as DBOS steps.
72
54
73
-
Here is a simple but complete example of wrapping an agent for durable execution. All it requires is to install the DBOS[open-source library](https://github.com/dbos-inc/dbos-transact-py):
55
+
Custom tool functions are not wrapped automatically. You can decorate them with `@DBOS.workflow` or `@DBOS.step` as needed.
74
56
75
-
```sh
76
-
uv add pydantic-ai[dbos]
77
-
```
57
+
The original agent, model, and MCP server can still be used as normal outside the DBOS workflow.
58
+
59
+
Here is a simple but complete example of wrapping an agent for durable execution. All it requires is to install Pydantic AI with the DBOS [open-source library](https://github.com/dbos-inc/dbos-transact-py):
78
60
79
-
or if you use pip:
80
61
```sh
62
+
uv add pydantic-ai[dbos]
63
+
# or
81
64
pip install pydantic-ai[dbos]
82
65
```
83
66
@@ -108,9 +91,9 @@ async def main():
108
91
#> Mexico City (Ciudad de México, CDMX)
109
92
```
110
93
111
-
1.The original `Agent` cannot be used inside a deterministic DBOS workflow, but the `DBOSAgent` can. Workflow function declarations and `DBOSAgent`creations need to happen before calling `DBOS.launch()` because DBOS requires all workflows to be registered before launch so that recovery can correctly find all workflows.
112
-
2.[`DBOSAgent.run()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run] works like [`Agent.run()`][pydantic_ai.Agent.run], but runs inside a DBOS workflow and wraps model requests, decorated tool calls, and MCP communication as DBOS steps.
113
-
3. This assumes DBOS is using SQLite. To deploy your agent to production, we recommend using a Postgres server.
94
+
1.Workflows and `DBOSAgent`must be defined before `DBOS.launch()` so that recovery can correctly find all workflows.
95
+
2.[`DBOSAgent.run()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run] works like [`Agent.run()`][pydantic_ai.Agent.run], but runs as a DBOS workflow and executes model requests, decorated tool calls, and MCP communication as DBOS steps.
96
+
3. This example uses SQLite. Postgres is recommended for production.
114
97
4. The agent's `name` is used to uniquely identify its workflows.
115
98
116
99
_(This example is complete, it can be run "as is" — you'll need to add `asyncio.run(main())` to run `main`)_
@@ -121,34 +104,35 @@ For more information on how to use DBOS in Python applications, see their [Pytho
121
104
122
105
## DBOS Integration Considerations
123
106
124
-
There are a few considerations specific to agents and toolsets when using DBOS for durable execution. These are important to understand to ensure that your agents and toolsets work correctly with DBOS's workflow and step model.
107
+
When using DBOS with Pydantic AI agents, there are a few important considerations to ensure workflows and toolsets behave correctly.
125
108
126
109
### Agent and Toolset Requirements
127
110
128
-
To ensure that DBOS knows what code to run when a workflow fails or is interrupted and then restarted, each agent instance needs to have a unique name.
111
+
Each agent instance must have a unique `name` so DBOS can correctly resume workflows after a failure or restart. Tools that perform I/O or external interactions should be annotated as DBOS steps.
129
112
130
113
Other than that, any agent and toolset will just work!
131
114
132
115
### Agent Run Context and Dependencies
133
116
134
-
As DBOS checkpoints workflow and step execution into a database, workflow inputs and outputs, and step outputs need to be serializable (JSON pickleable). You may also want to keep the inputs and outputs small (the maximum size for a single field in PostgreSQL is 1 GB, but usually you want to keep the output size under 2 MB).
117
+
DBOS checkpoints workflow inputs/outputs and step outputs into a database using `jsonpickle`. This means you need to make sure [dependencies](dependencies.md) object provided to [`DBOSAgent.run()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run] or [`DBOSAgent.run_sync()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run_sync], and tool outputs can be serialized using jsonpickle. You may also want to keep the inputs and outputs small (under \~2 MB). PostgreSQL and SQLite support up to 1 GB per field, but large objects may impact performance.
135
118
136
119
### Streaming
137
120
138
-
Because DBOS steps cannot stream output directly to the step call site, [`Agent.run_stream()`][pydantic_ai.Agent.run_stream] is not supported.
121
+
Because DBOS cannot stream output directly to the workflow or step call site, [`Agent.run_stream()`][pydantic_ai.Agent.run_stream] is not supported when running inside of a DBOS workflow.
139
122
140
123
Instead, you can implement streaming by setting an [`event_stream_handler`][pydantic_ai.agent.EventStreamHandler] on the `Agent` or `DBOSAgent` instance and using [`DBOSAgent.run()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run].
141
124
The event stream handler function will receive the agent [run context][pydantic_ai.tools.RunContext] and an async iterable of events from the model's streaming response and the agent's execution of tools. For examples, see the [streaming docs](agents.md#streaming-all-events).
142
125
143
126
144
127
## Step Configuration
145
128
146
-
DBOS step configuration, like retry policies, can be customized by passing [`StepConfig`][pydantic_ai.durable_exec.dbos.StepConfig] objects to the `DBOSAgent` constructor:
129
+
You can customize DBOS step behavior, such as retries, by passing [`StepConfig`][pydantic_ai.durable_exec.dbos.StepConfig] objects to the `DBOSAgent` constructor:
130
+
131
+
-`mcp_step_config`: The DBOS step config to use for MCP server communication. No retries if omitted.
132
+
-`model_step_config`: The DBOS step config to use for model request steps. No retries if omitted.
147
133
148
-
-`mcp_step_config`: The DBOS step config to use for MCP server communication. If no config is provided, it disables DBOS step retries.
149
-
-`model_step_config`: The DBOS step config to use for model request steps. If no config is provided, it disables DBOS step retries.
134
+
For custom tools, you can annotate them directly with [`@DBOS.step`](https://docs.dbos.dev/python/reference/decorators#step) or [`@DBOS.workflow`](https://docs.dbos.dev/python/reference/decorators#workflow) decorators as needed. These decorators have no effect outside DBOS workflows, so tools remain usable in non-DBOS agents.
150
135
151
-
For individual tools, you can annotate them with [`@DBOS.step`](https://docs.dbos.dev/python/reference/decorators#step) or [`@DBOS.workflow`](https://docs.dbos.dev/python/reference/decorators#workflow) decorators as needed. Decorated steps are just normal functions if called outside of DBOS workflows, which can be used in non-DBOS agents.
152
136
153
137
## Step Retries
154
138
@@ -160,9 +144,9 @@ You can customize DBOS's retry policy using [step configuration](#step-configura
160
144
161
145
## Observability with Logfire
162
146
163
-
DBOS generates OpenTelemetry traces and events for each workflow and step execution, and Pydantic AI generates events for each agent run, model request and tool call. These can be sent to [Pydantic Logfire](logfire.md) to get a complete picture of what's happening in your application.
147
+
DBOS emits OpenTelemetry traces and events for every workflow and step, and Pydantic AI generates events for each agent run, model request and tool call. These can be sent to [Pydantic Logfire](logfire.md) to get a complete picture of what's happening in your application.
164
148
165
-
To disable sending DBOS traces to Logfire, you can pass`disable_otlp=True`to the `DBOS` constructor. For example:
149
+
To disable DBOS traces and logs, you can set`disable_otlp=True`in `DBOSConfig`. For example:
166
150
167
151
168
152
```python {title="dbos_no_traces.py" test="skip"}
@@ -176,4 +160,4 @@ dbos_config: DBOSConfig = {
176
160
DBOS(config=dbos_config)
177
161
```
178
162
179
-
1. If `True`, disables OpenTelemetry tracing and logging for DBOS. Defaults to`False`.
163
+
1. If `True`, disables OpenTelemetry tracing and logging for DBOS. Default is`False`.
0 commit comments