Jean's Blog

一个专注软件测试开发技术的个人博客

0%

上下文工程

Context(上下文)是什么?

核心定义:上下文指的是大语言模型在处理你的当前请求时,所能“看到”和“考虑”的所有文本信息。

你可以把它类比为人类的短期记忆工作记忆

  • 当你和一个人对话时,你会记住刚才聊了什么,对方说了什么,这样才能做出连贯的回应。
  • 对大模型来说,上下文就是这个“刚才聊过”的全部内容

如下图形象的展示

image-20251029141401415

上下文的组成部分

一个典型的上下文通常包括:

  • 系统提示:在对话开始前,开发者或用户给模型的“人设”或“指令”。例如:“你是一个乐于助人的、专业的AI助手。”
  • 对话历史:你和模型之间已经进行的所有多轮问答。
  • 当前查询:你刚刚提出的新问题。
  • 外部知识/文档:你主动提供给模型的额外信息,比如一篇论文、一份数据表等。

上下文的内容常有:

  • 用户问题
  • 背景信息
  • 相关资料
  • 可用工具列表
  • 工具执行结果
  • 历史对话
  • ……

关键点:模型只理解上下文内的信息。如果信息不在上下文中,就如同没有发生过一样,模型无法基于它进行推理。

运行时上下文(Runtime context)

  • 定义:运行时上下文指的是本地上下文,即你的代码运行所需的数据和依赖关系。它包含了代码在执行过程中所依赖的各种资源,例如变量、函数、库等。
  • 作用:它为代码的运行提供了必要的环境和条件,确保代码能够正常执行。

LLM上下文(LLM context)

  • 定义:LLM上下文是指传递给LLM(大型语言模型)提示(prompt)的数据。它包含了用于引导LLM生成响应的输入信息。
  • 示例:在与LLM交互时,你可能会提供一段文本作为提示,让LLM根据这段文本生成相关的回答或内容,这段文本就是LLM上下文的一部分。

运行时上下文与LLM上下文的关系

  • 区别:运行时上下文主要关注代码运行的本地环境和依赖,而LLM上下文关注的是传递给LLM的输入数据以及与LLM交互过程中相关的数据。
  • 联系:运行时上下文可以被用来优化LLM上下文。例如,你可以利用运行时上下文中存储的用户元数据(如用户偏好设置等)来获取用户的相关信息,然后将这些信息作为输入数据传递给LLM,从而优化LLM生成的响应,使其更符合用户的期望和需求。

上下文窗口(Context Window)

核心定义:上下文窗口是指大模型一次性能处理和接受的最大文本量(模型的输入中最多能包含的Token数量)。这个容量通常以令牌为单位来衡量。

  • 令牌:是模型处理文本的基本单位。在英文中,一个令牌可能是一个单词或一个词根(例如,“unbelievably” 可能被拆成 “un”, “believe”, “ably” 三个令牌)。在中文中,通常是一个汉字或一个词。
  • 单位:常见的上下文窗口大小表示为 4K、8K、32K、128K、200K 甚至更高。例如,一个32K的窗口意味着模型可以一次性处理大约32,000个令牌的文本。

上下文窗口是指可以传递给LLM的最大令牌(token)数量。令牌是文本数据在处理过程中被分割成的最小单位,例如单词、短语或字符等。

限制:由于LLM的处理能力和资源有限,因此对输入数据的长度有一个上限,这个上限就是上下文窗口的大小。

为什么上下文窗口很重要?

  1. 决定对话深度:窗口越大,模型能记住的对话轮次就越多,可以进行更长的、连贯的对话。
  2. 限制处理能力:如果你提供的文档(比如一本电子书)超过了上下文窗口,模型将无法完整阅读它。
  3. 技术成本:处理更长的上下文需要更多的计算资源和内存,技术上更具挑战性,成本也更高。

举个例子
假设一个模型的上下文窗口是4K令牌(约3000个汉字)。

  • 如果你的对话历史加上当前问题已经达到了3800字,你还能再提供一篇2000字的文章让它总结吗?
  • 不能。因为总文本量会超过4K的限制,系统会报错或者自动截断前面的部分对话,导致模型“忘记”了开头的内容。

重要区分

  • 上下文窗口:是模型的短期记忆容量,关乎一次交互中能处理多少信息。
  • 训练数据:是模型在训练时“学习”到的长期知识,是固定的,模型无法实时更新它。

上下文工程(Context Engineering)

已经对上下文的概念有一个详细的了解,那么关键的部分上下文工程是我们在使用大模型及构建智能体中的核心了。

超越提示词:深入理解 AI 应用成功的关键—上下文工程

核心观点: 大多数 AI 智能体的失败,其根源不在于模型本身的能力不足,而在于“上下文工程”(Context Engineering)的缺失。

上下文工程”这个概念近期在 AI 大模型领域迅速升温,它究竟是新瓶装旧酒,还是真正揭示了构建强大AI应用的核心秘诀?它与我们熟知的提示工程(Prompt Engineering)和检索增强生成(RAG)有何不同?

image-20251029145451783

什么是上下文工程?

上下文的真正含义

上下文不是简单的历史聊天记录。它是提供给大语言模型(LLM)用于完成下一步任务的全部信息集合。我们可以将其分为三类:

image-20251029145748257

  • 指导性上下文 (Guiding Context): 告诉模型“做什么”和“怎么做”。这部分是提示工程的核心优化对象。
    • 系统提示词 (System Prompt): 定义模型的角色和行为准则。
    • 任务描述 (Task Description): 明确当前需要完成的任务。
    • 少量样本示例 (Few-shot Examples): 提供范例,指导模型输出风格。
    • 输出格式定义 (Output Schema): 规定模型必须遵循的输出格式,如JSON。
  • 信息性上下文 (Informational Context): 告诉模型“需要知道什么”。这部分为模型提供解决问题所需的事实和知识。
    • RAG: 从外部知识库(比如:文档、数据库)中检索相关信息。
    • 记忆 (Memory): 包括当前对话的短期记忆和跨对话的长期记忆(比如:用户偏好)。
    • 状态/草稿纸 (State / Scratchpad): 记录模型在任务过程中的中间思考和计划。
  • 行动性上下文 (Actionable Context): 告诉模型“能做什么”和“做了之后的结果”。这部分赋予模型与外部世界交互的能力。
    • 工具定义 (Tool Definition): 描述模型可以使用的工具(API、函数等)。
    • 工具调用记录 (Tool Traces): 记录模型调用了哪些工具以及返回了什么结果。

上下文工程的定义

上下文工程是一门系统性学科,专注于设计、构建并维护一个动态系统。该系统能在 AI 智能体执行任务的每一步,为其智能地组装出最优的上下文组合,从而确保任务能够被可靠、高效地完成。

一个绝佳的类比是,如果 LLM 是计算机的 CPU,那么上下文窗口(Context Window)就是内存(RAM)上下文工程就是这个系统中的“内存管理器”。它的任务不是简单地把信息塞满内存,而是通过精密的调度,决定在每个时刻加载什么、丢弃什么,以保证 CPU 高效运转,最终产出正确结果。

image-20251029150146285

与提示工程、RAG 的区别

image-20251029150244909

  • 提示词工程 (Prompt Engineering): 是上下文工程的子集,专注于优化“指导性上下文”,即如何下达清晰的指令。
  • RAG (Retrieval-Augmented Generation): 是实现上下文工程的关键技术手段之一,主要负责动态填充“信息性上下文”。

因此,上下文工程是一个更宏大、更系统的概念,它统筹管理所有类型的上下文,目标是构建一个最高效的信息供给系统。

为什么我们需要上下文工程?

当 AI 系统的表现不佳时,我们往往会怪罪于模型本身。但大多数情况下,问题出在上下文的供给上。

示例1:缺失上下文的代价

假设 AI 智能体收到邮件:“Hi, 明天有空聚一下吗?”

  • 上下文贫乏的 AI: “感谢您的消息。我明天有空。请问您希望约在什么时间?” (无效回复,未推进任务)
  • 上下文丰富的 AI: 在回复前,它的上下文工程系统会自动组装信息:
    • 信息性上下文: 检索日历发现明天已满;识别发件人 Jim 是重要伙伴;分析历史邮件确定应使用非正式语气。
    • 行动性上下文: 知道自己有 send_calendar_invite 这个工具。
    • 最终回复: “Hi Jim! 我明天日程完全满了。周四上午有空,你看方便吗?我发了一个暂定邀请,如果时间合适请确认。” (高效、智能)

这里的“魔力”并非来自更聪明的模型,而是来自一个能够为任务动态组装恰当上下文的系统。

示例2:上下文退化的挑战

既然上下文如此重要,是不是把它全部塞给模型就行了?答案是否定的。对于长期、复杂的任务(比如:编程),简单的信息累加会导致“上下文退化”:

  • 第一、性能下降: 无关紧要的旧信息会干扰当前任务,造成“上下文干扰”。
  • 第二、成本与延迟激增: 上下文越长,API 调用成本越高,响应越慢。
  • 第三、最终崩溃: 当信息量超过模型的上下文窗口上限时,系统将直接报错或因信息截断而出错。

结论: 上下文是一种需要被主动管理的、有限的资源。简单的缺失或无脑的堆砌都无法构建出强大的 AI 智能体应用。因此,我们需要一套系统性的方法论——上下文工程

如何实践上下文工程?

上下文工程的实践核心在于对上下文进行智能的写入(Write)、选取(Select)、压缩(Compress)和隔离(Isolate)

image-20251029150810491

  1. 写入 (Write): 将有价值的信息持久化,超越单次对话的限制。

    • 会话内写入: 将中间思考和计划写入“草稿纸”,供当前任务使用。
    • 持久化写入: 将用户偏好、关键事实等存入外部记忆系统(比如:向量数据库),实现跨会话的“学习”和“成长”。
  2. 选取 (Select): 在每次调用 LLM 前,从所有可用信息中,动态拉取与当前子任务最相关的信息。

    • 确定性选取: 根据预设规则加载固定上下文(比如:启动时加载项目配置文件)。
    • 检索式选取: 通过相似度搜索从知识库、记忆中拉取最相关的信息(RAG 的核心)。
  3. 压缩 (Compress): 在信息进入上下文窗口前,对其进行“降噪”,用更少的 Token 承载最核心的信号。

    • 自动总结: 当上下文过长时,自动总结历史对话,只保留关键部分。
    • 专用压缩模型: 使用一个专门微调过的“压缩 LLM ”来对上下文进行提炼。
    • 修剪策略: 例如,直接截断最早的历史记录。
  4. 隔离 (Isolate): 在系统架构层面设置信息边界,防止信息污染和干扰。

    • 多智能体架构: 这是最经典的隔离策略。让多个“专家”子智能体并行处理各自领域的信息,然后只将最关键的结论“压缩”并上报给主智能体。这极大地减轻了主智能体的认知负担,提高了信息密度,避免了长上下文带来的各种问题。

      image-20251029150936083

    • 工具调用: 将复杂的计算或操作隔离在沙盒环境中执行,只将最终结果返回到上下文中。

上下文工程标志着 AI 智能体应用开发的范式转变。我们的重心正从“寻找那句完美的提示词”,转向“如何设计一个能够为模型在每一步都动态组装出完美上下文的、健壮可靠的系统”。

理解并熟练运用写入、选取、压缩、隔离这四大实践,将是区分一个“有趣的演示”和一个“可靠的、可规模化的应用”的关键。归根结底,所有努力都指向同一个目标:在模型做出决策前,为它准备好一份恰到好处的上下文。这,就是上下文工程的禅意所在。

上下文的两个关键维度

可变性(Mutability)

  • 静态上下文(Static context)定义:静态上下文是不可变的数据,在执行过程中不会改变。
    • 示例:用户元数据(如用户的基本信息)、数据库连接、工具等。
    • 特点:这些数据在应用启动时被加载,并在整个运行过程中保持不变。
  • 动态上下文(Dynamic context)定义:动态上下文是可变的数据,随着应用的运行而变化。
    • 示例:对话历史(如用户与AI的交互记录)、中间结果(如计算过程中的临时数据)、工具调用的观察结果等。
    • 特点:这些数据会根据应用的运行状态和用户的交互动态更新,反映了应用的实时状态。

生命周期(Lifetime)

  • 运行时上下文(Runtime context)定义:运行时上下文是指在单次运行或调用中有效的作用域数据。
    • 特点:这些数据仅在当前运行实例中存在,当运行结束时,数据也会随之消失。
  • 跨对话上下文(Cross-conversation context)定义:跨对话上下文是指在多次对话或会话中持续存在的数据。
    • 特点:这些数据可以跨越多个运行实例,保留用户的历史信息和偏好设置等,为用户提供更加连贯和个性化的体验。

上下文与智能体

智能代理(Agent)的循环工作流程

graph TD
    A[思考
(大脑:任务分析/规划)] --> B[执行工具
(扳手:调用外部能力处理任务)] B --> C[获取结果
(文档:接收工具执行产出)] C -->|循环迭代:结果作为下一轮输入| A %% 可选:添加样式优化视觉效果 A:::nodeStyle B:::nodeStyle C:::nodeStyle linkStyle 0,1 stroke:#333,stroke-width:2px linkStyle 2 stroke:#666,stroke-width:2px,stroke-dasharray:5 5 %% 移除了行尾多余分号和行内注释,避免解析冲突 %% 样式定义:移除不兼容的padding和font-size,保留核心样式 classDef nodeStyle fill:#f5f9ff,stroke:#2f80ed,stroke-width:2px,rounded:true
  • 每一轮流程都遵循「思考→ 执行工具→ 获取结果」的逻辑
  • 上一轮 “获取结果” 会作为下一轮 “思考” 的输入,形成多轮循环迭代的模式,用来持续推进、优化任务。

Context管理

Context 管理是智能体的 “信息中枢”—— 它不是简单的 “存信息”,而是对 “任务相关信息(含历史交互、中间结果、环境数据、工具产出等)” 的全生命周期管理,覆盖 “信息的产生→筛选→优化→复用→隔离” 全过程,最终支撑智能体的多轮决策与任务推进。

Context 管理的核心目标

所有 Context 管理操作,都是围绕这 3 个目标展开:

  1. 支撑多轮决策:让智能体每一轮 “思考” 都有历史信息做依据,能推进复杂 / 长流程任务;
  2. 控制成本 & 效率:避免冗余信息耗尽大模型的 token 窗口(节省成本),同时让智能体 “思考” 更聚焦(提升效率);
  3. 避免信息干扰:确保不同任务 / 场景的信息不串扰,让决策更精准。

Context 管理的全流程核心环节

1. 保存 Context:信息的 “存储生命周期”

  • 核心动作:将智能体的任务产出(模型输出、工具结果、用户反馈等)留存下来,是后续管理的基础。
  • 落地细节
    • 存储介质
      • 内存(临时缓存):存当前正在处理的任务 Context,速度快但任务结束后会清除;
      • 硬盘(持久化存储):存需要长期复用的 Context(如用户历史偏好、通用任务模板),支持跨任务调用。
    • 存储策略
      • 全量保存:适合简单任务(如单轮问答),直接存所有内容;
      • 增量保存:适合复杂任务(如多轮报告撰写),仅存 “新产生的内容”,避免重复存储已有的上下文。

2. 选择 Context:信息的 “精准筛选”

  • 核心动作:从已保存的上下文库中,挑出和 “当前任务” 相关的信息。
  • 落地细节
    • 选择方式
      • 静态选择:全量调用当前任务的所有 Context(适合任务逻辑连贯、信息不冗余的场景);
      • 动态选择:基于 “语义相似度”“关键词匹配” 筛选相关内容(比如用户问 “报告数据是否准确”,仅选 “数据采集结果” 相关 Context)。
    • 匹配逻辑:常用大模型的 “文本嵌入(Embedding)” 技术,给 Context 打标签后做相似度匹配,实现精准筛选。

3. 压缩 Context:信息的 “轻量化优化”

  • 核心动作:对冗余 / 冗长的 Context 做 “精简”,既保留核心信息,又控制 token 占用。
  • 落地细节(结合你的补充)
    • 重点压缩对象:优先处理 “长文本(多轮模型输出)”“工具产出的大体积内容(如 Base64 编码的图片 / 音频)”;
    • 场景化压缩方法
      • 若 Context 是 “Base64 图片”:用「特征替代法」转成 “文本描述 + 核心特征”(比如 “一张包含 2024 年用户增长曲线的折线图”),替代原长编码;
      • 若 Context 是 “多轮对话”:用「摘要提炼法」提取核心诉求,舍弃寒暄内容。

4. 隔离 Context:信息的 “边界管控”

  • 核心动作:给不同任务 / 用户 / 场景的 Context 划清边界,避免串扰。
  • 落地细节(结合你的补充)
    • 隔离维度
      • 按任务隔离:给每个任务分配独立的上下文库(比如 “用户调研任务” 和 “报告生成任务” 的 Context 互不干扰);
      • 按子智能体隔离:构建多个子智能体,每个子智能体仅调用自身任务的 Context(比如 “数据采集子智能体” 只存采集结果,“文案撰写子智能体” 只存文本草稿)。
    • 实现方式:用 “命名空间” 给不同 Context 打标签,调用时仅读取对应命名空间的内容。

智能体与上下文工程的实现方法

上下文是智能体思考、执行任务的 “信息依据”,保存Context、选择Context、压缩Context和隔离Context,这四个操作,智能体实现 “多轮循环工作” 的核心支撑 —— 它们解决了智能体 “上下文怎么存、怎么用、怎么控量、怎么防干扰” 的问题。

智能体流程环节 对应的 Context 操作 操作细节补充 操作核心作用
思考前的准备(前置步骤) 1. 选择 Context
2. 压缩 Context
3. 隔离 Context
1. 选择方式:- 静态选择:所有已保存内容全量放入 Context- 动态选择:仅选与当前用户问题最相关的内容
2. 压缩对象:优先处理「模型输出文本」「工具执行结果」(尤其 Base64 编码的图片类长内容),用 auto-compact 自动精简
3. 隔离方式:构建多个子智能体,按任务分配上下文
1. 适配不同任务场景(全量 / 精准调用上下文)
2. 避免 Base64 等长内容耗尽模型 token 窗口
3. 实现子智能体间数据隔离,防止任务串扰
思考环节(规划任务) 依赖 “准备环节处理后的 Context” 基于「筛选 + 压缩 + 隔离后的上下文」规划任务 确保任务规划的信息精准、无冗余、无干扰
执行工具环节(处理任务) 依赖 “思考环节的规划结果” 调用对应工具(如搜索 / 文本生成 / 图片处理工具),执行当前任务 按规划完成任务的具体操作,产出中间 / 最终结果
获取结果环节(任务产出) 无(衔接后续操作) 接收工具执行结果(含模型输出文本、工具返回数据、Base64 编码内容等) 得到当前轮次任务的直接产出,作为上下文素材
结果后处理(衔接下一轮) 保存 Context 将结果筛选 / 总结后,存储到「内存(临时缓存)」或「硬盘(持久化存储)」 留存当前任务结果,作为下一轮流程的上下文依据
循环衔接(进入下一轮) 回到 “思考前的准备环节”,重复 Context 操作 基于新保存的上下文,再次执行 “选择→压缩→隔离” 流程 持续迭代推进复杂任务,同时保证上下文的有效性与可控性

流程图如下:

graph LR
    %% 前置:Context来源
    A[Context来源
智能体任务产出:
1. 模型输出文本
2. 工具执行结果(含Base64多媒体)
3. 用户反馈/中间状态] B[保存Context
核心操作:
1. 存储介质:内存(临时)/ 硬盘(持久化)
2. 存储策略:全量保存/增量保存] C[选择Context
两种方式:
1. 静态选择:全量放入
2. 动态选择:筛选用户问题相关内容] D[压缩Context(auto-compact)
重点压缩对象:
1. 模型输出长文本
2. Base64编码多媒体
3. 冗余工具结果] E[隔离Context
隔离维度:
1. 按任务隔离(命名空间)
2. 按子智能体隔离(数据互不干扰)] F[输出处理后的优质Context
供给智能体「思考」环节] G[智能体执行流程
1. 思考规划
2. 调用工具
3. 获取任务结果] %% 节点连接关系 A --> B B --> C C --> D D --> E E --> F F --> G G --> A %% 样式定义(用class命令绑定,规避:::简写兼容问题) class A sourceStyle class B,C,D,E coreStyle class F outputStyle class G agentStyle classDef sourceStyle fill:#f0f9ff,stroke:#2563eb,stroke-width:2px,rounded:true classDef coreStyle fill:#fef7fb,stroke:#c026d3,stroke-width:2px,rounded:true classDef outputStyle fill:#f0fdf4,stroke:#16a34a,stroke-width:2px,rounded:true classDef agentStyle fill:#fffbeb,stroke:#d97706,stroke-width:2px,rounded:true