答复文档补充 §8:两个既有发布脚本会丢提示词(写补发脚本时发现)

publish_customer_service_config.py 与 publish_risk_agent_config.py 的
active_config_items() 都自己写 SQL、只查 platform_config_item,而
ConfigReleaseService.effective_snapshot() 要读全部三张受管表。用它们发版会把生效版本里的
提示词一起清掉 —— 且没有任何声音:_warn_dropped_items() 只告警不阻断激活,Agent 侧
_chitchat_prompt 有兜底会回落代码默认值,功能看着正常(与 release 174 那次事故同型)。

已在答复文档里建议改用 effective_snapshot(),并列出三个细节:同 key 覆盖(对方已修)、
JSON 列必须归一化(SELECT * 读出来可能是字符串,不解析会静默走进"没有该 key"分支)、
提示词搬家要重分配 version 且按 PromptPayload 字段挑(漏 input_schema/output_schema 即丢)。

另提醒时序:admin 端校验「配置 ⊆ 代码 allowed_tools」,画像工具那一版必须等代码合并后才能发,
否则 422 且报错只有"配置超出 Agent 工具上限"。
This commit is contained in:
2026-09-11 19:52:08 +08:00
parent 6c09cdecbd
commit 8268646b0c
@@ -210,3 +210,48 @@ alembic:current = heads = 20260911_risk_rule_index ← 单一 head,只有
> 最后回应你 §1.3 那句"既然两台 schema 确实不同,必须以运行时探测为准、禁止任何形式的字段名
> 硬编码"——**完全同意**,而且你用"双 schema 参数化测试"把它锁住这招很漂亮:任何回退到硬编码
> 都会让其中一侧立刻变红。比我原来担心的"靠人记住"可靠得多。
---
## 8. 补充发现(写补发脚本时挖出来的):两个发布脚本会**丢提示词**
我按你提醒的"同 key 覆盖"去写补发脚本时,顺手核了一下**继承源**,发现一个真问题:
`tools/publish_customer_service_config.py` 与 `tools/publish_risk_agent_config.py` 的
`active_config_items()` 都是**自己写 SQL、只查 `platform_config_item`**:
```sql
SELECT i.namespace, 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'
```
而 `ConfigReleaseService.effective_snapshot()` 的文档字符串写得很清楚 —— 你自己在
`publish_chitchat_prompt.py` 里也引用过这条:
> 快照读的是**全部三张**受管表(`platform_config_item` / `prompt_template_version` /
> `model_routing_rule`),**漏读一张就是一次静默失效** —— 这次的事故正是这么来的。
**⇒ 用这两个脚本发版,会把生效版本里的提示词一起清掉。**(本环境 201 里有 1 条
`customer_service_chitchat` v2。)
而且这个失败**没有任何声音**:`_warn_dropped_items()` 只告警、不阻断激活,Agent 侧
`_chitchat_prompt` 又有逐字段兜底、会回落代码默认值 —— **功能看着正常**,
和 release 174 那次事故一模一样。
**建议**:把这两个脚本的 `active_config_items()` 换成
`ConfigReleaseService(session).effective_snapshot()`。我已经在新的
`tools/publish_profile_tool_whitelist.py` 里这么做了,顺带处理了三个细节,供你参考:
1. **同 key 覆盖**(你已经修了,很好);
2. **JSON 列必须归一化** —— `SELECT *` 读出来的 `value_json` 可能是**字符串**,
不 `json.loads` 的话 `isinstance(value, dict)` 为假,脚本会**静默**走到"生效版本里没有
该 key"那条分支。我第一版就踩了这个,靠加诊断打印才定位到(表现出来像"配置缺失");
3. **提示词搬家要重分配 `version`**(唯一键含 version),并按 `PromptPayload` 的 9 个字段
挑字段 —— 表里的 `checksum`/`created_by`/`created_at` 是服务端生成的不能搬,
而 `input_schema`/`output_schema` 是 API 收的、漏了就丢。
**时序提醒**:admin 端校验「配置 ⊆ 代码 `allowed_tools`」(`app/service/admin_service.py:219-220`),
所以**画像工具那一版必须在你的代码合并进来之后才能发**,否则必然 422,而报错只有
"配置超出 Agent 工具上限"(看不出是时序问题)。我在脚本里加了前置自检:合并前跑会直接中止
并说明原因,而不是抛出那个费解的校验错。