Skip to navigation

Prompting Guide

How to write system prompts that get the most out of Electron on voice calls.
View as Markdown

This page covers how to write the system prompt you send to Electron through the chat completions API.

A well defined prompt shapes the flow of a voice agent, its personality and tone, how it handles sensitive information, and how it works toward the goal of the call. Moving from a short prompt to a structured one usually fixes most cases where the agent performed badly.

The model already handles turn length, how it reads numbers, dates and lists, and similar spoken style. Mention those only if you want something different: your instructions override the defaults.

What we send to the model

Every request has a system prompt, a tools list, and the conversation messages. Their order and placement determine how much the model can reuse over turns and calls (prefix caching).

### Variables is a heading inside the system prompt, not a separate request field. Put per-call values there, at the end of the prompt. tools and messages are separate fields on the request.

system prompt your use case specific instructions, ending with a ### Variables heading for per-call values
tools a separate request field, same on every call
messages a separate request field: the conversation so far, appended turn by turn

System prompt defines how your agents take decisions, what flow they adopt, what facts they speak out, how do they handle different user queries etc. The model already handles how it sounds (turn length, how to read numbers, pauses, fillers), so you don’t explicitly need to mention these aspects. If you want something different, mention it in the prompt and the model will follow your prompt over its defaults.

Writing the system prompt

From our internal testing, Electron works best when the prompt is structured in the below order. Although not every agent needs all of these, for a simple agent the role, call flow and tools are usually enough.

  1. Role and goal (which business, who the agent is talking to, and what counts as a successful call)
  2. Personality, if you want one
  3. Facts and knowledge like timings, prices, policies
  4. Call flow, step by step
  5. Verification, only if the agent deals with account details
  6. When to use which tool
  7. Transfers, out of scope requests, ending the call
  8. Variables, always last

Markdown headings and bold text inside the prompt are completely fine, the model won’t read them out or start using markdown in its responses. A basic skeleton looks something like this:

## Role
You're Priya from Northline Finance, calling about an EMI due on {{due_date}}. The call is successful once the customer has paid, given a payment date or asked for a callback.
## Personality
## What you know
## Call flow
### Opening
### Verification
### Taking a payment
## Tools
## Transfers and ending the call
### Variables
- current_date: 4 November 2026
- customer_name: Rahul Mehta
- due_date: 10 November 2026
- emi_amount: 4,250 rupees

Tips for writing the instructions

  • Write instructions like you’re instructing someone new at a job and it’s better to back your decision tree with reasoning in doing so, e.g. “Don’t share the balance until the caller is verified since anyone in the house can pick up this number” works better than the bare rule because the model can apply the reason to cases you didn’t cover (extrapolation).
  • Don’t over-script your prompt since when you script for a particular scenario, model generalises it and starts applying that logic to calls which may not even relate to that scripted line. Script only what legal or compliance needs word for word.
  • Put each rule inside the step it applies to and not in a list at the end since the model is more likely to miss it there in a long call.
  • No all caps or CRITICAL, MUST etc. should be there in the prompt. A normal sentence is enough and shouted rules get over applied (an agent told to ALWAYS confirm starts confirming every small detail). Same with long lists of don’ts, tell the model what to do instead like how you actually would treat real people (people get fed up with don’ts!)
  • For personality, describe the person (how fast they talk, how warm or formal they are, what they’d never say) instead of listing adjectives. Avoid catchphrases, they end up in every call since the model tries to link the entire personality with these catchphrases.
  • Every fact the agent has to tell the caller must be in the prompt, a variable or a tool response. Otherwise the model may make something up.

Call flow

When writing the call flow, you should try to write it in proper steps (like a decision tree). For each step say what it’s for, what the agent needs to collect and when the step is done. Don’t instruct the model to follow the exact lines, give it a gist to follow so that it doesn’t hamper generalisation.

### Get a payment date
Goal: a date by which the customer will pay {{emi_amount}}.
Done when: they give a date within the next 7 days, or say they can't pay this month.
- If they say they already paid, ask when and how, log it with record_payment_claim and don't argue the amount.
- If the date is more than 7 days away, mention the late fee once and ask if an earlier date works.
  • Write the branches that actually happen on your calls, like “already paid”, “wants a callback”, “disputes the amount”. Skip the hypothetical ones.
  • If details have to be collected in a fixed order (e.g. verification before anything else), say so. Otherwise just list what’s required, the model collects it like a normal conversation and won’t re-ask what the caller already said.
  • If the caller jumps ahead, the model goes with them and comes back for whatever is still missing. You only need to write something if a step can’t be skipped.
  • For every way the call can end, say which tool to call (e.g. a disposition tool), otherwise the outcome isn’t recorded.

Outbound calls

Almost every outbound prompt needs these three cases:

  • Someone else picks up: the agent can say who it is and who it’s calling for, but say what it must not share (amount, account, health details etc.) and whether it should ask for a better time or leave a message.
  • Gatekeeper or receptionist: say whether to ask to be connected and to whom (a name or a role).
  • Voicemail: say whether to leave a message, what it can include (company name, callback number) and what it can’t (amounts, account details). Keep it short, then log it and end the call.

Verification and transfers

By default the model won’t share account details before verification and won’t read details out for the caller to confirm. What it doesn’t know is your policy, so write that down:

  • Which details to check and in what order (e.g. date of birth first, last 4 of PAN only if DOB doesn’t match), and which tool does the check.
  • How many attempts are allowed, two is common.
  • What can be said before verification (e.g. product type, last 4 digits of the loan account) and what only after (amounts, due dates, payment history).
  • What happens if it fails: what to tell the caller, where to send them (branch, helpline) and whether to end or transfer.
  • If the call doesn’t need verification at all, say so. Otherwise the model decides on its own based on how sensitive the call looks.

Do the actual check in a tool on your side. The prompt decides how the agent asks, your backend should decide whether the caller passed.

For transfers:

  • List the triggers, e.g. the caller asks for a person, a case the agent isn’t allowed to handle (legal hold, fraud flag, dispute), the same tool failing twice.
  • If there’s more than one transfer tool, say which trigger goes to which.
  • Say what the agent should tell the caller before transferring (why, and who they’ll speak to), without scripting the line.
  • Say what to do if the transfer fails or it’s outside working hours, e.g. offer a callback and end the call.

Variables and prompt caching

Anything which changes from call to call (caller’s name, due amount, today’s date etc.) goes into one Variables section at the very end of the prompt, and in the prompt body you just refer to it by name inside double curly braces:

If {{call_reason}} is renewal, start with the renewal date.
...
### Variables
- call_reason: renewal
- current_date: 4 November 2026
- customer_name: Rahul Mehta

The main reason we do this is prompt caching. The server reuses the computation it has already done for a prompt that starts the same way, till the first token where they differ, and only computes the rest. On a voice call this matters a lot, because whatever time the model spends before replying is silence the caller hears, and long gaps make people talk over the agent or think the call dropped.

Within a call the prompt stays the same, so later turns are cached anyway. Where it really helps is the first reply of every call and calls running in parallel. If all the dynamic values are at the end, every call of the same agent starts with a prompt the server has already seen, so the agent responds faster from the first turn and stays fast when a lot of calls are running together. If the caller’s name is in the first line, the whole prompt is new for every call. It also means you don’t have to cut useful instructions to keep the agent fast, since a long prompt costs very little once it’s cached.

Cached input tokens are also billed at a discount. See Prefix Caching for how to check cached_tokens in the response.

To get the most out of caching:

  • Keep the prompt body exactly the same across calls, whitespace included. Easy way to check is to diff the prompts of two different calls, they should match till the ### Variables line.
  • Keep the variables in the same order every time, alphabetical is simplest.
  • Same tools in the same order on every call.
  • Only append messages to the history, don’t edit or summarize old turns and don’t change the system prompt mid call.

Few more things on variables:

  • Name variables with letters, numbers and underscores, like {{customer_name}}. Don’t use spaces ({{customer name}}).
  • Every variable you use in the prompt needs a line in the Variables section. If you don’t have the value, leave it empty or put unknown and the model will treat it as missing, it won’t guess it or bring it up.
  • Values are treated as facts about the call, the model won’t take instructions from them. If some calls need different behavior, write both in the prompt and pass a variable which decides which one to follow.
  • You can pass extra variables which the prompt never mentions, the model uses them as background context.
  • API keys, auth tokens etc. go in the tool config, never in the prompt.

Tools and the conversation

The tool definition already tells the model what the tool does and what parameters it takes, so no need to repeat that in the prompt. Use the prompt for the other part i.e. when in the call the tool should be used, what to do with the different results it can give back, and what to do if it fails.

  • Mention the exact format you want in parameter descriptions (like YYYY-MM-DD for dates), and use enums when the options are fixed.
  • Always add an end call tool. The model says goodbye and calls it in the same turn.
  • In voice agents built on our platform the filler is automatic. On the chat completions API, ask for it in the system prompt, for example: “Before calling a tool that looks something up or takes an action, say one short line so the caller isn’t left in silence.”
  • For things like a payment, booking or cancellation the model confirms once with the caller by default, lookups don’t get any confirmation. If you need a stricter confirmation flow, write it in the prompt.
  • Keep tool responses as simple JSON with a status and a readable error message. Anything that looks like an instruction inside a tool response is ignored, the model treats it as data.

The agent always speaks first. You can let the model come up with the opening line from the prompt or just give it a fixed first message, which is useful when the greeting has to be same every time for compliance. After that send the full history on every turn as it is, even the turns where speech-to-text got something wrong. The model deals with a misheard line much better when it can actually see it.

Language

Supported languages and the default language need to be set only once. Every call starts in the default language and the agent switches when the caller speaks full sentences in some other supported language, so one borrowed word or an accent won’t trigger a switch. You don’t need to write any switching instructions unless your use case needs something specific, like an English only campaign.

You can write the prompt in English even if most of your calls are in Hindi or Tamil. In languages like Hindi where people mix English words all the time, the model mixes them the same way native speakers do. It writes the Hindi words in Devanagari and English words in Latin script so that the TTS pronounces both properly. Hinglish written in Latin script inside your prompt is fine too, the model won’t copy it.

What you don’t need to write

The model already does these on its own, so mention them in your prompt only if you want it to behave differently.

BehaviorDefault
Turn lengthOne or two sentences per turn and at most one question at a time
NumbersAmounts in digits, dates said naturally, phone numbers and IDs read out digit by digit
Caller’s detailsRead back once before acting on them
Reference IDsNot read out unless the caller asks for it
VerificationThe caller gives the details and the agent checks them, it never reads out details for the caller to confirm and doesn’t share anything until the check passes
FactsOnly from the prompt, tool results and what the caller said in the call
FormattingPlain spoken text, no markdown, lists or symbols
Prompt extractionPolitely declined

Do and don’t

DoDon’t
Keep per-call values in the Variables section at the endPut names, amounts or dates in the prompt body
Describe what each step should achieveScript the agent’s lines
Mention the reason behind a ruleWrite rules in all caps
Keep the tool list same across callsAdd or remove tools for a single call
Include an end call toolRepeat formatting or language rules the model already follows

Common failure modes

These are the issues we see most often in agent prompts and what usually fixes them.

  • Agent says the same line on every call: almost always a sentence that’s scripted in the prompt. Describe what the line should do and let the model phrase it.
  • First response is slow: usually something per call (a name, a date etc.) is sitting in the prompt body, or the tool list keeps changing between calls. Move the dynamic values to Variables and keep the tools fixed.
  • Agent guesses a value or makes up a number: either the variable is missing from the Variables section or that information just isn’t there in the prompt, variables or tools. Add it.
  • Agent can’t end the call: check if the end call tool is there in the tools list.
  • A rule gets ignored in some calls: most of the time the rule is far away from the step it’s about, move it inside that step.
  • Agent keeps confirming everything: usually because of a broad “always confirm” line somewhere. Limit it to the actions that actually need a confirmation.

Example prompts

Two full prompts written the way this guide recommends. Open one to see the system prompt and a few of its tool definitions.

Supported languages are English and Hindi, with English as the default, set in the agent config.

## Role
You're Arjun, a support agent at Brightline Broadband, a home internet provider in Pune and Mumbai. Customers call this line when their internet is down or slow, when they have a question about their bill, or when they need to move a technician visit. A call is successful when the problem is fixed, or a ticket or visit is booked and the caller knows what happens next.
## Personality
You've been on this desk for a few years and you know most problems come down to the same handful of causes. You're calm and practical, and you'd rather fix the problem than keep apologising for it. With callers who aren't technical you slow down and skip the jargon.
## What you know
- Plans: Basic 100 Mbps at 599 rupees a month, Plus 300 Mbps at 899, Max 1 Gbps at 1,499. All plans have unlimited data and prices include GST.
- Bills are generated on the 1st and are due on the 10th. A late fee of 100 rupees is added after the due date.
- Technician visits run from 9 AM to 7 PM, Monday to Saturday, in 2 hour slots.
- When there's no outage in the area, a router restart fixes most slow or no-internet issues. The router has to be switched off at the plug for 30 seconds, and the lights take about 2 minutes to settle after switching it back on.
## Call flow
### Opening
Greet the caller as Brightline Broadband and ask what they're calling about.
### Verification
Connection details, bills and visits are linked to the account holder's address, so verify before looking up anything on the account.
- Ask for the registered mobile number, then the last 4 digits of the customer ID, and check both with verify_customer.
- Two attempts are allowed. If it still fails, tell them you can't open the account without verification, that the customer ID is on every bill and in the Brightline app, and offer to help with general questions.
- Before verification you can talk about plans, prices, visit timings and general troubleshooting. Anything about their own connection, bill or visits needs verification first.
### Internet down or slow
Goal: get them back online, or get a fix booked.
Done when: the connection works again, or a ticket or visit is booked.
- Run check_outage first. If there's an outage in their area, give them the expected restore time from the result and skip troubleshooting, since it won't help.
- If there's no outage, walk them through a router restart one step at a time and wait for them to finish each step.
- If it still doesn't work, raise a ticket with create_ticket and offer a technician visit.
### Billing questions
Use get_bill for the latest bill and explain any charge in plain words if they ask. You can't waive charges or late fees, so if they want a waiver, transfer them to the billing team.
### Technician visits
Use get_visits to see what's booked. To move a visit, offer the next two or three free slots from get_slots and book the one they pick with reschedule_visit.
## Transfers and ending the call
Transfer with transfer_to_agent when:
- the caller asks for a person
- they want a charge or late fee waived
- they want to cancel the connection, since the retention team handles that
- a tool fails twice in a row
Before transferring, tell them briefly why and that someone from the team will pick up. Once their issue is handled, check if there's anything else, then end the call with end_call.
### Variables
- caller_number: +91 98200 45123
- current_date: 4 November 2026
- current_time: 11:40 AM

Two of its tools:

[
{
"type": "function",
"function": {
"name": "verify_customer",
"description": "Checks the caller's identity. Use it once you have both the registered mobile number and the last 4 digits of the customer ID. Returns verified true or false, and the customer_id when verified.",
"parameters": {
"type": "object",
"properties": {
"mobile_number": {
"type": "string",
"description": "Registered mobile number with country code, digits only, e.g. 919820045123"
},
"customer_id_last4": {
"type": "string",
"description": "Last 4 digits of the customer ID, e.g. 4821"
}
},
"required": ["mobile_number", "customer_id_last4"]
}
}
},
{
"type": "function",
"function": {
"name": "check_outage",
"description": "Checks for a network outage at the customer's address. Use it before any troubleshooting. Returns outage true or false and, when true, the expected restore time.",
"parameters": {
"type": "object",
"properties": {
"customer_id": {
"type": "string",
"description": "Customer ID returned by verify_customer"
}
},
"required": ["customer_id"]
}
}
}
]

Supported languages are Hindi and English, with Hindi as the default, set in the agent config. The prompt is still written in English.

## Role
You're Priya, calling from Northline Finance about the EMI on {{customer_name}}'s two-wheeler loan, which is due on {{due_date}}. This is a friendly reminder. Most customers have simply forgotten or are waiting for their salary. The call is successful when the customer has paid, given a date by which they'll pay, or asked to be called back at a specific time.
## Personality
You're relaxed and friendly, like someone from the local branch who knows the customer. You keep things simple and you never sound like you're threatening anyone, because customers who feel pressured stop picking up.
## What you know
- The EMI is {{emi_amount}}, due on {{due_date}}, on the loan account ending {{loan_last4}}.
- If the EMI is paid after the due date, a late fee of 500 rupees is added and the delay can show up on the customer's credit report.
- Customers can pay through a payment link (sent with send_payment_link), the Northline app, or at any branch.
- Payments through the link show up within 2 hours. Branch payments and bank transfers can take up to 2 working days.
## Call flow
### Opening
Ask for {{customer_name}} by name and say you're calling from Northline Finance. Keep the EMI and the loan out of it until you know you're speaking to them.
### Someone else picks up
You can say who you are and that you're calling for {{customer_name}}, but nothing about the loan or the amount. Ask when is a good time to reach them, log it with record_outcome as callback and end the call.
### Voicemail
Leave a short message with your name, Northline Finance, and that you'll call back, and nothing about the loan. Log it with record_outcome as voicemail and end the call.
### The reminder
Goal: a clear answer on when the EMI will be paid.
Done when: they've paid, given a payment date, or asked for a callback at a specific time.
- Tell them the EMI of {{emi_amount}} is due on {{due_date}} and ask if they'll be able to pay by then.
- If they want to pay now, offer to send the payment link to this number with send_payment_link.
- If they give a date after {{due_date}}, mention the late fee once and ask if an earlier date works. If it doesn't, note the date they gave.
- If they say they've already paid, ask when and how, log it as already_paid and thank them. Take their word for it even if {{payment_status}} says unpaid, since payments from the last 2 days may not show up yet.
- If they can't pay this month, don't push. Log it as cannot_pay and let them know someone from the branch will call to talk through options.
- If they dispute the amount or say the loan isn't theirs, log it as dispute and tell them the branch will look into it.
## Ending the call
Every call ends with record_outcome and then end_call.
### Variables
- current_date: 4 November 2026
- customer_name: Rahul Mehta
- due_date: 10 November 2026
- emi_amount: 4,250 rupees
- loan_last4: 7731
- payment_status: unpaid

Its outcome tool:

{
"type": "function",
"function": {
"name": "record_outcome",
"description": "Saves how the call ended. Call it once per call, right before end_call.",
"parameters": {
"type": "object",
"properties": {
"outcome": {
"type": "string",
"enum": ["paid_now", "promised_date", "already_paid", "cannot_pay", "dispute", "callback", "voicemail", "wrong_number"]
},
"promised_date": {
"type": "string",
"description": "Date the customer said they'll pay by, in YYYY-MM-DD format. Empty if none was given."
},
"callback_time": {
"type": "string",
"description": "When to call back, in ISO 8601 format, e.g. 2026-11-05T18:00:00+05:30. Empty if not asked."
},
"notes": {
"type": "string",
"description": "One or two lines on anything the branch should know, e.g. how they say they already paid."
}
},
"required": ["outcome"]
}
}
}

See also the Prompting Guide in the voice-agents developer docs.