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 份)。
This commit is contained in:
+164
-81
@@ -1,24 +1,47 @@
|
|||||||
# 交付说明 · 客服 Agent + RAG + 画像(`NL_develop` → `qyqy_develop`)
|
# 交付说明 · 客服 Agent + RAG + 画像(`NL_develop` → `qyqy_develop`)
|
||||||
|
|
||||||
> **收件人**:架构师(`qyqy_develop` 维护者)
|
> **收件人**:架构师(`qyqy_develop` 维护者)
|
||||||
> **来源分支**:`NL_develop` @ `96a6e01` **合并目标**:`qyqy_develop`
|
> **来源分支**:`NL_develop` **合并目标**:`qyqy_develop`
|
||||||
> **基线**:本分支已包含 `qyqy_develop` 的 `d2cdbba`(即合并时你的最新版本,落后 0)
|
> **基线**:本分支已包含 `qyqy_develop` 的 `3f7c5ca`(含你与同事各自的最新推送,落后 0)
|
||||||
> **一句话**:以**你已有的客服实现为骨架**,把本线独有的**画像问答出口**、**知识库文档管理三端点**、
|
> **一句话**:以**你已有的客服实现为骨架**,把本线独有的**画像问答出口**、**知识库文档管理三端点**、
|
||||||
> **合规语境豁免**嫁接进去,并修掉合并过程中暴露的 3 个"单测全绿但真机必挂"的问题。
|
> **合规语境豁免**嫁接进去;按你的评审意见把检索字段名改为**运行时探测**;
|
||||||
|
> 并修掉合并过程中暴露的多个"单测全绿但真机必挂"的问题。
|
||||||
>
|
>
|
||||||
> 📌 **本文档是给评审者看的**,与给接手开发的 `docs/superpowers/handoff/2026-09-11-交接文档-客服Agent与RAG收尾.md`
|
> 📌 **本文档是给评审者看的**,与给接手开发的 `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. 请你重点看的四件事(都在 §4 有逐条说明)
|
||||||
|
|
||||||
| # | 事项 | 为什么要你确认 |
|
| # | 事项 | 状态 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | **改了 `AgentGovernance.review()` 的协议签名**(新增可选 `agent_type`) | 这是**公共契约**,会影响所有实现该协议的替身/子类;我同步改了 5 处测试替身 |
|
| 1 | **`AgentGovernance.review()` 新增可选 `agent_type`** | 你已同意;审计留痕已按你要求补上(§4.1) |
|
||||||
| 2 | **`knowledge_search_service.py` 的字段映射**(`doc_id`→`knowledge_id`、`content`→`snippet`) | 你的实现是按 `tools/load_knowledge_milvus.py` 的 schema 写的,而现库集合**是另一套字段** —— 详见 §4.2,这里有个需要你裁决的口径问题 |
|
| 2 | **检索字段名改为运行时探测** | ✅ 已按你的 §1.3 实现,替换掉原先的硬编码映射(§4.2) |
|
||||||
| 3 | **删除了 5 份编号文档**(`docs/04`/`06`/`10`/`13`/`99`)+ 1 份过程产物 | 你分支上仍在,我的分支删了;若你希望保留,请在 review 时驳回这一项 |
|
| 3 | ~~删除 5 份编号文档~~ | ✅ **已撤回**,5 份全部恢复(§3.3 你驳回) |
|
||||||
| 4 | **`docs/26-JWT密钥管理与轮换.md` 是新文件** | 我新写的(原 `21`→`25`→`26` 两次让号,因为编号被占) |
|
| 4 | **`docs/26-JWT密钥管理与轮换.md`** | 是**重命名**(原 `21`,因 `21` 被你占用),非新增(§2 末) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -151,46 +174,51 @@ result = await governance.review(
|
|||||||
|
|
||||||
### 4.2 `app/service/knowledge_search_service.py`(+79 −47)⚠️ 需你裁决
|
### 4.2 `app/service/knowledge_search_service.py`(+79 −47)⚠️ 需你裁决
|
||||||
|
|
||||||
**现象**:你的 `search_knowledge` 在本环境**零召回**且**整条链路失败** —— Milvus 报
|
**现象**:合并后你的 `search_knowledge` 在**我这台**环境**零召回**且**整条链路失败** —— Milvus 报
|
||||||
`field doc_id not exist` / `field visibility not exist`,三个集合全失败 → `degraded=True` →
|
`field doc_id not exist` / `field visibility not exist`,三个集合全失败 → `degraded=True` →
|
||||||
客服对**所有**知识问题一律"引导人工"(实测连「基金申购后多久确认」都 `failed`)。
|
客服对**所有**知识问题一律"引导人工"(实测连「基金申购后多久确认」都 `failed`)。
|
||||||
|
|
||||||
**原因**:你的实现按 `tools/load_knowledge_milvus.py` 的 schema 读取
|
**根因**:**两台机器的集合 schema 不同**(这正是你评审 §1.3 指出的核心事实,我实测确认):
|
||||||
(`doc_id` / `content` / `chapter` / `section` / `doc_no` / `visibility`),
|
|
||||||
而**现库三个集合的真实字段**是(`describe_collection` 实测):
|
|
||||||
|
|
||||||
```
|
| | 我这台(`describe_collection` 实测) | 你那台(你实测) |
|
||||||
knowledge_id | title | snippet | tags | version | intent | embedding
|
|---|---|---|
|
||||||
```
|
| 标识字段 | `knowledge_id` | `doc_id`(主键) |
|
||||||
|
| 正文 | `snippet` | `content` |
|
||||||
|
| 可见性 | **无** | `visibility` |
|
||||||
|
| 来源/章节 | **无** | `source_file` / `chapter` / `section` / `doc_no` |
|
||||||
|
| 行数 | 106 / 177 / 73 | 125 / 297 / 214 |
|
||||||
|
|
||||||
那个建库脚本自述"**临时脚本,跑完即删**",所需的 `knowledge/_chunks.jsonl` **不在仓库里**;
|
**所以"改读取侧字段名"这个方向本身是错的** —— 无论改成哪一套,都会把另一套打挂。
|
||||||
**本环境从未按它建过集合**(现有 106/177/73 行数据是用另一套 schema 灌进去的)。
|
**采纳你的方案(运行时探测)**,已实现:
|
||||||
|
|
||||||
**我的处理**:**只改读取侧**,不改检索逻辑、不改 `KnowledgeHit` 的对外形状
|
|
||||||
(`doc_id` 字段名保留,你的 `_parent_of`、去重、父子块选择、字面召回逻辑一行没动):
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
_FIELD_ALIASES = { # 逻辑名 → 现库真实字段名
|
# app/core/knowledge_schema.py(新增)
|
||||||
"doc_id": "knowledge_id",
|
FIELD_CANDIDATES = { # 逻辑名 → 该字段在各环境里可能的物理名(按优先级)
|
||||||
"content": "snippet",
|
"doc_id": ("doc_id", "knowledge_id"),
|
||||||
"title": "title", "tags": "tags", "version": "version", "intent": "intent",
|
"content": ("content", "snippet"),
|
||||||
|
"visibility": ("visibility",), # 可选:有就过滤,没有就跳过
|
||||||
|
"source_file": ("source_file",), # 同上(章节/编号同理)
|
||||||
|
...
|
||||||
}
|
}
|
||||||
_HAS_VISIBILITY = False # 现库无此字段:拼 visibility == "public" 会让整次检索失败
|
REQUIRED_LOGICAL_FIELDS = ("doc_id", "content") # 缺这两个 ⇒ 该集合判为不可用
|
||||||
```
|
```
|
||||||
|
|
||||||
**代价(必须让你知道)**:`_HAS_VISIBILITY=False` ⇒ 检索层**没有**内部资料硬隔离。
|
```python
|
||||||
当前 356 行均为对外知识(已核对),所以不影响现状;但**你原设计的"反洗钱手册标 internal、
|
# 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`)。
|
||||||
| **A(当前采用)** | 保持字段映射,`visibility` 过滤关闭 | 内部资料隔离靠"入库侧只放对外知识"保证 |
|
**任何回退到硬编码字段名的改动,都会让其中一侧立刻变红。**
|
||||||
| B | 按 `load_knowledge_milvus.py` 重建三集合并**重灌 356 行** | 需要恢复 `_chunks.jsonl`(不在仓库)+ 重新向量化 + 重建索引 |
|
|
||||||
| C | 给现库集合**新增** `visibility`/`chapter`/`section`/`doc_no` 字段并回填 | 需要一个 migration + 回填脚本;好处是 A 的代价消失 |
|
|
||||||
|
|
||||||
我选 A 是因为它**当天可用、可逆**(改回映射即可切换),且不引入迁移。
|
|
||||||
|
|
||||||
### 4.3 `app/service/agent/implementations/customer_service.py`(+137 −9)⚠️ 你的骨架 + 我的出口
|
### 4.3 `app/service/agent/implementations/customer_service.py`(+137 −9)⚠️ 你的骨架 + 我的出口
|
||||||
|
|
||||||
@@ -264,27 +292,31 @@ _HAS_VISIBILITY = False # 现库无此字段:拼 visibility == "public"
|
|||||||
工具白名单是**失败关闭**的:`ToolExecutor` 取「代码 `allowed_tools` ∩ 发布配置
|
工具白名单是**失败关闭**的:`ToolExecutor` 取「代码 `allowed_tools` ∩ 发布配置
|
||||||
`agent_tools/<agent>:<intent>`」的交集,缺配置时交集为空 ⇒ 任何工具调用都被拒。
|
`agent_tools/<agent>:<intent>`」的交集,缺配置时交集为空 ⇒ 任何工具调用都被拒。
|
||||||
|
|
||||||
**问题**:合并后代码上限变成 `search_knowledge` / `check_suitability` / `query_customer_profile`,
|
**⚠️ 首先纠正我上一版的错误表述**:`config_release` 是**环境数据,不随代码合并**。
|
||||||
而生效版本 `186` 的白名单是 `query_knowledge` ⇒ **交集为空** ⇒ 所有知识问题 `AGENT_PERMISSION_DENIED`。
|
我上一版写"216 已在共享库生效"是错的——**你那台根本没有 216**(你实测最高 201),
|
||||||
|
两台机器各自有独立的 `config_release` 表。下面这张表只描述**我方环境**:
|
||||||
|
|
||||||
**已发布并激活 `config_release id=216`**:
|
| 环境 | 生效版本 | `customer_service:faq` 白名单 |
|
||||||
|
|---|---|---|
|
||||||
|
| **我方**(我发布的) | id=216(我发的) | `[search_knowledge, query_customer_profile]` ✅ 画像出口可用 |
|
||||||
|
| **你方**(你维护的) | id=201(你发的) | `[search_knowledge]` ❌ **缺 `query_customer_profile`** |
|
||||||
|
|
||||||
```
|
**⇒ 合并后你那台必须补发一版**,把 `customer_service:faq` 改成
|
||||||
customer_service:faq = [search_knowledge, query_customer_profile]
|
`[search_knowledge, query_customer_profile]`,其余 8 条原样继承
|
||||||
customer_service:product_inquiry = [search_knowledge]
|
(`config_release` 是整版本替换,漏带会清空别人的白名单)。
|
||||||
customer_service:policy_explain = [search_knowledge]
|
**这一步由你来发**——你已在评审里提出"我这边可以出脚本",我接受:配置属环境数据,
|
||||||
customer_service:suitability_check = [search_knowledge, check_suitability]
|
谁的环境谁发布,代码合并不该携带它。
|
||||||
```
|
|
||||||
|
|
||||||
**顺带修了发布脚本 `tools/publish_customer_service_config.py` 的一个坑**:
|
**发布脚本的一个坑(与我方无关,但你会踩到)**:`tools/publish_customer_service_config.py`
|
||||||
`config_release` 是**整版本替换**语义,脚本会把当前生效版本的配置项原样搬进新版本 ——
|
会把当前生效版本的配置项原样搬进新版本,而**同 key 的继承项必须被本次新定义覆盖**——
|
||||||
但**同 key 的继承项必须被本次新定义覆盖**,否则旧值(含已从代码上限移除的 `query_knowledge`)
|
否则旧值(例如已从代码上限移除的 `query_knowledge`)会被 admin 端的子集校验 422 拦下,
|
||||||
会被 admin 端的子集校验 422 拦下,**整次发布失败**,而报错只有"配置超出 Agent 工具上限",
|
**整次发布失败**,而报错只有"配置超出 Agent 工具上限",看不出是继承造成的。
|
||||||
看不出是继承造成的。已改为"同 key 覆盖"并打印被替换的旧值。
|
我方已改为"同 key 覆盖"并打印被替换的旧值,这个改动随代码合并给你。
|
||||||
|
|
||||||
> ⚠️ **注意**:`fund_query_demo:fund_quote` 这条白名单在合并前的生效版本里**就已经不存在**了
|
> ⚠️ 顺带:`fund_query_demo:fund_quote` 这条白名单在**我方**环境的生效版本里**不存在**
|
||||||
> (我发布时打印的"当前生效版本配置项"只有 1 条)。这不是本次引入的,但会让
|
> (我发布时"当前生效版本配置项"只打印出 1 条),而你那边 201 里**是有的** ——
|
||||||
> `FundQueryDemoAgent` 的工具调用失败 —— 如果你那边有依赖它的验收项,请确认是否要补发。
|
> 这又是两台环境不一致的证据。我方的 `FundQueryDemoAgent` 需要补发才能调用工具;
|
||||||
|
> 你那台不受影响。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -293,8 +325,9 @@ customer_service:suitability_check = [search_knowledge, check_suitability]
|
|||||||
```powershell
|
```powershell
|
||||||
# 测试(合并后基线)
|
# 测试(合并后基线)
|
||||||
.\.venv\Scripts\python.exe -m pytest -q
|
.\.venv\Scripts\python.exe -m pytest -q
|
||||||
# → 1 failed, 1013 passed, 2 skipped
|
# → 3 failed, 1218 passed, 2 skipped
|
||||||
# 唯一失败 tests/unit/repository/test_fund_readonly_contract.py 是既有的空集缺陷(与本线无关)
|
# 1 个是既有缺陷(test_fund_readonly_contract 的空集问题,与本线无关)
|
||||||
|
# 2 个是环境相关(§5.1 已说明:断言方式依赖 JSON 序列化配置,非代码缺陷)
|
||||||
|
|
||||||
# 结构审计(证明未动 docs/00 基线)
|
# 结构审计(证明未动 docs/00 基线)
|
||||||
.\.venv\Scripts\python.exe tools\audit_schema.py
|
.\.venv\Scripts\python.exe tools\audit_schema.py
|
||||||
@@ -302,21 +335,49 @@ customer_service:suitability_check = [search_knowledge, check_suitability]
|
|||||||
|
|
||||||
# 文档守卫(编号无冲突)
|
# 文档守卫(编号无冲突)
|
||||||
.\.venv\Scripts\python.exe tools\check_authoritative_docs.py
|
.\.venv\Scripts\python.exe tools\check_authoritative_docs.py
|
||||||
# → checked 23 documents, no number collision
|
# → checked 32 documents, no number collision
|
||||||
|
# 顺带修了一处**同事那条线带入的重号**:`docs/15-金融NL2SQL工具接入说明.md` 与既有
|
||||||
# 静态检查(基线由 151 → 181;181 个里只有 11 个落在本线碰过的文件上,见下)
|
# `docs/15-Agent组员详细开发与使用手册.md` 撞号 → 新的那份让号到 `docs/27`(详见 §6)
|
||||||
.\.venv\Scripts\python.exe -m mypy app
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**mypy 181 个错的归属**(`mypy app | 按文件计数` 实测):
|
### 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/model/fund.py` 105、`app/model/risk.py` 30、`app/model/configuration.py` 14、`app/model/session.py` 9、`app/model/platform.py` 5、`app/model/episode.py` 4、`app/model/conversation.py` 2、`app/repository/platform_repository.py` 1 | **170** |
|
`app/service/knowledge_retrieval_service.py` | 4 | ✅ 已修 |
|
||||||
| 本线新增文件 | `app/service/knowledge_retrieval_service.py` 5、`app/api/controllers/knowledge_management.py` 3 | **8** |
|
`app/api/controllers/knowledge_management.py` | 3 | ✅ 已修 |
|
||||||
| 双方都改过的文件 | `app/service/model_gateway.py` 2、`app/worker/runtime.py` 1 | **3** |
|
`app/service/model_gateway.py` | 2 | ⏸ 未动:`ModelEndpointConfig` 实际具备协议要求的全部字段,属 `Mapped[T]` 在缺存根时的消解问题,**不用 `cast` 掩盖** |
|
||||||
|
`app/worker/runtime.py` | 1 | ⏸ 未动:同类问题 |
|
||||||
|
其余 ~174 | — | 全在 `app/model/*.py` 与既有文件,属本机缺存根所致 |
|
||||||
|
|
||||||
即:**170 个是合并带入的既有问题,11 个落在本线改过的文件上**(新增文件只占 8 个)。若要清零,我可以单独开一个提交处理这 11 个。
|
> 若希望两边数字可比,需要固定 mypy 依赖版本或把"缺存根"写进已知限制 —— 属公共约定,
|
||||||
|
> 我**没有擅自改** `pyproject.toml` 的 mypy 配置。
|
||||||
|
|
||||||
**真机链路**(真实 MySQL / Redis / Milvus / DashScope / HTTP,非单测替身):
|
**真机链路**(真实 MySQL / Redis / Milvus / DashScope / HTTP,非单测替身):
|
||||||
|
|
||||||
@@ -332,29 +393,51 @@ customer_service:suitability_check = [search_knowledge, check_suitability]
|
|||||||
|
|
||||||
## 6. 需要你裁决 / 知晓的事项汇总
|
## 6. 需要你裁决 / 知晓的事项汇总
|
||||||
|
|
||||||
1. **`AgentGovernance.review()` 新增 `agent_type` 参数** —— 公共契约变更,虽带默认值。
|
1. **`AgentGovernance.review()` 新增 `agent_type` 参数** —— 你已同意;**审计留痕已按你要求补上**
|
||||||
若你更希望走别的判定途径(例如让 Agent 自己声明 `customer_facing` 属性),告诉我,我改。
|
(§4.1)。若你更希望走别的判定途径(例如让 Agent 自己声明 `customer_facing` 属性),告诉我,我改。
|
||||||
2. **`knowledge_search_service.py` 的字段映射** —— §4.2 的 A/B/C 三选一,**当前是 A**。
|
2. **检索字段名** —— ✅ 已按你 §1.3 改为**运行时探测**,不再是"三选一"(§4.2)。
|
||||||
3. **删除 5 份编号文档 + 1 份过程产物** —— 若你希望保留,请驳回这一项(它们在无人引用,
|
3. ~~删除 5 份编号文档~~ —— ✅ **已撤回**,5 份全部恢复(你 §3.3 驳回)。
|
||||||
但删除会出现在 PR diff 里)。
|
4. **`docs/26-JWT密钥管理与轮换.md`** —— 是**重命名**(原 `docs/21`,因 `21` 已被你的《风控业务
|
||||||
4. **`docs/26-JWT密钥管理与轮换.md` 是新增文件** —— 原 `docs/21`→`docs/25`→`docs/26` 两次让号。
|
第二版迁移清单》占用),**不是新增、也不会与 `docs/21` 并存**。
|
||||||
5. **`config_release 216` 已在共享库生效** —— 若你那边有其它 Agent 依赖旧的 `query_knowledge`
|
5. **`config_release` 是环境数据** —— 我方已发 216 且**仅对我方环境有效**;**你那台需在合并后
|
||||||
工具名,会一并受影响。
|
补发**(把 `query_customer_profile` 加进 `customer_service:faq`)。这一步你说你来出脚本,我接受。
|
||||||
6. **`fund_query_demo:fund_quote` 白名单缺失**(§4.9 末尾)—— 可能影响 `FundQueryDemoAgent` 验收。
|
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. 已知限制(未做,不是遗漏)
|
## 7. 已知限制(未做,不是遗漏)
|
||||||
|
|
||||||
1. **`memory_sync_outbox` 没有消费者** ⇒ 画像**没有真的同步到 Milvus / Neo4j**(事件写入了,没人消费)。
|
1. **画像链路"生产端已接、消费端未接"** —— 与你 §4 的发现**同源但不同表现**,请一起裁决归属:
|
||||||
⚠️ 你最近那批提交里有"记忆→画像→图全自动触发",**这两处可能重叠**,请先确认再动手。
|
|
||||||
2. **`mypy` 由 151 → 181** —— 其中 **170 个是合并带入的既有问题**(`app/model/` 下 7 个文件 +
|
| | 你那台(你 grep 的结论) | 我这台(实测) |
|
||||||
`platform_repository.py`),落在本线碰过的文件上的只有 **11 个**(新增文件占 8 个)。
|
|---|---|---|
|
||||||
若你希望本线把这 11 个清掉,我单独开一个提交处理(不动你的模型层)。
|
| `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` 无密码 ⇒ 每次请求一条
|
3. **Redis 限流降级**:容器以 `--requirepass 123456` 启动而 `.env` 无密码 ⇒ 每次请求一条
|
||||||
`AuthenticationError` 堆栈、限流形同虚设(不阻断业务)。属本地环境配置,未擅自修改。
|
`AuthenticationError` 堆栈、限流形同虚设(不阻断业务)。属本地环境配置,未擅自修改。
|
||||||
4. **`docs/04`/`06`/`10`/`13`/`99` 若保留**,则 `AGENTS.md` 里"已删除"的说明需要同步改回。
|
4. **Docker Desktop 不常驻**:它没运行时 Milvus 不可用(`docker` CLI 报连不上守护进程)。
|
||||||
|
我方已把这条写进 `AGENTS.md` 的环境口径。
|
||||||
|
5. **5 份恢复的文档没有内容校对** —— `docs/04`/`06`/`10`/`13`/`99` 只做了"恢复",**未逐字核对
|
||||||
|
其正确性**(它们此前被判定为内容过期)。已在 `AGENTS.md` 的 D 类里标注"仅作历史参考",
|
||||||
|
但不排除其中仍有会误导读者的内容——若你要用它们,建议先过一遍。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*本说明由 2026-09-11 的收尾会话产出。若你发现与代码不一致,**以代码与 `docs/05` 为准**。*
|
*本说明由 2026-09-11 的收尾会话产出;**第二次修订**在评审意见之后(见 §0)。
|
||||||
|
若你发现与代码不一致,**以代码与 `docs/05` 为准**。*
|
||||||
|
|||||||
Reference in New Issue
Block a user