Возможно Вам будет интересно как себя чувствует DeepSeek 70B на ноутбуке, но об этом в конце.

Идея этого проекта пришла мне на допросе, причины допроса оставим за скобками: статья всё-таки техническая. Там я впервые увидел, насколько сложно устроена работа с материалами дела. Со стороны кажется: задал вопросы, записал ответы, подшил бумаги. В реальности перед следователем лежат показания нескольких людей, протоколы, даты, адреса, телефоны, фотографии, аудиозаписи, результаты осмотров и экспертиз. Материалы приходят не по порядку, одни сведения уточняют другие, а иногда прямо им противоречат.
Скорее всего современные средства обработки больших объемов информации используются. Не то, чтобы в любой силовой структуре используют бумагу и ручку, а все тома дел нумеруются карандашом, затем после дырокола сшиваются собственноручно, как это было почти 100 лет назад.
Но прямо на допросе меня осенило: так это же работа для ИИ. Жеглов раскрывал дела через картотеку и чутьё. Картотеку я решил оцифровать, а чутьё заменить гибридным поиском — оно, в отличие от Глеба Егорыча, в 16 ГБ VRAM не помещается.
Так получился проект https://github.com/webzuweb/InvestigationAI.git
InvestigationAI (CaseAI) — автономная рабочая станция для следователя. Она принимает документы, сканы, изображения и аудиозаписи, извлекает текст, распознаёт речь, строит локальный поисковый индекс и позволяет задавать вопросы по материалам. Ответ должен вести не к абстрактному «источнику 2», а к конкретному тому, файлу, странице или таймкоду.
Система работает на Ubuntu без облачных API. В режиме жёсткой изоляции ей вообще не нужен интернет: веб-интерфейс, модели, индексы, аудиообработка и база данных находятся на одной машине и слушают только localhost.
Отдавать машине оценку доказательств, процессуальные решения и ответственность было бы не только глупо, но и опасно. А вот чтение, поиск, первичное сопоставление и подготовка проверяемых ссылок — как раз тот объём механики, который машина может снять с человека.
Тут обнаружилась маленькая проблема размером со всю идею: материалы конфиденциальны. Отправлять их в случайное облако нельзя. Даже обещание провайдера «мы не обучаемся на ваших данных» не превращает передачу охраняемой информации третьей стороне в хорошую идею.
Что я хотел получить — и что получилось
В моей задаче центральной сущностью является не чат, а дело: тома, материалы и проверяемое происхождение каждого фрагмента. Дело состоит из томов, тома — из материалов; файл можно перемещать между томами без повторного импорта.
Телефон, VIN, госномер и номер документа нельзя искать только по смысловой похожести. Аудио индексируется сегментами с таймкодами и метками говорящих. Длинные операции показывают стадию, текущий файл, таймер, успехи и ошибки. После подготовки станция работает в изолированной сети или вообще без внешнего интерфейса.

Железо должно помещаться в ноутбук, это и будет рабочая станция в режиме полета.
Конфигурацию ниже я называю проверенной, а не «минимальной»: без реальных сравнительных замеров обещать комфорт на более слабом железе было бы нечестно.
Компонент |
Проверенная конфигурация |
Роль |
CPU |
Intel Core i9-11900 |
Парсинг, OCR-обвязка, CPU-слои LLM, embedding и reranker |
RAM |
64 ГБ DDR4 |
32B/70B в гибридном режиме, индексация, запас для длительных задач |
GPU |
GeForce RTX 3080, 16 ГБ VRAM |
GPU-offload llama.cpp; по очереди — Whisper/pyannote и опциональный vision |
SSD |
1 ТБ |
Веса GGUF, исходные материалы, индексы и промежуточные файлы |
ОС |
Ubuntu 24.04 LTS x86_64 |
systemd-сервисы, NVIDIA-драйвер, управляемый air-gap |
Важная поправка к красивому маркетингу. Ни DeepSeek-R1-Distill-Qwen-32B Q4_K_M, ни тем более DeepSeek-R1-Distill-Llama-70B Q4_K_M не помещаются в 16 ГБ VRAM целиком. Оба профиля работают гибридно: часть слоёв на GPU, остальное — в RAM/CPU. Fast 32B легче и используется по умолчанию; Deep 70B запускается только для сложных сопоставлений и не обещает серверной скорости.
Embedding и reranker в стабильном релизе намеренно работают на CPU (--n-gpu-layers 0), чтобы не конкурировать с LLM за VRAM. Whisper освобождается перед запуском диаризации. На одной видеокарте диспетчеризация важнее попытки одновременно запустить всё сразу.
Архитектура: несколько сервисов вместо одного магического процесса
Первую версию хотелось сложить в один Python-процесс. Удобно — до первого зависшего распознавания аудио или смены модели. В стабильной версии компоненты разделены на systemd-сервисы, каждый можно перезапустить и диагностировать отдельно.
Все HTTP-службы привязаны к 127.0.0.1
Сервис |
Порт |
Роль |
CaseAI Web / FastAPI |
8080 |
Интерфейс, API, дела, тома, импорт, журнал, очередь |
Text LLM |
8081 |
llama.cpp с текущим профилем Fast или Deep |
Embedding |
8082 |
Qwen3 Embedding 0.6B Q8_0, CPU |
Vision |
8083 |
Опциональная Qwen3-VL 8B для изображений |
Reranker |
8086 |
Qwen3 Reranker 0.6B Q8_0, CPU |
Model Manager |
8087 |
Выгрузка, запуск и проверка готовности LLM |
Audio worker |
8090 |
faster-whisper large-v3 + pyannote Community-1 |
На одном из этапов я добавил ещё harness и прокси — хотелось «умнее управлять рассуждением». Взамен получил лишний процесс, новые таймауты и ещё один журнал, который надо читать ночью. Production-путь снова стал коротким: CaseAI → Model Manager → llama.cpp. Локальная система не обязана копировать облачную архитектуру, самым важным было улучшение производительности без потери качества обработки информации.
Как устроен RAG: смысл, точность и происхождение
RAG здесь это конвейер, который обязан сохранить происхождение фрагмента и сочетать несколько типов поиска. Материал копируется в хранилище дела, получает стабильный идентификатор и SHA-256.
Из документа извлекается текст; для сканов запускается OCR, для аудио — транскрибация и диаризация. Текст режется на фрагменты до 3200 символов с перекрытием 450; рядом сохраняются том, файл, страница или таймкод.
Qwen3 Embedding строит нормализованные векторы для FAISS IndexFlatIP.
Параллельно SQLite FTS5 даёт лексический поиск, а телефоны/VIN/номера попадают в точный индекс. Извлекается до 40 кандидатов; Qwen3 Reranker переоценивает их; в контекст попадает до восьми фрагментов в общем бюджете 18 000 символов (подобран эмпирическим путем).
LLM получает вопрос, текущие фрагменты и инструкцию ссылаться на карту источников. Для явного точного поиска LLM вообще не запускается.
combined = 0.30 base_score + 0.70 normalized_reranker
if exact_identifier_match:
combined += 1.2
retrieval_candidates = 40
answer_sources = 8
context_budget_chars = 18000
Эти коэффициенты — текущая инженерная эвристика, а не научно доказанный оптимум. До появления размеченного синтетического корпуса и ablation-теста относиться к ним надо именно так. Я оставляю числа в статье, чтобы решение было воспроизводимым, но не выдаю конфигурацию за объективную истину.
Почему нельзя оставить один vector search? Телефоны +7 999 123-45-67 и +7 999 123-45-68 почти близнецы для embedding, но для дела это разные сущности. И наоборот: вопрос «кто менял время своего прибытия?» может быть сформулирован в документах десятком способов — здесь FTS уже недостаточно. Поэтому точный, лексический и семантический маршруты работают вместе.
Аудио — это не приложение к делу
Часовую запись бесполезно транскрибировать одним полотном и сослаться на имя файла. faster-whisper large-v3 разбивает речь на сегменты, pyannote Community-1 назначает метки SPEAKER_XX. В результате источник ведёт не просто к записи, а к диапазону 00:12:31–00:12:47. Пользователь нажимает ссылку и попадает на нужную секунду.
Грабли, которые я собрал
Ниже — самая полезная часть проекта. Не каталог функций, а моменты, когда всё уже «работало», но только на одном красивом файле.
1. 70B не помещается в 16 ГБ VRAM. Кто бы мог подумать
Попытка загрузить максимум слоёв приводила либо к CUDA error, либо к тому, что система съедала память и переставала быть управляемой. Решение — два профиля и один резидентный LLM-процесс. Model Manager останавливает предыдущую модель, ждёт освобождения ресурсов, запускает новую и проверяет health endpoint. llama.cpp закреплён на конкретной ревизии: воспроизводимость важнее пары процентов из сегодняшнего nightly.
2. Векторный поиск уверенно нашёл не тот телефон
На фразах смысловой поиск выглядел волшебством. На идентификаторах — опасным фокусником. Я добавил нормализацию сущностей, отдельный точный индекс, SQLite FTS5/BM25 и бонус exact match. Если запрос явно про телефон, VIN или номер документа, система показывает совпадения напрямую и тратит ноль токенов LLM.
3. Ссылка «[ИСТОЧНИК 2]» ничего не доказывала
Ранний интерфейс честно нумеровал источники. Формально цитирование было. Практически пользователь понятия не имел, откуда взялась фраза. Теперь источник — структура: дело → том → материал → страница/таймкод → SHA-256. Номер удобен внутри ответа, но проверяемость появляется только после привязки к конкретному материалу.
[ИСТОЧНИК 2]
Том 4 → Протокол осмотра телефона
стр. 83
SHA-256: …
Для аудио:
Том 7 → Звонок 17 февраля
00:12:31–00:12:47 • SPEAKER_01
4. Потом пришёл database is locked
Небольшие тесты проходили. Я импортировал пачку файлов — и большинство операций закончилось знакомством с database is locked. «Хьюстон, у нас проблема». И, как в «Аполлоне-13», спасли не дополнительные мощности, а правильный порядок действий. Причины оказались не нейросетевыми: вложенная запись из кэша, аудит и статус после каждого файла, плюс перестроение FAISS на каждом шаге.
Исправление: SQLite WAL, единый сериализованный writer, запрет вложенных записывающих транзакций, одна активная партия импорта и перестроение FAISS один раз после партии. busy_timeout=300000 остался страховкой, а не основным способом «лечения». Ошибка одного файла теперь попадает в отчёт, но не откатывает остальные.
Самая заметная оптимизация RAG в итоге оказалась оптимизацией порядка транзакций. Нейросети снова остались без главной роли.
5. Флешка с пробелом в имени победила автоматику
Ubuntu вернула точку монтирования как /media/computer/UBUNTU\x2024_0, а реальный каталог назывался /media/computer/UBUNTU 24_0. Программа приняла \x20 буквально. Когда я это исправил, desktop automount уже смонтировал флешку, а агент каждые две секунды пытался сделать то же самое ещё раз.
Теперь агент сначала ищет существующую точку монтирования, декодирует \x20 и старый вариант \040, а собственный mount создаёт только при необходимости. Мелочь — пока не импортируешь пятьдесят файлов с носителя, который «не существует».
6. JSON.parse скрывал настоящую ошибку
Backend вернул обычный текст Internal Server Error, а фронтенд без проверки попытался разобрать его как JSON. Пользователь увидел ошибку парсера вместо PermissionError. Клиент теперь проверяет статус и Content-Type; backend отвечает структурированно. Обработчик ошибок не должен уничтожать исходную ошибку — неожиданно полезный урок и без всякого ИИ.
7. Длинная операция выглядела как зависание
OCR, аудио и индексация занимают минуты. Спиннер без объяснений провоцирует нажать кнопку ещё раз, затем появляется вторая партия, блокировка базы и тот самый «крайний случай». Интерфейс показывает текущий файл, стадию, таймер и счётчик вроде «7 из 24 • готово 6 • ошибок 1». Ход обработки показывает retrieval, rerank и подготовку модели, но не публикует скрытую chain-of-thought как будто это проверенный анализ.
8. Кнопка «Остановить» останавливала только настроение пользователя
AbortController закрывал запрос браузера, но llama.cpp продолжал считать. Получался HAL 9000: «Прости, Дэйв, боюсь, я не могу прервать генерацию». После перехода на streaming сервер при отмене закрывает поток к llama.cpp, освобождает слот и не сохраняет незавершённый ответ. На локальной машине один забытый запрос к 70B способен надолго занять весь аттракцион.
9. Ответ обрывался примерно на 1000 output токенах
Это выглядело как слабость модели, а оказалось жёстким max_tokens. Теперь предел настраивается, usage сохраняется, а finish_reason=length показывается явно. Для DeepSeek-R1 бюджет completion расходуется и на reasoning, и на видимый текст. При этом миллионы токенов, которые у фронтир моделей норма, на локальной машине будут несбыточной мечтой.
Чтобы понять локальную LLM, нужно стать локальной LLM
Даже если вы никогда не работали с материалами дела, в проекте есть несколько общих уроков для локального RAG и утилит на одной рабочей станции:
Точные идентификаторы требуют отдельного маршрута; embedding не обязан различать одну цифру.
Provenance надо хранить на уровне каждого chunk, а не придумывать ссылку после генерации.
Память диалога и доказательная выборка — разные контуры.
Один writer и пакетное перестроение индекса часто полезнее очередной «AI-оптимизации».
Отмена должна доходить до вычислительного backend, иначе она декоративна.
На одной машине меньше слоёв обычно означает больше надёжности.
Наблюдаемость длительной операции — часть корректности, а не косметика интерфейса.
А нельзя было взять готовый локальный RAG?
Можно — если нужен универсальный чат с базой знаний. Open WebUI и AnythingLLM гораздо зрелее как общие платформы, PrivateGPT даёт сильный API-фундамент. Я не объявляю InvestigationAI «лучше». Отличие — узкая предметная модель и другой набор приоритетов.
Система |
Сильная сторона |
Почему я не остановился на ней |
Open WebUI |
Зрелая self-hosted AI-платформа, знания, плагины, multi-user |
Нет модели дело → том → материал → проверяемый источник |
AnythingLLM |
Удобный on-device ассистент и document knowledge |
Не ориентирован на доказательное происхождение и такой workflow |
PrivateGPT |
Сильная private-AI основа и API |
Основа для разработки, а не готовое рабочее место с томами, USB и аудитом |
InvestigationAI |
Вертикальный hybrid RAG, exact ID, аудио, USB, карта источников |
Я тут! |
Коммерческие юридические продукты уровня CoCounsel живут в другой экосистеме: лицензированные правовые массивы, облачные workflows и многолетняя экспертная валидация. Сравнивать их по числу кнопок с проектом одного разработчика было бы странно.
Установка
Целевая система — обычная Ubuntu 24.04 LTS x86_64 с NVIDIA GPU, не WSL и не Docker-контейнер. Интернет требуется на этапе установки и загрузки моделей.
sudo apt update
sudo apt install -y git
git clone https://github.com/webzuweb/InvestigationAI.git
cd InvestigationAI
sudo bash install.sh
sudo bash scripts/download_models.sh
sudo bash scripts/build_deepseek_32b.sh
sudo bash scripts/download_audio_models.sh
sudo bash scripts/build_deepseek_70b.sh
sudo bash scripts/optimize_runtime.sh --all
sudo bash scripts/verify_install.sh
Для staging и сборки Fast-профиля проект требует около 180 ГБ свободного места; для Fast + Deep с промежуточными файлами рекомендуется примерно 420 ГБ. Это не размер готового Q4-файла, а запас на загрузку исходных весов, конвертацию и квантизацию.
После проверки интерфейс открыт только локально: http://127.0.0.1:8080. Жёсткую изоляцию включаем последней, иначе получаем очень безопасную машину, которая не успела скачать модели:
sudo bash scripts/generate_sbom.sh
sudo bash scripts/lockdown_offline.sh --confirm
sudo bash scripts/test_no_internet.sh
Безопасность, лицензия и честные ограничения
Локальность убирает риск передачи данных внешнему LLM-провайдеру, но не делает систему автоматически защищённой. Для реального внедрения потребуются модель угроз, шифрование накопителя, контроль USB, резервное копирование, роли, подписанные обновления, аудит, физическая защита и выполнение требований конкретного контура.
Текущий релиз — single-user станция без формальной сертификации и полноценного RBAC. LLM может ошибаться и убедительно связывать несвязанные факты. RAG уменьшает риск, но не отменяет проверку: если ссылка не подтверждает фразу, фразу нельзя использовать.
Что в итоге?
Я начинал с наивной идеи: большая локальная модель прочитает материалы и найдёт противоречия. В процессе выяснилось, что сама модель — едва ли половина работы.
Нужно правильно импортировать файлы, не поссориться с автомонтированием Ubuntu, не заблокировать SQLite, не потерять происхождение фрагмента, различать смысловую похожесть и точный номер, управлять общей памятью, останавливать генерацию по-настоящему и объяснять пользователю, чем машина занята прямо сейчас.
Именно эти скучные части превращают демонстрацию RAG в инструмент. Не «DeepSeek 70B» в заголовке, а возможность нажать на ссылку, открыть правильный том и проверить страницу или секунду записи. Облако здесь — синяя таблетка: удобно и не думаешь, где оказались данные. Локальная станция — красная: сложнее, зато сам видишь, насколько глубока кроличья нора и где лежит каждый файл.
InvestigationAI не является электронным следователем и не должен принимать процессуальные решения. Но он может снять часть механического поиска и первичного сопоставления — при условии, что человек проверяет каждый существенный вывод по первоисточнику.
Репозиторий и инструкции: github.com/webzuweb/InvestigationAI
Если вы работаете с локальным RAG, OCR, аудио или защищёнными контурами — мне полезна практическая обратная связь. Особенно по методике оценки retrieval, безопасной работе с синтетическими корпусами и операциям, которые автоматизировать нельзя.
Как себя чувствует DeepSeek 70B на ноутбуке?
Ответ с input 10.000 токенов и output 1.500 токенов требует примерно 30 минут, на модели 32B примерно 5минут. Это конечно вызывает неудобство, но за неимением альтернатив это убирает рутинную работу, а за счет очередности задач, можно задать хоть 20 вопрос сразу и подойти к машине через несколько часов.
Если Вы работаете в силовых структурах и будете использовать данное решение и оно принесет пользу радости моей не будет предела.
Спасибо за внимание!
Комментарии (6)

Bardakan
26.08.2026 07:05почему модель должна быть именно на ноутбуке? Почему например не использовать связку мощный пк+любой ноутбук?

webzuweb Автор
26.08.2026 07:05тогда будет сеть и будет контур, а это уже вопросы безопасности

Bardakan
26.08.2026 07:05ноутбук вы используете внутри своей организации? Тогда почему не стационарный пк?
Если выносите его куда-то за пределы, то получаются те же самые вопросы с безопасностью.
Или я вас неправильно понял?

webzuweb Автор
26.08.2026 07:05Согласен, ноутбук или ПК. Я имею ввиду, что изначально исключал связку (сервер+клиент)мощный пк+любой ноутбук
ya_gaeo
Хорошо, что здесь источником считается не абстрактный «фрагмент № 2», а том, файл, страница или таймкод. Но SHA-256 доказывает неизменность исходного файла, а не правильность OCR, чанкинга и ответа конкретной версии модели. Для реальной проверяемости придётся версионировать весь конвейер: OCR, модели, промпт, параметры поиска и карту фрагментов. Иначе ссылка на доказательство есть, а повторить путь от доказательства к выводу уже нельзя.
webzuweb Автор
Тут важнее просто найти взаимосвязь, закономерность, противроречие. Поиск провести не дословно, а смысловой по документам.