Agent 架构中的上下文管理:从 ReAct 到三层裁剪模式的演进
一、基础概念回顾
在深入探讨架构之前,我们先明确几个核心概念。
什么是 Agent
Agent 的核心能力在于自主决策与执行。与简单的聊天机器人不同,Agent 能够根据用户意图,主动选择并调用工具来完成特定任务,例如查询数据库、调用 API 或创建新记录。其典型工作流如下:
用户输入 → 意图解析 → 决策行动 → 调用工具 → 获取结果 → 决策下一步 → ... → 返回最终响应
其中,"决策行动"和"调用工具"是关键。这也意味着 Agent 潜在的操作风险远高于文本生成,错误的决策可能导致数据修改或删除等严重后果。
什么是 Tool
Tool 是 Agent 与外部世界交互的接口,可视为其"手脚"。例如:
fetchTaskList:获取任务列表addNewTask:创建新任务modifyTaskStatus:更新任务状态removeTask:删除任务
什么是 LangGraph
LangGraph 是一个用于构建基于图(Graph)的 Agent 系统的框架。它将 Agent 的工作流建模为一个状态机,包含节点(Node)、边(Edge)和状态(State)。其优势在于支持循环、中断和状态持久化,使得复杂工作流的管理更加可控。
什么是上下文
上下文是 Agent 做出决策的依据,例如用户当前所在的页面、选中的对象、筛选条件等。关键挑战在于:不同的处理环节需要的信息量截然不同。
二、架构演进:从 ReAct 到三层裁剪
第一阶段:ReAct 模式——"让模型自主思考"
ReAct(Reasoning + Acting)模式的核心循环是:思考 → 行动 → 观察 → ... → 最终回答。模型拥有完全的自主权来决定工具调用和参数。
遇到的问题:
- 行为不可预测: 模型可能会执行超出预期的复杂操作链路。
- 成本不可控: 模型自主决定的循环次数导致 Token 消耗难以预估。
- 安全风险高: 缺乏对高风险操作的约束机制。
思考: ReAct 的问题在于将所有决策权交给了 LLM,但对于有明确流程的操作,固定的执行路径更为高效。这引出了第一条原则:确定性工作流优先,仅在需要开放式决策时引入 LLM 推理。
第二阶段:Plan-Execute 模式——"先规划再执行"
该模式将"思考"与"执行"分离:先由强模型生成完整计划,再由轻量模型或固定代码逐步执行。
遇到的问题:
- 过度规划: 即使是简单任务,也需经过规划阶段,造成不必要的资源消耗。
- 路径单一: 所有请求,无论简单或复杂,都需经过规划器,导致简单操作效率低下。
思考: 需要一种机制来区分"需要规划的复杂请求"和"可以直接执行的简单请求"。
第三阶段:Router 分发模式——"先分流再处理"
在 Planner 之前引入一个轻量分发层(Router),根据用户请求的类别,将其路由到不同的处理路径。
用户输入 → Router(意图分类)
├─ 简单 CRUD → 直接执行
├─ 数据查询 → SQL 查询 + 结果解释
└─ 复杂任务 → Planner → Executor → Replanner
这解决了"所有请求走同一路径"的问题。我们进一步将其设计为两层:
- 零模型路由层: 处理结构化入口,无需 LLM,直接映射到能力模块。
- 轻量模型路由层: 仅处理自由文本,使用轻量模型进行意图分类。
新的问题: 不同路径上的节点获取了相同的、完整的上下文,导致信息过载和潜在风险。
第四阶段:三层上下文裁剪——"从源头控制信息流动"
触发重新思考的三个事件:
- Token 消耗异常: 路由节点消耗了远超预期的 Token,原因是传入了大量无用的列表 ID。
- 工具层逻辑耦合: 工具代码中出现了根据请求来源(`origin`)返回不同结果的 if-else,导致工具与 UI 入口耦合。
- 安全隐患增加: 完整的 JSON 上下文增加了 Prompt 注入的风险。
设计思路: 在信息进入 Agent 系统前,按消费者需求裁剪成三份独立的上下文视图。
前端传入:完整的页面上下文
│
Context Assembler(后端,执行一次)
│
┌───────┼───────────────┐
▼ ▼ ▼
路由上下文 执行上下文 模型上下文摘要
(RouterCtx) (ExecCtx) (ModelSummary)
│ │ │
▼ ▼ ▼
Router Tool/Executor LLM System Prompt
三、三层裁剪的设计细节
字段分配策略
字段分配的核心原则是:"给了这个字段之后,这一层会不会做出不该做的事"。
| 字段 | 路由层 | 执行层 | 模型层 | 判断理由 |
|---|---|---|---|---|
requestSource(请求来源) |
给 | 不给 | 不给 | 只有路由需要来源信息做 fast-path 映射 |
visibleItemIds(可见条目 ID) |
不给 | 有条件给 | 不给 | 最危险的膨胀源,严格控制 |
queryFilters(筛选条件) |
给精简版 | 给完整版 | 给摘要 | 三层需求粒度不同 |
selectedObject(选中对象) |
给 | 给 | 给(文字) | 三层都需要:路由判断目标、工具操作目标、模型描述目标 |
模型层为何使用自然语言摘要
- Token 效率: 自然语言摘要比 JSON 格式更节省 Token。
- 安全增强: 打断了结构化数据格式,降低了 Prompt 注入风险。
- 真实需求: 模型只需要理解场景,而非原始数据。摘要通过模板拼接生成,无需调用 LLM。
状态不可变性
为确保裁剪后的上下文不被污染,我们对三个上下文字段应用了"状态一旦设定即不可变"的策略。通过 LangGraph 的 Reducer 机制,任何后续节点尝试修改这些字段的行为都会被框架拒绝。这从架构层面保证了信息隔离,而非依赖代码规范。
四、架构演进对比
| 模式 | 核心思路 | 解决了什么问题 | 暴露了什么新问题 |
|---|---|---|---|
| ReAct | LLM 自主循环 | 灵活性高 | 不可预测、成本不可控、安全风险 |
| Plan-Execute | 先规划再执行 | 可预测性提升 | 简单操作也走重型链路 |
| Router 分发 | 先分类意图 | 简单走快路、复杂走慢路 | 所有节点共享全量上下文 |
| 三层裁剪 | 分类意图 + 按需裁剪 | 信息隔离、成本控制、安全增强 | (持续验证中) |
演进的核心逻辑是:逐步收回 LLM 的权限,将确定性还给确定性的模块,将信息控制权从"消费者自律"转移到"供给侧管控"。
五、防止架构退化
为防止架构在协作中退化,我们制定了"防滑坡检查表":
| 退化模式 | 原因 | 后果 |
|---|---|---|
| 直接将完整上下文传给规划节点 | 赶工期"先跑通再优化" | Token 浪费 + 注入面扩大 |
| 路由层读取列表数据辅助判断 | 看似合理的"优化" | 路由层承担业务逻辑,职责边界模糊 |
| 工具根据请求来源返回不同结果 | 需求驱动 | UI 入口与执行逻辑耦合 |
| LLM prompt 里直接拼入原始 JSON | 图省事 | Token 浪费,暴露不必要的数据结构 |
六、核心思考
Agent 系统的核心挑战不在于"让 LLM 更强",而在于"给 LLM 恰当的边界"。三层上下文裁剪模式的本质是最小权限原则在 LLM 系统中的实践:每个环节只应看到完成工作所必需的信息,多一个字段都是负债。