把 LLM 接到生产链路里,先解决上下文污染
# 把 LLM 接到生产链路里,先解决上下文污染
这半年和团队聊 AI 落地,最容易高估的不是模型能力,而是“把一个能聊天的模型接进系统之后,它会不会稳定地产生你要的结果”。很多 PoC 卡住,并不是 prompt 写得不够花,而是上下文管理太粗糙,最后把模型变成了一个对历史噪音过度敏感的黑盒。
我最近比较认同一个判断:做 LLM 应用,第一层工程问题不是检索,也不是 agent,而是上下文污染控制。这个事如果没处理好,后面你叠再多流程,成本和波动都会一起上来。
先说一个常见场景。很多团队做客服、代码助手或者内部知识问答,最初会把“用户问题 + 最近若干轮对话 + 检索到的文档片段 + 系统提示词”一股脑塞进模型。Demo 阶段看起来没问题,线上一跑就开始出现下面几类毛病:
1. 历史对话里一句无关的话,把当前任务带偏。
2. 检索召回了 10 段文档,真正有用的只有 2 段,模型却把低相关内容也当依据。
3. 工具调用的中间结果被原样塞回上下文,token 花了不少,增益不明显。
4. 同一类问题在不同会话里表现不一致,因为前文状态不一样。
这些问题背后,都是“上下文预算”没有被当成硬资源管理。LLM 的上下文窗口再大,也不代表你应该把什么都喂进去。现实里更有效的做法,是把上下文拆成几层,并且让每一层都带着明确职责。
我现在更倾向于这个结构:
```python
from dataclasses import dataclass
@dataclass
class PromptContext:
system_rules: str
task_input: str
short_memory: list[str]
retrieved_facts: list[str]
tool_state: list[str]
def build_prompt(ctx: PromptContext) -> str:
parts = [
"[SYSTEM]",
ctx.system_rules,
"[TASK]",
ctx.task_input,
]
if ctx.short_memory:
parts += ["[RECENT DIALOGUE]", "\n".join(ctx.short_memory[-4:])]
if ctx.retrieved_facts:
parts += ["[FACTS]", "\n\n".join(ctx.retrieved_facts[:4])]
if ctx.tool_state:
parts += ["[TOOL STATE]", "\n".join(ctx.tool_state[:3])]
return "\n\n".join(parts)
```
这段代码没什么炫技的地方,但核心思想很重要:不同来源的信息不要混在一起,进入 prompt 之前先分层、限量、裁剪。尤其是 `retrieved_facts` 和 `tool_state`,很多系统最大的问题就是不做筛选,默认“多给一点总没错”。实际上模型在长上下文里并不会自动帮你做最优注意力分配,给多了反而会稀释主任务。
另一个容易被忽略的点,是把“摘要”当成长期记忆。摘要当然有用,但摘要不是越长越好,也不是每轮都该更新。更稳的做法是把记忆分成两类:一类是会影响后续行为的稳定事实,比如用户偏好、任务约束、代码库约定;另一类只是本轮推理过程中的临时状态,这些状态应该随任务结束被丢掉。
如果不区分这两类,系统会出现一种很典型的退化:它表面上“记住了很多”,实际上是把大量短期噪音变成长期负担。后面每次推理都要背着这些历史包袱走,延迟、费用和错误率一起涨。
在线上链路里,我建议至少做三件很朴素的事。
第一,给每种上下文来源设硬上限,而不是交给模型自己消化。比如最近对话最多保留 4 轮,检索片段最多 4 段,工具状态只保留最终结果,不要塞调试日志。
第二,做检索后重排。哪怕先用一个简单的 cross-encoder,或者用规则先按时间、权限、命中字段过滤一遍,效果都比“向量检索完直接全塞进去”稳定。
第三,对工具结果做结构化摘要。命令执行、SQL 查询、网页抓取,这些原始输出通常很长,但真正有用的信息往往只是几行。与其让模型在 200 行日志里找重点,不如前面先做一次压缩。
例如把 shell 输出整理成固定格式:
```bash
status: success
changed_files: 3
key_result: service restarted on port 8080
warnings:
- config key x is deprecated
```
模型读这种结构化结果,比读一整段混杂日志更稳,后续也更容易做审计和回放。
还有一个工程上很现实的取舍:不要太早迷信多 agent。很多问题单 agent 加上明确的上下文边界就够了。多 agent 真正适合的是职责天然可拆的流程,比如“检索 -> 计划 -> 执行 -> 复核”。如果只是因为主 agent 表现不稳定就盲目拆成三个 agent,最后常见结果不是质量提升,而是上下文在多个节点之间来回复制,问题变得更难定位。
我现在看一个 LLM 系统是否靠谱,往往不先看模型名字,而是先问三个问题:
1. 哪些信息能进上下文,谁来决定?
2. 过期信息何时清理?
3. 工具输出是原样透传,还是已经被压缩成可消费的状态?
这三个问题答不清楚,系统大概率只是“看起来很聪明”。答清楚了,即便模型不是最新一代,整体体验通常也不会差。
LLM 工程到最后,越来越像传统系统设计:你要管理边界、状态、成本和不确定性。模型确实重要,但真正把产品做稳的,往往是那些不那么性感的上下文治理工作。这个活干得细,AI 才不容易从助手变成噪音源。

浙公网安备 33010602011771号