一个**双域单体仓库(dual-domain monorepo)**的加密货币新闻分析系统,在同一代码库和共享 PostgreSQL/pgvector 数据库中同时运行两个限界上下文:News(RSS/X/REST 新闻抓取、LLM 分析、结构化报告)和 Intelligence(Telegram/V2EX 群组消息收集、AI 主题研究管线)。私有 ingestion 服务负责抓取、采集与主题研究调度,公网 analysis 服务负责 HTTP API、Telegram 命令、LLM 分析与结果查询。Phase 1 已完成服务拆分。
crypto-news-analysis:公网服务,运行analysis-service,提供/health、/analyze、Telegram 命令监听crypto-news-ingestion:私有服务,运行ingestion,负责 scheduler 驱动的采集、去重、入库- PostgreSQL + pgvector:共享数据库,承载内容数据、
analysis_jobs、ingestion_jobs、数据源配置
旧版 API server 模式不再是推荐的生产模式;它只作为兼容别名映射到 analysis-service。
如果你要通过 HTTP API 调用新闻分析接口,或你是一个需要自动调用接口的 AI,请先阅读 AI Analyze API Guide。该文档记录了当前有效的 POST /analyze -> 轮询 -> 取结果 异步契约。
- 🔄 多源数据收集: 支持 RSS 订阅、X/Twitter 内容爬取和 REST API 数据源
- 🤖 智能分析: 使用大语言模型进行内容分析和分类(Kimi / Grok / OpenCode Go),支持大户动向、利率事件、监管政策、真相揭露等多种分类
- 📊 结构化报告: 生成 Markdown 格式的分析报告,通过 Telegram Bot 自动发送
- 🔎 统一语义搜索: 跨域检索 News
content_items和 Intelligenceraw_intelligence_items,通过UnifiedSemanticSearchHitDTO 返回统一结果(含source_type、source_breakdown等字段),底层使用 UNION ALL + pgvector HNSW 索引。支持POST /semantic-search异步检索与/semantic_searchTelegram 命令 - 🔧 数据库优先的数据源管理: 首次启动从
config.jsonc导入,运行时通过数据库管理,支持 REST API 和 Telegram 命令操作
作为 News 的同行域,Intelligence 独立运行一套 AI 主题研究管线,而非 Telegram 的附属功能:
- 🧠 AI 主题研究管线: 基于 LLM 的持续研究,支持创建/修订/确认主题 → 每日定时研究 → 研究成果合并与归档的完整生命周期
- 📥 群组消息收集: 从 Telegram 群组和 V2EX 论坛采集原始消息(RawIntelligenceItem),与新闻域的 ContentItem 完全分离
- 🌐 独立 API 和命令面: 提供
/intelligence/*REST 接口和/topic_*Telegram 命令 - 🔗 主题数据源关联: 可选择关联 Intelligence 用途的数据源到研究主题,支持查看、替换、添加、移除操作
- 🔁 Split-service 运行面: 仅保留
analysis-service、api-only、ingestion三种运行模式 - 🛡️ 容错设计: 完善的错误处理和恢复机制
- ☁️ 云端部署: 支持部署到 Railway 平台
- 🌐 HTTP API: 支持 Bearer Token 鉴权的异步分析接口(
POST /analyze创建任务,轮询获取结果) - 🤖 Telegram 交互: 支持
/news_analyze [hours]、/news_market、/status等命令
如果你要通过 HTTP API 调用新闻分析接口,或你是一个需要自动调用接口的 AI,请先阅读 AI Analyze API Guide。该文档包含最新的请求体要求、鉴权方式、异步轮询流程和生产环境验证结果。
crypto_news_analyzer/
├── __init__.py
├── main.py # 运行模式入口(analysis-service / api-only / ingestion)
├── api_server.py # FastAPI 异步分析 API
├── execution_coordinator.py # 分析、摄取与调度协调器
├── models.py # 共享数据模型
├── config/
│ └── manager.py # 配置加载与归一化
├── domain/
│ ├── models.py # 领域模型
│ └── repositories.py # 仓储接口
├── crawlers/
│ ├── rss_crawler.py # RSS 爬取器
│ └── x_crawler.py # X/Twitter 爬取器
├── intelligence/ # 情报主题研究管线(同行域)
│ ├── pipeline.py # 采集与主题研究调度
│ ├── topics.py # 主题 CRUD 管理
│ ├── topic_prompts.py # AI 提示词生成与版本管理
│ ├── topic_research.py # 每日定时主题研究
│ ├── topic_findings.py # 研究发现管理
│ └── merge.py # 研究成果合并
├── analyzers/
│ ├── llm_analyzer.py # LLM 分析器
│ └── prompt_manager.py # 提示词管理器
├── storage/
│ ├── repositories.py # SQLite/Postgres 仓储实现
│ └── data_manager.py # 数据管理器
├── reporters/
│ └── telegram_command_handler.py # Telegram 命令处理
└── utils/
├── logging.py # 日志管理
└── errors.py # 错误处理
本项目使用 uv。推荐 Python 3.9+。
uv pip install -e ".[dev]"cp .env.template .env至少需要根据运行模式配置:
# 共享数据库(当前默认后端为 postgres)
DATABASE_URL=postgresql://postgres:password@host:5432/railway
# LLM Provider 凭证(analysis-service / api-only 必需)
# 使用 provider-specific 环境变量而非通用 LLM_API_KEY
KIMI_API_KEY=your_kimi_api_key_here
GROK_API_KEY=your_grok_api_key_here
OPENCODE_API_KEY=your_opencode_api_key_here
# API 鉴权(启用 analysis-service / api-only 时必需)
API_KEY=your_api_key
# Telegram 配置(analysis-service 可选)
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_CHANNEL_ID=-1001234567890
# Telegram 授权用户(支持用户ID和用户名)
# 多个用户用逗号分隔,可以混合使用用户ID和@username格式
# 示例: 123456789,@user1,987654321,@user2
TELEGRAM_AUTHORIZED_USERS=your_user_id_here
# X/Twitter 认证 (可选)
X_CT0=your_X_CT0
X_AUTH_TOKEN=your_X_AUTH_TOKEN- 在 Telegram 中搜索
@userinfobot - 发送
/start命令 - Bot 会返回你的用户 ID
系统支持两种格式配置授权用户:
- 用户 ID(数字): 直接使用 Telegram 用户 ID,例如
123456789 - 用户名(@开头): 使用 Telegram 用户名,例如
@username
可以混合使用两种格式,用逗号分隔:
# 仅用户ID
TELEGRAM_AUTHORIZED_USERS=123456789,987654321
# 仅用户名
TELEGRAM_AUTHORIZED_USERS=@user1,@user2,@user3
# 混合格式(推荐)
TELEGRAM_AUTHORIZED_USERS=5844680524,@wingperp,@mcfangpy,@Huazero,@long0short注意事项:
- 使用用户名时,bot 必须先与该用户互动过,或者用户有公开的 profile
- 如果用户名解析失败,系统会记录警告并跳过该用户名
- 建议对关键用户使用用户 ID 作为备份
- 所有授权用户都有相同的权限,可以执行所有可用命令(/news_analyze, /status, /help 等)
模型配置在 config.jsonc 的 llm_config 字段中定义。环境变量仅用于提供 provider 的 API 密钥(KIMI_API_KEY、GROK_API_KEY)。
llm_config 结构:
{
"llm_config": {
"model": {
"provider": "kimi",
"name": "kimi-k2.5",
"options": {"thinking_level": "medium"}
},
"fallback_models": [
{"provider": "grok", "name": "grok-4-1-fast-reasoning", "options": {}}
],
"market_model": {
"provider": "grok",
"name": "grok-4-1-fast-reasoning",
"options": {}
},
"temperature": 0.5,
"max_tokens": 4000,
"batch_size": 10
}
}支持的 Provider 和模型:
- kimi (环境变量:
KIMI_API_KEY)- kimi-k2.5, kimi-k2-turbo-preview, kimi-k2-thinking-turbo
- grok (环境变量:
GROK_API_KEY)- grok-4-1-fast-reasoning, grok-4-1-fast-non-reasoning, grok-4.20-reasoning, grok-4.20-non-reasoning
- opencode-go (环境变量:
OPENCODE_API_KEY)- glm-5.1, kimi-k2.5, mimo-v2-pro
- 注意: OpenCode Go 模型不支持
market_model,请使用 Kimi 或 Grok 作为市场快照模型 - Phase 1 限制: 仅支持这 3 个固定模型;
glm-5、mimo-v2-omni、minimax-m2.5、minimax-m2.7以及thinking_level/ search / responses API 等能力均不支持
配置字段说明:
model: 主分析模型配置(必需)fallback_models: 备用模型列表,主模型失败时按顺序尝试(必需)market_model: 市场快照专用模型(必需,建议使用 grok)options.thinking_level: 可选,取值:disabled, low, medium, high, xhigh
支持三种常驻运行模式:
analysis-service:启动公网分析服务,提供/health、/analyze接口,并启用 Telegram/news_analyzeapi-only:仅启动 FastAPI 分析接口,不启用 Telegram 命令监听ingestion:启动私有摄取循环,按EXECUTION_INTERVAL周期抓取内容
# 公网分析服务(默认监听 0.0.0.0:8080)
uv run python -m crypto_news_analyzer.main --mode analysis-service
# 隔离 API 服务(默认监听 0.0.0.0:8080)
uv run python -m crypto_news_analyzer.main --mode api-only
# 私有摄取服务
uv run python -m crypto_news_analyzer.main --mode ingestion维护说明:migrate-postgres 是 docker-entrypoint.sh 提供的一次性 PostgreSQL 迁移入口,仅用于部署/维护场景,不属于 crypto_news_analyzer.main 的常驻运行模式列表。
可选 API 服务环境变量:
/app/docker-entrypoint.sh migrate-postgres更多说明见 migrations/postgresql/README.md。
uv run pytest tests/
uv run mypy crypto_news_analyzer/
uv run flake8 crypto_news_analyzer/系统支持通过 Telegram Bot 命令进行交互式控制:
/news_analyze [hours]- 按时间窗口分析历史消息(不传参数时按“距上次成功分析时间”自动估算,最大24小时)/semantic_search <hours> <topic>- 统一语义搜索(跨 News + Intelligence 两域,返回source_breakdown)/news_market- 获取当前市场快照/status- 查询系统运行状态/news_tokens- 查看token使用统计/help- 显示帮助信息
-
/topic_create <theme>- 从主题创建研究草稿(AI生成提示词) -
/topic_revise <topic_id> <feedback>- 修订主题提示词 -
/topic_set_prompt <topic_id> <prompt>- 手动设置主题提示词 -
/topic_confirm <topic_id>- 确认并激活主题 -
/topic_list- 查看主题列表 -
/topic_findings <topic_id>- 查看主题研究成果 -
/topic_prompt <topic_id>- 查看主题提示词 -
/topic_merge <topic_id>- 合并主题研究成果 -
/topic_archive <topic_id>- 归档主题 -
/topic_logs <topic_id>- 查看主题研究运行日志 -
/topic_sources <topic_id>- 查看主题数据源关联(空关联时跳过定时研究) -
/topic_sources_set <topic_id> <ds_id...|none>- 替换主题数据源关联(使用none清空所有关联) -
/topic_sources_add <topic_id> <ds_id...>- 幂等添加主题数据源关联 -
/topic_sources_remove <topic_id> <ds_id...>- 幂等移除主题数据源关联
主题与数据源的关联遵循以下行为:
- 新建主题默认空关联:通过
/topic_create或POST /intelligence/topics创建的主题在激活前不关联任何数据源。激活后如需关联,需显式调用/topic_sources_add或POST /intelligence/topics/{id}/datasources/{datasource_id}。 - 空关联跳过定时研究:若主题已激活但未关联任何数据源,每日定时研究调度器会跳过该主题,不消耗 LLM token。
- 关联变更不自动回填:添加或移除数据源关联不会影响已完成的研究运行记录;变更仅从下一次定时研究周期开始生效。
- 仅可关联 Intelligence 用途的数据源:News 用途的数据源无法关联到 Intelligence 主题。创建数据源时请使用
"purpose":"intelligence"。
详细 API 接口见下方 HTTP API 章节的「情报主题 API」部分。
系统支持多个授权用户在私聊和群组中与bot交互:
- 私聊授权: 授权用户可以在与 bot 的私聊中执行命令
- 群组授权: 授权用户可以在群组中执行命令(基于用户 ID,而非群组 ID)
- 统一权限: 所有授权用户拥有相同的权限,可以执行所有命令
- 默认频道报告: 未显式指定目标聊天时,发送到
TELEGRAM_CHANNEL_ID指定的频道 - 手动分析报告: 由 Telegram
/news_analyze触发时,发送到用户触发命令的聊天窗口(私聊或群组)
在 .env 文件中配置 TELEGRAM_AUTHORIZED_USERS,支持两种格式:
# 支持用户ID和用户名混合格式
# 格式1: 用户ID(数字)
# 格式2: 用户名(@开头)
# 多个用户用逗号分隔
# 示例1: 仅用户ID
TELEGRAM_AUTHORIZED_USERS=123456789,987654321
# 示例2: 仅用户名
TELEGRAM_AUTHORIZED_USERS=@user1,@user2,@user3
# 示例3: 混合格式(推荐)
TELEGRAM_AUTHORIZED_USERS=5844680524,@wingperp,@mcfangpy,@Huazero,@long0short为防止滥用,系统实施了速率限制:
- 每小时最多执行命令次数(默认:120次)
- 命令冷却时间(默认:1秒)
可在 config.jsonc 的 telegram_commands.command_rate_limit 中调整。
调用 POST /analyze 前,建议先阅读 AI Analyze API Guide。
对 AI 代理尤其重要:该文档说明了真实必填参数、错误响应样例,以及正确的 POST /analyze -> 轮询状态 -> 获取结果 工作流。
- 使用
Authorization: Bearer <API_KEY> API_KEY来自环境变量
GET /healthPOST /analyzeGET /analyze/{job_id}GET /analyze/{job_id}/resultPOST /semantic-search— 统一语义搜索,跨域检索content_items和raw_intelligence_items,返回source_breakdown(含news.matched_count、news.retained_count、intelligence.matched_count、intelligence.retained_count)GET /semantic-search/{job_id}GET /semantic-search/{job_id}/result
POST /intelligence/topics- 创建主题草稿POST /intelligence/topics/{id}/revise- 修订提示词PUT /intelligence/topics/{id}/prompt- 手动设置提示词POST /intelligence/topics/{id}/confirm- 确认激活GET /intelligence/topics- 列出主题GET /intelligence/topics/{id}- 主题详情(含提示词版本和研究成果)GET /intelligence/topics/{id}/datasources- 查看主题数据源关联列表PUT /intelligence/topics/{id}/datasources- 替换主题数据源关联(请求体:{"datasource_ids": ["ds-xxx", "ds-yyy"]})POST /intelligence/topics/{id}/datasources/{datasource_id}- 幂等添加主题数据源关联(路径参数)DELETE /intelligence/topics/{id}/datasources/{datasource_id}- 幂等移除主题数据源关联(路径参数)
curl -X POST "http://localhost:8080/analyze" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"hours":24,"user_id":"operator_01"}'请求约束:
hours > 0user_id仅允许字母、数字、_、-
成功时返回 202 Accepted,并提供:
job_idstatusstatus_urlresult_urltime_window_hours
状态流转:queued → running → completed / failed
完整部署文档见 docs/RAILWAY_DEPLOYMENT.md。
当前推荐拓扑:
- 创建一个私有 PostgreSQL 服务
- 从同一仓库部署两个应用服务:
crypto-news-analysis、crypto-news-ingestion - 两个服务共用同一个
DATABASE_URL - 仅为
crypto-news-analysis绑定公网域名 - 不要为
crypto-news-ingestion暴露公网入口
系统采用数据库优先的数据源管理模式。首次启动时,若数据源表为空,系统会从 config.jsonc 自动导入配置。此后运行时,所有数据源读写均通过数据库进行,修改 config.jsonc 不会影响运行时行为。
- 每个数据源最多 16 个唯一标签
- 单个标签最长 32 个字符
- 标签自动转为小写并去重
所有数据源接口需 Bearer 认证 (Authorization: Bearer <API_KEY>):
POST /datasources- 创建数据源(成功返回 201,重复返回 409)GET /datasources- 列出所有数据源(按类型和名称排序)DELETE /datasources/{id}- 删除指定数据源(成功返回 204,不存在返回 404,正在使用返回 409)
列表接口返回安全的摘要信息,敏感字段(如 rest_api 的认证信息)会被脱敏。
授权用户可通过 Telegram Bot 管理数据源:
/datasource_list- 查看已配置的数据源列表/datasource_add {json}- 添加数据源,参数为 JSON 对象/datasource_delete <id>- 删除指定 ID 的数据源
rest_api 数据源通过 Telegram 添加的限制:
Telegram 命令禁止内联提交认证信息。rest_api 的 config_payload 中不得包含 headers、params 或 auth 字段的敏感令牌。请改用服务端环境变量配置认证。
/datasource_add {"source_type":"rss","tags":["markets","btc"],"config_payload":{"name":"CoinDesk","url":"https://www.coindesk.com/rss","description":"Industry news"}}
/datasource_add {"source_type":"x","tags":["whales"],"config_payload":{"name":"Whale Watch","url":"https://x.com/i/lists/1234567890","type":"list"}}
/datasource_add {"source_type":"rest_api","tags":["news"],"config_payload":{"name":"News API","endpoint":"https://api.example.com/news","method":"GET","headers":{},"params":{},"response_mapping":{"title_field":"title","content_field":"body","url_field":"url","time_field":"published_at"}}}
MIT License