spec / applied-ai
ru en
open to offers
Senior / Lead Applied AI · remote · UTC+3

LLM systems
for revenue
and analytics

Dmitry Prom · AI Engineer & Data Analyst (LLM-based analytics)

$ conversation → transcript → scoring → structured data → decision

I build systems that take manual work off a sales floor: a customer conversation becomes verifiable data. And I do the analysis on top of that data — the analysis behind decisions on sales, marketing, product and pricing.

remote UTC+3 5 years in engineering, 2 in AI open to teams abroad RU / EN

example trace · synthetic data one conversation, end to end
00.118stttranscript, speaker separation
00.402filterduration and content filter
00.688retrievepolicy and customer record into context
00.977checkschecklist criteria, output schema
01.240summarysummary fields and detectors
01.361evalgolden-set check, release gates
01.640deliverCRM, BI and the stakeholder report
sttbusiness rules llm orchestration evalsrag voice agents crm / bi

This is a diagram, not a monitor: the steps show the processing order. No value on this page is pulled from a live system.

§01 / scale

Production systems on real commercial processes

every number comes with its denominator

90

production pipelines running the flow without a human in it

denominator — scenarios moved to automatic processing

100%

of eligible conversations evaluated, instead of ≤20% manual sampling

denominator — conversations passing the duration and content filter

98%

agreement between AI and expert decisions

denominator — 500 deals in a frozen golden set

−88%

cost of the key LLM scenario per 1,000 deals

with output schema, benchmark and quality gates unchanged

464

checklist criteria

246

summary fields and detectors

55 / 32

active checklists and summary configurations

≥ 1M RUB

monthly contact-centre saving · details on request

§02 / measurement layer

How the key metrics are computed

sample · denominator · comparison rule

Every result has a fixed denominator and comparison rule — without them a figure means nothing. Public repositories reproduce these calculations and quality controls on synthetic data.

metric denominator comparison rule value
01 Evaluation coverage Conversations that pass the duration and content filter How many of them are scored automatically — against the manual sample of the old process 100% / ≤20%
02 Decision agreement 500 deals in a frozen set, adjudicated by experts The model's decision against the expert verdict on each deal. Missed critical violations and error classes are checked against a separate release-blocking threshold: an average hides them 98%
03 Model economics Cost of the scenario per 1,000 deals Before and after the migration, with the output schema, benchmark and quality gates unchanged; prices frozen as a dated snapshot −88%
04 Voice AI impact Eligible routine consultations for the share; the previous process for the leads The share handled without an operator, and the qualified-lead lift in month one 45–50% · ×1.2
05 Contact-centre saving Cost of servicing the same consultation flow Before and after automation, RUB per month ≥ 1M RUB

§03 / main project · major edtech platform (RU)

AI quality control across every customer communication

from manual sampling to full coverage

Quality control used to listen to a manual sample of calls. Now the communication flow is transcribed, filtered, scored against checklists and turned into structured data for managers, CRM and BI — covering every employee who talks to customers.

I built this loop end to end: platform logic, system prompts, model selection, pipelines, scoring rules, delivery and calibration on live traffic.

01

CRM & telephony

calls, chats, deals, metadata

02

Transcription

speaker separation and text normalisation

03

Pipeline engine

filters, tags, failure actions

04

LLM layer

checklist scoring, summaries, semantic analytics

05

PostgreSQL / BI / CRM

data where the team already works

closed loop

A system that checks itself

Four golden sets — reference sets with expert labels — for different tasks: scoring, summaries, semantic analytics, violations. Human calibration, regression gates and error analysis after every model or prompt change. Critical misses block the release — average accuracy is not enough.

→ how sets like these are built, adjudicated and frozen

what it delivered

Evaluation stopped being a sample

A manager no longer sees an opinion based on ten calls, but the whole flow: where policy is broken, where deals are lost, which objections go unanswered. The analytics in the next section run on the same data — one system, not two.

§04 / analytics

The analysis behind the decisions

sales · marketing · product and pricing · competitors

The second half of my job starts where the pipeline ends. Tasks arrive from the business as tickets with a goal and an economic rationale: 'find out why conversion dropped', 'assess demand for this programme', 'understand why existing customers call sales'.

I build the cut, validate the sample and deliver an answer that can be acted on: what is happening, what supports it, and what the data cannot show. Reports are discussed with department heads and top management; each has a stakeholder and a usefulness score.

thousands of

deals in a single study

up to six months

period-comparison horizon

dozens of features

per deal in a deep-dive study

every channel

calls and chats of every employee who talks to customers

case · sales and traffic

business request"Find the reasons behind the May conversion drop and the shift in plan mix"

Conversion fell somewhere else than expected

Every substantive conversation for a product line across three months: unanswered and empty calls were excluded from the base, not diluted into percentages. Dozens of features per deal — need, purchase readiness, plan, objections and how they were handled, competitors mentioned, rep behaviour, coverage of new pitch blocks.

The month-over-month view showed the problem was not the sales team: inbound traffic was cooling, the share of purchase-ready customers was falling, money objections were growing. Observations are separated from explanations — 'the share of hot leads fell' is a fact, 'therefore revenue dropped' is a hypothesis, labelled as one, with a note on how to test it.

→ decisions on traffic buying, script and pricing pitch.

case · product and pricing

business request"Reasons for refusal, and whether customers ask for further-education programmes"

"Too expensive" is not always about price

Records that did not pass through the service were excluded explicitly — with the loss stated in the report rather than quietly dropped. The sample is defined by a filter: conversations over five minutes on a specific product line. Reasons for no purchase are broken down on two levels: a top-level category first, then a second-level breakdown of the two largest groups.

The second level changes the decision. 'Cost' at the top looks like a discount request, but inside the group something else dominates — the customer cannot get instalment financing. That is not a pricing problem, it is a payment-instrument problem. Every category is backed by a customer quote, so the conclusion can be re-checked instead of taken on trust.

→ payment scenarios, handling financing rejections, and a separate demand assessment for programmes with a formal diploma.

case · operations and lost revenue

business request"Understand why existing customers contact sales and find growth points in the customer journey"

Part of the sales team's load is not sales

Every deal closed under the 'existing customer' reason across several months. The report states explicitly how many requests reached the calculation and what did not. Each request is classified by meaning and by owner: sales, refunds or support, plus a month-over-month view to tell a one-off spike from a persistent load.

Separately I looked for lost sales: cases where the customer actually wanted to buy something new, but the deal was closed as 'existing customer'. It also turned out that a significant part of the inbound flow is service questions and work with money already paid. That is not only load on the wrong team: while those requests sit in the denominator, the team's conversion rate is measured wrong.

→ routing requests between teams, returning lost deals to sales, and a correct conversion denominator.

in every report, without exception

  • Sample control: how many records were included, how many were lost and why — before any percentages.
  • A denominator for every share, and the same one when periods are compared.
  • Observation and explanation are kept apart: a hypothesis is called a hypothesis and comes with a way to test it.
  • Every category is backed by a customer quote, and a separate sheet lets the stakeholder verify the labelling by hand.
  • A limitations section: what the data does not show and which conclusions it cannot support.

why this is fast

One chain from conversation to decision

I do not wait for an export from a neighbouring team. Feature extraction is part of the system I built myself, so I know where every field comes from, where the model errs most often and which sample can be trusted. A new business question usually means a new cut of already-labelled data, not a new project from scratch.

→ the same methodology on synthetic data, with code and tests

§05 / engineering decisions

What I chose and what I turned down

decision · alternative · revisit condition

stt

A managed speech service instead of self-hosted Whisper

Chose a managed speech-recognition service: quality on spontaneous phone speech and speaker separation out of the box, a predictable per-minute price, and nothing to operate — no hardware, no on-call.
Turned down self-hosted Whisper on GPU: cheaper at volume, but that means hardware, a queue, on-call duty and quality loss on noisy lines that I would have to fix myself.

I will revisit it when volume makes the price gap larger than the cost of operations: then a hybrid — bulk traffic in-house, hard recordings in the cloud.

→ the runtime where this latency is budgeted stage by stage

retrieval

pgvector instead of a dedicated vector database

Chose pgvector in the same PostgreSQL: search lives next to the business filters — customer, product, period. One query instead of two stores and the sync between them.
Turned down a dedicated vector database: faster on millions of vectors and richer in filtering, but another service, another backup policy and another point of failure for a gain invisible at current volume.

The migration threshold is set in advance: when retrieval time becomes noticeable next to model time, or the index stops fitting in memory.

→ retrieval strategies compared at different corpus sizes

evaluation

Model scoring against a frozen label set

Chose an LLM judge and an expert golden set: criteria change together with the policy, and the judge explains its decision — which can be shown to a manager and challenged.
Turned down training a classifier per criterion: more stable and cheaper at inference, but every policy edit needs new labelling, and there are dozens per quarter.

The price is judge drift when the model version changes. That is why the set is frozen and every comparison runs on the same labels.

→ how a set is frozen and how tampering is caught

migration to a cheaper model

What breaks first and how it is caught

When a scenario moves to a model several times cheaper, overall quality is not what falls first. Long context and format stability break first: invalid output schemas appear more often, and recall drops on rare critical categories. Average accuracy looks fine and shows nothing.

So the release is gated on two things: schema validity and recall on critical violations. The fixes are context compression, moving part of the rules from the prompt into code, examples for the failing classes, and a separate pass for critical categories.

The result is the same validated output at −88% scenario cost. Where the cost of a mistake is high, a human stays in the loop: a deliberate limit, not an unfinished feature.

→ the metrics and gates this was checked against

§06 / my own product · independent saas · leadchat.online

Lead Chat: a pay-per-result AI sales platform

50 ₽ per created lead — not per message

A real product, not a demo: the agent runs a goal-driven dialogue, qualifies the customer, handles objections, answers from the knowledge base and takes actions — books, captures the contact, pushes the lead into CRM.

Knowledge base

Websites and office files are normalised into chunks and embeddings, indexed in pgvector with keyword search as a fallback.

Agent runtime

Business goal, dialogue stages, qualification, objections, grounding and behavioural limits. History does not go into context wholesale: recent turns verbatim, earlier ones compressed into dialogue state and captured fields — otherwise cost and latency grow with every turn.

Actions & integrations

Function calling for lead capture, online booking and business actions; amoCRM, Bitrix24, Telegram, email.

Platform & billing

Web widget, background jobs, result-based billing and conversion analytics.

why the architecture is what it is

Pay-per-result dictates the rest: you cannot charge for a lead until a lead is defined in code. A lead counts not when a dialogue happened, but when the agent has captured the required fields and they passed validation. That is where the goal, the stages and the completeness check before closing come from.

who does what

I own the product concept, the AI logic and the core architecture. A development partner works with me on the technical side: selected components and code testing. Product metrics are confidential — I go through them separately.

Next.jsNode.jstRPCPrismaPostgreSQL / pgvectorRAGtool callingbackground jobspayments

§07 / production-systems

A voice agent, enterprise RAG, evaluation and model economics

a prompt is one component out of ten

voice ai

45–50%

of eligible routine consultations run without an operator

I turned the contact-centre policy into a live dialogue: script branching, clarifications, barge-in, answers from the knowledge base. Connected to Sipuni telephony, it holds 10 concurrent lines, works around the clock and does not depend on which rep picked up.

Latency is the binding constraint of the channel: 3 seconds to the first reply, up to 10 seconds between replies. It is the sum of speech recognition, one model call carrying the script and knowledge-base context, and speech synthesis. It shrinks not by swapping the model but by how early recognition starts and how much context the request carries.

Barge-in and dialogue-branch control live in the system prompt rather than a separate state machine. Policy edits ship without a release, but the whole dialogue policy sits in one contract — so its changes are checked against the reference set exactly like code.

Hence ×1.2 qualified leads in month one and a saving from 1M RUB per month: more answered calls, round-the-clock coverage, full script coverage and consistent product knowledge.

→ the runtime behind a dialogue like this: stages, barge-in, latency budget

enterprise rag

100+

daily internal users

Two Dify assistants answer staff questions from internal documents — that is what RAG means: the model answers from retrieved fragments rather than from memory. One for sales, one over the corporate Confluence base, 37 documents, purely vector retrieval.

I owned chunking, context assembly, grounding and answer quality. An employee gets an answer with a source link in under 10 seconds instead of roughly five minutes of manual search.

→ retrieval strategies compared and answer grounding checked

Hybrid retrieval is not needed here: keyword matching pays off once queries carry exact part numbers, version strings and rare terms — on a corpus this size it would add complexity without a result. The real work is not the model but document preparation, and making the assistant honestly say 'this is not in the documents'.

llm evaluation

4

task-specific golden sets

Separate sets and metrics for scoring, summaries, semantic analytics and violations. Human calibration, regressions and error analysis after every model change. 98% decision agreement — on a frozen set of 500 deals.

→ methodology and code in the public repository

model economics

−88%

of the key LLM scenario cost

I moved the same validated output from an expensive model to a compact one through prompt, context and pipeline work. The vendor price gap is only half the story: without context compression and a reworked output schema the cheap model does not pass the gates.

I measure cost per 1,000 deals and freeze a dated pricing snapshot — otherwise a before/after comparison means nothing.

§08 / method and stack

One person owns the whole path: from policy to decision

01

Formalise

turn policy and edge cases into verifiable behaviour

02

Build

prompts, output schemas, retrieval, orchestration, storage and APIs

03

Measure

golden sets, human calibration, regressions, error taxonomy

04

Deploy

CRM, BI and the workflows where the team already is

05

Explain

a report with its limits and the decision that follows

in production, under my responsibility

PythonTypeScriptFastAPINode.jsPostgreSQLpgvectorDockerOpenAI APIAnthropic APIGigaChatYandexGPTDifyRAGAI AgentsStructured OutputsTool CallingLLM-as-a-JudgeVoice AICRM / BISQLGit

worked with, outside that loop

LangChainLangGraphQdrantvLLMHugging FaceFine-tuning / LoRARAGASA/B TestingGuardrailsPrompt InjectionNLP

A deliberate split: on the left, what runs on real traffic and what I am responsible for; on the right, what I have worked with outside that loop.

§09 / positioning

Prompt engineering is one layer. I own the whole system.

I work where AI engineering, analytics and product meet. I take a task phrased as 'make this stop being done by hand' and carry it to a system running on real traffic — and to a report someone makes a decision on.

I do not manage people: I work alongside developers and own the AI loop myself — from business policy and prompts to pipelines, evaluation, CRM delivery and the analytics on top. In meetings with department heads and top management I am the person who turns a business question into something measurable, and back into a decision.

engineering artefacts

The public repositories hold what production holds, but on synthetic data: the prompts themselves as versioned contracts with output schemas, the metrics and release gates, a finished analytical report. Everything runs with one command and no model key.

→ six repositories and what is in each

§10 / public code

Six repositories you can open and run

over 10,000 lines of python · no dependencies · no model key

Each runs with one command — offline, no model key, no third-party dependencies, on synthetic data. Each has its own tests and CI that check not only that the code works but that the guards fire: a record edited after freezing, a prompt without an output schema, a reply with a link in a voice channel, an answer with an invented number.

evaluating llm output

llm-evaluation-harness

Four task families, a typed error taxonomy, bootstrap intervals and release gates. Critical recall is gated separately from average accuracy — those are exactly the misses an average hides.

→ open the repository · about 2,300 lines

tests and CI on Python 3.11 and 3.12

reference sets

golden-set-builder

Stratified sampling that reports which cells the pool could not fill. Annotator agreement is computed before any model metric, because it is the ceiling. Adjudication without majority vote, and freezing with a hash per record.

→ open the repository · about 1,500 lines

tests and CI on Python 3.11 and 3.12

prompts as contracts

prompt-contracts

Every prompt ships an output schema, refusal rules, a size budget and the golden set that gates its changes. The diff command answers the only question a reviewer has: must evaluation be re-run before merging.

→ open the repository · about 850 lines

tests and CI on Python 3.11 and 3.12

voice runtime

voice-agent-runtime

The dialogue policy is a transition table, not a paragraph in the prompt. A barge-in never resumes the interrupted sentence. Latency is budgeted per stage and judged at p95 — the value only one turn in twenty exceeds — against 3 seconds to the first reply and 10 seconds per turn.

→ open the repository · about 1,100 lines

tests and CI on Python 3.11 and 3.12

retrieval and grounding

rag-grounding-lab

What chunking costs and where each retrieval strategy loses — three failures reproduced rather than hidden. Answers are checked sentence by sentence: an invented number is caught separately from an unsupported phrasing, and an honest refusal counts as grounded.

→ open the repository · about 1,200 lines

tests and CI on Python 3.11 and 3.12

analytics on model output

conversation-intelligence-lab

The methodology from the analytics section, on synthetic data: a strict output contract, contradiction checks, traceable monthly aggregates and a reproducible report.

→ open the repository · about 300 lines

tests and CI on Python 3.11 and 3.12

$ ragl compare --top-k 1 --chunking title-prefixed

chunking        retrieval     hit   nDCG  paraphrase  exact-term

title-prefixed  vector        75%  0.750         70%         83%
title-prefixed  keyword       81%  0.812         70%        100%
title-prefixed  hybrid        81%  0.812         70%        100%

Real output from rag-grounding-lab, at rank one. hit is how often the right document was found at all, nDCG is how high it ranked. The column to read is the last one: vector search confuses two regulation codes that differ by a single digit, because they are made of almost the same character sequences, while exact word matching tells them apart. That gives a rule instead of an opinion: keyword search pays off where queries carry part numbers, codes and version strings. Where people ask in plain words, as in a 37-document base, vector retrieval is enough.

how i catch my own mistakes

A mistake is caught by a check, not by looking harder

three cases from these repositories

statistics

Krippendorff's alpha did not return 1.0 on perfect agreement

The coincidence matrix compared string identity instead of rater positions, so every pair where both raters chose the same label was dropped. The result looked plausible and was wrong.

Kept in the repository: a test asserting that for two raters on a nominal scale alpha and kappa must coincide. Currently 0.7630 against 0.7631.

ci

CI ran no jobs at all

A shell heredoc inside a run block put its body in column zero, which ends the YAML block scalar. GitHub could not parse the file: the pipeline looked red while the code had never executed.

Kept in the repository: a workflow structure test — inside a block scalar every line must be indented deeper than its key, and no heredocs. Verified against the broken file.

ci

The step died on the very check it was performing

GitHub starts bash with -e, so a command expected to exit non-zero ended the step before the code could be asserted. The log said «exit code 3» — exactly the number the step was checking for.

Kept in the repository: a helper that prints the expected and the actual code, and a rule — a step that asserts on an exit code must disable errexit.

ai engineer & data analyst · llm-systems · analytics for decisions

Looking for someone who takes AI to production — and to a decision?

Open to Senior / Lead Applied AI roles with end-to-end ownership: from business policy to a working system, a measurable effect and a report people act on. Remote, UTC+3, open to teams abroad.