# 上下文工程原理

## 背景

LLM 的上下文窗口有限，而 Agent 需要同时处理用户输入、工具描述、技能指令、记忆上下文、对话历史等多类信息。如何在不超出 token 限制的前提下，让 Agent 获得最相关的上下文，是上下文工程要解决的核心问题。

## 设计理念

EvoFlow 的上下文工程遵循三个原则：

1. **分层优先级**：不同信息类别有不同优先级，系统提示 > 工具描述 > 技能指令 > 记忆 > 对话历史
2. **动态裁剪**：接近 token 上限时，优先保留最近的消息，压缩或摘要旧消息
3. **按需加载**：不是所有上下文都始终加载，某些信息仅在触发条件满足时才注入

## 系统提示的上下文组成

Lead Agent 的系统提示由以下部分构成（按注入顺序）：

1. **角色描述**：Agent 的基本身份和职责
2. **工具描述**：所有可用工具的 name、description、参数 schema
3. **技能指令**：已启用技能的 SKILL.md 内容（含容器路径）
4. **记忆上下文**：前 15 条事实 + 用户上下文（如果启用）
5. **子 Agent 说明**：委派能力说明（如果启用）
6. **SOUL.md**：自定义 Agent 的人格内容
7. **USER.md**：全局用户画像（注入到所有自定义 Agent）
8. **对话历史**：当前线程的消息列表

## 工具上下文的优化

当 MCP 服务器很多时，工具描述会占用大量 token。EvoFlow 提供了两种策略：

### 直接加载（默认）

所有 MCP 工具描述直接注入系统提示。适用于工具数量较少的场景。

### 延迟加载（tool_search.enabled = true）

- 工具不在系统提示中直接列出
- 系统提示中只包含 tool_search 工具的简要说明
- Agent 在需要时通过 tool_search 发现和调用工具
- 大幅减少上下文占用，提高多 MCP 场景下的工具选择准确率

## 摘要压缩（SummarizationMiddleware）

当对话长度接近 token 上限时触发：

```yaml
summarization:
  enabled: true
  trigger:
    - type: tokens
      value: 15564     # token 数达到此值时触发
    # - type: messages
    #   value: 50       # 或消息数达到 50 时触发
    # - type: fraction
    #   value: 0.8      # 或达到模型最大输入的 80% 时触发
  keep:
    type: messages
    value: 10           # 保留最近 10 条消息不被摘要
```

摘要过程：
1. 计算需要摘要的消息范围（排除 keep 策略保留的部分）
2. 调用 LLM 生成摘要
3. 用摘要替换原始消息，保留 keep 范围内的完整消息

## 规划模式的上下文控制

在规划阶段（`planning`、`plan_ready`、`awaiting_exec`），PlanGuardMiddleware 会过滤掉有副作用的工具调用，只保留只读和确认类工具。这防止 Agent 在规划阶段意外执行修改操作。

## 视觉上下文的处理

对于支持 vision 的模型，ViewImageMiddleware 会：
1. 检测对话中的图片引用
2. 将图片转为 base64
3. 注入到模型输入中

## 为什么需要分层优先级？

LLM 对系统提示中不同位置的信息关注度不同。靠近开头和结尾的内容更容易被重视。通过合理安排：
- 角色描述和核心规则放在开头
- 工具描述放在中间
- 对话历史放在末尾（模型天然关注最近的对话）

这种排列让 Agent 在各种 token 压力下都能保持核心行为准则。

## 与记忆系统的协同

记忆注入在工具描述之后、对话历史之前。这样安排的原因是：
- 记忆是长期上下文，优先级高于单次对话的历史
- 但低于工具描述，因为工具描述是 Agent 能力的直接定义

## 延伸阅读

- [agent-system.md](./agent-system.md) - Agent 系统架构
- [memory-system.md](./memory-system.md) - 记忆系统原理
- [middleware-chain.md](./middleware-chain.md) - 中间件执行链
