LLM-based Agent 超长上下文处理:工程实践优化策略

Article Directory
  1. 1. 核心挑战:超长上下文引发的“记忆过载”问题
    1. 1.1 上下文长度限制与信息丢失
    2. 1.2 无关信息导致的模型“分心”与性能下降
    3. 1.3 计算成本与延迟的显著增加
  2. 2. 核心策略:上下文工程
    1. 2.1 选择:精准注入相关信息
      1. 2.1.1 基于检索增强生成的片段选择
      2. 2.1.2 基于问题驱动的动态检索
      3. 2.1.3 利用嵌入模型进行语义相似度检索
    2. 2.2 压缩:减少 Token 开销,保留关键信息
      1. 2.2.1 针对自然语言文本的摘要与总结
      2. 2.2.2 针对代码的特定压缩策略
      3. 2.2.3 利用小型模型进行内容重要性评估与压缩
    3. 2.3 写入与隔离:构建外部记忆与分割上下文
      1. 2.3.1 构建外部知识库或向量数据库
      2. 2.3.2 采用多轮对话或记忆更新机制
      3. 2.3.3 分割上下文空间以避免信息冲突
  3. 3. 进阶技术:结合记忆机制与检索增强
    1. 3.1 MemAgent:模仿人类“边读边记”的渐进式理解
      1. 3.1.1 分块处理与记忆更新机制
      2. 3.1.2 强化学习驱动的记忆策略优化
      3. 3.1.3 结合 RAG 进行高效检索与精读
    2. 3.2 聚焦 Transformer:解决模型“分心”问题
      1. 3.2.1 记忆注意力层机制
      2. 3.2.2 对比学习以区分相关与无关信息
      3. 3.2.3 在推理时动态访问外部记忆
  4. 4. 实践框架与工具
    1. 4.1 LangChain:构建端到端的 RAG 应用
      1. 4.1.1 文档加载与处理流程
      2. 4.1.2 向量存储与检索实现
      3. 4.1.3 结合 LangGraph 和 LangSmith 进行调试与优化
    2. 4.2 特定模型与 API 的应用
      1. 4.2.1 利用支持长上下文的先进模型
      2. 4.2.2 调用嵌入 API 进行语义检索
  5. 5. 针对特定场景的优化策略
    1. 5.1 文档智能:结构化信息提取与知识图谱构建
    2. 5.2 代码生成与理解:代码去重、结构分析与片段检索
    3. 5.3 深度研究:多源信息整合与交叉验证

本文初版文本由 Kimi Deep Research 结合互联网资料生成,原对话链接:https://www.kimi.com/share/d3a0ju9toom8l0ielitg ;由 HairlessVillager 校对与排版。

1. 核心挑战:超长上下文引发的“记忆过载”问题

在构建基于大语言模型(LLM)的智能体(Agent)时,处理超长上下文是实现文档智能、代码生成与理解、深度研究等高级应用的关键瓶颈。这些应用场景通常涉及远超模型标准上下文窗口(Context Window)的输入,例如分析数十万字的法律合同、理解包含多个模块和依赖关系的复杂代码库,或整合来自不同研究报告的分散信息。这种“记忆过载”问题主要体现在三个层面:上下文长度限制导致的信息丢失、无关信息引发的模型“分心”与性能下降,以及计算成本与延迟的急剧增加。这些问题共同构成了 LLM-based Agent 在处理真实世界复杂任务时必须克服的核心障碍。

1.1 上下文长度限制与信息丢失

大语言模型的上下文窗口大小是有限的,例如早期的 GPT-3 模型限制在 2048 个 token,尽管后续模型如 GPT-4 和 Claude 系列已将此限制扩展至数万甚至百万级别,但在面对超长文档时,这一限制依然存在 。当输入文本的长度超过模型的上下文窗口时,最直接的解决方案是截断文本。然而,这种粗暴的截断方式会导致关键信息的永久性丢失。例如,在分析一份长篇财报时,如果截断了包含关键财务数据的段落,模型将无法生成准确的分析摘要。同样,在代码理解任务中,截断可能恰好移除了定义关键函数或变量的部分,导致模型对代码逻辑的理解出现根本性错误。这种信息丢失问题在处理需要全局视野的任务时尤为致命,例如,在深度研究中,核心论点可能分散在文档的不同部分,截断任何一部分都可能导致结论的片面性或错误。

1.2 无关信息导致的模型“分心”与性能下降

即使能够将超长文本全部塞入一个巨大的上下文窗口,另一个严峻的挑战是无关信息的干扰。在超长上下文中,与当前任务(如回答特定问题或生成特定代码片段)真正相关的信息可能只占很小一部分。大量不相关的文本内容会分散模型的注意力,这种现象被称为“分心”(Distraction)或“大海捞针”(Needle in a Haystack)问题 。研究表明,随着上下文长度的增加,模型从海量信息中准确定位并利用关键信息的能力会显著下降。这不仅会降低生成答案的准确性,还可能导致模型产生幻觉(Hallucination),即基于不相关的上下文生成看似合理但实际上是错误的输出。例如,在代码生成任务中,如果上下文包含了多个功能相似但实现不同的代码模块,模型可能会混淆它们,生成一个结合了不同模块错误特征的“缝合怪”代码。这种性能下降使得简单地扩展上下文窗口长度并不能线性地提升模型在复杂任务上的表现。

1.3 计算成本与延迟的显著增加

从工程实践的角度看,处理超长上下文带来的计算成本和延迟是不可忽视的挑战。Transformer 架构的核心是自注意力机制(Self-Attention),其计算复杂度和内存消耗与输入序列长度(N)呈二次方关系,即 O(N²)。这意味着,当上下文长度增加一倍时,所需的计算资源和处理时间将增加近四倍。这种指数级的增长使得在有限的硬件资源下处理超长文本变得极其昂贵且缓慢。例如,处理一个包含 100 万 token 的文档,其计算量可能是处理 1 万 token 文档的 1 万倍。这不仅增加了运营成本,也使得实时交互式应用(如实时代码助手或交互式文档问答)变得不切实际。因此,任何旨在处理超长上下文的工程策略,都必须在提升模型能力和控制计算成本之间找到一个精妙的平衡点。

2. 核心策略:上下文工程

为了应对超长上下文带来的挑战,研究人员和工程师们提出了一系列统称为“上下文工程”(Context Engineering)的优化策略。这些策略的核心思想不再是被动地接受或拒绝超长输入,而是主动地、智能地管理和操作输入给模型的上下文,以期在有限的上下文窗口内,为模型提供最相关、最精炼、最有价值的信息。上下文工程可以被视为构建高效 LLM-based Agent 的“操作系统”,它通过一系列精细化的操作,如选择(Select)、压缩(Compress)、写入(Write)和隔离(Isolate),来最大化模型的性能 。这些策略并非相互排斥,而是可以根据具体的应用场景自由组合,形成一个强大的、可编排的上下文处理流水线。

2.1 选择:精准注入相关信息

“选择(Select)”策略的核心目标是从海量的原始上下文中,筛选出与当前任务最相关的片段,并将其注入到模型的上下文窗口中。这种方法避免了将整个超长文本一次性输入模型,从而有效解决了信息过载和计算成本高的问题。其基本范式是“检索增强生成”(Retrieval-Augmented Generation, RAG),即通过一个独立的检索模块,根据用户的查询,从一个庞大的知识库中找到最相关的文档或文本块,然后将这些精选的内容作为上下文提供给 LLM,以辅助其生成更准确、更具信息量的答案 。

2.1.1 基于检索增强生成的片段选择

检索增强生成(RAG)是实现“选择”策略最主流和成熟的框架。其工作流程通常包括三个步骤:索引(Indexing)、检索(Retrieval)和生成(Generation)。在索引阶段,一个庞大的文档库(如技术文档、代码库、研究报告)被分割成多个文本块(Chunks),每个文本块通过一个嵌入模型(Embedding Model)被转换成一个高维向量,并存储在向量数据库中 。在检索阶段,当用户提出一个问题时,该问题同样被转换成向量,然后在向量数据库中进行相似度搜索,找出与问题向量最相似(即语义上最相关)的 Top-K 个文本块。最后,在生成阶段,这些检索到的文本块被作为上下文,与用户的原始问题一起,输入到 LLM 中,引导模型生成基于这些特定信息的答案 。这种方法将 LLM 从一个纯粹的知识生成器转变为一个基于外部知识的推理器,极大地扩展了其知识边界和事实准确性。

2.1.2 基于问题驱动的动态检索

在复杂的深度研究或代码理解任务中,单一轮次的检索可能不足以获取所有必要信息。例如,回答一个多跳(Multi-hop)问题,可能需要先从一个文档中找到初步信息,然后基于这些信息去检索另一个文档。为了应对这种情况,可以采用更高级的、基于 Agent 的动态检索策略。在这种模式下,LLM Agent 不再被动地接收检索结果,而是主动地参与到检索过程中。Agent 可以根据初步的检索结果,判断信息是否足够,如果不足,它可以自主地生成新的、更具针对性的检索查询(Query),并发起新一轮的检索。这个过程可以迭代进行,直到 Agent 认为已经收集了足够的信息来回答原始问题。这种动态、迭代的检索方式,使得 Agent 能够像人类研究员一样,通过不断探索和追问,逐步深入复杂问题的核心,从而处理那些信息高度分散的超长上下文场景。

2.1.3 利用嵌入模型进行语义相似度检索

RAG 框架的核心是语义相似度检索,而这高度依赖于嵌入模型的质量。嵌入模型负责将文本(无论是文档块还是用户查询)映射到一个连续的向量空间,在这个空间中,语义上相似的文本在距离上也应该更接近。因此,选择一个强大的嵌入模型对于 RAG 系统的性能至关重要。在实践中,通常会使用像 OpenAI 的text-embedding-3-smalltext-embedding-3-large这样的通用嵌入模型 。然而,对于特定领域(如法律、医疗、金融),使用领域内的数据对嵌入模型进行微调(Fine-tuning)可以显著提升检索的准确性。此外,检索策略本身也在不断演进。除了简单的向量相似度搜索,还可以采用混合检索(Hybrid Search),结合关键词匹配(如 BM25 算法)和向量检索,以兼顾精确匹配和语义匹配。更先进的两阶段检索(Two-stage Retrieval)会先使用一个轻量级的检索模型快速召回大量候选文档,然后使用一个更强大的、被称为“重排器”(Reranker)的模型对这些候选文档进行精细的排序,从而将最相关的文档送入 LLM 的上下文窗口 。

2.2 压缩:减少 Token 开销,保留关键信息

“压缩(Compress)”策略的目标是在不损失关键信息的前提下,尽可能地减少输入给 LLM 的 Token 数量。这不仅能降低计算成本,还能为模型腾出更多的上下文空间来容纳更多相关的信息片段。压缩可以应用于不同的层面,包括对整个文档进行摘要,对检索到的文本块进行精炼,甚至对模型内部的 KV 缓存进行优化。

2.2.1 针对自然语言文本的摘要与总结

文本摘要(Summarization)是压缩自然语言文本最直接的方法。它分为抽取式(Extractive)和生成式(Abstractive)两种。抽取式摘要从原文中选择最重要的句子或短语来组成摘要,而生成式摘要则使用模型来理解原文的含义,并生成全新的、更简洁的文本。在工程实践中,可以利用现成的 API 或开源库来实现文本摘要。例如, Chrome 浏览器内置的 Summarizer API 提供了多种摘要类型(如tl;drkey-points)和长度选项(shortmediumlong),可以方便地集成到前端应用中 。在 Python 生态中,sumy库是一个强大的文本摘要工具,它支持多种算法,包括基于潜在语义分析(LSA)的算法、基于图的算法(如 LexRank、TextRank)以及基于词频和位置的算法(如 Luhn)。这些工具可以帮助开发者快速地将长篇文档压缩成精炼的摘要,作为 LLM 的输入。

2.2.2 针对代码的特定压缩策略

对于代码这种结构化文本,通用的文本摘要方法可能效果不佳。因此,需要采用针对代码的特定压缩策略。一种常见的方法是代码去重和结构分析。例如,在分析一个大型代码库时,可以首先识别出重复的代码块(如通过抽象语法树 AST 比对),并将其替换为对共享函数或模块的引用。此外,可以提取代码的元数据,如函数签名、类定义、关键注释和依赖关系,形成一个高度浓缩的代码“骨架”,而不是将整个代码文件内容都输入模型。对于特定的代码理解任务,例如“解释函数 X 的功能”,可以只提取函数 X 的定义及其直接相关的依赖(如被调用的其他函数、引用的全局变量),而忽略代码库中其他无关的部分。这种基于代码结构和依赖关系的智能压缩,能够在保留核心逻辑的同时,极大地减少 Token 消耗。

2.2.3 利用小型模型进行内容重要性评估与压缩

一种更智能的压缩方法是利用一个专门的小型模型来评估文本块中每个 Token 或句子对最终任务的重要性,然后只保留最重要的部分。例如,可以训练一个轻量级的分类器来判断一个句子是否包含关键信息。在推理时,先用这个分类器对所有文本块进行打分,然后只将高分句子送入 LLM 。另一种更前沿的方法是上下文压缩(In-context Autoencoder, ICAE),它通过一个自编码器将长上下文压缩成一个紧凑的、固定长度的“记忆槽”(Memory Slot),LLM 可以直接基于这个记忆槽进行生成 。这种方法可以实现极高的压缩率,并且压缩过程是可学习的。此外,一些研究提出了基于困惑度(Perplexity)的压缩方法,即计算每个句子在给定上下文下的困惑度,困惑度高的句子被认为是模型难以理解的,可能包含新信息,因此应该被保留,而困惑度低的句子则可能是冗余的,可以被压缩 。

2.3 写入与隔离:构建外部记忆与分割上下文

“写入(Write)”和“隔离(Isolate)”策略的核心思想是将 LLM 的内部上下文窗口与外部存储系统相结合,构建一个层次化的记忆架构,并通过分割上下文来避免信息冲突和干扰。这允许 Agent 在超越单个上下文窗口限制的情况下,维护和利用长期、跨会话的知识。

2.3.1 构建外部知识库或向量数据库

“写入”策略最直接的体现就是构建外部知识库。这通常通过 RAG 系统中的向量数据库来实现。当新的文档或信息进入系统时,它们被处理、嵌入并存储到向量数据库中,从而“写入”了 Agent 的长期记忆。这种外部存储是持久的,可以跨多个用户会话和任务使用。除了向量数据库,还可以使用更结构化的存储方式,如知识图谱(Knowledge Graph)。知识图谱将信息表示为实体(Entities)和关系(Relationships),能够更好地捕捉复杂的、多跳的知识关联。例如,GraphRAG 框架会先从文档中提取实体和关系构建知识图谱,当回答问题时,先在图谱中进行检索,找到相关的子图,然后再将子图信息提供给 LLM,这对于回答需要整合多个信息源的复杂问题非常有效 。

2.3.2 采用多轮对话或记忆更新机制

为了在交互过程中维护一个连贯的、不断演化的记忆,可以采用多轮对话或记忆更新机制。例如,LangGraph 等框架允许 Agent 在对话过程中将关键信息写入一个持久化的状态(State)中 。一个更高级的模式是“滚动摘要”(Rolling Summary)或“记忆更新”(Memory Update)。在这种模式下,Agent 的对话历史被分为两部分:一个是对迄今为止所有对话的精炼总结(Summary),另一个是最近的几条消息(Messages)。当新的消息到来时,一个专门的“总结器”节点会读取旧的摘要和最新消息,然后生成一个新的、更新后的摘要,并清空消息列表。这样,Agent 的“记忆”始终是精炼和最新的,避免了上下文无限增长的问题。MemAgent 模型则采用了一种更激进的覆盖式更新策略,每处理一个新的文本块,就用新生成的记忆完全覆盖旧的记忆,迫使模型在有限的记忆空间内做出最优的信息保留决策 。

2.3.3 分割上下文空间以避免信息冲突

“隔离”(Isolate)策略旨在通过分割上下文空间来避免不同任务或信息源之间的相互干扰。这在处理需要同时执行多个独立子任务的复杂工作时尤为重要。例如,一个 Agent 需要同时分析两份不同的合同,如果将两份合同的内容都放在同一个上下文窗口中,模型可能会混淆其中的条款。通过隔离策略,可以为每个任务创建一个独立的子 Agent 或沙盒环境,每个子 Agent 只处理与其任务相关的上下文 。在 LangGraph 中,这可以通过定义不同的状态模式(State Schema)来实现,确保不同子图(Subgraph)的状态是相互隔离的。这种上下文隔离不仅提高了任务执行的准确性,也使得整个系统更易于调试和维护,因为可以独立地追踪和优化每个子任务的执行流程。

3. 进阶技术:结合记忆机制与检索增强

在基础的上下文工程策略之上,研究者们正在探索更先进的、将记忆机制与检索增强深度融合的技术。这些技术旨在让 LLM-based Agent 不仅能被动地接收和检索信息,还能像人类一样,主动地、有策略地管理自己的记忆,并在处理超长上下文时进行复杂的推理。其中,MemAgent 模型通过模仿人类“边读边记”的认知过程,为渐进式文本理解提供了一个创新的解决方案。

3.1 MemAgent:模仿人类“边读边记”的渐进式理解

MemAgent 是一种新颖的 LLM 方法,旨在解决处理任意长度输入的挑战,同时保持线性时间复杂度并避免性能下降 。与传统长上下文模型试图通过扩展上下文窗口来“一次读完”所有文本不同,MemAgent 反其道而行之,它认为 LLM 无需拥有超大记忆力,只需学会像人一样聪明地工作即可 。其核心思想是将一个不可能完成的单次超长推理任务,分解成一系列简单的、可管理的迭代式状态更新任务。这种工作流模仿了人类阅读长文档时的行为:我们不会试图一次性记住所有内容,而是边读边做笔记,不断更新和精炼我们对文档核心内容的理解。

3.1.1 分块处理与记忆更新机制

MemAgent 的工作流程分为两个主要阶段:上下文处理(Context-Processing)和答案生成(Answer-Generation)。

  1. 上下文处理 (Context-Processing) :这是整个流程的核心。模型不会一次性看到全部文本,而是将长文档切分成固定大小的文本块(Chunks)。它会一块一块地阅读,每读完一块,就在一个固定大小的记忆区(Memory)中更新笔记。这个记笔记的过程是覆盖式的,即新笔记会完全取代旧笔记。模型必须在有限的笔记空间里,自己决定保留什么、丢弃什么、新增什么。这种简单的覆盖策略是系统实现扩展的关键:因为这样做记忆长度永远不会增长,每个块的总计算量保持为 O(1) 。

  2. 答案生成 (Answer-Generation) :当所有文本块都读完后,模型不再看原始文档。它只根据最终那份浓缩了全文精华的笔记和原始问题,来生成最终答案。

这个流程的精妙之处在于:

  • 线性复杂度 (O(N)) :由于每次处理的输入(问题+文本块+记忆)大小是固定的,总计算量只与文本块的数量成正比,完美解决了二次方复杂度的瓶颈。
  • 无限长度处理: 理论上,只要时间允许,这个迭代过程可以无限持续,从而处理任意长度的文档。
  • 能力倒逼: 由于最后回答问题时看不到原文,这迫使模型在记笔记阶段就必须学会精准地提炼和保留所有关键信息。

3.1.2 强化学习驱动的记忆策略优化

MemAgent 的核心挑战在于如何训练模型学会这种复杂的、多步骤的记笔记策略。由于没有标准的“好笔记”作为监督信号,作者将这个问题建模为一个强化学习(RL)问题 。记忆更新被视为策略(Policy)的一部分,并通过优化最终答案的正确性(即结果奖励)来进行训练。

具体来说,MemAgent 提出了一种名为多对话 DAPO(Multi-Conv DAPO) 的强化学习算法。DAPO 本身是一种用于大模型对齐的 RL 算法,而 Multi-Conv 则是针对 MemAgent 工作流的特殊扩展 。其核心思想是“一荣俱荣,一损俱损”:

  1. Rollout :对于一个训练样本(问题+长文档),让模型完整地执行一遍 MemAgent 工作流,生成一系列中间记忆和最终答案。
  2. Reward :用一个简单的基于规则的验证器(比如,答案是否与标准答案完全匹配)来给最终答案打分。答对得高分,答错得低分。
  3. 计算优势 (Advantage) :将获得的分数与同一批次其他样本的平均分进行比较,得出一个“优势值”。
  4. 统一应用 (The “Multi-Conv” Part) :计算出的这个优势值,会被无差别地、平等地应用到该样本所有的中间记忆更新步骤中。

这种方法巧妙地解决了“信用分配(Credit Assignment)”难题,即如何将最终答案的正确性归因于中间的每一个步骤。通过这种方式,模型能够学习到有效的记忆更新策略,学会在有限的记忆空间内保留对最终任务最重要的信息,忽略无关细节。

3.1.3 结合 RAG 进行高效检索与精读

虽然 MemAgent 本身通过迭代处理实现了对超长文本的覆盖,但其核心机制与 RAG 的理念是相辅相成的。可以将 MemAgent 的记忆更新过程看作是一种动态的、在线的上下文压缩和选择。在每个迭代步骤中,模型都在“选择”哪些信息值得被写入记忆,并“压缩”旧记忆以腾出空间。这种机制可以被看作是 RAG 的一种泛化形式,其中检索和生成被紧密地耦合在一个迭代循环中。

在实践中,可以将 MemAgent 与标准的 RAG 流程结合,形成一个更强大的系统。例如,可以先用 RAG 从一个庞大的知识库中检索出与问题相关的多个长文档,然后将这些长文档作为输入,交由 MemAgent 进行渐进式的精读和理解。MemAgent 的线性复杂度使其能够高效地处理这些由 RAG 筛选出的长上下文,而其强化学习驱动的记忆机制则能确保在精读过程中不遗漏关键信息。这种结合方式既利用了 RAG 在海量信息中快速定位相关文档的能力,又利用了 MemAgent 在超长文档中进行深度理解和推理的能力,从而构建一个既能“广撒网”又能“深钻研”的智能 Agent。

3.2 聚焦 Transformer:解决模型“分心”问题

聚焦 Transformer(Focused Transformer, FoT)是一种旨在解决 LLM 在处理超长上下文时“分心问题”(Distraction Issue)的创新技术 。当上下文窗口被大量文档填充时,与当前任务相关的信息(信号)会被淹没在大量无关信息(噪音)中,导致模型注意力分散,性能下降。FoT 通过引入一种受对比学习启发的训练过程,优化了模型内部键值(key-value)空间的结构,使其能够更好地区分相关与无关信息,从而有效扩展了模型的有效上下文长度 。

3.2.1 记忆注意力层机制

FoT 的核心创新之一是引入了“记忆注意力层”(Memory Attention Layers)。在标准的 Transformer 模型中,每个 token 的注意力计算仅限于当前上下文窗口内的其他 token。而 FoT 的记忆注意力层则允许模型在推理时,访问一个外部的、可扩展的“记忆库”。这个记忆库中存储了预先处理好的键值对(key-value pairs)。当模型处理一个新的查询(query)时,它不仅会关注本地上下文,还会通过 k 近邻(kNN)搜索算法,从记忆库中检索出与当前查询最相关的 top-k 个键值对 。这种机制可以被视为对全密集注意力的一种高效近似,它使得模型能够利用远超其上下文窗口长度的历史信息,而无需在每次推理时都重新处理这些长文本。在 LongLLaMA 的实现中,为了简化计算,记忆层中的键值对通常不包含位置编码,将 kNN 搜索视为一种无位置的注意力机制 。

3.2.2 对比学习以区分相关与无关信息

为了让记忆注意力层能够有效地检索到相关信息,FoT 采用了一种名为“CrossBatch”的对比学习训练方法 。该方法的关键思想是,在训练过程中,不仅将来自同一文档的当前片段和先前片段作为“正样本”(positive examples),还将来自其他不相关文档的片段作为“负样本”(negative examples)。通过这种方式,模型被训练去最大化正样本之间的相似度,同时最小化负样本之间的相似度。这种对比学习的过程,使得模型能够更好地学习到如何区分语义上相关和无关的键值对,从而在推理时能够更精准地从记忆库中检索出有用的信息。整个训练过程是可微分的,这意味着记忆注意力层的参数可以通过标准的反向传播进行优化 。

3.2.3 在推理时动态访问外部记忆

在推理阶段,FoT 模型能够动态地利用其外部记忆。当模型接收到一个长文档时,它会将文档分割成多个片段,并依次处理。在处理每个新片段时,模型会利用记忆注意力层,从之前处理过的所有片段(存储在外部记忆中)中检索出最相关的信息,并将其与当前片段的上下文结合起来,共同用于生成输出。这种“边读边记”的机制,使得模型能够以一种渐进的方式,构建对整个长文档的理解。实验表明,通过 FoT 技术微调的 LongLLaMA 模型,在处理 passkey retrieval 任务时,能够在远超其训练上下文长度(8K)的场景下保持高准确率,例如在 100k 长度的提示下准确率达到 94.5%,甚至在 256k 长度下仍有 73%的准确率,这充分证明了其强大的长上下文外推能力 。

4. 实践框架与工具

将上述优化策略从理论转化为实际应用,离不开强大的实践框架和工具的支持。这些框架和工具为开发者提供了构建、部署和优化 LLM-based Agent 的“脚手架”,极大地降低了技术门槛,并加速了开发迭代周期。其中,LangChain 作为目前最流行的 LLM 应用开发框架之一,为构建端到端的 RAG 应用提供了全面的支持。同时,各种特定模型和 API 的涌现,也为开发者提供了丰富的“武器库”,可以根据具体需求选择最合适的组件。

4.1 LangChain:构建端到端的 RAG 应用

LangChain 是一个开源框架,旨在简化由语言模型驱动的应用程序的开发流程。它提供了一套模块化的组件和预置的链(Chains),使得开发者可以像搭积木一样快速构建复杂的 LLM 应用,特别是 RAG 系统 。LangChain 的核心价值在于它将 RAG 流程中的各个环节——从文档加载、文本分割、嵌入生成、向量存储到最终的检索和生成——都进行了标准化和封装,让开发者可以专注于业务逻辑,而不是重复造轮子。

4.1.1 文档加载与处理流程

LangChain 提供了丰富的文档加载器(Document Loaders),可以方便地从各种来源加载数据,包括本地文件(如 TXT, PDF, Markdown)、网页、数据库、API 等。加载文档后,一个至关重要的步骤是文本分割(Text Splitting)。LangChain 内置了多种文本分割器,如RecursiveCharacterTextSplitter,它可以根据一组预定义的分隔符(如\n\n, \n, )递归地分割文本,并允许设置块大小(chunk_size)和块重叠(chunk_overlap),以在保持语义完整性和控制块大小之间取得平衡 。这种灵活的分割策略对于后续生成高质量的嵌入和实现精准的检索至关重要。例如,在处理 Markdown 文档时,可以优先按标题进行分割,以更好地保留文档的结构信息。

4.1.2 向量存储与检索实现

在文本被分割成块之后,LangChain 通过其嵌入(Embeddings)接口,可以方便地调用各种嵌入模型(如 OpenAI, Hugging Face 上的模型)将文本块转换为向量。然后,这些向量可以被存储到多种向量数据库(Vector Stores)中,如 Pinecone, Milvus, Chroma, FAISS 等。LangChain 为所有这些主流向量数据库提供了统一的接口,使得切换底层存储变得非常简单。当需要进行检索时,LangChain 的检索器(Retrievers)会接收用户的查询,将其转换为向量,并在向量数据库中执行相似度搜索,返回最相关的文本块。这种模块化的设计使得开发者可以轻松地实验不同的嵌入模型和向量数据库组合,以找到最适合其应用场景的方案。

4.1.3 结合 LangGraph 和 LangSmith 进行调试与优化

为了构建更复杂、更具交互性的 Agent,LangChain 团队推出了 LangGraph。LangGraph 允许开发者使用图(Graph)的结构来定义 Agent 的工作流,其中每个节点(Node)代表一个 LLM 调用或一个工具调用,边(Edge)则定义了执行的流程。这种基于状态机(State Machine)的模型非常适合实现需要多步推理、循环和条件判断的复杂 Agent 逻辑,例如上文提到的动态检索和记忆更新机制 。与 LangGraph 配套的是 LangSmith,一个用于调试、测试、监控和评估 LLM 应用的平台。LangSmith 可以详细记录下每一次 Chain 或 Agent 执行的完整轨迹,包括中间步骤、Token 消耗、延迟等,帮助开发者直观地理解 Agent 的内部工作过程,并量化评估不同上下文策略(如选择、压缩)对最终性能(如响应质量、工具命中率)的影响,从而实现数据驱动的优化 。

4.2 特定模型与 API 的应用

除了使用 LangChain 等框架进行组合式开发,直接利用一些先进的、支持长上下文的特定模型和 API,也是处理超长上下文的有效途径。这些模型和 API 通常由大型 AI 公司(如 OpenAI, Anthropic, Google)提供,它们在底层架构和训练数据上进行了专门的优化,以支持更长的上下文窗口。

4.2.1 利用支持长上下文的先进模型

近年来,各大 AI 厂商在扩展上下文窗口方面展开了激烈的竞赛。例如,Anthropic 的 Claude 3 系列模型支持高达 200K 的上下文窗口,而 Google 的 Gemini 1.5 Pro 更是将这一数字提升到了 100 万 token。这些模型通过采用更高效的注意力机制(如稀疏注意力、混合专家模型 MoE)和优化的位置编码方案,在保持性能的同时,显著提升了可处理的上下文长度 。对于一些应用场景,如果超长文本的长度在这些模型的支持范围内,并且成本可接受,那么直接使用这些模型可能是最简单的解决方案。然而,需要注意的是,即使上下文窗口足够长,“大海捞针”问题依然存在,模型在长文本中定位关键信息的能力仍然是一个挑战。

4.2.2 调用嵌入 API 进行语义检索

在构建 RAG 系统时,嵌入模型的选择至关重要。OpenAI 提供的嵌入 API,如text-embedding-3-smalltext-embedding-3-large,是目前业界广泛使用的选择 。这些模型在大量数据上进行了训练,能够生成高质量的文本向量,适用于多种语言的语义检索任务。调用这些 API 非常简单,只需将文本作为输入,即可返回对应的向量表示。将这些 API 与 LangChain 等框架结合,可以快速搭建起一个功能强大的 RAG 系统。除了 OpenAI,还有许多其他优秀的嵌入模型可供选择,如 Cohere 的嵌入模型,以及 Hugging Face 上大量开源的、针对特定领域优化的嵌入模型。选择合适的嵌入模型,是确保 RAG 系统检索精度的关键一步。

5. 针对特定场景的优化策略

虽然通用的上下文工程策略为处理超长上下文提供了坚实的基础,但在不同的应用场景中,还需要结合领域知识进行针对性的优化。文档智能、代码生成与理解、深度研究这三个场景,由于其数据特性和任务需求的差异,对上下文处理提出了各自独特的挑战和要求。因此,在应用通用策略的同时,必须设计专门的优化方案,以最大化 LLM-based Agent 在特定任务上的性能。

5.1 文档智能:结构化信息提取与知识图谱构建

在文档智能场景中,处理的对象通常是结构复杂、信息密集的文档,如 PDF 报告、合同、论文等。这些文档不仅包含纯文本,还包含表格、图表、标题、列表等丰富的结构信息。粗暴的文本分割很容易破坏这些结构,导致语义丢失。因此,优化的关键在于尽可能地保留和利用文档的原始结构。

一种有效的策略是文档结构感知分割。例如,在处理 PDF 文档时,可以首先使用专门的工具(如 pdfplumber, unstructured.io)提取文档的物理布局信息,识别出标题、段落、表格、图片等元素。然后,根据这些结构信息进行分割,例如,将一个完整的章节或一个独立的表格作为一个文本块。这种方法可以确保每个文本块内部的语义完整性。

更进一步,可以将提取出的结构化信息用于构建知识图谱(Knowledge Graph) 。通过命名实体识别(NER)和关系抽取(RE)技术,可以从文档中识别出关键的实体(如人名、公司、产品、日期)以及它们之间的关系。然后,将这些实体和关系存储在图数据库(如 Neo4j)中,形成知识图谱。当需要回答问题时,可以先在知识图谱中进行查询,找到相关的实体和关系,然后再将这些结构化的信息提供给 LLM。GraphRAG 就是基于这一思想,它将文档库转化为一个由实体和关系构成的图,从而能够高效地回答需要整合多源信息的复杂问题,特别是那些普通 RAG 难以处理的全局性问题 。

5.2 代码生成与理解:代码去重、结构分析与片段检索

代码是一种高度结构化的语言,具有严格的语法和逻辑关系。因此,在处理代码相关的超长上下文时,必须采用与处理自然语言不同的策略。

首先,代码去重和结构分析至关重要。在一个大型代码库中,往往存在大量的重复代码或功能相似的代码。在将代码输入模型之前,可以先进行去重处理,以减少冗余信息。更重要的是,应该利用代码的抽象语法树(AST)进行分析。通过解析代码的 AST,可以准确地识别出函数、类、变量定义以及它们之间的调用关系。基于 AST,可以实现更智能的上下文选择。例如,当需要理解一个特定函数时,可以只提取该函数的定义、其调用的其他函数以及引用到的全局变量,而忽略代码库中其他无关的部分。

其次,基于语义的代码检索是提升代码生成与理解能力的关键。传统的代码检索主要基于关键词匹配,这在很多情况下效果不佳。例如,用户想找一个“实现快速排序”的函数,但代码中可能并没有“quick sort”这个关键词。通过使用专门在代码数据上训练过的嵌入模型(如 CodeBERT, GraphCodeBERT),可以实现基于语义的代码检索。这些模型能够理解代码的深层含义,即使函数名或注释中没有直接的关键词,也能根据其实现逻辑找到相关的代码片段。将这种语义检索与 LLM 结合,可以构建出强大的代码助手,能够根据自然语言描述生成代码、解释复杂代码逻辑、甚至自动修复代码错误。

5.3 深度研究:多源信息整合与交叉验证

深度研究任务通常涉及从多个不同的信息源(如多篇学术论文、新闻报道、市场分析报告)中收集、整合信息,并形成一个全面、有深度的结论。这种场景对 LLM-based Agent 提出了更高的要求,不仅需要处理每个信息源内部的超长上下文,还需要在多个信息源之间进行有效的信息整合和交叉验证。

为了实现多源信息整合,可以采用多 Agent 协作的框架。可以为每个信息源分配一个专门的子 Agent,该 Agent 负责阅读和理解该信息源的内容,并生成一个摘要或报告。然后,由一个更高层次的“协调者”Agent(Coordinator Agent)来收集所有子 Agent 的报告,并对这些信息进行综合分析、比较和整合,最终生成一份完整的研究报告。这种分而治之的策略,可以有效地处理来自多个超长文档的信息。

交叉验证是确保研究结论准确性和可靠性的重要步骤。在生成最终结论之前,Agent 应该能够识别出不同信息源之间的一致性和矛盾之处。例如,如果两篇论文对同一个实验得出了相反的结论,Agent 应该能够指出这种矛盾,并可能需要进一步检索信息来解释这种差异。这可以通过设计特定的提示(Prompt)来实现,要求 LLM 在生成答案时,不仅要陈述事实,还要分析不同来源信息的异同点。通过这种方式,LLM-based Agent 可以模拟人类研究员的批判性思维过程,从而产出更高质量的深度研究成果。

Author: HairlessVillager

Permalink: http://hairlessvillager.github.io/2025/09/24/llm-agent-long-context/

The article is licensed under the CC BY-NC-SA 4.0 protocol by default.

Please comply with the protocol when using it.