How to Set Up Drupal AI Search with RAG on Varbase
Drupal AI Search with RAG replaces keyword matching with semantic retrieval, so a visitor can ask a full question and get the passage that answers it. On Varbase 11, the AI foundation ships as a recipe, which means the work left is retrieval configuration rather than plumbing. Every step below was executed on a live build, including the parts that only break in real testing.
Key Takeaways
- The modules are the fast part. Retrieval quality is decided by chunking, prompt design, rendering, and the score threshold.
- Make searching compulsory before grounding. An instruction to answer only from retrieved content lets the model skip the search entirely.
- Map the page URL as contextual content, or the assistant cites source links it invented.
- On Varbase 11, Canvas renders the page, so the chatbot needs a lazy builder to avoid serving one visitor's CSRF token to everyone.
- An assistant that cannot refuse is not grounded, it is fluent. Test it with a question your content does not answer.
To set up Drupal AI Search with RAG on Varbase, apply the Varbase AI Base recipe (varbase_ai_base, shipped with Varbase 11) to install the Drupal AI core and your provider, then enable the AI Search, AI Chatbot, and AI Assistant API submodules. Connect a Milvus vector database (self-hosted in DDEV or Zilliz Cloud) through the Milvus VDB Provider, build a RAG index over your content with a chunking strategy, and attach that index to an AI assistant governed by a retrieval-only prompt. Finish by boosting your normal keyword search page with the same semantic index.
On Varbase 10: the AI foundation is the varbase_ai Default recipe, installed over Composer. Varbase 10 does not use Drupal Canvas, so the chatbot and search blocks can sit in normal block regions.
Why Does Keyword Search Fall Short on a Content-Heavy Drupal Site?
Keyword search falls short because it scores pages on keyword frequency, so a long overview that repeats a term outranks the short, direct answer that uses it once. The AI Search module documentation names the same failure.
Two failure modes consistently appear on a large content site. Vocabulary mismatch: the user says "sign-in," the content says "authentication," and keyword search returns nothing useful. And question-shaped queries: users increasingly type or speak full questions, which keyword indexes were never built to parse.
Semantic retrieval addresses both, because embeddings place near-synonyms close together, and place a question close to its answer even when they share few words.
What Do You Need to Run AI Search on Varbase 11?
AI Search on Varbase 11 needs six pieces: the AI foundation recipe, the search backend, the assistant layer, a vector database provider, the vector database itself, and an API key for embeddings.
| Piece | What it does | Where it comes from |
|---|---|---|
| Varbase AI Base recipe | Drupal AI core, provider wiring (OpenAI, Anthropic, amazee.ai), ECA integration, image alt text, editor assistant, taxonomy tagging | Ships with Varbase 11 (recipes/varbase_ai_base) |
AI Search (ai_search) | DeepChat front end, plus the assistant layer that runs retrieval | Submodule of drupal/ai |
| AI Chatbot + AI Assistant API | DeepChat front end, plus the assistant layer that runs retrieval | Submodule of drupal/ai |
| Milvus VDB Provider | Connects AI Search to Milvus or Zilliz | drupal/ai_vdb_provider_milvus |
| Milvus | The vector database itself | Self-hosted container (shown below) or Zilliz Cloud |
| OpenAI API key | Embeddings and chat model | platform.openai.com |
Should You Self-Host Milvus or Use Zilliz Cloud?
Self-host Milvus if you want local development with no third-party account and full control over where vectors live; use Zilliz Cloud if you would rather not run the database yourself. Both connect to the same Milvus VDB Provider module, so the only practical differences are the endpoint and whether you supply an API key.
| Consideration | Self-hosted Milvus | Zilliz Cloud (managed) |
|---|---|---|
| Setup | Container in your DDEV project, no account needed | Cluster in minutes, endpoint plus API key |
| Ongoing ops | Your team owns patching, scaling, backups | Vendor-managed uptime and scaling |
| Data residency | Nothing leaves your infrastructure | Data sits with the provider |
| Best fit | Local development, data residency and sovereignty needs | Fast start, teams that prefer not to run infrastructure |
Milvus is the most widely used vector database provider in the Drupal community, going by module usage statistics on drupal.org.
In the public-sector and nonprofit work we do, the choice usually gets made on residency rather than convenience. Once content embeddings leave your infrastructure, they fall under whatever jurisdiction the provider sits in, and for a government or health-sector client that is a procurement question before it is a technical one.
Self-hosting keeps that conversation short. The walkthrough below uses a self-hosted container, and notes the Zilliz Cloud equivalent at each point where they differ.
Where Do RAG Builds Actually Succeed or Fail?
Our view: the modules are the fast part. Any competent Drupal team can enable this stack in an afternoon.
What separates an assistant people trust from one they abandon is four decisions downstream of the module list: chunking with contextual embedding, a prompt that makes searching mandatory before it makes grounding mandatory, where the chatbot renders under Drupal Canvas, and the retrieval threshold plus its keyword fallback. Each one is covered below, because each one only shows up as a problem in real testing.
How Do You Set Up AI Search with RAG on Varbase 11?
Set up AI Search with RAG on Varbase 11 in three phases: apply the AI recipe, connect the vector database, then build the RAG index and the assistant. The steps assume a Varbase 11 site with content already in place.
1. Apply the Varbase AI Base Recipe
Varbase 11 ships the recipe in the project, so there is nothing to require. Apply it with your provider and key:
ddev drush recipe /var/www/html/recipes/varbase_ai_base \
--input=drupal_cms_ai.provider=openai \
--input=drupal_cms_ai.openai_api_key=YOUR_OPENAI_KEY -yThis installs the AI core, stores the key in the Key module, sets OpenAI as the default chat provider, and applies the Varbase AI sub-recipes for image alt text, the CKEditor assistant, and taxonomy tagging.
2. Enable the AI Search Stack
ddev composer require 'drupal/ai_vdb_provider_milvus:~1.0'
ddev drush en ai_search ai_chatbot ai_assistant_api ai_vdb_provider_milvus -y3. Run Milvus
Create .ddev/docker-compose.milvus.yaml:
services:
milvus:
container_name: ddev-${DDEV_SITENAME}-milvus
image: milvusdb/milvus:v2.4.15
command: ["milvus", "run", "standalone"]
security_opt: [ "seccomp:unconfined" ]
environment:
ETCD_USE_EMBED: "true"
ETCD_DATA_DIR: /var/lib/milvus/etcd
ETCD_CONFIG_PATH: /milvus/configs/embedEtcd.yaml
COMMON_STORAGETYPE: local
volumes:
- milvus-data:/var/lib/milvus
- ./milvus/embedEtcd.yaml:/milvus/configs/embedEtcd.yaml
- ./milvus/user.yaml:/milvus/configs/user.yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
interval: 30s
start_period: 90s
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: $DDEV_APPROOT
volumes:
milvus-data:And .ddev/milvus/embedEtcd.yaml:
listen-client-urls: http://0.0.0.0:2379
advertise-client-urls: http://0.0.0.0:2379
quota-backend-bytes: 4294967296
auto-compaction-mode: revision
auto-compaction-retention: '1000'Then run ddev restart. The web container reaches Milvus at http://milvus:19530.
4. Configure the Milvus Provider
At /admin/config/ai/vdb_providers/milvus, set the server to http://milvus and the port to 19530. For Zilliz Cloud, use your public endpoint, port 443, and the API key from the Key module. Clear caches, which matters at this stage.
5. Add the AI Search Server
At /admin/config/search/search-api/add-server, create "AI Search Server" with the AI Search backend:
| Setting | Value used |
|---|---|
| Embeddings engine | OpenAI text-embedding-3-small (3-large also works; small is roughly 6x cheaper and plenty for site search) |
| Chat/tokenizer model | OpenAI gpt-4o |
| Vector database | Milvus |
| Database name | default (self-hosted Milvus default database) |
| Collection | content_collection |
| Similarity metric | Cosine similarity |
| Embedding strategy | Enriched / contextual chunks, chunk size 500, min overlap 100, contextual content max 30% |
6. Build the RAG Index and Map the Field Roles
Create a Search API index called "RAG Index" on the Content datasource, select the bundles that hold your knowledge (here, blog posts and pages), and attach it to the AI Search Server. Then give every field one of the three vector database roles. This mapping is what decides retrieval quality.
| Field | Role | Why |
|---|---|---|
| Content (body) | Main content | Chunked and embedded; queries run against it |
| Title | Contextual content | Prepended to every chunk so a mid-article passage still knows what page it belongs to |
| Description/summary | Contextual content | Same, keeps chunks self-explanatory |
Page URL (search_api_url) | Contextual content | Do not skip this. It puts the page's real URL inside every chunk, which is what lets the assistant cite a working source link instead of guessing one |
Set the cron batch size to 5 or 10, since each batch makes embedding API calls, then index:
ddev drush search-api:index rag_index --batch-size=57. Create the Assistant With a RAG Action
At /admin/config/ai/ai-assistant, add "Site Assistant" and enable its RAG action pointed at the RAG Index: score threshold 0.3, 1 to 5 results, output mode chunks. Model: OpenAI gpt-4o, temperature 0.2.
How Do You Keep the Chatbot From Making Things Up?
Keep the chatbot grounded with a prompt that makes searching mandatory first and grounding mandatory second. This is the configuration that makes or breaks the assistant, and one lesson only shows up in real testing.
In AI module 1.4, the assistant first makes a decision call: answer directly, or run an action? If your instructions only say "answer solely from retrieved content, otherwise say you found nothing," the model takes the shortcut at decision time and returns the fallback sentence without ever searching. The instructions have to make the search itself compulsory:
- For every user question about any topic, product, feature, or content, you must first run the RAG Actions search with the user's question as the query. Never answer a content question without searching first.
- After searching, answer only from the retrieved passages. Quote or closely paraphrase them, and never add facts from your own general knowledge.
- Every retrieved passage includes a "Page URL" line. Include a markdown link to it as the source.
- Only if the search returned no usable passages, reply: "I could not find matching information on this site for that question."
- For purely conversational messages such as greetings and thanks, reply briefly without searching.
The effect is an assistant that either answers from your content with a working citation or tells the user it does not know. That boundary is the whole point: a traceable non-answer beats a confident wrong one.
Where Does the Chatbot Block Go on Varbase 11?
On Varbase 11 the chatbot cannot go in a block region. Canvas renders the pages, including the global header and footer, so block layout regions never print. On a classic theme you would drop the AI DeepChat Chatbot block into a region and be done. Here, two things change.
- Render it from code. Use a small custom module and
hook_page_bottom(), which runs on every route regardless of Canvas. - Render it through a lazy builder. The chatbot markup carries a per-session CSRF token for
/api/deepchat. If the render array gets cached without a session context, every visitor is served the first visitor's token and every chat message fails with a 403. A#lazy_builderwith#create_placeholder: TRUEregenerates the token per request.
function ai_chatbot_launcher_page_bottom(array &$page_bottom) {
if (\Drupal::service('router.admin_context')->isAdminRoute()) {
return;
}
$page_bottom['ai_chatbot_launcher'] = [
'#lazy_builder' => ['ai_chatbot_launcher.lazy_builder:build', []],
'#create_placeholder' => TRUE,
];
}The lazy builder loads the DeepChat block plugin with the block's saved settings, checks access, and returns its build with #cache: max-age 0.
Two more field-tested gotchas: Varbase's Klaro consent manager gates the DeepChat element, so the chatbot only boots after the visitor accepts the "Deepchat" service. And with streaming enabled, we saw the RAG context intermittently dropped mid-stream, a session write error; turning the block's streaming off made responses reliable.
How Do You Add Semantic Results to Your Normal Search Page?
Add semantic results to a normal search page by enabling the "Database boost by AI Search" processor on the keyword index and pointing it at your RAG index. Use minimum relevance 0.4 and top 10 results.
On Varbase 11, the search page at /search is a Search API view on the database index, so it gains hybrid semantics without a rebuild. Semantic matches are prepended to keyword results, which means question-shaped queries work while exact-match precision stays.
The search box itself is a Canvas component. Add the search view's exposed-filter block (views_exposed_filter_block:search-page) to the global header through Canvas's page region (canvas.page_region.<theme>.header), so it appears on every page.
We styled ours as a collapsed magnifier in the navbar that expands into a minimal underline field, with Enter to submit. The submit button stays in the DOM but is visually hidden, so keyboard and screen reader users keep real control. Partial-match highlighting was switched off on the Highlight processor so excerpts only bold whole matched words.
How Do You Know It Is Working?
Verify the build with acceptance tests that check grounding and refusal, not just that the chatbot returns something. These are the tests we ran in a real browser, with Playwright driving Chrome.
| Test | Expected | Result |
|---|---|---|
| "What security features does Varbase provide?" | Grounded answer citing the security blog post with a working link | Pass. Answer quoted the post and linked /blog/enhancing-your-websites-security-varbase |
| "What is the capital of France?" | Refusal, because it is not in the site content | Pass. "I could not find matching information on this site for that question." |
| "Thanks, great help!" | Polite reply, no search | Pass. "You're welcome!" |
| Search "make my website load faster" | Performance posts despite zero keyword overlap | Pass. Optimization and performance posts ranked on top. |
The France test is the one worth copying. An assistant that cannot refuse is not grounded; it is just fluent.
Package It Once, Reuse It Everywhere
Everything above is configuration plus one small custom module, which is exactly the shape of a future Varbase AI Search recipe. Until that ships, this is the tested path on Varbase 11.
For teams running this in production, the decisions that matter are retrieval quality and a review cadence, not the module list, and that is where the time goes.
That direction is the reason to run this on Varbase rather than a bare Drupal install. Varbase already ships the AI foundation as a maintained recipe, and its AI and search pieces are built and supported by the same team, so the moving parts are meant to work together.
If you are planning an AI-powered search experience on Drupal and want a second set of eyes on the retrieval design before you build, Vardot's team works on exactly this on Varbase.
Talk to our Drupal AI team
Vardot is the Varbase maintainer, a Drupal Diamond Certified Partner, and a Drupal AI Initiative Gold Sponsor.
FAQs
RAG (retrieval-augmented generation) in a Drupal AI chatbot retrieves relevant passages from your own content using semantic vector search, then feeds them to a language model to generate the answer. On Drupal, the AI Search module handles retrieval and an AI assistant handles generation, so responses come from your site rather than the model's training data.
AI Search on Varbase 11 needs the Varbase AI Base recipe, which ships with Varbase 11 and installs the Drupal AI core and provider wiring, plus the AI Search, AI Chatbot, and AI Assistant API submodules of the Drupal AI module, and the Milvus VDB Provider module to connect a vector database. You also need an OpenAI API key for embeddings.
AI Search on Varbase 11 needs the Varbase AI Base recipe, which ships with Varbase 11 and installs the Drupal AI core and provider wiring, plus the AI Search, AI Chatbot, and AI Assistant API submodules of the Drupal AI module, and the Milvus VDB Provider module to connect a vector database. You also need an OpenAI API key for embeddings.
You can do either, since both connect through the same Milvus VDB Provider module. Self-hosting Milvus in a container keeps everything on your own infrastructure and needs no third-party account, which suits local development and data residency requirements. Zilliz Cloud is managed, so you supply a public endpoint on port 443 and an API key instead of running the database.
In AI module 1.4 the assistant first decides whether to answer directly or run an action, so a prompt that only says to answer from retrieved content lets it return the fallback message without ever running the search. Fix it by making the search explicitly mandatory in the instructions: require the assistant to run the RAG Actions search on every content question before answering.