上下文窗口是一个 API 界面:像对待合约一样对待你的提示词结构
· 阅读需 11 分钟
在一个生产环境中的 LLM 功能上线半年后,一名工程师提交了一个 bug:模型在上个季度的某个时间点开始给出错误的输出。没人记得改过提示词(Prompt)。Git blame 显示它为了“提高可读性”被清理过。之前的版本已经找不到了。调试工作只能从零开始。
就在这一刻,团队才发现他们的上下文窗口(context window)从未被真正工程化过——它只是被拼凑出来的。
上下文窗口是你的系统与模型之间的契约。进入其中的每一个标记(token)——系统指令、检索到的文档、对话历史、工具架构、用户查询——都是对一个函数调用的输入,这个调用既费钱又耗时,且会产生非确定性的输出。然而,大多数团队将上下文组合视为实现细节,而非 API 表面。提示词被就地编辑,没有版本控制。各部分通过累加增长。没有人负责布局。变化在无声无息中传播。调试体验比 LLM 时代之前的任何东西都要糟糕,因为至少堆栈跟踪(stack traces)会告诉你什么是改变了的。
问题:上下文窗口布局是“狂野西部”
在传统服务中,接口契约是显式的:输入有类型,输出有模式(schema),错误有代码。接口的变更会触发评审。破坏性的改动会立即暴露。
基于提示词的系统默认没有任何这种纪律。上下文窗口就是一块文本,在运行时通过字符串拼接、f-strings 或模板库构建而成。“部分”(Sections)——即使存在的话——也只是某人曾经理解过的散文式约定。没有 schema。没有版本。没有 diff。
失败模式是完全可以预见的:
- 无声的性能偏移。 检索块(chunk)格式发生了变化,导致准确率下降了 8%,但没有“语义质量退化”的警报。回归测试就这样发布了。
- 无法归因的破坏。 用户报告了一个回归问题。你今天可以复现它,但两周前的版本却不行,因为提示词在那之后已经改了三次。
- 知识流失。 某条约束的原始作者离职了。没人知道系统提示词(system prompt)中第三段内容的含义。删掉它似乎很安全。事实并非如此。
- 凭感觉调试。 评估一个提示词变更意味着手动运行几十次,形成一种直觉,然后合并。你不是在测试;你是在猜。
超过 65% 的 LLM 开发者表示,提示词版本控制和可观测性是将原型扩展到生产环境中最艰巨的挑战。差距不在于模型质量——而在于围绕上下文组合的工程纪律。
