Back to blogs

AI Engineering, RAG, Agents, System Design

What Building an AI System Taught Me About Reliability

Most AI engineering content online focuses on models.

Which model should you use? How many agents should you have? Should you use Graph RAG? What framework is the newest?

After building a production-style AI system from scratch, I learned that none of those were the hardest problems.

The hardest problem was reliability.

The first mistake: making the AI too smart

My initial architecture looked like what many AI tutorials recommend.

Give an LLM access to a database schema. Let it generate SQL. Retrieve documents with RAG. Combine everything into a final answer.

On paper, it looked elegant. In practice, it introduced a problem that took me a while to appreciate: the more intelligence you add, the less predictable your system becomes.

If an LLM generates SQL dynamically, the same question can produce different queries on different runs. Sometimes the results are identical. Sometimes they are not.

That realization changed the direction of the entire project. Instead of asking, "How can I make the AI smarter?" I started asking, "How can I make the system more reliable?"

Determinism beats intelligence more often than people think

One of the biggest lessons from the project was understanding where AI should be used and where it should not.

Structured data already has exact answers. If a user asks for occupancy, lease expirations, highest balances, or a specific unit detail, the LLM does not need to reason. It needs to retrieve the correct data.

So I built deterministic query paths for common requests and used AI only as a governed fallback mechanism.

The result was surprisingly powerful. Responses became faster, easier to debug, easier to test, and more trustworthy.

The AI stopped being the system. It became one component inside the system.

Why I stopped chasing one database

Another lesson came from storage design. Early on, I considered putting everything into a single database.

That sounds simple until you realize structured and unstructured data have completely different access patterns.

Numbers want exact queries. Documents want semantic search.

Trying to force both into the same model creates complexity without providing much value. Splitting responsibilities turned out to be cleaner.

One system handled structured records. Another handled semantic retrieval. The architecture became easier to reason about and easier to evolve.

The most valuable skill was debugging

This project taught me that AI engineering is often just software engineering wearing a different shirt.

Some of the hardest problems had nothing to do with machine learning: duplicate ingestion pipelines, state management bugs, routing failures, model provider outages, broken API quotas, and data consistency issues.

None of these were solved by a larger model. They were solved through engineering discipline: observability, testing, guardrails, and failure handling.

Latency is psychological

One insight I found fascinating was that users care less about total response time than they do about the first sign of progress.

A system that responds immediately and streams information feels faster than a system that stays silent and then responds all at once.

That led me to think more deeply about Time To First Token instead of only optimizing total runtime. The experience can feel faster even when the full processing time remains similar.

Open-source models changed my perspective

At the beginning, I relied heavily on cloud APIs. Eventually quota limits, model changes, and availability issues pushed me to explore local alternatives.

What surprised me was how practical local AI infrastructure has become. Running components locally eliminated entire classes of operational problems: quotas, rate limits, vendor lock-in, and unexpected API changes.

I left the project with much more confidence in self-hosted AI infrastructure than when I started.

What I would do differently

If I rebuilt the system today, I would focus on better chunking strategies, hybrid retrieval, memory-aware conversations, automated ingestion agents, and stronger evaluation pipelines.

Not because the current system does not work, but because building the first version taught me where complexity is actually worth adding.

Further reading

This post focuses on the lessons and engineering decisions that stood out to me while building the system.

I also wrote a much more detailed engineering design document covering architecture, trade-offs, database design, orchestration decisions, retrieval strategies, latency optimizations, failure cases, and implementation details for readers interested in the deeper technical aspects.

Final thought

The biggest takeaway from this project is simple: building AI systems is not about maximizing intelligence. It is about deciding where intelligence belongs.

The best systems are not the ones with the most agents, the most prompts, or the most complex architecture.

They are the systems that remain understandable, testable, and reliable when something inevitably goes wrong.

That is the lesson I wish I had learned before I started.


Disclaimer: The ideas, architecture decisions, implementation details, and final draft were written by me. AI was used only for grammar, readability improvements, and minor editorial polishing.