| name | dspy-ollama |
| description | Run DSPy with local models via dspy.LM and Ollama — no API key needed. Use when you want to run DSPy locally, use Ollama, set up a local LLM, run offline, or configure local model parameters. Also used for ollama, local model, run LLM locally, llama local, self-hosted LLM, ollama serve, ollama_chat, local inference, run DSPy offline, no API key needed, ollama pull, ollama list, ollama rm, num_ctx, ollama context window, ollama GPU, OLLAMA_NUM_GPU, OLLAMA_HOST, ollama remote, ollama embeddings, nomic-embed-text, dspy.Embedder ollama, which local model, best model for ollama, ollama too slow, ollama vs vllm, develop locally deploy remotely, ollama environment variables, ollama systemd, ollama background service. |
Ollama — Run DSPy with Local Models
Guide the user through running DSPy with local models via Ollama. No API keys, no cloud costs, full privacy.
Step 1 — Gather context
Before diving in, confirm:
- Model: Do you have a specific model in mind (e.g.,
llama3.1:8b, qwen2.5:7b), or do you need a recommendation based on your hardware?
- Location: Is Ollama running locally, or on a remote GPU server you want to point DSPy at?
- Task: Classification, RAG, optimization, or general pipelines? (This affects context window and model recommendations.)
What is Ollama
Ollama is a local LLM runner that wraps llama.cpp. It downloads, manages, and serves models locally with a simple CLI. DSPy connects to it through LiteLLM's ollama_chat/ provider.
Setup
Install Ollama
brew install ollama
curl -fsSL https://ollama.com/install.sh | sh
Start the server and pull a model
ollama serve
ollama pull llama3.1
ollama run llama3.1 "What is DSPy?"
Connect DSPy to Ollama
import dspy
lm = dspy.LM(
"ollama_chat/llama3.1",
api_base="http://localhost:11434",
api_key="",
temperature=0.7,
num_ctx=8192,
)
dspy.configure(lm=lm)
classify = dspy.Predict("text -> sentiment")
result = classify(text="DSPy makes AI development easier")
print(result.sentiment)
Note: dspy.OllamaLocal is deprecated. Use dspy.LM("ollama_chat/...") instead.
Model selection guide
| Model | Sizes | Context | Good for | Notes |
|---|
| Llama 3.1 | 8B, 70B | 128K | General purpose, instruction following | Best all-rounder |
| Llama 3.2 | 1B, 3B | 128K | Edge, mobile, lightweight tasks | Very fast, less capable |
| Qwen 2.5 | 0.5B–72B | 128K | Multilingual, coding, math | Strong on benchmarks |
| Qwen 3 | 0.6B–32B | 128K | Reasoning, multilingual | Latest, thinking mode |
| Mistral | 7B | 32K | Fast general purpose | Good speed/quality tradeoff |
| Phi-4 | 14B | 16K | Reasoning, STEM, code | Small but capable |
| Gemma 2 | 2B, 9B, 27B | 8K | Lightweight, fast | Google, good quality/size ratio |
| DeepSeek-R1 | 1.5B–70B | 128K | Complex reasoning | Distilled reasoning chains |
| CodeLlama | 7B, 13B, 34B | 16K | Code generation | Fine-tuned for code |
Quick recommendations
Prototyping (fast iteration, good quality):
→ llama3.1:8b or qwen2.5:7b
Best quality on consumer hardware (16GB+ RAM):
→ llama3.1:8b or phi4:14b
Complex reasoning:
→ deepseek-r1:14b or qwen3:14b
Coding tasks:
→ qwen2.5-coder:7b or codellama:13b
Minimal resources (8GB RAM):
→ llama3.2:3b or gemma2:2b or qwen2.5:3b
Context window gotcha (critical)
Ollama defaults to 4096 tokens regardless of the model's actual capacity. This is the #1 source of issues when running DSPy with Ollama. DSPy prompts with few-shot demos can easily exceed 4096 tokens.
Always set num_ctx explicitly:
lm = dspy.LM("ollama_chat/llama3.1", api_base="http://localhost:11434", api_key="")
lm = dspy.LM(
"ollama_chat/llama3.1",
api_base="http://localhost:11434",
api_key="",
num_ctx=8192,
)
Larger context = more VRAM. If you get OOM errors, reduce num_ctx:
| num_ctx | VRAM overhead (approx) | When to use |
|---|
| 4096 | Baseline | Simple classification, short prompts |
| 8192 | +2-4 GB | Most DSPy tasks, few-shot demos |
| 16384 | +4-8 GB | RAG with long contexts |
| 32768 | +8-16 GB | Long document processing |
Environment variables
| Variable | Default | Description |
|---|
OLLAMA_HOST | 127.0.0.1:11434 | Bind address. Set to 0.0.0.0:11434 to allow remote access (e.g., GPU server serving DSPy clients on other machines) |
OLLAMA_NUM_GPU | auto | Number of GPU layers. 999 = all GPU, 0 = CPU only |
OLLAMA_NUM_PARALLEL | 1 | Concurrent requests. Increase for DSPy batch/optimization runs |
OLLAMA_MAX_LOADED_MODELS | 1 | Models kept in memory simultaneously. Increase for multi-model pipelines |
OLLAMA_MODELS | ~/.ollama/models | Model storage directory. Change if disk space is limited |
Setting env vars per platform:
- macOS (app):
launchctl setenv OLLAMA_HOST "0.0.0.0:11434" then restart Ollama
- Linux (systemd):
sudo systemctl edit ollama.service, add Environment= lines under [Service], then systemctl daemon-reload && systemctl restart ollama
- Everywhere else:
export OLLAMA_HOST="0.0.0.0:11434" before ollama serve
Remote Ollama (GPU server)
If Ollama runs on a different machine (e.g., a GPU server), point DSPy to it:
lm = dspy.LM(
"ollama_chat/llama3.1:8b",
api_base="http://gpu-server:11434",
api_key="",
num_ctx=8192,
)
Make sure the server has OLLAMA_HOST=0.0.0.0:11434 set.
Performance tuning
GPU acceleration
Ollama automatically uses GPU if available. Check with:
ollama ps
Apple Silicon optimization
Ollama runs natively on Apple Silicon using Metal. Performance tips:
- M1/M2 (8GB): 8B models work well with
num_ctx=4096
- M1/M2 Pro (16GB): 8B models with
num_ctx=8192, or 14B with num_ctx=4096
- M1/M2 Max (32GB+): 70B quantized models with
num_ctx=4096
- M3/M4 Max (64GB+): 70B models with
num_ctx=8192
Embedding models (for retrieval pipelines)
Ollama can serve embedding models for dspy.Embedder:
embedder = dspy.Embedder(
"ollama/nomic-embed-text",
api_base="http://localhost:11434",
api_key="",
batch_size=200,
)
| Model | Dimensions | Size | Notes |
|---|
nomic-embed-text | 768 | 274 MB | Good default, fast |
mxbai-embed-large | 1024 | 670 MB | Higher accuracy |
bge-m3 | 1024 | 1.2 GB | Multilingual |
Pull embedding models the same way: ollama pull nomic-embed-text
Model management
ollama list
ollama pull llama3.1:8b
ollama rm codellama:7b
ollama ps
ollama show llama3.1:8b
curl http://localhost:11434/api/tags
Run Ollama as a background service instead of ollama serve &:
- macOS: The Ollama app runs as a menu bar service automatically
- Linux:
sudo systemctl enable --now ollama (installed by the install script)
Per-module model assignment
Use a big model for hard tasks and a small model for simple ones:
import dspy
big = dspy.LM("ollama_chat/llama3.1:8b", api_base="http://localhost:11434",
api_key="", num_ctx=8192)
small = dspy.LM("ollama_chat/llama3.2:3b", api_base="http://localhost:11434",
api_key="", num_ctx=4096)
dspy.configure(lm=small)
class Pipeline(dspy.Module):
def __init__(self):
self.classify = dspy.Predict("text -> category")
self.analyze = dspy.ChainOfThought("text, category -> analysis")
def forward(self, text):
cat = self.classify(text=text)
return self.analyze(text=text, category=cat.category)
pipeline = Pipeline()
pipeline.classify.set_lm(small)
pipeline.analyze.set_lm(big)
Running DSPy optimization with Ollama
Optimization works with local models but is significantly slower than cloud APIs. Tips:
import dspy
lm = dspy.LM("ollama_chat/llama3.1:8b", api_base="http://localhost:11434",
api_key="", num_ctx=8192)
dspy.configure(lm=lm)
optimizer = dspy.BootstrapFewShot(metric=metric, max_bootstrapped_demos=4)
optimized = optimizer.compile(program, trainset=trainset)
optimizer = dspy.MIPROv2(metric=metric, auto="light")
optimized = optimizer.compile(program, trainset=trainset)
teacher_lm = dspy.LM("ollama_chat/llama3.1:70b", api_base="http://localhost:11434",
api_key="", num_ctx=8192)
optimizer = dspy.BootstrapFewShot(metric=metric, max_bootstrapped_demos=4)
with dspy.context(lm=teacher_lm):
optimized = optimizer.compile(program, trainset=trainset)
Expect hours, not minutes for optimization with local models. A MIPROv2 auto="medium" run that takes 5 minutes with GPT-4o-mini might take 2-4 hours with a local 8B model.
Ollama vs vLLM
| Ollama | vLLM |
|---|
| Setup | brew install ollama | pip install vllm (NVIDIA only) |
| Platform | macOS, Linux, Windows | Linux (NVIDIA GPU required) |
| Apple Silicon | Yes (Metal) | No |
| Throughput | Single-user | High concurrency (10+ users) |
| Multi-GPU | No | Yes (tensor parallelism) |
| Best for | Development, prototyping | Production serving |
Recommended workflow: Develop with Ollama locally, deploy with vLLM in production. The DSPy code is identical — only the LM config line changes:
lm = dspy.LM("ollama_chat/llama3.1:8b", api_base="http://localhost:11434", api_key="")
lm = dspy.LM("openai/meta-llama/Llama-3.1-8B-Instruct", api_base="http://gpu-server:8000/v1", api_key="none")
Gotchas
- Context window defaults to 4096 — always set
num_ctx explicitly. DSPy optimized prompts with few-shot demos easily exceed 4096 tokens.
api_key="" is required — even though Ollama doesn't use it, LiteLLM requires the parameter.
- First request is slow — Ollama loads the model into memory on the first call. Subsequent calls are fast.
- OOM errors — reduce
num_ctx or switch to a smaller model. Check VRAM with ollama ps.
dspy.OllamaLocal is deprecated — use dspy.LM("ollama_chat/...") instead.
Cross-references
Install any skill: npx skills add lebsral/DSPy-Programming-not-prompting-LMs-skills --skill <name>
- LM configuration basics (providers, parameters, caching) —
/dspy-lm
- Production serving with vLLM —
/dspy-vllm
- Reducing costs (model routing, caching) —
/ai-cutting-costs
- Switching models without breaking things —
/ai-switching-models
- Install
/ai-do if you do not have it — it routes any AI problem to the right skill and is the fastest way to work: npx skills add lebsral/DSPy-Programming-not-prompting-LMs-skills --skill ai-do
Additional resources