fix: 今日文章配额控制,避免全部虚拟用户集中互动同一篇

问题:今日只有1篇文章时,所有虚拟用户全部互动该文章,历史文章无人问津

修复方案(配额制):
- 新增 count_today_articles():轻量统计今日广场文章数
- 配额规则:每篇今日文章最多吸引3个虚拟用户(可调)
  - 今日1篇 → 最多3人互动今日,其余全走历史
  - 今日5篇 → 最多15人互动今日,其余走历史
  - 今日10篇以上 → 批次内所有人均可互动今日文章
- get_news_list() 新增 force_history 参数,强制走 Phase 2
- 调度器在分发任务前计算配额,超出配额的用户透传 force_history=True

效果:新文章获得合理曝光,历史文章持续被互动,分布更自然
This commit is contained in:
stefanfeng
2026-04-08 11:47:36 +08:00
parent b43ee777fc
commit c944fbb0ea
2 changed files with 68 additions and 8 deletions

View File

@@ -171,13 +171,28 @@ class SchedulerService:
random.shuffle(rest_users)
selected = priority_users + rest_users[:max(0, batch_size - priority_size)]
# ── 今日文章配额计算 ──────────────────────────────────────
# 获取今日文章数量,决定本轮有多少用户应互动今日文章
today_count = 0
try:
from app.services.news_service import news_service as _ns
today_count = await _ns.count_today_articles(db, selected[0] if selected else None)
except Exception:
pass
# 配额规则:每篇今日文章最多吸引 3 个虚拟用户,超出部分走历史
today_quota = min(today_count * 3, len(selected))
logger.info(
f"[调度] 共 {len(all_users)} 个用户,{len(eligible)} 个满足间隔,"
f"本轮选取 {len(selected)}执行互动"
f"本轮选取 {len(selected)},今日文章 {today_count} 篇,"
f"配额 {today_quota} 人互动今日/{len(selected)-today_quota} 人走历史"
)
for user in selected:
asyncio.create_task(self._execute_user_interaction(user.id))
for i, user in enumerate(selected):
# 超出今日配额的用户强制走历史文章
force_history = (i >= today_quota)
asyncio.create_task(self._execute_user_interaction(user.id, force_history=force_history))
async def _try_login_users(self, db):
"""尝试登录未登录的用户"""
@@ -196,7 +211,7 @@ class SchedulerService:
except Exception as e:
logger.error(f"自动登录失败 {user.account}: {e}")
async def _execute_user_interaction(self, user_id: int):
async def _execute_user_interaction(self, user_id: int, force_history: bool = False):
"""执行单用户互动 - 基于真实接口"""
from app.services.news_service import news_service
from app.services.ai_service import ai_service
@@ -224,7 +239,7 @@ class SchedulerService:
# 获取新闻列表(基于接口 GET /news/list
articles = await news_service.get_news_list(
db, user, count=5, interest_tags=interest_tags
db, user, count=5, interest_tags=interest_tags, force_history=force_history
)
if not articles:
# 尝试从 session 获取 org_id 再试一次