From 9f616aaf1dc2c5c4065b723a3a93ec1e9f6006cd Mon Sep 17 00:00:00 2001 From: itqop Date: Sat, 19 Jul 2025 19:42:03 +0300 Subject: [PATCH] Add full README --- README.md | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) diff --git a/README.md b/README.md index 3f47c30..5a3a605 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,349 @@ Сервис для генерации персонализированных холодных писем с использованием RAG и LangGraph. +## О программе + +- Персонализация писем под роль, индустрию и компанию лида +- RAG-подход с базой знаний реальных кейсов +- LangGraph пайплайн обработки запросов +- Векторный поиск в ChromaDB +- Поддержка OpenAI и Google Gemini +- RESTful API для интеграции с CRM + +### Логика работы + +Система обрабатывает запросы через 10-этапный LangGraph пайплайн: + +1. **Валидация входа** - проверка обязательных полей лида +2. **Извлечение признаков** - нормализация роли, индустрии из входных данных +3. **Построение запроса** - формирование поискового запроса на основе профиля лида +4. **Векторный поиск** - поиск релевантных кейсов в ChromaDB (top-30) +5. **Ранжирование контекста** - отбор лучших кейсов (top-6) и создание bullets +6. **Построение промпта** - формирование системного и пользовательского промптов +7. **LLM генерация** - создание письма через OpenAI/Gemini +8. **Парсинг ответа** - извлечение JSON с темой и телом письма +9. **Проверка качества** - валидация длины, структуры, наличия CTA +10. **Формирование результата** - финальная структура ответа с метаданными + +## Промпт-инжиниринг: обоснование подхода + +### Почему именно такая структура письма? + +Структура **Приветствие -> Хук -> Ценность -> Кейс -> CTA -> Подпись** выбрана на основе исследований конверсии холодных писем: + +**1. Приветствие по имени** +- Персонализация создает впечатление индивидуального подхода +- Снижает восприятие письма как спама + +**2. Хук-вопрос в первых строках** +- Привлекает внимание и активирует любопытство +- Касается специфики индустрии лида -> создает ощущение релевантности + +**3. Конкретная ценность с цифрами** +- Мозг лучше воспринимает конкретные числа vs абстракции +- "15 минут" vs "быстро", "95%" vs "значительно" +- Снижает скептицизм -> повышает доверие + +**4. Социальное доказательство с кейсом** +- Название реальной компании + численный результат +- Психология: "если помогли похожей компании, помогут и нам" +- Снижает воспринимаемый риск принятия решения + +**5. Мягкий CTA без давления** +- "Если интересно" vs "Давайте встретимся завтра" +- Оставляет ощущение выбора -> снижает сопротивление +- 15-минутный формат -> низкий барьер входа + +**6. Эмоциональные триггеры** +- "Спокойствие", "контроль" -> позитивные эмоции от решения проблем +- "Избежите", "снизьте риски" -> страх потерь (loss aversion) +- Комбинация мотивирует к действию + +### Ограничения для максимальной эффективности + +- **≤ 1000 символов**: оптимальная длина письма для цифрового потребления. Согласно Nielsen Norman Group, пользователи читают в среднем 20–28% текста на веб-странице и быстро теряют внимание после первых 200–250 слов (~1000–1200 символов). +Источник: [How Users Read on the Web](https://www.nngroup.com/articles/how-users-read-on-the-web/) +- **Микро-абзацы 1-2 предложения**: улучшают восприятие текста на экранах смартфонов. Люди сканируют информацию взглядом, и короткие абзацы помогают быстрее вычленять ключевые мысли. +Источник: [F-Shaped Pattern of Reading Web Content](https://www.nngroup.com/articles/f-shaped-pattern-reading-web-content/) +- **1 конкретный CTA**: письма с одним призывом к действию получают на **371 % больше кликов** и могут увеличить доход на **1617 %** по сравнению с письмами с несколькими CTA. +Источник: [Unlayer - Call to Action in Emails](https://unlayer.com/blog/call-to-action-in-emails) + +### Настройка промптов + +Системные промпты: `src/services/prompt_templates.py` + +- Тон: деловой, лаконичный, дружелюбный +- Длина: до 1000 символов +- Структура: Приветствие -> Хук -> Ценность -> Кейс -> CTA -> Подпись + +## Быстрый старт + +### 1. Подготовка окружения + +```bash +git clone https://git.itqop.pw/itqop/ai-email-assistant.git +cd ai-email-assistant + +# Создание конфигурации +cp .env.example .env +# Или создайте .env файл сами +``` + +### 2. Базовая конфигурация .env + +```bash +LLM_PROVIDER=openai +OPENAI_API_KEY=your_openai_api_key_here +API_SECRET_KEY=your_admin_token +``` + +### 3. Запуск через Docker + +```bash +docker compose up --build +``` + +### 4. Загрузка базы знаний + +```bash +curl -X POST "http://localhost:8000/api/v1/admin/ingest" \ + -H "Authorization: Bearer your_admin_token" +``` + +### 5. Использование + +```bash +curl -X POST "http://localhost:8000/api/v1/generate_email" \ + -H "Content-Type: application/json" \ + -d '{ + "contact": "Помящий Никита", + "position": "Технический директор", + "company_name": "FIVE", + "segment": "маркетинговое агентство" + }' +``` + +## Альтернативный запуск (без Docker) + +```bash +# Создание виртуального окружения +python -m venv .venv +.venv\Scripts\activate # Windows +source .venv/bin/activate # Linux/Mac + +# Установка зависимостей +pip install -r requirements.txt + +# Загрузка данных +python -m src.ingest.ingest_cli --data-dir articles_konsol_pro --recreate + +# Запуск сервиса +python -m src.app.main +``` + +## API документация + +### Основные эндпоинты + +- `GET /healthz` - Проверка здоровья +- `GET /readiness` - Готовность к работе +- `GET /docs` - Swagger документация +- `POST /api/v1/generate_email` - Генерация письма + +### Формат запроса + +**Обязательные поля:** +```json +{ + "contact": "string", + "position": "string", + "company_name": "string", + "segment": "string" +} +``` + +**Полный формат:** +```json +{ + "contact": "Помящий Никита", + "position": "Технический директор", + "company_name": "FIVE", + "segment": "маркетинговое агентство", + "email": "nikita@five.agency", + "locale": "ru", + "notes": "Дополнительная информация" +} +``` + +### Формат ответа + +```json +{ + "subject": "Как упростить работу с самозанятыми в FIVE?", + "body": "Здравствуйте, Никита!....", + "meta": { + "locale": "ru", + "lead_normalized": { + "contact_name": "Помящий Никита", + "contact_first_name": "Никита", + "contact_last_name": "Помящий", + "role_title": "Технический директор", + "role_category": "tech", + "company_name": "FIVE", + "industry_segment": "маркетинговое агентство", + "industry_tag": "marketing_agency", + "email": null, + "locale": "ru", + "notes": null + }, + "used_chunks": [ + "sds_podkluchenie_k_konsoli#sds_podkluchenie_k_konsoli#c7", + "vysotnik_rental#vysotnik_rental#c2" + ], + "model": "gpt-4o", + "tokens_prompt": 1132, + "tokens_completion": 289, + "guardrails_violations": 0, + "context_chunks_used": 5, + "context_quality_score": 0.87 + } +} +``` + +**Структура meta:** +- `locale` - Язык, на котором сгенерировано письмо (например, ru) +- `lead_normalized` - Объект с нормализованной и обогащенной информацией о лиде: + - `contact_first_name/contact_last_name` - Распознанные имя и фамилия + - `role_category/industry_tag` - Машинно-читаемые теги для должности и сегмента компании (например, tech, marketing_agency) +- `used_chunks` - Массив с ID фрагментов из базы знаний, которые были использованы для генерации ответа +- `model` - Использованная LLM модель +- `tokens_prompt/tokens_completion` - Расход токенов на запрос и ответ для мониторинга затрат +- `guardrails_violations` - Количество нарушений правил безопасности (guardrails). 0 означает, что все проверки пройдены +- `context_chunks_used` - Общее количество фрагментов контекста, которые были использованы для генерации +- `context_quality_score` - Оценка релевантности найденного контекста (0-1): + - 1.0 - отличное качество контекста + - 0.8+ - хорошее качество (высокая релевантность) + - 0.6+ - приемлемое качество (достаточная релевантность) + - <0.6 - низкое качество (слабая релевантность) + +## Конфигурация + +### Переменные окружения + +| Параметр | Описание | По умолчанию | +|----------|----------|--------------| +| `LLM_PROVIDER` | openai или gemini | openai | +| `LLM_MODEL` | Модель генерации | gpt-4o | +| `EMBEDDING_MODEL` | Модель векторизации | text-embedding-3-large | +| `TOP_K` | Чанков для поиска | 30 | +| `TOP_N_CONTEXT` | Чанков в контексте | 6 | +| `CHUNK_SIZE` | Размер чанка (токены) | 500 | +| `CHUNK_OVERLAP` | Перекрытие чанков | 100 | + +## Мониторинг + +### Качество контекста + +Метрика `context_quality_score` вычисляется на основе: +- **Средний similarity score** (40%) - релевантность найденных кейсов +- **Доля высококачественных chunks** (25%) - процент кейсов с similarity > 0.7 +- **Консистентность результатов** (20%) - равномерность качества chunks +- **Фактор количества** (15%) - достаточность объема контекста + +**Интерпретация для мониторинга:** +- `context_quality_score < 0.5` - критически низкое качество, требует обновления базы знаний +- `context_quality_score < 0.7` - предупреждение о качестве контекста +- `context_quality_score >= 0.8` - хорошее качество генерации + +### Логи + +Все запросы логируются в JSON: + +```json +{ + "request_id": "1641234567890", + "method": "POST", + "url": "http://localhost:8000/api/v1/generate_email", + "status_code": 200, + "process_time": 2.341 +} +``` + +### Проверка состояния + +```bash +# Статус сервиса +curl http://localhost:8000/healthz + +# Статистика базы знаний +curl -H "Authorization: Bearer secret" \ + http://localhost:8000/api/v1/admin/knowledge-base/stats + +# Docker логи +docker-compose logs -f ai-email-assistant +``` + +## Устранение ошибок + +### Частые проблемы + +**404 No relevant knowledge found** +```bash +# Загрузите базу знаний +curl -X POST -H "Authorization: Bearer secret" \ + "http://localhost:8000/api/v1/admin/ingest" +``` + +**502 External service error** +- Проверьте API ключи LLM провайдера в .env + +**400 Validation failed** +- Убедитесь что все обязательные поля заполнены + +## Обновление базы знаний + +### Добавление кейсов + +1. Поместите `.md` файлы в `data` +2. Файлы должны содержать: + - Заголовки для структуры + - Числовые метрики + - Ключевые слова индустрии + - Упоминания ролей + +3. Дополните базу (инкрементально): +```bash +curl -X POST -H "Authorization: Bearer secret" \ + "http://localhost:8000/api/v1/admin/ingest" +``` +4. (альтернативно) Пересоздайте базу: +```bash +curl -X POST -H "Authorization: Bearer secret" \ + "http://localhost:8000/api/v1/admin/ingest?recreate=true" +``` + +### Формат кейсов + +```markdown +# Кейс компании FIVE + +Маркетинговое агентство автоматизировало работу с подрядчиками. + +## Результаты +- Онбординг: с 2 дней до 15 минут +- Снижение ошибок: на 95% +- Выплаты: мгновенные + +Технический директор Никита отмечает эффективность. +``` + +## Тестирование + +```bash +# Все тесты +pytest src/tests/ + +# Только API +pytest src/tests/test_api.py + +```