Everyone has the same week with Ollama.
On Monday you run ollama run llama3.2 and it feels like magic: a real model on your own hardware, no API bill, nothing leaving the machine. By Wednesday you want the model to answer questions about your own documents. By Friday your "local AI" is five pieces:
- Ollama, for inference.
- A vector database, because Ollama can create an embedding but has nowhere to keep it.
- Postgres or SQLite, for the actual data.
- LangChain or LlamaIndex, to glue the three together.
- An nginx config, because your teammate wants to use it too.
None of that is Ollama's fault. Ollama set out to run models well and it does. But if you've ever sat in that Friday mess wondering why "local AI" needs so much plumbing, this article is for you.
Five places Ollama stops
These come straight from Ollama's own docs, and every one is a reasonable design choice for a model runner. Each one is also a job that falls to you.
1. It forgets everything. /api/embed returns a vector, and then it's your problem. Ollama has no storage, no index and no search, so every RAG tutorial starts with "now install a vector database".
2. It can't see your data. The model knows what it was trained on, plus whatever you paste into the prompt. Finding the right rows, deciding what goes in the context window, and citing where an answer came from is all code you write and maintain.
3. It lets anyone in, or no one. By default Ollama listens only on 127.0.0.1:11434. Its FAQ shows how to open it up with OLLAMA_HOST=0.0.0.0, nginx, ngrok or a Cloudflare Tunnel, and none of those sections mentions authentication, because the server doesn't have any. There are no API keys, no per-user limits and no "this key can read the support docs but not the payroll table". Most teams either keep it on one laptop or put it behind a proxy and hope.
4. It can't tell you when it's wrong. A 7B model will tell you, with total confidence, that your refund window is 90 days when your policy says 45. Ollama streams those tokens just as happily as the right ones. Checking the answer against the source is, once again, your problem.
5. It doesn't learn. Run the same agent task a thousand times and the thousand-and-first attempt is no better informed than the first. Nothing records which attempts worked.
Keep your Ollama code and change the server
SynapCores is a single-binary database for AI agents: SQL, vectors, graph, agent memory and local inference in one process. Since the 2.3 line it also serves the Ollama API, including /api/chat, /api/embed, /api/tags, /api/ps and /api/version. It pulls models from the same Ollama registry, so qwen2.5, llama3.2 and all-minilm keep the names you already use.
This is the official ollama Python client (0.6.3), unchanged except for the host and an API key. I ran it against SynapCores 2.4.0 this morning:
import ollama
client = ollama.Client(
host="http://localhost:8080", # SynapCores
headers={"Authorization": "Bearer aidb_..."}, # a read-only API key
)
print([m.model for m in client.list().models])
# ['all-minilm:latest', 'qwen2.5:0.5b']
client.chat(model="qwen2.5:0.5b",
messages=[{"role": "user", "content": "Reply with just the word OK."}])
# → "OK."
client.embed(model="all-minilm", input=["a", "b"]) # two 384-dim vectors
Streaming works as well (NDJSON, the same as Ollama). LangChain's ChatOllama and OllamaEmbeddings (langchain-ollama 1.1.0) also worked with only base_url and the auth header changed.
Look again at that auth header. It addresses gripe #3: every request carries a key, and an unauthenticated call gets a 401. Keys can be read-only, limited to specific databases, and set to expire. The one in the example above is read-only and expires in 24 hours.
The part Ollama can't do: answers grounded in your data
Here's a three-row support knowledge base stored as an ordinary SQL table:
CREATE TABLE kbtext (id INT PRIMARY KEY, body TEXT);
INSERT INTO kbtext VALUES
(1, 'Orbit Pro refunds: customers can request a full refund within 45 days of purchase.'),
(2, 'Orbit Pro support hours are 7am to 7pm Eastern, Monday through Saturday.'),
(3, 'Error code E-221 means the sync token expired; sign out and sign back in.');
First, ask through the Ollama API the way you always have:
curl localhost:8080/api/chat -H "Authorization: Bearer $KEY" -H "content-type: application/json" -d '{
"model": "qwen2.5:0.5b", "stream": false,
"messages": [{"role":"user","content":"How many days do I have to get a refund on Orbit Pro?"}]
}'
"As an AI language model, I cannot provide specific information about the refund policies for Orbit Pro… check the official website or contact their customer support."
That's the answer you get from plain Ollama, and it's honest but useless. Now add one field:
"rag": {"source": "collection:kbtext", "mode": "inject", "top_k": 2},
"…customers can request a full refund within 45 days of purchase for Orbit Pro."
The response headers show where the answer came from:
x-synapcores-grounding: grounded
x-synapcores-citations: ["collection:kbtext/row-0","collection:kbtext/row-1"]
It's the same model and the same endpoint. The difference is that the model is now running inside the database that holds the answer. There's no vector database to deploy, no glue code, and no second copy of your data.
Catching the model when it's wrong
Gripe #4 was confident wrong answers. SynapCores includes a small natural-language-inference (NLI) model that checks a claim against your own rows, in SQL:
SELECT NLI_VERIFY('nli-default',
'Orbit Pro customers have 90 days to request a refund.',
NLI_ANCHORS(body)) AS v
FROM kbtext;
-- verdict: LIE (confidence 0.99)
-- violated_anchor: 'Orbit Pro refunds: ... within 45 days of purchase.'
SELECT NLI_VERIFY('nli-default',
'Orbit Pro customers can get a full refund within 45 days.',
NLI_ANCHORS(body)) AS v
FROM kbtext;
-- verdict: TRUTH (confidence 0.997)
That means "only show or store the model's answer if your own data supports it" becomes a WHERE clause instead of a separate microservice. The check runs in-process, with no Python sidecar.
Your model, used directly in SQL
Because inference runs inside the engine, the model is also available in a query:
SELECT id, GENERATE('Summarize in 6 words: ' || body) AS s FROM kbtext WHERE id = 3;
-- 'Error Code: E-221 - Sync Token Expired; Sign Out & Sign In.'
EMBED() works the same way, so semantic search is just ORDER BY COSINE_SIMILARITY(embedding, EMBED('...')), with an HNSW index if the table is large.
Answering the rest of the list
- Memory (#1):
CREATE MEMORYgives agents persistent memory. When a newer fact replaces an older one ("moved from Miami to Denver"), the newer fact wins. - Learning (#5): with
CREATE GOALandEXECUTE GOAL, you define a goal and a deterministic success check. SynapCores records each attempt, scores it, and updates a policy from the results that actually passed. A new policy goes live only after it proves itself on held-out evidence. Learning is off by default, writes wait for approval, and every decision goes into a hash-linked, tamper-evident ledger. - Who can do what (#3): agent permissions are separate from data permissions (monitor, operate, approve, configure), and you grant them with ordinary SQL
GRANTstatements.
What I'd tell you before you switch
- SynapCores is a database, not a lighter Ollama. If all you need is a model in a terminal, keep Ollama. SynapCores is for when your model needs to work with data.
- Auth is required by default. Your client needs a host change and a bearer key, and the API is on port 8080, not 11434. The
ollamaCLI itself assumes an open server, so I tested the Python and LangChain clients rather than the CLI. - I tested on a laptop with a small 0.5B model, because that's the quickest way to show the API. New installs default to
qwen2.5:7b, which is far better at following grounded context. - Grounding reduces made-up answers but doesn't eliminate them. That's why the NLI check exists.
Try it in five minutes
curl -fsSL https://get.synapcores.com | sh
# or
docker pull synapcores/community:v2.4.0-ce
It's the free Community Edition, released today (v2.4.0) and self-hosted. All of the above is included.
Start here: synapcores.com · Docs: docs.synapcores.com
Keep Ollama for running models, and use SynapCores when the model needs to work with your data.