Prompt 为什么会产生维护债务?
简化版
Prompt 会因例外不断追加、规则重复冲突、动态变量隐式耦合和模型升级而产生维护债务:没人知道某句话为何存在,改一处可能伤另一个场景。治理方法是模块化模板、类型化变量、单一规则源、版本与变更说明、冻结回归集;确定性业务逻辑和权限应移到代码或策略引擎。
详细版
债务信号包括 Prompt 只增不减、同一规则出现多次、if/else 用自然语言嵌套、线上直接编辑、无法复现历史输出,以及模型/检索/解析器版本未绑定。短期补一句能修 case,长期会提高 Token 成本、引入矛盾并让评测对旧错误过拟合。
可把 Prompt 拆为 policy、task、context、examples、output schema 等模块,每个模块有 owner、版本和测试;渲染后保存哈希与依赖。变更走代码评审、离线回归、灰度与回滚。定期统计长度、重复规则、变量数量、失败簇和无效条款,做删除实验;当规则能确定执行时改成代码。
线上失败 -> 临时补丁 -> Prompt增长 -> 冲突/成本 -> 更多失败
| |
└-> 结构化治理与回归 <----┘
完整版教学
一、维护债务是如何累积的
Prompt 初期往往只有任务和格式。每遇到一个失败就追加“不要 X”“遇到 Y 必须 Z”,旧条款很少删除。经过几十次补丁,规则之间出现重叠、例外套例外,维护者不敢修改,于是继续往末尾加更强措辞。
这和代码技术债类似:局部修复速度快,但复杂度利息在未来支付。Prompt 还缺少编译器检查,冲突常不会报错,只表现为概率性质量下降,因此更隐蔽。
二、哪些结构最容易欠债
复制粘贴的公共规则、未类型化的模板变量、混在一起的政策与示例,以及依赖具体模型习惯的技巧,都容易腐化。RAG 文档、工具描述和历史摘要也属于最终 Prompt 的依赖,仅版本化主模板并不够。
| 债务信号 | 后果 | 治理动作 |
|---|---|---|
| 同一规则多处出现 | 更新不一致 | 单一规则源 |
| 自由文本变量 | 注入、格式破坏 | 类型/枚举/转义 |
| 大量负向补丁 | 难理解边界 | 正向契约与状态机 |
| 无 owner | 规则无人解释 | 模块责任人 |
| 无版本绑定 | 历史不可复现 | 依赖 manifest |
记忆钩子:一句 Prompt 的成本不只按 Token 付费,还要为它与其他句子的所有潜在交互付“维护利息”。
三、模块化如何降低耦合
将内容拆成 system policy、task definition、context adapter、examples 和 output contract,定义每个模块输入输出。共享安全规则从中央版本引用,业务模板只声明所需版本。渲染时生成完整 manifest,方便复现。
prompt: invoice_extract@17
policy: enterprise_safe@8
schema: invoice_v3
examples: invoice_cn@5
model_profile: model_x@2026-09
模块化不是把一个文件拆五个文件就结束;边界必须清楚,不能多个模块同时定义输出格式或冲突处理。
四、变量为什么需要类型系统
模板里的 {context}、{style} 若接受任意字符串,可能闭合标签、注入指令或造成超长截断。为变量定义来源、类型、最大长度、转义和缺省行为,例如 style 只能取 formal|friendly,文档数组必须包含 source_id。
渲染前验证,渲染后检查所有占位符已绑定并计算 Token。缺变量时明确失败或使用安全默认值,不要把字符串 undefined 发给模型。类型化变量还让测试可自动生成边界值。
五、测试如何成为重构安全网
回归集应覆盖核心业务、历史失败、安全边界和格式解析。每条用例说明保护的规则,避免没人敢删。重构时先验证行为等价,再删除冗余;对于开放生成,用结构指标、Judge 和人工抽查组合,而非逐字快照。
若删除 500 Token 后全部测试不变,可减少成本;但要做线上灰度防长尾。失败测试也应审查:大量高度相似 case 会让团队只优化旧问题,新增真实流量和轮换隐藏集保持代表性。
六、什么时候应把逻辑移出 Prompt
权限、金额阈值、日期计算、字段校验和路由条件都可由代码确定,应写成程序或策略表。Prompt 适合解释开放语义和生成表达,不适合承担交易状态机。自然语言 if/else 越多,越说明边界错位。
例如“金额大于 10000 且用户不是管理员时拒绝”应由授权代码执行;模型只负责说明拒绝原因。这样规则可单测、审计且无法被用户措辞覆盖。输出 JSON schema 也应由约束解码和解析器保证。
七、怎样量化维护债务
可监控 Prompt Token 长度、重复规则数、变量数、模块依赖、每月补丁次数、变更导致回滚率、失败复现时间和无 owner 条款。还可做 clause ablation:逐条移除并运行回归,长期无影响的规则候选删除。
假设模板从 1200 增到 5000 Token,半年加入 40 条补丁,最近 10 次修改有 4 次回滚,说明债务已影响交付。重构目标不是单纯变短,而是减少规则冲突和恢复可解释的所有权。
八、常见误区与追问
- 误区:Prompt 只是文本,不需要工程治理。 它直接控制生产行为,应像代码和配置一样版本化测试。
- 误区:旧规则不删最安全。 冗余与冲突会增加不确定性和成本。
- 误区:所有业务逻辑都放 Prompt 最灵活。 确定性规则失去类型、测试和强制执行能力。
- 追问:如何安全重构? 建行为基线,模块化,小步删改,离线回归后灰度。
- 追问:怎样知道一句话还有用? 记录规则对应测试,并做移除消融;无可观测贡献则审查删除。
- 追问:模型升级为何放大债务? 旧技巧可能失效或反作用,隐式依赖没有版本契约。
九、加强记忆
Prompt 债务可记成“补丁、重复、变量、耦合、失测”。治理则是“拆模块、强类型、单一源、全版本、有回归、能下沉”:把确定性逻辑移到代码,Prompt 专注语义任务。目标不是追求最短文本,而是让每条规则有归属、有测试、可删除、可回滚。
项目实战落地
项目里怎么做的
《AI Agent智能教务排课与教学质量分析系统》有两处调用大模型:排课 Agent 和教学质量分析。两处的提示词都按「谁来改、多久改一次」拆成两段:
前半段 角色设定和判断口径 -> 存在 prompt_template 表,教务在页面上随时调,保存后下次调用生效
后半段 这次调用的业务数据 -> Java 代码从数据库现查现拼,管理员改不到
- 模板里没有占位符。 模板
content是一段完整的中文,没有{课程}这类要靠代码替换的记号;代码取到后原样拼在提示词最前面,业务数据另起一段接在后面。 - 排课的步骤写在代码里。 排课 Agent 在模板正文之后,由代码拼上任务 ID、任务配置、执行步骤和最终回复要求,这几段教务在页面上改不到。
- 程序契约写在代码里。 质量分析在模板正文后面固定追加一句:
// 这一句决定返回格式,fillAiFields 要按 JSON 解析,所以固定写在代码里,不放进可编辑的模板
prompt.append("请只输出 JSON 对象,不要输出 Markdown,不要解释。字段必须包含 summary、strengths、problems、suggestions。\n\n");
排课指令里为什么不放课程、教师、教室这些数据,见「Agent 如何管理上下文窗口?」。
为什么这样取舍
- 按变化频率拆。 「硬约束有哪些、软约束有哪些」这类口径是教务想调就调的文字;业务数据每次调用都不同,只能由代码拼。混在一起,教务改一句口径就可能碰坏数据拼接。
- 契约和口径分开。 后端按
summary、strengths、problems、suggestions四个字段解析,这句话属于程序契约,和可以随教务口径调整的文字不是一回事;放进模板,教务改措辞时删掉一个字段名,解析就会失败。 - 模板不带变量,就没有变量要对齐。 模板里写什么,模型就原样读到什么,改模板不需要知道代码传了哪些值。
面试官还会追问
- 排课规划模板和质量分析模板分别是怎么被选中的?同一类型有多条启用中的模板时,用的是哪一条?
- 排课 Agent 开始执行前要做哪几项检查?为什么这些检查必须放在清空上一次课表之前?
学完《AI Agent智能教务排课与教学质量分析系统》,上面这些追问你都会迎刃而解。