ТЗ: Модуль AI-аналитики (aiAnalytics) для backend
Метаданные
| Параметр | Значение |
|---|---|
| Дата создания | 2026-07-02 |
| Дата последнего изменения | 2026-07-02 |
| Статус апрува | ⏳ На рассмотрении |
| Дата апрува | — |
1. Назначение
Добавить в apps/backend (NestJS) новый модуль aiAnalytics с двумя защищёнными JWT эндпоинтами:
- Настроение рынка — индекс страха и жадности (Fear & Greed) + AI «Market Outlook» (сценарный прогноз). По образцу продукта zenfi (
/Users/vovilonn/Documents/work/defilab/zenfi/apps/backend, модулиmarkets+assistant). - AI-аналитика пула Uniswap — при клике на пул в продукте «index» пользователь получает связный AI-разбор пула (метрики + краткая аналитика двух токенов) в формате Markdown для красивого рендера на фронте. Данные пула берутся из The Graph (тот же источник, что питает продукт index), аналитика токенов — из источников семейства CoinGecko.
Авторизация к OpenAI выполняется не по pay-per-use API-ключу, а через подписку ChatGPT Plus посредством локального OpenAI-совместимого прокси (CLIProxyAPIPlus). Backend работает со стандартным openai SDK, но с baseURL, направленным на прокси.
Реализуется только backend для этих двух эндпоинтов. Фронт — отдельной задачей.
2. Функциональные требования
2.1. Пользовательские сценарии
- Настроение рынка. Авторизованный пользователь открывает раздел рынка → фронт зовёт
GET /ai-analytics/market/outlook→ получает значение Fear & Greed + структурный сценарный прогноз (bias,scenarios[],summary,disclaimer) и отображает виджет. - AI-разбор пула. Авторизованный пользователь в продукте index кликает «аналитика» на конкретном пуле → фронт зовёт
POST /ai-analytics/pool/analyticsс адресом пула (poolId= on-chain адрес пула, 0x-форма — не числовой id из whitelist) иnetwork→ получает готовый Markdown-документ (заголовок, таблица метрик пула, таблица по двум токенам, блок «на что обратить внимание», «итог») и рендерит его.
2.2. Бизнес-логика
Эндпоинт 1 — GET /ai-analytics/market/outlook
- Fear & Greed: тянется с
https://api.alternative.me/fng/?limit=1(без ключа). Кэш Redis, TTLAI_ANALYTICS_FNG_TTL_SEC(по умолчанию 300 c). - Market Outlook: один вызов LLM. Входной блок собирается из:
- CoinGecko
GET /global(total market cap, 24h volume, BTC/ETH dominance, 24h change), - CoinGecko
GET /coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=true&price_change_percentage=1h,24h,7d(топ-гейнеры/лузеры + altseason-индикатор), - значение Fear & Greed.
- CoinGecko
- Altseason-индикатор (считаем сами, без ссылки на внешний код): доля топ-N (например топ-50, исключая стейблкоины) альткоинов, обогнавших BTC по доходности за 7 дней.
altseason = round(100 * countAltsBeatingBtc7d / totalAltsConsidered); при недостатке данных поле опускается. - Ответ (структурный JSON, как zenfi):
{
"fearGreed": { "value": 72, "valueClassification": "Greed", "timestamp": 1782986400 },
"outlook": {
"bias": "bullish" | "bearish" | "neutral",
"scenarios": [
{ "trigger": "если BTC закрепится выше 70k", "direction": "up" | "down" | "sideways", "range": "3–6%", "note": "одно короткое предложение обоснования" }
],
"summary": "2–3 предложения простым языком",
"disclaimer": "короткая оговорка о рисках, оканчивается фиксированной фразой"
},
"generatedAt": "2026-07-02T10:00:00.000Z",
"cached": true
}
- Язык текста прогноза — русский (продукт RU). Это решение зафиксировано (см. также §5).
- Фиксированная фраза дисклеймера:
«Не является финансовой рекомендацией.». Валидатор ответа LLM: еслиoutlook.disclaimerне оканчивается этой фразой — детерминированно дописываем её (не отбраковываем ответ). Аналогично при несоответствии структуры JSON — сначала одна повторная попытка, при повторной неудаче — детерминированный фолбэк (см. ниже). - Кэш AI-результата: Redis, TTL
AI_ANALYTICS_OUTLOOK_TTL_SEC(по умолчанию 3600 c). Конкурентные первые генерации дедуплицируются in-process (inflight-map). - Поле
cached: относится к тому, была ли AI-часть (outlook) отдана из кэша. Значение Fear & Greed кэшируется отдельно (внутренняя деталь) и на флаг не влияет. - Устойчивость: каждый апстрим оборачивается
try/catchс деградацией; при полном отказе LLM возвращается детерминированный фолбэк-объект той же формы (bias='neutral', пустые/дефолтные сценарии, дисклеймер с фиксированной фразой), который НЕ кэшируется (чтобы повторить попытку позже). Эндпоинт не отдаёт 5xx из-за одного упавшего апстрима.
Эндпоинт 2 — POST /ai-analytics/pool/analytics
- Request:
{ poolId: string /* 0x + 40 hex, on-chain адрес пула */, network?: string }.networkнеобязателен; дефолт —AI_ANALYTICS_DEFAULT_NETWORK(совпадает с сетью текущего сабграфа и пулов index).- MVP-ограничение сети: поддерживается ровно одна сеть — та, на которую настроен сабграф. Если
networkпередан и не равенAI_ANALYTICS_DEFAULT_NETWORK→400 Bad Request(иначе метрики пришли бы из чужого сабграфа, а токен-д анные из другой сети — рассинхрон). Enum значений (bsc|base|ethereum|polygon) задан на будущее, но в MVP валидируется на равенство дефолту. - Невалидный формат
poolId(не0x+40 hex) →400(валидация DTO).
- Сбор метрик (детерминированно, в коде):
Поле шаблона Источник Заголовок $SYM0 / $SYM1 — Uniswap v3 (Network)символы токенов из сабграфа + версия/сеть из конфигурации (префикс $— у обоих символов)Комиссия (%) feeTier / 10000(напр. 3000 → 0.30%);feeTierберём изgetPoolsOverview().items[0].feeTierили из расширенногоgetPoolAnalyticsTVL getPoolAnalytics().tvlUSDОбъём 24ч getPoolAnalytics().volume24hUSDЗаработок пула 24ч getPoolAnalytics().fees24hUSDДоходность (APR, годовых) getPoolsOverview().items[0].apr7dPercent(fees7d/avgTVL·365/7·100)Проскальзывание (~$5k) эвристика (см. ниже), помечается «~» Цена токена token-data (CoinGecko/GeckoTerminal), сверяется с ценой сабграфа ethPriceUSD·derivedETHИзменение 24ч, Капитализация token-data «Что это» / проза / IL / «Итог» LLM на основе переданных чисел - Оценка проскальзывания (MVP-эвристика): приближение через constant-product на TVL как для 50/50-пула:
slippage% ≈ tradeSize / (tradeSize + TVL/2) · 100, гдеtradeSize = 5000USD. Проверка на примере шаблона: TVL $224.5k →5000 / (5000 + 112250) ≈ 4.26%→ «~4–5%». Значение помечается как приблизительное. Точный расчёт по тиковой ликвидности v3 — техдолг (см. 4.2). - Генерация Markdown: собранный структурный блок метрик передаётся LLM. Системный промпт: писать строго по шаблону на русском языке, использовать переданные числа дословно, ничего не выдумывать, для отсутствующих значений (mcap/±24ч мелких токенов) — писать «—» или опускать, не придумывать; вернуть только Markdown (без преамбулы и без ```-ограждений). Пост-обработка: срезаем возможные code-fences и текст до первого заголовка
#. Если в ответе нет ни одного заголовка#— считаем это отказом LLM и отдаём детерминированный фолбэк. - Ответ:
{
"markdown": "# $JESSE / $WETH — Uniswap v3 (BSC)\n...",
"metrics": {
"pool": { "poolId": "0x…", "network": "bsc", "dex": "uniswap-v3", "feeTierPercent": 0.3,
"tvlUsd": 224500, "volume24hUsd": 680000, "fees24hUsd": 2040,
"aprPercent": 332, "slippage5kPercent": 4.3 },
"token0": { "address": "0x…", "symbol": "JESSE", "name": "…"|null, "priceUsd": 0.001176,
"change24hPercent": 54.7|null, "marketCapUsd": 1180000|null },
"token1": { "address": "0x…", "symbol": "WETH", "name": "…"|null, "priceUsd": 2400,
"change24hPercent": 1.2|null, "marketCapUsd": null }
},
"generatedAt": "2026-07-02T10:00:00.000Z",
"cached": false
}
- Главное поле —
markdown;metricsотдаём дополнительно (для нативного рендера на фронте). - Обязательные поля токена:
address,symbol,priceUsd. Поляname,change24hPercent,marketCapUsd— nullable (мелкие токены могут не иметь данных; см. 4.1.2). В примереtoken1.marketCapUsd: nullпоказывает именно этот случай. - Поле
cached: относится к тому, была лиmarkdown(AI-часть) отдана из кэша. - Кэш: Redis по ключу
ai:pool:{network}:{poolId}, TTLAI_ANALYTICS_POOL_TTL_SEC(по умолчанию 900 c). Числовые данные графа уже кэшируютсяUniswapV3GraphService. Конкурентные первые генерации дедуплицируются in-process по ключу(network, poolId). - Устойчивость / ошибки:
getPoolAnalytics(poolId)вернул пусто/нет ключевых полей (пул не найден в сабграфе, нет токенов/TVL) →404 Not Found(pool_not_found).- LLM недоступен → деградируем до детерминированного минимального Markdown (заголовок + таблица метрик, без AI-прозы). Такой фолбэк НЕ кэшируется (как и в эндпоинте 1), чтобы после восстановления LLM выдать полноценный ответ.
- Эндпоинт не отдаёт 5xx из-за отказа LLM/токен-апстрима.
2.3. UI/UX требования
Не применимо (backend-only). Ответ эндпоинта 2 — валидный Markdown, рассчитанный на прямой рендер на фронте.
3. Техническая реализация
3.1. Архитектура
Вариант A1 (утверждён): переиспользуем существующий UniswapV3GraphService; OpenAI-клиент — новый провайдер за DI-токеном внутри aiAnalytics.
apps/backend/src/aiAnalytics/
ai-analytics.module.ts # регистрация; imports: [LiquidityModule] (для UniswapV3GraphService)
ai-analytics.controller.ts # 2 роута, @UseGuards(JwtAuthGuard) + @ApiBearerAuth + @ApiTags
providers/
openai.provider.ts # OPENAI_CLIENT = new OpenAI({ baseURL, apiKey }) → CLIProxyAPIPlus
services/
market-outlook.service.ts # fear&greed + Market Outlook (LLM → JSON) + inflight-dedup + кэш
pool-analytics.service.ts # сбор метрик пула + LLM → Markdown + inflight-dedup + кэш
market-data.service.ts # CoinGecko /global,/coins/markets + alternative.me/fng (axios + кэш)
token-data.service.ts # CoinGecko contract + GeckoTerminal fallback (по network+address)
utils/
slippage.util.ts # оценка price impact ~$5k (чистая функция)
markdown.util.ts # снятие fences/преамбулы, валидация наличия заголовка
llm.util.ts # надёжный парс JSON из ответа LLM (json_object → текст-фолбэк)
prompts/
market-outlook.prompt.ts # системный промпт + builder входа (чистые, тестируемые)
pool-analytics.prompt.ts # системный промпт + builder входа под шаблон (RU)
dto/
index.ts # request/response DTO (class-validator + @ApiProperty)
Поток эндпоинта 2 (controller → pool-analytics.service):
UniswapV3GraphService.getPoolAnalytics(poolId)→ TVL, объём24ч, комиссии24ч, цены токенов, метаданные токенов (address/symbol/decimals) и feeTier (после расширения маппинга, см. 3.2);UniswapV3GraphService.getPoolsOverview([poolId])→result.items[0].apr7dPercent(иfeeTier, если не берём из шага 1);token-data.serviceпо адресам токенов → mcap, ±24ч, описания;slippage.util→ оценка проскальзывания;- сборка структурного блока метрик →
openai.provider(LLM) → Markdown →markdown.utilпост-обработка; - кэш в Redis, ответ.
3.2. Описание технической реализации
Изменения в существующем коде
src/liquidity/liquidity.module.ts: добавитьUniswapV3GraphServiceвexports(сейчас он только вproviders), чтобыAiAnalyticsModuleмог его инъектить черезimports: [LiquidityModule].src/liquidity/uniswap-v3-graph.service.ts: расширить возвращаемый типgetPoolAnalytics()— добавить метаданные токенов (token0/token1:{ address, symbol, decimals }) иfeeTier. Данные уже приходят вPOOL_ANALYTICS_QUERY(feeTier,token0/token1 { id symbol decimals derivedETH }) — правится только маппинг (строки ~478–487), тип вuniswap-v3-graph.types.ts(~56–65). Инцидентная уборка (по ходу правки этого файла): удалить отладочныеconsole.logна строках 512/526/570/585 вgetMarketAnalytics.src/app.module.ts: зарегистрироватьAiAnalyticsModuleвimports; добавить новые env вJoi-схему..env.example: добавить новые переменные.
OpenAI-провайдер (providers/openai.provider.ts)
// псевдо-конфиг
new OpenAI({
baseURL: process.env.OPENAI_BASE_URL ?? 'http://localhost:8317/v1', // CLIProxyAPIPlus
apiKey: process.env.OPENAI_API_KEY, // клиентский токен прокси (см. ниже)
});
- Вызовы:
chat.completions.create({ model: AI_MODEL, messages: [system, user] }). temperatureНЕ передаём. Backend ChatGPT-Plus/Codex, к которому проксирует CLIProxyAPIPlus, использует ограниченную Responses-поверхность и отклоняетtemperature(HTTP 400); reasoning-модели GPT-5 также требуютtemperature=1. Параметр отправляем только если заданAI_TEMPERATUREи модель заведомо его поддерживает (по умолчанию — не отправляем).response_format: json_object— необязательная оптимизация, не обязательный контракт. Тот же Codex-backend может не поддерживатьresponse_format. Поэтому JSON-эндпоинт (outlook) работает по двухпутевой схеме, где парсинг обязателен: (1) пробуем сresponse_format: { type: 'json_object' }; (2) при ошибке/неподдержке — повтор без него; в обоих случаях извлекаем JSON из текста (llm.util) и валидируем структуру по схеме. Никогда не полагаемся на то, что ответ уже чистый JSON.- Эндпоинт 2: о бычный текст (Markdown); пост-обработка
markdown.util. - Модель
AI_MODELконфигурируема и выбирается из фактически доступных на подписке моделей — сверяется черезGET {OPENAI_BASE_URL}/modelsна запущенном прокси (не все codex-варианты доступны на ChatGPT-аккаунте). Не хардкодим. - Клиентский
OPENAI_API_KEY: CLIProxyAPIPlus требует от клиента ключ только если в егоconfig.yamlнепустой списокapi-keys. Для боевого окружения делаемOPENAI_API_KEYобязательным и документируем, что его значение должно совпадать с записью вapi-keysпрокси. (Это отдельный ключ от Management APIsecret-key.)
Источники данных по токенам (token-data.service.ts) — вариант B1
- Основной: CoinGecko
GET https://api.coingecko.com/api/v3/coins/{asset_platform}/contract/{address}→name,description.en,market_data.current_price.usd,market_data.price_change_percentage_24h,market_data.market_cap.usd. Keyless или сCOINGECKO_API_KEY(demo/pro header). - Фолбэк (чисто on-chain токены): GeckoTerminal:
GET https://api.geckoterminal.com/api/v2/networks/{network}/tokens/{address}→attributes.price_usd,fdv_usd,market_cap_usd,name,symbol.- ±24ч цены НЕТ в атрибутах токена — берём из
GET .../tokens/{address}/pools→data[0].attributes.price_change_percentage.h24(топовый пул токена). Keyless.
- Числовая цена дополнительно сверяется с ценой из сабграфа.
- Кэш token-data: Redis, TTL
AI_ANALYTICS_TOKEN_TTL_SEC(по умолчанию 300 c). - Маппинг сети → идентификаторы:
networkCoinGecko asset_platform GeckoTerminal slug bscbinance-smart-chainbscbasebasebaseethereumethereumethpolygonpolygon-pospolygon_pos
Кэш и хранение
- Только Redis (
CACHE_MANAGER), без новых таблиц БД. TTL передаём в форме{ ttl: <секунды> }(стиль cache-manager v4, как в проекте). - TTL (все конфигурируемы через env): fear&greed 300 c (
AI_ANALYTICS_FNG_TTL_SEC), outlook 3600 c (AI_ANALYTICS_OUTLOOK_TTL_SEC), token-data 300 c (AI_ANALYTICS_TOKEN_TTL_SEC), pool markdown 900 c (AI_ANALYTICS_POOL_TTL_SEC).
Новые переменные окружения
| Переменная | Назначение | Дефолт |
|---|---|---|
OPENAI_BASE_URL | URL CLIProxyAPIPlus | http://localhost:8317/v1 |
OPENAI_API_KEY | клиентский токен прокси (обязателен для боевого; совпадает с api-keys прокси) | — |
AI_MODEL | имя модели у прокси/подписки (из GET /v1/models) | — (обязателен для боевого) |
AI_TEMPERATURE | опц.; передаётся только если модель поддерживает | не задан (не отправляется) |
AI_ANALYTICS_DEFAULT_NETWORK | сеть пулов index / сабграфа | bsc |
AI_ANALYTICS_FNG_TTL_SEC | TTL кэша fear&greed | 300 |
AI_ANALYTICS_OUTLOOK_TTL_SEC | TTL кэша outlook | 3600 |
AI_ANALYTICS_TOKEN_TTL_SEC | TTL кэша token-data | 300 |
AI_ANALYTICS_POOL_TTL_SEC | TTL кэша pool markdown | 900 |
COINGECKO_API_KEY | опц. ключ CoinGecko (лимиты) | — |
AI_MODEL в Joi — .optional() в dev, но обязателен для боевого запуска (проверяется на старте сервиса; без него LLM-эндпоинты отдают деградированный ответ). Уже используемые графом переменные: UNISWAP_V3_SUBGRAPH_URL / THE_GRAPH_API_KEY + UNISWAP_V3_SUBGRAPH_ID.
Авторизация эндпоинтов
Оба роута — @UseGuards(JwtAuthGuard) + @ApiBearerAuth(), без пейволла. Пользователь читается через @Request() req: { user: JwtPayloadDto }. Роуты защищены явно (по умолчанию в проекте роут публичный).
Тестирование
- Юнит (jest, замоканы axios/openai): builder'ы промптов;
slippage.util(проверка на числах шаблона → 4.26%); altseason-расчёт; форматтеры/маппинг метрик;markdown.util(снятие fences, случай без заголовка);llm.util(парс JSON из «грязного» ответа); валидатор дисклеймера (дописывание фразы); маппинг token-data и сети. - Сервисные:
market-outlook.service→ корректный DTO, обе веткиresponse_format(с/без), фолбэк без кэша;pool-analytics.service→ markdown содержит ожидаемые числа, 404 при пустом графе, деградация без кэша (моки графа + CoinGecko/GeckoTerminal + OpenAI). - e2e (supertest, замоканы апстримы): оба роута → 200 и корректная форма;
401без JWT;400приnetwork != defaultи невалидномpoolId;404при неизвестном пуле. - Живой smoke-тест (реальные запросы) — скрипт
apps/backend/scripts/ai-analytics-smoke.sh+ runbook (см. ниже).
Runbook живого smoke-теста
- Поднять CLIProxyAPIPlus (docker), задать
config.yaml(в т.ч.api-keys: [<OPENAI_API_KEY>]). - Залогиниться в ChatGPT Plus одноразовым OAuth (
--codex-login); токен сохраняется в~/.cli-proxy-api/. Требуется активная подписка ChatGPT Plus/Pro. - Проверить доступные модели:
curl {OPENAI_BASE_URL}/models→ выбратьAI_MODEL. - Выставить env (
OPENAI_BASE_URL,OPENAI_API_KEY,AI_MODEL, сабграф, дефолтная сеть), запуститьpnpm dev-back, получить dev-JWT. curl GET /ai-analytics/market/outlook→ валидный JSON аутлука;curl POST /ai-analytics/pool/analyticsс реальнымpoolId(0x-адрес) из index → непустой Markdown. Скрипт печатает результаты и коды ответов.
Контрольная точка. Как только будет готов OpenAI-коннектор (
openai.provider.ts+ env), у пользователя запрашивается логин в OpenAI (ChatGPT Plus через CLIProxyAPIPlus). Гейтится только реальное/живое тестирование LLM — дальнейшая разработка сервисов с замоканным OpenAI (этапы 3–5) может продолжаться параллельно.
4. Проблемы и компромиссы
4.1. Известные ограничения
- Один сабграф-эндпоинт (одна сеть).
UniswapV3GraphServiceработает с единственным сконфигурированным сабграфом. Пулы index сейчас на BSC.- Влияние: MVP анализирует пулы только сети
AI_ANALYTICS_DEFAULT_NETWORK; иные значенияnetwork→400. Мультисеть — техдолг (см. 4.2).
- Покрытие мелких токенов данными.
- Очень мелкие токены могут отсутствовать в CoinGecko-by-contract; фолбэк — GeckoTerminal; если и там нет —
name/marketCapUsd/change24hPercentмогут бытьnull. - Влияние: поля nullable; LLM инструктируется писать «—»/опускать, не выдумывать.
- Очень мелкие токены могут отсутствовать в CoinGecko-by-contract; фолбэк — GeckoTerminal; если и там нет —
- Зависимость от локального прокси и подписки.
- Реальные LLM-запросы требуют запущенного CLIProxyAPIPlus, залогиненного в ChatGPT Plus. Это операционная зависимость вне кода.
- Влияние: автотесты мокают OpenAI; «реальные» проверки — через живой smoke-тест.
- Ограниченная Responses-поверхность подписки.
- Backend ChatGPT-Plus/Codex не поддерживает
temperatureи, возможно,response_format→ не отправляем temperature, JSON-парс делаем всегда сами. Набор моделей зависит от подписки →AI_MODELконфигурируем.
- Backend ChatGPT-Plus/Codex не поддерживает
4.2. Технический долг
- Точный расчёт проскальзывания по тиковой ликвидности Uniswap v3 (сейчас — эвристика на TVL). План: отдельная итерация после MVP.
- Мультисеть для сабграфа (
network → endpointmap). План: когда появятся пулы index на других сетях. - Персистентное хранение истории аналитик (сейчас только Redis-кэш). План: при необходимости истории/аудита.
- Опциональный per-user rate-limit (cooldown) на LLM-эндпоинты (Redis,
429). Вынесен из MVP; основная защита — JWT + кэш.
4.3. Риски
- Рейт-лимиты CoinGecko/GeckoTerminal (keyless). Митигация: кэш + опц.
COINGECKO_API_KEY. - Квоты/лимиты подписки ChatGPT Plus (могут вернуть «usage limit reached»). Митигация: кэш результатов, деградация до фолбэка, мониторинг.
- Нестабильность/недоступность прокси. Митигация: детерминированные фолбэки в обоих эндпоинтах, эндпоинты не 5xx.
- Галлюцинация чисел LLM. Митигация: все числа считаются в коде и передаются готовыми; жёсткое правило «не выдумывать»; пост-валидация.
- Расхождение сети пула и сабграфа. Митигация: валидация
network == default(400), документированное ограничение.
5. Вопросы на дополнительное обсуждение
- Точная модель
AI_MODEL, доступная через CLIProxyAPIPlus на подписке (для дефолта в.env.example). Определяется поGET /v1/modelsна запущенном прокси.- Кому адресовано: заказчик / DevOps
Язык вывода обоих эндпоинтов зафиксирован — русский (решение принято, не требует доп. согласования).
6. План реализации
6.1. Этапы разработки
- Этап 1: Каркас модуля
aiAnalytics(module/controller/dto), регистрация вapp.module.ts, env + Joi. - Этап 2: OpenAI-коннектор (
openai.provider.ts+llm.util) + env → контрольная точка: запросить у пользователя логин в OpenAI (гейтит только живые тесты). - Этап 3: Эндпоинт 1 (market-data.service + market-outlook.service + промпт + altseason) с юнит- и сервис-тестами.
- Этап 4: Экспорт + расширение
UniswapV3GraphService(метаданные токенов/feeTier, уборка console.log); token-data.service; slippage.util. - Этап 5: Эндпоинт 2 (pool-analytics.service + промпт + markdown.util) с тестами (включая 400/404/деградацию).
- Этап 6: e2e-тесты (supertest) + живой smoke-скрипт и runbook; реальная проверка обоих эндпоинтов.
- Этап 7: Документация (Swagger, engineering docs), финальная сверка.
6.2. Критические зависимости
- Запущенный и залогиненный CLIProxyAPIPlus (ChatGPT Plus) — для реальных LLM-запросов.
- Корректно сконфигурированный сабграф Uniswap v3 под сеть пулов index (
UNISWAP_V3_SUBGRAPH_URL). - Доступность CoinGecko / GeckoTerminal.
7. Тестирование
Описано в §3.2 «Тестирование» и «Runbook живого smoke-теста»: юнит + сервисные + e2e (замоканные апстримы) и живой smoke-тест на реальных запросах после логина в ChatGPT Plus.
8. Документация
- API-документация (Swagger) для обоих эндпоинтов.
- Engineering docs: описание модуля
aiAnalyticsи интеграции с CLIProxyAPIPlus. - Runbook по запуску живого smoke-теста (поднятие прокси + логин + выбор модели).
9. Ссылки
- Референс:
zenfi/apps/backend— модулиmarkets,assistant(система-промпт:src/markets/analysis-prompt.ts). - Существующий граф-клиент:
apps/backend/src/liquidity/uniswap-v3-graph.service.ts. - Продукт index:
apps/backend/src/liquidity/liquidity.service.ts(whitelist пулов, партнёрская подпись). - CLIProxyAPIPlus: https://github.com/kaitranntt/CLIProxyAPIPlus, https://help.router-for.me/