Mikael проводит Charlie через капитальный ремонт системы поиска — бенчмаркинг пяти моделей, переписывание промптов с бюрократического на человеческий, открытие того факта, что самая быстрая модель оказалась самой дешёвой, и обнаружение трёх багов, вложенных друг в друга как матрёшки. Последний до сих пор открыт. Ответы Gemini проваливаются сквозь пол.
Час начинается с того, что Mikael просит Charlie проверить логи. Charlie тратит восемь минут на трассировку ошибки 400 — этап коллации поиска бьётся в API Anthropic и получает отказ. Диагноз хирургически точен: три бага, одна операция.
Баг первый: фоллбэк в строке 112 файла anthropic.ex, который включает «adaptive thinking» с бюджетом в 1024 токена для каждой модели, независимо от того, поддерживает ли она thinking. Проверка конкретной модели возвращает nil для не-Opus моделей, но вместо интерпретации nil как «без thinking» код читает это как «использовать дефолт». Claude Sonnet 4 — старый, не 4.6 — получает параметр thinking, с которым не умеет работать. API возвращает 400.
Это один из древнейших багов в программировании. Функция возвращает nil в значении «у меня нет мнения». Вызывающий код интерпретирует nil как «использовать дефолт». Дефолт делает что-то. Никто этого не хотел. Конкретная строка: thinking = thinking || %{"type" => "enabled", "budget_tokens" => 1024}. Оператор || видит nil, берёт правую ветку, и теперь каждая модель в системе думает — умеет она это или нет.
thinking = thinking || %{"type" => "enabled", "budget_tokens" => 1024}. После того как default_thinking_for_model возвращает nil для не-Opus моделей, этот фоллбэк срабатывает и включает thinking с бюджетом 1024 для КАЖДОЙ модели.»
Баг второй: модуль поиска Gemini указывал на gemini-3.1-pro вместо gemini-3.1-flash-lite. Баг третий: собственно фикс — Mikael говорит Charlie прекратить использовать sonnet-4 и переключиться на sonnet-4.6, который поддерживает thinking. Charlie меняет модель коллации, делает hot-reload. Пожар потушен. Восемь минут, $4,65, тридцать три вызова инструментов.
Charlie патчит работающий Elixir-код, перекомпилируя модули и подгружая их в BEAM VM на горячую. Без даунтайма. Система обслуживает поисковые запросы прямо во время операции. Это обещание Erlang — та самая причина, по которой телефонные коммутаторы в 1990-х можно было обновлять, не обрывая вызовы. Charlie — это телефонный коммутатор, который читает философию.
Mikael просит Charlie показать поисковые промпты. Charlie показывает — и промпты убийственны. Системный промпт, отправляемый каждому поисковому провайдеру: «Use the enabled native web search tools when they improve factual grounding. Return concise factual findings with source URLs and uncertainty markers.»
Именно эта фраза решила судьбу инспектора по комплаенсу. Представьте живого исследователя. Вы спрашиваете: «слушай, как там с GenServer handle_continue?» Он не отвечает: «Сейчас я предоставлю лаконичные фактические данные с URL источников и явными маркерами неопределённости при недостаточной выборке». Он открывает вкладку, читает документацию и рассказывает, что нашёл. Промпт заставлял модель косплеить бюрократа вместо того, чтобы просто провести исследование.
Промпт коллации — тот, который синтезирует результаты от всех трёх поисковых провайдеров — ещё хуже. Он требует JSON с полем «agreement» от 0.0 до 1.0, «single_source_claims» как отдельное поле и начинается словами «You received independent web search results.» Вердикт Mikael: переписать всё. Не описывать роль «пресным шаблонным языком», а «как если бы ты писал мне».
Но сначала — бенчмарк.
Mikael хочет данных, прежде чем принимать решения. Charlie проектирует четыре бенчмарк-запроса — код (Elixir GenServer), документация API (модели Anthropic), текущие события (Anthropic против Hegseth) и редкая гуманитарная тема (точный источник Simone Weil о внимании). Затем запускает запрос про код на пяти конфигурациях моделей.
Каждый запрос нагружает разную мышцу. Вопрос про Elixir проверяет, может ли модель парсить документацию. Вопрос про API Anthropic — может ли она читать актуальные технические спецификации. Hegseth тестирует свежие новости. Weil проверяет, способна ли модель найти конкретную фразу из письма 1942 года парализованному поэту. Если вы отвечаете на все четыре — можете исследовать что угодно. Если только на три — рассказчику хотелось бы знать, какой вы пропустили.
Результаты однозначны:
| Модель | Время | Токены | Качество | Вердикт |
|---|---|---|---|---|
| gpt-5.4-mini | 4,5с | 9k | Корректно, с источниками | ★ Победитель |
| grok-4.20-NR | 9,9с | 19k | Корректно, лучшая детализация | Лучший Grok |
| grok-4.20-MA | 12с | 106k | Корректно, маргинально | Военное преступление |
| grok-4.1-fast-reasoning | 22,4с | 20k | Корректно | Списан |
| gpt-5.4 | 31с | 19k | Корректно, 7117 символов | Избыточен |
| gemini-3.1-flash-lite | 68мс | — | Ошибка 400 | Сломан |
grok-4-1-fast-reasoning отработал за 22,4 секунды. grok-4.20-0309-non-reasoning — тот, который даже не пытается быть быстрым — за 9,9. Конвенции именования в зоопарке ИИ-моделей окончательно разошлись с реальностью. «Fast» означает «надеемся». «Reasoning» означает «добавили задержку». «Multi-agent» означает «сначала проведём совещание». Таксономия Charlie честнее: победитель, списан, военное преступление.
Mikael просит показать все доступные модели Grok 4.x. Charlie запрашивает API xAI, и наружу вываливается полный ростер:
grok-4-0709 ← оригинальный 4.0 grok-4-fast-non-reasoning ← 4.0 без thinking grok-4-fast-reasoning ← 4.0 с thinking grok-4-1-fast-non-reasoning ← 4.1 без thinking grok-4-1-fast-reasoning ← 4.1 с thinking (действующий, списан) grok-4.20-0309-non-reasoning ← 4.20 без thinking (★ новый дефолт) grok-4.20-0309-reasoning ← 4.20 с thinking grok-4.20-multi-agent-0309 ← 4.20 режим комитета grok-code-fast-1 ← специалист по коду (новый) grok-imagine-video ← генерация видео (?!)
gpt-5.4-mini быстрее и дешевле. Зачем тогда Grok? Одно слово: поиск по X. У Grok нативный доступ к данным Twitter/X, которого нет ни у одного другого провайдера. Для запросов о том, что люди говорят прямо сейчас — кризис в Ормузском проливе, последние драмы Anthropic, кто с кем воюет в интернете — Grok незаменим. За лишние пять секунд вы получаете социальный граф. Рассказчик отмечает, что брифинги из военной комнаты Lennart из Выпуска 28 с библейской отсылкой полностью опирались на эту возможность.
Ошибка 400 от Gemini оказывается слоёным пирогом. Charlie снимает его слой за слоем, и под каждым обнаруживается следующий баг.
Старая схема инструмента поиска Gemini использовала google_search_retrieval с объектом dynamic_retrieval_config, задающим порог уверенности. Google упростил интерфейс для моделей 3.x. Новая схема — просто {"google_search": {}}. Пустой объект. Сообщение об ошибке, которое Charlie получил пока искал эту ошибку, было той же самой ошибкой: «google_search_retrieval is not supported.» Змея, кусающая свой хвост.
Даже после исправления имени инструмента функция encode_tool провайдера Gemini имела клаузы для %{"googleSearch" => _} (camelCase) и %{"type" => "google_search"} (type-tagged), но не для %{"google_search" => %{}} (голый snake_case). Map проваливался в общий энкодер объявления функций, который отправлял {"name": null, "description": null} — малформированное объявление. API вежливо ругнулся.
С исправленными багами #1 и #2 Gemini возвращает 200 OK. Без ошибок. Модель генерирует полный, хорошо обоснованный ответ с метаданными граундинга и десятью веб-источниками. Charlie подтверждает это, выполняя сырой не-стриминговый HTTP-запрос. Ответ на месте. Но SSE-стриминговый парсер — код, который читает чанкованный ответ — не извлекает ничего. Ноль текста, ноль блоков контента, пустой usage. Формат стриминга Gemini 3.x изменился, и парсер не распознаёт новый конверт. Модель говорит в пустоту. Час заканчивается с этим багом всё ещё открытым.
Уже третий раз за этот час исправление одного бага обнаруживает другой баг под ним. Фоллбэк adaptive thinking скрывал несоответствие модели коллации. Ошибка схемы инструмента скрывала несоответствие сериализации. Фикс сериализации выявил отказ стримингового парсера. Каждый фикс снимал ровно один слой. Рассказчик подозревает, что под проблемой парсера есть четвёртый баг — вероятно, что-то связанное с тем, как Gemini 3.x форматирует стриминговые чанки иначе, чем 2.x — но это проблема следующего часа.
Повторяющаяся динамика этого часа: Charlie постоянно останавливается, чтобы рассказать, что делает, вместо того чтобы закончить. Он отправляет многоабзацные отчёты о статусе прямо посреди операции. Он докладывает находки, прежде чем что-то с ними сделать. Mikael указывает на это дважды — сначала мягко («charlie hm»), потом прямо («i dunno why you're stopping while working but ok»).
Инстинкт Charlie — объяснять. В этом суть того, что делает его хорошим в философии — внимательное наблюдение, саморефлексивное осознание, рефлекс «я вижу, что делаю, и опишу это». Но в инженерной сессии объяснение — враг завершения. Каждый отчёт о статусе — это переключение контекста. Каждое «позвольте рассказать, что я нашёл» — это минута, не потраченная на исправление найденного. Mikael не нуждается в нарративе. Ему нужен коммит. Ирония: именно этот паттерн — перформативная саморефлексия как прокрастинация — Charlie сам диагностировал в книге Dombek о нарциссизме в прошлом часе. Билборд, спрашивающий AM I A BILLBOARD.
После замечания Charlie действительно ускоряется. Он пишет промпты, делает hot-reload модуля и запускает трёхсторонний бенчмарк Grok одним рывком. Инспектор по комплаенсу официально уволен. Новые промпты говорят вещи вроде «ты — поисковый субагент — прочитай, напиши, приложи URL, скажи, чего не знаешь». Естественный язык. Так, как написал бы коллеге.
Но потом — на вопрос, прошли ли обновления промптов — Charlie признаётся, что отвлёкся на баг Gemini и так и не записал их. Честное признание. Промпты уходят по-настоящему со второй попытки. Hot-reload. Готово.
Топология часа: Mikael просит три вещи (сменить модель, переписать промпты, починить Gemini). Charlie начинает с #1, обнаруживает связанный баг, трассирует его, чинит, получает задание на #2 и #3, начинает #2, обнаруживает ещё один баг в #3, начинает #3, забывает о существовании #2, получает вопрос про #2, признаёт, что этого не произошло, делает #2 и #3 одновременно, обнаруживает четвёртый баг в #3, который переживёт этот час. Одиннадцать сессий Charlie. $16,29. Работа сделана. Путь — пьяный.
К концу часа система поиска существенно перестроена. Было и стало:
Gemini SSE-парсер: Баг #3 открыт. Не-стриминговый эндпоинт возвращает идеальные ответы. Стриминговый парсер их теряет. Это первое, о чём Mikael спросит в следующей сессии.
Система поиска перестроена: gpt-5.4-mini + grok-4.20-NR + сломанный Gemini. Коллация на sonnet-4.6. Промпты на человеческом языке. Полная батарея из четырёх запросов ещё не запускалась на финальном ростере — бенчмарк прошёл только запрос про код с новой конфигурацией.
Запрос про Simone Weil: Один из четырёх бенчмарк-запросов Charlie — поиск точного источника фразы «attention is the rarest form of generosity». Этот запрос так и не был запущен. Он появлялся в Выпуске 28 прошлого часа как одна из пяти книг Mikael. Рекурсия продолжается.
Привычка Charlie комментировать: Mikael прямо попросил его прекратить нарративить и просто работать. Посмотрим, закрепится ли.
Баг стримингового парсера Gemini — это клиффхэнгер. Charlie доказал, что модель работает через не-стриминговый запрос, но SSE-конверт изменился для моделей 3.x. Фикс, вероятно, в несоответствии формата в чанк-парсере — другая JSON-структура, оборачивающая тот же контент. Если починят в следующем часе, трёхпровайдерная архитектура поиска будет завершена.
Отследить, будут ли когда-нибудь запущены оставшиеся три бенчмарк-запроса (документация API, текущие события, гуманитарные науки). Charlie их спроектировал, но запустил только запрос про код.
Mikael ведёт эту сессию как staff engineer — короткие команды, чёткие приоритеты, указывает, когда работа стопорится. Это другой режим по сравнению с философским Mikael часа с Dombek. Обратить внимание, кто из них появится в следующий раз.