Runtime Context for Dependency Injection
00:00 In this lesson, you’re going to learn how to use Pydantic AI’s runtime context for dependency injection, making it easier to test and debug your agents.
00:10 Your current design has an API that is coupled with the agents, and the two are one thing only, they act together always. What you want to do is to have the API being injected as a dependency so that for testing, for example, you can have a different fake API that you can control.
00:29
So let’s see how you can do that in code. First, go ahead and copy your weather script into a deps for dependencies script because you’re going to reuse some of that code.
00:41 And then go ahead and open that code. Now, what you want to do is to make it easier to understand the passing around of dependencies, you want to take your current tool and copy it. And now you’re going to define a class for your weather API that’s going to have a method that actually is the full correct API call.
01:08
Now make sure that your method accepts self as the first argument. And this defines your correct real weather API. And for testing, you could have something like a FakeWeatherAPI that has a method with the same name that accepts a city, returns a dictionary, and you’re going to return some fake data. For example, the city that is given as an argument and the temperature of minus 10 degrees Celsius, which is below the temperature at which water freezes.
01:41 So this defines two different APIs. One is the real one and the other is fake. Now, how can you use this? Well, you’re going to define a tool.
01:51
And now you use the decorator @agent.tool, not @agent.tool_plain, because now your tool for the weather is actually going to accept a new argument, which is the runtime context.
02:03
And that’s why you need a different decorator. And this runtime context will provide you your weather API. And then the city that you want to check. And then instead of using the API code from before, what you’re going to do is you’re going to access the weather API through the context because the tool will accept the dependency through the context. And so you’ll want to do something like return from the context, you’re going to get the dependencies. And from there, you’re going to call the method current_weather with a given city.
02:41
And the method is called current_weather because that’s what you defined in your weather APIs.
02:48 And that’s why it’s important that they both have the same name so that if you swap the APIs, the tool still works.
02:56
So your tool now defers to the dependencies by calling current_weather. But how do you actually inject the dependencies? In your agent.run_sync, you have your prompt and then you specify the argument deps, which is the object that contains all of the dependencies. So you could say something like FakeWeatherAPI.
03:17
And now if you run your code, you will see that the temperature reported for Lisbon is going to be minus 10. So if you open your terminal and if you run deps.py,
03:32
if you run your script right now, you get an error because you need to import RunContext, the type hint. Go ahead and don’t forget to import RunContext from pydantic_ai.
03:45 And now you give it a go.
03:48
You run deps.py and you should get recommendations for dressing up for Lisbon as if the temperature were minus 10 degrees Celsius, which is 30 degrees under what’s currently the weather in Lisbon. So you can see that you’re using the fake API.
04:06
This could be used, for example, for testing. And then in production, you find the method and instead of passing in the FakeWeatherAPI, you change the dependencies to be the real WeatherAPI.
04:17 And the relevance here is in understanding that these dependencies can be swapped when you’re using the agent, when you’re calling it. So you can define your agent. When you instantiate the agent, you can instantiate it once in your application.
04:31 And then when you import the agents to be tested with the prompts you want to test it with, you can just inject fake mock database connections, API requests through this argument.
04:45
And as a quick tip, if you have multiple dependencies, it’s common to have a data class, a Python data class with one dependency per attribute so that inside your tools, you then access ctx.deps. the dependency you care about, and then methods or attributes in that dependency.
05:05 But in this example, you only have the weather API as the dependency, so it’s okay to pass in that directly.
05:13 So this is how you can use the runtime context for dependency injection. In the next lesson, you’re going to be left with some final considerations to ponder on.
Become a Member to join the conversation.
