Instrument multi-agent systems
このページはまだあなたの言語に翻訳されていません。 現在取り組んでいますので、後でもう一度確認してください。
In a multi-agent system, a parent agent delegates work to child agents. Create child agents from the parent with the AI SDK and Agent Analytics records the delegation: child agents carry [Agent] Parent Agent ID, sessions record the root agent and chain depth, and provider wrappers suppress spurious user-message events inside delegated calls. The AI SDK sets [Agent] Message Source to agent on a delegated user message unless you set the source yourself. Every agent's events stay under one [Agent] Session ID.
Give every agent a stable, human-readable ID. Those IDs become the primary dimension for comparing quality and cost across your system.
Declare and dispatch child agents
Declare children off the parent with .child(), then dispatch to them with runAs() (Node) or arun_as() (Python):
const orchestrator = ai.agent('shopping-agent', { description: 'Orchestrates shopping requests' });
const recipeAgent = orchestrator.child('recipe-agent', { description: 'Finds recipes' });
await orchestrator.session({ userId }).run(async (s) => {
s.trackUserMessage(userInput);
const result = await s.runAs(recipeAgent, async (cs) => {
cs.trackUserMessage(delegatedQuery);
return openai.chat.completions.create({ model: 'gpt-4o', messages: [...] });
});
});
Child agents inherit the parent's experiments, and a child can add or override entries by key. Events from runAs() and arun_as() also carry the session's experiments. Refer to Record experiment variants in Agent Analytics.
For the full delegation semantics (context inheritance, span wrapping, nested children, fan-out), refer to Multi-agent architectures in the SDK reference.
Analyze multi-agent sessions
Each [Agent] Session Record carries [Agent] Root Agent Name and [Agent] Agent Chain Depth. Depth is the number of agents on the longest delegation path: 1 is a single agent, 2 is one hop, and 3 or more is deeper nesting. When a parent fans out to several children, depth follows the deepest branch. Filter Session Records where chain depth is greater than 1 to find multi-agent sessions. Depth 2 means exactly one hop. Group any chart by [Agent] Agent ID to compare agents. Refer to Data hierarchy.
A span's parent span isn't the parent agent. On OpenTelemetry, set the span attribute amplitude.parent.agent.id. A LangSmith forwarder stamps one configured agent: nested LangSmith runs stay tool calls or spans and don't become child agents.
Across processes
When an agent calls another agent in a different process, service, or company, the AI SDK sends an agent context envelope with the request. The envelope carries the caller's session, agent, and trace. By default it doesn't share the caller's user ID, so the receiving agent tracks its own user, the same as for any other request. To share the user, the caller sends a per-recipient pseudonym or, with signing, the real user ID. What the receiving agent does with it depends on whether it can verify the envelope's signature. The wire format is public. Refer to Amplitude agent context v1.
Agent context v1 requires @amplitude/ai 0.29.0 or later, or amplitude-ai 1.26.0 or later.
Trusted and untrusted peers
A receiver trusts a context only when its signature verifies against a key the receiver holds. Nothing the sender sets on the message can mark it as trusted.
| Trusted peer | Untrusted peer | |
|---|---|---|
| Typical case | Your own agents, which share a signing key | Another company's agent, or any unsigned context |
| Session and user | The receiver joins the caller's session and user | The receiver keeps its own session and user |
| Trace ID | The receiver adopts the caller's trace ID | The receiver keeps its own [Agent] Trace ID |
| Caller recorded as | [Agent] Parent Agent ID, and the hop counts in [Agent] Agent Chain Depth | [Agent] Peer Agent ID, [Agent] Peer Session ID, and [Agent] Peer Trace ID |
[Agent] Message Source on the inbound request | agent, a delegated prompt inside the caller's session | user, so the request counts as a turn and shows in the transcript |
A trusted context joins the two sides into one session only when both agents send events to the same Amplitude project. When they send to different projects, each project holds only its own side of the session, and Amplitude doesn't join sessions across projects.
Every inbound context also stamps [Agent] Context Trust, [Agent] Context Verify Result, [Agent] Actor Type, and [Agent] Identity Type on the receiver's session. A verify result such as unknown_kid or expired names the reason a context isn't trusted, so a missing key or a clock problem shows up in your data. Use [Agent] Actor Type to separate agent-led sessions from human-led ones. Refer to Agent context properties.
By default, A2A and Agent Client Protocol (ACP) contexts carry no user ID. To send one, refer to Identity modes.
Set up signing between your own agents
Generate a random secret of at least 32 bytes and give it a key ID. Load both into every service that sends or receives agent context, from your secret manager. Any service that holds the key can vouch for any user and session, so treat key holders like database credentials and never put a key in a browser or mobile app.
The SDK reads the keys from the environment:
AMPLITUDE_AI_CONTEXT_KEYS='{"ctx-2026-11": "<secret from your secret manager>"}'
AMPLITUDE_AI_CONTEXT_ACTIVE_KID=ctx-2026-11
To configure the keys in code instead, pass a ContextPolicy to the client:
import { AIConfig, AmplitudeAI, ContextPolicy } from "@amplitude/ai";
const ai = new AmplitudeAI({
apiKey: process.env.AMPLITUDE_AI_API_KEY!,
config: new AIConfig({
contextPolicy: new ContextPolicy({
signingKeys: { "ctx-2026-11": config.contextSigningKey },
activeKid: "ctx-2026-11",
}),
}),
});
The SDK signs outbound context with the active key and accepts every configured key, so you can rotate keys without dropping trust. Use a separate key ID and secret for each counterparty, so you can revoke one without rotating the rest. Without a key, the SDK sends unsigned context, and every receiver treats it as untrusted. If the key environment variables are invalid, the SDK logs an error and treats every inbound context as untrusted; amplitude-ai doctor names the problem.
The policy in AIConfig applies to the client's sessions and, outside a session, to the whole process. Run one policy per process: a second client with a different policy replaces the first and logs a warning. Refer to Key rotation.
Send and receive over A2A
On the calling agent, add the context to the outbound A2A message. On the receiving agent, extract it and open the session with context=. The SDK applies the trust rules, so don't copy IDs from the extracted context into the session yourself.
import { extractA2aMetadata, injectA2aMetadata } from "@amplitude/ai";
// Calling agent
message.metadata = injectA2aMetadata(message.metadata);
// Receiving agent
const context = extractA2aMetadata(request.message.metadata);
await sellerAgent.session({ context }).run(async (s) => {
s.trackUserMessage(text);
// ...
});
To advertise support, add the extension to your AgentCard with declare_a2a_extension() (declareA2aExtension() in Node). The extension URI is the agent context v1 page.
The other transports follow the same pattern:
| Transport | Outbound | Inbound |
|---|---|---|
| Agent2Agent (A2A) | inject_a2a_metadata() on Message.metadata | extract_a2a_metadata() |
| Agent Client Protocol (ACP) | inject_acp_meta() on the request's _meta | extract_acp_meta() |
| HTTP | inject_context() on request headers | extract_context(headers) |
Node has the same helpers in camel case, and both SDKs read each other's envelopes, so a Python agent and a Node agent interoperate. For HTTP services, the bundled middleware can apply the same trust rules to every request. Refer to Propagate context across services.
Link the response back to the caller
The receiving agent can return its own context in the response, so the caller can find the receiver's session too. Inside the receiver's session, add it with inject_a2a_response_metadata() for A2A, inject_acp_result_meta() for ACP, or inject_response_headers() for HTTP. Response contexts never carry a user ID or an actor type.
On the calling agent, extract the response context and attach it to the tool call that made the request. The tool call event then carries [Agent] Peer Agent ID, [Agent] Peer Session ID, and [Agent] Context Verify Result for that one call:
const reply = await a2aClient.sendMessage(message);
s.trackToolCall("seller_agent.checkout", latencyMs, true, {
peer: extractA2aMetadata(reply.metadata),
});
The link attaches to one call, never to the session, so an agent that calls several peers in parallel keeps each peer's IDs on its own tool call. The caller's session and user never change. To get the same properties as a dictionary, call peer_properties() (peerProperties() in Node) on the extracted context.
Join outcomes to the agent session
A business outcome such as a checkout usually arrives as a product event, not an agent event. To join it to the agent session that produced it, add the agent's IDs to the event with context_properties() (contextProperties() in Node):
amplitude.track(
"Checkout Completed",
{ orderId, ...ai.contextProperties() },
{ user_id: userId },
);
Inside a session, the helper returns [Agent] Session ID, [Agent] Trace ID, and [Agent] Agent ID, plus [Agent] Peer Agent ID and [Agent] Peer Session ID when an untrusted peer started the session. Outside a session, it returns an empty object, so it's safe to spread into any event. It never adds a user ID. When the outcome completes in another service or later, pass a propagated context: context_properties(context=extracted).
The outcome then joins in both directions. In the receiver's project, the checkout shares [Agent] Session ID with the receiver's agent session, and that session's [Agent] Peer Trace ID holds the caller's trace ID. In the caller's project, the tool call's [Agent] Peer Session ID names the receiver's session.
Coding agents
Coding agents carry the parent agent without code:
- Claude Code: Subagent log records carry
agent_idandparent_agent_id, so subagents nest under the agent that started them. Refer to Claude Code. - Codex: The Codex hook forwarder reads each subagent thread's parent from the session transcript. Refer to Codex.
- Buzz: The forwarder sets each worker's parent to the coordinator that delegated to it. Refer to Buzz.
これは役に立ちましたか?
For AI agents: a documentation index is available at /docs/llms.txt. Append .md to any page URL for markdown, or send Accept: text/markdown.