Files
Jyotisha/docs/tasks/PROGRESS-content-moderation-20260930.md
T

4.8 KiB
Raw Blame History

PROGRESS · 敏感内容审核 · 2026-09-30

合规轮四项之一(产品 2026-09-30「合规与法律的前四个你可以帮我做吗」)。执行:Claude fork D,直接执行。分支 codex/content-moderation-20260930,基于 codex/compliance-base-20260930(= origin/staging 5208f19b + lib/legal-entity.ts)。 产品决定:输入命中 → 不发模型、不扣点、固定一句;输出命中 → 整段替换并退点;命中留脱敏日志。

做了什么

部分 位置 说明
审核接口 src/lib/moderation/index.ts moderate(text, side, context) → {verdict, categories, ruleIds, providerId};本地词表先跑,命中即终判;配置了阿里云再跑远端(≤1.5 s);远端失败/超时 → 沿用本地判定(输入:本地兜底不放空;输出:不因服务不可用而扣下回答)
本地词表 src/lib/moderation/lexicon.ts 12 条规则、5 类(政治 3 / 暴恐 3 / 涉未成年色情 1 / 自伤 2 / 违法交易 3),均为多字短语;归一化去空格标点零宽、全角转半角
阿里云适配 src/lib/moderation/aliyun-provider.ts TextModerationPlus(llm_query_moderation / llm_response_moderation),RPC 签名 v1;high → 拦,medium → 待复核(放行并记录);endpoint 限定 *.aliyuncs.com;超 2000 字分段,最多 4 段
日志 src/lib/moderation/log.ts + 迁移 20260930040000_moderation_events.sql 只记类别、规则编号/服务标签、方向、入口、模型、request、user_id;不存原文;仅 service_role
普通咨询 app/api/consult/route.ts 输入:在 prompt-extraction 守卫之后、预留点数之前;输出:三条 agentic 流 moderateOutput + completeResponse 兜底(覆盖旧 text/plain 运行时);命中走新函数 complete_consultation_moderated(复制自免费结算,释放预留)
流式替换 lib/stream-agent-response.ts、lib/consultation-agent-events.ts、lib/consultation-run-timeline.ts、hooks/use-consultation-run.ts answer.delta 增加可选 replace: true;客户端时间线与发送钩子遇到即整段替换
生时校正 v9/agent-route-request.ts(输入)、v9/agent-run-finish.ts(输出) 输出命中:skipBilling → billing.release(),spoken 换成撤下提示,走既有 replace
出生时间引导 app/api/birth-time-guide/route.ts draft_evidence.message / reframe_unmatched.note 输入审核
后台 app/api/admin/moderation-events、components/admin/moderation-events-resource.tsx、菜单「内容审核」 只读、audit.read、14 天分类计数

未接入(无用户自由文本进模型):报告生成、今日星语、合盘、星盘 / 星历。Python API 未发现把用户自由文本送进模型的端点(模型调用都在 Next.js 侧)。

既有断言改动(原值 / 新值 / 原因)

文件 原值 新值 原因
tests/test_api_server_security.py app_routes 列表 admin/models 后直接 admin/orders 中间加 admin/moderation-events 新增只读后台页
frontend/tests/admin-contracts.test.ts 只读资源 四个 加 moderation-events 同一只读约束覆盖新页

验证(Claude fork 实跑,Linux,Node 22.14)

项 结果
tsc --noEmit 0 错
npm run lint 0 error,126 warning(同基线)
新增 content-moderation.test.ts 10/10:占星用语 8 句全部放行;五类各自拦截含空格/全角/零宽规避;自伤给求助句;阿里云 high→拦、medium→待复核、none→放行,签名与表单校验;本地拦截不调远端;远端超时(50 ms)/500 → 沿用本地;无钥匙/非 aliyuncs.com 只用本地且只警告一次;日志不含原文、写失败不抛;流式回答被整段替换且 onComplete 收到提示句、时间线最终文本为提示句;路由里输入审核在预留点数之前、校正输出审核在结算之前
npm test 全量 4,428 / fail 26。与基线(24 条环境失败)相比多 2 条:a lookup does not reset the answer clock… 与 a refresh inside a rectification conversation stays in it…,均为并发负载下超时(后者等待 16.8 s 超时),单独各跑两次全部通过,且不涉及本次改动文件。新增 10 条,消失 0 条
next build / 仍 ○ Static;首屏 gzip-9 646,505 B(基线 646,480 B,+25 B)
Python tests/test_api_server_security.py::test_capability_audit_scans_registry_and_local_sources 通过;快速门 Python 步 1000 passed / 2 skipped(门内 npm test 步走系统 Node 20,属已知环境失败)

未验证:阿里云真实调用;迁移在真实 PostgreSQL 上执行(无 Docker);浏览器中被拦与被替换的表现;遗留 text/plain 运行时(无法就地替换,只保证存档与结算为提示句)。