AnythingLLM не индексирует документы: причины и решение
Файл загрузился, в списке он есть, а на вопрос по нему чат отвечает, что ничего не нашёл. Жалоба «anythingllm не видит документы» почти никогда не означает поломку: между загрузкой и ответом с цитатой лежит конвейер из пяти шагов, и рвётся он чаще всего на втором — там, где от пользователя ждут нажатия кнопки, о существовании которой он не догадывается.
Содержание
- Пять шагов от файла до ответа — и где рвётся конвейер
- Документ загружен, но не «вшит» в рабочее пространство
- Коллектор разобрал файл не так, как вы думаете
- Векторы не посчитались: чанки, лимиты эмбеддера и кэш
- Векторы есть, а чат отвечает «ничего не найдено»
- Порядок восстановления: переиндексация без потери базы
- Какой сервер под AnythingLLM брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Пять шагов от файла до ответа — и где рвётся конвейер
AnythingLLM не «читает файлы» в момент вопроса — он заранее строит по ним индекс. Путь документа состоит из пяти независимых операций, и любая может отработать вхолостую.
- Загрузка. Сервер на порту
3001передаёт файл коллектору на8888. - Разбор. Коллектор вытаскивает текст в
storage/documents/отдельным JSON. - Привязка. Документ появляется в общем списке «My Documents» и не принадлежит ни одному пространству.
- Эмбеддинг. Текст режется на чанки, они превращаются в векторы и пишутся в LanceDB.
- Поиск. На вопрос считается вектор запроса, ближайшие чанки уходят в промпт.
Главное: шаги 2 и 4 — разные операции, между ними стоит ручное действие пользователя. Файл в списке доказывает одно — разбор прошёл.
| Что вы наблюдаете | Где оборвалось | Куда смотреть |
|---|---|---|
| Файл в «My Documents», чат его не знает | шаг 3 | кнопка Save and Embed |
| Документ в пространстве, ответы пустые | шаг 4 | эмбеддер, лимит чанка, размерность |
В карточке документа 0 words | шаг 2 | скан без текстового слоя, кодировка |
| Цитаты приходят, но не те | шаг 5 | порог сходства, число сниппетов, язык |
Первую развилку дают три команды:
docker logs --tail 300 anythingllm 2>&1 | grep -iE 'collector|embed|chunk|failed|error'
sudo find /opt/anythingllm/storage/documents -name '*.json' | wc -l
sudo du -sh /opt/anythingllm/storage/{documents,vector-cache,lancedb,models}
Каталог documents растёт на шаге 2, vector-cache и lancedb — только на шаге 4. Если documents весит 40 МБ, а lancedb — 20 КБ, диагноз готов: разбор прошёл, эмбеддинга не было.
Документ загружен, но не «вшит» в рабочее пространство
Причина четырёх обращений из пяти — не техническая, а интерфейсная. Окно документов состоит из двух колонок: слева My Documents — общее хранилище всех разобранных файлов сервера, справа документы этого пространства. Перетаскивание кладёт файл в левую колонку.
Чтобы документ участвовал в ответах, нужны два действия подряд: пометить его галочкой и нажать Move to Workspace, а затем — обязательно — появившуюся внизу кнопку Save and Embed. Расчёт векторов запускает вторая, и она легко теряется в списке: закрыли окно крестиком — изменения отменены молча.
Два следствия. Документы не глобальные: файл, вшитый в пространство «Договоры», не виден пространству «Регламенты», хотя в «My Documents» лежит в одном экземпляре. И загрузка через API не привязывает файл никуда: /api/v1/document/upload только разбирает документ — главная ошибка при наполнении базы скриптом.
ALLM=http://127.0.0.1:3001
curl -s -X POST $ALLM/api/v1/document/upload -H "Authorization: Bearer $ALLM_KEY" \
-F "file=@/root/docs/reglament.pdf" | jq -r '.documents[].location'
curl -s -X POST $ALLM/api/v1/workspace/kb/update-embeddings \
-H "Authorization: Bearer $ALLM_KEY" -H 'Content-Type: application/json' \
-d '{"adds":["custom-documents/reglament.pdf-6f2c….json"],"deletes":[]}'
Значение location из первого ответа подставляется во второй дословно, вместе с хэшем в имени; ключ берётся в разделе Developer API.
Проверять привязку надёжнее в базе. Таблица workspace_documents хранит связь документа с пространством, document_vectors — записанные векторы. Работайте с копией:
sudo cp /opt/anythingllm/storage/anythingllm.db /tmp/allm.db
sqlite3 /tmp/allm.db "SELECT w.name, COUNT(wd.id) AS docs FROM workspaces w
LEFT JOIN workspace_documents wd ON wd.workspaceId = w.id GROUP BY w.id;"
sqlite3 /tmp/allm.db "SELECT wd.filename, COUNT(dv.id) AS vectors
FROM workspace_documents wd LEFT JOIN document_vectors dv ON dv.docId = wd.docId
GROUP BY wd.id ORDER BY vectors ASC LIMIT 20;"
docs = 0 — документ до пространства не доехал. docs > 0, а vectors = 0 — привязка есть, эмбеддинг провалился. Векторы есть, ответов нет — дело в поиске.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть AnythingLLMКоллектор разобрал файл не так, как вы думаете
Второй сценарий: документ в пространстве, векторы посчитаны, ответов нет — вшили пустоту. Если текста в файле нет, коллектор сохранит ноль символов, а карточка будет выглядеть обычной. Смотрите wordCount в разобранном JSON:
sudo jq -r '[.title, .wordCount, .token_count_estimate] | @tsv' \
/opt/anythingllm/storage/documents/custom-documents/*.json | sort -k2 -n | head
Ноль слов на шестидесятистраничном PDF — это скан. Своего OCR у AnythingLLM нет: файлы из сканера для него пустые. Лечится до загрузки:
sudo apt-get install -y ocrmypdf tesseract-ocr-rus poppler-utils
pdftotext -layout skan.pdf - | wc -c # около нуля — текстового слоя нет
ocrmypdf -l rus+eng --skip-text skan.pdf skan-ocr.pdf
Остальные причины пустого разбора:
- Формат. Старый бинарный
.doc(не.docx),.pages,.numbersи архивы не разбираются:libreoffice --headless --convert-to docx *.doc. PDF с паролем останавливает парсер даже при пустом пароле — снимайте защитуqpdf --decrypt. - Кодировка. Текст и CSV из российских учётных систем часто в
windows-1251. Коллектор читает их как UTF-8, в чанки уезжает мусор. Проверка —file -i notes.txt, лечение —iconv -f cp1251 -t utf-8 notes.txt -o notes-utf8.txt. - Вёрстка. Текст идёт потоком: двухколоночный PDF даёт перемешанные строки, таблица теряет структуру — выгружайте её отдельно в CSV.
- Ссылки на сайты. Сбор страниц по URL поднимает headless-Chromium внутри коллектора, и без
--cap-add SYS_ADMINон падает сNo usable sandbox!, тогда как файлы грузятся: «PDF индексируются, а сайты нет». Отдельная беда — Cloudflare и SPA: в индекс уходит текст капчи или пустой каркас.
Крупные файлы отваливаются ещё на прокси: client_max_body_size 1m рубит PDF молча — конфиг в статье про ошибки AnythingLLM на сервере.
Векторы не посчитались: чанки, лимиты эмбеддера и кэш
Если document_vectors пуст, а документ привязан, ищите в логе строку вида Could not embed document chunks! This document will not be recorded.: эмбеддер вернул ошибку, приложение откатило запись.
Эмбеддер не скачался. Режим native тянет ONNX-сборку all-MiniLM-L6-v2 с huggingface.co в storage/models/ при первом использовании; с обрезанным исходящим доступом загрузка виснет без сообщения. Проверка — sudo du -sh /opt/anythingllm/storage/models/: там сотни мегабайт, а не пустой каталог.
Чанк длиннее окна. Размер куска задаёт настройка Max embedding chunk length. У all-MiniLM-L6-v2 окно 512 токенов, и лишнее отбрасывается; у OpenAI превышение приходит явной ошибкой:
This model's maximum context length is 8192 tokens, however you requested
9411 tokens (9411 in your prompt). Please reduce the length of the prompt.
Рабочие значения — 500–1000 для встроенного эмбеддера, до 8000 для text-embedding-3-small; chunk overlap обязан быть меньше длины чанка.
Провайдер и модель. Индексация книги шлёт тысячи чанков подряд, OpenAI отвечает Rate limit reached for text-embedding-3-small ... on tokens per min, и документ пишется частично — грузите партиями. Эмбеддер в Ollama ставится отдельно от чат-модели (ollama pull nomic-embed-text), иначе получите model "nomic-embed-text" not found, try pulling it first.
Размерность не совпала. Самое коварное — смена эмбеддера на живой базе. Встроенный даёт 384 измерения, text-embedding-3-small — 1536, nomic-embed-text — 768. Chroma скажет прямо: Embedding dimension 384 does not match collection dimensionality 1536, LanceDB промолчит и перестанет находить старое.
И ловушка, на которой теряют вечер: AnythingLLM кэширует векторы в storage/vector-cache/ по хэшу файла. Меняете эмбеддер, удаляете документ, заливаете заново — а приложение достаёт из кэша старые. Поэтому чистка кэша обязательна: sudo rm -f /opt/anythingllm/storage/vector-cache/*.json.
Векторы есть, а чат отвечает «ничего не найдено»
Конвейер отработал, вопрос к поиску. Начните с режима чата в настройках пространства. В режиме Query модель отвечает строго по найденным фрагментам и при пустой выдаче возвращает шаблон There is no relevant information in this workspace to answer your query. В режиме Chat та же ситуация даёт ответ из общих знаний модели и выглядит как «документ проигнорирован» — для отладки Query удобнее.
Порог сходства. Параметр Document similarity threshold принимает значения от «No restriction» до «High». Высокий порог отсекает всё, что не совпало с запросом почти дословно, и на русской базе режет много. Для отладки поставьте «No restriction»: появились цитаты — дело в пороге.
Число сниппетов. Max Context Snippets по умолчанию равно 4. PDF на 200 страниц при чанке в 1000 знаков даёт порядка полутора тысяч фрагментов, а в промпт попадут четыре — вопрос «перечисли все сроки» так не решается. Поднимите до 6–12, если окно позволяет.
Контекстное окно. Сниппетов подняли до 12, а Ollama по умолчанию режет контекст до нескольких тысяч токенов: лишнее отбрасывается, и модель отвечает так, будто документов не видела.
ollama show qwen2.5:7b-instruct-q4_K_M --modelfile | grep -i num_ctx
printf 'FROM qwen2.5:7b-instruct-q4_K_M\nPARAMETER num_ctx 8192\n' > Modelfile
ollama create qwen-ctx8k -f Modelfile
Язык эмбеддера. Про это молчат инструкции, а по русскоязычным базам бьёт сильнее всего: встроенный all-MiniLM-L6-v2 обучен на английском. Русские документы он векторизует, но качество поиска падает, особенно если вопрос сформулирован иначе, чем текст. Берите многоязычную модель — bge-m3 (1024 измерения), multilingual-e5-large или text-embedding-3-large.
Честное ограничение. Векторный поиск не умеет считать («сколько всего договоров») и находить по точному идентификатору («что в пункте 5.3.2»). Обход один — закрепить документ булавкой: текст уйдёт в промпт целиком, минуя поиск, но это годится для одного-двух небольших файлов. Подбор компонентов — в материале про векторную базу для RAG.
Порядок восстановления: переиндексация без потери базы
Когда причина в эмбеддингах, документы надо пересчитать. Порядок важен: пропущенный кэш сводит работу к нулю.
- Бэкап. SQLite не любит копирование на ходу:
docker compose stop && sudo tar -czf /root/allm-$(date +%F).tgz -C /opt/anythingllm storage && docker compose start. - Зафиксируйте эмбеддер и проверьте ответ:
curl -s http://127.0.0.1:11434/api/embeddings -d '{"model":"bge-m3","prompt":"тест"}' | head -c 200. Пусто — дальше бессмысленно. - Выставьте нарезку заранее: чанк под окно модели, перекрытие 10–20% от длины.
- Удалите документы из пространства — снятие галочек и
Save and Embed; чистятся иworkspace_documents, иdocument_vectors. - Почистите
vector-cache, иначе пересчёт вернёт старые векторы. - Вшивайте партиями по 5–10 файлов под
docker logs -f anythingllm: так проще поймать файл, на котором всё встало. - Проверьте тем же SQL-запросом: у каждого документа ненулевое число векторов.
Две вещи проверьте заранее. Диск: документ хранится трижды — исходник, разобранный текст, векторы, — и ENOSPC: no space left on device посреди индексации оставит базу в половинчатом состоянии. Память: на тесной машине процесс уходит по OOM, это видно в docker inspect anythingllm --format '{{.State.OOMKilled}}'. Расчёт есть в статье про то, сколько RAM нужно для AnythingLLM.
Какой сервер под AnythingLLM брать в MAATRIX
Требования к железу задаёт индексация, а не чат: разбор PDF, расчёт эмбеддингов и запись в LanceDB идут в одном контейнере.
Честный минимум: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Документация называет 2 ГБ, но это граница для интерфейса поверх внешнего API: как только идут документы, к Node-серверу добавляются парсер и эмбеддер, и первая же партия сканов укладывает такую машину.
Комфортный вариант: 4 vCPU, 8 ГБ RAM, 80–120 ГБ NVMe. Разница видна не в скорости ответа, а в скорости наполнения: расчёт эмбеддингов на CPU хорошо параллелится. Восьми гигабайт хватает на несколько пространств, переиндексацию на живой системе и внешнюю векторную базу (Qdrant, Chroma) рядом. Диск считайте по правилу тройного хранения: 10 ГБ исходников займут в storage около 25–30 ГБ. Локальный инференс добавит веса — 7B в Q4 это ~4,5 ГБ, — поэтому генерацию разумнее отдать Ollama на отдельной машине.
Локация — Лондон (UK). Причина связана с темой статьи напрямую: встроенный эмбеддер идёт за ONNX-моделью на huggingface.co, а эмбеддеры OpenAI отвечают не на все адреса. С российского IP индексация встаёт на первом же документе и выглядит как поломка приложения. С британской площадки оба доступны напрямую, пинг до Европы низкий, а база рабочих документов лежит в понятном европейцам правовом поле. США (Нью-Йорк) берите под OpenAI, Россию — под 152-ФЗ, но тогда эмбеддер держите локальным.
Приложение из каталога apps.maatrix.io разворачивается автоматически при заказе сервера — команды вводить не нужно, работает и на Ubuntu, и на Debian. Адрес панели и ключи появятся в личном кабинете, в разделе «Доступ»: останется войти, выбрать эмбеддер (многоязычный, если база на русском) и залить первую партию документов. Оплата — картами российских банков, по СБП, криптой или токеном MAAT. Как подбирается площадка — в обзоре VPS в Великобритании для нейросетей.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть AnythingLLMОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Загрузил PDF, он виден в списке, но чат про него не знает.
Документ остался в «My Documents» и не привязан к пространству. Отметьте файл, нажмите Move to Workspace, а затем обязательно Save and Embed — векторы считает вторая кнопка. Проверка — запрос к workspace_documents в anythingllm.db.
Документ вшит, векторы посчитаны, а ответы всё равно «не нахожу».
По очереди: режим чата на Query, порог сходства на «No restriction», сниппетов с 4 до 8. Не помогло — смотрите wordCount в JSON внутри storage/documents/: у скана без OCR там ноль, вшита была пустота.
Сменил эмбеддер, перезалил документы — поиск не работает.
Старые векторы достались из кэша: AnythingLLM хранит их в storage/vector-cache/ и переиспользует по хэшу файла. Удалите документы из пространства, очистите vector-cache/*.json, только потом вшивайте заново.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.