XLM-RoBERTa Job Taxonomy — Sales (German)

License Language Base Categories

Fine-tuned xlm-roberta-base for classifying German sales and distribution job listings into 8 sales subcategories.

Part of the JobBlast taxonomy model family — a system for automated classification of German-language job postings. This model provides fine-grained classification within the Sales & Distribution top-level category, distinguishing field sales, inside sales, retail, key account management, technical sales, business development, sales leadership, and sales operations that the broader main taxonomy collapses into a single bucket.


Test Metrics

Metric Value
Accuracy 92.65%
F1 macro 87.95%
F1 weighted 92.72%

Evaluated on a held-out test set of 1,115 German sales job listings.

Per-class results

Category Precision Recall F1 Support
Retail & Store Sales 0.982 0.982 0.982 500
Inside Sales & Telesales 0.951 0.879 0.913 132
Field Sales & Outside Sales 0.925 0.876 0.900 226
Key Account & Account Management 0.879 0.892 0.885 65
Business Development & Strategic Sales 0.852 0.868 0.860 53
Technical Sales & Sales Engineering 0.824 0.875 0.848 48
Sales Operations & Support 0.759 0.936 0.838 47
Sales Management & Leadership 0.760 0.864 0.809 44

The gap between F1 macro (0.879) and F1 weighted (0.927) reflects the underlying class imbalance — Retail & Store Sales alone makes up 45% of the test set and reaches F1 0.982, while smaller and semantically harder categories (Sales Management, Sales Operations, Technical Sales) sit in the 0.81–0.85 range.


Label Schema

Label Typical signals in German job ads
Field Sales & Outside Sales Außendienst, Außendienstmitarbeiter, Vertrieb im Außendienst, Gebietsverkaufsleiter, Reisetätigkeit, Kundenbesuche vor Ort, Firmenwagen
Inside Sales & Telesales Innendienst, Vertriebsinnendienst, Telesales, Telefonverkauf, Kundenbetreuung am Telefon, Angebotserstellung, Auftragsannahme
Retail & Store Sales Verkäufer, Verkäuferin, Einzelhandelskaufmann, Verkaufsberater, Filiale, Ladengeschäft, Kassentätigkeit, Warenpräsentation
Key Account & Account Management Key Account Manager, Account Manager, Großkundenbetreuung, Bestandskundenbetreuung, strategische Kundenbeziehungen
Technical Sales & Sales Engineering Vertriebsingenieur, Sales Engineer, Technischer Vertrieb, Applikationsingenieur, technische Beratung, erklärungsbedürftige Produkte
Business Development & Strategic Sales Business Development Manager, Geschäftsentwicklung, Neukundenakquise, Markterschließung, strategische Partnerschaften
Sales Management & Leadership Vertriebsleiter, Verkaufsleiter, Head of Sales, Führungsverantwortung, Teamführung, Vertriebssteuerung, Umsatzverantwortung
Sales Operations & Support Sales Operations, Vertriebsassistenz, Sales Support, CRM-Pflege, Auftragsabwicklung, Vertriebscontrolling, Angebotsmanagement

Key disambiguations

  • Field Sales vs Inside Sales is decided by where the work happens: Außendienst (travel, on-site customer visits) → Field Sales; Innendienst / Telesales (office or phone) → Inside Sales.
  • Sales Management & Leadership requires personnel / team responsibility (Führungsverantwortung). An individual contributor with the title "Sales Manager" but no team goes to the relevant selling category (Field / Inside / Key Account), not here.
  • Technical Sales & Sales Engineering is for technically complex, explanation-heavy products requiring an engineering background — distinct from general Field or Inside sales.
  • Retail & Store Sales is point-of-sale work in a store (Einzelhandel), not B2B field sales.
  • Sales Operations & Support is back-office / enablement with no own selling quota (CRM, order processing, sales controlling) — distinct from quota-carrying selling roles.
  • Key Account Management focuses on existing strategic accounts; Business Development is about opening new markets and acquiring new customers.

Repository Structure

Ashybalka/xlm-roberta-taxonomy-sales-de/
├── config.json                    # shared — label map, model config
├── tokenizer.json                 # shared — fast tokenizer
├── tokenizer_config.json          # shared
├── sentencepiece.bpe.model        # shared
├── special_tokens_map.json        # shared
├── test_metrics.json              # evaluation results
├── classification_report.txt      # full per-class report
│
├── pytorch/
│   ├── config.json                # needed for from_pretrained(subfolder=)
│   └── model.safetensors          # GPU inference / fine-tuning (~1.1 GB)
│
├── onnx/
│   └── model.onnx                 # CPU fp32 inference (~1.1 GB)
│
└── onnx-int8/
    └── model_quantized.onnx       # CPU INT8 quantized (~280 MB, 3-4× smaller)

Usage

Input Format

[Job Title] [SEP] [Job Description]
text = "Vertriebsmitarbeiter im Außendienst (m/w/d) [SEP] Betreuung von Bestandskunden " \
       "in der Region Süd, Neukundenakquise, Reisetätigkeit, Firmenwagen wird gestellt."

PyTorch (GPU / fine-tuning)

from transformers import pipeline
clf = pipeline(
    "text-classification",
    model="Ashybalka/xlm-roberta-taxonomy-sales-de",
    subfolder="pytorch",
    device=0,  # GPU; -1 for CPU
)
result = clf("Verkäufer im Einzelhandel [SEP] Beratung von Kunden, Warenpräsentation und Kassentätigkeit in unserer Filiale.")
print(result)
# [{'label': 'Retail & Store Sales', 'score': 0.9831}]

ONNX fp32 (CPU inference)

from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer, pipeline
model     = ORTModelForSequenceClassification.from_pretrained(
                "Ashybalka/xlm-roberta-taxonomy-sales-de",
                subfolder="onnx"
            )
tokenizer = AutoTokenizer.from_pretrained("Ashybalka/xlm-roberta-taxonomy-sales-de")
clf       = pipeline("text-classification", model=model, tokenizer=tokenizer)
result = clf("Key Account Manager [SEP] Strategische Betreuung unserer Großkunden, Ausbau bestehender Geschäftsbeziehungen.")
print(result)
# [{'label': 'Key Account & Account Management', 'score': 0.9412}]

ONNX INT8 (CPU, lightweight)

from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer, pipeline
model     = ORTModelForSequenceClassification.from_pretrained(
                "Ashybalka/xlm-roberta-taxonomy-sales-de",
                subfolder="onnx-int8"
            )
tokenizer = AutoTokenizer.from_pretrained("Ashybalka/xlm-roberta-taxonomy-sales-de")
clf       = pipeline("text-classification", model=model, tokenizer=tokenizer)

Direct ONNX Runtime (no transformers)

For production FastAPI services or environments without transformers:

import json
import numpy as np
import onnxruntime as ort
from huggingface_hub import snapshot_download
from tokenizers import Tokenizer
# download model
path = snapshot_download(
    "Ashybalka/xlm-roberta-taxonomy-sales-de",
    allow_patterns=["onnx/model.onnx", "tokenizer.json", "config.json"]
)
# load
session   = ort.InferenceSession(f"{path}/onnx/model.onnx",
                                  providers=["CPUExecutionProvider"])
tokenizer = Tokenizer.from_file(f"{path}/tokenizer.json")
tokenizer.enable_truncation(max_length=510)
tokenizer.no_padding()
with open(f"{path}/config.json") as f:
    labels = [v for _, v in sorted(json.load(f)["id2label"].items(), key=lambda x: int(x[0]))]
vocab    = tokenizer.get_vocab()
bos, eos = vocab["<s>"], vocab["</s>"]
def classify_sales(title: str, description: str) -> dict:
    text     = f"{title} [SEP] {description}"
    encoding = tokenizer.encode(text, add_special_tokens=False)
    ids      = [bos] + encoding.ids + [eos]
    mask     = [1] * len(ids)
    logits = session.run(None, {
        "input_ids":      np.array([ids],  dtype=np.int64),
        "attention_mask": np.array([mask], dtype=np.int64),
    })[0][0]
    exp   = np.exp(logits - logits.max())
    probs = exp / exp.sum()
    idx   = int(np.argmax(probs))
    return {"category": labels[idx], "confidence": round(float(probs[idx]), 4)}
print(classify_sales(
    "Vertriebsingenieur",
    "Technische Beratung und Verkauf erklärungsbedürftiger Maschinen, Schnittstelle zwischen Kunde und Entwicklung."
))
# {'category': 'Technical Sales & Sales Engineering', 'confidence': 0.9145}

Training Details

Parameter Value
Base model FacebookAI/xlm-roberta-base
Training samples 11,186 German sales job listings (majority class Retail & Store Sales capped at 5,000)
Labeling LLM consensus (3-model voting: Qwen3-4B + Gemma-2-9B + Llama-3.1-8B)
Agreement filter 2/3 or 3/3 required (≈81.6% at 3/3, ≈18.4% at 2/3 after capping)
Soft labels Vote distribution used as soft targets
Max length 512 tokens
Learning rate 2e-5
Epochs 5 (early stopping)
Class weighting Balanced

Class distribution in training data

Counts after capping the majority class at 5,000 samples:

Category Count Share
Retail & Store Sales 5,000 44.7%
Field Sales & Outside Sales 2,262 20.2%
Inside Sales & Telesales 1,329 11.9%
Key Account & Account Management 657 5.9%
Business Development & Strategic Sales 531 4.7%
Technical Sales & Sales Engineering 485 4.3%
Sales Operations & Support 476 4.3%
Sales Management & Leadership 446 4.0%

Retail & Store Sales was capped from 8,339 raw samples down to 5,000 to limit its dominance. The remaining 11.2× imbalance ratio between Retail & Store Sales and Sales Management & Leadership is handled through balanced class weights at training time. Despite the imbalance, even the smaller selling categories (Key Account, Business Development) reach F1 ≥ 0.86 — soft-label training and class weighting compensate effectively when the LLM consensus on the class is clean.


Limitations

  • Optimized for German sales job listings only — performance on other languages or non-sales jobs is not validated. Use the main taxonomy model first to route only listings tagged as Sales & Distribution into this classifier.
  • Sales Operations & Support (F1 0.838) has high recall (0.936) but lower precision (0.759) — generic administrative or back-office roles in a sales department are sometimes pulled into this class. This is the noisiest class by far: 57% of its training samples had inter-model disagreement (only 2/3 consensus), reflecting a genuinely fuzzy boundary with administration and sales support.
  • Sales Management & Leadership (F1 0.809) is the weakest class — the boundary between an IC "Sales Manager" and a manager with team responsibility is often ambiguous in German job ads, where "Manager" does not reliably imply Führungsverantwortung. 41% of its training data had inter-model disagreement.
  • Business Development & Strategic Sales (F1 0.860) overlaps with Key Account and Field Sales on growth-oriented roles — 35% inter-model disagreement in training.
  • Technical Sales & Sales Engineering (F1 0.848) overlaps with Field Sales on technically-flavored outside-sales roles (27% disagreement); listings combining both signals may go either way.
  • The model classifies the role described in the job ad, not the qualifications of any candidate.
  • Inputs longer than 512 tokens are truncated — title and the first paragraph of the description carry most of the role signal.

Related Models

Model Categories Use case
xlm-roberta-taxonomy-main-de 21 top-level Industry / field classification
xlm-roberta-taxonomy-it-de 14 IT subcategories Detailed IT role classification
xlm-roberta-taxonomy-healthcare-de 11 healthcare subcategories Fine-grained classification within healthcare jobs
xlm-roberta-taxonomy-seniority-de 5 grades Experience-level classification, orthogonal to industry
xlm-roberta-taxonomy-sales-de (this model) 8 sales subcategories Fine-grained classification within sales jobs

A typical JobBlast pipeline: the main model assigns the top-level category. Listings tagged as Sales & Distribution are passed to this model for fine-grained role classification (Field Sales, Retail, Key Account, etc.).

Downloads last month
2
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for Ashybalka/xlm-roberta-taxonomy-sales-de

Quantized
(26)
this model