Use the Python SDK for agents built with plain functions, async code, or frameworks like LangGraph. It works with sync and async functions, and concurrent runs in threads or asyncio tasks stay in separate traces.
Install and configure
pip install uncoil-sdk
Set UNCOIL_API_KEY in the environment where your agent runs. Configure the rest on the decorator:
from uncoil import trace_agent
@trace_agent(name="support-agent", environment="production", release="2026-10-15")
def answer(question: str):
return llm.complete(question, context=search_docs(question))
The decorator accepts client, name, environment, release, deployment_id, session_id, end_user_id and tags. Use session and user fields when those dimensions matter to debugging, for example to find every run for one customer.
Each call of the decorated function is one trace. A key belongs to one region, EU or US, and the client refuses a mismatched configuration instead of sending data to the wrong place.
Record steps with span and observe
Use span for a block of work and observe for a function. Steps started inside another step become its children.
import uncoil
@uncoil.observe(type="tool")
def search_docs(query):
return search(query)
@uncoil.trace_agent()
def answer(question):
for turn in range(5):
with uncoil.span("think", type="agent"):
with uncoil.span("chat", type="llm", input=question) as step:
reply = call_model(question)
step.set_output(reply.text)
step.set(
model="your-model-id",
input_tokens=reply.usage.input,
output_tokens=reply.usage.output,
)
if reply.done:
return reply.text
search_docs(reply.query)
type is one of agent, llm, tool, retrieval or span. Exceptions are recorded with their type and message and then raised again. observe also accepts name, capture_input=False and capture_output=False when arguments or results should stay out of the trace.
Record finished calls directly
from uncoil import llm_call, tool_call
llm_call(
input_data=question,
output_data=reply.text,
model_id="your-model-id",
cost_usd=0.002,
latency_ms=800,
input_tokens=reply.usage.input,
output_tokens=reply.usage.output,
)
tool_call(
tool_name="web_search",
input_data={"q": question},
output_data=results,
latency_ms=1200,
)
Wrap provider clients
uncoil.wrap_openai, uncoil.wrap_anthropic and uncoil.langgraph_callback() record provider calls without changing your code. See OpenAI, Anthropic and LangGraph.
What the SDK sends
Inputs and outputs have obvious secrets removed and are capped at 10,000 characters. Do not record anything you would not want stored. Delivery problems never interrupt your agent.
Feedback, scores and prompts
Create a UncoilClient with project_id to attach feedback and scores. See Feedback and scores. To resolve a deployed prompt, see Prompt deployment.