I spent 10 years building enterprise search for clients. Then I open-sourced all of it.
DEV Community

I spent 10 years building enterprise search for clients. Then I open-sourced all of it.

Every enterprise search project I did in the last decade ended the same way. A search engine (Solr or Elasticsearch), a pile of glue code for facets and relevance, then, in recent years, a RAG pipeline bolted on the side, and finally an agent framework on top of that. Three stacks, three sets of bugs, one recurring client requirement: the data cannot leave our network.

After repeating that build enough times, I turned it into a single platform. This year I open-sourced the whole thing under Apache 2.0: Viglet Turing ES. This post is about the three design decisions that I think matter most, and how to try it in one command.

Decision 1: run on the engine you already have

Most teams evaluating "AI search" already operate Solr or Elasticsearch. Asking them to migrate to a new engine just to get RAG is a non-starter. So Turing sits on top of the engine instead of replacing it - Solr, Elasticsearch or an embedded Lucene index, behind one query API.

Hybrid retrieval fuses keyword (BM25) and vector results with Reciprocal Rank Fusion, and a pluggable reranker (LLM, cross-encoder or Cohere) reorders the page. If you have nothing installed, the embedded Lucene engine means the whole stack runs in a single container.

The same idea applies to models: OpenAI, Anthropic, Gemini, Azure, or fully local via Ollama. For air-gapped deployments, local models plus local embeddings plus embedded Lucene means literally nothing leaves the machine.

Decision 2: answers you can audit, including "no answer"

The feature enterprises actually ask about is not chat. It's trust. A support portal or an intranet cannot ship confident wrong answers. Turing's RAG chat streams answers with inline citations that trace back to the exact source passage.

  • Before the LLM sees anything, a relevance gate drops weak matches.
  • After generation, an optional groundedness check flags claims the sources don't support.
  • When nothing in the index clears the bar, the assistant gives a deterministic "not covered here" answer instead of improvising.

That last behavior sounds small. In practice it's the difference between a demo and something a regulated organization will put in front of users.

Decision 3: agents grounded in the same index

Once search and RAG share an index, agents get interesting: they can act on content instead of just answering. Turing's agents do tool calling, run skills in a Docker sandbox, and connect to MCP servers, so the same assistant that cites your docs can also call your internal APIs.

Try it

One command, no account, no telemetry:

docker run -p 2700:2700 ghcr.io/openviglet/turing-ce

The console comes up at http://localhost:2700/console (set the admin password with the TURING_ADMIN_PASSWORD env var on first run).

Searching is a plain REST call:

curl "http://localhost:2700/api/sn/sample-site/search?q=enterprise+search&rows=10&_setlocale=en_US"

And the RAG chat streams over SSE:

curl "http://localhost:2700/api/sn/sample-site/chat?q=What+is+enterprise+search"

There are TypeScript SDKs (a zero-dependency vanilla one and a React one) if you're embedding search in a frontend. The live demo on the site runs on that same SDK, over Turing's own documentation, so you can see the cited answers before installing anything: turing.viglet.org/#playground

One honest note about the repo

The public repository is a clean snapshot per release, because day-to-day development happens against client work I can't publish. I know a thin commit history looks odd at first glance, so I'd rather say it here than have you wonder. Issues and PRs are very real and ship in the next release.

What I'd love feedback on

If you self-host Elasticsearch or run local LLMs and have opinions about hybrid ranking, citation UX, or what a search platform should refuse to answer, I want to hear them.

Thanks for reading!

Comments

No comments yet. Start the discussion.