e-volv Berserker
Agent observability and evals. Any agent instrumented with OpenTelemetry sends its traces to one endpoint, and Berserker turns the GenAI spans into agent runs: one row per top-level agent span, with tokens, cost, tool calls, session and error. It works on its own; with e-volv Observer on the same workspace, a run sits beside the logs and error groups of the service that ran it.
Opt in. Berserker is opened per workspace while the first partners run it. Every workspace gets the free tier once it is on; see tiers and retention.
1. Create a project and a key
In the app, open Berserker, then Settings, and create a project for the service or agent. Its key is shown once. A key with the agents:write scope can send traces and nothing else; an existing Observer key with logs:write works too. Keys go in the Authorization: Bearer evk_… header.
2. Point your exporter at the endpoint
POST https://api.e-volv.io/api/public/v1/logs/otlp/v1/traces Authorization: Bearer evk_...
OTLP over HTTP, JSON or protobuf, gzip welcome. The resource’s service.name picks the project within the key’s workspace.
OpenTelemetry collector
exporters:
otlphttp/evolv:
endpoint: https://api.e-volv.io/api/public/v1/logs/otlp
headers:
Authorization: Bearer ${env:EVOLVE_AGENTS_KEY}
compression: gzip
service:
pipelines:
traces:
exporters: [otlphttp/evolv]Vercel AI SDK
Turn on the SDK’s telemetry per call; the functionId becomes the agent name.
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await generateText({
model: openai('gpt-4o'),
prompt,
experimental_telemetry: {
isEnabled: true,
functionId: 'support-reply', // becomes the agent name
metadata: { sessionId, userId },
},
});and export the spans to Berserker:
// instrumentation.ts (Next.js) or your OTel bootstrap
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
new NodeSDK({
serviceName: 'support-bot',
traceExporter: new OTLPTraceExporter({
url: 'https://api.e-volv.io/api/public/v1/logs/otlp/v1/traces',
headers: { Authorization: `Bearer ${process.env.EVOLVE_AGENTS_KEY}` },
}),
}).start();OpenAI Agents SDK
import os
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
provider = TracerProvider(resource=Resource.create({"service.name": "support-bot"}))
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
endpoint="https://api.e-volv.io/api/public/v1/logs/otlp/v1/traces",
headers={"Authorization": f"Bearer {os.environ['EVOLVE_AGENTS_KEY']}"},
)))
trace.set_tracer_provider(provider)then add the openai-agents OpenTelemetry instrumentation as its own docs describe.
What is read
The OpenTelemetry GenAI semantic conventions (current and previous attribute names), the OpenInference vocabulary used by Arize Phoenix and the LangChain and LlamaIndex instrumentations, and the Vercel AI SDK’s own ai.* telemetry.
| Fact | Attribute |
|---|---|
| Operation | gen_ai.operation.name (invoke_agent, chat, execute_tool, embeddings), or openinference.span.kind, or the span name |
| Agent | gen_ai.agent.name, gen_ai.agent.id |
| Provider and model | gen_ai.provider.name (older: gen_ai.system), gen_ai.request.model, gen_ai.response.model |
| Tokens | gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, and the cache_read and cache_creation variants |
| Tool | gen_ai.tool.name |
| Session and user | gen_ai.conversation.id, enduser.id |
| Prompt version | evolv.prompt.name, evolv.prompt.version |
A run is the subtree under a top-level invoke_agent span, a Vercel ai.generateText root, or an OpenInference AGENT or CHAIN span. A bare chat span with no parent is a run of its own. Nested agents fold into the top-level run, so a session’s tokens are counted once. A root that arrives after its children is caught by a sweep every five minutes; a trace with GenAI spans and no root after an hour becomes an orphan run, so the spend is still counted.
Cost
Tokens are priced per model call from a maintained price list. A workspace that sets its own input and output price per million tokens on a model under Integrations is priced from that instead. Anthropic and Bedrock cache reads and writes are repriced at their cache rates; OpenAI-compatible providers report the discount in their own numbers.
Content
Prompt and completion content is off by default: the rollup reads only the facts above. Where an instrumentation sends gen_ai.input.messages and gen_ai.output.messages (or the older and OpenInference or Vercel equivalents), the run page shows it, cut at 32 KB, and the run can be replayed and saved as an eval fixture. Turning content on is a setting of your SDK or collector.
Runs without spans
An agent that cannot emit OpenTelemetry posts a summary to POST /api/public/v1/runs (scope runs:write) with tokensInput, tokensOutput, costUsd, sessionId and userId. The run appears with no tree.
Alerts
Three rule metrics read the runs: agent spend per day in dollars, agent run error rate in percent over a lookback (one hour by default), and agent run p95 duration in milliseconds over the same lookback. Each takes an optional agent name; without one the rule covers every agent in the workspace. They notify on the same channels as every other alert.
API
Under /api/workspaces/:wsId/logs/agents, with a signed-in session. Projects, sampling and usage live under /api/workspaces/:wsId/ai.
| Route | Returns |
|---|---|
GET overview?from&to&projectId | Totals, a time series, a per-agent table |
GET runs?agent&status&model&sessionId&userId&limit&offset | Runs, newest first |
GET runs/:traceId | The run and its spans, each classified |
GET sessions, GET sessions/:id | Conversations and their runs |
GET cost?groupBy=agent|model|day | Spend |
POST runs/:traceId/replay | Read-only replay through the eval harness (needs content) |
POST runs/:traceId/fixture | Save the run as an eval fixture (needs content) |
Next: evals, prompts or tiers and retention.