DEV Community

shashank ms
shashank ms

Posted on

Single-Task vs Multi-Task Learning in LLM Models

We are building a customer support triage agent that processes incoming tickets using two different LLM strategies. First, we will chain single-task specialists, each optimized for one job. Then we will build a multi-task generalist that handles classification, drafting, and entity extraction in a single call. The comparison will show you exactly where each pattern wins, and why Oxlo.ai's flat per-request pricing makes the cost trade-off easy to reason about.

What you'll need

Step 1: Set up the Oxlo.ai client

I start by instantiating the OpenAI-compatible client against Oxlo.ai. Every snippet in this tutorial reuses this client.

from openai import OpenAI
import json

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

# Quick connectivity check
response = client.chat.completions.create(
    model="deepseek-v3.2",
    messages=[{"role": "user", "content": "Say OK"}],
    max_tokens=10
)
print(response.choices[0].message.content)

Step 2: Build the single-task urgency classifier

The single-task pipeline begins with a classifier that has exactly one job: assign an urgency level. I keep the prompt narrow and set temperature to zero.

CLASSIFIER_PROMPT = """You are an urgency classifier.
Read the customer support ticket and reply with exactly one word: Low, Medium, or High.
Do not explain your reasoning."""

def classify_urgency(ticket: str) -> str:
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": CLASSIFIER_PROMPT},
            {"role": "user", "content": ticket},
        ],
        max_tokens=10,
        temperature=0.0,
    )
    return response.choices[0].message.content.strip()

Step 3: Build the single-task response drafter

Next, a drafter that only writes the reply. I use a strong general-purpose model for coherent tone.

DRAFTER_PROMPT = """You are a support response drafter.
Write a brief, empathetic reply to the customer ticket.
Do not ask follow-up questions unless the ticket is missing critical information."""

def draft_response(ticket: str) -> str:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": DRAFTER_PROMPT},
            {"role": "user", "content": ticket},
        ],
        max_tokens=200,
        temperature=0.7,
    )
    return response.choices[0].message.content.strip()

Step 4: Build the single-task entity extractor

The last specialist pulls structured data. I force JSON mode so the output is predictable.

EXTRACTOR_PROMPT = """You are an entity extractor.
Extract order_id and product_name from the support ticket.
Reply with valid JSON in this exact format:
{"order_id": "...", "product_name": "..."}
If a value is missing, use null."""

def extract_entities(ticket: str) -> dict:
    response = client.chat.completions.create(
        model="deepseek-v3.2",
        messages=[
            {"role": "system", "content": EXTRACTOR_PROMPT},
            {"role": "user", "content": ticket},
        ],
        max_tokens=100,
        temperature=0.0,
        response_format={"type": "json_object"},
    )
    return json.loads(response.choices[0].message.content)

Step 5: Compose the single-task pipeline

I wire the three specialists into a sequential pipeline. Under Oxlo.ai's per-request pricing, this consumes three API requests for every ticket.

def single_task_pipeline(ticket: str) -> dict:
    urgency = classify_urgency(ticket)
    reply = draft_response(ticket)
    entities = extract_entities(ticket)
    return {
        "strategy": "single-task",
        "urgency": urgency,
        "draft_reply": reply,
        "entities": entities,
        "requests": 3,
    }

Step 6: Build the multi-task agent

The multi-task agent does the same work in one shot. The system prompt must be explicit about the three sub-tasks and the required JSON shape.

MULTI_TASK_PROMPT = """You are a support triage agent.
Given a customer ticket, produce a single JSON object with exactly these keys:
- urgency: one of Low, Medium, or High
- draft_reply: a brief empathetic response string
- entities: an object with keys order_id and product_name (null if missing)

Rules:
1. Do not output markdown fences or explanations.
2. Output only valid JSON.
3. Keep draft_reply under three sentences."""

def multi_task_agent(ticket: str) -> dict:
    response = client.chat.completions.create(
        model="kimi-k2.6",
        messages=[
            {"role": "system", "content": MULTI_TASK_PROMPT},
            {"role": "user", "content": ticket},
        ],
        max_tokens=300,
        temperature=0.3,
        response_format={"type": "json_object"},
    )
    result = json.loads(response.choices[0].message.content)
    result["strategy"] = "multi-task"
    result["requests"] = 1
    return result

Step 7: Run both strategies side by side

I execute the same ticket through both paths. Because Oxlo.ai charges per request rather than per token, the cost difference is directly proportional to the number of agent calls, not the length of the context you pass in.

TICKET = (
    "Hi, I ordered laptop #ORD-7782 last week and the battery dies after 30 minutes. "
    "This is unacceptable for a $2,000 machine. Please fix this immediately."
)

if __name__ == "__main__":
    print("=== Single-Task Pipeline ===")
    st_result = single_task_pipeline(TICKET)
    print(json.dumps(st_result, indent=2))

    print("\n=== Multi-Task Agent ===")
    mt_result = multi_task_agent(TICKET)
    print(json.dumps(mt_result, indent=2))

Run it

Save the complete script as agent.py and run it:

python agent.py

Example output:

=== Single-Task Pipeline ===
{
  "strategy": "single-task",
  "urgency": "High",
  "draft_reply": "I'm sorry to hear about the battery issue with your new laptop. We take this seriously and will prioritize a replacement or refund for order #ORD-7782.",
  "entities": {
    "order_id": "ORD-7782",
    "product_name": "laptop"
  },
  "requests": 3
}

=== Multi-Task Agent ===
{
  "strategy": "multi-task",
  "urgency": "High",
  "draft_reply": "We sincerely apologize for the battery issue with your laptop. Our team will expedite a replacement for order #ORD-7782 right away.",
  "entities": {
    "order_id": "ORD-7782",
    "product_name": "laptop"
  },
  "requests": 1
}

Wrap-up

Single-task pipelines give you modular prompts that are easy to tune in isolation, but they multiply latency and request count. Multi-task agents reduce both, yet require tighter prompt engineering to maintain output quality. A practical next step is to add a length-based router: send short tickets to the multi-task agent and long, ambiguous tickets through the single-task chain. If you are running this at volume, the request-based pricing on Oxlo.ai means that routing decision has a direct, predictable impact on your monthly bill.

Top comments (0)