RAG по архитектурному архиву: как найти действующее решение для компонента
Новый разработчик спрашивает, почему сервис использует очередь, хотя в архиве есть документ о синхронном API. Поиск находит оба текста и уверенно пересказывает более подробный. Команда теряет время на спор, который уже состоялся год назад. Для вопросов об архитектуре важно найти решение, которое сейчас относится к нужному компоненту, и восстановить его основания.
Архитектурные решения часто хранят как ADR: короткие документы с контекстом, выбранным вариантом и последствиями. Помимо текста у них есть статус и связи: принято, отклонено, заменено другим решением. Поиск по содержимому полезен, когда человек не знает номера ADR. После поиска нужен переход по структуре архива: именно она объясняет, какое решение действует.
От вопроса к цепочке решений
Добавьте к каждому документу ID компонента, статус и ссылку superseded_by на заменяющее решение. Компонент лучше выбирать из каталога сервисов: слово «billing» может встречаться в обсуждении соседней системы. Модель может предложить подходящий компонент, а интерфейс дать пользователю подтвердить его. После этого граница поиска становится явной.
Для запроса «почему платежи отправляются через очередь» сначала найдите кандидатов по тексту, затем пройдите связи замен. Действующий документ отвечает, что выбрано сейчас. Старый нужен для объяснения изменения условий. Передайте модели оба с разными ролями: текущая политика и исторический контекст. Иначе старое ограничение легко попадёт в ответ как актуальное.
Проверьте структуру архива до вызова LLM
Код ниже реализует навигационную часть на стандартном Python. Начальный найденный ADR передан как вход поискового этапа. Скрипт проверяет ссылки и циклы во всём небольшом архиве, затем возвращает цепочку замен для выбранного компонента. Он не выполняет семантический поиск: его задача — подготовить однозначный контекст после retrieval.
В примере решение adr-10 заменено на adr-24. Документ о поисковой системе остаётся в архиве, но не попадает в пакет платежного компонента. Если связь ведёт к отсутствующему документу, сборка останавливается: лучше показать проблему каталога, чем сообщить пользователю, что последнее найденное решение точно действует.
docs = {
"adr-10": {"component":"payments", "status":"superseded", "next":"adr-24", "text":"Синхронная отправка в ERP"},
"adr-24": {"component":"payments", "status":"accepted", "next":None, "text":"Очередь: ERP недоступна во время закрытия дня"},
"adr-30": {"component":"search", "status":"accepted", "next":None, "text":"Полнотекстовый индекс"}}
def chain(start, component):
seen, result = set(), []
current = start
while current is not None:
if current in seen:
raise ValueError("ADR cycle")
if current not in docs:
raise ValueError("Missing ADR: " + current)
seen.add(current)
doc = docs[current]
if doc["component"] != component:
raise ValueError("Cross-component replacement")
result.append(current)
current = doc["next"]
if docs[result[-1]]["status"] != "accepted":
raise ValueError("No accepted decision")
return result
for key, doc in docs.items():
chain(key, doc["component"])
path = chain("adr-10", "payments")
packet = {"current": path[-1], "history": path[:-1],
"sources": {key: docs[key]["text"] for key in path}}
assert packet["current"] == "adr-24"
assert packet["history"] == ["adr-10"]
assert "adr-30" not in packet["sources"]
print(packet)
Используйте модель для объяснения причин
После получения packet пользователь спрашивает: «Почему платежи теперь отправляются через очередь, а раньше шли синхронно?» Вход содержит текущее решение adr-24 и историческое adr-10. Именно связанный пакет даёт модели основание описать изменение, а не пересказать случайно найденный старый документ.
Объясни текущее архитектурное решение по packet. Верни current_decision_id, explanation, historical_ids и missing_information. Текущее решение бери только из current; history описывает прошлое. Каждое объяснение свяжи с source_id. Не придумывай сравнительные характеристики технологий, если их нет в источниках.
В данном пакете основание очереди — недоступность ERP во время закрытия дня. В нём нет выбора конкретного брокера и сведений о производительности. Эти вопросы должны попасть в missing_information. При подключении исходного поиска сохраняйте найденный ADR и цепочку навигации, чтобы инженер мог проверить путь к текущему решению.
Сформулируйте вопрос к источникам
В готовом пакете модель должна объяснить, какая проблема привела к очереди и какие последствия решения записаны в текущем ADR. Если документ не отвечает, почему выбрали конкретный брокер, этот пробел лучше вернуть автору решения. Наличие архитектурного архива не означает, что в нём записаны все причины. Полезный ответ может заканчиваться точным вопросом владельцу компонента.
Для командного применения сохраните ID ревизии документа и ссылку в репозитории. Разработчик должен открыть ту же версию, которая участвовала в ответе. На странице сервиса разместите блок «действующие решения» с историей замен. Такой интерфейс приносит пользу ещё до подключения модели: команда видит устаревшие и оборванные цепочки.
Оцените ответы глазами нового сотрудника
Подготовьте вопросы о нескольких компонентах, включая отменённые решения. Успех — это действующий ADR в ответе, корректно отмеченная история и объяснение, подтверждённое текстом. Отдельно проверьте вопросы с неверной предпосылкой: «почему всё ещё используем синхронный вызов». Ассистент должен исправить предпосылку по текущему решению, а не искать аргументы в его пользу.
Масштабируйте поиск по архитектурному архиву
Следующий этап — находить исходный ADR среди большого числа похожих документов. На курсе вы освоите поиск с фильтрами, гибридную выдачу и реранжирование, затем соберёте RAG с цитатами и API семантического поиска. Эти навыки нужны, чтобы навигация по структуре архива начиналась с надёжно найденного компонента и документа. Откройте программу платного курса «Vector DB & RAG Developer».
Продолжить на практике
- Vector DB & RAG Developer ↗
Практический курс по векторным базам данных и семантическому поиску. Вы развернёте Qdrant, Weaviate и FAISS, научитесь индексировать миллионы эмбеддингов, строить k-NN-поиск с фильтрами, объединять его с BM-25 и создавать RAG-ботов, которые отвечают на вопросы на основе ваших данных.
