When to Use Different Emitter Types in Agent-Lightning: A Complete Guide to Observability
Agent-lightning provides six specialized emitter types—emit_reward, emit_message, emit_object, emit_exception, emit_annotation, and operation—each designed to capture specific telemetry data as OpenTelemetry spans with distinct semantic conventions for RL training, debugging, and workflow tracing.
Agent-lightning ships a lightweight emitter API that lets you record custom OpenTelemetry spans directly from your agent code. Understanding when to use different emitter types in agent-lightning ensures that reinforcement learning signals, debug logs, and exception traces follow consistent semantic conventions that downstream dashboards and reward-model trainers can reliably consume. This guide maps each emitter to its intended use case based on the actual implementation in the Microsoft agent-lightning repository.
Choosing the Right Emitter for Your Use Case
Each emitter helper in agent-lightning wraps the active tracer to produce a span with a well-known semantic convention. Select the emitter that matches the data you need to capture.
emit_reward: Recording Scalar and Multi-Dimensional Rewards
Use emit_reward when you need to report reinforcement-learning signals or any scalar feedback that a training loop will consume. According to the source code in agentlightning/emitter/reward.py#L148, this emitter creates a span of type AGL_ANNOTATION and stores either a numeric reward or a dictionary of multi-dimensional rewards.
- Typical use: Intermediate or final rewards during tool execution or episode completion.
- Key feature: Automatically links to the surrounding operation span, if any.
- Data format: Float or dict with optional
primary_keyfor multi-objective rewards.
emit_message: Debug Logging and Status Updates
Use emit_message for high-level status messages that you want to keep in the same telemetry store as your spans. This emitter, implemented in agentlightning/emitter/message.py#L15, creates a span of type AGL_MESSAGE containing a free-form string plus optional attributes.
- Typical use: Debugging tool invocations, logging step transitions, or communicating agent state.
- Key feature: Lightweight string-based logging integrated with the OpenTelemetry pipeline.
emit_object: Serializing Arbitrary Python Objects
Use emit_object when you need to capture model outputs, configurations, or any data structure useful for post-hoc inspection. As defined in agentlightning/emitter/object.py#L17, this emitter creates a span of type AGL_OBJECT that serializes the object via repr().
- Typical use: Storing structured model outputs, API responses, or agent configurations.
- Key feature: Automatically flattens nested dictionaries into dotted OpenTelemetry keys using
sanitize_attributes.
emit_exception: Capturing Non-Fatal Errors
Use emit_exception to report unexpected errors that you do not want to raise to the caller. The implementation in agentlightning/emitter/exception.py#L15 creates a span of type AGL_EXCEPTION marked with exception.type, exception.message, and exception.stacktrace.
- Typical use: Non-fatal failures in tool calls, fallback handling, or graceful degradation paths.
- Key feature: Records full traceback information without interrupting execution flow.
emit_annotation: Generic Custom Metadata
Use emit_annotation when you need a custom data payload that does not fit the reward or message model. This generic emitter, located in agentlightning/emitter/annotation.py#L35, produces an AGL_ANNOTATION span storing a free-form dictionary of key-value pairs.
- Typical use: Tagging spans with experiment metadata, model versions, or custom metrics.
- Key feature: Most flexible payload structure for domain-specific attributes.
operation: Grouping Related Work into Logical Spans
Use the operation decorator or context manager to group a series of emitter calls, inputs, and outputs under a single parent span. Implemented in agentlightning/emitter/annotation.py#L281, this creates an AGL_OPERATION span that lives for the duration of a logical block.
- Typical use: Wrapping a full tool invocation, multi-step workflow, or high-level agent step.
- Key features: Supports
set_input(),set_output(), and automatic attribute flattening viaflatten_attributes.
Architecture: How Emitters Flow Through the Tracer
Understanding the internal flow helps you decide when to set propagate=False or add custom attributes.
- Tracer Resolution – All emitter functions call
agentlightning.tracer.base.get_active_tracer()to retrieve the currently bound tracer (usually anOtelTracer). Ifpropagate=Falseis passed, aDummyTracercreates a local span that never reaches exporters. - Semantic Conventions – Each emitter uses constants from
agentlightning.semconv(e.g.,AGL_MESSAGE,AGL_EXCEPTION) ensuring downstream consumers can query spans by standardized names. - Attribute Processing – Helper utilities
flatten_attributesandsanitize_attributesinagentlightning.utils.otelconvert nested dictionaries into dotted OpenTelemetry keys (e.g.,meta.some_key), allowing rich metadata without manual preprocessing.
Code Examples
Emitting Scalar and Multi-Dimensional Rewards
from agentlightning import emit_reward
# Simple scalar reward
emit_reward(0.85)
# Multi-dimensional reward with a primary key
emit_reward({"task_success": 1.0, "efficiency": 0.7}, primary_key="task_success")
Linking Rewards to Previous Spans
from agentlightning import emit_reward
from agentlightning.utils.otel import make_link_attributes, make_tag_attributes
# Link the reward to a previously emitted response span
link_attrs = make_link_attributes({"gen_ai.response.id": "resp-123"})
emit_reward(0.5, attributes=link_attrs)
# Tag the reward span with custom tags
tag_attrs = make_tag_attributes(["fast", "reliable"])
emit_reward(0.7, attributes=tag_attrs)
Logging Debug Messages
from agentlightning import emit_message
emit_message("Starting tool call", attributes={"tool": "search"})
Capturing Arbitrary Objects
from agentlightning import emit_object
model_output = {"answer": "42", "confidence": 0.96}
emit_object(model_output, attributes={"step": "postprocess"})
Reporting Exceptions Without Raising
from agentlightning import emit_exception
try:
risky_operation()
except Exception as exc:
emit_exception(exc) # Records stacktrace in a span
# continue execution or fallback
Grouping Work with the Operation Decorator
from agentlightning import operation, emit_reward, emit_message
@operation(category="tool", tool_name="search")
def run_search(query: str):
emit_message(f"Executing search for '{query}'")
results = external_search_api(query)
emit_reward(0.9, attributes={"result_count": len(results)})
return results
Using Operation as a Context Manager
from agentlightning import operation
with operation(user_id=123) as op:
op.set_input(data="input payload")
# ... work ...
op.set_output(result="output payload")
Summary
- Use
emit_rewardfor numerical RL feedback and multi-dimensional reward signals. - Use
emit_messagefor lightweight string-based debug logging and status updates. - Use
emit_objectto serialize complex Python structures like model outputs or configs. - Use
emit_exceptionto capture non-fatal errors with full stacktraces without raising. - Use
emit_annotationfor custom key-value metadata that does not fit other categories. - Use
operationto group related emitter calls into a single parent span with inputs and outputs.
Frequently Asked Questions
When should I use emit_reward versus emit_annotation?
Use emit_reward when the data represents a scalar or multi-dimensional reinforcement learning signal that a training loop will consume, as it enforces numeric or dictionary structures with optional primary_key semantics. Use emit_annotation for generic experiment metadata or custom metrics that do not represent reward signals, since it accepts any free-form dictionary without semantic constraints.
How do I prevent spans from reaching external exporters during unit tests?
Pass propagate=False to any emitter function. This triggers the use of a DummyTracer that creates local spans only, preventing telemetry from hitting OTLP endpoints or console exporters while still allowing you to verify span creation in memory.
Can I link an emitter span to a previous operation or response?
Yes. Import make_link_attributes from agentlightning.utils.otel and pass the resulting attributes to any emitter. This creates explicit span links using OpenTelemetry's linking mechanism, allowing you to correlate rewards or messages with prior generations or tool calls.
What is the difference between emit_object and emit_message?
emit_message stores a string payload in an AGL_MESSAGE span and is optimized for human-readable debug text. emit_object stores the repr() of an arbitrary Python object in an AGL_OBJECT span, making it suitable for capturing structured data like dictionaries or class instances that require post-hoc analysis.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →