We are going to build a named entity recognition pipeline that turns unstructured text into structured JSON using an LLM. This is useful for anyone extracting people, companies, locations, and dates from news articles, support tickets, or legal documents without maintaining a separate spaCy or Hugging Face model. Because Oxlo.ai charges a flat rate per request, you can feed it long documents or batch multiple inputs without watching token costs climb.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Configure the client
First, instantiate the OpenAI client pointing at Oxlo.ai's endpoint. This gives us a drop-in replacement for any OpenAI code we already have.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
SYSTEM_PROMPT = "You are a helpful assistant."
USER_MESSAGE = "Say OK"
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": USER_MESSAGE},
],
)
print(response.choices[0].message.content)
Step 2: Write the system prompt
The system prompt tells the model exactly which entities to extract and what schema to return. Keeping this in a separate variable makes it easy to iterate without touching the rest of the code.
SYSTEM_PROMPT = """
You are a precise entity extraction engine.
Analyze the user text and extract all named entities.
Return ONLY a JSON object with no markdown formatting and no explanation.
Use this exact structure:
{
"entities": [
{"type": "PERSON", "text": "..."},
{"type": "ORGANIZATION", "text": "..."},
{"type": "LOCATION", "text": "..."},
{"type": "DATE", "text": "..."}
]
}
Include every entity that appears in the text. If a category has no matches, omit it.
"""
Step 3: Build the extraction function
We wrap the API call in a function that enables JSON mode and parses the result into a native Python dict. I use Llama 3.3 70B here because it follows structured instructions reliably on Oxlo.ai.
import json
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
def extract_entities(text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
)
raw = response.choices[0].message.content
return json.loads(raw)
Step 4: Test with a realistic document
Here is a messy news excerpt with overlapping entity types. We pass it through the function and print the structured result.
document = """
In March 2024, Sarah Chen from OpenAI visited the London office of DeepMind
to discuss a joint research initiative with Demis Hassabis.
The meeting took place at the King's Cross campus before the team flew to
San Francisco for the next phase of the project.
"""
result = extract_entities(document)
print(json.dumps(result, indent=2))
Step 5: Batch multiple documents
Since Oxlo.ai uses flat per-request pricing, you can pack several passages into a single call without inflating the cost. This is useful for overnight ETL jobs, and you can check current plans at https://oxlo.ai/pricing.
BATCH_SYSTEM_PROMPT = SYSTEM_PROMPT + """
The user will provide multiple texts separated by ---BATCH---.
Return a JSON object where each key is an integer index starting at 0,
and each value is the entity list for that text.
Example: {"0": {"entities": [...]}, "1": {"entities": [...]}}
"""
def extract_entities_batch(documents: list[str]) -> dict:
combined = "\n---BATCH---\n".join(documents)
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": BATCH_SYSTEM_PROMPT},
{"role": "user", "content": combined},
],
response_format={"type": "json_object"},
)
return json.loads(response.choices[0].message.content)
docs = [
"Apple Inc. announced record earnings in Cupertino on January 10, 2025.",
"Marie Curie won the Nobel Prize in Stockholm in 1911."
]
print(json.dumps(extract_entities_batch(docs), indent=2))
Run it
Save the complete script as ner_pipeline.py, set your API key, and run it. The snippet below shows the single-document output you should expect.
export OXLO_API_KEY="your-key-here"
python ner_pipeline.py
{
"entities": [
{"type": "DATE", "text": "March 2024"},
{"type": "PERSON", "text": "Sarah Chen"},
{"type": "ORGANIZATION", "text": "OpenAI"},
{"type": "LOCATION", "text": "London"},
{"type": "ORGANIZATION", "text": "DeepMind"},
{"type": "PERSON", "text": "Demis Hassabis"},
{"type": "LOCATION", "text": "King's Cross"},
{"type": "LOCATION", "text": "San Francisco"}
]
}
Next steps
Wire this function into a FastAPI endpoint so other services can POST text and receive JSON. For retrieval workflows, send the extracted entities through Oxlo.ai's embedding models to build a searchable knowledge graph.
Top comments (0)