Files
group_fqcd_jr/tools/probe_release_state.py
lzf_0626 927a6fecc0 评审 NL_develop 交付说明:三个环境前提必须先对齐
产出 docs/NL_develop交付说明-评审意见.md(可直接转给组员),以及一个只读探查工具
tools/probe_knowledge_collections.py(Milvus 集合 schema 与行数)。

核查中发现的硬矛盾,都有可复核的证据:

1. 配置库不是同一个。对方说 active=216、合并前生效版本是 186;我这边实测 active=201,
   最近 5 条 id 就是 201/198/197/196/195 —— release.id 自增,同库不可能一边 216 一边 201。
   所以他以为已发布的 customer_service:faq=[search_knowledge, query_customer_profile]
   在这边并不存在,而他的画像出口复用的正是这个 key ⇒ 合并后被 ToolExecutor 失败关闭。
   同理他说的 fund_query_demo:fund_quote 缺失,我这边是存在的。

2. Milvus 也不是同一个。对方说现库字段是 knowledge_id/snippet、无 visibility、行数
   106/177/73;我这边实测是 doc_id/content/chapter/section/.../visibility 共 15 个字段、
   行数 125/297/214,且与 knowledge_search_service.py 的 OUTPUT_FIELDS 逐字一致。
   他这次的字段映射改动(doc_id→knowledge_id)在这边会直接报 field knowledge_id not
   exist,把客服知识检索整条打挂 —— 比他自述的"关闭 visibility 隔离"严重得多。
   建议不是 A/B/C 三选一,而是第四种:运行时探测字段名,两套 schema 都能跑。

3. 解释器不同。他用 .venv(项目里不存在,那是他机器上的 gitignore 目录),约定是
   D:\conda\envs\jr_py313。所以"mypy 151→181"跑不到本基线 —— 这边是 138 文件 0 错。

另指出:docs/26-JWT密钥管理与轮换.md 会与已存在的 docs/21-JWT密钥管理与轮换.md 重复,
建议并入 21;驳回删除 docs/04/06/10/13/99。

四项待裁决的答复:同意 agent_type 方案(要求补审计);字段映射改为运行时探测;
驳回删除编号文档;26 并入 21。
2026-09-11 16:51:52 +08:00

113 lines
3.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""只读探查:当前 active 配置发布与配置项数量(用于同步 docs/24 的"当前状态"表)。
只做 SELECT,结果写 `docs/evidence/release-state.json`:
python tools/probe_release_state.py
"""
from __future__ import annotations
import asyncio
import json
from pathlib import Path
from typing import Any
from sqlalchemy import text
from app.infrastructure.db import SessionFactory
OUTPUT = Path("docs/evidence/release-state.json")
async def collect() -> dict[str, Any]:
report: dict[str, Any] = {}
async with SessionFactory() as session:
report["recent_releases"] = [
dict(row)
for row in (
(
await session.execute(
text(
"""
SELECT id, release_no, title, status, created_at, activated_at
FROM config_release
ORDER BY id DESC
LIMIT 5
"""
)
)
)
.mappings()
.all()
)
]
report["active_items"] = [
dict(row)
for row in (
(
await session.execute(
text(
"""
SELECT i.namespace, COUNT(*) AS items
FROM platform_config_item i
JOIN config_release r ON r.id = i.release_id
WHERE r.status = 'active'
GROUP BY i.namespace
ORDER BY i.namespace
"""
)
)
)
.mappings()
.all()
)
]
report["active_prompt_versions"] = (
await session.execute(
text(
"""
SELECT COUNT(*) FROM prompt_template_version p
JOIN config_release r ON r.id = p.release_id
WHERE r.status = 'active'
"""
)
)
).scalar_one()
# 工具白名单的**具体内容**:它必须与代码里的 allowed_tools 交集非空,
# 否则 ToolExecutor 失败关闭,Agent 任何工具调用都被拒。
report["active_agent_tools"] = [
dict(row)
for row in (
(
await session.execute(
text(
"""
SELECT i.config_key, i.value_json, i.schema_version
FROM platform_config_item i
JOIN config_release r ON r.id = i.release_id
WHERE r.status = 'active' AND i.namespace = 'agent_tools'
ORDER BY i.config_key
"""
)
)
)
.mappings()
.all()
)
]
return report
async def main() -> None:
report = await collect()
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
OUTPUT.write_text(
json.dumps(report, ensure_ascii=False, indent=2, default=str),
encoding="utf-8",
)
print(f"wrote {OUTPUT}")
if __name__ == "__main__":
asyncio.run(main())