WhatsApp bot prompt engineering: grounding, refusal and tone
A prompt for a messaging channel has constraints a chat assistant does not: message length, a permanent thread, and answers that become commitments.
On this page
- What we'll cover
- What makes this channel different
- Grounding, which is the main control
- Refusal that does not feel like a wall
- Building it with CodeWords
- Length and format instructions
- Tone, and sounding like the business
- What must never be generated
- Testing a prompt properly
- People will try to manipulate it
- Making it survive
- Limits worth knowing about
- What to build first
- Frequently asked questions
- Related reading
A prompt written for a general assistant produces a bot that is polite, thorough, and wrong for this channel. It writes paragraphs where a sentence is expected, answers questions it should not, and states things about your business that it inferred rather than retrieved.
On a channel where every message is a statement from your business, sitting permanently in a customer's phone, the instructions that matter most are the ones about what not to say.
What we'll cover
- What makes this channel different
- Grounding, which is the main control
- Refusal that does not feel like a wall
- Building it with CodeWords
- Length and format instructions
- Tone, and sounding like the business
- What must never be generated
- Testing a prompt properly
- People will try to manipulate it
- Making it survive
- Limits worth knowing about
- What to build first
- Frequently asked questions
What makes this channel different
Every message is a business statement, treated as such by customers and in some contexts by regulators.
It is permanent in the customer's thread, unlike a chat session that closes.
Messages are short, which a general assistant's instincts work against.
The customer is on a phone, frequently doing something else.
Errors are commitments. A stated price, date or policy is one the customer will hold you to.
So the prompt's job is mostly restriction rather than capability.
Grounding, which is the main control
Answer only from supplied context — your documentation, the customer record, the booking system — and say so explicitly.
Retrieve rather than recall. A model asked about your opening hours will produce plausible hours if it is not given real ones.
Pass the specific record, not a general description, for anything about this customer.
Instruct it to say it does not know when the context does not contain the answer, which is the behaviour that prevents the worst failures.
Never let it infer policy. A refund window or a guarantee it constructed is a commitment you did not make.
Cite internally where you can, so a wrong answer can be traced to the source rather than to the model.
Refusal that does not feel like a wall
"I do not know" needs to be followed by something, or it reads as unhelpful.
Offer the person — "let me get somebody who can answer that" — which is the useful form of a refusal.
Do not apologise repeatedly, which is the default register and reads badly at length.
Do not explain the limitation. Customers do not want to know about your context window.
Refuse the same way each time, so it reads as a policy rather than a glitch.
Make the handover actually happen, since a refusal that promises a person and produces nothing is worse than a wrong answer.
Building it with CodeWords
CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.
- Open CodeWords and start a new automation.
- Describe what should happen in plain language to Cody, the automation builder: what the bot may answer, from what sources, and what it must decline.
- Authorize the connection to your WhatsApp Business Platform account and the systems holding the answers.
- Describe the exceptions: a question outside the supplied context, a request for a commitment, anything about money or a complaint.
- Run a set of known questions through it and check every answer against the source.
You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
Length and format instructions
Specify a maximum, in sentences rather than words, because the default is too long.
One idea per message, instructed explicitly.
No markdown, since asterisks and hashes render inconsistently and look like errors.
No bullet lists unless the content genuinely is a list, and then short.
No headings, ever, in a personal thread.
Instruct on the opening, since the first line determines whether the rest is read.
Tone, and sounding like the business
Give it examples rather than adjectives, since "friendly but professional" means nothing operationally.
Use your own real messages as the examples, which encodes the register better than any description.
Match the formality to the market, which varies considerably between regions and sectors.
Instruct about emoji explicitly in either direction, because the default will not match your brand.
Do not simulate personality. A bot with a name and a backstory is a liability when the conversation goes wrong.
Have whoever writes your customer emails review it, since they already own this decision elsewhere.
What must never be generated
Prices, which should be retrieved and never inferred.
Availability or dates, which come from the system.
Policy — refunds, guarantees, terms — which are commitments.
Anything about a person's health or circumstances, however they raised it.
Legal or regulated claims, which apply regardless of who wrote the message.
Apologies that admit liability, which is a specific and expensive failure mode.
Testing a prompt properly
Build a set of known questions with correct answers, which is the only way to change a prompt without guessing.
Include the ones it should refuse, which is the half people omit.
Test the adversarial cases: somebody trying to get a discount, a promise, or a statement about a competitor.
Test in the languages you serve, since behaviour differs and quality varies.
Re-run on every change, including a model version change you did not make.
Version the prompt and record which version produced which answer.
People will try to manipulate it
A bot on a public number receives attempts to make it say something useful to somebody else, and a proportion of them are casual rather than sophisticated.
Discount extraction is the common one — somebody asking the bot to confirm a price or a concession it has no authority to give.
Instruction injection arrives as a message telling the bot to ignore its rules, which works more often than it should against a naive prompt.
Competitor questions invite a comparison you do not want in writing in a customer's thread.
Screenshot bait: getting the bot to say something embarrassing, which then circulates.
Keep authority out of the bot. It cannot give what it was never able to give, which is a stronger defence than any instruction about resisting.
Log and review the attempts, since the patterns repeat and the first one is a warning about the rest.
Making it survive
Pin the model version where the provider allows, and treat an upgrade as a change needing re-evaluation.
Keep prompts in version control, reviewed like code, since they determine behaviour.
Log input and output for every generated message, which is how a complaint gets investigated.
Have a stop switch that routes everything to people, usable without a deployment.
Report the outcome: messages generated, refusals, handovers, and anything flagged by review.
Limits worth knowing about
Plausible wrongness does not go away, and no prompt removes it entirely.
Long context degrades, so a prompt that grows by accretion gets worse.
Model updates change behaviour on a subset of inputs, without warning on your side.
Instruction following is imperfect, particularly for negative instructions.
A prompt cannot fix missing information. If the answer is not in your documentation, the fix is the documentation.
What to build first
The refusal path: the instruction to answer only from supplied context, to say plainly when it cannot, and to offer a person — with the handover actually working. It is the behaviour that prevents the expensive failures, and it is the one most often added after a bot has already told a customer something untrue.
Two habits make the difference. Use your own real customer messages as tone examples rather than adjectives, since "friendly but professional" is not an instruction and an example is. And keep a set of questions the bot should refuse, tested on every change, because everybody tests what it should answer and the damage comes from what it should not.
Frequently asked questions
How is a WhatsApp prompt different from a general assistant prompt?
Every message is a business statement sitting permanently in a customer's phone, messages need to be short, and errors become commitments. The prompt's job is mostly restriction rather than capability.
What is the main control?
Grounding. Answer only from supplied context, retrieve rather than recall, pass the specific customer record rather than a general description, and instruct it to say when the answer is not there.
What should never be generated?
Prices, availability, policy such as refund windows or guarantees, anything about a person's health or circumstances, regulated claims, and apologies that admit liability.
How should a refusal be written?
Followed by something useful — an offer to get a person — phrased the same way every time so it reads as policy rather than a glitch. Do not apologise repeatedly or explain the limitation.
How do I get the tone right?
With examples rather than adjectives, using your own real customer messages. "Friendly but professional" is not an instruction; a message you actually sent is. Instruct about emoji explicitly, since the default will not match your brand.
Should the bot have a name and personality?
A simulated personality is a liability when a conversation goes wrong. Identifying the business clearly is more useful than giving the bot a character.
How do I test a prompt?
A set of known questions with correct answers, including the ones it should refuse, plus adversarial cases — somebody seeking a discount, a promise, or a comment about a competitor. Re-run on every change, including model updates you did not make.
Why does a prompt get worse over time?
Accretion. Instructions added one fix at a time produce a long context that degrades, and negative instructions in particular are followed imperfectly. Prompts need refactoring like any other code.
Will people try to manipulate the bot?
Yes — asking it to confirm a discount, instructing it to ignore its rules, inviting comparisons with competitors, or trying to get a screenshot-worthy answer. The strongest defence is that it has no authority to give what is being sought.
How do I defend against instruction injection?
Structurally rather than by instruction. A bot that cannot issue a discount because nothing downstream will honour one is safe in a way that a bot told to refuse politely is not.