Blog
Mar 1, 2025 - 3 MIN READ
Data Extraction with LangChain and Ollama Locally

Data Extraction with LangChain and Ollama Locally

Getting typed rows out of a local LLM with Pydantic and LangChain.

Phanith LIM

Phanith LIM

An LLM will happily answer "give me the top 10 phones" in prose. What I want is rows I can put in a DataFrame.

Here is how I do that on my own machine: Pydantic describes the shape I expect, LangChain's output parser forces the model to answer in that shape, and pandas takes it from there. Nothing leaves the laptop.

1. Install

pip install langchain
pip install ollama
pip install pydantic
pip install pandas

You need Ollama running

Install Ollama, open it, and let the server start. If it is new to you, these command-line basics cover enough to get going.

2. Imports

from pydantic import BaseModel, Field
from langchain_ollama.llms import OllamaLLM
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import HumanMessagePromptTemplate, ChatPromptTemplate
import pandas as pd

3. Describe what you want back

The Pydantic model is the contract. Each description is a hint the model actually reads, so it is worth writing them properly.

class PhoneModel(BaseModel):
    brand: str = Field(description="Brand of the phone")
    model: str = Field(description="Model of the phone")
    year: int = Field(description="Year of the phone")
    price: float = Field(description="Price of the phone")

class PhonesModel(BaseModel):
    phones: list[PhoneModel] = Field(description="List of phones")

4. Turn the schema into instructions

PydanticOutputParser writes the formatting instructions for you and parses the reply back into your objects.

output_parser = PydanticOutputParser(pydantic_object = PhonesModel)
format_instructions = output_parser.get_format_instructions()
print(format_instructions)

Print them once and read them. That text is what the model is being told.

5. Pick a local model

Pull whichever model you want from Ollama. I used llama3.2:3b here, with temperature at 0 so the output stays repeatable.

model = OllamaLLM(
    model='llama3.2:3b',
    temperature=0.0,
)

6. Chain prompt, model, and parser

The prompt carries my instruction plus the format instructions. The pipe operator puts the three pieces in a row, which is where the name LangChain comes from.

human_text = "{instruction}\n{format_instructions}"
message = HumanMessagePromptTemplate.from_template(human_text)
prompt = ChatPromptTemplate.from_messages([message])

chain = prompt | model | output_parser
products = chain.invoke({"instruction":"Give top 10 popular phone now", "format_instructions":format_instructions})

products is a PhonesModel, not a string. If the model answers in the wrong shape, the parser raises instead of quietly handing me junk.

7. Into a DataFrame

df = pd.DataFrame([product.model_dump() for product in products.phones])
df
brandmodelyearprice
0AppleiPhone 132021699.0
1SamsungGalaxy S212021799.0
2GooglePixel 62021599.0
3OnePlus9 Pro2021969.0
4XiaomiMi 112021749.0
5OppoFind X3 Pro20211149.0
6RealmeGT 2 Pro2022599.0
7VivoX70 Pro2021899.0
8SonyXperia 1 III20211299.0
9MotorolaEdge 30 Pro2022799.0

One thing worth saying out loud: the model made these numbers up from what it remembers. The schema guarantees the shape of the answer, never the truth of it. For anything that matters, check the values against a real source.

print("Thank you for reading!")
© 2026 Phanith LIM