The Gap Between Demo and Production Is MASSIVE 😰
Building an AI demo takes an afternoon. Shipping it to production takes weeks. Not because the AI part is hard — because everything around it is hard.
After shipping multiple AI features to production, here are the lessons that cost me the most time.
📋 Lesson 1: LLMs Are Non-Deterministic (And That's a Problem)
Same input, different output. Every. Single. Time.
[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop
The Fix
- **Pin the temperature to 0** for deterministic tasks
- **Don't test exact output** — test for properties (contains certain info, valid JSON, etc.)
- **Use semantic checks** — "does this answer contain the user's name?" not "does this equal X?"
- **Add retry logic** — if the first response doesn't validate, try again (up to 3 times)
📋 Lesson 2: Latency Will Surprise You
| Operation | Expected | Actual |
|-----------|----------|--------|
| Sonnet response (simple) | 500ms | 1-3 seconds |
| Opus response (complex) | 1 second | 5-15 seconds |
| Opus with extended thinking | 2 seconds | 10-60 seconds |
| Tool use (multi-step) | 3 seconds | 15-45 seconds |
The Fix
- **Stream responses** — users see tokens appearing instantly
- **Use the smallest model that works** — Haiku for simple tasks, Sonnet for medium, Opus for complex
- **Cache common queries** — if 100 users ask the same thing, don't call the API 100 times
- **Show progress indicators** — "AI is thinking..." with a spinner
📋 Lesson 3: Rate Limits Are Real
You WILL hit rate limits at scale. I did. At 2 AM. On a Saturday.
[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop
The Fix
[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop
Also: queue your requests, implement circuit breakers, and have a fallback (cached response, degraded experience, etc.).
📋 Lesson 4: Cost Estimation Is Guesswork (Until It Isn't)
My estimate: "$50/month for 10K users." Actual: "$340/month." 😬
| What I Missed | Cost Impact |
|---------------|------------|
| Users send longer messages than expected | 2x more input tokens |
| AI responses are verbose | 3x more output tokens |
| Retry logic on failures | 1.5x more API calls |
| System prompts on every request | +500 tokens/request |
| Context grows with conversation | Exponential token growth |
The Fix
- **Log every request's token count** — know your actual usage
- **Set hard limits** — max conversation length, max response tokens
- **Use prompt caching** — Anthropic supports this, saves 90% on repeated system prompts
- **Implement usage quotas** — per-user limits to prevent runaway costs
📋 Lesson 5: Hallucination in Production = Support Tickets
In a demo, hallucination is funny. In production, it's a support ticket.
User: "What's my order status?"
AI: "Your order #12345 has been shipped and will arrive Tuesday!"
Reality: No such order exists. 💀
The Fix
- **Ground responses in data** — RAG, database lookups, API calls
- **Add citations** — "Based on your order #12345 (source: orders API)..."
- **Validate claims** — if AI says a number, check it
- **Add disclaimers** — "AI-generated response. Please verify."
- **Monitor for hallucination** — log responses, sample and review
📋 Lesson 6: Prompt Versioning Is Essential
Your prompt is code. Treat it like code.
[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop
Or better: store prompts in a database with version history, A/B test between versions.
📋 Lesson 7: Users Will Break Your AI (On Purpose)
If users can type anything into your AI feature, they WILL try to break it. See my blog post on prompt injection for the full story.
The Minimum Viable Defense
- Input sanitization
- Output validation
- Rate limiting per user
- Logging suspicious inputs
- Kill switch to disable AI feature if things go wrong
🎬 The Production Checklist
Before shipping any AI feature:
- [ ] Streaming enabled for user-facing responses
- [ ] Rate limit handling with exponential backoff
- [ ] Token usage logging and cost monitoring
- [ ] Response validation (format, content, safety)
- [ ] Fallback for when AI is down or slow
- [ ] Input sanitization for prompt injection
- [ ] Conversation length limits
- [ ] User-level usage quotas
- [ ] Prompt versioning system
- [ ] Monitoring dashboard for quality and cost
AI in production is 20% model quality and 80% engineering around it. Get the engineering right. 🔥