Hasan Hüseyin Yurdagül
← All projects

Selected project

MdsAI

Deployed · Active R&D

Four years of municipal helpdesk history turned into retrieved evidence, LLM answer drafts, and routing suggestions that a support expert approves before anything reaches a customer.

MdsAI is the AI layer of Universal Software’s support desk for FlexCity, the company’s city-management platform, which runs in 84 municipalities: 14 metropolitan and 70 district municipalities. A new ticket arrives; the platform retrieves solved tickets that look like it, drafts an answer with an LLM from their approved solutions, and suggests where the ticket should go. A support expert reviews, edits, accepts, or rejects every draft before it reaches a customer.

I lead the AI and data work: corpus preparation, retrieval and model research, evaluation, and the integration with the ticket workflow, working with support experts on what useful behavior looks like and with software engineers on where it lives. Since the assistant went into the workflow, median first-response time has fallen by half.

The problem

The helpdesk had years of useful solutions, but they were buried in event logs. Keyword search missed tickets that described the same fault in different words, the same problems were solved again and again, and categorization, assignment, and deadline-risk decisions depended on who happened to pick up the ticket.

The source contained 132,497 process-log rows for 29,118 tickets from 2022 to 2025. One ticket could appear dozens of times as comments, status changes, and reassignments piled up, and the fields mixed missing values, placeholders, SQL fragments, Turkish domain vocabulary, and product-specific error codes.

New support tickets per year, with the highest recorded volume in 2025

So the first job was not prompting an LLM. It was building a knowledge source worth retrieving from.

Building the corpus

A Polars and Parquet pipeline standardizes identifiers and timestamps, turns placeholder values into nulls, keeps technical tokens intact, and folds event histories into one record per ticket.

Corpus measureValue
Raw process-log rows132,497
Normalized analysis rows130,168
Unique tickets29,118
Closed, resolution known28,369
Closed with a written solution27,188
Training-grade after semantic review15,404

The cleaned history also showed why the desk needed help. Median resolution took about seven days, 28.7% of resolved tickets took longer than four weeks, and only 20.6% were resolved within a day. Of 20,282 tickets with both a planned and an actual closing date, 98.5% closed after the planned date, so the planning field was not a usable estimate.

Distribution of eligible closed tickets by resolution time

Semantic filtering, with people deciding

A syntactically valid ticket is not necessarily a good example. Test records, thank-you replies, template answers, and solutions without technical content would all pollute retrieval and supervised training.

I embedded ticket text with google/embeddinggemma-300m, reduced it with UMAP, and grouped dense regions with HDBSCAN. The clustering did not decide what was good. It changed the size of the review: support experts and I judged coherent groups instead of reading 29,000 tickets one by one. The first curation pass kept 79 clusters holding 15,404 tickets, 52.9% of the original set.

Human-reviewed data funnel from raw tickets to the training-grade corpus

Those 79 groups are for quality control. They are separate from the 281 BERTopic clusters used later to analyze support themes and trends.

Choosing the embedding model

Retrieval, duplicate detection, clustering, and classification all sit on the embedding layer. I compared four model families with three downstream classifiers on 4,500 labeled tickets, measuring quality alongside memory and encoding time.

Embedding benchmark balancing downstream score, memory use, and encoding time
ModelMemoryEncode timeMean downstream score
TRModel~384 MB8 s0.892
Qwen2,274 MB45 s0.892
EmbeddingGemma578 MB16 s0.914
E5-Large2,136 MB24 s0.937

E5-Large scored highest, but EmbeddingGemma became the workhorse: within 2.3 points while using about a quarter of the memory and encoding 33% faster.

The same work exposed a taxonomy problem. The source system had 194 category labels, including near-duplicates and classes with fewer than ten examples; predicting them gave about 0.14 macro-F1. Support experts consolidated them into seven operational groups, on which the model reached 0.46 macro-F1 and 0.67 accuracy. Those are different prediction tasks, so the result argues for redesigning the taxonomy rather than showing a threefold better model.

Measuring retrieval on real questions

Retrieval quality decides whether a draft is grounded, so I built a benchmark from the questions users actually wrote: 151 historical questions, each paired with the ticket that solved it, hidden among 2,000 distractor tickets, plus 500 questions with no correct answer to test abstention.

Recall@1 and Recall@5 for character n-gram, word, hybrid and dense retrieval on 151 raw support questions, scoped to the user's product
Method (raw questions)Recall@1, all productsRecall@1, scopedRecall@5, scoped
Character n-gram54.3%79.5%97.4%
Word41.7%70.9%92.7%
Hybrid (RRF)36.4%74.2%95.4%
Dense (MiniLM)22.5%55.6%81.5%

Two findings changed the design. First, scoping the search to the product the user is on matters more than the retrieval method: it lifts character n-gram Recall@1 from 54% to 80%. Second, on raw Turkish support text full of error codes, module names, and misspellings, character n-grams beat a general dense model by 24 points at Recall@1. When the same questions were rewritten into clean form, every method scored above 85% scoped Recall@1, which says most of the difficulty is in how people write tickets, not in the solved cases.

This is an offline benchmark on historical tickets. It measures whether the right evidence reaches the drafting step, not how good the final answers are.

The workflow

The assistant retrieves similar solved tickets and passes their approved solutions as context to a language model running on Universal’s own servers. The draft appears in the support workflow next to the cases it was built from, and an expert stays responsible for the answer. The LLM speeds the expert up; it does not answer customers on its own.

Models on our own servers

Municipal support tickets carry citizen and institution data, so the drafting models run on-premises. I fine-tuned Gemma 4 (12B and 27B) and Qwen models of similar size on the desk’s Turkish support language, its module names, error codes, and the way people actually write tickets, and serve them with vLLM so many tickets are drafted in parallel. A draft comes back in under a minute, no ticket leaves the building, and the cost per ticket is close to zero because there is no per-token bill.

Routing is moving the same way. Ticket categories and assignments are often wrong because people file tickets in a hurry, and the current fix is an embedding model plus a classifier. I am replacing it with decision models such as Jev, Laya, and Clef: instead of generating text, they read the ticket and return a calibrated probability for each queue or category the desk defines, so a low-confidence ticket can go to a person instead of the wrong team.

StateCapability
DeployedRetrieval of solved cases, evidence-backed answer drafts from fine-tuned Gemma 4 / Qwen models served on-premises with vLLM, routing suggestions, expert approval in the workflow
Measured researchCorpus filtering, embedding benchmark, taxonomy redesign, retrieval benchmark, 281-cluster topic analysis
Active developmentDecision models (Jev, Laya, Clef) for auto-routing and for correcting misfiled ticket categories, replacing the embedding-plus-classifier models; assignee and resolution-time models, SLA-risk signals, anomaly detection, trend reporting

What I took from it

  • An LLM system is only as good as its knowledge base. Most of the work went into deciding which solved cases deserve to be retrieved.
  • Review belongs in the architecture. Support experts govern both the corpus and every customer-facing answer, and their rejections feed the next evaluation.
  • Simple retrieval can win. On this text, product scoping and character n-grams beat a general-purpose dense model; the benchmark, not intuition, decided that.
  • Owning the model fits the public sector. Fine-tuned open models on our own servers keep citizen data in house and bring the cost of a draft close to zero.
  • A label space can be the bottleneck. Redesigning 194 categories into seven gave the team a prediction task it could act on.