llm-agent-trace
Zero-dependency LLM call tracer. Patch once — every provider is captured automatically.
┌─ research_agent · #a3f2b1 1149 tokens $0.0022 3.4s
│
│ ├─ summarize 312→87 tok $0.0004 1.2s
│ │ └─► openai · api.openai.com/v1/chat/completions gpt-4o 312→87 tok $0.0004 1.2s ✓
│ │
│ └─ verify 540→210 tok $0.0018 2.1s
│ └─► anthropic · api.anthropic.com/v1/messages claude-sonnet-4-6 540→210 tok $0.0018 2.1s ✓
│
│ 2 call(s) · 852→297 tokens · $0.0022 · 3.4s
└────────────────────────────────────────
Why
Every LLM observability tool is either a paid SaaS, a massive framework dependency, or tied to a specific provider. llm-agent-trace is none of those — it's a small library you drop in and forget about.
- Zero runtime dependencies — stdlib only
- Provider-agnostic — works with OpenAI, Anthropic, Mistral, Groq, Gemini, Cohere, Ollama, LM Studio, Azure OpenAI, and anything that speaks HTTP
- Works with LangChain, LiteLLM, and any other framework — intercepts at the HTTP layer, not the SDK layer
- Sync + async — both are captured
Install
pip install llm-agent-trace
Quickstart
import llm_agent_trace
# One line at the top of your script
llm_agent_trace.patch()
# Wrap your agent run in a session
with llm_agent_trace.session("my_agent"):
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}]
)
# Trace is printed to stderr automatically when the session ends
Works identically with LiteLLM, LangChain, Anthropic SDK, or any HTTP-based LLM client — no changes to your existing code.
Adding structure with spans
Without spans you get a flat list of calls. Spans let you group calls into named steps:
import llm_agent_trace
llm_agent_trace.patch()
@llm_agent_trace.span("summarize")
def summarize(text):
return llm.invoke(f"Summarize: {text}")
@llm_agent_trace.span("verify")
def verify(summary):
return llm.invoke(f"Is this accurate? {summary}")
with llm_agent_trace.session("research_agent"):
summary = summarize(long_document)
verdict = verify(summary)
Spans also work as context managers:
with llm_agent_trace.session("agent"):
with llm_agent_trace.span("step_1"):
result = llm.invoke(...)
with llm_agent_trace.span("step_2"):
result = llm.invoke(...)
Save trace as JSON
with llm_agent_trace.session("my_agent", output="trace.json"):
...
{
"session_id": "a3f2b1",
"name": "my_agent",
"duration_ms": 3400,
"total_calls": 2,
"total_tokens_in": 852,
"total_tokens_out": 297,
"total_cost_usd": 0.0022,
"spans": [...],
"orphan_calls": [...]
}
Disable terminal output
with llm_agent_trace.session("my_agent", print_trace=False, output="trace.json"):
...
Custom cost table
llm_agent_trace.patch(cost_table={
"my-fine-tuned-model": (0.005, 0.015), # per 1k tokens: in, out
})
Introspection
import llm_agent_trace
sess = llm_agent_trace.current_session() # active Session or None
sp = llm_agent_trace.current_span() # active Span or None
Supported providers (auto-detected)
| Provider | Endpoint pattern |
|---|---|
| OpenAI | api.openai.com/v1/chat/completions |
| Anthropic | api.anthropic.com/v1/messages |
| Azure OpenAI | *.openai.azure.com/*/chat/completions |
| Mistral | api.mistral.ai/v1/chat/completions |
| Groq | api.groq.com/openai/v1/chat/completions |
| Gemini | generativelanguage.googleapis.com/*/generateContent |
| Cohere | api.cohere.com/v1/chat |
| Together AI | api.together.xyz/v1/chat/completions |
| Perplexity | api.perplexity.ai/chat/completions |
| OpenRouter | openrouter.ai/api/v1/chat/completions |
| Ollama / LM Studio | localhost:*/api/chat |
Any provider not listed but using HTTP/REST is captured as unknown.
Limitations (v1)
- Streaming responses are logged as a single event when the stream closes; per-chunk tracing is not yet supported.
- gRPC-based providers are not supported (rare in practice — all major providers use HTTP).
- Monkey-patching works best when
patch()is called before your LLM library imports. If you importfrom litellm import completionbefore callingpatch(), that specific reference won't be intercepted — uselitellm.completion(...)instead.
Contributing
Issues and PRs welcome. Please open an issue before starting work on a large change.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llm_agent_trace-0.2.0.tar.gz.
File metadata
- Download URL: llm_agent_trace-0.2.0.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8fe6660e41e8645debb0528397f653ae81f7ad69fcf696de0d3eefeb772a96b8
|
|
| MD5 |
6e7918300b563d3735605254e3aaf978
|
|
| BLAKE2b-256 |
a24ae8a6a5195fce3d24d1bc9a0455149f544206db8ffc8c9016cc76ae84bc0d
|
File details
Details for the file llm_agent_trace-0.2.0-py3-none-any.whl.
File metadata
- Download URL: llm_agent_trace-0.2.0-py3-none-any.whl
- Upload date:
- Size: 13.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbd6cd5b38cfe4b91b2cacd126cce4f593def74ee3bfff6bf875b4a4f1b9652d
|
|
| MD5 |
e3bc879862e39fe0ed00569c5a83908e
|
|
| BLAKE2b-256 |
6f74ec7e2deebafcb85e5ceb6bc55b5ad67e0683942e58a67935575a580103d7
|