DEV Community

Cover image for I Built a Local RAG Assistant with Ollama, ChromaDB and LangChain. Here's What I Learned

I Built a Local RAG Assistant with Ollama, ChromaDB and LangChain. Here's What I Learned

TAGBA G-Josaphat E. on July 25, 2026

During my internship at a software services company, I noticed a recurring problem: technicians spent hours searching through hundreds of pages of ...
Collapse
 
ahmetozel profile image
Ahmet Özel •

The 9,669 reported chunks versus zero vectors in ChromaDB is exactly why ingestion needs a post-write invariant. Counting the collection after each batch, then running a small sentinel retrieval, catches a silently local client before users discover an empty index. Explicit HttpClient fixes the cause here, but verifying what was actually persisted is just as important as a successful ingestion log.

Collapse
 
josaphatstar profile image
TAGBA G-Josaphat E. • • Edited

You're absolutely right, and this is the exact bug I hit; ingestion.py reported "9669 vectors stored" with zero errors, but ChromaDB had 0 vectors because the old client settings
syntax was writing locally instead of to the server.

The successful log was lying.

Your point about is well taken.

Collapse
 
ahmetozel profile image
Ahmet Özel •

That kind of split-brain persistence is especially dangerous because every local signal says the run succeeded. I would include the resolved backend, tenant, and collection identity in the ingestion receipt, then verify with a separate client that both the count increased and a known sentinel can be retrieved. That makes the success condition match the query path instead of merely proving the SDK raised no exception.

Thread Thread
 
josaphatstar profile image
TAGBA G-Josaphat E. • • Edited

Your point about the ingestion receipt is something I hadn't considered; documenting the resolved backend identity alongside the count makes the receipt actually auditable instead of just a count that could have come from anywhere.

Thread Thread
 
ahmetozel profile image
Ahmet Özel •

Exactly. I would make that receipt carry a run ID, collection or index name, resolved backend host or tenant, expected-versus-committed count, and a hash of the source plus ingestion configuration. I would also add a small read-after-write verification from the target store, because a receipt that only repeats what the writer reports can still certify the wrong destination.

Thread Thread
 
josaphatstar profile image
TAGBA G-Josaphat E. •

The run ID and config hash are exactly what the receipt was missing. Without them you can't distinguish the verified run from a leftover count that happened to match. I'll add expected-versus-committed, so the receipt certifies the destination rather than just echoing the writer. Thanks for pushing it further.