# 文献阅读价值评分系统方案 ## 一、定位与目标 **定位:** 成为肿瘤学文献领域的权威价值标尺——每篇文献一个分,用户信任这个分来做阅读决策。评分的价值不在于一个数字,而在于它每天帮医生决定"哪篇值得先读"。 **目标:** 评分直接驱动每日推送排序。用户每天早上打开 Feed,看到的第一篇不是最新的一篇,而是今天最重要、最值得读的一篇。 **核心理念:** 医生不需要从 60 篇里自行筛选。排序就是筛选,评分就是排序的依据。 --- ## 二、分层定价 | 功能 | 免费 | 专业版 | 团队版 | |---|---|---|---| | 系统评分(整数分+排序) | ✅ | ✅ | ✅ | | Feed 按评分排序 | ✅ | ✅ | ✅ | | 评分标签(文献卡片上) | ✅ | ✅ | ✅ | | 5 维明细(hover 卡片) | ❌ | ✅ | ✅ | | 雷达图展示(详情页) | ❌ | ✅ | ✅ | | 预设方案(临床/科研/综合) | ❌ | ✅ | ✅ | | 自定义权重 | ❌ | ❌ | ✅(管理员设) | | 团队共用评分方案 | ❌ | ❌ | ✅ | --- ## 三、评分算法 ### 3.1 五维度模型 每个维度的满分即体现其权重——证据强度 30 分天然就是影响力 10 分的 3 倍重要,无需额外权重系数。 | 维度 | 满分 | 数据来源 | 计算方式 | |---|---|---|---| | **证据强度** | 30 | `study_design.sub` + `rct_detection` | 研究类型映射表(下详) | | **期刊信誉** | 25 | `journal_issn` → `global_journals.tier` | Tier 1-4 对应分值 | | **时效性** | 15 | `pub_date` | 分段基准,同年度内比较 | | **临床相关性** | 20 | PICO + trial_reg + AI 判断 + 其他信号 | 多个信号叠加,无数据时给基础分 10 | | **学术影响力** | 10 | `cited_by_count` | 同一年发表的文献之间按被引分位排名 | | **合计** | **100** | | | ### 3.2 各维度详细规则 #### 证据强度(0-30 分) | 研究类型 | 分值 | 说明 | |---|---|---| | Practice Guideline / Consensus | 30 | 直接影响临床决策 | | Meta-Analysis | 27 | 综合证据最高形式 | | Systematic Review | 27 | | | RCT Phase III | 28 | 随机对照金标准 | | RCT(未分期) | 26 | | | RCT Phase II | 24 | 探索性疗效证据 | | RCT Phase I | 22 | | | Non-Randomized / Single-Arm | 20 | | | Cohort / Case-Control | 18 | 观察性研究 | | Cross-Sectional | 14 | | | Narrative Review | 12 | | | Case Report / Case Series | 8 | | | Editorial / Letter / Comment | 2(×20%折扣) | 排除类型,打 20% | | 无分类 | 5 | 默认值 | 多条 pub_type 冲突时取最高分。RCT Detection 模块检测到 RCT 但未标注时补偿 +5。 #### 期刊信誉(0-25 分) | 等级 | 分值 | 期刊示例 | |---|---|---| | Tier 1 | 25 | NEJM, Lancet, JAMA, BMJ | | Tier 2 | 22 | JCO, Lancet Oncol, JAMA Oncol, Cancer Discov, Nat Med | | Tier 3 | 18 | Cancer Res, Ann Oncol, Clin Cancer Res, EJC... | | Tier 4 | 12 | 其他同行评议期刊 | | 未识别 | 8 | 无 ISSN 或未收录 | #### 时效性(0-15 分) 按发表年份分段,**仅在同一年份内比较**。即 2026 年的文献之间经其他维度拉开差距,不因年份新旧系统性吃亏。 | 发表年份 | 基准分 | |---|---| | 当年 | 15 | | 前 1 年 | 13 | | 前 2 年 | 11 | | 前 3 年 | 9 | | 前 4 年 | 7 | | 前 5 年 | 5 | | 6-10 年 | 3 | | >10 年或无日期 | 1 | > 设计说明:同一年发表的文献之间,时效性的影响是相同的。真正体现区分度的是**被引次数分位**(学术影响力)、**研究类型**(证据强度)等维度。 #### 临床相关性(0-20 分) 采用**信号叠加**模式,逐步丰富: | 信号 | 加分 | 当前覆盖率 | |---|---|---| | 有 `pico.population` | +4 | 低(仅 Meta 等已处理文献) | | 有 `pico.intervention` | +4 | 低 | | 有 `pico.sample_size` > 100 | +3 | 低 | | 有 `pico.outcome` | +2 | 低 | | 有 `trial_reg`(NCT/EudraCT) | +3 | 中 | | `pub_types` 含 Guideline/RCT | +2 | 高 | | 有 PMC 全文(`is_oa`) | +1 | 中 | | 有 AI 摘要(`ai_summary`) | +1 | 中 | | AI 临床相关性判断(第二阶段) | 覆盖基础分 | 仅高分文献 | | **无任何信号** | **基础分 10** | 新文献默认 | > 设计说明:初期数据不足时,大部分文献走基础分 10,区分度由其他 4 个维度提供。后续数据工程推进后,这个维度自然产生区分度。进入 AI 评估阶段的高分文献,临床相关性由 AI 重新评估并覆盖基础分。 #### 学术影响力(0-10 分) 基于 `cited_by_count`,只在**同一年发表的文献之间**排名: | 分位 | 分值 | |---|---| | 同年前 10% | 10 | | 同年前 25% | 8 | | 同年前 50% | 6 | | 其他 | 3 | | `cited_by_count` = 0 | 1(刚发表,尚未被引) | ### 3.3 打折因子 | 条件 | 处理 | |---|---| | Editorial / Letter / Comment | 证据强度分 ×0.2 | | 撤稿(`retracted = true`) | 总分 ×0.1,上限 5 | | 阴性结果 | 不扣分,标注 `is_negative` | ### 3.4 计算公式 ``` 总分 = 证据强度得分 + 期刊信誉得分 + 时效性得分 + 临床相关性得分 + 学术影响力得分 满分 = 30 + 25 + 15 + 20 + 10 = 100 ``` --- ## 四、两阶段评分流水线 ### 4.1 设计原则 规则分提供**稳定基础**,AI 分提供**增量信号**。AI 挂了,规则分仍然能跑。 **只对高分文献跑 AI:** 规则分 ≥60 的文献才进 AI 评估阶段。每日新文献 200-300 篇,规则筛选后约 30-50 篇进入 AI 阶段,token 成本 ≈ 15K tokens/天 ≈ 0.2 元/天。 ### 4.2 流水线流程 ``` 每日新文献 200-300 篇 │ ▼ ┌──────────────────────┐ │ 第一阶段:规则分 │ ← 5 维规则打分,零成本 │ (evidence + journal │ │ + recency + clin │ │ + impact) │ └──────────┬───────────┘ │ ▼ 规则分 ≥ 60?──── 否 ──→ 存储规则分,结束 │ 是 ▼ ┌──────────────────────┐ │ 第二阶段:AI 评估 │ ← DeepSeek,仅高分文献 │ │ │ ├─ 临床相关性修正 │ ← 覆盖规则分的临床维度 │ ├─ landmark 标记 │ ← +5 bonus │ ├─ 一句话推荐理由 │ ← 展示在 Feed 卡片上 │ └─ 研究要点摘要 │ ← MDT/汇报可直接使用 │ │ └──────────┬───────────┘ │ ▼ 合并为 reading_value ``` ### 4.3 AI 评估内容 对于每条规则分 ≥60 的文献,调用 DeepSeek 一次,输入标题 + 摘要(约 300 tokens),输出: ```json { "clinical_relevance": 16, "clinical_reason": "III期RCT,含PFS/OS数据", "is_landmark": true, "landmark_reason": "首个针对EGFR Exon20ins的一线III期数据", "landmark_bonus": 5, "one_liner": "首个对比化疗的III期研究,mPFS 9.2 vs 5.8mo,可能改变一线标准", "key_points": "人群:EGFR Exon20ins一线NSCLC(n=423)\n干预:Amivantamab + 化疗 vs 化疗\n结果:mPFS 9.2 vs 5.8mo (HR=0.58)" } ``` | 字段 | 用途 | |---|---| | `clinical_relevance` | 覆盖规则分的临床相关性基础分(0-20) | | `is_landmark` | 是否为 landmark 研究,是则加 `landmark_bonus` | | `one_liner` | 展示在 Feed 卡片上,用户直接看到理由 | | `key_points` | 结构化要点,可用于 MDT 摘要、导出 | ### 4.4 最终分值计算 ``` 最终分 = 规则 5 维总分(规则分 mode:临床相关性维使用 AI.clinical_relevance 覆盖基础分) + (is_landmark ? landmark_bonus : 0) 例如: 规则分 = evi(28) + jnl(22) + rec(12) + clin_base(10) + imp(4) = 76 AI 修正临床分为 16(覆盖基础 10) is_landmark = true → +5 最终分 = (76 - 10 + 16) + 5 = 87 ``` ### 4.5 边缘情况:阈值外的重要文献 Tier 4 期刊上的 breakthrough 研究,规则分可能不到 60(期刊分低)。设一个**缓冲阈值** 50-59 之间的文献进入 AI 做一次快速筛查: ``` 规则分 50-59?── 是 ──→ AI 快速筛查(只判断"是否重要") │ │ │ 重要?── 是 ──→ 进入完整 AI 评估 │ │ │ 否 ──→ 存储规则分,结束 │ 否(<50) │ ▼ 存储规则分,结束 ``` ### 4.6 AI 产出存储 AI 产出缓存在 `reading_value` 中: ```json { "score": 87, "version": 2, "dims": { "evidence": 28, "journal": 22, "recency": 12, "clinical": 16, "impact": 4 }, "ai": { "clinical_relevance": 16, "is_landmark": true, "bonus": 5, "one_liner": "首个对比化疗的III期研究,mPFS 9.2 vs 5.8mo", "key_points": "人群:EGFR Exon20ins一线NSCLC..." } } ``` --- ## 五、数据存储 ### 5.1 GlobalLiterature 新增字段 ```python reading_value: Mapped[dict | None] = mapped_column(JSON) ``` 免费版存储: ```json {"score": 82, "version": 1} ``` 专业版/团队版存储(含 5 维明细): ```json { "score": 82, "version": 1, "dims": { "evidence": 28, "journal": 22, "recency": 12, "clinical": 16, "impact": 4 } } ``` **为什么用 JSON 而非整数字段?** 1. **可扩展性**——后期加维度不减字段,老数据兼容 2. **专业版直接展示**——dimensions 明细无需额外查询 3. **版本控制**——score 旁带 version,算法更新时可区分新旧 ### 5.2 索引 ```sql CREATE INDEX ix_gl_reading_value_score ON global_literature(((reading_value->>'score')::int) DESC) WHERE reading_value IS NOT NULL; ``` --- ## 六、计算时机 ### 6.1 全量回算(仅上线时跑一次) ```python scripts/compute_reading_values.py ``` 扫描全库(或 `reading_value IS NULL` 的记录),一次性打分写入。 ### 6.2 每日增量 每条文献入库时,在 `_process_article()` 末尾附带计算一次: ```python # pubmed_api.py _process_article() 末尾 lit.reading_value = compute_reading_value(lit) # 如果规则分 ≥60,异步触发 AI 评估(不阻塞入库) if (lit.reading_value or {}).get("score", 0) >= 60: await schedule_ai_evaluation(lit.id) ``` ### 6.3 脚本版本 ```bash # 全量重算 python scripts/compute_reading_values.py # 指定文献重算 python scripts/compute_reading_values.py --pmids 12345678,23456789 ``` ### 6.4 算法版本升级 `reading_value.version` 字段用于版本标识。新版本上线时用脚本重算所有旧版本数据。 --- ## 七、Feed 引擎整合 ### 7.1 当前流程 ``` 文献入库 → 标签匹配 → UserFeed (priority: must_read/recommended/related) → Feed 查询:先按 priority 分组,组内按 created_at 倒序 ``` ### 7.2 改动方案 **保留 priority 三档结构**——must_read / recommended / related 解决"用户订阅场景",评分解决"同一场景内哪篇更重要",两个维度不冲突。 **UserFeed 表新增字段:** ```python reading_score: Mapped[int | None] = mapped_column(Integer, default=0) ``` 在 `batch_generate_feeds()` 中,从 `GlobalLiterature.reading_value` 取出 score 写入 `UserFeed.reading_score`。 **Feed 查询改为:** ```python order_by(UserFeed.priority, UserFeed.reading_score.desc().nullslast()) ``` 用户看到的 Feed: ``` must_read ────────────── [92] 肺癌新辅助III期... ← 同must_read内按评分倒序 [88] EGFR新药I期结果... [75] 肺癌免疫微环境综述... recommended ──────────── [80] 胃癌腹腔镜对比... [72] 食管癌放疗新方案... ``` ### 7.3 个性化排序(团队版) 团队版自定义权重不落库,查询时**纯内存实时算**: ```python for feed in user_feeds: dims = (feed.literature.reading_value or {}).get("dims", {}) feed._user_score = sum( dims.get(dim, 0) * weights.get(dim, 0) / max_score[dim] for dim in ALL_DIMS ) ``` N 篇文献 × 5 次乘加 = 毫秒级,对服务器接近零压力。 --- ## 八、前端展示 ### 8.1 LiteratureCard(免费版) ``` [Oncotarget] Title... 期刊信誉: tier2 阅读价值 82 ▲ ``` - 分数在卡片右下角/右上角 - 颜色梯度:≥85 绿色,70-84 蓝色,50-69 灰色,<50 不显示 - Feed 默认按评分倒序排列 - 若该文献有 AI 产出(`one_liner`),在标题下方显示一行推荐理由 ### 8.2 LiteratureCard(专业版 hover) ``` ┌──────────────────────────┐ │ 阅读价值 82/100 │ │ │ │ 证据强度 ██████████░ 28/30 │ │ 期刊信誉 ████████░░ 22/25 │ │ 时效性 ████████░░ 12/15 │ │ 临床相关 ██████░░░░ 16/20 │ │ 学术影响 ██░░░░░░░░ 4/10 │ │ │ │ 当前方案: 临床优先 │ │ │ │ 💡 首个对比化疗的III期 │ │ 研究,mPFS 9.2 vs 5.8mo│ └──────────────────────────┘ ``` ### 8.3 详情页(专业版) 在文献详情页新增「价值评估」区域,横向展示五维条形图。 右上角选择器可切换预设方案(临床优先 / 科研优先 / 综合)。团队版用户可在此调整权重。 --- ## 九、不做的改动 - **不存用户级评分**——所有用户共享一份维度分,个性化只在查询时实时算 - **不改变免费版页面结构**——只多加一个数字标签 - **不改变 Feed 引擎的标签匹配逻辑**——priority 仍是 must_read/recommended/related - **不支持用户级自定义权重**——放在团队版,由管理员统一设 - **临床相关性维度不等数据完备再上线**——骨架先搭进去,当前无信号给基础分 10,后续信号逐步加权 --- ## 十、执行顺序 ``` Phase 1 ─── GlobalLiterature 新增 reading_value 字段 + 索引 读写:单次 Alembic 迁移 Phase 2 ─── 实现规则评分算法 + 全量回算脚本 读写:新建 backend/app/services/reading_value.py 新建 backend/scripts/compute_reading_values.py Phase 3 ─── Feed 引擎整合(加 reading_score 字段 + 排序逻辑) 读写:feed_engine.py + 各导入路径 Phase 4 ─── AI 评估集成(DeepSeek 调用 + 异步任务) 读写:reading_value.py + ARQ worker 任务 Phase 5 ─── 前端展示(文献卡片评分标签 + 推荐理由) 读写:LiteratureCard.vue + LiteratureDetailView.vue Phase 6 ─── 专业版功能(5 维展示、预设方案选择) 独立,可与 Phase 5 并行 Phase 7 ─── 团队版自定义权重 不紧急,有团队客户后再做 ``` Phase 1-3 上线后用户无感知,但排序已优化。Phase 4 增加 AI 评估(后端任务,不影响用户操作)。Phase 5 用户才看到分数和推荐理由。 --- ## 十一、验证 1. 运行 `scripts/compute_reading_values.py`,检查全库 `reading_value IS NOT NULL` 比例 2. 查看分数分布曲线(大部分文献应在 50-85,不应过于集中或离散) 3. 抽样 5-10 篇人工判断:高分的确实应该高,低分的确实低 4. Feed 列表中观察排序顺序:同 priority 的文献是否按分倒序 5. 检查 AI 评估覆盖率:规则分 ≥60 的文献是否都有 AI 产出