AI architecture
From Natural Language to Deterministic Systems
How to build enterprise chat assistants that accept natural language while preserving reliable workflows, controlled actions, and predictable outcomes.
The engineering problem begins at the language boundary
Natural language gives people a flexible way to interact with software, while software still needs predictable inputs, valid state transitions, and controlled outcomes. Users may omit details, combine intentions, correct themselves, or express the same request in many forms.
A single message can also carry several responsibilities at once, such as providing contact information while asking a knowledge question. The design challenge is to preserve the richness of human language while preventing its uncertainty from spreading into the operational system.
This architecture builds on the broader idea of institutional listening : the LLM interprets expression, while state, rules, review, and action remain governed by process.
Designing a deterministic enterprise AI chat assistant
The website assistant handles two independent responsibilities: collecting lead information and answering questions from an approved knowledge catalog. A user can trigger either responsibility, or both, in the same message. The assistant preserves the complete message and lets each responsibility evaluate it independently.
The actor boundary
The chat UI sends each user message to the Chat actor inside a common event envelope—a standard message structure shared by all actors. The Chat actor then broadcasts that envelope to the Lead Collection Actor, the Question Answering (QA) Actor, and any future actors.
An actor is an independent process that owns one responsibility, its state, rules, and actions. Each actor decides whether the message is relevant within its own responsibility. A message such as "I'm Raj from Acme. Can you tell me about your EBS archive work?" can advance lead collection and question answering without losing either meaning.
Interpreting language without surrendering control
Inside each actor, the same processing pipeline is repeated. Each actor runs as an independent process with its own private state and workflow. In this implementation, Elixir GenServers provide the process runtime, while Harel state machines define the workflow states and transitions.
Its local LLM interprets language only within that responsibility. The actor validates the proposed event before it reaches the state machine, keeping invalid, malformed, or unsupported events within a defined skip, error, retry, or recovery path.
The pipeline is straightforward: natural language to local LLM parser to actor validation to candidate event to actor-specific Harel state machine to controlled action. The GenServer owns the process and state, the LLM interprets language, and the state machine controls behavior.
Same pattern, different business rules
The lead actor and Question Answering (QA) actor follow the same architecture while applying different business rules. The lead actor accepts information over several messages and in any order, while database writes and email delivery occur only after the required fields are complete and validated.
The Question Answering (QA) actor performs deterministic catalog search, uses an LLM to compare close matches or express approved answers, and skips questions that lack sufficient evidence. Both actors receive the same event envelope, yet each defines valid progress according to its own workflow.
Parallel execution and composed response
The actors execute in parallel and return a common response envelope to the response composer. The composer presents completed work immediately, identifies actors that are still processing, and updates their sections as late results arrive.
Its role resembles rendering a dashboard: each actor owns its feedback area, and the composer displays its current result. Parallel execution avoids sequential latency, while progressive feedback prevents slower work from blocking the entire conversation.
What the architecture enables
| Outcome | Design concept | Architectural elements |
|---|---|---|
| Predictable execution | Deterministic workflow control | Actor-specific Harel state machines, guarded transitions, validation rules, controlled side effects |
| Readable business workflows | Explicit workflow modeling | Named states, transitions, guards, hierarchy, parallel regions, and visible actions |
| Faster extension | Bounded responsibility | Independent actors, common event envelopes, common response envelopes |
| Graceful degradation | Failure isolation | Independent GenServer processes, local error states, timeouts, recovery paths, and supervision |
| Progressive user feedback | Non-blocking composition | Parallel broadcast, processing statuses, response composer, and late-result updates |
| Focused testing | Separation of interpretation and execution | Mocked LLM outputs, candidate-event validation, and deterministic state-machine tests |
These outcomes depend on disciplined boundaries. Actors need focused responsibilities, candidate events require validation, the composer should remain a presentation layer, and concurrent processes need logging, monitoring, supervision, and resource controls. The architecture contains uncertainty by giving every form of behavior an explicit owner.
Reliable software turns unknown input into controlled behavior
Natural language expands the range of inputs software can accept, while reliable execution still depends on explicit rules, valid state transitions, and controlled consequences. The same principle applies beyond website chat to approvals, service requests, registration, quoting, support intake, and other workflows where people describe what they need in their own words while the business still requires predictable behavior.
If you are designing business software that needs the flexibility of natural-language interaction without sacrificing deterministic control, let's connect. I would be happy to discuss how this architecture could fit your existing systems and workflows.
The goal is not to make software think like people. The goal is to let people communicate naturally while software continues to behave predictably.