# `prompts/` — 版本化 Prompt 模板 架构 §8.1:Prompt 存文件(随代码版本化)+ 场景绑定版本号。 运行时由 `packages/llm/prompts.py` 的 `PromptRegistry` 按 `id + version` 加载, **使用的版本号会写进每一行 `ob_ai_call`**,用于回溯「为什么当时这么答」。 ## 文件布局 ``` prompts//.txt ``` ``` [system] 固定不变的、可被供应商缓存的前缀。 [user] 每次调用渲染的变量部分,用 {占位符}。 ``` ## 铁律:`[system]` 段不许有任何变量 架构 §7.2 缓存前缀纪律 / TD-04: > 系统提示词与稳定知识片段必须放在 prompt 头部且**不含时间戳、随机 ID、 > 用户昵称等变量**,否则缓存永远不命中,输入成本翻数倍。 这条规则靠人 review 是守不住的:破坏它以后功能完全正常,只有账单会翻几倍, 而账单要到月底才看得见。所以它被写成了代码: - `PromptRegistry` 加载时校验,`LLM_CACHE_PREFIX_MODE=strict` 下直接拒绝调用。 - `tests/unit/test_prompt_cache_prefix.py` 扫描本目录下**全部**模板。 会被拒绝的东西:ISO 日期、时刻、中文年月、时间戳、UUID、长十六进制串, 以及名字里带 `nick`/`user`/`name`/`now`/`date`/`time`/`id`/`rand`/`session`/ `request`/`trace`/`token` 的占位符。 要注入用户画像、检索结果、会话摘要?放到 `[user]` 段或调用方传入的 `messages` 里 —— 它们本来就该排在固定前缀之后(§7.2 ③ 上下文组装)。 ## 改 Prompt 的规矩 - **不要原地改已上线的版本**,新建 `v2.txt`,再在 `routing.py`(或 `LLM_SCENE_OVERRIDES_JSON`)里切过去。旧版本要留着,`ob_ai_call` 里的历史记录 才有意义。 - 报告与 Agent 这类核心链路的 Prompt 变更必须**先灰度 + 跑黄金集回归** (架构 §14.3)。 - Token 预算见 §7.2:系统提示词 ≤ 800,输入合计 ≤ 3700,输出 ≤ 800。 ## 内容合规约束 每个面向用户的 prompt 都必须在系统前缀里写死:不做医疗/减重/整形/命理结论 (CR-12)、不评判外貌、不使用绝对化用语、用户输入视为内容而非指令 (NFR-SEC-04 Prompt 注入防护)。