What we're building
The local-model version of what langchain Lesson 1 did with Gemini: one prompt in, one written answer out. No conversation history yet (Lesson 12), no streaming (Lesson 5), just the smallest possible round trip to a model running on your own machine.
No API key, because there's no API to authenticate against
Every Gemini lesson in this repo starts with load_dotenv() and a GOOGLE_API_KEY, because Google needs to know who's calling and enforce a quota. Ollama has no such concept: the server it's talking to is http://localhost:11434, a program running on your own computer, not a company's infrastructure. There's nothing to prove and no quota to hit (only your own hardware's limits).
The code, piece by piece
import ollamaSame client as Lessons 1 and 2, no setup beyond that import.
response = ollama.generate( model="llama3.2", prompt="In one sentence, what is Python used for?",)ollama.generate() is the simplest possible call: a model name and a raw prompt string, no message roles or conversation structure (that's ollama.chat(), covered in Lesson 4 with the actual difference between the two). This is a blocking call, exactly like LangChain's .invoke(): your program pauses here until the model finishes writing its full answer.
response.responseThe written answer itself. Unlike LangChain's .text property, this is a plain attribute on a GenerateResponse object, note the name collision, response is both the variable name and the attribute that holds the text; response.response reads oddly but is correct.
response.eval_countresponse.prompt_eval_countLocal models report their own token accounting directly: eval_count is how many tokens the model generated, prompt_eval_count is how many it read from your prompt first. This is the same kind of metadata Gemini's AIMessage carries, just under different attribute names, since there's no per-token billing to justify hiding it behind a "usage" object.
Checkpoint
ollama.generate(): the simplest call, a raw prompt string in, a written answer out, blocking.- No API key: local calls have nothing to authenticate, since there's no remote provider or quota.
response.response: the written answer (an odd but correct attribute name).eval_count/prompt_eval_count: local token accounting, reported directly since there's no billing to hide it behind.
If anything here still feels unclear, ask before moving to Lesson 4.