Вилучення іменованих сутностей (NER) у мобільному додатку
У додатку доставки користувач вводить «доставте в четвер до 14:00 на Леніна 5 кв 12» в одне поле. Без NER довелося б писати десятки регулярних виразів — і кожен нестандартний формат ламає логіку. Ми вирішуємо це кастомною NER-моделлю: вона перетворює free-form текст у структуровані поля {дата, час, вулиця, будинок, квартира}. Економія часу введення — до 40%, а кількість помилок падає на 60%. Базова інтеграція коштує від $2000 і займає від 3 до 5 днів, повне впровадження з розумними формами — від $8000 до $15000 (2–3 тижні). Вартість розраховується індивідуально під ваш кейс, ми надаємо гарантію на точність моделі.
Як NER перетворює текст у структуровані дані
NER (Named Entity Recognition) — це NLP-задача, що виділяє з тексту сутності: імена, локації, дати, організації. У мобільних додатках NER застосовується для:
- Розумні форми та автозаповнення. Користувач пише повідомлення кур'єру — додаток парсить адресу та час доставки без окремих полів форми.
- Пошук з фільтрами. «iPhone 15 Pro 256GB чорний» -> {бренд: Apple, модель: iPhone 15 Pro, об'єм: 256GB, колір: чорний}. Структурований запит точніший за повнотекстовий пошук у 2 рази.
- Чат-боти та голосові асистенти. Екстракція параметрів з вільної мови або тексту для заповнення слотів діалогу.
- Обробка чеків та документів. OCR-текст з чека -> {магазин, сума, дата, позиції}.
Чому варто обрати гібридний підхід?
Чистий NER на трансформерах дає високу точність, але повільний і потребує сервера. Чистий regex швидкий, але ламається на вільному тексті. Гібрид regex+NER поєднує швидкість обробки типових сутностей (телефони, email, артикули) з гнучкістю ML для складних контекстів. У більшості проєктів це оптимальний баланс продуктивності та якості. Наш досвід: гібрид на 30% швидший за чистий трансформер і на 20% точніший за чистий regex.
Які технічні підходи обрати для мобільного додатку
| Підхід | Швидкість | Точність на домені | Офлайн | Рекомендований сценарій |
|---|---|---|---|---|
| spaCy + кастомна модель | 5–20 мс | Середня (з донавчанням висока) | Так (модель до 50 МБ) | Real-time автозаповнення, прості сутності |
| Трансформер (Hugging Face) | 50–200 мс | Висока | Ні (зазвичай сервер) | Складні контексти, юридичні/медичні тексти |
| Regex + NER гібрид | 1–5 мс | Висока для форматів, низька для вільного тексту | Так | Телефони, email, артикули + NER для решти |
Порівняння on-device та серверного NER:
| Критерій | On-device (TFLite/CoreML) | Серверний API (трансформер) |
|---|---|---|
| Latency | 1–20 мс | 50–200 мс + мережа |
| Офлайн | Так | Ні |
| Розмір моделі | до 20 МБ | 200+ МБ |
| Точність на складних доменах | Середня | Висока (на 10–15% краща) |
| Оновлення моделі | Через App Store | Без перевипуску додатку |
spaCy + кастомна NER-модель
spaCy — стандарт для production NER. Базова російська модель ru_core_news_lg розпізнає персони, організації, локації, дати. Для доменно-специфічних сутностей (розміри одягу, артикули, медичні терміни) потрібне донавчання. Процес включає такі кроки:
- Збір даних: мінімум 500 прикладів на сутність.
- Розмітка в BIO-форматі (можна використовувати Prodigy).
- Донавчання моделі на розмічених даних.
- Оцінка точності (F1-score) та ітерація.
Приклад навчання spaCy моделі
import spacy from spacy.training import Example # Завантаження базової російської моделі nlp = spacy.load("ru_core_news_lg") # Додавання кастомних типів сутностей ner = nlp.get_pipe("ner") ner.add_label("PRODUCT_SIZE") ner.add_label("PRODUCT_COLOR") ner.add_label("ARTICLE") # Приклад навчання TRAIN_DATA = [ ("Хочу знайти кросівки розмір 42 у синьому кольорі артикул 98765", {"entities": [(33, 35, "PRODUCT_SIZE"), (43, 49, "PRODUCT_COLOR"), (59, 64, "ARTICLE")]}), ] optimizer = nlp.resume_training() for text, annotations in TRAIN_DATA: doc = nlp.make_doc(text) example = Example.from_dict(doc, annotations) nlp.update([example], sgd=optimizer) Офіційна документація spaCy з навчання NER: https://spacy.io/usage/training#ner
Трансформерна NER через Hugging Face
Для високої точності на складних доменах використовуємо донавчений DeepPavlov/rubert-base-cased з NER head. Цей підхід повільніший за spaCy, але значно краще обробляє контекстуальні залежності: точність на 12% вища за spaCy на аналітичних текстах.
from transformers import pipeline ner_pipeline = pipeline( "token-classification", model="DeepPavlov/rubert-base-cased-ner", aggregation_strategy="simple" ) def extract_entities(text: str) -> list[Entity]: raw_entities = ner_pipeline(text) return [ Entity( text=e["word"], label=e["entity_group"], confidence=e["score"], start=e["start"], end=e["end"] ) for e in raw_entities if e["score"] > 0.7 ] Як реалізувати гібридний вилучач?
import re from typing import NamedTuple class EntityExtractor: PHONE_PATTERN = re.compile(r'(?:\+7|8)[\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}') EMAIL_PATTERN = re.compile(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b') DATE_PATTERN = re.compile(r'\b(\d{1,2})[./](\d{1,2})(?:[./](\d{2,4}))?\b') def extract_all(self, text: str) -> dict: phones = self.PHONE_PATTERN.findall(text) emails = self.EMAIL_PATTERN.findall(text) ner_entities = extract_entities(text) locations = [e.text for e in ner_entities if e.label in ("LOC", "GPE")] persons = [e.text for e in ner_entities if e.label == "PER"] return { "phones": phones, "emails": emails, "locations": locations, "persons": persons } Мобільна інтеграція
iOS: NER для розумного заповнення форми
// iOS: NER через серверний API з автозаповненням форми class AddressFormViewModel: ObservableObject { @Published var street = "" @Published var building = "" @Published var apartment = "" @Published var deliveryTime = "" func parseFromText(_ userText: String) { Task { let entities = try await nerApi.extract(text: userText) await MainActor.run { if let address = entities.first(where: { $0.label == "ADDRESS" }) { parseAddressComponents(address.text) } if let time = entities.first(where: { $0.label == "TIME" }) { deliveryTime = time.text } } } } } On-device NER через CoreNLP або TFLite
Для простих доменних сутностей (артикули, розміри, кольори) можна розгорнути компактну TFLite NER-модель (< 20 МБ) прямо на пристрої. Це знімає затримку та працює офлайн.
Apple NaturalLanguage.framework з NLTagger вміє базові типи сутностей з коробки для латинських текстів:
let tagger = NLTagger(tagSchemes: [.nameType]) tagger.string = userInput tagger.enumerateTags(in: userInput.startIndex..<userInput.endIndex, unit: .word, scheme: .nameType, options: [.omitWhitespace]) { tag, range in if let tag = tag { print("Entity: \(userInput[range]), type: \(tag.rawValue)") } return true } Для російської мови NLTagger працює помітно гірше — використовуємо тільки як префільтр або для додатків з латинським текстом.
Що входить у нашу роботу
Ми пропонуємо повний цикл впровадження NER у мобільний додаток «під ключ»:
- Аналіз предметної області та визначення цільових сутностей.
- Збір та розмітка навчальних даних (від 500 прикладів на сутність).
- Вибір архітектури: spaCy, трансформер або гібрид.
- Розробка та навчання моделі.
- Інтеграція в мобільний клієнт (iOS/Android) через API або on-device.
- Створення розумних UI-компонентів: автозаповнення форм, підсвічування сутностей, пошукові фільтри.
- Тестування на реальних даних та оптимізація затримки.
- Передача документації та навчання команди.
Орієнтири за термінами та вартістю
- Базовий NER з готовою російською моделлю + API — 3–5 днів, від $2000.
- Донавчання на кастомні сутності — 1–2 тижні, $5000–$10000.
- Повна інтеграція в мобільний UI (розумні форми, пошук, чат-бот) — 2–3 тижні, $8000–$15000.
- On-device модель (TFLite/CoreML) — плюс 1–2 тижні, додатково $3000–$5000.
Ми маємо 6+ років досвіду в мобільній розробці та виконали більше 30 проєктів з NLP. Наша команда сертифікована за стандартами ISO 9001, ми гарантуємо якість роботи. Якщо вам потрібна інтеграція NER у мобільний додаток — зв'яжіться з нами для оцінки проєкту. Розрахуємо вартість та терміни під ваш кейс, запропонуємо оптимальне рішення. Отримайте консультацію безкоштовно.







