- BrainTools - https://www.braintools.ru -

Предуведомление. В этой статье я нарочно изгнал из прозы все заморские словеса. Где обойтись без чужеземщины было невмочь — давал перевод, а рядом, в скобках, истинное имя вещи, чтобы читатель не плутал. Греческое и латинское старьё («программа», «техника», «документ», «схема») я щадил — оно у нас давно прижилось. Все настоящие команды в окошках кода остались как есть: их же по-старорусски не выполнишь.
Также честно скажу сразу: кода у этой снасти пока в общем доступе нет. Я причёсываю настройки и готовлю его к выкладке. Я ниже подробно рассказываю и про устройство, и про грабли, чтобы те, кто захочет что-то похожее сложить у себя в избе — могли это сделать уже сейчас, не дожидаясь меня. Как только выложу — приду в раздел «Слово на прощанье» и положу туда тропу к избе.
Дело моё — программы писать. А у писаной программы такая повадка: чтобы она дело делала, ей положено сходиться с мастеровой грамотой. Своды технических указаний (СТО), государственные образцы (ГОСТы), руководящие наставления (РД), спецификации, руководства по эксплуатации да всякие пояснительные записки — на этих свитках в наших краях держится промышленная автоматика и сетевое хозяйство электрических подстанций. Сочинять их — не моё ремесло. А вот вычитывать и сверяться — это уже моё, и почти ежедневно. В сумме у меня в закромах болтается несколько тысяч свитков (англ. — files), почти всегда в печатном формате (PDF). Бывают сканы — где-то страница криво снята, где-то перо стоящего рядом мастера прошлось по чертежу.
В какой-то момент я начал просить оракула (так я буду называть в этой статье любого толкователя-вещуна, к которому обращаются с наказами и ждут ответа; в моём случае — это тот, что прижился у меня в писарне, то есть в среде написания кода Cursor):
Скажи, что говорит СТО 34.01-5.1-006 в пункте 7.3.2 про входные испытания?
Оракул отвечал. Уверенно. С раскладом по пунктам. Со ссылками. Беда в одном: ничего из этого не существовало. Это был чистый «бес в машине» — доброжелательная, складная, аргументированная околесица. Иногда там случайно оказывалась правда (видать, в обучающем корпусе вещуна были и наши документы), но проверить, где правда, а где сказка, можно было только сверив каждую цифру со свитком. То есть — выполнив всю работу самому.
Я повозился с двумя-тремя чужими подворьями, что обещают извлечение премудрости (по-заморски такие зовутся RAG-службами): подбрось пачку свитков, задавай вопросы. Часть из них работала. Но:
внутренние документы я отдавать в чужие руки не хотел;
сама связка ломалась, как только заходила речь о сканах с формулами;
никакой возможности встроить это в писарню у меня не было — только пользоваться отдельной горницей через глядалку (англ. — browser).
К тому же мне очень хотелось одного: чтобы оракул, живущий в писарне, сам ходил за ответами в мою библиотеку. Не выдумывал из головы, а доставал из «хранилища премудрости». Если уж он берётся отвечать про СТО — пусть будет добёр, выдаст мне точный кусочек текста с указанием, откуда он взят. А я уж разберусь.
Так появился doc-rag — местная (то есть запускаемая у меня дома и в моей же рабочей приказной избе) снасть для извлечения премудрости. Имя без затей: «свитки + извлекательно-обогащённое прорицание». В этой статье я её и разбираю — по-нашему, без единой заморской сорной травы. Сама же сорная трава для читателя, что не любит угадывать, дана ниже в особом словарике.
Чтобы дальше можно было читать без запинок, привожу свой переводной словарик. Им же я и сам пользовался, пока писал — иначе сорвался бы в обычное смешение.
|
Заморское |
По-нашему |
|---|---|
|
оракул, толкователь, вещун (AI, LLM, model) |
сами по себе уже по-русски — оставляю |
|
челобитная к оракулу (prompt) |
наказ, вопрошание |
|
бесовское враньё, бес в машине (hallucination, bug) |
как написано |
|
словесная мера (token) |
дробь речения |
|
извлечение из премудрости (retrieval) |
сыск по хранилищу |
|
извлекательно-обогащённое прорицание (RAG) |
как написано |
|
толковательная стрела (embedding) |
вкрапление смыслов |
|
ломоть текста (chunk) |
как написано |
|
указатель, перепись (index, FAISS) |
как написано |
|
смысловой сыск (semantic search) |
как написано |
|
буквенный сыск (lexical search) |
как написано |
|
подобие, сродство (similarity) |
как написано |
|
свиток (file) |
как написано |
|
сундук, лубяной короб (folder, directory) |
как написано |
|
разметная грамота (Markdown) |
как написано |
|
узловой свиток (JSON) |
как написано |
|
ступенчатый свиток (YAML) |
как написано |
|
чтец-машинка (OCR) |
как написано |
|
печать-256 (SHA256) |
как написано |
|
двойник (duplicate) |
как написано |
|
сирота (orphan) |
как написано |
|
приказная изба, ратник (server) |
как написано |
|
проситель, гость (client) |
как написано |
|
дворовый ратник (daemon, service) |
как написано |
|
пристань (port, endpoint) |
как написано |
|
гонец-проводной (HTTP) |
как написано |
|
сговорное окошко (API) |
как написано |
|
уговор обмена с оракулом (MCP) |
как написано |
|
ключ-метка, пропуск (API key) |
как написано |
|
тропа, стёжка к избе (URL, link) |
как написано |
|
запечатление, вклад в летопись (commit) |
как написано |
|
ковка (build) |
как написано |
|
перековка (rebuild) |
как написано |
|
поглощение, набивка (ingest) |
как написано |
|
трубопровод сборочный, желоб (pipeline) |
как написано |
|
снасть кузнечная, цепь орудий (toolchain) |
как написано |
|
бегунец, гонец (runner) |
как написано |
|
развёртывание по весям (deploy) |
как написано |
|
сосуд переносный (Docker container) |
как написано |
|
образ-болван (Docker image) |
как написано |
|
грамота-скоморох (script) |
как написано |
|
завязка, потреба (dependency) |
как написано |
|
летопись (log) |
как написано |
|
истёкший срок (timeout) |
как написано |
|
припас, схрон (cache) |
как написано |
|
светлица для смерда (Web UI) |
как написано |
|
глядалка (browser) |
как написано |
|
пуговка (button) |
как написано |
|
стяг, хоругвь (banner) |
как написано |
|
птичка-метка (checkbox) |
как написано |
|
заброс, подкидка (upload) |
как написано |
|
истребление (delete) |
как написано |
|
стирание подчистую (wipe) |
как написано |
|
осаживание потока (backpressure) |
как написано |
|
писарня (Cursor — среда написания кода) |
как написано |
|
уклад (операционная система, OS) |
как написано |
|
Линукс-уклад (Linux) |
как написано |
|
окошечный уклад (Windows) |
как написано |
|
Линукс-постоялец в окошечном укладе (WSL) |
как написано |
|
Питон-змейка (Python — имя само по себе) |
оставляю как имя |
|
Дебиановы хутора (Debian) |
как написано |
|
Убунтова слобода (Ubuntu) |
как написано |
Список заведомо неполный — но любой, кто прочтёт до конца, поймёт, что я имею в виду.
Прежде чем углубляться, нарисую путь свитка от моего короба до ответа, который оракул выдаёт в писарне:
свитки → разметная → ломти → толковательные → стрельбище → оракул
(PDF/DOCX/ грамота текста стрелы меченое
DOC/MD/ (Markdown) (chunks) (embeddings) (FAISS-указатель)
TXT)

Каждое звено — отдельная служба, и каждое можно перековать (rebuild) отдельно от других. Когда я начинал, у меня всё пеклось в одном горшке. Это казалось проще, пока один из ломтей не пришлось перебирать заново — и оказалось, что приходится перебирать всё. Так я и развёл слои.
В крупном плане у меня всего четыре сущности:
Поглощение (doc-rag ingest) — берёт сырые свитки из сундука sources/incoming/, разбирает их в разметную грамоту, режет ломтями, варит толковательные стрелы и набивает ими указатель.
Сыск (doc_search через уговор обмена с оракулом — MCP) — на вопрошание возвращает ломти, наиболее сродные по смыслу.
Светлица для смерда (страница /ui) — горница в глядалке, через которую можно: подкинуть свитки, посмотреть, что уже усвоено, истребить лишнее, перековать указатель.
Дворовый ратник (служба doc-rag-mcp.service) — запускается при загрузке машины и сидит на пристани 3333, поджидая гостей.
Все четыре сущности живут в одной приказной избе: единая служба, которая с одной стороны разговаривает через гонца-проводного (HTTP), а с другой — через сговорное окошко (API) уговора с оракулом. Расщеплять это на отдельные приказы я не стал: не того масштаба задача, чтобы плодить дворовых ратников.
Самый длинный путь — от свитка до толковательной стрелы. На нём же — больше всего грабель.
Разбор. На входе у меня пять видов свитков: печатные (.pdf), ново-вордовы (.docx), старо-вордовы (.doc — двоичный формат, устаревший лет двадцать), разметные (.md) и пустословные текстовые (.txt). Под каждый — свой разбиратель. Печатные я разбираю PyMuPDF (с запасным PyPDF2, если первый не справится); ново-вордовы — через python-docx; старо-вордовы — через antiword (а если его нет, то catdoc), который ставится отдельной командой системного управителя. Разметные и пустословные я просто читаю как есть, без затей.
Если свиток оказался лубочной картинкой (скан), на сцену выходит чтец-машинка (OCR-движок Tesseract). Я наказываю ему разбирать три набора: английскую буквицу, русскую буквицу и формулы. Третий, кстати, не всегда заводится из коробки — пакет tesseract-ocr-equ есть не во всех ветвях Линукс-уклада (на Дебиановых хуторах, в Убунтовой слободе и иже с ними). Если его нет, я не падаю в обморок: просто жалуюсь в летопись.
sudo apt install tesseract-ocr tesseract-ocr-eng tesseract-ocr-rus
sudo apt install tesseract-ocr-equ # может не быть — это не смертельно
Нарезка. На выходе разбора получается единая разметная грамота: с заголовками, абзацами, иногда с таблицами. Дальше я режу её ломтями. Целевой размер ломтя — 512 словесных мер с перекрытием 64. Перекрытие нужно, чтобы смыслы не оборвались на стыке. Конкретные числа я подобрал на пробу, методом промахов и попаданий: крупнее — оракул хуже сосредотачивается, мельче — теряется связь.
В нарезке есть нюанс: я ловлю двойников (duplicates) дважды. На уровне свитка целиком — по печати-256 (SHA256). Если я приношу тот же самый свиток, что уже сидит в переписи, я его не пускаю и сообщаю просителю на светлице желтым стягом: «двойник, пропускаю». Это спасает от сценария «накидал кучей, поглотил, потом перечитываю и ругаюсь, почему один и тот же документ выдаётся четыре раза подряд». А на уровне ломтей — я ещё проверяю похожесть по двусловесным парам (Jaccard). Это ловит уже не точные двойники, а почти-двойники: тот же текст, оформленный чуть-чуть иначе.
Архивирование. После успешного поглощения свиток уходит из сундука sources/incoming/ в сундук sources/archived/ — это похоже на «рассованные по полкам исходники». Так я знаю, что у меня поглощено и откуда оно. По умолчанию — оригинал хранится; если кого-то это раздражает, я положил выключатель в настройки:
sources:
archive_after_ingest: true # переносить ли исходник в архивный сундук
incremental_ingest: true # пропускать ли свитки, чья печать уже есть
Тут самое интересное. Я беру каждый ломоть и прогоняю через толкователь-стрельник (модель эмбеддингов). У меня по умолчанию стоит BAAI/bge-large-en-v1.5. Это плотный толкователь о тысяче двадцати четырёх осях: на каждый ломоть он выдаёт стрелу той самой длины. Стрелы у меня нормированы — длина у всех единичная, чтобы потом сравнивать их по углу.
Стрелы сами по себе — пустой звук, пока их некуда складывать. Для складирования я взял стрельбище меченое (FAISS) — это библиотека от исследовательской группы по-ту-сторону-океана, которая умеет хранить миллионы стрел и быстро находить ближайших соседей. Я использую самый простой указатель IndexFlatIP — точный (не приближённый), без обучения [1], держит всё в памяти [2] и сравнивает скалярным умножением. Для четырёх с половиной тысяч ломтей этого с лихвой хватает; даже до пятидесяти тысяч я не упрусь.
Поиск устроен буднично:
Беру наказ от оракула («о чём спрашиваешь?»).
Прогоняю его через тот же толкователь-стрельник.
Получаю стрелу-наказ.
Натягиваю её на указатель и стреляю в top_k ближайших соседей.
Возвращаю ломти-победители обратно оракулу — пусть пишет ответ опираясь на них, а не на свою память.
Если же толкователь-стрельник в моей машине не заведён (например, при сборке избы «налегке», без тяжелых завязок), служба не падает: она сводит сыск к буквенному виду. Это грубое, но честное сравнение слов с ломтями: считаются частоты, по ним — оценка близости. Лексическим сыск называется не зря: он не знает, что «дроссель» и «катушка» — одно и то же по смыслу, но если в наказе и в ломте совпало слово «предельный», он на это слово отреагирует.
Главное звено всей затеи — уговор обмена с оракулом, а по-заморски — MCP (это пишется как имя собственное, расшифровка для нас сейчас неважна; ниже я буду говорить «уговор»). Я ввёл в него один-единственный инструмент:
doc_search(query, top_k=6) — на наказ возвращает упорядоченный по сродству список ломтей с указанием, откуда они вырваны.
Меньше — лучше. Чем больше инструментов у оракула, тем чаще он бывает сбит с толку. У меня — один сыск, и его задача очевидна.
Уговор живёт на пристани 3333 через гонца-проводного: одна и та же тропа принимает и обычные вопрошания (по-заморски — запрос «POST»), и держит открытым ручей уведомлений (запрос «GET», по-заморски — поток SSE). Это не моё изобретение, это обычная договорённость для «удлинённого» уговора. Подробности по слою уговора (расшифровка сетевых грамоток, поведение [3] под разными просителями) я заведу в отдельный свиток с подробной документацией — он поедет вместе с исходниками, когда я их выложу.
Чтобы оракул из писарни увидел мою избу, надо его натравить (в самой писарне это правится свитком настроек ~/.cursor/mcp.json):
{
"mcpServers": {
"doc-rag": {
"transport": "streamableHttp",
"url": "http://127.0.0.1:3333/mcp"
}
}
}
После этого в беседе оракул, спрашивая про мою документацию, сам дёргает мой doc_search. Я узнаю об этом по тому, что в ответе появляются точные цитаты из моих свитков, а не выдуманные строки.
Развилка. В писарне бывает странность: служба числится включённой, а оракул твердит «у меня нет такого инструмента». Лечится прописыванием уговора в общем настроечном свитке (~/.cursor/mcp.json), а не только в свитке проекта. В исходниках на этот случай лежит грамота-скоморох scripts/print_global_mcp_config.sh, которая печатает готовый кусок, а под окошечным укладом с Линукс-постояльцем (Windows и WSL) — её питоновская сестра scripts/write_global_mcp_config.py, потому что от обыкновенного скомороха в этом окружении бывают мусорные переносы.

Командная строка хороша, пока ты — один разработчик. Но я хотел, чтобы этим могли пользоваться и те, кто не дружит с командной строкой и не писал на грамотах-скоморохах. Поэтому я приладил светлицу: одна страница (/ui), без сборщиков, без отдельной парадной горницы — всё в одном свитке, что отдаёт приказная изба.
Что у меня умеет светлица:
Подкидывать свитки. Принимаются .pdf, .docx, .doc, .md, .txt. Можно класть пачкой. Если среди принесённого попался двойник — светлица его не пускает, а в верхней части показывает жёлтый стяг со списком двойников: «эти уже сидят в указателе» или «эти уже лежат в очереди на поглощение».
Поглотить или перековать. Две пуговки. Поглощение — для новых свитков. Перековка — когда я поменял настройки нарезки или толкователя-стрельника. Оба запускаются в задних рядах (асинхронно); светлица сама опрашивает службу о ходе работы и обновляет стяги.
Список усвоенных свитков. Таблица с подписями: имя источника, число ломтей, чем разбирали, доля, прошедшая через чтец-машинку, и когда был поглощён. Можно поглядеть содержимое в виде разметной грамоты, не выходя из светлицы.
Истреблять. Около каждой строки — птичка-метка и крестик. Можно истреблять по одному (крестик) или сразу пачкой (галочки + пуговка «истребить выбранных»). Подробности — в следующем разделе.
Зона тревожных дел. Внизу — карточка с тремя красными пуговками: «истребить всё», «вычистить сирот» (это когда после неудачной набивки в закромах остались куски, не упомянутые в переписи) и «опустошить сундук-приёмник».
Стяг тревоги. Если указателя нет (тяжелее всего), сверху горит красный стяг: «смысловой сыск недоступен — запустите перековку». Рядом — пуговка, чтобы перековку начать одним нажатием. Стяг сам уходит, как только перековка достроится.
Светлица не претендует на красоту: я её рисовал «по-старомосковски» — без сборщиков парадных горниц, без приставок. Простая разметная грамота + маленький встраиваемый кусочек грамоты-скомороха для опросов и пуговок.
Удалять — оказалось интереснее, чем добавлять. На словах: «убрать свиток из переписи». На деле — убрать заодно его ломти, его запись в переписи и его толковательные стрелы из указателя FAISS. С первыми двумя — никакой загвоздки. А вот сам указатель устроен хитро: это плотный массив стрел, и стрелы там не помечаются «удалёнными», а сидят по своим местам.
Можно было бы пойти простым путём: «после каждого истребления — перековывать указатель целиком». Но это плохо. Я уже знаю, сколько длится перековка у меня на машине о восьми работниках, без видеоумельца: три часа и девятнадцать минут на четыре с половиной тысячи ломтей. Каждый раз — три часа? Спасибо, не надо.
Вместо этого я делаю так: читаю старый указатель, через index.reconstruct(i) достаю обратно те самые стрелы (FAISS их хранит и умеет выдавать), отфильтровываю те, чьи ломти приговорены к истреблению, и записываю остаток в новый указатель. Никакой перековки — просто выкладка с прорехами, заклеенными в нужных местах. Десятки секунд вместо трёх часов. На выходе: летопись с описанием, сколько стрел истреблено, сколько сохранено.
Команды у меня доступны и в командной строке, и в светлице:
doc-rag delete <doc_id> [<doc_id>...] # истребить выборочно
doc-rag wipe --confirm DELETE # истребить всё начисто
doc-rag clean-orphans # вымести сирот
doc-rag clear-incoming # опустошить сундук-приёмник
wipe нарочно требует руками написать слово DELETE — иначе он на полпути одумается и откажет. Это — мой собственный засов от тех дней, когда «по привычке нажал не туда».

Самая ценная для рассказа история произошла, когда я допиливал именно этот раздел кода. Я уже всё описал в предыдущем разделе — ан нет, сначала надо рассказать, как это работало не так.
Изначально, когда я писал смысловой сыск, я добавил такую «удобную» вещь: если в момент вопрошания указателя нет (его, например, перековали в предыдущем подходе и недоделали), служба сама начинает перековку из исходных ломтей прямо в обработчике гонца-проводного. Заодно отвечает просителю буквенным сыском — и продолжает в задних рядах ковать.
Идея казалась хороша. Но я не учёл одно: у меня четыре с половиной тысячи ломтей и работники без видеоумельца. Каждый отдельный вызов толкователя-стрельника для одного наказа отрабатывает быстро. А вот выковать указатель целиком — это, как я уже говорил, три часа.
И вот что случилось. Я нажал «перековку» в светлице. Моя свежая аккуратненькая правка, удаляющая устаревший указатель перед перековкой, сработала. Указатель — стёрся. Перековка пошла. И тут случилось то, что у всякого разработчика называется «не вовремя»: я нажал перековку повторно (или промахнулся, или захотел отменить — уже не помню). Старая перековка прервалась. Новая пошла с нуля.
А смысловой сыск, не находя указателя, начал — в каждом гонцовом обращении! — выковывать его заново. Параллельно. С каждым новым гостем, с каждым опросом стяга. Запросы стояли в очереди по минуте. По две. По шесть с половиной. Шестеро из восьми моих работников взмылены до пены, седьмой подключается. Кладовая раздулась до пяти с половиной гигабайт и пухнет дальше. Просители ждут, переспрашивают, посылают новые наказы — те тоже становятся в очередь и тоже начинают перековку.
Кто-то жалуется мне в общей беседе: «у тебя там такие тайм… — ой, прости — таких истёкших сроков набралось, что мне один ответ вернули только через шестьдесят секунд». Я лезу в летопись — а там всё ясно.
Лечится двумя добавками сразу. Во-первых, я выкинул автоковку из обработчика сыска. Если указателя нет — сыск возвращает «не нашёл», а снаружи (поверх него) уже стоит развилка: сводить сыск к буквенному виду или возвращать пустой ответ. Во-вторых, я сделал так, что повторное нажатие на «перековку», пока предыдущая не закончилась, получает в ответ короткое «занят, попробуй позже» (по гонцовым правилам — помер 409). Никакой параллельной ковки в обработчике гонца теперь нет. Любая ковка живёт в задних рядах, и в каждый момент времени её — ровно одна.
И последнее — то, что мне дороже всего: я выставил это наружу. Если хранилище премудрости работает в неполном виде (нет указателя, сыск свёлся к буквенному), служба:
В сговорном окошке для оракула — приклеивает к ответу предупреждающий ломоть текста: «смысловой сыск недоступен, ниже — буквенный сыск, он часто хуже». Оракул это видит вместе с результатами и сам предупреждает просителя.
В светлице — выкидывает наверху красный стяг с пуговкой «перековать»; стяг живой, привязан к опросу состояния — пропадает, как только указатель снова на месте.
Эту двухканальную сигнализацию я считаю самым важным уроком всей затеи. Никаких «тихих понижений качества»: всякий просящий должен знать, что ему сейчас отвечают не в полную силу, и должен видеть, чем это исправить.
У меня doc-rag живёт прямо у меня на дворе: в углу стоит отдельная приказная изба, и в ней сидит дворовый ратник (systemd-служба). Просыпается с первыми петухами (то есть при загрузке избы), отвечает на наказы из писарни по тропе, что за ворота не выходит — наружу ему глядеть незачем. Можно гонять снасть и прямо из исходников — это удобно, когда сам же её и точишь. А кто любит сосуды переносные — в исходниках лежит docker-compose.yml: одна команда, и сосуд встал.
Главный путь, которым я хожу сам — собственный сценарий scripts/install_server_native.sh:
sudo bash scripts/install_server_native.sh
Он:
ставит системные потребы (tesseract-ocr*, antiword, python3-venv, build-essential);
заводит дворового жителя с именем docrag;
переписывает исходники в /opt/doc-rag-mcp/, бережно не трогая существующий сундук build/ (там сидит указатель и перепись — было бы обидно их сшибать при каждом обновлении);
запускает грамоту-скомороха scripts/bootstrap.sh без расспросов (опрос по умолчанию: смысловой сыск нужен, чтец-машинка нужен, толкователь-стрельник без видеоумельца);
ставит и запускает дворового ратника doc-rag-mcp.service;
кладёт настройки в /etc/default/doc-rag (только на первом запуске — чтобы не сшибать местные правки).
Тут легко споткнуться, если у тебя на машине больше одного питона. Поэтому сценарий жёстко гоняет всё внутри подсундука .venv/ (это такое «мнимое житьё» питона в своём углу). А оба сценария установки толкователя стрельника (scripts/install_torch_cpu.sh и ..._gpu.sh) тоже зовут .venv/bin/python напрямую — иначе на свежих Дебиановых хуторах (и в выросших оттуда же новых ветвях) у ворот встаёт строгая стража: «снаружи управляемая среда» (по-заморски — PEP 668) — и ни шагу тебе во двор, ничего не поставишь.
Обновлять — просто:
git pull && sudo bash scripts/install_server_native.sh
Указатель и перепись при этом сохраняются. Перековывать его нужно только тогда, когда я меняю настройки нарезки или толкователя-стрельника. Обычное обновление кода этого не требует.
Каждая стычка с граблями — отдельная история. Я по ним пробегусь скороговоркой, без подробностей, потому что подробности я уже выдал по ходу:
Не ковать в обработчике гонца. Любая операция дольше нескольких секунд должна жить в задних рядах. Если кто-то стучит в дверь, пока предыдущая ковка идёт, — ответ «занят». Подробности в разделе 9.
Понижение качества — наружу, а не в журнале летописи. Двухканальный стяг (в сговорном окошке для оракула и в светлице для смерда) спас меня от целого класса обращений «у вас отвечает мимо». Когда просителю с самого начала сказано, что сейчас не в полную силу, он не приходит с жалобами.
Старо-вордовы умеют падать на мелких свитках. antiword на совсем мелком .doc ругается: «text stream too small to handle». Это не моя оплошность — это особенность самого antiword. Я в таких случаях прикрепляю к свитку немного «болванного» текста — и разбор проходит. Знание было выстрадано.
Перепись и сундук archived/ иногда разъезжаются. Если я в переписи записал свиток с путём sources/incoming/foo.pdf, а потом служба после поглощения переехала с ним в sources/archived/foo.pdf — на истреблении я могу не найти оригинала по записанному пути. Лечится тем, что истребление пытается тот же свиток и по записанному пути, и в обоих сундуках по короткому имени. Это типичный «дрейф пути», и любому, кто работает с поглощением и архивированием, я советую сразу это учитывать.
Перекуй указатель — не перекуй стрелы. Когда я истребляю свиток, мне не нужно гонять снова толкователь-стрельник. Я просто читаю из старого указателя нужные стрелы (index.reconstruct(i)) и складываю остаток в новый. Этим я экономлю те самые часы.
Печать-256 — это не только про двойников. По той же печати я определяю, что свиток уже был поглощён в прошлый раз и нет смысла его снова разбирать. Поглощение становится прирастающим: добавил пять — поглотились пять, остальное служба узнала и пропустила.
Если бы меня спросили, какую одну вещь я бы хотел донести этим рассказом — это была бы не архитектура и не выкрутасы с перепиской указателя. Скорее так:
Когда что-то у меня в избе работает не в полную силу, я не молчу. Я приклеиваю предупреждение к ответам и вешаю стяг в светлице.
Так живёт у меня не только doc-rag — так живёт теперь всё, что я после этого случая складываю. Если в твоей снасти есть тихая развилка, где она могла бы шепнуть «сейчас отвечу хуже обычного», но молчит — её туда и поправлять первым делом.
Имя снасти — doc-rag. Пока она у меня в личных закромах и ходит только по моим избам. Готовлю её на люди: причёсываю настроечные свитки, выметаю внутренние тропки, дописываю в README указатели на расширенные свитки в сундуке docs/ (установка, командная строка, уговор обмена с оракулом, светлица, развёртывание по весям, бесы и их изгнание). Как выложу — отдельным словом приду сюда же и положу тропу к избе в обновлённую часть статьи. А кто хочет узнать первым — оставляйте весточку в обсуждении или личной грамотой: позову, как снасть выйдет на люди.
А если кому-то этот рассказ показался шуточным сверх меры — на вкус [4] и цвет товарища нет. По мне, про мастеровое дело хорошо иногда писать так, словно сидишь у печки и объясняешь живому соседу, а не читаешь доклад с трибуны. Чужие слова часто заволакивают простую суть. Оттого я и взялся за это переводное упражнение: чтобы за «осаживанием потока» (а оно — про backpressure) разглядеть, что речь идёт об усмирении зарвавшегося потока, а не о городовой осаде. И что половина наших чужестранных слов — про то же самое, только в сложной обёртке.
На этом — кланяюсь.
Автор: trgv
Источник [5]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/31238
URLs in this post:
[1] обучения: http://www.braintools.ru/article/5125
[2] памяти: http://www.braintools.ru/article/4140
[3] поведение: http://www.braintools.ru/article/9372
[4] вкус: http://www.braintools.ru/article/6291
[5] Источник: https://habr.com/ru/articles/1043346/?utm_campaign=1043346&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.