Most AI agents are polite. They sit at a URL, waiting for you to say hello. You send a message; they reply. The conversation ends; they forget everything. That's fine for question-and-answer tasks. It's the wrong shape for customer experience.
The most important CX moments don't announce themselves. A customer who's been on hold for 22 minutes and just visited your competitor's pricing page isn't going to ask your agent for help. They're going to leave. And your agent, patiently waiting at its endpoint, will never know it happened.
Ambient agents change this. They don't wait for a prompt. They watch event streams, detect signals, and act before the customer has to say a word. This article is about building them.
What Makes an Agent Ambient
An ambient agent is event-driven, not conversation-driven. Instead of sitting behind an HTTP endpoint, it subscribes to one or more event streams and evaluates each incoming event against a set of conditions. When conditions match, it acts.
The architecture difference is real. A conversational agent has a turn structure: user speaks, agent responds, repeat. An ambient agent has a trigger structure: event arrives, condition evaluates, action fires or doesn't.
Here's the structural contrast:
The condition is where the intelligence lives. It might be a simple threshold: "if sentiment score < 0.35, fire." It might be a compound rule: "if frustration signal AND hold time > 15 minutes AND customer tier is enterprise, fire." The evaluation happens at event-arrival time, not at conversation-start time.
What this means practically: your ambient agent can watch 50,000 simultaneous sessions. It's not bounded by how many conversations a single model can hold in context. It's bounded by how fast your event pipeline delivers events and how well your condition logic is tuned.
Which Event Streams Matter for CX
Not every event stream is worth subscribing to. For customer experience specifically, four categories generate the most actionable signal.
Conversation events are the richest. Real-time STT output, sentiment scores, intent classifications, and silence detection all arrive as a stream of events per session. An ambient agent watching this stream can detect when a conversation is going sideways before the customer hangs up. That's a capability a conversational agent inside that same call simply doesn't have.
Behavioral events come from your web or app layer. Page views, scroll depth, time-on-page, cart mutations, and navigation patterns are a leading indicator of intent. A customer who visits /account/cancel is signaling something your CRM doesn't know yet. The ambient agent can act on that signal before a cancellation request ever reaches your support queue.
CRM and ticketing events carry relationship context. A deal moving from negotiation to at_risk, a support ticket reopening for the third time this week, or a payment method failing silently: all of these should trigger an ambient agent response that's specific to that customer's situation.
Infrastructure and operational events are underused. Queue depth spiking, average handle time jumping, a model's latency doubling: your ambient agent can watch these and preemptively adjust behavior. Route to a faster model, enable a simplified response mode, do it before customers experience the degradation themselves.
Here's the shape of a subscription handler. The pattern is a thin wrapper around your stream consumer (Kafka, NATS, SQS, webhooks, whatever you've already got):
type Event =
| { stream: 'conversations'; sessionId: string; sentimentScore: number; durationSec: number }
| { stream: 'behavioral'; customerId: string; event: string; page: string }
| { stream: 'crm'; customerId: string; event: string; to: string };
const triggers = [
(e: Event) =>
e.stream === 'conversations' && e.sentimentScore < 0.35 && e.durationSec > 300,
(e: Event) =>
e.stream === 'behavioral' && e.event === 'page_view' && e.page === '/account/cancel',
(e: Event) =>
e.stream === 'crm' && e.event === 'deal_stage_changed' && e.to === 'at_risk',
];
async function onEvent(event: Event) {
if (!triggers.some((match) => match(event))) return;
if (await alreadyActedOn(event)) return; // dedup by sessionId/customerId
await act(event);
await audit(event);
}The condition layer is plain TypeScript. No framework required. The two things you can't skip are deduplication and the audit write, and we'll come back to both later.
Three CX Use Cases Where This Architecture Pays Off
The event-driven approach earns its complexity in three scenarios where conversational agents can't help.
Churn prevention during the call. When a customer's sentiment drops below your threshold and they've been on hold for more than five minutes, a conversational agent can't catch it. It's busy talking. An ambient agent watching the sentiment stream fires right away. It can inject a context note to the human agent on the call, route the conversation to a senior team member, or trigger a callback request if no human is available. The intervention happens in the same call, not in a follow-up email the next day.
Context preloading before the conversation starts. Your ambient agent subscribes to the call-initiation event, fired the moment a phone number hits your IVR. It pre-fetches account history, recent tickets, subscription status, predictive intent based on that customer's recent browsing. By the time the conversation actually starts (after queue wait, after greeting), the context window is already loaded. No "let me pull up your account" lag. The companion piece cx-agents-fail-between-conversations-async-tasks walks through building that pre-conversation state in detail.
Post-conversation follow-through. Most agents forget everything the moment a call ends. An ambient agent watching conversation-closed events triggers post-call workflows on its own. Here's a sketch using the @chanl/sdk transcript API plus the memory module to record commitments the customer made on the call:
import { Chanl } from '@chanl/sdk';
const chanl = new Chanl({ apiKey: process.env.CHANL_API_KEY! });
type ConversationClosedEvent = {
conversationId: string;
customerId: string;
};
async function handleConversationClosed(event: ConversationClosedEvent) {
const { data: transcript } = await chanl.calls.getTranscript(event.conversationId);
// Your own LLM call against the transcript, returning the fields you care about.
const extracted = await summarize(transcript, [
'resolution_status',
'promise_made',
'follow_up_date',
'issue_category',
]);
if (extracted.promise_made) {
await chanl.memory.create({
customerId: event.customerId,
content: `Promised: ${extracted.promise_made} by ${extracted.follow_up_date}`,
kind: 'commitment',
});
await scheduleFollowUp(event.customerId, extracted.follow_up_date);
}
if (extracted.resolution_status === 'unresolved') {
await flagForReview(event.conversationId, 'unresolved_at_close');
}
}The pattern is the same one mcp-webhooks-event-driven-agents covers for tool-side event hooks. The ambient agent pattern extends that event-driven thinking to the full session lifecycle, not just tool invocations.
The Monitoring Problem That Catches Teams Off Guard
Ambient agents introduce a monitoring problem that conversational agents don't have: you can't just look at conversation quality scores. An ambient agent that never fires is failing silently. One that fires too often is making things worse.
You need four metrics, not one:
Trigger rate measures how often the agent fires per 1,000 sessions. Too high means your conditions are too loose. Too low means you're missing real events. Your trigger rate should be calibrated against your actual bad-outcome rate. If 3% of sessions end in churn, your trigger rate should be somewhere in that range, not 40%.
Action accuracy measures what percentage of triggered actions achieved a desired outcome. "Customer stayed on the call and issue resolved" is an outcome. "Customer hung up 30 seconds after intervention" is not. This is hard to measure in real time, which is why most teams skip it. Don't skip it. It's the only way to know if your conditions are tuned correctly.
False positive rate is the percentage of interventions that weren't needed. A customer who was about to convert, interrupted by a "we noticed you might be frustrated" message, is a false positive. Start with a 5% false positive budget. The cost of a bad intervention is real.
Coverage measures the percentage of distressed sessions your agent caught. If 100 sessions ended in churn this week and your agent only fired on 20 of them, your coverage is 20%. Coverage and false positive rate trade off against each other. Tightening your conditions to reduce false positives will lower coverage.
Chanl's analytics dashboard surfaces all four metrics per ambient agent so you can see trigger rate and coverage trending together without building a separate data pipeline.

Testing Ambient Agents Before Going Live
You can't test an ambient agent by chatting with it. You need to test its event handling, its condition logic, and its action outcomes against real history.
The most effective approach is event stream replay: feed historical session events through your new agent configuration and compare what the agent would have done against what actually happened. This tells you false positive rate and coverage before you ever touch production.
Scenarios supports synthetic event injection for edge cases: concurrent triggers on the same session, events arriving out of order, stream gaps from infrastructure flakiness. These are hard to reproduce manually but critical to test. Ambient agents running on incomplete streams are a source of both missed events and spurious triggers.
Shadow mode is the safest production ramp. Deploy the ambient agent, subscribe to all the same streams, evaluate all the same conditions, but instead of acting, log its would-be actions. After two weeks of shadow mode, you have a real dataset of "things the agent would have done." Review the 10 most controversial cases with your team. The ones that look correct become evidence you're ready to go live. The ones that look wrong become training data for tightening conditions.
Never skip shadow mode for ambient agents. A false-positive intervention on a high-value customer during a contract renewal call is the kind of mistake that's hard to explain.
From Prototype to Production
The path from a working ambient agent to one that runs reliably at scale has a few non-obvious requirements.
Session state and deduplication. Without a session state store keyed by session ID, a single churn signal might fire five times as the customer stays on hold. Use a short-lived session state store with a TTL matching your maximum session duration. Redis works; most agent platforms provide a managed version.
Per-customer rate limiting. Even with deduplication, you don't want to intervene more than once per session, and probably not more than once per day per customer. A rate limiter with a cooldown period is table stakes.
Graceful degradation. Ambient agents that depend on third-party data (CRM, order management, loyalty platform) need to handle unavailability cleanly. If the CRM is down when an at-risk signal fires, your agent should fall back to a simpler model rather than throwing an unhandled error. Monitoring alerts on stream disconnects catch this class of failure before it becomes a silent gap.
Auditability. Every intervention your ambient agent makes should generate an immutable audit record: which event triggered it, what conditions matched, what action was taken, what the outcome was. You'll need this for debugging, compliance, and the inevitable "why did the system send that message?" question.
The build, connect, monitor triad applies here. You build the condition logic and action handlers. You connect to the event streams (conversation, behavioral, CRM). Then you monitor trigger rate, coverage, and false positives. It's a calibration loop that never fully ends and shouldn't.
Closing the Feedback Loop
The teams building ambient agents today are finding that the hard part isn't the trigger logic. It's the outcome measurement. You can tell when your agent fired. You can't always tell, in the moment, whether it helped.
Building a closed feedback loop between ambient agent actions and customer outcomes is the frontier. It needs behavioral data, CRM outcomes, and sometimes a signal weeks later when you can see if the at-risk deal closed. That loop is what separates an ambient agent that's interesting from one that's getting better every week.
Start with the trigger logic, ship it in shadow mode, graduate to action mode with a conservative false positive budget, then invest in outcome measurement. The customer who was about to leave, the one your request-reply agent never knew about, is now the one your ambient agent can catch. That's the shift the architecture enables.
See What's Happening Between Your Conversations
Chanl's analytics tracks trigger rate, action accuracy, false positive rate, and coverage for every ambient agent you deploy. Know what your agents are doing while you sleep.
Explore AnalyticsCo-founder
Building the platform for AI agents at Chanl — tools, testing, and observability for customer experience.
Learn Agentic AI
Weekly. Patterns and recipes for shipping AI agents that actually work — MCP, scorecards, regression tests, prompts, model comparisons. From teams running agents in production.



