B Blengi docs

Build your agent

Fixed answers & CTAs

Curated answers and CTAs are the two kinds of "deterministic" behavior the widget supports — they bypass the LLM in favor of exact text or structured calls-to-action. Use them where you can't tolerate the model paraphrasing or going off-script.

When to use curated answers

Curated answers are for questions where the response has to be exact:

  • Pricing — visitors want numbers, not "around $99/month".
  • Legal / compliance — return policy, GDPR statement, contract terms.
  • Routing — "how do I contact you?" where you want to push a specific URL.
  • Brand-critical FAQs — your highest-stakes 5-10 questions.

Authoring

From Knowledge › Fixed answers (/app/agents/{id}/curated):

  1. Question pattern (question_pattern column) — one or more trigger keywords. Use commas to split a single field into independent OR-tokens (pricing, refund, web design). The matcher splits on commas, lowercases each token, and short-circuits the LLM if ANY token appears as a substring of the visitor's message. Case-insensitive. Add variants (price, pricing, how much) so misspellings still hit.
  2. Answer — the exact text to stream back. Markdown is supported (bold, links, lists). Anchor markdown links inside the answer if you want clickable citations — there is no dedicated citation_url column.
  3. Priority — higher wins when multiple curated entries match the same input.
  4. Slug + KB title + KB published — toggle the row into a public Knowledge Base article. When kb_published = true the answer renders at /kb/{workspace.slug}/{slug} and the bot can recommend it mid-chat via the send_kb_article tool.
  5. Lang — optional ISO code so a single agent can serve curated answers per language.
  6. Enabled — boolean toggle. Lets you author then publish, or pause a curated row without deleting it.
  7. Conditions (conditions JSON) — optional matching constraints (e.g. page_url_prefix, visitor_lang) layered on top of the question pattern.

How matching works

Before the RAG pipeline runs, the message goes through CuratedAnswerMatcher. If any trigger matches, the curated text is returned and we never call retrieval or the LLM. That makes curated answers fast — usually under 100ms end-to-end — and cheap (no inference cost).

The streaming behavior matches the LLM's: tokens stream out one at a time over a small interval so the visitor sees the same typing animation. They have no way to tell a curated answer from a generated one.

CTAs

A CTA is a button the assistant can show under an answer. CTAs are cta_rules rows, not behavior rules. Each has:

FieldPurpose
nameFor your list only.
labelThe button text the visitor sees.
kindThe type: what the button is for and what a click does (open the URL, or the in-chat lead form for contact-shaped types without a URL).
targetThe URL, and optionally signed conversation context (see Signed CTA context).
conditionsWhen it shows: a plain-language rule (when_text), url_contains, intent_keywords matched on the answer, and lang. All optional.

Types, triggers and the full rules are on CTA buttons.

Common CTA patterns

  • Pricing — a Request a quote button whose rule is "the visitor asks about price", or whose answer contains price / cost.
  • Demo — a Book a demo button for "the visitor wants to see the product in action"; without a URL it opens the in-chat lead form.
  • One section of the site — a View a product or Buy / order button only on pages whose address contains /products/.

A CTA only ever shows under an answer. To open the chat by itself — when a visitor is about to leave, or has scrolled far — use a trigger instead (Behavior rules & triggers).

Editing

Behaviour › Buttons in the chat (/app/agents/{id}/ctas) is the management page. The form is a structured builder — you don't need to write JSON. Save creates or updates a CTA rule; Edit loads one back into the form and Delete removes it. The page has no on/off switch for a CTA (the enabled column exists, but only the API sets it).

A suggested answer does nothing until you approve it. Answers proposed by the self-improvement loop arrive as suggestions and are excluded from matching until you press Approve — visitors keep getting generated replies for those questions in the meantime. The curated page shows a banner while any suggestion is waiting, and when a live turn misses only because the matching answer is still unapproved, that turn's trace names the pending pattern (pending_curated_match in the conversation debugger).

A language tag on an answer prefers it for conversations in that language — it never excludes. The conversation's language comes from the visitor's browser locale, which regularly disagrees with the language they actually type (a Dutch visitor on an English-configured browser), so keywords do the real selecting and the language tag only breaks ties when the same keyword is pinned in several languages.

Testing CTAs and curated answers

The live preview on the Appearance and Personality tabs — and the same widget floating on every other page of the agent — is your sandbox. It is the real widget, but its conversation carries is_playground=true, so it doesn't count against your monthly quota and stays out of the analytics report.

Type a trigger phrase and confirm the curated answer fires. Type something close-but-not-quite and confirm it doesn't (otherwise your triggers are too loose).