An agent’s final message compresses a lot of execution into a few sentences. It does not show whether a tool timed out, a delegated task returned incomplete evidence, or the application retried an operation. In a VoltAgent application, those details become important as soon as one request involves several steps.
VoltAgent monitoring should connect the user conversation to the execution that produced each reply. Preserve identity, export supported spans, and record the outcome of external actions independently from the agent’s final text.
Agnost AI provides agent analytics and observability through conversation events and OpenTelemetry ingestion. Its VoltAgent integration uses VoltAgent’s observability layer to attach an OTLP exporter.
Worked example: a tool returns an error as ordinary text
Suppose a VoltAgent assistant updates a workspace setting through a custom tool. The HTTP request succeeds, but the service payload says the account lacks permission. The tool converts that payload into a string and the agent replies “updated.” This is an illustrative diagnosis, not a real customer incident.
| Layer | Apparent success | Missing distinction |
|---|---|---|
| HTTP client | Received a response | The operation may be rejected |
| Tool function | Returned a string | The string may describe a failure |
| Agent run | Produced a final answer | The answer may contradict the tool |
| User task | Setting should change | The authoritative state did not change |
Inspect the structured service result first. Then check whether the tool preserves status and whether the agent receives it. A retry will not resolve a permission rejection unless the required permission changes, so blindly retrying adds delay without progress.
Record a stable reason such as permission denied instead of treating every payload as successful tool output. Preserve the external action identity across retries. In Agnost, review the conversation alongside the received tool records; if the tool’s status was never exported, avoid assuming that a green parent span proves completion.
The corrective work belongs at the contract boundary: the tool and agent need an unambiguous outcome. Monitoring supplies the evidence to find that boundary.

Metrics that answer useful VoltAgent questions
Use these definitions to design your measurement plan. Calculate them from the required application or tracing evidence; they are not all precomputed dashboard metrics.
| Metric | Definition | Interpretation |
|---|---|---|
| Semantic tool failures | Rejected or failed operations / recorded operations | Requires meaningful result status, not just HTTP status. |
| Retries per action | Execution attempts / distinct intended actions | High retry count can indicate a non-retryable error. |
| Unsupported completion claims | Reviewed replies claiming an unconfirmed action / reviewed action replies | Requires paired reply and authoritative outcome evidence. |
Add an exporter to the observability layer
In your existing VoltAgent application, install the HTTP/protobuf exporter and span processor package:
Example scope: the code below is an integration adapter for an existing application. Configure its framework, model, credentials, and output contract as described; the demo screenshots were not generated by running these snippets.
npm install @opentelemetry/exporter-trace-otlp-proto \
@opentelemetry/sdk-trace-base
Create a processor and attach it to the VoltAgentObservability instance used by your application:
import { VoltAgentObservability } from '@voltagent/core';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
const orgId = process.env.AGNOST_ORG_ID;
if (!orgId) throw new Error('AGNOST_ORG_ID is required');
export const observability = new VoltAgentObservability({
spanProcessors: [
new BatchSpanProcessor(new OTLPTraceExporter({
url: 'https://otel.agnost.ai/v1/traces',
headers: { 'X-Agnost-Org-ID': orgId },
})),
],
});
Pass this observability object into your existing VoltAgent configuration alongside its agents. If you already have an observability instance, add the processor there instead of constructing a second competing setup. Preserve existing processors if you intend to keep their destinations.
VoltAgent documents this exporter pattern in its OpenTelemetry integration example. The destination and organization header above are specific to Agnost. Registering a processor is necessary; merely importing an exporter does not instrument an application.
Preserve identity on each call
Pass your application’s user and conversation IDs when invoking an existing agent:
const result = await agent.generateText(prompt, {
userId: authenticatedUserId,
conversationId: applicationConversationId,
});
Those values are application inputs, not global constants. Reuse the conversation ID across related turns and choose a fresh one for unrelated conversations. See VoltAgent’s metadata setup and confirm the actual fields in a received Agnost event.
Identity propagation is particularly important when a top-level agent delegates work. Inspect a real delegated execution instead of assuming every child span has all the metadata you supplied at the root. A correctly nested trace and a correctly grouped product conversation are separate things to verify.
Know what the exporter does not prove
An exporter sends the spans that the application and instrumentation produce. It does not guarantee visibility into every operation inside a custom tool. A tool that calls three services may appear as one opaque step unless those calls are instrumented.
Nor does a normally completed span establish user success. If a booking tool returns a request identifier, the booking may still be pending. If a tool returns an error in an ordinary string, execution may look successful while the task failed.
Keep evidence at the appropriate boundary:
| Boundary | Evidence worth capturing |
|---|---|
| Public turn | Sanitized request and final reply |
| Delegated work | Responsible agent and assigned task |
| Tool execution | Operation, duration, structured result status |
| External action | Stable action ID and authoritative completion |
| Product outcome | Acceptance, correction, or unresolved state |
The last two often require application instrumentation. They cannot be reconstructed reliably from a fluent answer alone.
Investigate a failed action
For an assistant that changes an account setting, start with the external operation’s result. If it failed, inspect the inputs and any retry. If it succeeded but the answer was wrong, inspect how the result reached the final response. If the wrong account was selected, investigate identity and lookup before changing the writing prompt.
Give retries distinct attempt context while preserving the original action identity. That lets you distinguish repeated reasoning from an external change applied twice. Monitoring can reveal this difference; the action implementation still needs its own duplicate-prevention behavior.
When the complaint is slowness, compare the outer request duration with its dependent operations. Parallel steps overlap. Summing every child span produces total work time, not necessarily the time the user waited.
Add conversation tracking only where needed
Agnost’s agnostai npm SDK can wrap agent.generateText() to record a deliberate public input/output boundary. Use this when that boundary is missing from your current traces or when you need to select sanitized public content.
If both sources describe the same invocation, do not count them as two requests. Choose a canonical request record and use child execution records for diagnosis. For streaming, complete the interaction at the stream’s terminal state, not when generation begins.
Review evidence in Agnost
Open Users for the user-facing sequence and Events for the records that arrived. Review whether a recurring problem belongs to one task type, tool, or agent version. Configured intents help organize what users wanted; confirm completion from recorded outcomes.
A useful first review pairs a normal request with a known failed one. Can you see the distinction? Can you follow the same conversation across turns? Does the trace include the operation that matters? Missing evidence is an instrumentation gap, not proof that no problem occurred.
Frequently asked questions
Why do traces arrive locally but not in production?
Check the active environment’s endpoint, header, initialization path, sampling, and process lifecycle. Buffered exporters need an opportunity to flush before short-lived processes terminate.
Should I export every tool argument?
Only what is appropriate for your data policy. Prefer an allowlist of diagnostic fields and resource references over whole account objects or secrets.
Can I use an existing tracing destination too?
You can configure multiple processors when supported by your setup. Review duplication and data destinations explicitly, and avoid adding the same processor twice.
Continue with Agnost’s VoltAgent configuration. For another TypeScript framework’s exporter model, see Mastra observability.
Browse all agent observability guides by framework.
