A composites shop in Argentina was paying about USD 2,000/month for prometheo.ai, a hosted AI sales assistant. It worked. It also hallucinated prices on products the SaaS never saw, could not be told to escalate on specific SKUs, and locked every customer conversation inside a vendor the shop did not own.
The ask was simple: replace it with something we control, at a fraction of the cost, without giving up any capability. Here is what shipped.
The core design decision: two models, chosen per turn#
Running every message through Claude Sonnet 5 is comfortable but wasteful. Most turns in a sales conversation are trivial ("hola", "cuánto sale el 3mm", "tenés stock del gris?"). Sonnet's reasoning depth is overkill for those, and its price per million tokens reflects that.
A cheaper model — Claude Haiku 4.5 — handles the trivial turns for a fraction of the cost. The problem was: how do you decide, per turn, which model to route to?
The answer was a small classifier that runs before every LLM call. It scores each incoming message on complexity (multi-turn context needed / catalog query / structured output / just a greeting) and picks the model. In practice, ~70% of turns route to Haiku, ~30% to Sonnet.
Measured against a Sonnet-only baseline over 4 weeks of production traffic:
- 74% average token cost reduction.
- Zero measurable quality drop on the sales-conversion KPI.
- Latency dropped from 1.4s to 0.6s median (Haiku is faster).
Hard guards against price hallucination#
The single biggest risk in a sales AI is a wrong price. A hallucinated price is a lost sale, a refund, or a lawsuit — and every LLM will invent a price if you let it.
The design: the assistant does not have prices in its context window. Ever. Every price question triggers a RAG lookup against the live product catalog (Postgres, updated hourly from the shop's ERP). The assistant is instructed at the system-prompt level to refuse to answer any price question if the catalog lookup returns no result.
If the catalog cannot answer, the assistant says "un vendedor te confirma el precio ahora mismo" and hands off to a human agent, with the conversation state, the SKU asked about, and the customer's profile pre-loaded on the agent's screen.
This is boring. This is also the single most important design decision in a sales AI.
Unified inbox across 5 channels#
The old SaaS handled WhatsApp only. The shop was also getting leads on MercadoLibre, TiendaNube, Facebook Messenger, Instagram DMs, and their own website widget. Every channel was a separate tab, a separate app, a separate identity for the same customer.
The new platform runs one unified inbox:
- WhatsApp Business Cloud API (official — via a BSP, never Baileys or Evolution).
- MercadoLibre v1 API — questions on listings appear as conversations.
- TiendaNube v1 API — same for their online store.
- Facebook Messenger + Instagram via Meta Graph API.
- A web widget on the corporate site.
Every conversation is one thread, tagged by channel, with the customer identity de-duplicated across channels when we have a phone or email match.
RBAC and audit log#
5 roles: owner, admin, agent, viewer, bot. Owner and admin can edit prompts, agents can only handle conversations, viewer is read-only for the sales manager to review AI decisions, bot is the AI itself.
Every message the AI sends, and every prompt change, is written to an audit log. If a bad answer goes out on Tuesday, the operator can go back and see exactly which prompt version produced it.
263-test Playwright E2E sweep#
The AI is the last thing to break. The infrastructure around it (webhook delivery, DB writes, channel integrations) is where most incidents happen. A 263-test Playwright sweep runs before every deploy — it walks a fake customer through each channel, verifies the AI response, checks the DB state, and asserts no regressions.
Zero-downtime deploy with schema-drift guard#
The AI is talking to customers 24/7. Even a 30-second downtime is a lost conversation. The deploy pipeline:
- Runs the new build in a separate container.
- Executes DB migrations in a schema-drift-safe transaction. If any migration would drop a column or change a type in a way the old version still uses, the deploy aborts.
- Switches nginx traffic to the new container.
- Drains the old container over 60 seconds.
Since launch, ~40 deploys, zero downtime, zero broken conversations mid-migration.
What the numbers ended up being#
- USD 2,000/month → USD 180/month in LLM costs (Anthropic API, at ~74% Haiku routing).
- 1.4s → 0.6s median response latency.
- 1 tab → 1 tab, but now it is the shop's own tab and the shop owns the data.
- 0 hallucinated prices reaching a customer since the RAG guard was tightened.
What did not work the first time#
The complexity classifier was originally a rule-based function ("if the message contains a price question, escalate to Sonnet"). It was 40% accurate. Replacing it with a Haiku call (yes, using Haiku to route to Haiku) got it to 91% accuracy at a rounding-error cost. The classifier itself is now the cheapest LLM call in the whole pipeline.
What the client owns#
The Next.js frontend, the NestJS backend, the PostgreSQL database, the deploy scripts, the Playwright test suite, the system prompts, the audit log, and every conversation to date. The Anthropic API key is in the client's own Anthropic account, billed to the client's card.
If Anthropic doubles their pricing tomorrow, we swap in GPT-5 or Gemini as a fallback in a day. That optionality is worth more than the monthly savings.

