9ad02a778f
C-1(必须修): 墙的执行侧没接租户管道——runtime.compiled_wall 全库只有 AIService 的 $DEFLECTION_POOL 一处消费,conversation.py 执行侧全走模块级 DEFAULT_WALL(jiancai 出厂),auto 租户会话实际跑的是 jc 墙。修复: - manager 构造时 self._wall = runtime.compiled_wall(与 AIService 同源); - 6 处过滤调用(violates_boundary/no_contact_value/asks_contact 的句内 与 pending 尾巴两路)、CC 墙模板/替换句、no_contact 收尾选择、 pivot/deflection、兜底句、contact_ask 触发日志判定全部传 wall=self._wall; - _build_context_reminder/_contact_completion_note/_cc_confirm_note/ _cc_script/_cc_wall_template/_lang_note_for 加 wall=None 尾参 (None = 模块级默认墙,旧测试直调语义不变;流式侧 _contact_completion_note 双胞调用同传 wall,写回与注入不漂移); - 模块级 DEFAULT_WALL 视图常量(BOUNDARY_TRIGGER_RE/_CC_*/_EMAIL_NOTE_* 等) 保留——boundary_filter 出厂默认与旧测试锚定,boundary_filter 模块级 DEFAULT_WALL 照旧,conversation 会话流内一律租户墙; - 端到端回归锁 tests/test_wall_execution_tenant.py(两租户真 runtime + 脚本化假 AI): jc 独有 [€£] pattern 句在 jiancai 拦截替换(收尾=jc pivots 池)/auto 放行逐字流出;同一邮箱违规句两租户各自精确收到自己 no_contact["web"](12 hours vs replies fast!);contact_ask 提醒注入 各自墙文案互不渗漏。已验证模拟旧 DEFAULT_WALL 行为时三测全败。 I-1: 两租户 seed 补 email 组(以 brand_values.json 实际值为准: auto=notify_email 环境值,jiancai=品牌邮箱——其 notify_email 记录是 notify@example.com 占位): auto {sender_name: XYH, notify_emails: [18339827479@163.com]}, jiancai {sender_name: HESUPIPE, notify_emails: [hesu@hesuu.com]};seed 存裸名,From 头渲染时外层再包【】。补测 test_seed_tenants_ship_email_group: env NOTIFY_EMAIL patch 成异值证明 seed 槽胜出。 M-1/M-2: README/CLAUDE.md "platform.db 热加载"改为"文件级 registry_reload 热加载(Phase 2 升级为 platform.db)";requirements.txt 删 alembic (全库零引用,grep 实证唯一命中即该行)。 M-3/M-4(挂账): CLAUDE.md Phase 2 清理单补两项——/health 分级健康 (Phase 4 部署批次)、PromptProvider.from_dir FileNotFoundError 带路径上下文。 全量回归: 463 passed(459 基线 + 4 新增),根目录与 tests/ 子目录同数。 Co-Authored-By: Claude Code <noreply@anthropic.com>
67 lines
6.6 KiB
Markdown
67 lines
6.6 KiB
Markdown
# CLAUDE.md — all-kefu 工作约定
|
||
|
||
## 项目定位
|
||
|
||
本项目 all-kefu 是**统一多租户 AI 客服平台**:一套引擎 + 租户配置包,消除"每客户复制一套代码"的旧模式。项目由 ai-kefu / ai-kefu-jc 两个复制分叉项目合并而来,**jc 为主线**(代码以 ai-kefu-jc 为基础迁移,再做租户化改造)。
|
||
|
||
## 硬约束
|
||
|
||
- **uvicorn 必须以 `--workers 1` 运行**。内存中的 token 缓存、限流状态、配置缓存、每租户 engine 缓存均假设单进程,多 worker 会导致状态割裂。任何启动脚本/部署配置不得改动此项。
|
||
- **Windows 环境**:跑 python / pytest 前设置 `PYTHONUTF8=1`(GBK 控制台遇 emoji / 中文 payload 会直接崩,血泪教训)。
|
||
|
||
## 本地开发访问方式
|
||
|
||
- 路由按 Host 解析租户:`/` 与 `/static` 也需要已知租户域名(未知 Host 一律 404,唯一豁免 `/health`,供部署健康检查 curl 用)。
|
||
- 本地访问二选一:改 hosts 把 `chat.agent.hnxinyouhe.com` / `chat2.agent.hnxinyouhe.com` 指到 `127.0.0.1`;或 curl 显式带 `-H "Host: chat2.agent.hnxinyouhe.com"`。
|
||
- uvicorn 起在 8018:`PYTHONUTF8=1 .venv/Scripts/python -m uvicorn app.main:app --port 8018 --workers 1`。
|
||
|
||
## 开发流程
|
||
|
||
- 改动 `seed_profiles` 后必须跑全量 pytest(出厂配置影响面大)。
|
||
- 全量回归命令:`PYTHONUTF8=1 .venv/Scripts/python -m pytest -q`(根目录与 tests/ 子目录均可跑,pytest.ini 已锚定根路径)。
|
||
|
||
## Phase 1 完成状态(2026-10-12 收尾核对)
|
||
|
||
**测试基线:459 passed**(根目录与 tests/ 子目录各跑一遍,数字一致;唯一 warning 为 starlette TestClient 对 httpx 的弃用提示,无害)。收尾提交前基线即此数,后续任务回归以此为准。
|
||
|
||
**零同步 IO 审计**(`grep -rn "requests\.\|urllib\|time\.sleep" app/`):
|
||
|
||
- 命中数 **0**——app/ 内无 requests 调用、无 urllib、无 time.sleep。
|
||
- 全库唯一 HTTP 出站点为 `app/engine/services/lead_push_service.py` `_do_post`,使用 `httpx.AsyncClient`(async with 上下文),异步路径成立。
|
||
- `app/engine/providers/glm.py` 的同步 token 生成与兜底同步调用分别经 `loop.run_in_executor` / `asyncio.to_thread` 下卸,事件循环不被阻塞。
|
||
- `app/engine/services/rate_limit.py` 的 `import time` 仅用 `time.time()` 读时钟(纯 CPU,非 IO);app/ 源码内无 `open()` 文件读取。
|
||
|
||
**spec §6.2 合并清单核对**(逐项,全部在位):
|
||
|
||
- 取自 jc:cc_completion 完整判定树+状态机+extractor `cc_reply`+e164 出站渲染(`app/engine/services/cc_completion.py`,conversation.py 双门控消费);多语言墙(€/£、西/葡/俄/阿词表在 `seed_profiles/jiancai/wall.json`、ES 迂回池 boundary_filter+wall.json、建材防误杀白名单为 pattern 级 comment+后顾断言 DN800/SDR11/PN16/"euro pallets" 排除);dual-contact 分步双要(cc_settled 串行门控邮箱轻补)+`_email_asked`;CC 强制墙(conversation.py cc_wall 裁决段)+零号码墙回显豁免收窄(boundary_filter.py:旧豁免移除,改 allow_number 回显确认轮白名单+防自锁线);XFF 服务端优先(chat_rest `_server_ip`/chat.py 握手期提取,均取第一段)、阿语数字归一(contact_pipeline 捕获源头 translate)、`resolve_region_code`(ip_service.py)。
|
||
- 上游吸收:input-placeholder 可配置化(品牌配置组,public.py 下发,widget/chat data-placeholder 管道);7 个测试文件(test_channel_hygiene / test_chat_rest_ip / test_lead_push_cc / test_cc_integration / test_ip_service_region / test_prompt_static / test_placeholder_static,commit d1aed8e)。
|
||
- 三不带:blog.html(static/ 无此文件)、Redis(app+scripts 零命中)、旧版 whatsapp-cc-completion(零命中,jc 版 cc_completion.py 取代)。
|
||
|
||
**当前能力一览**:多租户引擎(TenantRuntime 隔离边界,engine 不感知 platform);站点模型(tenant_config.Site,一租户多站点覆盖);词表/提示词/品牌全配置化(seed_profiles 出厂包 + 文件级 registry_reload 热加载,Phase 2 升级为 platform.db);Host 路由(host_middleware,未知 Host 404);WS 防串库(租户化 client key + 会话站点标);WS 每 IP 连接上限(conn_limiter,租户级 ws_conn_limit 配置)。
|
||
|
||
## Phase 2 清理单(前序审查挂账,集中列此)
|
||
|
||
1. **FakeAI 三份拷贝收敛进 conftest**——下次吸收测试时先做(出处:上游吸收审查,tests/ 内多处 FakeAI 定义重复)。
|
||
2. **rate_limit 与 ws_conn_limit 的 0 语义统一 + 配置类型校验**——试金石批次(出处:配置接线审查)。
|
||
3. **name_to_region_extras / context_seed_map 等散装 resolver 收拢为 config_views 单入口**(出处:配置接线审查"种子映射消双路径"遗留)。
|
||
4. **AIService.from_runtime 类方法**——组装正典化(出处:引擎改造审查)。
|
||
5. **boundary_filter 视图常量退役**——admin 重写后旧测试迁移时(出处:引擎改造审查)。
|
||
6. **push enabled 布尔空槽语义**——admin 配置显式化时解决(出处:push 审查)。
|
||
7. **contact.template_languages 运行期接线**——后台批次(出处:配置 schema 审查)。
|
||
8. **话术含引号/换行的转义**——编辑器批次(`_format_deflection_pool` docstring 有注)。
|
||
9. **产品决策项**:国名纠正 e164 变化时是否补发更正邮件(上游行为更优);REST/WS 服务端 IP 口径是否统一(出处:上游吸收审查)。
|
||
10. **avatar 从 seed_profiles 迁 uploads 卷**——上传功能落地时(出处:品牌下发审查)。
|
||
11. **/health 分级健康**——Phase 4 部署批次(进程存活之外按依赖分级上报,健康检查可区分"进程活"与"依赖通";出处:终审审查 M-3)。
|
||
12. **PromptProvider.from_dir 的 FileNotFoundError 带路径上下文**——提示词目录缺失时异常信息含实际路径,定位不用猜(出处:终审审查 M-4)。
|
||
|
||
## Phase 2 计划编写注意
|
||
|
||
- conftest 跨循环纪律:`async_db` 夹具用 NullPool;TestClient 必须走 portal 桥接事件循环;禁止 `asyncio.run` 直开租户 session_factory(三个坑都在 tests/conftest.py 有既成解法,照抄勿发明)。
|
||
- `build_app` / `app_client` / `TenantTestClient` 夹具已就绪,新测试优先复用而非自建 app 实例。
|
||
|
||
## 文档索引
|
||
|
||
- 设计文档(spec):`docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md`
|
||
- Phase 1 实施计划:`docs/superpowers/plans/2026-10-12-phase1-engine-merge-tenantization.md`
|
||
- 部署坑手册:Phase 4 补 `docs/deploy-production.md`(尚未存在)
|