ChanlChanl
Knowledge & Memory

What your agent does when it knows nothing about a customer

The cold-start problem hits every CX agent on first contact: no history, no profile, no context. Here's a practical architecture for handling first-contact customers without making them feel like strangers.

DGDean GroverCo-founderFollow
June 20, 2026
15 min read
Empty customer profile card with a question mark, representing an AI agent meeting an unknown customer for the first time

A customer opens your chat widget at 11pm. They type: "I need help with my recent order."

Your agent has nothing. No account lookup. No order history. No name. This customer has never contacted you before -- no conversation history, no stored preferences, no profile. The context window is empty except for the message you just received.

This is the cold-start problem: zero history, zero context, first contact. Every AI agent faces it on every first interaction with a new customer. And how your agent handles this moment determines whether the customer feels like they're talking to something intelligent or something that forgot to load.

Most agents handle it badly. "I'd be happy to help! Could you please provide your full name, account number, email address, and the reason for your inquiry?" That's an IVR in a chat box.

Here's how to do it differently.

What cold start actually is

Cold start in AI agents has a specific technical meaning. It's not "low context" (the agent has some information but not much) or "stale context" (the agent has outdated information). It's the condition where the agent has no stored history for this specific customer at all.

The distinction matters because the solutions are different. Stale context is a memory freshness problem. Low context is a retrieval problem. Cold start is a first-contact problem, and it requires a different architecture.

The naive mental model is that cold start means the agent knows nothing. That's not quite right. Before the customer sends a single message, a well-architected CX agent already has:

  • The channel (chat, voice, SMS, email)
  • The time and day of the contact
  • For chat: the page the customer is on, the referrer, any URL parameters, session data if authenticated
  • For voice: the phone number, which can be looked up in the CRM
  • The device type and sometimes the locale

This isn't nothing. It's enough to make a reasonable first guess at the customer's situation and to avoid asking for information you already have. The problem isn't that you have no information -- it's that teams often don't collect and use the information they already have before the first message arrives.

Tier 1: pre-conversation signals

The signals available before the first message are the cheapest context you'll ever get. Collect all of them.

For a voice agent, the phone number is often enough to pre-load account context from your CRM before the agent says a word:

cold-start-context-loader.ts·typescript
interface PreConversationContext {
  channel: "voice" | "chat" | "sms" | "email";
  phoneNumber?: string;
  pageUrl?: string;
  sessionData?: AuthenticatedSession;
  referrer?: string;
  locale?: string;
  timestamp: Date;
}
 
interface CustomerContext {
  customerId?: string;
  name?: string;
  accountStatus?: string;
  recentOrders?: Order[];
  openTickets?: SupportTicket[];
  preferredLanguage?: string;
  inferredIntent?: string;
}
 
async function loadPreConversationContext(
  signals: PreConversationContext
): Promise<CustomerContext> {
  const context: CustomerContext = {};
 
  // Voice: look up by phone number
  if (signals.phoneNumber) {
    const crmResult = await crm.lookupByPhone(signals.phoneNumber);
    if (crmResult) {
      context.customerId = crmResult.id;
      context.name = crmResult.name;
      context.accountStatus = crmResult.status;
      context.recentOrders = await orders.getRecent(crmResult.id, 3);
      context.openTickets = await support.getOpen(crmResult.id);
    }
  }
 
  // Chat: authenticated session
  if (signals.sessionData?.userId) {
    const account = await accounts.get(signals.sessionData.userId);
    context.customerId = account.id;
    context.name = account.name;
    context.accountStatus = account.status;
  }
 
  // Infer intent from page context
  if (signals.pageUrl) {
    context.inferredIntent = inferIntentFromUrl(signals.pageUrl);
  }
 
  // Set locale from browser or phone
  context.preferredLanguage = signals.locale || "en";
 
  return context;
}
 
function inferIntentFromUrl(url: string): string | undefined {
  if (url.includes("/cancel") || url.includes("/cancellation")) return "cancellation";
  if (url.includes("/return") || url.includes("/refund")) return "return_refund";
  if (url.includes("/billing") || url.includes("/invoice")) return "billing";
  if (url.includes("/orders") || url.includes("/track")) return "order_status";
  return undefined;
}

When this context loads cleanly -- you know who they are from the phone number or session -- you've turned a cold start into a warm start without the customer doing anything. The first message your agent sends can reference their open ticket or recent order, and the interaction starts in the middle, not at zero.

When the lookup fails -- unknown phone number, unauthenticated session -- you're genuinely starting cold. That's where tier 2 comes in.

Tier 2: progressive profiling during the conversation

Progressive profiling means learning what you need to know during the conversation, exactly when you need to know it, instead of front-loading a questionnaire.

The principle is: the agent starts with the problem, not the identity. Most customers open by describing what they need ("my order is late," "I can't log in," "I need to cancel"). The agent's job in the first turn is to understand the problem, not to establish who the customer is.

Here's what that looks like in practice. A customer sends: "I need to return something I bought last week."

A cold-start agent with poor design says: "Of course! Before I can help you with that, could you please provide your full name, email address, and order number?"

A well-designed cold-start agent says: "I can help with that. What's the order number for the item you'd like to return?"

One piece of information, the one you actually need right now to take the next step. When the customer provides the order number, the agent looks it up and now has everything: their identity, the order details, the return eligibility, and the purchase date. All from one natural ask.

progressive-context-collector.ts·typescript
class ColdStartAgent {
  private context: Partial<CustomerContext> = {};
  private collectedFields: Set<string> = new Set();
 
  async handleMessage(message: string, turnIndex: number): Promise<string> {
    // On first turn: understand the problem, don't ask for identity
    if (turnIndex === 0) {
      const intent = await this.classifyIntent(message);
      this.context.inferredIntent = intent;
      return this.generateOpeningResponse(intent, message);
    }
 
    // Ask for identifying info exactly when you need it
    if (this.needsOrderContext() && !this.collectedFields.has("orderId")) {
      return "To look that up for you, what's your order number?";
    }
 
    if (this.needsAccountContext() && !this.collectedFields.has("customerId")) {
      return "I'll need to pull up your account -- could you share the email on the account?";
    }
 
    // Process with available context
    return await this.processWithContext(message);
  }
 
  private async generateOpeningResponse(intent: string, message: string): Promise<string> {
    // Acknowledge the problem, start helping immediately
    const responses: Record<string, string> = {
      return_refund: "I can help with that return.",
      order_status: "Let me look into that order for you.",
      billing: "I can help sort out the billing question.",
      cancellation: "I can take care of that cancellation.",
    };
 
    return responses[intent] ?? "I can help with that.";
  }
}

The key discipline: never ask for information before you need it. If you don't yet have a reason to know the customer's name, don't ask for it. When you have a reason -- you're about to initiate a refund and need to confirm the account -- ask then, in context, with the reason clear.

Tier 3: context enrichment from what the customer says

Even before you ask for anything, the customer is giving you information in every message. Their word choice, the specifics of their problem, the order details they volunteer, the language they're using -- all of this is context you can extract and use.

An entity extraction pass on every customer message costs almost nothing and can quickly build a partial profile from natural conversation:

entity-extractor.ts·typescript
interface ExtractedEntities {
  orderIds: string[];
  productNames: string[];
  dates: string[];
  amounts: string[];
  emailAddresses: string[];
  phoneNumbers: string[];
}
 
async function extractEntities(message: string): Promise<ExtractedEntities> {
  const response = await anthropic.messages.create({
    model: "claude-haiku-4-5-20251001",
    max_tokens: 256,
    system: `Extract structured entities from customer messages.
Return JSON only: { orderIds, productNames, dates, amounts, emailAddresses, phoneNumbers }.
Use empty arrays for fields not found. Do not hallucinate values.`,
    messages: [{ role: "user", content: message }],
  });
 
  return JSON.parse(response.content[0].text);
}
 
// In the agent loop:
async function enrichContextFromMessage(
  message: string,
  context: Partial<CustomerContext>
): Promise<Partial<CustomerContext>> {
  const entities = await extractEntities(message);
 
  // If they mentioned an order ID, look it up
  if (entities.orderIds.length > 0 && !context.recentOrders) {
    const order = await orders.getById(entities.orderIds[0]);
    if (order) {
      context.customerId = order.customerId;
      context.recentOrders = [order];
    }
  }
 
  // If they mentioned their email, look them up
  if (entities.emailAddresses.length > 0 && !context.customerId) {
    const customer = await crm.lookupByEmail(entities.emailAddresses[0]);
    if (customer) {
      context.customerId = customer.id;
      context.name = customer.name;
    }
  }
 
  return context;
}

By the third turn of most support conversations, you've typically collected enough through entity extraction to identify the customer, look up their account, and have a full context profile -- without ever asking "what's your name?"

The graceful introduction pattern

When you've collected enough context through the tiers above, you can switch modes: from cold-start handling to personalized assistance. This transition needs to feel natural, not jarring.

A bad transition: "Now that I've confirmed your order number, I can see you're James Kim with account ID 48291. Your order #12345 was..."

A good transition: "Got it -- that order shows as eligible for a return. I'll get that started for you, James."

The customer doesn't need to know you just looked them up. The system performed the lookup silently, and the agent now uses the information naturally. The "reveal" is just using their name once you have it confirmed, not announcing that you now know who they are.

The architecture that makes this work:

Yes No Yes No Customer contacts agentzero stored history Tier 1: Pre-conversation signalsphone number, page URL, session Identity resolved? Warm startpre-loaded account context Tier 2: Progressive profilingask exactly when needed Tier 3: Entity extractionfrom conversation content Profile complete enoughto take next action? Personalized assistancetransition to normal flow
Cold-start context pipeline: pre-signal to warm profile

What good cold-start handling looks like in practice

A well-handled first contact goes from zero context to a full working profile in two turns, without the customer noticing any gap. Here's the exchange:

text
Customer: My package hasn't arrived and it's been two weeks.
Agent: That's too long to wait. What's the order number?
Customer: It's 88234.
Agent: [looks up order 88234 -- finds customer Maria Chen, order placed May 28, still in transit]
       That order was marked as still in transit as of this morning. It looks like there was a delay
       at the distribution center in your area. I can file a trace request now, Maria -- that
       typically resolves within 48 hours. Want me to go ahead?
Customer: Yes please.
Agent: Done. You'll get an email at maria@... when the trace completes. Should I also set up
       a replacement shipment in case the package can't be located?

By the end of turn two, the agent has: the customer's full name, email, order details, shipping status, and the customer's preference. All from one natural ask. This is what Chanl's memory system is built to support -- collecting and persisting this context so that if Maria calls back next week, it's not a cold start anymore.

Testing cold-start scenarios

Cold start deserves its own slice in your eval dataset. Your scenario testing suite should include cases where the agent starts with zero customer history and is scored on:

Time to context. How many turns does it take before the agent has enough context to take a productive action? Two turns is good. Four or more is a sign of unnecessary friction.

Unnecessary questions. Did the agent ask for information it already had from pre-conversation signals? If the phone number lookup succeeded and the agent still asked "can I get your name?", that's a failure.

Natural question framing. When the agent did need to ask, did it ask in context ("to look that up, what's your order number?") or upfront ("before I can help, I'll need your name, account number, and...")? The former is acceptable. The latter is an IVR.

Identity resolution accuracy. When the customer provides an order number or email, does the agent correctly resolve it to a customer profile? Mismatches here are high-cost failures.

For monitoring in production, track two metrics specifically for cold-start interactions: average turns to first productive action, and percentage of first-contact sessions where customer identity was resolved by the end of the conversation. Both should improve as you iterate on your cold-start handling.

Memory is the long-term fix

The cold-start problem is permanent for first-time customers but solvable for every subsequent contact. Every conversation a customer has with your agent is an opportunity to build a profile that makes the next contact faster and more personalized.

After a well-handled cold-start interaction, your agent memory system should store: who the customer is, what their issue was, how it was resolved, any preferences they expressed, and any context they'll need next time. The full memory architecture covers how to build this across session, persistent, and semantic layers.

The goal is that after the first contact, cold start never happens again for that customer. The second call starts warm. The third call starts warmer. Over time, the gap between a new customer and a known customer collapses.

But the first contact always starts cold. Having an architecture that handles it well -- pre-conversation signals, progressive profiling, entity extraction, and a graceful introduction pattern -- is what separates agents that feel like systems from agents that feel like help.

The first impression is set by the first contact. Make sure yours is designed.

Customer service representative

Customer Profile

Contact details & preferences

SC

Sarah Chen

Premium
Company
Acme Corp
Last Call
2 days ago
Preferred
Email
Agent Override
Sales Bot
Custom Attributes
VIPEnterpriseWest Coast

Give every agent conversation context from the first word

Chanl's memory and scenario testing give you the tools to build warm-start pipelines, test cold-start handling at scale, and make sure first impressions are designed, not accidental.

Explore memory features
DG

Co-founder

Building the platform for AI agents at Chanl — tools, testing, and observability for customer experience.

El briefing de Signal

Un email por semana. Cómo los equipos líderes de CS, ingresos e IA están convirtiendo conversaciones en decisiones. Benchmarks, playbooks y lo que funciona en producción.

500+ líderes de CS e ingresos suscritos

Frequently Asked Questions