Grounder › Guides › Local LLM web search
Give a Local LLM Live Web Search (Ollama & LM Studio)
A local model - Llama, Qwen, Gemma on Ollama or LM Studio - stopped learning at its training cutoff. Ask it about this week and it will invent an answer with total confidence. This guide shows the full pipeline to give it live web search, the three practical ways to do it, and the real limitation each one runs into.
Why a local LLM can't answer current questions
Every model is frozen at its training cutoff. A local 7B doesn't know today's framework release, a library's new API, or a price that changed last month - and because it was trained to be helpful, it fills the gap with a plausible guess rather than admitting it doesn't know. In a small test, a local Qwen2.5-7B answered 3 of 8 current-fact questions correctly on its own; with live web evidence in the prompt, 7 of 8.
The pipeline: search, fetch, clean, rank, prompt
"Web search for a local LLM" is really five steps. The model itself only does the last one:
- Search - turn the question into a query and get ranked result URLs.
- Fetch - download the actual pages (many results are protected and come back empty).
- Clean - strip nav, ads, and boilerplate down to the real content (markdown).
- Rank - keep only the passages relevant to the question. This step is what makes it fit.
- Prompt - put those passages in the context window and let the model answer.
Skip step 4 and you hit the wall that breaks most first attempts.
Approach 1 - DIY with SearXNG
SearXNG is a free, self-hosted metasearch engine. It's the search backend behind Perplexica (whose README states "Web search powered by SearxNG") and similar self-hosted RAG stacks, precisely because it's free - but it hands you only step 1. You still build fetch, clean, and rank yourself, and you inherit rate-limiting and blocking on public instances.
# Step 1 only: query a SearXNG instance for result URLs
import requests
def searxng_search(query, instance="http://localhost:8080"):
r = requests.get(f"{instance}/search",
params={"q": query, "format": "json"}, timeout=15)
r.raise_for_status()
return [hit["url"] for hit in r.json().get("results", [])[:5]]
# You still have to fetch each URL, strip boilerplate, rank passages,
# and cap the result to your context window - none of that is SearXNG.
Real limitations
- Public instances rate-limit and block automated queries; you end up self-hosting to be reliable.
format=jsonis disabled on many instances, so you scrape HTML instead.- It's search only - fetch, clean, and rank (the parts that actually make it usable) are on you.
Approach 2 - Ollama's web search API
Ollama added a hosted web search API (2025). It covers search and returns snippet content, which is a step up from raw SearXNG - but it requires a free Ollama account and API key, and it returns results, not a context-fitted pack, so the token-budget step is still yours.
import requests
def ollama_web_search(query, api_key):
r = requests.post("https://ollama.com/api/web_search",
headers={"Authorization": f"Bearer {api_key}"},
json={"query": query}, timeout=30) # schema: docs.ollama.com/capabilities/web-search
r.raise_for_status()
return r.json() # results with snippet content - you still cap to your window
Real limitations
- Requires an account and key - a friction point for a "local, no cloud accounts" setup.
- Returns results/snippets; capping to your model's window and reranking for relevance is still your code.
- No control over how protected pages are handled.
Approach 3 - a token-capped evidence pack
The three steps that actually make web search usable for a local model - fetch the real page, clean it, and rank it down to what fits - are the same every time. A search API built for LLMs does all five steps and returns a token-capped evidence pack, so the model gets only the passages that answer. Grounder is one such tool (it's what we build); the pattern matters more than the vendor.
import requests
KEY = "your_grounder_key" # free tier: 1,500 pages/month, no card
# One call: search -> fetch pages -> rank -> a pack capped to your window
r = requests.post("https://grounder.dev/v1/deep_search",
headers={"Authorization": f"Bearer {KEY}"},
json={"query": "latest stable Node.js LTS version",
"max_tokens": 600}, # <- guarantees it fits an 8k model
timeout=180)
pack = r.json()
# pack["passages"] are cited, ranked, and capped to your window - answer only from them
evidence = "\n\n".join(p["text"] for p in pack["passages"])
# Hand `evidence` to your local model in the prompt - it stays well under the window.
Then the model answers from evidence that fits:
import requests # any OpenAI-compatible local server (LM Studio, Ollama)
resp = requests.post("http://localhost:1234/v1/chat/completions", json={
"model": "qwen2.5-7b-instruct",
"messages": [{"role": "user",
"content": f"Use the evidence to answer.\n\nEVIDENCE:\n{evidence}\n\n"
f"Question: latest stable Node.js LTS version"}]
}).json()
print(resp["choices"][0]["message"]["content"])
Which approach fits
| SearXNG (DIY) | Ollama web search | Token-capped pack | |
|---|---|---|---|
| Steps it covers | Search | Search + snippets | Search + fetch + clean + rank |
| Fits a small window | You build it | You build it | Yes (token-capped) |
| Protected pages | You handle it | Limited | Handled |
| Account needed | No (self-host) | Yes | Yes (free tier) |
| Ops burden | High (host + build) | Medium | Low |
Try the token-capped pack
Grounder returns a token-capped evidence pack sized to your context window. Free tier is 1,500 pages a month, email only, no card.
Get a free keyTransparency note: Grounder is a commercial product we build, so we have an interest here. The pipeline and the token-budget constraint are true regardless of which tool you use - SearXNG and Ollama's API are real, valid options. Verify any current version numbers above against the official source.
FAQ
Can Ollama or LM Studio search the web on their own?
Not the model itself. They run the model; live web results require a search step, a fetch step, and passing cleaned content back into the prompt - via a DIY pipeline, Ollama's web search API, or a search API that returns a token-capped evidence pack.
Why does dumping web pages into a local model break it?
A local model runs a small window (4k-32k tokens). A few full pages can exceed 20,000 tokens, overflow the window, and the model returns nothing or a truncation error. Return a token-capped pack - the relevant passages, not whole pages.
Is SearXNG a good backend for this?
It's free and self-hosted, which is why Perplexica and similar self-hosted stacks use it, but it inherits public-instance rate-limiting and blocking, and you still build the fetch-and-rank step yourself.