TL;DR
- Вызов LLM заканчивается на этапе генерации ответа: модель получает сформированный промпт и возвращает токены. Всё, что до и после — ответственность backend-системы.
- Backend на FastAPI управляет цепочкой: эмбеддинг запроса → поиск по векторному индексу → сборка контекста → вызов Ollama → постобработка и логирование. Без этого RAG превращается в «чёрный ящик» без прозрачности.
- Обновление индекса, кэширование, контроль версий документов и мониторинг — чистая backend-логика, не имеющая отношения к инференсу модели.
Разбор
На практике граница проходит ровно в одной точке: когда сформирован промпт и передан в ollama.generate(). Всё, что до — подготовка контекста (поиск чанков, фильтрация, сортировка по релевантности). Всё, что после — разбор ответа, сбор метаданных (какие документы использованы, сколько токенов, время генерации).
Пример типичной архитектуры локального RAG:
@app.post("/ask")
async def ask(query: str):
# 1. Эмбеддинг запроса (backend)
query_emb = embed(query)
# 2. Поиск по FAISS (backend)
chunks = index.search(query_emb, k=5)
# 3. Сборка промпта (backend)
context = "\n".join([c.text for c in chunks])
prompt = f"Контекст:\n{context}\n\nВопрос: {query}"
# 4. Вызов LLM (граница)
response = ollama.generate(model="llama3", prompt=prompt)
# 5. Постобработка и логирование (backend)
log_entry = {
"query": query,
"sources": [c.metadata for c in chunks],
"prompt_tokens": len(prompt.split()),
"response_time": response["total_duration"]
}
return {"answer": response["response"], "meta": log_entry}
Ключевой момент: модель не знает, откуда взялся контекст. Она просто генерирует текст на основе переданного промпта. Вся ответственность за актуальность данных, размер контекстного окна и фильтрацию шума лежит на backend. Если индекс не обновлён — модель будет отвечать по устаревшим документам, и это проблема инфраструктуры, а не LLM.
Для управления версиями документов и переиндексации удобно добавить отдельный endpoint:
curl -X POST http://localhost:8000/reindex \
-H "Content-Type: application/json" \
-d '{"path": "/docs/v2"}'
Этот вызов не трогает модель — он перестраивает FAISS-индекс и обновляет метаданные. Backend также отвечает за кэширование частых запросов (например, через Redis) и мониторинг времени каждого этапа через middleware.
Выводы
- Чёткое разделение: LLM отвечает только за генерацию, backend — за контекст, логику и инфраструктуру. Смешивать их — путь к неконтролируемому поведению.
- Локальный RAG на FastAPI + Ollama — это не «вызов модели», а полноценная backend-система с поиском, кэшем и мониторингом. Без этого вы не сможете отлаживать ответы и гарантировать актуальность.
- Инвестиция в backend-слой (индексация, логирование, управление сессиями) окупается сразу, как только проект выходит за рамки демо.
Нужна такая автоматизация? Обсудить проект в Telegram: https://t.me/Cvister0