A visitor arrives on a technical website with a question: “How do I configure SMTP in Drupal?” Traditional search returns matching pages. A chatbot can take the next step: find the relevant passage, give a short answer, and link to the full article.
This guide explains how we built that feature with Drupal and Ollama. The chatbot uses published articles as its knowledge source and runs model inference on our own hardware. Start with Set Up Local AI with Ollama if you have not yet installed and tested a local model. One machine is enough to begin; a separate GPU computer is optional.
What does the chatbot do?
The chatbot is a website widget that accepts a question and returns an answer supported by article excerpts. Readers can follow the source links to check the explanation or continue reading.
“Site-wide” describes where the widget appears. The implemented search covers published articles, rather than every page, file, or entity on the site. Basic navigation questions, such as finding the contact page, use predefined site information.
Why combine Drupal with local AI?
Drupal already manages the content, publication state, and URLs. Ollama provides an HTTP API for generating text. Combining them allows Drupal to control which information reaches the model and how the answer is presented.
This is useful when readers need a concise explanation across a growing collection of articles. Local inference gives you control over the model and the hardware processing those prompts. The tradeoff is that response time and capacity depend on your resources.
The model is not trained on the website. Instead, Drupal retrieves useful content for each question and includes it in the prompt. This pattern is called retrieval-augmented generation, or RAG.
How a question becomes an answer
Visitor submits a question
-> Drupal finds relevant article passages
-> Drupal checks for a reusable cached answer
-> Ollama receives the question and passages
-> Drupal validates the returned source identifiers
-> Widget displays the answer and article links
The browser communicates with Drupal. The Drupal backend calls Ollama; visitors do not need network access to the inference server.
Step 1: make Ollama reachable from Drupal
Download a model and verify a chat request before adding the website integration. For example, llama3.2:1b is a lightweight starting point; test whether its answers are adequate for your content. A larger model such as qwen2.5:7b needs more resources.
Choose the API address according to where Drupal runs:
| Deployment | Example Ollama base URL |
|---|---|
| PHP and native Ollama on the same host | http://localhost:11434 |
| Drupal and Ollama on the same Docker network | http://ollama:11434 |
| Drupal container accessing Ollama through the host | http://host.docker.internal:11434, when configured |
| Optional second computer on a private network | http://<server-address>:11434 |
Inside a container, localhost refers to that container. Verify the endpoint from the environment running PHP, not just from a terminal on the host.
Step 2: index published content in smaller sections
Sending every article with every question is expensive and can exceed the model's context capacity. Our custom module, article_chatbot, maintains an index of article sections instead.
The indexer splits bodies at H2–H6 headings and divides long sections at sentence boundaries. Each chunk retains its article title, heading, text, and source URL. Article creation, edits, unpublishing, and deletion keep the index current; the module's update path indexes existing published articles.
Retrieval scores chunks using whole-word matches, question-term coverage, and additional weight for title and heading matches. It selects a small set of relevant passages—three by default in this implementation.
This is keyword-based retrieval, not vector search. A question using entirely different terminology may miss a relevant article. Embeddings could improve semantic matching later, but are not required for this implementation.
Step 3: send a prompt with evidence
A Drupal service uses the injected HTTP client to call Ollama's /api/chat endpoint. The prompt combines the visitor's question, numbered article excerpts, and instructions to answer only from those excerpts.
An abbreviated request looks like this:
// $url and $model come from configuration.
// $prompt includes the question, numbered excerpts, and answer rules.
$response = $this->httpClient->request('POST', rtrim($url, '/') . '/api/chat', [
'connect_timeout' => 2,
'timeout' => 10,
'json' => [
'model' => $model,
'stream' => FALSE,
'format' => 'json',
'messages' => [
['role' => 'user', 'content' => $prompt],
],
'options' => [
'temperature' => 0.1,
'num_ctx' => 2048,
'num_predict' => 80,
],
],
]);
The time and token limits are examples from our implementation, not universal settings. A low temperature encourages consistent responses, while bounded context and output help control work per request. See the Ollama chat API documentation.
Step 4: validate the answer and add source links
The prompt requests structured output:
{"answer":"A short answer supported by the supplied text.","source_ids":[1]}
Drupal reads message.content, parses the model's JSON, and checks that the cited identifiers belong to the supplied excerpts. Drupal adds the corresponding URLs itself. The model does not choose arbitrary destination links.
When the evidence does not answer the question, the expected output is:
{"answer":"NOT_FOUND","source_ids":[]}
The widget can then offer a contact link instead of inventing an answer. Citation checks make the response traceable, but readers should still be able to inspect the source: a valid citation identifier does not guarantee that every generated claim is correct.
Step 5: connect the widget and configuration
We implemented the indexer, retriever, Ollama client, controller, and widget in a custom module. This guide describes that architecture; the module is not a standard Drupal feature or a contributed package that these instructions install automatically.
With the custom code available, enable the module, apply its database updates, configure the endpoint and model at /admin/config/services/article-chatbot, and place the Article chatbot block in a visible theme region. Verify existing content is indexed, then test as a logged-out visitor.
Keep endpoint settings in Drupal configuration so a model or server change does not require editing the request code.
Keep responses useful when inference is slow
Cache reusable answers and invalidate them when their source articles change. Our cache includes the question hash, evidence hashes, model configuration, and prompt version. Successful answers default to 24 hours; grounded no-answer results default to 15 minutes. Request errors are not cached.
If another inference machine is available, the application can try it first and use a smaller local model after a connection or request failure. Our implementation also temporarily skips a failed primary endpoint using a circuit breaker. This is optional application logic; installing Ollama alone does not provide failover.
A valid no-answer response should not trigger another model call merely because it is disappointing: the second model would receive the same evidence.
Test the complete visitor experience
Check a question answered by a known article, an unsupported question, and a navigation request. Edit or unpublish a source article and confirm stale answers disappear. Repeat a successful question to verify caching, and stop the inference service in development to check the failure message.
The result is an assistant whose answers remain connected to content Drupal manages. For another use of the same local runtime, see Analyze Google Analytics Data in Drupal with Local AI.