How do I trace an agent built with Pydantic AI and deployed to AWS Lambda?
Rius traces a Pydantic AI agent on AWS Lambda when you call rius.init and Agent.instrument_all(True) once at module level and call client.flush() at the end of every invocation. Pydantic AI emits its own spans, so the agent run, each model request and each tool call arrive with no wrappers. The root span is named after your agent, and service_name sets the name Rius groups it under.
How it works
Pydantic AI is OpenTelemetry-native. rius.init() installs the global OpenTelemetry tracer provider, and Agent.instrument_all(True) tells Pydantic AI to emit its spans through it. No auto-instrumentation extra is involved. Rius reads the framework’s GenAI attributes and computes cost on the server.
Spans leave your function from a background thread, in batches. Lambda freezes the process between invocations, so a frozen thread exports nothing and the exit hook may never run. That is why Lambda needs an explicit flush at the end of each invocation. The details are on Reliability.
Three choices matter for this runtime:
- Where to call init. Call
rius.initandAgent.instrument_all(True)once, at module level, outside your handler. Both are global, so they do not belong inside the per-request path. - What to flush. Call
client.flush()in afinallyblock so spans are exported even when the run raises. - What to name the agent. Set
service_name. Rius groups the agent under it, or underRIUS_AGENT_NAMEif you set that variable. The root span isinvoke_agentfollowed by your agent’s name, model requests arechatfollowed by the model, and tool calls areexecute_toolfollowed by the tool name.
Set it up
- Add the SDK and the framework to your function’s dependencies. No extra is needed.
pip install glassflow-rius pydantic-ai- Initialize at module level, turn off the heartbeat, and flush inside the handler. The
eventkeys below are your own. Replaceri_...with your API key, or setRIUS_API_KEYinstead.
import rius
from pydantic_ai import Agent
client = rius.init(
api_key="ri_...",
service_name="support-agent",
heartbeat=False,
)
Agent.instrument_all(True)
support_agent = Agent(
"openai:gpt-5-mini",
instructions="Answer support questions; check accounts with the tool.",
)
@support_agent.tool_plain
def account_status(email: str) -> str:
"""Fetch a customer's account standing by email."""
return lookup(email)
def handler(event, context):
try:
with rius.session(event["conversation_id"]):
support_agent.run_sync(event["ticket"])
return {"statusCode": 200}
finally:
client.flush(timeout_millis=30_000)-
Keep
heartbeat=False. Heartbeats are a signal for long-lived processes. On Lambda the runtime suspends the process between invocations, so the instance would flap between alive andstaleorgone. You can also setRIUS_HEARTBEAT=false. -
Keep the flush at the invocation boundary and out of any inner loop.
flush()blocks until the export completes. It returnsFalseon timeout or when the latest export was rejected, for example a 401 on a bad key, so you can log that case. -
Scope each run with
rius.session()and your conversation id. The framework’s spans inherit the session. -
Invoke the function with a request that calls a tool, then open the trace in the console. You should see the
invoke_agentroot,chatgenerations with model, tokens and cost, andexecute_toolspans. See the Pydantic AI integration page for the full recipe and quirks.
What you get
- A trace for each invocation, with the agent run as the root and model requests and tool calls underneath it, named after your agent, model and tools.
- Tokens and cost for each model request. Costs are list-price estimates in US dollars, computed by Rius from the spans.
- Time to first token with
glassflow-rius1.0.1 or later, and reasoning tokens with 1.0.2 or later. - Invocations grouped by conversation through
rius.session(). - The agent listed under your
service_name, with no registration step.
For other frameworks and client libraries, see Integrations.
When something else fits
- If your Lambda runs Pydantic AI without the Rius SDK, you can point any OpenTelemetry setup at the Rius ingest endpoint instead, but then you wire the exporter and the flush yourself.
- If you need per-agent control over what the spans carry, such as prompt and completion content, set it in Pydantic AI’s
InstrumentationSettings, on top of the SDK’s privacy controls.