Instrument with traceAI Helpers
Future AGI's traceAI library offers convenient abstractions to streamline your manual instrumentation process.
About
Manual tracing with raw OpenTelemetry means writing a lot of setup code for every function you want to track. traceAI helpers solve this. Add a one-line decorator like @tracer.chain or @tracer.tool to a function, and inputs, outputs, and status are captured automatically. For more control, wrap a code block with a context manager and set values yourself. Each span gets a type (chain, agent, tool, LLM, retriever) that determines how it appears in the dashboard, so you can tell at a glance what each step in a trace is doing.
When to use
- Function-level tracing: Decorate a function with
@tracer.chain,@tracer.agent, or@tracer.tooland the entire call is captured as a span with automatic input/output. - Code block tracing: Wrap any code segment with
tracer.start_as_current_spanfor precise control over what gets captured. - Typed spans: Use FI Span Kinds (
chain,agent,tool,llm,retriever) so spans render with the right icon and label in the dashboard. - Tool metadata: Attach tool name, description, and parameters to tool spans so the dashboard shows full tool call context.
- Mixed workflows: Combine decorators (for complete functions) and context managers (for sub-operations) in the same codebase.
How to
Install the instrumentation package
pip install fi-instrumentation-otelnpm install @traceai/fi-core Set up your tracer
Register your project and initialize a FITracer from the returned provider.
from fi_instrumentation import register, FITracer
from fi_instrumentation.fi_types import ProjectType
# Setup OTel via our register function
trace_provider = register(
project_type=ProjectType.EXPERIMENT,
project_name="FUTURE_AGI",
project_version_name="openai-exp",
)
tracer = FITracer(trace_provider.get_tracer(__name__))const { trace, context, SpanStatusCode, propagation } = require("@opentelemetry/api");
const { AsyncLocalStorageContextManager } = require("@opentelemetry/context-async-hooks");
const { register, ProjectType } = require("@traceai/fi-core");
const { registerInstrumentations } = require("@opentelemetry/instrumentation");
const { suppressTracing } = require("@opentelemetry/core");
context.setGlobalContextManager(new AsyncLocalStorageContextManager());
const tracerProvider = register({
projectName: "manual-instrumentation-example",
projectType: ProjectType.OBSERVE,
sessionName: "manual-instrumentation-example-session"
});
const tracer = tracerProvider.getTracer("manual-instrumentation-example"); Instrument with spans
Choose the span kind that matches your operation, then pick your instrumentation style.
Use chain spans for general logic, processing pipelines, and code blocks.
from opentelemetry.trace.status import Status, StatusCode
with tracer.start_as_current_span(
"my-span-name",
fi_span_kind="chain",
) as span:
span.set_input("input")
span.set_output("output")
span.set_status(Status(StatusCode.OK))tracer.startActiveSpan("my-span-name", { attributes: { "fi.span.kind": "chain" } }, (span) => {
span.setAttribute("input", "input");
span.setAttribute("output", "output");
span.setStatus({ code: SpanStatusCode.OK });
span.end();
}); Plain text output:
@tracer.chain
def decorated_chain_with_plain_text_output(input: str) -> str:
return "output"
decorated_chain_with_plain_text_output("input")JSON output:
@tracer.chain
def decorated_chain_with_json_output(input: str) -> Dict[str, Any]:
return {"output": "output"}
decorated_chain_with_json_output("input")Override span name:
@tracer.chain(name="decorated-chain-with-overriden-name")
def this_name_should_be_overriden(input: str) -> Dict[str, Any]:
return {"output": "output"}
this_name_should_be_overriden("input") Use agent spans for orchestrator functions : typically a top-level or near top-level span.
with tracer.start_as_current_span(
"agent-span-with-plain-text-io",
fi_span_kind="agent",
) as span:
span.set_input("input")
span.set_output("output")
span.set_status(Status(StatusCode.OK))tracer.startActiveSpan("agent-span-with-plain-text-io", { attributes: { "fi.span.kind": "agent" } }, (span) => {
span.setAttribute("input", "input");
span.setAttribute("output", "output");
span.setStatus({ code: SpanStatusCode.OK });
span.end();
}); @tracer.agent
def decorated_agent(input: str) -> str:
return "output"
decorated_agent("input") Use tool spans for tool calls. Attach name, description, and parameters for full call context in the dashboard.
with tracer.start_as_current_span(
"tool-span",
fi_span_kind="tool",
) as span:
span.set_input("input")
span.set_output("output")
span.set_tool(
name="tool-name",
description="tool-description",
parameters={"input": "input"},
)
span.set_status(Status(StatusCode.OK))tracer.startActiveSpan("tool-span", { attributes: { "fi.span.kind": "tool" } }, (span) => {
span.setAttribute("input", "input");
span.setAttribute("output", "output");
span.setAttribute("tool.name", "tool-name");
span.setAttribute("tool.description", "tool-description");
span.setAttribute("tool.parameters", JSON.stringify({"input": "input"}));
span.setStatus({ code: SpanStatusCode.OK });
span.end();
}); @tracer.tool(
name="tool-name",
description="tool-description",
parameters={"input": "input"},
)
def decorated_tool(input: str) -> str:
return "output"
decorated_tool("input") Use LLM spans for direct LLM calls. LLM spans only support context managers (no decorator available).
with tracer.start_as_current_span(
"llm-span",
fi_span_kind="llm",
) as span:
span.set_input("input")
span.set_output("output")
span.set_status(Status(StatusCode.OK))tracer.startActiveSpan("llm-span", { attributes: { "fi.span.kind": "llm" } }, (span) => {
span.setAttribute("input", "input");
span.setAttribute("output", "output");
span.setStatus({ code: SpanStatusCode.OK });
span.end();
}); Use retriever spans for document retrieval operations. Retriever spans only support context managers (no decorator available).
with tracer.start_as_current_span(
"retriever-span",
fi_span_kind="retriever",
) as span:
span.set_input("input")
span.set_output("output")
span.set_status(Status(StatusCode.OK))tracer.startActiveSpan("retriever-span", { attributes: { "fi.span.kind": "retriever" } }, (span) => {
span.setAttribute("input", "input");
span.setAttribute("output", "output");
span.setStatus({ code: SpanStatusCode.OK });
span.end();
}); Key concepts
FITracer: Future AGI wrapper around the standard OTel tracer. Addsset_input()/set_output()/set_tool()on spans, automatic context injection, and typed decorators (@tracer.chain,@tracer.agent,@tracer.tool,@tracer.llm,@tracer.retriever).- FI Span Kinds: Typed labels that control how spans are rendered in the Future AGI UI. Set via
fi_span_kindin Python orfi.span.kindattribute in JS/TS. - Decorators: Wrap entire functions. Input/output/status are captured automatically from function args and return values.
- Context managers: Wrap specific code blocks. You call
set_input(),set_output(), andset_status()manually. set_tool(): Setstool.name,tool.description, andtool.parameterson a tool span for full call context in the dashboard.
FI Span Kinds reference:
| Span Kind | Use |
|---|---|
chain | General logic operations, functions, or code blocks |
llm | Making LLM calls |
tool | Completing tool calls |
retriever | Retrieving documents |
embedding | Generating embeddings |
agent | Agent invocations : typically a top-level or near top-level span |
reranker | Reranking retrieved context |
guardrail | Guardrail checks |
evaluator | Evaluators |
unknown | Unknown |
Next Steps
Set Up Tracing
Register a tracer provider and add instrumentation.
Add Attributes & Metadata
Attach custom data to spans for filtering and evals.
Set Session & User ID
Group traces into sessions and link them to end users.
Mask Span Attributes
Redact sensitive data with TraceConfig before export.
Auto Instrumentation
Browse all supported framework instrumentors.
Set Up Observability
Register an Observe project and start capturing traces.