惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
博客园 - 【当耐特】
博客园 - 三生石上(FineUI控件)
量子位
aimingoo的专栏
aimingoo的专栏
V
V2EX
Vercel News
Vercel News
B
Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
TaoSecurity Blog
TaoSecurity Blog
N
News and Events Feed by Topic
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
S
Secure Thoughts
U
Unit 42
博客园 - 叶小钗
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
N
News | PayPal Newsroom
Help Net Security
Help Net Security
S
Security Affairs
Microsoft Security Blog
Microsoft Security Blog
W
WeLiveSecurity
博客园 - Franky
Forbes - Security
Forbes - Security
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
Schneier on Security
Schneier on Security
I
InfoQ
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
A
About on SuperTechFans
Webroot Blog
Webroot Blog
AWS News Blog
AWS News Blog
Last Week in AI
Last Week in AI
Security Archives - TechRepublic
Security Archives - TechRepublic
C
CERT Recently Published Vulnerability Notes
N
News and Events Feed by Topic
阮一峰的网络日志
阮一峰的网络日志
L
Lohrmann on Cybersecurity
SecWiki News
SecWiki News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
J
Java Code Geeks

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как мы отучали LLM выдумывать цифры в данных. Допрос Claude Desktop с пристрастием
Сергей Франгулов · 2026-06-24 · via Все публикации подряд на Хабре

Простой

7 мин

218

Никто не верил, что модель можно подпустить к таблицам и заставить не галлюцинировать. Цифры из воздуха, выдуманные колонки, суммы, которые не сходятся с источником, думаю на этом обжигались все, кто пробовал. Мы заставили, проблемы все еще есть, но выглядят решаемыми.

Сначала про то, почему любая LLM врёт на данных. Она достраивает правдоподобное продолжение токен за токеном. Таблица, которую вы положили ей в контекст, для модели такой же текст, как и всё остальное. Не хватило данных, неудобно читать, вопрос чуть в стороне — она не скажет «не знаю», а допишет то, что выглядит как правда. Прямой путь, отдать ей CSV и попросить посчитать, ровно поэтому и не работает.

Сработал другой подход. Мы взяли Claude Desktop и оказалось, что он прекрасно пережевывает большие датасеты: не захлёбывается и не врёт цифрой там, где обычная связка «модель плюс CSV» уже ломается. Стало интересно, за счёт чего. Мы начали его опрашивать и разбирать, как он это делает. Вот что выяснили — и что из этого перенесли в свой MCP-сервер.

Первый подход: Claude Desktop умеет, но непредсказуемо

Сначала честно: анализ данных Claude делает и сам, без всякой обвязки. Дай ему датасет и вопрос — думаю он посчитает. Он умеет, проблема в том, что делает это каждый раз по-разному. Тот же вопрос и он то возьмёт один разрез, то на полпути сменит подход, то выберет другую логику расчёта. Для разовой задачи сносно, но на должность дата аналитика не тянет.

Раз он справляется с данными, рецепт у него есть. Мы решили его просто спросить.

Что рассказал Claude Desktop

Мы стали опрашивать напрямую: как ты работаешь с большими датасетами, как устроена твоя песочница, как устроены навыки для работы с данными и тд. Устройство его песочницы я оставлю за скобками — это кухня Anthropic, и реконструировать её догадками в статье про то, как не выдумывать, было бы смешно. Если хотите спросите сами, он кое-что расскажет, а песочница claude code вообще с открытыми исходниками. Свою мы потом собрали сами, о ней дальше. Нас интересовало переносимое.

Переносимое свелось к трём вещам. Считать данные движком вместо счёта в уме — тут он сразу назвал DuckDB. Аналитику, которую нельзя выразить в SQL запрос, выносить в Python в песочницу. И описывать данные и схему так, чтобы модель не гадала, что внутри. Эти три вещи мы и зашили в свой MCP-сервер: фронт на Next.js (ai-sdk), бэкенд на FastMCP, под капотом DuckDB, модель ходит в данные только через инструменты. Смысл обвязки — забрать у модели свободу импровизировать и пользоваться инструментами. Дальше по порядку.

Движок: считать, а не прикидывать

Самая частая ложь модели при работе с данными — это арифметика и агрегации в уме. Спросите модель «какая средняя выручка по регионам», положив ей таблицу на 50 тысяч строк, и она с удовольствием выдаст число. Иногда даже близкое к правде.

Поэтому считать ей мы не даём. Она пишет SQL, а выполняет его DuckDB — тот самый движок, который Claude назвал первым. Среднее, сумма, группировка, джойн — всё уходит в движок, который не ошибается в арифметике по определению.

DuckDB выбран не случайно. Это встраиваемый OLAP-движок, который читает CSV, Parquet и JSON напрямую через read_csv_auto() и read_parquet(), а к внешним базам подключается через federation — ATTACH к PostgreSQL, MySQL, SQLite без копирования данных:

ATTACH 'host=... dbname=...' AS pg (TYPE postgres, READ_ONLY)

Подключение всегда READ_ONLY и всегда in-memory: данные живут на диске или во внешней базе, а DuckDB поднимает их в память только на время запроса.

Но дать модели писать произвольный SQL — это путь к биде. Поэтому каждый запрос проходит через гейт, еще один слой защиты. Функция validate_read_only()mcp_server/duckdb_utils.py) режет всё, что меняет данные или лезет мимо данных:

def validate_read_only(sql: str) -> None:
    """Бросает ValueError, если в SQL есть мутации.
    Блокирует INSERT / UPDATE / DELETE / DROP / CREATE / ALTER / ATTACH,
    а ещё функции glob(), sqlite_scan(), postgres_query() — они
    обходят изоляцию файловой системы."""

Проверка идёт по очищенному SQL — без комментариев и строковых литералов, чтобы фильтр нельзя было обмануть, спрятав что-то в комментарий. Рядом prepare_user_sql() разворачивает относительные пути файлов в полные и проверяет, что путь не вышел за пределы разрешённой папки.

Сам движок тоже закрыт на замок. При создании соединения мы запрещаем автозагрузку расширений и в конце замораживаем конфигурацию:

con.execute("SET autoinstall_known_extensions=false")
con.execute("SET autoload_known_extensions=false")
con.execute("SET lock_configuration=true")  # после этого настройки не поменять

И последнее в этой части — то, без чего модель снова начинает врать даже на честно посчитанных данных. Результат запроса мы усекаем: если строк больше двух сотен, показываем первые и последние, а к ним прикладываем предупреждение прямо в выводе тула:

WARNING: показаны 200 из 5000 строк. Агрегации по этому выводу будут неверны — используйте SQL-агрегацию.

Без этой строчки модель честно получает 200 строк, видит, что это «таблица», и спокойно «усредняет» показанное, забыв про оставшиеся 4800. Предупреждение возвращает её к реальности.

Но костяк — это SQL. Не всё на него ложится: сложная статистика, прогнозы, нестандартные преобразования. Для этого есть вторая рука.

Вторая рука: песочница с Python

Второе, что назвал Claude, — Python для аналитики, которую неудобно гнать через SQL. У нас это отдельный сервис-песочница: изолированный контейнер на своём порту, код исполняется под непривилегированным пользователем. Модель пишет код, песочница его запускает и возвращает результат — тот же принцип, что и с SQL: считает среда, модель только формулирует.

Песочница приходит с предустановленным набором библиотек, чтобы модель не тянула зависимости на ходу:

  • данные: pandas, numpy, scipy, polars, pyarrow, duckdb;

  • статистика и прогнозы: statsmodels, scikit-learn, statsforecast, mlforecast, плюс бустинг lightgbm и catboost с интерпретацией через shap;

  • графика: matplotlib, seaborn, plotly;

  • выгрузки и документы: openpyxl, xlsxwriter, python-docx, python-pptx;

  • русский текст: natasha, razdel, pymorphy3.

Список залочен и заранее закеширован в образе: модель работает тем, что есть, и не тянет что попало из сети.

Песочница изолирована на сколько можно: изолированный контейнер, непривилегированный пользователь, фиксированный список либ. Свобода у модели есть, но внутри этих границ.

Описание данных: чтобы модель не гадала о схеме данных

Третий совет Claude был про описание данных, и он закрывает вторую частую ложь — выдуманные колонки и таблицы. Модель пишет SELECT revenue FROM sales, а колонка называется total_amount, и таблицы sales нет вовсе. Корень один: модель не знает структуру и достраивает «похоже на правду».

Лечится это тем, что структуру ей дают раньше, чем она успеет придумать. У нас за это отвечают два тула.

data_list показывает каталог: какие датасеты вообще есть, сколько в каждом строк и колонок, краткое описание. Модель сначала видит, с чем она работает, а не угадывает имена файлов.

data_schema идёт глубже — это профиль каждой колонки. Тип, доля пустых значений, число уникальных, минимум, максимум и среднее для чисел. Плюс то, что мы добавили специально под аналитику: детект валют и единиц измерения. Тул смотрит на сами значения и подсказывает модели, что profit лежит в долларах, а quantity — в тоннах:

Table: sales.csv
Rows: 250 000
Columns: 8

Column          Type            Null   Unique
profit          INTEGER         2%     —
quantity        DECIMAL(10,2)   0%     —
region          VARCHAR         0%     7
date            DATE            0%     —

Подсказки по единицам:
- profit   → валюта: USD
- quantity → единица: тонна

Это не косметика. Без подсказки по валютам модель спокойно сложит доллары с евро в одном SUM() и выдаст бессмысленную сумму с видом эксперта.

Чтобы не считать профиль на каждый чих, описания кэшируются. Метаданные датасетов лежат в PostgreSQL (таблица dataset_metadata: число строк, колонок, текст схемы, описание), а структура подключённых внешних баз — в cached_schema. Модель получает готовый контекст за один вызов.

И последнее — дисциплина. Системный промпт требует фазу PLAN: сначала data_list и data_schema, и только потом data_query. Узнай, что есть и как устроено, потом спрашивай данные. Этот порядок снимает большую часть выдуманных колонок ещё до первого запроса.

Когда данных нет: главный соблазн соврать

Самый опасный момент в работе с данными — не сложный запрос, а пустой ответ. Модель спросила, фильтр ничего не нашёл, вернулось ноль строк. Вот тут LLM особенно тянет «спасти» ситуацию: раз данных нет, выдам правдоподобное. Ровно так и берутся цифры из воздуха.

Поэтому просто пустой ответ мы модели не отдаем. На нулевом результате тул сам идёт разбираться, почему фильтр не сработал: прогоняет SELECT DISTINCT по колонкам из условия и возвращает реальные значения:

Запрос вернул 0 строк. Возможная причина в фильтре: колонка year содержит значения: 2020, 2021, 2022. В вашем фильтре было year = 2025.

Теперь у модели есть зацепка, и она чинит фильтр. Промпт это поддерживает: до трёх попыток, прочитай ошибку, поменяй, повтори.

И ещё одна мелочь в ту же сторону. Каждый тул честно сообщает не только данные, но и их состояние: сколько вернулось строк, усечён ли ответ. Модель не гадает, полный ли у неё результат. Без такой честности она додумывает там, где достаточно посмотреть на факт.

Как это выглядит на одном запросе

Соберём вместе. Пользователь спрашивает: «покажи выручку по регионам».

  1. data_list — модель видит, что есть датасет sales на 250 тысяч строк.

  2. data_schema — узнаёт колонки: region, revenue в долларах, date.

  3. data_query — пишет SELECT region, SUM(revenue) ... GROUP BY region, сумму считает DuckDB.

  4. viz_chart — строит график на тех числах, что вернул запрос.

В финале каждое число прослеживается до конкретного выполненного SQL. Нет шага, где модель «прикинула» цифру по памяти. Та самая «выручка +23%» теперь либо берётся из запроса, либо не появляется вовсе.

Где модель всё равно может соврать

Честный взгляд со стороны, без которого разбор был бы не полным.

validate_read_only — это регулярки, а не разбор AST. Гейт ловит мутации и небезопасные функции, но не семантику. Кривой JOIN, который молча размножит строки, пройдёт проверку и даст неверную сумму. Движок посчитает её безупречно — и она будет ошибочной.

cached_schema устаревает. Если в подключённой базе поменяли таблицу, а кэш не пересканировали, модель сошлётся на колонку, которой больше нет. Модель это увидит и попытается поправить, пересканировать заголовок датасета, но это лишние шаги.

Предупреждение об усечении спасает не всегда, про «200 из 5000» будет в ответе, но это текст, а текст модель может проигнорировать. Жёсткого запрета агрегировать усечённое нет.

Смешанные валюты — та же история. Детект подсказывает, что складывать доллары с евро нельзя, но это подсказка, а не блок. Дисциплина держится на промпте, а промпт можно не дочитать.

Вывод один. Наша поделка не убирает галлюцинации, она сужает область, где они возможны. Мы перенесли ответственность с памяти модели на инструменты с жёсткими границами. Где граница вшита в код (read-only, скоуп файлов, схема данных), модели не надо выдумывать цифры, они все есть. Ответ воспроизводим: тот же вопрос завтра даёт ту же цифру — ровно то, чего Claude в одиночку не давал. Где осталась промпт-дисциплина, соврать ещё может, и за этими местами приходится следить руками.

И кажется, в этом вся работа. Каждый раз, когда наша модель уверенно выдумывала цифры, разбор упирался не в «модель тупая», а в место, где ей просто негде было взять данные. Вопрос всегда оказывался один: где проходит граница между «пусть посчитает модель» и «пусть посчитает движок».