Files
group_fqcd_jr/docs/交付说明-NL_develop-给架构师.md
T
qyqy f2ac8a4460 docs: 交付说明按评审意见第二次修订;修同事带入的文档重号
评审意见逐条落地(详见文档新增的 §0 对照表):
- §1.1/§1.2/§4:确认两台机器连的**不是同一套 MySQL/Milvus**(我方 config_release 总共 4 条、
  最高 216;架构师侧 201 + 9 条白名单),据此把"216 已在共享库生效"整体改写为
  "**我方环境**已发布,你那台需补发";补发由架构师做(配置属环境数据,不随代码合并)
- §1.3:字段映射已改为运行时探测(见上一提交),文档里的 A/B/C 三选一整体替换为探测方案说明
- §1.4:mypy 那条改写——查清主因是**本机缺 SQLAlchemy 2.0 类型信息**(装 sqlalchemy2-stubs
  181→43,卸载回 184),明确"本机数字不可作为质量结论、两边不可比";我文件里的 8 个真实错误已修
- §2:明确 docs/26 是**重命名**(原 21,因 21 已被风控迁移清单占用),不是新增、不会并存
- §3.1:审计留痕已补(agent_type + governance_rewrite)
- §3.3:5 份文档删除**已撤回**(上一提交)
- §5/§7:更新验证数字(1218 passed)、两个环境相关失败的证据、memory_sync_outbox 双环境对照表

另修一处**同事那条线带入的重号**:docs/15-金融NL2SQL工具接入说明.md 与既有
docs/15-Agent组员详细开发与使用手册.md 撞号 → 新那份让号到 docs/27
(依据:手册被 docs/16、docs/17、AGENTS.md 三处引用,改名代价更大)。守卫恢复通过(32 份)。
2026-09-11 19:15:23 +08:00

29 KiB
Raw Blame History

交付说明 · 客服 Agent + RAG + 画像(NL_develop → qyqy_develop)

收件人:架构师(qyqy_develop 维护者) 来源分支:NL_develop 合并目标:qyqy_develop 基线:本分支已包含 qyqy_develop 的 3f7c5ca(含你与同事各自的最新推送,落后 0) 一句话:以你已有的客服实现为骨架,把本线独有的画像问答出口、知识库文档管理三端点、 合规语境豁免嫁接进去;按你的评审意见把检索字段名改为运行时探测; 并修掉合并过程中暴露的多个"单测全绿但真机必挂"的问题。

📌 本文档是给评审者看的,与给接手开发的 docs/superpowers/handoff/2026-09-11-交接文档-客服Agent与RAG收尾.md 定位不同:那份讲"怎么继续开发",这份讲"动了你什么、为什么、要不要你点头"。


0. 第二次修订:评审意见的落实情况(2026-09-11 晚)

你那份《评审意见》里的每一条我都核对过实测证据,除 §3.3 我照你的要求撤回之外,其余全部采纳。

你的意见 我的处理 落地位置
§1.1 我说的 active 216 在你那边不存在 ✅ 你是对的。我这边 config_release 总共只有 4 条(最高 id=216),你那台有 201/198/197… 与 9 条 agent_tools 白名单 —— 两台机器连的不是同一套 MySQL/Milvus。已把"216 已在共享库生效"整体改写为"我方环境已发布,你那台需在合并后补发" §4.9
§1.2 合并后画像出口会 AGENT_PERMISSION_DENIED ✅ 采纳。customer_service:faq 必须补 query_customer_profile。你已提出"我这边可以出脚本"——接受,由你来发(config_release 是环境数据,不随代码合并) §4.9
§1.3 字段映射不是 A/B/C,应改运行时探测 ✅ 已按你的方案实现:新增 app/core/knowledge_schema.py,describe_collection 拿真实字段名建映射、按集合缓存;visibility 有才过滤;缺必需字段的集合明确判为不可用。两套 schema 各有单测(任何回退到硬编码都会让其中一侧红) §4.2
§1.4 解释器不统一、mypy 数字不可比 ✅ 你是对的,而且我查到了根因:本机 mypy app 报 181/184 个错的主因是缺 SQLAlchemy 2.0 类型信息(装上 sqlalchemy2-stubs 后 181→43,卸载回 184)。这个数字双方不可比,我不再拿它当结论;我文件里的 8 个真实错误已单独修掉 §5
§2 docs/26 会和 docs/21 重复 ⚠️ 核对后是同名重命名而非并存:你那台的 docs/21-JWT密钥管理与轮换.md 与我这台的 docs/26-… 是同一份内容,我这边 21 已被你的《风控业务第二版迁移清单》占用,所以只能让号。合并后是一次 rename(删 21、加 26),不会出现两份同主题文档 §2 末
§3.1 agent_type 同意,但要写进审计 ✅ 已加:interaction_audit.detail 增 agent_type + governance_rewrite(不改表结构,detail 是 JSON 列);真机已验证最新审计行含这两个键 §4.1
§3.3 驳回删除 5 份文档 ✅ 撤回,5 份已全部恢复(git show 从你分支取回,逐字节相同)。AGENTS.md 改为"保留但仅作历史参考"并入 D 类 §1 第 3 项
§4 memory_sync_outbox ⚠️ 两台的结论不同,我这边更"进一步":我方有生产者(profile_repository.py:142)、表里已有 2 行待处理,但消费端从未被实例化(ProjectionReconciliationService( 全仓无调用点);你说的 GraphProjectionWorker 无实例化点在我这边同样成立。同一类问题:组件写好了、线没接。归属待定,见 §7 §7
§5 合并顺序 ✅ 按你的顺序:先对齐环境口径 → 改字段探测 → 撤回删除项 → 合代码 → 补发配置(你来) 全文

一句话总结这次核对:不是谁配错了,而是两台机器各自有独立的 MySQL + Milvus。 由此推出的第一条纪律:"配置已发布""数据是某 schema"这类结论必须带环境限定, 否则每次合并都要重吵一遍——这正是你 §1.4 想避免的事。


1. 请你重点看的四件事(都在 §4 有逐条说明)

# 事项 状态
1 AgentGovernance.review() 新增可选 agent_type 你已同意;审计留痕已按你要求补上(§4.1)
2 检索字段名改为运行时探测 ✅ 已按你的 §1.3 实现,替换掉原先的硬编码映射(§4.2)
3 删除 5 份编号文档 ✅ 已撤回,5 份全部恢复(§3.3 你驳回)
4 docs/26-JWT密钥管理与轮换.md 是重命名(原 21,因 21 被你占用),非新增(§2 末)

2. 净差异总量(相对 qyqy_develop 的 d2cdbba)

93 项:新增 51 / 修改 35 / 删除 6 / 重命名 1

新增的 51 项里包含本文档自身(docs/交付说明-NL_develop-给架构师.md); 本说明写作时的数字是 92 项/新增 50,加入本文后为 93/51。

类别 数量 说明
新增 app/ 模块 16 画像生成与投影、知识入库/检索/管理、Milvus 读写适配、文档解析与落盘、合规语境
新增 tests/ 17 与服务一一对应;另有 1 个 MySQL 集成测试
新增 tools/ 5 知识集合建表、种子导入、画像演示数据、合规种子、QA 素材解析
新增文档 14 交接文档、工作报告、本交付说明、验收证据(从被 gitignore 的 .superpowers/ 复制)、ARCHIVE 归档、设计 spec
修改 35 其中 7 个是你的核心文件(见 §4)
删除 6 5 份编号文档 + 1 份过程产物(见 §1.3)

未新增任何数据库表、未新增迁移:fin_knowledge_meta 等本就在 docs/00 基线内,本次只补 ORM 映射。 .venv\Scripts\python.exe tools\audit_schema.py → 51 business tables, no missing or unexpected tables。


3. 本线交付了什么(按功能,附真机证据)

3.1 画像问答出口(你的实现里没有这个出口)

  • 新增 app/service/customer_profile_service.py:query_customer_profile 只读工具。 权限 memory:read:self;作用域校验 self/own_customers/all;审计 memory.profile_read; fields 参数拒绝任何 PII 字段;快照缺失/为空失败关闭(不返回空对象假装成功)。
  • 新增 app/core/profile_projection.py:画像字段白名单投影,PII 全剔除,assessment_expired 重算。
  • 新增 app/service/profile_generation_service.py + app/repository/profile_repository.py: 一次 MySQL 事务内 新快照 + 2 条同步事件 + 旧快照 is_current 置 0(符合 docs/00 §6.4.6)。
  • 修掉 app/service/public_platform_service.py 的 memory() 恒返回 {} 静默故障 → 现返回投影。
  • 在 customer_service.py 中新增出口零:is_profile_question() 确定性关键词识别(不经意图分类), 命中即查本人权威字段;失败关闭为转人工。

真机证据:

客户 9101(C5)→ succeeded  「您的风险测评等级是 进取型(C5)。」
客户 9001(测评过期)→ succeeded  「…保守型(C1)。注意:您的风险测评已过有效期,需要重新完成测评…」
规则类问题「风险等级怎么划分」→ 未被画像分支截走,走知识检索
跨客户读取 → GenericResourceNotFoundError: 客户不可访问

3.2 知识库文档管理三端点(老师验收标准第 7 条)

app/api/controllers/knowledge_management.py + app/service/knowledge_management_service.py

POST   /api/v1/knowledge/upload     → 201(切分 → 逐块写 fin_knowledge_meta → 投向量同步事件)
GET    /api/v1/knowledge/list       → 200(只返 content_preview 前 200 字,不做正文旁路)
DELETE /api/v1/knowledge/{id}       → 200(status='expired' + 投向量删除事件;不存在 → 404)

真机证据(含向量的真实进出,不只是返回码):

客户 9001 上传 → 403 ✅ 权限隔离正确
管理员上传     → 201 ids=['369']
消费同步事件    → Milvus 出现 ✅
列表           → 200 命中本次上传 1 项 ✅
删除           → 200 {"status":"expired","vector_delete_event":"knowledge.vector_delete_requested"}
消费删除事件    → Milvus 向量消失(轮询 2s)✅
不存在 id       → 404 ✅

📌 路径口径:老师草稿写的是 POST /api/knowledge/upload(无 /v1),实现为 /api/v1/knowledge/upload。 docs/05 §8.3 与 §19 目录(K002/K003/K004)均以带 /v1 的路径为权威。

3.3 合规语境豁免(恢复政策问答)

app/core/compliance_context.py(新增)+ app/service/agent/governance.py(改)

问题:零容忍词库是朴素子串匹配,它分不清"作出承诺"与"禁止承诺/谈论该表述"。 政策原文里含「严禁承诺保本保收益」「禁止使用『保证收益』」时,平台会用自己的规则拦下自己的合规教材 —— 实测「基金销售有哪些合规要求」的回答从 1097 字被替换成 83 字的"该内容需要人工核实"。

修法:按句界限定窗口(12 字符)的否定/元语言线索豁免。第一版没限句界, 把 严禁承诺保本。但这只基金保本 错误豁免了 —— 已收紧为句内才认,并有 17 条单测锁定。

3.4 知识向量链路(入库 → 同步 → 检索)

  • app/service/document_parser.py(txt/md/docx,512 字符切块 / 64 重叠)
  • app/service/knowledge_ingest_service.py → 写 fin_knowledge_meta + 投 knowledge.vector_sync_requested
  • app/worker/knowledge_vector_worker.py → 消费事件 → MilvusKnowledgeWriter 写 Milvus
  • app/service/knowledge_retrieval_service.py → 读路径(Milvus 失败降级 MySQL LIKE,并如实标 degraded)
  • 读写物理隔离(写适配器与召回客户端不共用连接)

顺带修掉的 4 个真机静默故障(都是"单测绿、真机挂"):

# 位置 缺陷 原后果
1 milvus_knowledge_writer.py 写字段名 vector,集合 schema 是 embedding 所有向量写入失败
2 knowledge_vector_worker.py Milvus VARCHAR 上限是 UTF-8 字节,未按字节截断 title 346 字节 > 256 → 整批失败
3 同上 乱序到达的旧同步事件会把已删向量复活 已删知识又出现在检索结果
4 knowledge_tool.py async with _session_factory() 少一层调用 工具 100% 抛错

4. 我对你的代码做的修改(逐文件说明)

4.1 app/service/agent/base.py(+6 −1)⚠️ 公共契约

# 原来
result = await governance.review(result, context, config, memories)
# 现在
result = await governance.review(
    result, context, config, memories, agent_type=self.definition.agent_type
)

理由:门禁 F5(面向客户输出 100% 附固定话术)只该对面向客户的 Agent 生效。 你的风控 Agent 输出是字段化摘要(预警编号/级别/建议动作),被追加一句面向投资者的免责声明后, tests/contract/test_risk_agent_contract.py 直接失败(实测)。agent_type 从定义取最可靠 (不需要查库、与发布配置无关)。

协议同步(governance.py):AgentGovernance.review 与 PlatformGovernance.review 均新增 关键字参数 agent_type: str = "",带默认值,所以旧的调用点不会 TypeError。 判定口径是确认式白名单:只有 CUSTOMER_FACING_AGENT_TYPES = {customer_service, fund_query_demo} 才注入;空串(未声明)不注入——理由见代码注释(测试替身刻意不连库,若默认注入则每个替身测试 都会被塞进话术,用测试噪声换假安全感)。

受影响的测试替身已同步更新(5 处):tests/conftest.py、tests/contract/test_fund_query_demo_agent_contract.py、 tests/contract/test_risk_agent_contract.py、tests/unit/service/test_agent_governance.py (test_risk_agent_contract.py 里那个 StubGovernance 也补了转发 agent_type)。

4.2 app/service/knowledge_search_service.py(+79 −47)⚠️ 需你裁决

现象:合并后你的 search_knowledge 在我这台环境零召回且整条链路失败 —— Milvus 报 field doc_id not exist / field visibility not exist,三个集合全失败 → degraded=True → 客服对所有知识问题一律"引导人工"(实测连「基金申购后多久确认」都 failed)。

根因:两台机器的集合 schema 不同(这正是你评审 §1.3 指出的核心事实,我实测确认):

我这台(describe_collection 实测) 你那台(你实测)
标识字段 knowledge_id doc_id(主键)
正文 snippet content
可见性 无 visibility
来源/章节 无 source_file / chapter / section / doc_no
行数 106 / 177 / 73 125 / 297 / 214

所以"改读取侧字段名"这个方向本身是错的 —— 无论改成哪一套,都会把另一套打挂。 采纳你的方案(运行时探测),已实现:

# app/core/knowledge_schema.py(新增)
FIELD_CANDIDATES = {          # 逻辑名 → 该字段在各环境里可能的物理名(按优先级)
    "doc_id": ("doc_id", "knowledge_id"),
    "content": ("content", "snippet"),
    "visibility": ("visibility",),      # 可选:有就过滤,没有就跳过
    "source_file": ("source_file",),    # 同上(章节/编号同理)
    ...
}
REQUIRED_LOGICAL_FIELDS = ("doc_id", "content")   # 缺这两个 ⇒ 该集合判为不可用
# app/service/knowledge_search_service.py(改造)
schemas = {c: self._schema_for(client, c) for c in targets}   # 逐集合探测,按集合缓存
expression = self._visibility_filter(schemas, include_internal)  # 有 visibility 才拼
raw = client.search(..., output_fields=list(schema.output_fields))  # 只请求存在的字段

代价与边界(如实说明):

  • visibility 缺失的集合没有检索层内部资料隔离(我方 356 行均为对外知识,已核对); 你那台有该字段,过滤照常生效——所以这条能力不是被关掉,而是"按环境自动启用"。
  • 既无 doc_id 又无 knowledge_id(或既无 content 又无 snippet)的集合会被明确判为 不可用并记 degraded=True,不静默零召回——这是刻意的:静默零召回最难定位。

测试:新增 17 个探测单测;并把你那三个关键词召回用例参数化为两套 schema 各跑一遍 (tests/unit/service/test_knowledge_keyword_recall.py 的 SCHEMAS)。 任何回退到硬编码字段名的改动,都会让其中一侧立刻变红。

4.3 app/service/agent/implementations/customer_service.py(+137 −9)⚠️ 你的骨架 + 我的出口

保留你的全部实现(三档置信阈值、适当性裁决、闲聊、话题矩阵、_topic_of/_search_query/ _suitability_text 等方法一字未改——你的 3 个测试文件全绿即为证)。

新增:

  1. 出口零:画像问答(handle() 最前面加一次 is_profile_question() 判定);
  2. allowed_tools 增加 query_customer_profile(代码上限);
  3. 删掉 Agent 自己拼的 DISCLAIMER 常量及 3 处 f"...\n{DISCLAIMER}" —— 见 §4.5。

PROFILE_WHITELIST_INTENT = INTENT_FAQ:画像工具调用复用已发布的 faq 意图 key。 换新意图码会让 allowed_tools_by_intent 缺 key → 交集为空 → AGENT_PERMISSION_DENIED。

4.4 app/service/model_gateway.py(+53 −35)⚠️ 我改了你的映射表

你的版本把 intent_classification 映射成同名的 intent_classification;现库没有任何端点声明该能力 (实测 embedding-primary=["embedding"]、chat-primary=["chat"])⇒ 筛选得空集,靠你新加的 "空集 → 回退全部端点"才不至于失败。我改为映射到 chat(意图分类走 /chat/completions)。

同时并入你新增的 5 个风控 task_type,与我的映射合并成同一张表(REQUIRED_CAPABILITY_BY_TASK_TYPE, TASK_CAPABILITY 保留为别名指向它 —— 两个名字不要各存一份内容,那正是"修复被后续合并悄悄回退"的成因)。 你新加的"未登记 task_type 要告警留痕"我保留了(并补上了被你删掉的 logger 定义)。

4.5 app/service/agent/governance.py(+141 −5)

改动 说明
语境豁免 _first_violation 走 app/core/compliance_context.py,见 §3.3
客服热线白名单 CUSTOMER_SERVICE_HOTLINE = "15936583816" 不再被脱敏成 [手机号已脱敏](实测:客户拿不到联系方式)
免责声明限定范围 agent_type 判定,见 §4.1
免责声明重复的修复 见下

免责声明曾出现两条(Agent 自己拼一句 + 治理层追加权威话术):

## 第三章 客户风险等级划分
(以上内容由智能客服依据公司公开资料整理,不构成投资建议)      ← Agent 拼的
本内容仅为投资分析参考,不构成任何直接投资建议…                ← 治理层追加的

修法:话术只由治理层注入。理由:合规文案属发布配置,改文案不该改代码; 且治理层无法判断"业务是不是已经加过了"(它只认自己追加过的形状)。 副作用:customer_service.py 的 DISCLAIMER 常量被删除 → 你的 test_customer_service_topic_matrix.py 原本 from ...customer_service import DISCLAIMER,已改为从 governance 取 FALLBACK_DISCLAIMER (该测试只用它拼"治理后"的正文形状,断言对象是 _topic_of,语义不变)。

4.6 app/service/agent/bootstrap.py(+40 −0)

  • 补回 get_milvus_knowledge_writer()(知识向量写适配器装配入口;我的 Worker 依赖它, 返回 None 表示显式降级 —— 语义与你的 projection_cleaner 一致)。
  • 注册 query_customer_profile 工具(required_permission="memory:read:self")。

你新增的平台验证探针(PlatformProbeAgent + 两个探针工具)全部保留,与我的改动无交集。

4.7 app/worker/runtime.py(+50 −0)

  • 新增知识向量同步的装配:knowledge_writer / knowledge_embedder / knowledge_endpoint_resolver 三个注入点 + 降级告警只打一次。你新增的 relationships(图关系服务)保留,两段是并集。

4.8 其他被修改的你的文件(改动很小)

文件 改动
app/core/knowledge_contracts.py 两条链路的契约并存:你的 KnowledgeSearchInput + 本线的 ALLOWED_COLLECTIONS/VECTOR_DIM/intent_for_qa_id/KnowledgeQuery/KnowledgeHit/KnowledgeSearchResult。合并时一度误删后者,导致 23 个测试模块收集失败,已恢复并在文件头注明"删任何一半前先看两份引用点"
app/main.py 挂载知识库管理路由(knowledge_management_router)
tests/conftest.py 替身 review 转发 agent_type
tools/publish_customer_service_config.py 见 §4.9
tests/unit/service/test_knowledge_keyword_recall.py 替身字段名改成现库 schema(否则测试假绿:业务读到空 snippet 静默丢弃,断言又只查 doc_id)

4.9 配置发布(这是运行期必须的一步,请留意)

工具白名单是失败关闭的:ToolExecutor 取「代码 allowed_tools ∩ 发布配置 agent_tools/<agent>:<intent>」的交集,缺配置时交集为空 ⇒ 任何工具调用都被拒。

⚠️ 首先纠正我上一版的错误表述:config_release 是环境数据,不随代码合并。 我上一版写"216 已在共享库生效"是错的——你那台根本没有 216(你实测最高 201), 两台机器各自有独立的 config_release 表。下面这张表只描述我方环境:

环境 生效版本 customer_service:faq 白名单
我方(我发布的) id=216(我发的) [search_knowledge, query_customer_profile] ✅ 画像出口可用
你方(你维护的) id=201(你发的) [search_knowledge] ❌ 缺 query_customer_profile

⇒ 合并后你那台必须补发一版,把 customer_service:faq 改成 [search_knowledge, query_customer_profile],其余 8 条原样继承 (config_release 是整版本替换,漏带会清空别人的白名单)。 这一步由你来发——你已在评审里提出"我这边可以出脚本",我接受:配置属环境数据, 谁的环境谁发布,代码合并不该携带它。

发布脚本的一个坑(与我方无关,但你会踩到):tools/publish_customer_service_config.py 会把当前生效版本的配置项原样搬进新版本,而同 key 的继承项必须被本次新定义覆盖—— 否则旧值(例如已从代码上限移除的 query_knowledge)会被 admin 端的子集校验 422 拦下, 整次发布失败,而报错只有"配置超出 Agent 工具上限",看不出是继承造成的。 我方已改为"同 key 覆盖"并打印被替换的旧值,这个改动随代码合并给你。

⚠️ 顺带:fund_query_demo:fund_quote 这条白名单在我方环境的生效版本里不存在 (我发布时"当前生效版本配置项"只打印出 1 条),而你那边 201 里是有的 —— 这又是两台环境不一致的证据。我方的 FundQueryDemoAgent 需要补发才能调用工具; 你那台不受影响。


5. 验证证据(均可复现)

# 测试(合并后基线)
.\.venv\Scripts\python.exe -m pytest -q
# → 3 failed, 1218 passed, 2 skipped
#   1 个是既有缺陷(test_fund_readonly_contract 的空集问题,与本线无关)
#   2 个是环境相关(§5.1 已说明:断言方式依赖 JSON 序列化配置,非代码缺陷)

# 结构审计(证明未动 docs/00 基线)
.\.venv\Scripts\python.exe tools\audit_schema.py
# → schema audit passed: 51 business tables, no missing or unexpected tables

# 文档守卫(编号无冲突)
.\.venv\Scripts\python.exe tools\check_authoritative_docs.py
# → checked 32 documents, no number collision
#   顺带修了一处**同事那条线带入的重号**:`docs/15-金融NL2SQL工具接入说明.md` 与既有
#   `docs/15-Agent组员详细开发与使用手册.md` 撞号 → 新的那份让号到 `docs/27`(详见 §6)

5.1 两个环境相关失败(不是代码缺陷)

tests/unit/service/test_offsite_document_recognition_adapter.py 的 2 个用例断言 请求体里是中文原文("产品代码".encode() in requests[1].content), 而本机 httpx 把中文序列化成 \uXXXX,字节序列自然不匹配。

判定它既不是代码缺陷、也不是我引入的,有两条硬证据: ① 该测试文件与我合并的分支 origin/qyqy_develop 逐字节相同(git diff 无输出); ② 本机 .pytest_cache 的 lastfailed 里早已记录这两个用例(合并前的运行结果)。

功能无影响(OCR/LLM 请求本身正常)。建议改为断言 json.loads(body) 后的字段值—— 比字节级断言稳,也不受序列化配置影响。

5.2 mypy:这个数字不可比,我不拿它当结论(采纳你 §1.4)

你那边 mypy app 是 138 文件 0 错;我这边同一份代码报 184 个错。 根因不是代码质量差异,而是本机缺 SQLAlchemy 2.0 的类型信息:

本机(无存根)          mypy app → 184 errors
装 sqlalchemy2-stubs    mypy app →  43 errors   ← 该类存根是 2.0 之前的旧包,
                                                 还会换一批新错(mapped_column/DeclarativeBase 不存在)
卸载后                  mypy app → 184 errors

结论:本机 mypy 基线不可作为质量结论,两边也不可比。 但那 184 里有 8 个是我文件里的真实错误,已单独修掉:

文件 错数 处理
app/service/knowledge_retrieval_service.py 4 ✅ 已修
app/api/controllers/knowledge_management.py 3 ✅ 已修
app/service/model_gateway.py 2 ⏸ 未动:ModelEndpointConfig 实际具备协议要求的全部字段,属 Mapped[T] 在缺存根时的消解问题,不用 cast 掩盖
app/worker/runtime.py 1 ⏸ 未动:同类问题
其余 ~174 — 全在 app/model/*.py 与既有文件,属本机缺存根所致

若希望两边数字可比,需要固定 mypy 依赖版本或把"缺存根"写进已知限制 —— 属公共约定, 我没有擅自改 pyproject.toml 的 mypy 配置。

真机链路(真实 MySQL / Redis / Milvus / DashScope / HTTP,非单测替身):

场景 结果
知识问答「基金申购后多久确认」 succeeded,免责声明仅 1 条
知识问答「风险等级怎么划分」 succeeded(政策集合真实命中)
画像问答 9101 / 9001(测评过期) succeeded,过期被明说
知识库三端点 403 / 201 / 200 / 200+expired / 404 全绿
跨客户读画像 被拒(客户不可访问)

6. 需要你裁决 / 知晓的事项汇总

  1. AgentGovernance.review() 新增 agent_type 参数 —— 你已同意;审计留痕已按你要求补上 (§4.1)。若你更希望走别的判定途径(例如让 Agent 自己声明 customer_facing 属性),告诉我,我改。
  2. 检索字段名 —— ✅ 已按你 §1.3 改为运行时探测,不再是"三选一"(§4.2)。
  3. 删除 5 份编号文档 —— ✅ 已撤回,5 份全部恢复(你 §3.3 驳回)。
  4. docs/26-JWT密钥管理与轮换.md —— 是重命名(原 docs/21,因 21 已被你的《风控业务 第二版迁移清单》占用),不是新增、也不会与 docs/21 并存。
  5. config_release 是环境数据 —— 我方已发 216 且仅对我方环境有效;你那台需在合并后 补发(把 query_customer_profile 加进 customer_service:faq)。这一步你说你来出脚本,我接受。
  6. fund_query_demo:fund_quote 白名单 —— 在我方环境缺失(你那边 201 里有)。属环境差异, 我方需补发;你那台不受影响。
  7. 同事那条线带入的文档重号 —— docs/15-金融NL2SQL工具接入说明.md 与既有 docs/15-Agent组员详细开发与使用手册.md 撞号,我把新的那份让号到 docs/27 (依据:15-…手册 被 docs/16/17 与 AGENTS.md 三处引用,改名代价更大)。 若你认为该由旧的那份让号,我改回来。
  8. 同事那条线带入 11 个 alembic 迁移,我方已执行 alembic upgrade heads 建出 offsite_* / promotion_* 等表(本库此前一张都没有,而 alembic_version 却已指向 同事的 revision —— 属"版本号跑了但表没建"的状态)。你那台若也这样,合并后需补跑迁移。

7. 已知限制(未做,不是遗漏)

  1. 画像链路"生产端已接、消费端未接" —— 与你 §4 的发现同源但不同表现,请一起裁决归属:

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

    ⇒ 同一类问题:组件写好了、线没接。 我这台更进一步:事件已经写进表里、没人消费。 建议先定归属再动手(涉及 app/worker/ 与 app/service/profile_*,跨你我两条线), 否则两边各接一根线会更乱。

  2. mypy —— 见 §5.2:本机数字不可比(缺 SQLAlchemy 2.0 类型信息);我文件里的 8 个真实错误已修, 其余未动。没有擅自改 mypy 配置。

  3. Redis 限流降级:容器以 --requirepass 123456 启动而 .env 无密码 ⇒ 每次请求一条 AuthenticationError 堆栈、限流形同虚设(不阻断业务)。属本地环境配置,未擅自修改。

  4. Docker Desktop 不常驻:它没运行时 Milvus 不可用(docker CLI 报连不上守护进程)。 我方已把这条写进 AGENTS.md 的环境口径。

  5. 5 份恢复的文档没有内容校对 —— docs/04/06/10/13/99 只做了"恢复",未逐字核对 其正确性(它们此前被判定为内容过期)。已在 AGENTS.md 的 D 类里标注"仅作历史参考", 但不排除其中仍有会误导读者的内容——若你要用它们,建议先过一遍。


本说明由 2026-09-11 的收尾会话产出;第二次修订在评审意见之后(见 §0)。 若你发现与代码不一致,以代码与 docs/05 为准。