Мы построили помощника, который отвечает инженерам и диспетчерам железной дороги на вопросы об инфраструктуре сети. Данные по ней лежат в нескольких разрозненных системах, и помощник сам выбирает нужный источник под каждый вопрос, не путая то, что выглядит связанным, но значит разное: запланированный в справочнике телефон ещё не означает установленное на станции оборудование.
Железную дорогу Сербии сводят в один диспетчерский центр: движение, связь, видеонаблюдение, пожарную и охранную автоматику, сети передачи данных — всё, что раньше жило по станциям и постам, стягивают в единое управление. У людей, которые это обслуживают, каждый день возникают вопросы про саму инфраструктуру. Диспетчер спрашивает, что подключено к узлу в Макише. Сетевой инженер — какие VLAN настроены на станции Врчин. Сервисный техник — какое оборудование уже установлено на объекте и под какой гарантией.
Вопросы звучат однотипно, но ответы на них лежат в совершенно разных системах. Топология связей — в одной выгрузке, конфигурации станций — в другой, телефонные справочники — в третьей, поставки и монтаж оборудования — в отдельной базе закупок. Человек, который отвечает на такие вопросы, на самом деле работает переводчиком между этими системами: он знает, куда смотреть под каждый тип вопроса, и держит в голове, что одно и то же название в разных местах значит разное.
Это не специфика железной дороги. Так живёт почти любая компания, у которой за годы накопился парк учётных систем: один и тот же объект разнесён по нескольким базам под разными именами, и всю эту карту кто-то держит в голове.
Система берёт вопрос на естественном языке и отвечает на него поверх всех этих источников сразу, на том же языке, на котором её спросили — сербском, русском или английском. Снаружи это выглядит как чат. Внутри стоит один агент-оркестратор и набор типизированных инструментов, по одному на каждый источник.
Главная сложность этой задачи прячется в одном слове — «Макиш». Это центральный узел сети, и он присутствует почти в каждом источнике. Беда в том, что в каждом он означает свой тип факта и записан по-своему.
| Где лежит | Как записано | Что это за факт |
|---|---|---|
| Топология сети | MAKIS-PE2 | маршрутизатор узла; его порты физически соединены с портами на других устройствах |
| Реестр объектов | Макиш | сам диспетчерский центр — запись в каталоге объектов и участков |
| Справочник связи | Makiš | запланированный пульт или телефонный номер |
| База закупок | Макиш | позиция оборудования с гарантией, накладной и признаком, смонтирована ли она |
Три разных написания латиницей и кириллицей, четыре разных типа факта. Для системы, которая складывает всё в один поисковый индекс, «Макиш» — это одна строка, и по ней с равной готовностью выдаются и устройство, и здание, и телефон, и складская позиция, перемешанные в одном ответе. В диспетчерской это означает уверенный неправильный ответ: например, что телефон на станции есть, хотя в справочнике он только запланирован, а смонтирован ли он, знает совсем другая система.
Поэтому система устроена как маршрутизатор. На каждый вопрос агент сначала решает, в какой источник смотреть, и только потом отвечает. Под каждый источник — свой инструмент: топология, реестр объектов, конфигурации станций, телефонные справочники, база закупок и документация поставщиков. Шесть источников вместо одной поисковой строки.
Между источниками прописаны явные правила старшинства и запреты на смешивание, потому что данные в них пересекаются и местами противоречат друг другу. Связи между устройствами есть и в файле топологии, и намёками в конфигурациях станций; система знает, что авторитетный источник по связям — топология, а намёки из конфигов вторичны.
Реестр объектов похож на карту сети, но системе сказано прямо, что это каталог объектов, не граф связей. Телефонный справочник выглядит как список установленных телефонов, но он описывает план: запись в нём не значит, что устройство стоит и работает.
Доходит до того, что часть «телефонов» в справочнике телефонами не является: рядом с обычными SIP-аппаратами там лежат кнопки диспетчерских пультов и линейные терминалы — у них есть номер, но позвонить на него нельзя. Система помечает их отдельно, чтобы не выдать номер кнопки за номер телефона.
Пять из шести источников — это небольшие файлы: сотни строк топологии, несколько сотен объектов в реестре, конфигурации полудюжины станций, телефонные справочники. Они невелики, поэтому при старте целиком загружаются в память и отдаются модели как есть. Шестой, база закупок, устроен принципиально сложнее: это живая реляционная база, и инструмент к ней — единственный, где есть настоящая работа с запросами. По объёму кода он больше всех остальных инструментов вместе взятых, и вот почему.
Сначала про склад. Оборудование на складе, отложенное под замену, и оборудование, которое привезли на объект, но ещё не смонтировали, отвечают на разные вопросы инженера. За этим стоят два независимых признака — лежит вещь на складе или на объекте, и смонтирована она или нет; их комбинации система разводит по смыслу вопроса.
| Вопрос инженера | Что это значит |
|---|---|
| что стоит на станции | смонтировано и работает на объекте |
| что привезли, но не смонтировали | лежит на объекте, ещё не в строю |
| что держат в запасе под замену | резерв на складе |
Дальше про гарантию. Ни «установлено», ни «под гарантией» не хранятся готовым полем: это вычисляемые факты. Позиция считается установленной, если смонтированной отмечена хотя бы одна её поставка, а срок гарантии берётся по самой поздней из них. Записей о поставке у одной позиции бывает несколько, поэтому оба факта система собирает сразу по всем поставкам этой позиции.
И язык. Инженер пишет «свич» или «switch», а в каталоге описания лежат на сербском и русском. Поиск идёт сразу по обоим языковым полям и по названию вендора, а сам запрос модель сначала переводит на язык базы. Если по названию объекта база не нашла ничего, система не сдаётся: она идёт в реестр объектов за каноническим написанием имени и повторяет запрос уже с ним. Один вопрос про оборудование на станции превращается в цепочку из двух источников только ради того, чтобы правильно опознать саму станцию.
Сюда же зашиты доменные допущения. Cisco в этой сети не разворачивали, поэтому модели прямо запрещено его предлагать и велено по умолчанию иметь в виду те семейства оборудования, которые реально стоят на сети.
Шестой источник — документация поставщиков: руководства по телефонной системе, описания коммутаторов, проектная документация по станциям, даташиты. Это PDF-файлы, и заманчиво было бы порезать их на куски фиксированного размера и сложить в общий поиск. Здесь сделали иначе.
Каждый документ режется по главам из его собственного оглавления. Сначала система пытается взять структуру из закладок PDF; если их нет — распознаёт оглавление по тексту; а если документ оказался сканом без текстового слоя, прогоняет его через OCR на трёх языках и ищет оглавление уже в распознанном тексте. Одна глава становится одной записью. Большой документ, в котором структуру найти не удалось, в базу не попадает вовсе: лучше не загрузить его, чем отдать модели нечитаемый ком текста, из которого она выхватит случайный фрагмент. Короткие бумаги вроде даташита на пару страниц, наоборот, кладутся целиком — резать там нечего.
Текст в базе — это производная от исходного PDF, и со временем он может разойтись с оригиналом из-за ошибок распознавания или сдвига границ глав. Поэтому есть отдельная проверка: система берёт случайные главы из базы, заново извлекает те же страницы из исходника и сравнивает. Это ловит ровно тот случай, когда модель уверенно сошлётся на «страницу 14», а на странице 14 написано другое.
Надёжность ответа начинается с того, что система отвечает с конкретного источника и показывает, откуда взят каждый факт. Дальше её держат несколько границ, потому что в этой среде уверенный неправильный ответ дороже честного «не знаю».
Важнее всего то, к чему помощник вообще подключён. Он читает справочные и учётные источники: топологию, конфигурации, справочники, базу закупок. К самим системам, которые управляют движением, стрелками и маршрутами, он не подключён вовсе и работает с их описаниями и выгрузками, а не с живым управлением.
Есть и мелкие, но важные предохранители. Перебирая большую выдачу из базы закупок, модель любит повторять один и тот же запрос; система ловит повтор до того, как он уйдёт в базу, и возвращает модели сообщение, которое разворачивает её на ответ по уже полученным данным. Когда у инженера спрашивают живое состояние оборудования, система не выдумывает телеметрию, а предлагает команды, которыми он сам это состояние снимет. А когда ответа нет или вопрос вне темы, помощник не угадывает: он отдаёт реальные контакты дежурных служб, чтобы человек позвонил тем, кто разберётся.
О границах честно. Модель сама проставляет каждому найденному куску оценку уверенности, но пока она задана инструкцией в промпте и в коде не закреплена, так что полагаться на неё как на жёсткий порог рано. Справочные файлы попадают в память при старте: если на станции что-то переключили, помощник увидит это только после следующего перезапуска.
Оба места — довести оценку уверенности до кода и обновлять справочники на ходу — понятны и на очереди. Система работает уже сейчас.
Инженер или диспетчер задаёт вопрос обычными словами, на сербском, русском или английском, и получает собранный ответ: с нужного источника, по правильному написанию имени, со ссылкой, откуда он взят. Где уверенности не хватает, система отдаёт вопрос человеку и не выдаёт запланированное за установленное — поэтому ответу можно верить. Раньше такой обход нескольких систем держал в голове один опытный человек, и процесс упирался в него. Теперь то же самое делает один вопрос.
Один оркестратор на pydantic-ai: разбирает вопрос, выбирает под него источник и отвечает на языке вопроса. Доменное поведение задаётся системной инструкцией и маршрутизацией, а не дообучением модели
Документация поставщиков, разрезанная по главам из собственного оглавления, а не на куски фиксированного размера. Сканы проходят распознавание на трёх языках, большие документы без структуры в базу не попадают
Доступ только на чтение во всех инструментах, дедуп повторных запросов к базе, потолки на размер контекста и число глав, запрет выдумывать живую телеметрию и обязательный откат на реальные контакты дежурных, когда ответа нет
Внешняя модель Claude Sonnet 4.5 через OpenRouter; встроенный веб-поиск по документации поставщиков подключается суффиксом :online. Отдельного дообучения под проект нет — поведение задаётся инструкцией и инструментами
Ответим, подходит ли задача для AI-агентов, и если да, предложим конкретный план.
Заявка отправлена
Ответим в течение дня на указанный email.
или напишите напрямую — ilya@manaraga.ai