О проекте
Cold Outreach Pipeline — это система автоматизации B2B cold outreach. Она помогает находить контактные данные руководителей компаний, которых нет в публичных реестрах: финансовых директоров, коммерческих директоров, HR-директоров, CTO и других.
Какую задачу решает
В публичных реестрах (ЕГРЮЛ, Checko) можно найти только генерального директора и учредителей. Но для B2B-продаж нужно выходить на конкретных руководителей: кто отвечает за финансы, за продажи, за IT. Эта система автоматически ищет таких людей в открытых источниках — на сайтах компаний, в новостях, на конференциях, в профессиональных сетях — и заносит их в таблицу Google Sheets с оценкой достоверности.
Как это работает (в двух словах)
Этап 1 — Обогащение компаний. Вы отмечаете компании в Google Sheets галочкой, нажимаете кнопку «Начать работу». Система автоматически подтягивает данные из Checko (реквизиты, контакты, учредители), DaData (бренд, описание), проверяет сайт компании и записывает всё обратно в таблицу.

Этап 2 — Поиск руководителей. Для каждой компании система формирует 16 поисковых запросов в Яндекс, скачивает найденные страницы, извлекает ФИО и должности через AI (нейросети), оценивает достоверность каждого найденного человека и записывает лучших кандидатов в таблицу.
Технический стек
Yandex Cloud (Cloud Functions, Object Storage S3, Workflows, Lockbox, YDB), Python 3.12, Google Sheets API, Yandex Search API (асинхронный режим), AI-модели gpt-oss-20b и DeepSeek V3.2. Весь код — 11 serverless-функций для поиска людей + 7 для обогащения + 1 для дашборда (CRUD) + 1 для авторизации + 1 триггер.
Ключевые метрики
Pipeline функций
Этап 1 + Этап 2 (без служебных)
В Yandex Cloud
Всего функций в облаке (вкл. служебные)
Открытых проблем
Прогонов
Стоимость обработки 100 компаний
КомпонентРасчётСтоимостьИсточник тарифа
ЭТАП 1 — ОБОГАЩЕНИЕ
Checko Company (E2)100 компаний × 0.15 ₽/запрос~15 ₽checko.ru, апр. 2026
Checko Finances (E3)100 компаний × 0.15 ₽/запрос~15 ₽checko.ru, апр. 2026
DaData Brand (E4)100 компаний × 7 ₽/бренд~700 ₽dadata.ru, апр. 2026. Списание если есть название + сайт + описание
ЭТАП 2 — ПОИСК РУКОВОДИТЕЛЕЙ
Yandex Search API (async)100 × 16 = 1 600 запросов × 30.50 ₽/1000~49 ₽Тариф на апр. 2026
LLM gpt-oss-20b~300 страниц × 1 200 токенов × 0.10 ₽/1K~36 ₽AI Studio, апр. 2026
LLM DeepSeek V3.2 (fallback ~10%)~30 страниц × 1 200 токенов × 0.50 ₽/1K~18 ₽AI Studio, апр. 2026
Search API верификация (09a)~50 запросов × 30.50 ₽/1000~2 ₽Тариф на апр. 2026
Итого~835 ₽~8.35 ₽ за компанию
Главный расход — DaData Brand (84%). Кэш 730 дней (2 года) снижает стоимость при повторных прогонах. При повторном прогоне тех же компаний: Checko кэш 30 дней, DaData кэш 2 года, SERP кэш 14 дней → реальная стоимость значительно ниже.
Схема работы pipeline
Полный путь данных: от нажатия кнопки в Google Sheets до появления найденных руководителей в таблице. Каждый блок — это отдельная Cloud Function в Yandex Cloud.
Запуск
Пользователь отмечает компании галочкой (столбец A) в Google Sheets и нажимает кнопку «Начать работу» в меню. GAS-скрипт отправляет запрос на Cloud Function outreach-trigger, которая запускает Yandex Workflow.
📊 Google SheetsКнопка «Начать работу» ⚡ GAS Scriptspreadsheet_id + token outreach-triggerЗапускает Workflow
Этап 1 — Обогащение компаний
Считывает отмеченные компании, запрашивает данные из трёх внешних API параллельно (с while-циклом для больших объёмов), проверяет сайт, записывает всё обратно в таблицу.
E1 Считать из SheetsКомпании с галочкой + ИНН
ПАРАЛЛЕЛЬНО (while)
E2 Checko CompanyРеквизиты, контакты, учредители E3 Checko FinanceВыручка, прибыль, дебиторка E4 DaData BrandБренд, описание, домен
E6 Проверка сайтовDNS + HTTP + MX проверка E5 Запись в SheetsMega-batch обновление
Этап 2 — Поиск скрытых руководителей (11 функций)
Фаза 1: Подготовка
00 Сбор данныхТаблица → JSONL 01 Определение брендаHTTP title + AI fallback
Фаза 2: Поиск страниц в интернете
02 Поиск в Яндексе16 запросов × компания 03 Фильтрация URLКлассификация + дедупликация 04 Скачивание страницHTML + PDF → текст
Фаза 3: Извлечение ФИО и должностей
05 ПредобработкаDOM + regex + prefilter 06 AI-извлечениеgpt-oss-20b → DeepSeek 07 Сбор фактов→ person_facts.jsonl
Фаза 4: Оценка и запись результатов
08 Склейка + ролиДедупликация ФИО 09 СкорингОценка достоверности 0–100 10 Запись в SheetsНовые строки + группировка
Результат
📊 Google SheetsНовые строки с руководителями под каждой компанией + 📱 TelegramИтоговый отчёт
Запуск (GAS)
Обогащение (Этап 1)
Поиск людей (Этап 2)
Результат / Запись
Скоринг и Quality Gates
Pipeline оценивает каждого найденного человека по 5 факторам. Итоговый балл 0–100 определяет, попадёт ли человек в таблицу. Кроме того, на каждом этапе pipeline есть контрольные точки — Quality Gates.
Пороги отбора
60–100
✅ Принят
Записывается в таблицу Google Sheets
40–59
⚠️ На проверку
Попадает в review queue
<40
❌ Отброшен
Недостаточно доказательств
5 факторов оценки
score = источник × свежесть × подтверждение × качество × привязка Шаг 09 • pipeline-score-select
Источник
55–90
Главный фактор. Откуда взята информация о человеке
Свежесть
×0.4–1.0
Насколько старый источник. Может снизить до −60%
Подтверждение
×1.0–1.2
Найден в 2+ источниках? Бонус +20%
Качество
×0.7–1.0
Есть ли цитата с ФИО + должность рядом
Привязка
×0.0–1.0
Принадлежит ли человек этой компании
Калькулятор скоринга
100
Веса источников
ИсточникБаллДоверие
🏢 Сайт компании (/team, /about)90Высокое
📄 PDF-документ / отчёт80Высокое
📰 Новость / интервью72Среднее
🎯 Конференция / спикер70Среднее
💬 TenChat68Среднее
🔗 LinkedIn65Ниже среднего
📝 Тендер60Ниже среднего
💼 hh.ru55Низкое
Множители детально
⏳ Свежесть источника
<1 года×1.0Нет штрафа
1–2 года×0.8− 20%
2–3 года×0.6− 40%
3+ лет×0.4− 60%
Без даты×0.5− 50%
🔗 Привязка к компании
URL на домене компании×1.0Точно свои
Бренд в цитате×0.9Упомянут рядом
Бренд в контексте ±500×0.85Вероятно свои
DOM-парсер не совпал×0.0Точно чужой
Не найдено×0.3Отсеется
Шаг 07 (evidence-build) + шаг 09a (verify)
✅ Кросс-подтверждение
Найден в 2+ независимых источниках×1.2
Один источник → ×1.0

Например: найден на сайте + в новости = 2 источника
📝 Качество доказательства
Цитата с ФИО + должность рядом×1.0
Только должность без имени → ×0.7

Проверка: evidence_quote содержит фамилию (шаг 07)
Последний этап: поисковая верификация (шаг 09a)
Для кандидатов из внешних источников делается дополнительный поиск: "Фамилия Имя" "бренд". Если они встречаются на одной странице — probability ×1.3. Если нет — probability ×0.5. Кандидаты с сайта компании не проверяются.
Quality Gates — контроль на каждом этапе
Если метрика ниже порога — отправляется Telegram-алерт. Pipeline не останавливается.
01 Определение бренда — у скольких % компаний есть бренд ≥ 88% Мёртвые сайты → поиск без бренда даёт мусор
04 Скачивание страниц — % успешно скачанных ≥ 70% Блокировки → 30% данных потеряно
07 Сбор фактов — % компаний с хотя бы 1 человеком ≥ 30% Нет людей → pipeline бесполезен
10 Экспорт — итоговое покрытие (компании с хотя бы 1 ролью) ≥ 55% Мало контактов для outreach
Где это в коде
Скоринг: pipeline_score_select.py (шаг 09) — веса, формула, пороги.
Привязка к компании: pipeline_evidence_build.py (шаг 07) — company_match_confidence.
Верификация: pipeline_verify.py (шаг 09a) — поисковая проверка ФИО+бренд.
Quality Gates: pipeline_page_fetch.py (шаг 04), pipeline_export_sheets.py (шаг 10) — Telegram-алерты.
Целевые роли
Pipeline ищет руководителей по 9 целевым ролям. Для каждой роли настроен словарь синонимов — система распознаёт разные варианты написания должности и приводит их к единому виду.
РольСинонимы (base / extended / full)
Источник данных
Словарь загружается из S3: config/roles_synonyms.json. Используется функцией pipeline-serp-fetch для генерации поисковых запросов. Три уровня синонимов: base (режим base), extended (режим extended), full (режим full).
Хранилище S3
Все данные pipeline хранятся в Yandex Object Storage (S3-совместимое хранилище). Bucket: cold-outreach. Используется гибридная архитектура: общий кэш API-ответов (один запрос на ИНН для всех таблиц) + отдельные сессии для каждой таблицы.
Общий кэш API-ответов
Один ИНН в двух таблицах = один API-запрос. Кэш общий для всех таблиц. Путь: cache/
ФайлИсточникTTLОписание
checko_company.jsonlE2 Checko30 днейНазвание, контакты, учредители, ген.дир. Ключ = ИНН + fetched_at
finances.jsonlE3 Checko365 днейВыручка, прибыль, дебиторка за 3 года + тренды
brands.jsonlE4 DaData730 днейБренд, описание, домен сайта
Сессионные данные Этапа 1
Изолированы по spreadsheet_id. Путь: sessions/{spreadsheet_id}/
Файл / ПапкаШагTTLОписание
companies_to_enrich_{ts}.jsonlE1 → E2,E3,E4Список компаний на обогащение (timestamp для уникальности)
sites.jsonlE630 днейНайденные и проверенные сайты компаний
archive/E5Обработанные списки (перемещаются после записи в Sheets)
progress/всеПрогресс каждого шага (для возобновления и мониторинга)
Данные Этапа 2 — Pipeline
Промежуточные результаты каждого шага. Путь: sessions/{spreadsheet_id}/pipeline/data/
ФайлШагСодержимое
00_companies.jsonl00 → 01Входные данные: ИНН, бренд, домен, известные люди
01_companies_enriched.jsonl01 → 02,03С определённым брендом + internal_links сайта
02_serp_results.jsonl02 → 03Результаты поиска Яндекса (до 16 запросов × компанию)
03_candidate_urls.jsonl03 → 04Отфильтрованные URL с классификацией (website/news/pdf/hh/...)
04_pages_text.jsonl04 → 05Текст скачанных страниц (HTML→text, PDF→text)
05_extracted.jsonl05 → 06,07Результат DOM-парсинга + флаги needs_llm
06_llm_extracted.jsonl06 → 07Результат AI-извлечения (ФИО + должность + цитата)
08_entities.jsonl08 → 09Склеенные сущности с нормализованными ролями
09_final.jsonl09 → 09a → 10Финальные кандидаты + оценки (обновляется шагом 09a)
09a_verify_results.jsonl09aРезультаты поисковой верификации
Факты и QA. Путь: sessions/{spreadsheet_id}/pipeline/
ФайлПапкаОписание
person_facts.jsonlevidence/Атомарные факты: ФИО + должность + цитата + URL + confidence
review_queue.jsonlqa/Спорные случаи (score 40–59) для ручной проверки
{run_id}/step_XX.jsonprogress/Прогресс + метрики каждого шага, группировка по run_id
Кэши Этапа 2
Путь: sessions/{spreadsheet_id}/pipeline/cache/
ПапкаTTLКлючСодержимое
serp/14 днейmd5(query_text)Кэш поисковых выдач Яндекса
pages/30 днейmd5(url)text + html_snippet (300KB для DOM-доменов, 100KB для остальных)
llm/Бессрочныйmd5(url + text_hash)Ответы AI-моделей (экономия при перезапуске)
Настройки (общие)
Можно менять без передеплоя функций. Путь: config/
ФайлНазначениеГде используется
roles_synonyms.jsonСловарь синонимов должностей → 9 целевых ролейШаг 08 (нормализация)
url_patterns.jsonПравила классификации URL по типуШаг 03 (фильтрация)
source_weights.jsonВеса источников для скорингаШаг 09 (оценка)
Принципы проектирования
Ключевые решения, определяющие архитектуру pipeline. Полезно перечитать перед внесением изменений.
01

Сначала факты, потом люди

Каждое упоминание человека из любого источника записывается как отдельный факт (person_fact) с цитатой, ссылкой и датой. Только потом факты склеиваются в людей. Это позволяет прозрачно проследить, откуда взялась каждая запись.

02

Два источника лучше одного

Если человека нашли на сайте компании И в новости — его оценка умножается на 1.2. Мульти-source подтверждение резко повышает достоверность.

03

Без доказательства — нет факта

Каждый person_fact обязан содержать цитату из источника (evidence_quote) и ссылку (source_url). Без них — запись не попадает в финал.

04

Продолжение с места остановки

Каждая функция сохраняет свой прогресс в S3 (progress/). При перезапуске — пропускает уже обработанное. Таймер 240 секунд + механизм partial/complete для больших объёмов.

05

Настройки без передеплоя

Словари ролей, веса скоринга, паттерны URL — всё хранится в JSON-файлах в S3 (config/). Можно менять без пересборки функций.

06

AI только когда нужен

Сначала бесплатный DOM-парсинг → потом проверка маркеров должностей → только потом AI. Дешёвая модель (gpt-oss-20b за 0.10₽/1K) → дорогая (DeepSeek за 0.50₽/1K) только для перспективных страниц (/team, /about).

07

Кэш по ИНН, не по строке

Строки в таблице удаляются и пересоздаются. UUID нестабилен. Единственный надёжный идентификатор компании — ИНН. Все кэши привязаны к нему.

08

Минимум обращений к Google Sheets

Один get_all_values() в начале → все изменения собираются в памяти → 1–3 batch-вызова API в конце. Иначе — ошибка 429 (rate limit).

09

Асинхронный поиск = 16× экономия

Yandex Search API в async-режиме: 30.50₽ за 1 000 запросов вместо 488₽. Платим за ожидание 5+ минут, экономим 16 раз.

10

Логи прежде всего

При дебаге Cloud Functions — всегда сначала yc serverless function logs, только потом гипотезы. Не фантазировать, не гадать — читать логи.

Центр управления
Открыть Google Sheets
Обогащение Workflow →
Поиск руководителей Workflow →
Команды CLI
Все команды для PowerShell. Кликните на команду, чтобы скопировать её в буфер обмена. Путь проекта: F:\Projects\Cold-outreach
Запуск Этапа 1 — Обогащение компаний
Запускает Yandex Workflow обогащения. Обрабатывает компании с галочкой (A=TRUE) в таблице. Используется файл test_event.json с spreadsheet_id.
cmd /c 'yc serverless workflow execution start --id dfqen1c7rm7dl2cdqc0c --json-input "{\"spreadsheet_id\":\"181uHU4PCctSiY2Gnd1DPNL6G8JSffLCCQuF4VkWsQpM\"}"'
Запуск Этапа 2 — Поиск руководителей
Запускает Yandex Workflow поиска скрытых руководителей (11 шагов).
cmd /c 'yc serverless workflow execution start --id dfqf4tr2mttv4mhmpjun --json-input "{\"spreadsheet_id\":\"181uHU4PCctSiY2Gnd1DPNL6G8JSffLCCQuF4VkWsQpM\"}"'
Деплой функций
Перейдите в папку проекта. Файлы лежат в deployed\. Обёртка powershell -ExecutionPolicy Bypass обязательна.
cd "F:\Projects\Cold-outreach"
powershell -ExecutionPolicy Bypass -Command ".\deploy.ps1 -Name <имя-функции> -File deployed\<файл.py> -Deps '<зависимости>' -Timeout <секунды>"
Деплой с переменными окружения (для YDB)
powershell -ExecutionPolicy Bypass -Command ".\deploy.ps1 -Name ydb-dashboard-api -File deployed\ydb_dashboard_api.py -Deps 'ydb,boto3' -Timeout 30 -Env 'YDB_ENDPOINT=grpcs://ydb.serverless.yandexcloud.net:2135,YDB_DATABASE=/ru-central1/b1gelq57oiacd1bq11p3/etnvkh6bsq6pt5cjh69o'"
Просмотр логов функции
yc serverless function logs --name <имя-функции> --since 30m --limit 100
Вызов функции вручную
Тестовый JSON: {"spreadsheet_id":"181uHU4PCctSiY2Gnd1DPNL6G8JSffLCCQuF4VkWsQpM"}. Используйте --data-file вместо --data (PowerShell съедает кавычки).
yc serverless function invoke --name <имя-функции> --data-file "$env:USERPROFILE\Downloads\test_event.json"
Просмотр файлов в S3
yc storage s3api list-objects --bucket cold-outreach --prefix "sessions/181uHU4PCctSiY2Gnd1DPNL6G8JSffLCCQuF4VkWsQpM/pipeline/data/"
yc storage s3api get-object --bucket cold-outreach --key "<ключ>" "$env:USERPROFILE\Downloads\<файл>"
Очистка данных pipeline
Массовое удаление — через консоль Yandex Cloud (быстрее CLI). Удаление одного объекта:
yc storage s3api delete-object --bucket cold-outreach --key "<ключ>"
Деплой dashboard
yc storage s3api put-object --bucket cold-outreach-dashboard --key dashboard.html --body "F:\Projects\Cold-outreach\deployed\dashboard.html" --content-type "text/html; charset=utf-8"
Обновление Workflow
yc serverless workflow update --id dfqen1c7rm7dl2cdqc0c --yaml-spec "F:\Projects\Cold-outreach\deployed\cold-outreach-enrich.yaml"
yc serverless workflow update --id dfqf4tr2mttv4mhmpjun --yaml-spec "F:\Projects\Cold-outreach\deployed\cold-outreach-stage2.yaml"
Запись в Changelog
Шаг 1: создать JSON без BOM. ВАЖНО: [System.IO.File]::WriteAllText() БЕЗ второго параметра кодировки — иначе BOM сломает парсинг.
[System.IO.File]::WriteAllText("$env:USERPROFILE\Downloads\changelog_entry.json", '{"action":"upsert","table":"changelog","item":{"id":"ch-YYYYMMDD-NAME","date":"DD.MM.YYYY HH:MM","function_name_ru":"Название","function_name":"tech-name","problem":"Что было не так","fix":"Что сделали","result":"Результат"}}')
Шаг 2: вызвать API.
yc serverless function invoke --name ydb-dashboard-api --data-file "$env:USERPROFILE\Downloads\changelog_entry.json"
Облако и API
Вся инфраструктура в Yandex Cloud. Клик на ID открывает соответствующую страницу в консоли.
Yandex Cloud
Service Account
ajehdrv1u3sm5tr8b84b
Lockbox (секреты)
S3 Bucket (данные)
cold-outreach
S3 Bucket (проект)
cold-outreach-project-files
Google Spreadsheet
Workflow Этап 1
Workflow Этап 2
YDB Dashboard
Dashboard API
Auth API
Архитектура
Google Sheets (кнопка «Начать работу» → GAS скрипт → Workflow) Yandex Cloud folder: cold-outreach ├── Object Storage bucket: cold-outreach ├── cache/ sessions/ config/ logs/ ├── Cloud Functions (21 функция) ├── outreach-* (7) обогащение + sheets + trigger ├── pipeline-* (11) поиск руководителей ├── ydb-dashboard-api (1) CRUD бэкенд дашборда └── outreach-auth (1) авторизация (login/logout/users) ├── Yandex Workflows 2 workflow (Этап 1 + Этап 2) ├── YDB Serverless данные дашборда ├── Lockbox API-ключи и секреты ├── AI Studio gpt-oss-20b + DeepSeek V3.2 └── Search API async mode (30.50₽/1000 запросов)
Секреты в Lockbox
Все API-ключи и пароли хранятся в Yandex Lockbox. Функции получают их через REST API с IAM-токеном.
КлючЧто хранитГде используется
s3_access_keyКлюч доступа к Object StorageВсе функции
s3_secret_keyСекрет Object StorageВсе функции
s3_bucketИмя bucket (cold-outreach)Все функции
google_sheets_credentialsJSON-ключ сервисного аккаунта GoogleE1, E5, 00, 10
checko_api_keyAPI-ключ checko.ruE2, E3
dadata_api_keyAPI-ключ dadata.ruE4
dadata_secret_keySecret dadata.ruE4
yandex_search_api_keyКлюч Yandex Search API02 serp-fetch
gas_trigger_tokenТокен авторизации для GAS → triggeroutreach-trigger
telegram_bot_tokenТокен Telegram-ботаУведомления
telegram_chat_idChat ID для TelegramУведомления
AI-модели и стоимость
МодельВходВыходГде используетсяТарифы на
gpt-oss-20b0.10 ₽ / 1K токенов0.10 ₽ / 1KБренд (01), AI-извлечение (06, каскад 1), Нормализация (08)Апр. 2026
DeepSeek V3.20.50 ₽ / 1K токенов0.80 ₽ / 1KAI-извлечение (06, каскад 2 — только /team, /about)Апр. 2026
Пользователи
Лог авторизации
Нажмите кнопку для загрузки