Вилучення іменованих сутностей (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 у мобільний додаток — зв'яжіться з нами для оцінки проєкту. Розрахуємо вартість та терміни під ваш кейс, запропонуємо оптимальне рішення. Отримайте консультацію безкоштовно.







