DEV Community

shashank ms
shashank ms

Posted on

Using LLM for Topic Modeling

We are going to build a lightweight topic modeling pipeline that feeds raw text snippets into an LLM and returns a structured taxonomy of themes. It is a direct replacement for classical LDA when you need results in minutes instead of days, and it works especially well on short, noisy documents like support tickets or app reviews.

What you'll need

Step 1: Configure the Oxlo.ai client

I start by instantiating the OpenAI-compatible client pointing at Oxlo.ai. Because Oxlo.ai uses flat per-request pricing, I do not need to worry about token costs creeping up as I pass long documents or verbose prompts. See https://oxlo.ai/pricing for details.

from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

Step 2: Prepare the document list

I hardcode six raw support tickets so the script is fully runnable without external dependencies. In production I would read from a CSV or database.

raw_docs = [
    "The login button is broken on mobile Safari after the latest update.",
    "I love the new dark mode, but the contrast is too low in the sidebar.",
    "Billing receipt never arrived. Support took 3 days to respond.",
    "Feature request: export to CSV from the dashboard.",
    "Dark mode makes text unreadable. Please fix the font colors.",
    "Login fails with a 500 error when I use SSO.",
]

Step 3: Define the system prompt

The system prompt forces structured JSON output so I can parse topics programmatically. I keep it strict to avoid markdown fences or extra narration.

SYSTEM_PROMPT = """You are a topic modeling assistant. Read the user-provided text and extract the main topics.

Rules:
- Output ONLY a JSON array of strings.
- Each string is a concise topic label, 2 to 4 words long.
- Use lowercase with underscores, e.g., "mobile_login_bug".
- Return 1 to 3 topics per document.
- Do not add markdown, explanations, or code fences."""

Step 4: Extract topics from every document

I loop over the documents and call Oxlo.ai for each one. Because Oxlo.ai charges a flat rate per request, the cost is predictable even if some tickets are long rants.

import json

def extract_topics(document: str) -> list[str]:
    user_message = document

    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )

    return json.loads(response.choices[0].message.content)

topics_per_doc = [extract_topics(doc) for doc in raw_docs]
print(topics_per_doc)

Step 5: Consolidate into a ranked taxonomy

Now I flatten the lists, count frequencies, and sort to get the final topic model. This gives me a human-readable dashboard of what is actually being discussed.

from collections import Counter

flat_topics = [t for sublist in topics_per_doc for t in sublist]
topic_counts = Counter(flat_topics)

for topic, count in topic_counts.most_common():
    print(f"{topic}: {count}")

Run it

Save the full script as topic_model.py, set your API key, and run python topic_model.py. You should see output similar to this:

[
  ["mobile_login_bug", "safari_compatibility"],
  ["dark_mode_ui", "contrast_accessibility"],
  ["billing_receipt_issue", "support_response_time"],
  ["feature_request_csv", "dashboard_export"],
  ["dark_mode_ui", "font_readability"],
  ["sso_login_error", "server_error_500"]
]

dark_mode_ui: 2
mobile_login_bug: 1
safari_compatibility: 1
contrast_accessibility: 1
billing_receipt_issue: 1
support_response_time: 1
feature_request_csv: 1
dashboard_export: 1
font_readability: 1
sso_login_error: 1
server_error_500: 1

Next steps

Replace the hardcoded list with a CSV reader and process hundreds of tickets in a batch loop. If you need higher reasoning fidelity for ambiguous documents, swap the model string to kimi-k2.6 or deepseek-v3.2 without changing any other code.

Top comments (0)