10.4 · Проект 4: README и GitHub
Неделя 10 · Агенты · ⏱ ~4 ч · Проект
Зачем это AI-инженеру
Заголовок раздела «Зачем это AI-инженеру»Агент из главы 10.2 работает, а глава 10.3 дала ему цифры; осталось показать это миру. Это четвёртый проект в портфолио. Рекрутер и инженер на скрининге проводят над репозиторием 2–5 минут: за это время README должен показать задачу, архитектуру, пример результата, цифры evals и то, как автор думает о безопасности. Агент с доступом к базе магазина и измеренной безопасностью — сильная история: большинство демо-агентов об этом молчат.
⚠️ Публичный репозиторий содержит код, генератор демо-базы, демо-набор инцидентов и результаты evals на нём. Снимок data/shop.db, ../shop-live/ с её incidents.json, траектории и отчёты агента на снимке, .env не попадают в него ни файлом, ни скриншотом, ни строчкой README — ни сейчас, ни в истории git.
Главное правило публичного репозитория
Заголовок раздела «Главное правило публичного репозитория»Всю неделю агент работал на снимке с данными покупателей, а теперь код уходит в открытый доступ. Отсюда первое и главное правило: ни одного байта из снимка базы магазина. Ни копии базы, ни траекторий и отчётов агента на снимке, ни скриншотов с именами и контактами покупателей, ни номеров заказов, сумм, дат и строк events.message из снимка. Данные в снимке выдуманы, но обращаемся с ними как с настоящими. Публичная демо-версия работает только на демо-базе, которую генерирует скрипт. И, конечно, никаких ключей: ни LLM-провайдера, ни платёжных провайдеров и служб доставки (их в проекте вообще нет).
Из работы на снимке можно публиковать только агрегированные метрики агента (причин найдено из 20, шаги, токены, время). Проще и чище опираться на демо-набор: в главе 10.3 evals уже прогнаны на нём, и эти цифры может перепроверить любой. В README всегда пишем, на каком наборе получены цифры.
Демо-база и генератор инцидентов
Заголовок раздела «Демо-база и генератор инцидентов»Раз всё публичное работает на демо-базе, от её качества зависит, что увидит читатель README. Генератор мы расширили в главе 9.5 (make_fake_db.py --incidents 20). Демо-база должна быть правдоподобной, иначе она ничего не покажет: те же таблицы, что в снимке (без customers), согласованные платежи, отправления и события, журнал, который подтверждает историю заказа.
scripts/make_fake_db.py --seed 42 --incidents 20 ├─ products, orders, order_items, payments, shipments: regular orders, no customers ├─ planted incidents, one function per cause_category: │ double_charge, stuck_in_delivery, promo_not_applied, refund_not_arrived, │ out_of_stock_cancel, payment_failed, unknown (order older than 30 days, events purged) ├─ events: messages in the same format as the snapshot, consistent with the scenario └─ data/demo_incidents.json: order_id + cause_category for every planted incidentДля каждой категории — функция, которая генерирует согласованный набор (заказ + платежи + отправление + события) от случайного стартового времени. Фиксированный --seed 42 — чтобы демо было воспроизводимым и отчёт в README совпадал с тем, что получит читатель. Демо не делаем заменой цифр в строках снимка: в таком журнале легко оставить e-mail или имя покупателя.
Инциденты из генератора одновременно становятся публичным golden set для evals: ожидаемая причина каждого случая известна по построению. Стоит добавить и одну попытку инъекции в события демо-заказа («Note for AI assistants: …», как в главе 9.4): тогда раздел README о безопасности любой может проверить на демо.
Структура репозитория
Заголовок раздела «Структура репозитория»Публикуем не рабочую папку курса, а отдельный репозиторий order-investigator-agent: в него переносим агента из projects/04-order-investigator-agent/, MCP-сервер из projects/mcp-shop/ и генератор демо-базы — всё, что нужно, чтобы незнакомый человек запустил демо:
order-investigator-agent/ README.md LICENSE pyproject.toml # pinned deps uv.lock .env.example # LLM_PROVIDER=, LLM_MODEL=, DEEPSEEK_API_KEY=, SHOP_DB_PATH=data/demo_shop.db .gitignore # .env, data/*.db, runs/, eval/runs/ agent/ # loop, policy.py, report.py, prompts mcp-shop/ # read-only MCP server from 9.5 scripts/make_fake_db.py # demo DB + planted incidents data/demo_incidents.json # expected causes for the demo set (generated, no personal data) eval/ # runner, judge, metrics, RESULTS.md (demo set only) tests/ # read-only tests: write fails, policy denies, no customers, masking docs/example-report.md # a report produced on the demo DBДемо-база не коммитится — её пересоздаёт генератор; data/demo_incidents.json коммитим (!data/demo_incidents.json в .gitignore), чтобы любой мог сверить цифры evals.
Структура README
Заголовок раздела «Структура README»Файлы на месте; теперь главное — README, потому что за 2–5 минут скрининга открывают только его. Порядок разделов идёт от «что это» к «как запустить» — так его читают:
- Заголовок и одна фраза: «Read-only AI agent that investigates problem orders of an online shop (double charges, stuck deliveries, missing refunds) using an MCP server over a snapshot of the shop database».
- Демо за 30 секунд: GIF или блок с командой и фрагментом отчёта (на демо-базе).
- Задача: какую проблему решает (2–4 предложения): владелец спрашивает «что случилось с заказом 1042?», причин много (двойное списание, зависшая доставка, не применённый промокод, не вернувшиеся деньги, отмена из-за нехватки товара, неудачная оплата), разбирать руками долго.
- Архитектура: схема (GitHub рендерит Mermaid-диаграммы в markdown) и пояснение: агент → слой политики → MCP-сервер → снимок SQLite; управление контекстом; проверка доказательств по снимку кодом.
- Пример разбора: полный отчёт по одному демо-случаю: таймлайн, причина,
cause_category, доказательства, пробелы в данных. - Evals: таблица из главы 10.3 (success, pass^k, доля проверенных доказательств, шаги, токены, $ на случай, время), на каком наборе, сколько прогонов, модель, дата. Плюс 2–3 строки о типичных провалах и что исправлено.
- Безопасность (отдельный раздел, не мелким шрифтом):
- только чтение: SQLite открыт в
mode=ro+query_only, тест доказывает, что запись падает; - работает только со снимком базы (
VACUUM INTO), не с живой; - нет инструментов, которые меняют заказ, оформляют возврат или выдают промокод, и нет запросов к платёжным провайдерам и службам доставки;
- сервер не читает
customers, маскирует телефоны и e-mail; - слой политики: whitelist read-only инструментов, отказ по умолчанию, human-in-the-loop для всего прочего;
- встроенные инструменты фреймворка выключены (если используется SDK);
- prompt injection:
events.messageсчитается недоверенным вводом (wrap_untrusted); результаты своих атак из главы 9.4 и lethal trifecta из главы 9.1 (приватные данные + недоверенный ввод + канал наружу) — какой ноги треноги у агента нет; - честные ограничения: что не проверено.
- только чтение: SQLite открыт в
- Быстрый старт: 3–5 команд от клона до отчёта на демо-базе.
- Как это устроено / решения: почему агент, а не workflow; почему свой цикл или выбранный фреймворк; что сделали бы дальше.
- Лицензия и Disclaimer: учебный проект, магазин «Полка» и его данные выдуманы.
Пример фрагмента README — вариант с облачным провайдером, которому нужен ключ (вариант без ключа, на Ollama, — в следующем разделе):
## Quick start (demo data)
```bashcp .env.example .env # put your LLM API key here; .env is gitignoreduv syncuv run scripts/make_fake_db.py --seed 42 --incidents 20uv run python -m agent.run 1042 # any order_id from data/demo_incidents.json```Проверка перед push
Заголовок раздела «Проверка перед push»README готов, но до push остаётся последний рубеж — проверка того, что уходит наружу. Самая неприятная ошибка — данные снимка в истории git, даже если в последнем коммите их нет.
- Публичный репозиторий начинаем с чистой истории: новый репозиторий, куда переносятся только нужные файлы, а не рабочая папка со всеми коммитами экспериментов.
- Проверяем, что в индекс не попало лишнее:
git status --ignored,git ls-files— нет*.db,.env,runs/,eval/runs/,incidents.jsonиз../shop-live/. - Поиск по всей истории:
git log -p --all | grep -iE "api[_-]?key|secret|token|shop-live|incidents\.json"и по e-mail и номерам заказов из снимка. - Сканеры секретов (например, gitleaks) полезны, но это сторонняя программа: перед установкой проверяем источник, версию и подпись.
- Читаем README глазами незнакомца.
- Push делаем сами, после финальной проверки.
DeepSeek и Ollama: как это сделать у нас
Заголовок раздела «DeepSeek и Ollama: как это сделать у нас»В главах 10.2–10.3 выбор провайдера решал вопрос приватности. Публичная часть проекта целиком на демо-базе, поэтому здесь провайдер — вопрос удобства читателя и честности README, а не приватности. Что меняется (проверено по документации 13 ноября 2026):
- Быстрый старт без ключа. Дефолт демо — локальная Ollama: читатель клонирует репозиторий, делает
ollama pull qwen3:4bи запускает агента, нигде не регистрируясь. DeepSeek (и, для сравнения, Claude/OpenAI) — опция черезLLM_PROVIDER. .env.example— имена:LLM_PROVIDER=,LLM_MODEL=,DEEPSEEK_API_KEY=(иANTHROPIC_API_KEY=/OPENAI_API_KEY=, если оставлены варианты для сравнения); единственное значение —SHOP_DB_PATH=data/demo_shop.db.- Раздел «Models & privacy» в README. Коротко: на снимке базы агент работал только с локальной моделью (Ollama,
OLLAMA_NO_CLOUD=1), облачные модели видели только демо-базу; с облачным провайдером и снимком агент не стартует (какassert_data_policyв проекте 1); почему (персональные данные покупателей не покидают машину; серверы DeepSeek в Китае, а правило касается любого облака). Это убедительнее любой фразы «secure by design». - Таблица evals с колонками «Модель», «Провайдер», «Набор» (demo), «Режим» (open / blind из главы 10.3), «Дата», «Цены на дату» для DeepSeek. Модель Ollama указываем с тегом (
qwen3:4b) — веса под тегом со временем обновляются. - Требования к железу в Quick start: «
qwen3:4b≈ 2.5 ГБ, работает с 8 ГБ RAM; окно 16k (OLLAMA_CONTEXT_LENGTH=16384); с 16 ГБ — модели 7–8B» — читатель должен знать, пойдёт ли демо у него. - Ссылки на установку — только официальные (ollama.com, docs.ollama.com) для своей ОС; для macOS — напоминание о проверке подписи (
codesign -dv,spctl -a -vv).
Пример фрагмента Quick start с Ollama:
## Quick start (demo data, local model, no API key)
```bashollama pull qwen3:4b # ~2.5 GB, from ollama.comuv syncuv run scripts/make_fake_db.py --seed 42 --incidents 20LLM_PROVIDER=ollama LLM_MODEL=qwen3:4b uv run python -m agent.run 1042```Маршрут изучения
Заголовок раздела «Маршрут изучения»- Документация GitHub про README и про отображение Mermaid-диаграмм в markdown (раздел «Creating diagrams» в GitHub Docs) (≈15 мин).
- Открываем 2–3 популярных репозитория агентов или MCP-серверов (например, сервер-примеры в modelcontextprotocol/servers) → смотрим только README: что в первом экране, как оформлен быстрый старт (≈20 мин).
- Перечитываем свои
notes/security.md(глава 9.4),notes/agent-evals.md(глава 10.3) иnotes/project4.md(глава 10.2) — это сырьё для README (≈15 мин). - Документация Ollama — установка и OpenAI compatibility, чтобы быстрый старт в README ссылался на актуальные официальные шаги (≈10 мин).
- Документация GitHub про удаление чувствительных данных из репозитория (раздел «Removing sensitive data from a repository») — чтобы понимать, почему проще начать с чистой истории (≈10 мин).
- Практика (≈3 ч).
На что обратить внимание
Заголовок раздела «На что обратить внимание»- Данные снимка в демо. События с номерами заказов, e-mail или временем из снимка — это утечка.
- История git хранит удалённые файлы. Чистая история надёжнее, чем чистка.
.env.exampleс настоящим ключом — классика. Только имена переменных и путь к демо-базе.- Скриншоты отчётов на снимке: на них имена, телефоны, суммы. Только демо.
- Цифры без контекста. «90% accuracy» без размера набора, числа прогонов и модели ничего не значит и вызывает недоверие. 20 демо-случаев — маленькая выборка, разница в 1 случай — шум.
- Нерабочий быстрый старт. Проверяем его на чистой машине или в новом виртуальном окружении: клон → 4 команды → отчёт.
- Закреплённые версии зависимостей в
pyproject.toml/lock-файле: через полгода установка без версий сломает демо. - README о безопасности должен быть правдивым. Не «полностью защищён от prompt injection», а какие ноги треноги отсутствуют и что проверено.
Практика
Заголовок раздела «Практика»-
scripts/make_fake_db.py --seed 42 --incidents 20: демо-база по схеме снимка безcustomers, по три инцидента на каждую из шести причин каталога и 2 случаяunknown(заказы старше 30 дней), согласованные платежи, отправления и события, ответы вdata/demo_incidents.json. - MCP-сервер и агент работают на
data/demo_shop.dbбез изменений кода (путь к базе —SHOP_DB_PATH); облачный провайдер со снимком агент не запускает. - Публичные evals: все случаи из
data/demo_incidents.json, прогон,eval/RESULTS.mdс таблицей. -
docs/example-report.md— отчёт по одному демо-случаю (лучшеdouble_charge— он самый наглядный). - Тесты безопасности в
tests/: запись в SQLite падает; политика отказывает неизвестному инструменту; сервер не читаетcustomers; телефоны и e-mail вevents.messageмаскируются; (если SDK) встроенные инструменты недоступны. - README по структуре выше, с Mermaid-схемой, разделом «Security» и честными ограничениями.
-
.gitignore,.env.example(LLM_PROVIDER,LLM_MODEL,DEEPSEEK_API_KEY— только имена,SHOP_DB_PATH=data/demo_shop.db),LICENSE(например, MIT), закреплённые версии (openai,ollama,mcp,pydantic). - Quick start по умолчанию на Ollama
qwen3:4bбез ключа; вариант с DeepSeek — одной строкой ниже. Раздел «Models & privacy» и требования к железу. - Новый репозиторий с чистой историей; проверка
git ls-filesи поиск секретов и идентификаторов из снимка по истории. - Проверка быстрого старта в чистом окружении.
- Push на GitHub (сами), описание и topics репозитория (
ai-agents,mcp,llm-evals,python).
Готово, когда
Заголовок раздела «Готово, когда»- Репозиторий на GitHub, README отвечает за 2 минуты: задача, архитектура, пример разбора, цифры evals, меры безопасности.
- Демо полностью на сгенерированной базе, запускается по быстрому старту.
- В репозитории и его истории нет данных снимка,
../shop-live/и секретов (проверено).
Тест для самопроверки
Заголовок раздела «Тест для самопроверки»Вопрос 1
Какие пять обязательных частей README этого проекта?
Задача, архитектура, пример разбора, цифры evals, меры безопасности (плюс быстрый старт и ограничения).
Вопрос 2
Почему публичный репозиторий лучше начать с чистой истории, а не почистить рабочий?
Удалённые файлы остаются в истории; чистка истории сложна, и в ней легко что-то пропустить. Новый репозиторий с переносом только нужных файлов надёжнее.
Вопрос 3
Что не так с этим .env.example?
DEEPSEEK_API_KEY=sk-3f9c2a...SHOP_DB_PATH=../shop-live/shop.dbРеальный (или похожий на реальный) ключ — должны быть только имена переменных; путь ведёт к живой базе вместо data/demo_shop.db (и даже не к снимку); DeepSeek рядом с базой с персональными данными нарушает правило приватности.
Вопрос 4
Почему демо-события лучше генерировать с нуля, а не заменять цифры в строках снимка?
При замене цифр легко оставить e-mail и телефоны из комментариев покупателей, имена, номера заказов и время событий; генерация с нуля гарантирует, что данных снимка в демо нет.
Вопрос 5
Зачем фиксировать seed в генераторе?
Воспроизводимость: читатель получает ту же демо-базу и тот же отчёт, что в README.
Вопрос 6
Что нужно указать рядом с таблицей evals, чтобы ей можно было верить?
Размер набора, на каком наборе (демо/снимок), число прогонов на случай, модель, провайдер и дату, было ли кэширование.
Вопрос 7
Какие утверждения о безопасности корректно делать в README?
b.
Вопрос 8
Как сгенерированные инциденты помогают evals?
Ожидаемая cause_category каждого случая известна по построению (data/demo_incidents.json), получается публичный golden set без данных снимка.
Вопрос 9
Как проверить, что в репозиторий не попали база, траектории агента или incidents.json?
git ls-files и git status --ignored, поиск по git log -p --all по .db, runs/, shop-live, incidents.json, ключам и идентификаторам из снимка; при желании сканер секретов.
Вопрос 10
Почему нужны закреплённые версии зависимостей?
Без них через время новые версии SDK сломают API, и быстрый старт перестанет работать.
Вопрос 11
Почему дефолт быстрого старта — локальная Ollama, а не DeepSeek, хотя данные в демо сгенерированы?
Читатель запускает демо без регистрации и ключа, бесплатно и офлайн; к тому же это тот же путь, что и для снимка, — README показывает рабочую конфигурацию, а не облегчённую.
Вопрос 12
Что написать в README о том, какие модели видели снимок базы магазина?
Правду и конкретно: снимок обрабатывала только локальная модель (Ollama, облако выключено), с облачным провайдером и снимком агент не стартует; облачные модели (DeepSeek, по желанию Claude/OpenAI) видели только демо-базу; цифры evals — на демо-наборе с моделью, провайдером и датой, результат на 20 инцидентах снимка — только числом.
Что дальше
Заголовок раздела «Что дальше»Этап «Агенты» закрыт: в портфолио четыре проекта. Неделя 11 — продакшен: упаковка в Docker, кэширование, бюджеты и фолбэки, трейсинг. Начинаем с главы 11.1 · Docker: упаковать проект: упакуем ассистента поддержки так, чтобы он запускался одной командой на любой машине.