|
|
@@ -1,3 +1,203 @@
|
|
|
# LongArticleAlgServer
|
|
|
|
|
|
-长文算法服务
|
|
|
+面向公众号长文场景的算法服务,提供历史文章查询、候选文章过滤、账号兴趣相关性评分、文章排序、文本向量化和文章爬取入库能力。
|
|
|
+
|
|
|
+服务基于 Quart/ASGI 构建,使用 BGE 计算标题级语义相关性,默认通过 Hypercorn 监听 `6060` 端口。
|
|
|
+
|
|
|
+## 核心能力
|
|
|
+
|
|
|
+- 使用 `BAAI/bge-large-zh-v1.5` 生成中文文本 embedding,并计算余弦相似度。
|
|
|
+- 根据公众号历史高阅读文章构建账号兴趣集合。
|
|
|
+- 支持均值、最大值和阅读量加权的相关性聚合方式。
|
|
|
+- 按历史重复、低质量标题和敏感内容过滤候选文章。
|
|
|
+- 支持多种文章排序策略,并结合语义相关性与历史阅读量排序。
|
|
|
+- 使用 `lili666/text2vec-word2vec-tencent-chinese` 提供分词和词向量测试接口。
|
|
|
+- 调用外部公众号爬虫服务,将文章信息写入 MySQL。
|
|
|
+
|
|
|
+## 技术栈
|
|
|
+
|
|
|
+- Python 3.10+(源码使用 `match/case`)
|
|
|
+- Quart + Hypercorn
|
|
|
+- PyTorch
|
|
|
+- `similarities` / `text2vec`
|
|
|
+- jieba
|
|
|
+- pandas / NumPy
|
|
|
+- aiomysql / MySQL
|
|
|
+- 阿里云日志服务
|
|
|
+
|
|
|
+## 项目结构
|
|
|
+
|
|
|
+```text
|
|
|
+.
|
|
|
+├── alg_app.py # 应用入口、数据库和模型初始化
|
|
|
+├── alg.toml # Hypercorn 配置
|
|
|
+├── routes/
|
|
|
+│ ├── __init__.py # HTTP 路由注册
|
|
|
+│ ├── accountArticleRank.py # 候选文章过滤与排序
|
|
|
+│ ├── accountServer.py # 账号兴趣相关性评分
|
|
|
+│ ├── articleDBServer.py # 公众号文章爬取和入库
|
|
|
+│ ├── nlpServer.py # NLP 功能分发
|
|
|
+│ └── word_2_vec.py # 分词与 Word2Vec 编码
|
|
|
+├── applications/
|
|
|
+│ ├── articleTools.py # 历史文章和账号统计查询
|
|
|
+│ ├── textSimilarity.py # 相似度矩阵及聚合算法
|
|
|
+│ ├── embedding_manager.py # embedding 内存/磁盘缓存
|
|
|
+│ ├── pipeline.py # 重复、质量和安全过滤
|
|
|
+│ ├── asyncMySQL.py # 异步 MySQL 连接池
|
|
|
+│ ├── wxSpider.py # 外部公众号爬虫客户端
|
|
|
+│ ├── aliyunLog.py # 阿里云日志客户端
|
|
|
+│ └── functions/ # 排序调用和标题规则工具
|
|
|
+├── test/ # 手工联调脚本
|
|
|
+├── tools/ # 辅助脚本
|
|
|
+├── Dockerfile
|
|
|
+├── docker-compose.yaml
|
|
|
+└── requirements.txt
|
|
|
+```
|
|
|
+
|
|
|
+## 相关性计算原理
|
|
|
+
|
|
|
+主排序链路使用 `BAAI/bge-large-zh-v1.5`,而不是 Word2Vec。计算过程如下:
|
|
|
+
|
|
|
+```text
|
|
|
+候选标题 ──BGE──> 1024 维语义向量 ─┐
|
|
|
+ ├──> 余弦相似度矩阵 ──> 聚合 ──> 相关性分数
|
|
|
+历史标题 ──BGE──> 1024 维语义向量 ─┘
|
|
|
+```
|
|
|
+
|
|
|
+两个文本向量的余弦相似度为:
|
|
|
+
|
|
|
+```text
|
|
|
+similarity(a, b) = (a · b) / (||a||₂ × ||b||₂)
|
|
|
+```
|
|
|
+
|
|
|
+若有 `n` 个候选标题和 `m` 个历史标题,服务会生成 `n × m` 的相似度矩阵。每个候选标题可通过以下方式得到最终分数:
|
|
|
+
|
|
|
+- `max`:取该候选标题与所有历史标题相似度的最大值。
|
|
|
+- `mean`:取该候选标题与所有历史标题相似度的算术平均值。
|
|
|
+- `avg`:将历史文章阅读量经过 L2 归一化和 softmax 后作为权重,对相似度加权求和。
|
|
|
+
|
|
|
+embedding 由 `EmbeddingManager` 缓存在内存中,并定期持久化到 `cache/embedding_cache.npy` 和对应的 key 文件。缓存只减少重复模型推理,不改变相似度算法。
|
|
|
+
|
|
|
+## 文章排序流程
|
|
|
+
|
|
|
+```text
|
|
|
+候选文章
|
|
|
+ → 过滤历史低质量标题
|
|
|
+ → 过滤历史已发布的相似标题
|
|
|
+ → 调用敏感内容服务
|
|
|
+ → 查询账号历史高表现文章
|
|
|
+ → 计算 BGE 语义相关性
|
|
|
+ → 按策略排序
|
|
|
+ → 标题去重
|
|
|
+ → 截取 publishNum 篇文章
|
|
|
+```
|
|
|
+
|
|
|
+当前策略:
|
|
|
+
|
|
|
+- `ArticleRankV1`:按 `producePlanName` 将文章分为 `【1】`、`【2】` 和其他三组;部分分组按相关性排序,`【2】` 分组按阅读量排序,最后合并和去重。
|
|
|
+- `ArticleRankV2`:统一按相关性降序、`crawlerViewCount` 降序排序。
|
|
|
+- `ArticleRankV3`、`ArticleRankV4`、`ArticleRankV5`:当前复用 `ArticleRankV1` 的实现。
|
|
|
+
|
|
|
+## HTTP API
|
|
|
+
|
|
|
+| 方法 | 路径 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `GET` | `/healthCheck` | 服务连通性检查 |
|
|
|
+| `POST` | `/embed` | jieba 分词和 Word2Vec 向量化 |
|
|
|
+| `POST` | `/nlp` | 文本相似度及相似度矩阵聚合 |
|
|
|
+| `POST` | `/score_list` | 计算候选标题与账号兴趣的相关性 |
|
|
|
+| `POST` | `/title_list` | 查询公众号历史标题 |
|
|
|
+| `POST` | `/articleRank` | 过滤并排序待发布文章 |
|
|
|
+| `POST` | `/article_crawler` | 抓取公众号文章并写入 MySQL |
|
|
|
+
|
|
|
+### NLP 相似度示例
|
|
|
+
|
|
|
+```bash
|
|
|
+curl -X POST http://localhost:6060/nlp \
|
|
|
+ -H 'Content-Type: application/json' \
|
|
|
+ -d '{
|
|
|
+ "function": "similarities",
|
|
|
+ "data": {
|
|
|
+ "text_a": ["新能源汽车销量持续增长"],
|
|
|
+ "text_b": ["电动车市场快速扩张"]
|
|
|
+ }
|
|
|
+ }'
|
|
|
+```
|
|
|
+
|
|
|
+`function` 支持:
|
|
|
+
|
|
|
+- `similarities`
|
|
|
+- `similarities_cross`
|
|
|
+- `similarities_cross_max`
|
|
|
+- `similarities_cross_mean`
|
|
|
+- `similarities_cross_avg`
|
|
|
+
|
|
|
+## 本地启动
|
|
|
+
|
|
|
+### 前置条件
|
|
|
+
|
|
|
+启动过程不是纯本地运行,当前实现要求:
|
|
|
+
|
|
|
+1. 能够访问项目配置的 MySQL 实例。
|
|
|
+2. 首次启动时能够获取两个模型,或本地已有对应模型缓存。
|
|
|
+3. 调用文章过滤、排序或爬取接口时,能够访问相应的内部服务。
|
|
|
+4. 有足够内存或显存加载 BGE 和 Word2Vec 模型。
|
|
|
+
|
|
|
+### 使用 Python 启动
|
|
|
+
|
|
|
+```bash
|
|
|
+python -m venv .venv
|
|
|
+source .venv/bin/activate
|
|
|
+pip install -r requirements.txt
|
|
|
+hypercorn alg_app:app --config alg.toml
|
|
|
+```
|
|
|
+
|
|
|
+健康检查:
|
|
|
+
|
|
|
+```bash
|
|
|
+curl http://localhost:6060/healthCheck
|
|
|
+```
|
|
|
+
|
|
|
+### 使用 Docker Compose 启动
|
|
|
+
|
|
|
+```bash
|
|
|
+docker compose up --build
|
|
|
+```
|
|
|
+
|
|
|
+`alg.toml` 当前配置 `3` 个 worker。每个 worker 都会分别加载模型,需要根据实际内存或显存容量调整 worker 数量。
|
|
|
+
|
|
|
+## 测试现状
|
|
|
+
|
|
|
+`test/` 目录当前主要存放连接固定环境的手工联调脚本,不是隔离外部依赖的自动化测试套件。运行这些脚本可能访问数据库或内部 HTTP 服务,执行前应先检查目标地址和请求数据。
|
|
|
+
|
|
|
+建议优先补充以下自动化测试:
|
|
|
+
|
|
|
+- `/nlp` 的相似度矩阵和聚合算法单元测试。
|
|
|
+- `/score_list` 的数据库查询与账号兴趣计算契约测试。
|
|
|
+- `/articleRank` 的过滤、分组、去重和排序测试。
|
|
|
+- 使用 mock 隔离 MySQL、模型下载、敏感词服务和公众号爬虫服务。
|
|
|
+
|
|
|
+## 已知限制与安全提示
|
|
|
+
|
|
|
+- 当前源码包含硬编码的数据库和云日志配置。投入新环境前应轮换现有凭证,并迁移到环境变量或密钥管理服务。
|
|
|
+- 部分 SQL 使用字符串拼接构造,接收外部输入时存在 SQL 注入风险,应改为参数化查询。
|
|
|
+- Quart 请求链路中仍存在同步 `requests` 调用,会阻塞 event loop。
|
|
|
+- 排序流程通过 HTTP 回调本服务的 `/title_list` 和 `/score_list`,增加了延迟和故障传播范围。
|
|
|
+- 当前代码中的账号标识存在 `accountName`、`account_nickname_list`、`ghId`、`gh_id_list` 等多套命名,调用接口前应核对契约。
|
|
|
+- 当前 checkout 中部分路由参数和底层方法签名不一致,完整联调前需要先完成接口对齐。
|
|
|
+
|
|
|
+## 部署
|
|
|
+
|
|
|
+容器入口为:
|
|
|
+
|
|
|
+```bash
|
|
|
+hypercorn alg_app:app --config alg.toml
|
|
|
+```
|
|
|
+
|
|
|
+默认监听 `0.0.0.0:6060`。生产部署前应至少完成:
|
|
|
+
|
|
|
+- 外部化数据库、日志、模型和下游服务配置。
|
|
|
+- 移除或轮换源码中的历史凭证。
|
|
|
+- 确认 worker 数量与模型资源占用匹配。
|
|
|
+- 为所有外部 HTTP 请求增加明确的超时、重试和熔断策略。
|
|
|
+- 建立健康检查、关键接口测试和基础监控。
|