跳转至

后端-数据库-v4模型缺少negative_penalty列导致评分写入失败

问题现象

  • 日报 docs/day/2026-7-14-day.md 显示 "AI 评分文章数: 0",但当天采集了 617 篇网页新闻 + 136 篇公众号文章 = 753 篇新文章
  • AI 分析耗时仅 3 秒(正常评分 700+ 篇至少需几分钟),说明评分逻辑几乎未执行
  • 查看 log/daily_crawl.log 发现:
sqlalchemy.exc.OperationalError: (asyncmy.errors.OperationalError) (1364, "Field 'negative_penalty' doesn't have a default value")
[SQL: INSERT INTO recommendation_scores (news_type, news_id, final_score, score_reason, scored_at) VALUES (...)]

核心问题

  • 数据库 recommendation_scores 表保留了 v2 规则引擎 时代的 negative_penalty 列(float NOT NULL 无默认值)
  • v4 LLM 综合评分模型(modules/ai-recommendation/models.py)简化后未定义该字段
  • SQLAlchemy 生成的 INSERT 语句不包含 negative_penalty → MySQL 拒绝写入
  • 异常被 daily_crawl.pyrun_ai_recommendation() 顶层 except 捕获,scored = 0

数据库实际列(v2 遗留): | 列名 | 类型 | NULL | 默认 | 状态 | |------|------|------|------|------| | negative_penalty | float | NO | 无 | 缺失(引发错误) | | llm_score | float | YES | NULL | 可省略 | | topic_score | float | YES | NULL | 遗留 | | depth_score | float | YES | NULL | 遗留 | | utility_score | float | YES | NULL | 遗留 | | source_score | float | YES | NULL | 遗留 | | topic_label | varchar(50) | YES | NULL | 遗留 |

解决方法

1. 修复模型定义

modules/ai-recommendation/models.pyRecommendationScore 类中添加:

negative_penalty: Mapped[float] = mapped_column(Float, default=0.0, server_default="0", comment="负例惩罚值")

2. 部署到服务器

git add modules/ai-recommendation/models.py
git commit -m "fix(ai-recommendation): add negative_penalty field to fix INSERT error"
git push origin main
ssh news "cd /www/news && git pull origin main && systemctl restart news-backend"

3. 重新触发评分

ssh news "curl -s -X POST 'http://localhost:8000/api/ai-recommendation/score-articles' \
  -H 'Content-Type: application/json' -d '{\"date\": \"2026-07-14\"}'"

下次防错措施

快速定位

# 查看评分是否异常(score=0 但文章数 > 0)
ssh news "cat /www/news/docs/day/$(date +%Y-%-m-%-d)-day.md | grep -A1 'AI 评分'"

# 查看评分阶段日志
ssh news "grep -A10 '阶段四' /www/news/log/daily_crawl.log | tail -15"

模型变更检查清单

  1. 修改 Python 模型后,对比 MySQL 表结构 — 不可仅依赖 extend_existing=True
  2. 服务器端执行:
ssh news "mysql -u root -p\$DB_PASS -D news -e 'DESC recommendation_scores'"
  1. 确认 Python 模型中所有 NOT NULL 无默认值的列都有对应的字段定义

巡检脚本

#!/bin/bash
# 检查今天日报中的 AI 评分是否为 0
TODAY=$(date +%Y-%-m-%-d)
FILE="/www/news/docs/day/${TODAY}-day.md"
COUNT=$(grep "AI 评分文章数" "$FILE" | grep -oP '\d+')
ARTICLES=$(($(grep "网页新文章数" "$FILE" | grep -oP '\d+') + $(grep "公众号新文章数" "$FILE" | grep -oP '\d+')))
if [ "$COUNT" -eq 0 ] && [ "$ARTICLES" -gt 0 ]; then
  echo "告警: 今天采集了 ${ARTICLES} 篇文章但 AI 评分为 0"
  exit 1
fi
echo "正常: AI 评分 ${COUNT} 篇 / ${ARTICLES} 篇"