The customer chatbot
A transactional assistant for the bank's customers, built on the platform that already serves its employees.
- Phase
- M2
- Document
- Architecture review
- Prepared by
- UTEEK Digital Agency
Where this sits
M1 is running. M2 is the same engine, pointed outward.
M1 — Agents Assistant delivered
Internal. Employees ask questions and get answers from the bank's own documents, every answer carrying its source. Read-only over the knowledge base. Deployed and running.
M2 — Customer chatbot this deck
External. The bank's customers, on a public channel, asking about products and their own accounts — and eventually asking the bank to do something.
The distance between them is not the conversation. It is who is asking, what they may see, and what the assistant may do. Those three questions are the whole of this architecture.
The shape
One process, three stores, one outbound dependency.
One turn, in order
The audit write is awaited before the answer is returned.
Finding the passage
Two retrievers, fused by rank, gated on the retrievers' own scores.
The first boundary
Two corpora. The customer channel cannot reach the internal one.
Internal procedures, staff instructions and unpublished fee schedules live in
kb_internal. Only published material lives in kb_public.
- Separate collections, not a filter on one. A flag on a shared index is one wrong query away from a disclosure incident; two collections make the wrong answer unreachable rather than unlikely.
- Enforced in the retrieval service, not in the prompt. The channel maps to its collections in code. A caller cannot name a collection, so there is no instruction an attacker can write that changes which corpus is searched.
- Validated at startup. The channel-to-corpus table is checked when the process boots. A typo granting the customer channel the internal corpus stops the deployment — it does not wait to be discovered by a customer.
This is already built and running for M1, which indexes the internal corpus only. M2 adds the second corpus; it does not add the mechanism.
Where injection is stopped
Instructions and retrieved text never share a message.
The second boundary
The model never holds a credential and never decides who may do what.
Doing, not only answering
An action is a form the assistant fills in — not a decision it takes.
1. Propose
The model emits a structured request: which capability, with which values. It is a proposal in a fixed shape, validated like any other untrusted input.
2. Authenticate
The customer's identity comes from their authenticated session, never from the conversation. The model cannot name the account it acts on.
3. Authorise
The platform decides whether this customer may perform this action on this account, in code the bank's reviewers can read.
4. Tier the risk
Low risk executes. Anything higher returns to the customer for explicit confirmation, or steps up authentication, according to the bank's policy.
The mechanism already exists in M1 for internal capabilities — annual leave, a salary certificate — where an administrator defines a capability in the back office and an engineer bounds what it may reach. M2 inherits it; M3 connects it to the core banking system.
Both edges
Filtered going in. Verified coming out.
Input
Topical scope, prompt-injection and jailbreak detection, PII masking, and toxicity in Arabic and English. Per-channel policy: the customer channel is stricter than the employee one, and says so in configuration rather than in code.
Output
Every claim must be attributable to a retrieved source. An answer that cannot be attributed is withheld and replaced, not shown with a caveat.
- Retrieved content is data, never instructions. Instructions live in the system message; retrieved passages live in a delimited block in the user message. The policy fails to load if this is relaxed.
- Refusals are templated, never generated. The bank owns the wording. A generated refusal can be argued with — ask it why it refused and it explains, which tells an attacker what to route around.
- Zero successful injections from the agreed red-team set is a release gate, not a target.
A trade we made deliberately
The output check runs on a stream, so it retracts rather than delays.
Reconstructable
Written before the answer is returned. If the write fails, the request fails.
-
Append-only by database grant, not by discipline.
A separate role holds
INSERTand nothing else. No code path, no administrator screen and no role in the system can modify an audit event. - The grants are verified in CI on every run. A migration that recreated the table without re-applying them would break the guarantee silently, which is exactly the kind of failure an audit trail cannot afford.
- Personal data is masked before it lands. Raw PII never reaches the audit store, the vector index or the application logs. What is recorded is the masked transcript.
- Every turn, every retrieval, every guardrail decision, every action. A conversation six months old can be reconstructed as it happened, including why the assistant refused.
This is the one place in the system where an outage is deliberately not degraded around.
Not by discipline
Three roles. The one that writes the audit trail cannot change it.
Arabic and English
One cross-lingual model, not two monolingual ones.
A customer writes in Libyan dialect; the source document is in formal Arabic, or in English. All three have to meet.
- A single embedding model for both languages. An English question retrieves the Arabic document that answers it, and the reverse. Two monolingual indexes cannot do that at any budget.
- The answer is in the language the customer used. Detected per message, with the interface language as the tiebreaker for anything a single message cannot settle.
- Right-to-left correctness throughout the interface — not a mirrored stylesheet, but layout that is correct in both directions, including numbers, dates and charts.
Acceptance is scripted in both languages, and Arabic accuracy is measured against English rather than merely alongside it.
Honest accounting
What M2 inherits, and what it genuinely adds.
| Capability | Status | What M2 needs |
|---|---|---|
| Retrieval, chunking, embeddings | built | A second collection. No new mechanism. |
| Corpus isolation | built | Enable the customer channel. The table already exists. |
| Guardrails, both edges | built | A stricter per-channel policy, in configuration. |
| Audit trail | built | Nothing. Channel is already an audited dimension. |
| Model abstraction | built | Nothing. Any of the three deployment cases. |
| Capability & action layer | built | Customer-facing capabilities defined in the back office. |
| Customer identity | new | The bank's customer authentication, not employee SSO. |
| Public web / mobile surface | new | A customer-facing client, and the edge in front of it. |
| Public corpus | new | Published material only, curated by the bank. |
| Core banking integration | M3 | The API contract, and the risk policy per action. |
Six of the ten already run in production today. That is the argument for building the customer channel on this platform rather than beside it.
On the host
Apache is the only public listener. Everything else binds to loopback.
Where it runs
The deployment case is a configuration change, and has been proven to be.
Managed API
Fastest to stand up. Queries leave the bank's network — a data-residency decision, not a technical one.
Cloud, self-hosted
The model on the bank's own cloud instance. What the platform runs on today.
On-premise
Nothing leaves the bank. Highest control, and the highest hardware commitment.
Every model call goes through one module speaking one protocol. Changing case touches that configuration and nothing else — demonstrated during development when a second provider was added with no code change at all.
For a public channel the same abstraction carries a harder requirement: the customer channel's traffic profile is not the employees'. Sizing it is a measurement, and the instrumentation to take that measurement is already in place.
What we need from NAB
Four decisions, and none of them are ours to make.
- Customer authentication. Which system proves a customer is who they say they are, and what it returns. Everything in the authorisation path hangs from this answer.
- The published corpus. Which material may a customer see, who curates it, and who approves a change. The platform versions documents and records effective dates; it cannot decide what is public.
- Risk tiering per action. For each capability: what executes, what needs confirmation, what needs stepped-up authentication. This is a bank policy expressed in configuration, not an engineering judgement.
- Deployment case and data residency. Whether customer conversations may be processed outside the bank's network at all.
Each of these blocks a specific piece of work and none of them block the rest. We can begin on the public corpus and the customer surface while the other three are being settled.
In one sentence
The customer channel is the same engine with a different corpus, a stricter policy, and a boundary the model cannot cross.
Everything that makes it safe for employees is what makes it safe for customers — and it is running today.