# 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 请求增加明确的超时、重试和熔断策略。 - 建立健康检查、关键接口测试和基础监控。