CI / lint_and_test (push) Successful in 2m34s
Details
|
||
---|---|---|
.gitea/workflows | ||
src | ||
.dockerignore | ||
.env.example | ||
.gitignore | ||
Dockerfile | ||
README.md | ||
docker-compose.yml | ||
requirements-dev.txt | ||
requirements.txt |
README.md
AI Email Assistant
Сервис для генерации персонализированных холодных писем с использованием RAG и LangGraph.
О программе
- Персонализация писем под роль, индустрию и компанию лида
- RAG-подход с базой знаний реальных кейсов
- LangGraph пайплайн обработки запросов
- Векторный поиск в ChromaDB
- Поддержка OpenAI и Google Gemini
- RESTful API для интеграции с CRM
Логика работы
Система обрабатывает запросы через 10-этапный LangGraph пайплайн:
- Валидация входа - проверка обязательных полей лида
- Извлечение признаков - нормализация роли, индустрии из входных данных
- Построение запроса - формирование поискового запроса на основе профиля лида
- Векторный поиск - поиск релевантных кейсов в ChromaDB (top-30)
- Ранжирование контекста - отбор лучших кейсов (top-6) и создание bullets
- Построение промпта - формирование системного и пользовательского промптов
- LLM генерация - создание письма через OpenAI/Gemini
- Парсинг ответа - извлечение JSON с темой и телом письма
- Проверка качества - валидация длины, структуры, наличия CTA
- Формирование результата - финальная структура ответа с метаданными
Промпт-инжиниринг: обоснование подхода
Почему именно такая структура письма?
Структура Приветствие -> Хук -> Ценность -> Кейс -> 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
- Микро-абзацы 1-2 предложения: улучшают восприятие текста на экранах смартфонов. Люди сканируют информацию взглядом, и короткие абзацы помогают быстрее вычленять ключевые мысли. Источник: F-Shaped Pattern of Reading Web Content
- 1 конкретный CTA: письма с одним призывом к действию получают на 371 % больше кликов и могут увеличить доход на 1617 % по сравнению с письмами с несколькими CTA.
Источник: Unlayer - Call to Action in Emails
Настройка промптов
Системные промпты: src/services/prompt_templates.py
- Тон: деловой, лаконичный, дружелюбный
- Длина: до 1000 символов
- Структура: Приветствие -> Хук -> Ценность -> Кейс -> CTA -> Подпись
Быстрый старт
1. Подготовка окружения
git clone https://git.itqop.pw/itqop/ai-email-assistant.git
cd ai-email-assistant
# Создание конфигурации
cp .env.example .env
# Или создайте .env файл сами
2. Базовая конфигурация .env
LLM_PROVIDER=openai
OPENAI_API_KEY=your_openai_api_key_here
API_SECRET_KEY=your_admin_token
3. Запуск через Docker
docker compose up --build
4. Загрузка базы знаний
Полоджите файлы/папку с md в data/, а после выполните запрос
curl -X POST "http://localhost:8000/api/v1/admin/ingest" \
-H "Authorization: Bearer your_admin_token"
5. Использование
curl -X POST "http://localhost:8000/api/v1/generate_email" \
-H "Content-Type: application/json" \
-d '{
"contact": "Помящий Никита",
"position": "Технический директор",
"company_name": "FIVE",
"segment": "маркетинговое агентство"
}'
Альтернативный запуск (без Docker)
# Создание виртуального окружения
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
- Генерация письма
Формат запроса
Обязательные поля:
{
"contact": "string",
"position": "string",
"company_name": "string",
"segment": "string"
}
Полный формат:
{
"contact": "Помящий Никита",
"position": "Технический директор",
"company_name": "FIVE",
"segment": "маркетинговое агентство",
"email": "nikita@five.agency",
"locale": "ru",
"notes": "Дополнительная информация"
}
Формат ответа
{
"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:
{
"request_id": "1641234567890",
"method": "POST",
"url": "http://localhost:8000/api/v1/generate_email",
"status_code": 200,
"process_time": 2.341
}
Проверка состояния
# Статус сервиса
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
# Загрузите базу знаний
curl -X POST -H "Authorization: Bearer secret" \
"http://localhost:8000/api/v1/admin/ingest"
502 External service error
- Проверьте API ключи LLM провайдера в .env
400 Validation failed
- Убедитесь что все обязательные поля заполнены
Обновление базы знаний
Добавление кейсов
-
Поместите
.md
файлы вdata
-
Файлы должны содержать:
- Заголовки для структуры
- Числовые метрики
- Ключевые слова индустрии
- Упоминания ролей
-
Дополните базу (инкрементально):
curl -X POST -H "Authorization: Bearer secret" \
"http://localhost:8000/api/v1/admin/ingest"
- (альтернативно) Пересоздайте базу:
curl -X POST -H "Authorization: Bearer secret" \
"http://localhost:8000/api/v1/admin/ingest?recreate=true"
Формат кейсов
# Кейс компании FIVE
Маркетинговое агентство автоматизировало работу с подрядчиками.
## Результаты
- Онбординг: с 2 дней до 15 минут
- Снижение ошибок: на 95%
- Выплаты: мгновенные
Технический директор Никита отмечает эффективность.
Тестирование
# Все тесты
pytest src/tests/
# Только API
pytest src/tests/test_api.py
TODO:
- Улучшить валидацию входных данных (почта, защита хака llm)
- Увеличить покрытие кода тестами до 80%, доавить unit тесты для бизнес-логики
- Сделать качественную докуентацию