简介:本文从第一性原理出发,对比智能体循环工程中的两类上下文组织方式:以查找表与固定提示词锚点为核心的确定性上下文分配方案,以及依赖模型隐式记忆的自由长上下文堆叠方案。文章从架构、功能、性能、成本、运维与适用场景等维度系统分析两者差异,并给出选型建议与迁移注意事项,帮助开发者在长任务、多轮工具调用的智能体应用中做出合理的工程决策。
近年来,基于大模型的智能体(Agent)逐渐从“单轮问答”走向“多轮循环”:模型在循环中反复执行“规划—调用工具—观察结果—修正方向”,直到完成任务。这类循环式工作流让智能体具备了处理长任务的能力,但也暴露出一个根本问题——上下文窗口是稀缺资源,而模型对超长上下文的注意力是有损的。
从第一性原理出发可以得出两个基本事实:其一,上下文窗口容量有限,不可能无限制地把所有历史信息塞进去;其二,即使塞进去,随着轮数增加,早期信息在注意力分配中会被不断稀释,相当于发生了“有损压缩”,模型可能出现目标漂移、遗漏约束,甚至凭空捏造并不存在的结果。
围绕这个问题,工程实践中形成了两条典型路线:一条是方案A——像操作系统管理内存那样,对上下文窗口进行确定性的显式分配;另一条是方案B——把每轮产生的思考与工具结果全部追加进对话历史,依赖模型自身的隐式记忆能力。本文将围绕这两类方案展开系统对比。
核心思想是把上下文窗口当作显式管理的内存空间。工程上通常包含两类构件:
每轮循环由调度组件决定“本轮上下文数组里放什么”:只将与当前步骤相关的条目按确定性规则注入,工具结果先落入查找表,而非全量堆积在对话历史中。这样做的直接收益,是模型在需要检索历史信息时有明确的“地址”可查,从而提高搜索与工具调用的命中率。
方案B不引入额外调度组件,循环的每一轮把模型的思考、工具调用结果原样追加到对话历史,上下文随轮数线性增长,依赖模型自身的注意力机制去“记住”全部信息。它的特点是实现极简、贴近模型原生用法,但把记忆质量完全托付给了模型本身。
尽管工程形态差异明显,两类方案在多个层面是一致的:
方案A在“模型调用”之外引入了明确的调度层:上下文管理器负责分配与回收,查找表负责持久化中间产物,提示词锚点负责稳定性。系统边界清晰,每个组件可以独立测试。方案B则几乎没有额外组件,架构成本最低,但状态信息隐式分布在不断增长的历史中,没有显式的系统边界。
方案A通过查找表和锚点,使跨多轮的约束保持成为工程保证,而不是模型自觉:例如“不要修改某个目录”这类硬约束,可以每轮以固定条目重新注入,避免长循环后被遗忘。方案B在短任务中表现往往足够好,但任务轮数一多,早期指令相当于被有损压缩,常见表现包括目标漂移、重复执行已完成的工作,甚至“虚构”出并不存在的结果。
从可观察的行为趋势看:
需要说明的是,以上为定性规律,具体幅度与模型版本、任务类型相关,应以实际测试为准。
方案B几乎零改造,任何具备循环调用模型能力的程序都可以直接运行。方案A则需要前期投入:设计任务状态模型、定义查找表结构、编写并调优锚点提示词、实现分配与淘汰策略。前期成本高,是方案A最主要的接入门槛。
方案A是“前期重、运行期轻”:工程投入集中在设计与实现阶段,运行期token消耗可控,失败重试的代价也较低。方案B是“前期轻、运行期重”:起步快,但长任务中token开销与重试成本会随轮数累积,隐性成本不可忽视。
方案A每轮注入的内容有明确清单,便于回归测试、行为审计与故障回放,这与企业级应用对合规审计的普遍要求是契合的。方案B的输入是完整历史流,复现某次异常需要还原整段上下文,审计成本高。
方案A的运维重点在查找表一致性、提示词版本管理、状态序列化兼容性,属于“常规但必须持续维护”的工程项。方案B运维项少,但故障定位困难——问题往往埋在超长历史中,排查如同大海捞针。
| 维度 | 方案A:确定性上下文管理 | 方案B:自由长上下文堆叠 |
|---|---|---|
| 架构复杂度 | 需要调度层、查找表、锚点提示词 | 极简,无额外组件 |
| 上下文来源 | 按确定性规则分配的相关条目 | 全量历史追加 |
| 长任务稳定性 | 约束可工程化保持 | 易漂移、易遗忘 |
| 工具/检索命中率 | 依赖索引,趋势更稳定 | 随历史增长趋于下降 |
| Token消耗趋势 | 与当前步骤相关,总体可控 | 随轮数线性膨胀 |
| 可审计与复现 | 输入清单明确,易回放 | 需还原整段历史,成本高 |
| 接入成本 | 前期设计与改造投入大 | 接近零改造 |
| 运维重点 | 查找表一致性、提示词版本管理 | 故障定位困难 |
| 适用场景 | 长任务、高可靠性、企业级应用 | 短任务、原型验证 |
方案B(自由堆叠):
history = [system_prompt]while not task_done:plan = call_model(history) # 模型基于全量历史决策obs = run_tool(plan.tool_call)history.append(plan, obs) # 无差别追加,上下文持续膨胀
方案A(确定性分配):
lookup = build_lookup_table(task) # 状态/文件/结果索引anchor = load_anchor_prompts() # 固定约束与角色锚点while not task_done:ctx = allocate(anchor, # 每轮确定性构造上下文数组lookup.query(current_goal),budget=token_budget)plan = call_model(ctx)obs = run_tool(plan.tool_call)lookup.commit(obs) # 结果入表,而非全量入上下文
两者差异的本质在于:中间结果存放在哪里、由谁决定模型“看到什么”。
在百度智能云等提供大模型服务与AI应用开发能力的平台上构建此类应用时,上述两条路线均可落地:可以结合平台提供的模型推理、日志监控等通用能力,将方案A的查找表与分配策略实现为应用层组件;方案B则可直接基于对话接口循环调用实现。
选型不应脱离具体条件,可参考以下判断路径:
需要强调的是,方案A与方案B并非互斥:方案A可以兼容方案B作为退化模式——当查找表命中失败时,回退为把相关历史全量注入,是一种常见的工程兜底。
若计划从方案B迁移到方案A,建议关注以下事项:
反向迁移(从方案A退回方案B)的风险则在于:长任务稳定性会重新依赖模型自觉,此前通过工程手段消除的漂移与幻觉风险可能回归,需重新评估。
从第一性原理看,两类方案的分野源于一个根本问题:中间状态由谁维护。方案B把记忆交给模型的注意力机制,实现简单,但长任务下不可避免地经历有损压缩;方案A把记忆交给显式的工程组件,用确定性分配取代“希望模型记得”,以更高的前期投入换取长任务下的稳定性、可审计性与可控成本。决策时,建议围绕任务长度、可靠性要求、团队工程能力与成本结构四个条件综合判断,并优先考虑两者结合的混合形态——这往往比非此即彼的选择更贴近工程实际。