Skip to main content
Every call your agent handles produces structured reporting data automatically. There are two layers, both configured by you in Agent Studio:
  • Real-time metrics are written during the call from your flow functions using conv.write_metric.
  • Post-call AI extraction runs after the call ends. The full transcript is sent to an LLM via conv.utils.prompt_llm so you can pull out fields that can only be determined by reviewing the whole conversation.
Together they cover the two questions builders typically need to answer for reporting: “What happened at specific moments in the call?” and “What does the call mean once it’s over?”.

Layer 1: Real-time metrics

Inside your flow functions, write metrics at key moments using a single line of code:
conv.write_metric("BOOKING_CONFIRMED")
conv.write_metric("HANDOFF_REASON", "billing_dispute")
conv.write_metric("LANGUAGE", "Spanish")
Each call fires in real time as the conversation progresses and is immediately available in Dashboards, Smart Analyst, and the Conversations API. Common examples:
MetricWhen it fires
APPOINTMENT_BOOKEDCaller confirms an appointment
PAYMENT_PROCESSEDPayment completes on the call
HANDOFF_BILLINGCaller is transferred to your billing team
SMS_SENTAn SMS confirmation is sent during the call
INSURANCE_VERIFIEDInsurance is confirmed on the call
You decide what to track. Add conv.write_metric() calls anywhere in your flow functions. See Metrics for naming conventions and how metric definitions affect Smart Analyst.

Layer 2: Post-call AI extraction

After the call ends, the platform can run the full transcript through an LLM to extract structured data that depends on the whole conversation – call reasons, sentiment, summaries, follow-up flags, and so on. You configure this in your End tool (end_function.py). The pattern has three pieces: a dictionary of extraction queries, a helper function that builds the prompt and calls the LLM, and a call from end_function itself.
1

Define what you want to extract

Define each field as a key with a plain-English instruction. The key becomes the metric name; the value tells the LLM what to look for.
EXTRACTION_QUERIES = {
    "CALL_REASON": "Categorize why the customer called (e.g. appointment scheduling, billing dispute, prescription refill).",
    "RESOLUTION": "Was the caller's issue resolved? Answer: yes, no, or partial.",
    "SENTIMENT": "Rate the caller's overall sentiment: positive, neutral, or frustrated.",
    "REPEAT_CONTACT": "Did the caller mention they've called about this before? Answer: yes or no.",
    "ESCALATION_COUNT": "Count how many times the caller asked to speak to a human agent.",
    "AGENT_QUALITY": "Score 0 or 1: 1 = the call was handled well, 0 = repeated misunderstandings or inappropriate responses.",
}
2

Build the prompt and call the LLM

Format the transcript from conv.history, embed the queries, and call conv.utils.prompt_llm with return_json=True so the response is parsed into a dict.
def post_call_extraction(conv):
    # Format the conversation transcript
    conversation_text = "\n".join(
        f"{event.role.capitalize()}: {event.text}"
        for event in conv.history if event.text
    )

    # Build the prompt
    prompt = f"""You are analyzing a completed voice conversation.

## Transcript
{conversation_text}

## Extract the following
{chr(10).join(f'- **{k}**: {v}' for k, v in EXTRACTION_QUERIES.items())}

Return a JSON object with one key per metric."""

    # Call the LLM — returns parsed JSON
    return conv.utils.prompt_llm(prompt, return_json=True, show_history=False)
prompt_llm requires activation on your account. If you receive a NotImplementedError, contact your PolyAI representative to enable it.
3

Call it from end_function

Run the extraction from end_function, alongside any real-time metrics that depend on final call state.
def end_function(conv):
    # Real-time metrics
    if conv.state.booking_completed:
        conv.write_metric("OUTCOME_BOOKING_COMPLETED")

    # Post-call extraction
    results = conv.functions.post_call_extraction()
    # results = {"CALL_REASON": "appointment scheduling", "RESOLUTION": "yes", ...}

    for key, value in results.items():
        conv.write_metric(key, value)
Writing each extracted field back with conv.write_metric is what makes the extracted values available in dashboards, Smart Analyst, and API exports alongside your real-time metrics.
The extraction runs automatically after every call. You can add or change queries any time by editing the dictionary – no extra configuration beyond shipping your update.

Example queries

QueryWhat it extracts
CALL_SUMMARYOne-line summary, e.g. “Patient called to reschedule a cleaning, booked for June 18th”
CALL_REASONCategorized reason for the call
RESOLUTIONyes / no / partial
SENTIMENTpositive / neutral / frustrated
FOLLOW_UP_NEEDEDFree-text note, e.g. “Patient asked about a referral to an oral surgeon – needs callback”
NO_SHOW_RISKFree-text note, e.g. “Patient mentioned they might not make it depending on work schedule”
ESCALATION_COUNTNumber of times the caller asked for a human
You write the extraction instructions in plain English. The LLM does the rest.

When to use each layer

Use real-time metrics when the outcome is known at a specific point in the call – a function succeeded, a booking was confirmed, a handoff happened. Use post-call extraction when the answer depends on the full transcript – sentiment, summaries, categorized reasons, or counts that span the whole conversation. For each extraction query you plan to expose in dashboards, register a matching metric and write the result back with conv.write_metric. This keeps real-time and post-call data in a single, queryable column per conversation.
end_function runs asynchronously and its errors do not surface to the caller. Wrap your extraction logic in try/except and log failures externally so silent regressions don’t corrupt downstream reporting. See End tool for details.

Where the data goes

Both real-time metrics and post-call extractions land in the same surfaces:
SurfaceWhat it does
DashboardsVisual analytics in Agent Studio – call volumes, outcomes, trends
Smart AnalystBuilt-in AI analyst. Ask “What are the top reasons callers request a human this week?” and get answers linked to actual conversations
Conversations APIProgrammatic export of transcripts and structured data to your BI tools, data warehouse, or CRM
Once metrics are written, your team can query Smart Analyst directly with questions like:
  • “How many callers mentioned insurance concerns this month?”
  • “What percentage of calls resulted in a booked appointment?”
  • “Show me all calls where follow-up was flagged.”
No separate analytics integration is needed – it’s all native to the platform.

End-to-end flow

Your agent handles a call → real-time metrics fire during the call → the call ends → post-call extraction runs automatically → all data lands in dashboards, Smart Analyst, and the Conversations API.

Metrics

Define the custom metrics that hold your reporting data.

End tool

Run post-call processing asynchronously after every conversation.

prompt_llm

Standalone LLM call used by the extraction pattern.

Smart Analyst

Natural-language queries over your metrics and transcripts.

Conversations API

Export metrics and transcripts to external systems.

Dashboards

Visualize metric trends and outcomes.
Last modified on June 10, 2026