Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
4.8 KiB
4.8 KiB
PROGRESS · 敏感内容审核 · 2026-09-30
合规轮四项之一(产品 2026-09-30「合规与法律的前四个你可以帮我做吗」)。执行:Claude fork D,直接执行。分支
codex/content-moderation-20260930,基于codex/compliance-base-20260930(= origin/staging5208f19b+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 运行时(无法就地替换,只保证存档与结算为提示句)。