Pattern Tracing¶
TracedPattern wraps any BasePattern with OpenTelemetry spans so every run appears in your observability backend (Arize Phoenix, Jaeger, Honeycomb, Grafana Tempo, …).
When no OTEL backend is configured the wrapper is a zero-overhead pass-through — it uses the no-op tracer from brain.obs.tracing.
Usage¶
from brain.patterns import ReActAgent
from brain.patterns.tracing import TracedPattern
agent = TracedPattern(
ReActAgent(tools={"search": my_search}),
name="research_agent", # span name (default: class name)
attributes={"env": "prod", # extra span attributes
"team": "platform"},
record_steps=True, # add span events for each step (default: True)
)
result = agent.run("What is the latest on AI safety?")
# → emits a "research_agent" span with step events
print(result.metadata.get("trace_id")) # hex trace ID if OTEL is active
Span attributes¶
| Attribute | Value |
|---|---|
pattern.name |
Class name of the wrapped pattern |
pattern.task |
Task string (first 500 chars) |
pattern.ok |
True/False |
pattern.iterations |
Number of steps |
pattern.answer |
Final answer (first 500 chars) |
pattern.latency_ms |
Wall-clock run time in ms |
pattern.step_count |
len(result.steps) |
pattern.error |
Error message (if any) |
Plus any attributes you pass to the constructor.
Enabling OTEL¶
from brain.obs.tracing import init_tracing
init_tracing(
project_name="my_project",
endpoint="http://localhost:6006/v1/traces", # e.g. Arize Phoenix
dev_mode=True, # SimpleSpanProcessor — immediate export
)
Or via environment variables:
export PHOENIX_COLLECTOR_ENDPOINT=http://localhost:6006/v1/traces
export PHOENIX_PROJECT_NAME=my_project
export SB_TRACING_DEV_MODE=true
trace_pattern decorator/factory¶
from brain.patterns.tracing import trace_pattern
# Wrap an instance
agent = trace_pattern(name="prod_agent", attributes={"version": "0.3.0"})(my_agent)
# Or use as a class decorator (wraps run() on every instance)
@trace_pattern(name="my_react", attributes={"team": "ml"})
class MyReActAgent(ReActAgent):
pass
API Reference¶
brain.patterns.tracing.TracedPattern
¶
TracedPattern(pattern: BasePattern, name: str | None = None, attributes: dict[str, Any] | None = None, record_steps: bool = True)
Bases: BasePattern
Wrap any BasePattern with OpenTelemetry spans.
Transparent proxy — all method calls are forwarded to the inner pattern.
The run() method is intercepted to create a root span and record
step-level events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pattern
|
BasePattern
|
The pattern to wrap. |
required |
name
|
str | None
|
Span name. Defaults to the wrapped pattern's class name. |
None
|
attributes
|
dict[str, Any] | None
|
Extra OTEL attributes added to the root span. |
None
|
record_steps
|
bool
|
If True (default), add span events for each |
True
|
Source code in brain/patterns/tracing.py
run
¶
Run the wrapped pattern inside an OTEL span.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task
|
str
|
The question or instruction for the agent. |
required |
Returns:
| Type | Description |
|---|---|
PatternResult
|
The |
PatternResult
|
|
PatternResult
|
(as a hex string) when OTEL is available. |
Source code in brain/patterns/tracing.py
brain.patterns.tracing.trace_pattern
¶
trace_pattern(name: str | None = None, attributes: dict[str, Any] | None = None, record_steps: bool = True) -> Any
Decorator / factory that wraps a pattern instance in TracedPattern.
Can be used as a decorator on a class, or called directly:
.. code-block:: python
from brain.patterns.tracing import trace_pattern
@trace_pattern(name="my_agent", attributes={"team": "platform"})
class MyAgent(ReActAgent):
pass
# or on an instance:
agent = trace_pattern(name="prod_agent")(ReActAgent(tools=...))