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
Metadata
Release files for llm-agent-trace 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| llm_agent_trace-0.2.0.tar.gz | 16.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_agent_trace-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.3 kB
Release files / llm_agent_trace-0.2.0.tar.gz
| Download URL | llm_agent_trace-0.2.0.tar.gz |
|---|---|
| Size | 16.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8fe6660e41e8645debb0528397f653ae81f7ad69fcf696de0d3eefeb772a96b8
|
|
BLAKE2b-256 checksum How to use checksums |
a24ae8a6a5195fce3d24d1bc9a0455149f544206db8ffc8c9016cc76ae84bc0d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / llm_agent_trace-0.2.0-py3-none-any.whl
| Download URL | llm_agent_trace-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fbd6cd5b38cfe4b91b2cacd126cce4f593def74ee3bfff6bf875b4a4f1b9652d
|
|
BLAKE2b-256 checksum How to use checksums |
6f74ec7e2deebafcb85e5ceb6bc55b5ad67e0683942e58a67935575a580103d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|