作者:来自 Elastic Anish Mathur

借助 Context Engine,相同的 agent 和模型仅用 64 秒和 9 次 工具调用 就给出了答案。基线方案则耗时 213 秒,进行了 33 次工具调用,而且完全遗漏了一项关键的关联关系。
Agent Builder 现已正式发布(GA)。立即开始使用 Elastic Cloud 试用版 ,并**点击此处**查看 Agent Builder 文档。
查询企业数据的 agent 会将大部分 token 消耗在数据发现上:了解 schema、字段的含义,以及实体之间如何在复杂且可能规模庞大的文档和数据源中相互关联。即使没有任何变化,它们也会在下一次查询时将这一切重新做一遍。
Context Engine 会在问题到来之前理解你的数据。它读取你的数据源,并将学到的内容存储为小型、结构化的上下文单元。因此,当任务到来时,agent 就能获取相关的上下文单元,从而跳过数据发现过程。我们基于 Elasticsearch 构建了一个 Context Engine,并发现其中的每个阶段实际上都是一个搜索问题。
自动化流程会搜索并预计算知识,将其存储在专用的 AI index 中,并在其中启用原生的**混合搜索**和检索能力。借助 Context Engine,agent 可以直接获取所需内容,而不必在原始数据中费力查找。
在一个示例中,使用相同的模型和数据后,工具调用次数从 33 次降至 9 次,输入 token 数量减少了 71%。此外,延迟从 213 秒降至 64 秒,agent 的回答也更加完整,揭示了原本可能被遗漏的关联关系。
没有 Context Engine 时,agent 会做什么
向数据 agent 提出一个具有战略意义的业务问题,例如:总结一下影响我们最大客户的那些问题。
如果没有辅助,一个能力不错的 agent 会先列出索引,以了解有哪些数据。它会读取 mappings,弄清楚哪些字段表示"客户",哪些字段表示"问题"。它会扫描合同,以确定客户账户的价值并找出最大的客户账户。在这个过程中,它可能会遗漏这样一个事实:有 5 个账户隶属于同一家母公司,因此低估了你最重要的客户关系之一。它也不知道 account_id 在 tickets 索引中有时会是 null,因此查询会在不知不觉中返回错误的部分数据行。
模型的推理本身没有问题,但在能够推理数据所表达的含义之前,agent 已经将大部分预算花在弄清楚数据是什么上了。而在下一次提问时,它还会重复整个过程。
然而,如果获得正确的上下文,agent 就能高效得多。基于 Elasticsearch 构建的 Context Engine 会从 tickets 和 contracts 等原始数据源中预计算知识,并在一开始就将这些知识提供给 agent,使其能够跳过实际推理答案之前那些成本高昂的步骤。
下表展示了针对上述业务问题,这种方式带来的优势。实验使用相同的 system prompt、模型和数据,唯一的区别在于 agent 是否能够从 Context Engine 中读取上下文。本文将进一步介绍如何构建 Context Engine,以及它如何带来这些优势。
| 相同的 prompt 和模型* | 没有 Context Engine | 使用 Context Engine |
|---|---|---|
| 工具调用次数 | 33 | 9 |
| 输入 token 数量 | 2,279,253 | 653,511 |
| 延迟 | 213 秒 | 64 秒 |
| 是否发现母公司关联关系 | 否 | 是 |
| 成本 | 基线 | 降低 71% |
在多个维度上,Context Engine 都提升了 agent 的性能。agent 减少了工具调用次数、token 消耗和延迟,同时能够给出更完整的答案。
* 运行时模型:claude-sonnet-5,使用 LangChain Deep Agent Harness;预计算阶段使用 claude-haiku-4-6,处理约 636K 个输入 token。
为什么 AI agent 需要上下文层
到目前为止,大多数**上下文工程**工作都集中在如何为单个 agent 的 上下文窗口 提供内容:prompt、工具定义、对话历史、上下文压缩。这些工作很重要,但当我们与基于 Elastic Agent Builder 构建应用的客户合作时,我们发现,决定 agent 能否成功的上下文通常根本不在对话中。它是业务知识,例如每个数据源的用途、不同系统中的数据源如何相互关联、数据中存在哪些趋势或异常,以及如何针对这些数据构建高效的查询。
当没有地方存储这些知识时,同样的问题就会在生产环境中反复出现,包括:
-
每次查询的数据发现成本。 每次查询时,agent 都需要承担数据发现成本,花费 token 来弄清楚有哪些数据、字段代表什么,以及数据源之间如何关联,即使一切都没有变化也是如此。
-
上下文漂移。 无论有人将多少上下文记录在 Markdown 文件或目录条目中,随着数据和使用方式的变化,这些内容最终都会过时。
-
知识孤岛。 一个 agent 学到的知识永远无法帮助其他 agent,因此整体质量无法不断提升,成本也无法持续下降。此外,演示与生产环境之间的差距依然存在。
Context Engine 的作用
上下文层位于原始数据与 agent 之间。它会提前完成理解数据的工作,并将结果存储为小型、结构化的上下文单元。然后,在 agent 需要时,将相关的上下文单元提供给它们。
我们将这些单元称为 Knowledge Indicators(KI,知识指标)。一个 KI 可以描述:
-
实体及其关系,例如:"LongHaul(ACC-1007)是 Orion Holdings 的子公司"。
-
数据源概况,例如:"tickets 索引存储客户支持问题;应针对问题描述进行语义搜索"。
-
数据特性 ,例如:"
account_id并非始终存在,因此应过滤掉 null 值"。 -
事实、异常或模式,这些信息原本可能需要进行完整扫描才能找到,例如:"过去 30 天内的查询负载峰值和中位数是多少"。
这一层通过持续循环来创建和提供 KI:
-
收集(Gather)。 读取每个数据源,了解其结构,并找出与 agent 需要执行的任务相关的内容。
-
构建(Build)。 将这些内容转化为 KI(元数据、实体、关系、异常、事实和查询指导),并将其存储起来。
-
检索(Retrieve)。 当 agent 接收到任务时,它会获取一小组经过排序的相关 KI,而不是自己进行 schema 发现和文档扫描。
-
改进(Improve)。 每次 agent 交互都会生成一条 trace,而这些 trace 会作为新的数据源反馈回来,让上下文持续跟上 agent 的实际使用方式。
为什么上下文工程的每个阶段都是一个搜索问题
在这些讨论中,搜索通常被视为最后的检索步骤。但在实践中,整个循环的每个阶段都依赖于找到正确的信息。
| 阶段 | 搜索问题 |
|---|---|
| 收集(Gather) | 你需要处理从 GB 到 PB 规模的数据,无法持续地对所有数据进行重新处理。要缩小范围,找出真正重要的内容,就需要兼顾高召回率和高精确率:使用 agentic search 理解意图,使用**词法搜索** 实现精确匹配,使用**语义搜索**提高召回率,并通过 workflows 实现自动化。 |
| 构建(Build) | KI 会预先计算 agent 原本需要在运行时自行推导的内容。保留什么、舍弃什么,取决于 KI 将如何被检索,因此 KI 需要 embeddings、元数据字段,以及专为检索设计的组合字段。 |
| 检索(Retrieve) | 放入上下文窗口的内容必须相关、完整,同时还要简洁。如果内容包含太多噪声,agent 就会忽略它,转而重新探索原始数据源。调整这一过程本质上是一个相关性问题。 |
| 改进(Improve) | Trace 和对话记录都是非结构化数据。要发现反复出现的故障及其共同模式,就需要混合搜索。 |
我们基于 Elasticsearch 构建了上下文层,因为其中各个阶段都依赖于**混合搜索、Elasticsearch Query Language( ES|QL)和 向量搜索**,而且往往会在同一个请求中使用这些能力。
**之前的博客文章**分别介绍了这些技术,而本文将展示 Context Engine 如何将它们结合起来运行。
与 agentic RAG 和更长的上下文窗口等方案相比
上下文工程并不是一种新实践,目前已经有许多现有方案可以帮助应对相同的挑战。通过上述循环来创建上下文,可以对现有方案进行补充,并有助于解决它们目前面临的许多权衡与挑战。
| 方案 | 查询时会发生什么 | 权衡与局限 |
|---|---|---|
| 静态上下文文件或目录 | agent 读取人工编写的描述 | 内容会逐渐过时,也无法从实际使用中学习 |
| Agentic 检索增强生成(RAG) | agent 搜索原始数据块,并不断循环检索,直到得到满意的结果 | 每次执行任务时都要重新组装知识,而且容易遗漏跨文档的关联关系 |
| 使用 grep 的编程 agent | agent 直接浏览文件 | 速度慢、消耗大量 token,而且难以判断哪个匹配结果才是正确的 |
| 更长的模型上下文窗口 | agent 将数据直接加载到上下文窗口中进行推理 | 更长的上下文窗口仍然面临上下文退化和注意力方面的问题;随着上下文不断增长,后续每一轮交互的成本也会越来越高 |
上下文层以预计算和处理数据的成本,换取运行时效率的提升。由于可以提前定义预计算过程,因此能够采用更明确的处理方式,并使用规模更小、成本更低的模型。这样一来,这种权衡就更容易管理,同时也能解决上述方案在效率和工作量方面的许多问题。
构建 Context Engine
Context Engine 由五个组件组成,如下图所示:数据源、 自动化流程 、AI index、agent 记忆(agents)和反馈循环。

数据源
上下文可以来自任何 Elasticsearch 索引或**数据流**,因此你可以直接在数据现有的存储位置构建上下文。上下文也可以来自外部应用程序和数据源,通过 connectors 获取;还可以来自 Agent Builder 捕获的 agent trace,或通过 OpenTelemetry(OTel)从其他 agent 框架发送过来的 trace。
自动化流程如何构建上下文
自动化流程负责填充 AI index。它们是带有专用步骤的 Elastic Workflows,可以搜索原始内容,使用大语言模型( LLM )或其他模型处理结果,为检索构建结构化输出,验证来源信息,应用访问控制,跟踪状态,并将 KI 写入 AI index。
你不必从头开始编写这些流程。一个设置 agent 会检查你已连接的数据源,并推荐相应的自动化流程。它们可以使用小型、低成本的模型运行,也可以直接使用 ES|QL,从而降低构建成本,而节省的成本会体现在之后的每一次查询中。
基于 Elasticsearch 向量数据库 构建的 AI index
AI index 是上下文存储。它以 Elasticsearch 向量数据库为基础运行,并包含 ES|QL 和混合搜索能力。它存储由自动化流程生成的 KI,其 schema 和 mappings 专为 agent 检索而设计。
Agent 记忆的工作方式
随着用户逐步完成任务,agent 可以使用 remember、recall 和 forget 工具来存储和检索记忆。记忆整合以及在整个组织范围内共享记忆,是路线图中接下来的工作。
Agent trace 如何反馈到上下文中
每次 agent 交互都会生成一条 trace,记录 agent 如何完成任务,包括它在哪些地方取得成功、在哪些地方受阻,以及 token 消耗在了哪些环节。反馈循环会在这些 trace 中寻找效率低下的问题,并建议修改自动化流程。因此,KI 不仅能根据你预先编写的测试集得到改进,也能从真实使用情况中持续改进。
借助 Context Engine,从原始数据获得更好的答案
下面介绍如何使用 Context Engine,取得本文开头展示的结果。我们对一个模拟的账户分析 agent 进行了评估,让它回答类似前文的问题。它需要从多个数据源中获取信息:
-
四个 Elasticsearch 索引,分别存储客户工单、订阅用户、内部知识库,以及支持页面搜索查询日志。
-
一个 Google Drive 文件夹,其中包含约 50 份模拟合同,这些合同由企业与其客户或供应商签订。
自动化流程根据这些数据源创建了两种 KI。索引概况(Index profiles) 描述每个数据源的用途以及查询方式。账户实体(Account entities) 则从原始合同和工单文本中提取账户、项目和人员,以及它们与其他实体之间的关系。最终生成了约 80 个 KI,每个 KI 都包含提取出的内容,以及用于跟踪来源信息、生命周期和上下文查询方式的元数据。自动化流程使用成本更低的小型 LLM 运行,因此提取成本保持在较低水平。
我们通过 Model Context Protocol(MCP),将 AI index 连接到了两个 agent 框架:Elastic Agent Builder 和 LangChain Deep Agents。
基线 agent 如何消耗 33 次工具调用
使用以下请求:总结一下影响我们最大客户的问题,基线 agent 执行了以下操作:
-
执行数据发现。 检查每个数据源、其中的字段和示例文档,以了解数据结构。
-
弄清楚数据中"客户"的含义。 数据中既有订阅用户,也有签约账户;同时,还需要确定如何定义"最大",因为数据中存在年度合同价值(ACV)和月度经常性收入(MRR)字段。
-
查询工单索引。 找出存在的问题。
-
提取合同全文。 获取每份提及受影响客户的合同全文,以查找这些客户与其他组织之间的关联关系。
基线方案花费了 18 次工具调用来核对工单与账户之间的关系,又额外花费了 13 次调用,逐一获取合同。Context Engine Agent 只需读取一次账户关系,随后花费 7 次调用来检查原始工单。
数据发现和合同读取是成本最高的部分,也是基线运行中 token 成本的大部分来源。
上下文层带来了哪些变化
借助 AI index,agent 在开始时就能获取自动化流程预先计算的知识。它已经知道哪些字段用于标识客户,以及哪些字段用于确定规模最大的客户。实体 KI 还从原始合同文本中提取并记录了关联关系,例如一家母公司旗下拥有多家规模较小的公司。
提前读取 KI 后,agent 就可以跳过成本高昂的查询和完整文档扫描,转而针对原始数据执行轻量级检查。因此,这次运行的输入 token 减少了 71%,上下文窗口中也避免了无关信息的干扰。
为什么面向 agent 的上下文工程是一个搜索问题
上下文工程的第一波实践主要关注上下文窗口:prompt 中应该放入什么、应该压缩什么,以及应该删除什么。这些工作仍然很重要,但对于需要处理企业数据的 agent 来说,更难的问题是如何从一开始就构建上下文。业务知识必须在对话开始之前完成收集、整理和更新,并在多个 agent 之间共享,这样每个 agent 就不必重新构建这些知识。
上下文层承担了这项工作,并改变了 agent 的工作方式。agent 能够获得一致的指导,知道应该去哪里查找数据以及如何查询,因此答案仍然来自实时数据,同时避免陷入无效的探索过程。上下文会根据数据源进行刷新,因此无需人工维护,就能适应数据、用户行为和使用场景的变化。每次 agent 运行也会揭示哪些信息有所缺失,从而让知识库在实际使用中不断完善,并使所有共享这些知识的 agent 都能从中受益。
这一切都依赖于搜索。在大型数据集中发现有价值的信号、整理上下文以便后续再次检索、仅检索相关内容,以及从数千条 trace 中发现模式,这些都属于搜索问题。如果你正在为自己的 agent 设计上下文层,就应该基于搜索来构建它。
我们正在积极与希望优化生产环境中 agent 的开发者合作。如果你有兴趣为自己的 agent 探索 Context Engine,可以在 **此处申请访问权限**。
原文:Context engineering for agents: 33 tool calls down to 9 | Elasticsearch Labs