Files
group_fqcd_jr/docs/接手文档-NL_develop-给架构师.md
T
qyqy f7a666fb5a fix(env)+docs: 按架构师第二轮纠正 mypy 根因(环境版本);补场外/推广域表登记
架构师第二轮答复里有一条技术纠正是对的,我原归因错了:
- 我原判断"184 个 mypy 错是因为缺 SQLAlchemy 2.0 类型信息"——**方向对了一半、结论反了**。
  SQLAlchemy 2.0 自带 py.typed,根本不需要 sqlalchemy2-stubs(那是 1.4 用的)。
- 实测复现矩阵(决定性证据):
    SQLAlchemy 2.0.34 + mypy 1.14.1 → 173 错(我原来的环境)
    SQLAlchemy 2.0.34 + mypy 1.20.2 → 173 错
    SQLAlchemy 2.0.52 + mypy 1.14.1 →   6 错
    SQLAlchemy 2.0.52 + mypy 1.20.2 →   3 错
  ⇒ 主因是 SQLAlchemy 的**补丁版本**(173→6),mypy 版本是次因(6→3)。
- 已把环境升到 SQLAlchemy 2.0.52 + mypy 1.20.2(均在 pyproject 约束内),
  mypy 从 184 降到 **3 个错**(剩下的 3 个全在同事的 offsite 文件里,非本线代码)。
- 没有把 sqlalchemy2-stubs 写进依赖(采纳架构师明确要求)。
- 交接文档已重写该条,并留下"两个反面教训":不要装 1.4 的存根包;补丁版差异会造成量级差异,
  若要门禁稳定需把 SQLAlchemy 钉到具体补丁版(属公共约定,未擅自改)。

按架构师裁决补文档(他裁定:不动 docs/00,另立登记):
- 新增 docs/28-场外与推广域数据表登记.md:17 张表逐表登记(表名/来源迁移/归属域/当前行数),
  并做规则 8 的**两向边界核对**——场内代码零引用这 17 张表(config.py 里的 offsite_ 只是配置项名)、
  场外代码零写场内交易表
- docs/08 审计口径更新为「场内 51 + 场外/推广 17 = 68」,并新增"第四种坏状态"
  (alembic_version 已指向新 revision 但表没建)的处置说明
- 澄清一个易误读点:audit_schema.py 的期望集合是**动态推导**的(读 baseline_generated.sql
  + 扫描 alembic/versions/*.py),表数 51→68 是自动结果,**没有人手工改期望值**;
  代价是只增不减(DROP 表会报 missing 假失败)

测试:3 failed(1 既有 + 2 环境相关)/ 1218 passed;文档守卫 35 份无重号;
mypy 3 错(180 文件);结构审计 68 张表通过。
2026-09-11 20:00:56 +08:00

14 KiB
Raw Blame History

接手文档 · NL_develop 这条线(给架构师)

交接对象:qyqy_develop 维护者 交接时点:2026-09-11 晚 分支状态:origin/NL_develop = c6a52a3 与你的关系:本分支已包含你 qyqy_develop 的全部提交(3f7c5ca,落后 0) 本文用途:你要接着维护/合并这条线时,先读这一份就够——环境口径、当前状态、 必须知道的 5 个坑、待你裁决的 3 件事。与另外两份文档的分工见 §9。

📌 配套文档:

  • 要 review 我的改动 → docs/交付说明-NL_develop-给架构师.md
  • 要对照你的评审意见 → docs/评审意见回复-NL_develop.md
  • 给下一位开发者(接手继续写代码)→ docs/superpowers/handoff/2026-09-11-交接文档-客服Agent与RAG收尾.md

1. 三条最要紧的结论(先看这个)

① 你这台和我这台不是同一套环境(已核实,不是配置没对齐)

我这台 你那台
config_release 总共 4 条,最高 id=216(我发的) 最高 201 + 9 条 agent_tools
Milvus 标识字段 knowledge_id / snippet doc_id / content
Milvus 可见性字段 无 visibility(过滤正常工作)
Milvus 行数 106 / 177 / 73 125 / 297 / 214

⇒ 由此推出的两条硬纪律(已写进 AGENTS.md):

  1. "配置已发布""数据是某 schema"这类结论必须带环境限定——config_release 与 Milvus 数据 都是环境数据,不随代码合并。
  2. 禁止硬编码 Milvus 字段名——检索层已改为运行时探测(app/core/knowledge_schema.py), 候选表在 FIELD_CANDIDATES。任何硬编码都会打挂另一套环境。

② 本库表数已从 51 张变成 68 张业务表,而文档没更新 ⚠️

同事(袁聪)那条线带进 11 个 alembic 迁移,新建 17 张表(我方已执行 alembic upgrade heads):

offsite_*  (10)  offsite_fund_mail / offsite_fund_attachment / offsite_fund_document /
                 offsite_execution_plan_task / offsite_rule_result / offsite_query_record /
                 offsite_notification / offsite_mail_cursor / offsite_recognition_attempt /
                 offsite_field_correction
promotion_*( 7)  promotion_attachment / promotion_compliance_check / promotion_delivery_record /
                 promotion_input_snapshot / promotion_material_task / promotion_material_version /
                 promotion_review_record
  • tools/audit_schema.py 现在报 68 business tables(原来 51)
  • 但 docs/00 基线与 docs/02 建表设计都还是 51 张 —— 你第二轮的裁决是: 不动 docs/00(它冻结的是场内交易域,把独立域塞进去会让"基线"概念失效), 改为另立登记文档。我方已按此落地:新增 docs/28-场外与推广域数据表登记.md (17 张表逐表登记来源迁移/归属域/跨域引用核对),并同步 docs/08 的审计口径为 「场内 51 + 场外/推广 17 = 68」。
  • ⚠️ 表数跳变不是"有人偷偷建表":audit_schema.py 的期望集合是动态推导的 (读 baseline_generated.sql + 扫描 alembic/versions/*.py 的 CREATE TABLE), 随迁移自动增长、没人手工改过。代价是只增不减:将来若有迁移 DROP 表, 期望集合仍含它、会报 missing 假失败(详见 docs/28 §5)。
  • 你的仓库若也是"alembic_version 指向同事 revision、但表没建"的状态,合并后需补跑迁移。

③ 测试基线不是"全绿",但 3 个失败都不是代码缺陷

pytest -q  →  3 failed, 1218 passed, 2 skipped

1. tests/unit/repository/test_fund_readonly_contract.py
   → 既有的"空集缺陷"(历史遗留,双方都不要修也不要报)

2. tests/unit/service/test_offsite_document_recognition_adapter.py(2 个用例)
   → 环境相关:断言要求请求体里是**中文原文**,而本机 httpx 序列化成 \uXXXX
   → 证据①该文件与 origin/qyqy_develop 逐字节相同(非我方改动)
     证据②本机 .pytest_cache 的 lastfailed 早已记录这两个用例
   → 建议改为断言 json.loads(body) 后的字段值,比字节级断言稳

2. 环境口径(照抄,别创新)

项 值 / 说明
解释器 你这台用 D:\conda\envs\jr_py313\python.exe;我这台用 .\.venv\Scripts\python.exe。.venv 被 .gitignore 忽略、不进仓库,不存在"需要统一"的仓库状态
MySQL 127.0.0.1:3306 / 库 jr_agent(两台机器各自的库)
Redis 127.0.0.1:6379。我这台容器以 --requirepass 123456 启动而 .env 无密码 ⇒ 每个请求打一条 AuthenticationError 堆栈、限流降级放行(不阻断业务,但日志噪声大)
Milvus http://localhost:19530(只监听 IPv6,写 127.0.0.1 可能连不上);容器 milvus-standalone
⚠️ Docker Desktop 不常驻:它没运行时 Milvus 不可用(docker CLI 报连不上守护进程)。跑真机验证前先确认它在运行 —— 我这次就被它挡过一次
迁移 python -m alembic upgrade heads;当前我方=head 20260911_merge_risk_heads
mypy ✅ 已收敛到与你同量级:mypy 1.20.2 + SQLAlchemy 2.0.52 → 3 个错(180 文件)。此前 184 的真因是我的环境版本旧,不是"缺类型存根"——你在第二轮答复里纠正过:SQLAlchemy 2.0 自带 py.typed,不需要 sqlalchemy2-stubs(那是 1.4 用的)。教训与实测矩阵见 §10

环境版本教训(第二轮答复纠正后的复现矩阵)

症状:同一份代码,mypy app 在我这台报 184 个错、架构师那台 0 错。

我最初的归因是错的("缺 SQLAlchemy 2.0 类型信息")。实测矩阵:

组合 报错数
SQLAlchemy 2.0.34 + mypy 1.14.1(我原来的环境) 173
SQLAlchemy 2.0.34 + mypy 1.20.2 173
SQLAlchemy 2.0.52 + mypy 1.14.1 6
SQLAlchemy 2.0.52 + mypy 1.20.2 3

⇒ 主因是 SQLAlchemy 的补丁版本(173 → 6):旧补丁版的类型标注不完整, BIGINT/DATETIME 被判成未类型化函数,于是 app/model/*.py 每个列定义都报一条。 mypy 版本是次因(6 → 3)。

两个反面教训(写在这里免得别人重走):

  1. sqlalchemy2-stubs 不能装 —— 它是给 SQLAlchemy 1.4 用的。装上后 181→43 看着"变好了",实际是换了一批按 1.4 API 核对产生的错(mapped_column/DeclarativeBase 不存在)。我当时把它当成"缺存根"的证据,方向对了一半、结论反了。
  2. pyproject.toml 的 sqlalchemy>=2.0,<3 允许的范围内,补丁版差异会造成量级差异。 若希望门禁数字稳定,需要把 SQLAlchemy 钉到具体补丁版(属公共约定,我没擅自改)。

3. 分支与提交

origin/NL_develop = c6a52a3(本地一致,工作区干净)

c6a52a3  docs: 新增《评审意见回复》
f2ac8a4  docs: 交付说明第二次修订;修同事带入的文档重号
8cff6b3  fix(tests): tmp_path 落点改到仓库内(33 个 setup ERROR → 0)
636dcbb  chore: 修我文件里的 mypy 类型错误(8 处)
7677aea  merge: 并入同事的场外申购/推广/行情/NL2SQL 线(11 提交、334 文件)
928d0bc  chore: 按评审恢复 5 份文档、审计补 agent_type、修订环境口径
5f82ac5  feat(knowledge): 检索字段名改为运行时探测(两套 schema 都能跑)
e342670  docs: 交付说明计数修正
…
e4c4099  wip: 客服Agent + RAG + 画像收尾(代码主体,82 文件 / +13902 行)

本地备份分支(可回退到"按评审整改之前"的状态): NL-backup-20260911 = e342670

另一条更早的工作分支(上一轮"第二次跟进合并"的中间态,已被取代): nl-merge-latest = 928d0bc(可删)


4. 这条线交付了什么(一句话清单)

交付 位置 状态
画像问答出口(你原实现里没有) customer_profile_service.py + customer_service.py 的"出口零" 真机通过
知识库文档管理三端点(老师验收第 7 条) api/controllers/knowledge_management.py 真机 403/201/200/404 全绿
合规语境豁免(恢复政策问答) app/core/compliance_context.py 17 个单测
知识向量链路(入库→同步→检索) knowledge_ingest_service / knowledge_vector_worker / milvus_knowledge_writer 真机通过
检索字段运行时探测(按你 §1.3) app/core/knowledge_schema.py 双 schema 参数化测试
治理审计留痕(按你 §3.1) interaction_audit.detail 加 agent_type + governance_rewrite 真机验证
同 key 覆盖修复(发布脚本) tools/publish_customer_service_config.py 你会用到
测试临时目录修复 tests/conftest.py 覆盖 tmp_path 33 错→0

5. 必须知道的 5 个坑(我踩过的)

  1. Milvus 删除/写入有读一致性延迟 —— 删除后的断言必须轮询。我早期只查一次, 得到过假的"删除失败"结论。
  2. Milvus VARCHAR 上限是 UTF-8 字节(中文 3 字节/字)—— 写入前必须按字节截断, 否则一条超长 title 会让整批失败(knowledge_vector_worker 里已修)。
  3. config_release 是"整版本替换"语义 —— 发新版会清空旧版所有配置项; 且同 key 的继承项必须被本次定义覆盖,否则旧值会被 admin 端子集校验 422 拦下整次发布, 报错只说"配置超出 Agent 工具上限",看不出是继承造成的。
  4. 两个 outbox 不能混 —— domain_event_outbox(领域事件)与 memory_sync_outbox(画像同步) 语义与消费者都不同。
  5. interaction_audit 没有 agent_type 列 —— 我用 detail JSON 键承载, 没有改表结构(遵守规则 4)。若你希望有独立列,那是一次迁移。

6. 待你裁决的 3 件事

6.1 画像工具白名单补发 —— 由你来做(你已提议出脚本)

你那台 201 的 customer_service:faq 只有 ["search_knowledge"],合并后画像出口会 AGENT_PERMISSION_DENIED。需补发一版:

customer_service:faq = [search_knowledge, query_customer_profile]   ← 唯一变化
其余 8 条原样继承(整版本替换语义,漏带会清空别人的白名单)

配置属环境数据,谁的环境谁发布 —— 我这边不再重发,避免两边各改一版。

6.2 memory_sync_outbox / GraphProjectionWorker 的接线归属 —— 我先不动手

你那台 我这台(实测)
MemorySyncOutbox 生产者 无 有:profile_repository.py:142
表内数据 空 2 行待处理(MILVUS/NEO4J 各 1)
消费端 无 有服务定义 ProjectionReconciliationService,但全仓无实例化点
GraphProjectionWorker 无实例化点(你发现) 无(我复核一致)

同一类问题:组件写好了、线没接。 涉及 app/worker/ 与 app/service/profile_*, 跨你我两条线 —— 请先定归属,否则两边各接一根线会更乱。

6.3 两处文档让号是否认可

让号对象 原号 新号 依据
JWT 密钥管理与轮换 21 26 21 已被你的《风控业务第二版迁移清单》占用
金融NL2SQL工具接入说明 15 27 15 已被《Agent组员详细开发与使用手册》占用,而手册被 docs/16/17/AGENTS.md 三处引用

若你认为该由另一方让号,我改(守卫已通过:34 份无重号)。


7. 还有两件建议你拍板的事

  1. 文档体系的两套口径:AGENTS.md 的「接手先读」是按"清理后只读正确的"设计的 (docs/04/06/10/13/99 我按你要求保留了,但列进了 D 类"不要用来判断当前进度")。 若团队更希望"全部保留、都读",这套索引需要相应改写。
  2. docs/00 基线要不要补那 17 张新表(见 §1②)—— 涉及不可变基线,我只提示、不动手。

8. 快速自检(接手后先跑这几条)

# 1) 测试(期望 3 failed / 1218 passed;那 3 个见 §1③,都不是代码缺陷)
.\.venv\Scripts\python.exe -m pytest -q

# 2) 结构审计(期望 68 business tables —— 与文档里的 51 张不一致,见 §1②)
.\.venv\Scripts\python.exe tools\audit_schema.py

# 3) 文档守卫(期望 34 documents, no number collision)
.\.venv\Scripts\python.exe tools\check_authoritative_docs.py

# 4) 迁移状态(期望 head = 20260911_merge_risk_heads)
.\.venv\Scripts\python.exe -m alembic current

# 5) Milvus 是否在(Docker Desktop 必须先启动)
docker ps --filter name=milvus

注:上面命令用的是我这边的解释器路径。你那台把 .\.venv\Scripts\python.exe 换成 D:\conda\envs\jr_py313\python.exe 即可,其余完全一致。


9. 三份文档的分工(别读串了)

文档 读者 回答什么问题
本文 你(接手维护) 起点在哪、有哪些坑、哪些待裁决
docs/交付说明-NL_develop-给架构师.md(443 行) 你(review 用) 我动了你什么、为什么、证据
docs/评审意见回复-NL_develop.md(251 行) 你(对照评审意见) 你提的每条我是怎么处理的
docs/superpowers/handoff/2026-09-11-交接文档-客服Agent与RAG收尾.md 下一位开发者 怎么继续写代码(环境、命令、模块)

本文所有数字均为 2026-09-11 实测。若与代码不一致,以代码与 docs/05 接口文档为准。