Back to Home

AI for auto-filling job filters

The article describes data-driven pipeline for automatic filling of job search filters on HH, SuperJob and others. LLM analyzes queries, database resolves IDs. 150x token savings, conversion growth.

Auto-filling job search filters AI and DB
Advertisement 728x90

AI-Powered Auto-Fill for Job Search Filters Using a Data-Driven Database

Job seekers often struggle with filters on sites like HeadHunter, SuperJob, Zarplata.ru, and TrudVsem. Analytics reveal that users open the filter panel, enter data haphazardly, get irrelevant results—from thousands of janitor jobs to empty lists—and bounce. Fixes like disclaimers, required fields, and highlights flopped: conversion dropped as users got intimidated or typed nonsense like "job".

Key insight: it's the complexity. Each platform uses unique IDs for cities (HeadHunter has 1,600 with IDs, SuperJob its own), specializations, experience levels. Dumping full dictionaries into an LLM means 140,000 tokens per query (25–40 RUB), hallucinations, or bankruptcy.

Data-Driven AI Pipeline Architecture

The solution leverages an existing database with tables job_filters, job_filter_options, job_service_filters, city_master, and city_source_map. These map canonical values to platform-specific IDs (e.g., Moscow: HeadHunter=1, SuperJob=4).

Google AdInline article slot

The system auto-categorizes filters flagged is_ai_eligible = true:

  • Small dictionaries (≤30 options): experience (noExperience, between1And3), employment (FULL, PART). Sent to the prompt (~400 tokens).
  • Large dictionaries (>30): cities, roles. LLM outputs text ("Moscow"), code resolves IDs from DB.
  • Free text: queries like "Python backend developer".
  • Numbers: salary from resume or LLM.

Prompts are dynamically generated from the DB. Example:

== MULTIPLE-CHOICE FILTERS ==
experience: noExperience="No experience", between1And3="1-3 years"
employment_form: FULL="Full-time"

== DICTIONARY FIELDS ==
city_name: "Moscow"

== TEXT FIELDS ==
text: 2-8 words

Input: resume summary (skills, experience), desired role, target sites. Output—JSON without IDs:

Google AdInline article slot
{
  "text": "Python backend developer",
  "area_name": "Moscow",
  "experience": "between1And3",
  "salary": {"from": 250000}
}

Processing Phases and Resolution

Phase 1: Prompt Generation and LLM Call

BuildSearchFiltersPromptTask assembles the instruction. LLM (GigaChat) parses user intent, picks from small dictionaries, names large ones.

Phase 2: Code Post-Processing

  • Resolution: SearchCitiesAction looks up "Moscow" in city_master, maps to IDs via city_source_map.
  • Adaptation: converts between1And3 to platform API format.
  • Assembly: unified_filters + filter_labels for frontend.

Result: pre-filled filters for all sites. Users review and save.

Scalability: new site/filter—just add DB data; prompt and pipeline adapt automatically.

Google AdInline article slot

Performance Metrics

| Approach | Tokens | Cost per Query | Accuracy |

|----------|--------|----------------|----------|

| Naive (full dictionaries) | 140,000 | 25–40 RUB | Low (hallucinations) |

| Data-driven | 850 + 150 | 0.1 RUB | High (DB resolution) |

Savings: 150x. Search bounce rate dropped, average revenue per user from paid features rose.

Key Takeaways

  • Role separation: LLM handles semantics, DB does ID mapping—cuts tokens and errors.
  • Auto-classification: 30-option threshold is dynamic; new filters integrate code-free.
  • JSON output: Strict LLM format simplifies parsing.
  • Scale: Handles thousands of users without cost spikes.
  • UX: Auto-fill lowers entry barriers.

— Editorial Team

Advertisement 728x90

Read Next