跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

上下文工程

模型只能使用其上下文窗口中可用的信息。这些信息可能包括当前对话、记住的细节、应用数据、工具结果,或知识库中的相关段落。

上下文工程是一门决定模型应看到哪些信息以及何时看到的实践。目标不是尽可能多地提供信息,而是让上下文保持相关且最新。上下文太少会让模型缺少所需信息;上下文太多则会让重要细节更难被找到,增加成本,并在模型远未达到上下文上限之前就降低响应质量。

Mastra 提供了多种方式将信息带入上下文、使其随时间保持可用、在需要时检索它,以及随着任务增长压缩或隔离它。本指南说明每种机制的适用场景以及它们如何配合。

需求从这里开始模型看到什么
稳定的身份、规则或约束指令每次模型调用的系统上下文
来自数据库或 API 的数据工具工具定义及所选结果
当前客户或应用数据内联上下文插入用户消息中的数据
大型、稳定的知识库RAG来自索引的语义相关 chunk
用户或组织管理的文档文件系统通过读取或搜索工具选择的文件
最近的对话或持久事实Memory历史、观察结果或检索到的记忆
长时间运行的对话Observational Memory密集观察结果加近期未被观察的消息
运行期间的新事件或变化状态Signals用户消息、响应式消息、通知消息或状态消息
仅部分任务需要的指令动态 skillsskill 元数据及按需加载的指令

指令
指令的直接链接

agent 的 instructions 定义其稳定身份、行为和约束。它们是系统消息,在模型请求中出现在对话消息之前。

src/mastra/agents/support-agent.ts
import { Agent } from '@mastra/core/agent'

export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support Agent',
instructions: `You help customers understand their account.
Today is ${new Date().toDateString()}.
Use plain language and don't invent account details.`,
model: 'openai/gpt-5.6-sol',
})

请让指令聚焦于适用于大多数调用的行为。添加当前账号数据、检索到的文档或任务特定细节会让基础提示词更大,也更难复用。

指令也可以在运行时从 RequestContext 解析:

src/mastra/agents/support-agent.ts
instructions: ({ requestContext }) => {
const name = requestContext.get('name')

return `You help ${name} understand their account.`
}

当指令依赖于随每次请求变化的数据(例如当前用户、租户、locale、角色或功能开关)时,请使用 RequestContext。不来自请求的值(例如当前日期)可以直接插值,如第一个示例所示。

提示

如果解析后的指令经常变化,模型提供方可能无法复用相同的提示词缓存前缀。请将稳定部分放在前面,并通过消息或 signals 传递频繁变化的背景信息。

观看这段关于提示词缓存的短视频,了解可缓存的提示词前缀如何降低延迟和成本。

内联上下文
内联上下文的直接链接

大多数应用通过将相关值插入当前消息来传递运行时上下文。当你的代码已经加载了客户或应用数据时,这种方式效果很好:

const customer = await db.customer.findById(customerId)

await supportAgent.generate(`
Customer: ${customer.name}
Plan: ${customer.plan}
Question: ${question}
`)

请选择并标注模型需要的字段,而不是序列化整条数据库记录。这样提示词更小,每个值的含义也更清晰。

启用 memory 后,Mastra 会保存当前用户消息。不要插入不应出现在对话历史中的敏感或临时数据。

对于较少见的情况——背景信息应影响一次响应但不保存为对话历史——请传入一条 context 消息:

await supportAgent.generate('Recommend the next action.', {
context: [{ role: 'user', content: 'The customer has an unresolved billing dispute.' }],
})

模型会在当前执行中看到该背景信息,但 Mastra 不会将其保存到 memory。当持久化背景信息会污染对话,或在之后轮次暴露临时应用状态时,请使用 context。

工具
工具的直接链接

工具是从数据库、API 或服务获取当前数据的推荐方式。模型决定何时需要数据并提供工具参数,而你的应用控制查询和返回字段。

src/mastra/tools/customer-tool.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const getCustomer = createTool({
id: 'get-customer',
description: 'Gets the current profile and plan for a customer',
inputSchema: z.object({ customerId: z.string() }),
execute: async ({ customerId }) => {
const customer = await db.customer.findById(customerId)
return { name: customer.name, plan: customer.plan, status: customer.status }
},
})

当应用代码需要完整结果而模型只需要较小表示时,请使用 toModelOutput。

RAG
RAG的直接链接

检索增强生成(RAG)从已索引的语料库中检索语义相关的 chunk。它仍适用于大型、稳定的知识库,尤其是用户提出无法清晰映射到结构化数据库查询的开放式问题时。

import { ModelRouterEmbeddingModel } from '@mastra/core/llm'
import { createVectorQueryTool } from '@mastra/rag'

const knowledgeBase = createVectorQueryTool({
vectorStoreName: 'knowledgeBase',
indexName: 'support-docs',
model: new ModelRouterEmbeddingModel('openai/text-embedding-3-small'),
})

请在与 agent 相同的 Mastra 实例上注册 vectorStoreName 所引用的向量存储。Mastra 支持多种向量数据库。RAG 通常通过工具暴露,如本例所示。设计上的选择在于:agent 是需要语义检索,还是可以直接查询数据源。

许多应用现在会从直接的、针对特定数据源的工具开始。模型变得更善于选择这些工具,而直接查询通常更简单、更便宜,因为它不需要分块、嵌入和向量索引流水线。当实际需求是对非结构化内容进行语义搜索时,再选择 RAG,并通过元数据过滤、重排序和保守的 topK 来约束返回的上下文。

文件系统
文件系统的直接链接

文件系统让 agent 持久访问文档和其他文件。文件可以位于本地目录,也可以位于 Amazon S3、AgentFS 或 Google Drive 等提供方中。agent 会获得用于列出、读取和搜索文件的内置工具。

src/mastra/workspace.ts
import { LocalFilesystem, Workspace } from '@mastra/core/workspace'

export const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './knowledge-base' }),
bm25: true,
autoIndexPaths: ['**/*.md'],
})

// Agents receive tools including read_file, list_files, grep,
// mastra_workspace_search, and mastra_workspace_index.
await workspace.init()

Workspace 搜索支持 BM25 关键词搜索、向量语义搜索或两者的混合。对于处理用户文件的个人助理,或团队成员在 Google Drive 等服务中更新的组织知识库,可以使用文件系统。搜索针对 workspace 索引运行,因此变更过的文件必须先建立索引,agent 才能检索到其最新内容。

提示

文件系统搜索也可以使用向量,因此它与 RAG 有重叠。当事实来源是一组 agent 可能需要列出、读取或更新的文件时,请选择文件系统。当检索是主要需求且源内容不需要像文件一样运作时,请选择独立的 RAG 流水线。

Memory
Memory的直接链接

Memory 让 agent 的对话在多个轮次之间保持连贯。它将最近的消息和记住的细节带入上下文,而无需应用在每一轮重新发送完整记录。

Memory 需要存储提供方。每次调用还会指定拥有 memory 的 resource 以及标识对话的 thread。复用这两个值即可继续同一段对话:

src/mastra/agents/assistant.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'

export const assistant = new Agent({
id: 'assistant',
name: 'Assistant',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
lastMessages: 20,
},
}),
})

await assistant.generate('Help me plan the next project milestone.', {
memory: {
resource: 'user-123',
thread: 'project-456',
},
})

本例假设已在注册的 Mastra 实例或直接在 Memory 上配置了存储。lastMessages 控制 Mastra 从 thread 加载多少条最近消息。默认值为 10。

消息历史适用于较短对话,即最近轮次包含 agent 所需上下文的情况。由于 lastMessages 窗口在每次请求时向前滑动,超过上限后,每轮都会从提示词开头移除最旧的消息,并使提供方的提示词缓存失效。对于长时间运行的对话,Mastra 推荐 Observational Memory,它让近期对话保持可用,同时将较早历史转换为密集的观察日志,并保持提示词前缀稳定以利于缓存。

Observational Memory
Observational Memory的直接链接

对话历史会随着每条用户消息、响应和工具调用而增长。即使尚未达到模型的硬性上下文上限,过长的记录也会增加成本,并让模型更难找到相关细节。压缩(Compression)用更小的表示替换旧的冗长历史。

Observational Memory 会持续处理这一点。Observer 将较早的消息和工具交互转换为密集的观察结果,而定期的反思(reflection)会重组并压缩这些观察结果。

启用 Observational Memory 时,无需配置 lastMessages。Observational Memory 自行管理历史:将近期未被观察的消息保留在上下文中,并用观察结果替换较早的消息。

src/mastra/agents/assistant.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'

export const assistant = new Agent({
id: 'assistant',
name: 'Assistant',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
observationalMemory: true,
},
}),
})

消息被观察后,模型会收到观察日志、尚未被观察的近期消息以及一条延续提醒。由于延迟提示在缓冲 chunk 激活时可能已经过时,异步缓冲观察不会生成延续提示(currentTask 或 suggestedResponse)。原始消息仍会保留存储,但不再占用活跃的模型上下文。

观察结果以稳定的 chunk 添加,这有助于提供方复用现有的提示词前缀。Observational Memory 还可以在提示词缓存可能即将过期时,或在 agent 切换提供方之前,激活缓冲的观察结果。

Signals
Signals的直接链接

Signals 向有 memory 支撑的 thread 添加消息或系统生成的上下文。投递方式取决于 thread 的状态:signal 可以唤醒空闲 agent 或进入活跃循环。它也可以等待下一轮,或在持久化后不唤醒 agent。

状态 signals 需要 memory 和已存在的 thread。通知收件箱 signals 需要支持通知的存储适配器。

API用途上下文行为
sendMessage()活跃 agent 应立即看到的用户输入进入活跃循环或唤醒空闲 thread
queueMessage()应等待下一轮的用户输入在当前运行结束后启动
sendSignal()后台结果、策略提醒或外部事件根据其投递选项添加响应式或通知上下文
sendStateSignal()浏览器状态、编辑器状态、任务状态或其他变化的值维护带快照和增量的 thread 作用域状态通道

请使用 sendSignal() 传递由系统而非用户产生的上下文:

const result = agent.sendSignal(
{
type: 'notification',
contents: 'CI failed on pull request 123: three tests failed.',
attributes: { source: 'github', pullRequest: 123 },
},
{
resourceId: 'user-123',
threadId: 'project-456',
},
)

await result.accepted

Processor 可以在 processInputStep() 期间发送响应式 signal。这对于依赖当前步骤或最近工具结果的指导很有用。当 signal 应仅到达当前模型调用时,请设置 transient: true。需要时重新发送它,而不是在对话历史中存储重复提醒。

状态 signals 表示随时间变化的上下文。对于每个状态通道,Mastra 会跟踪快照和增量,以便在上一个快照离开活跃上下文窗口后重新插入最新快照。当 processor 拥有状态时,请使用 computeStateSignal()。即使历史或 Observational Memory 移除了较早消息,该通道也能让工作记忆和浏览器上下文与任务列表一起保持可用。

Signals 会在当前轮次附近追加变化的上下文,而不是重写 agent 的基础指令。因此,transient 和状态 signals 可以在保持当前指导和状态对模型可见的同时,维持更稳定的提示词前缀。

动态 skills
动态 skills的直接链接

Agent skills让 agent 仅在需要时加载任务特定的指令,而不是在基础指令中携带所有过程。将它们用于适用于部分请求的专门指导,并让默认上下文保持较小。

上下文控制
上下文控制的直接链接

上下文控制限制任务增长时模型看到的内容。压缩(compaction)和 processors 在单个 agent 内缩减上下文,而 subagent 边界控制 agent 之间传递的内容。

压缩
压缩的直接链接

如果你用过 Claude Code,可能见过长会话期间发生的压缩(compaction)。Mastra 团队喜欢开玩笑说:“朋友不会让朋友做压缩。”

压缩会等到对话达到某个 token 阈值,然后总结记录并替换较早的消息。这是一种粗糙的兜底手段。压缩轮次会增加延迟,而且一份摘要必须代表之前的所有内容。反复摘要可能压平时间顺序,或丢失后来变得重要的细节。

对于长时间运行的对话,优先使用 Observational Memory。它可以在后台异步处理历史,同时保留时间上下文。反思会重新审视累积的 memory,并自然地修剪不再重要的细节。Mastra 开箱不提供压缩,但你可以通过自定义 processor实现它。

Processors
Processors的直接链接

Processors 控制进入模型上下文的内容,并可在模型调用前重写内容。当信息应保留在已存储历史或应用输出中,但无需在每一步都回传给模型时,请使用它们。

例如,ToolCallFilter 会从下一次模型请求中移除旧的工具参数和结果,而不会从存储中删除这些消息。模型获得更小的提示词,而你的应用仍可显示或检查完整交互。

使用 processInput() 或 processInputStep() 修改活跃消息列表。这些修改之后可能会保存到 memory。当重写只应应用于当前提供方调用且不影响 memory 时,请使用 processLLMRequest()。

Mastra 为常见的上下文膨胀来源提供了若干控制手段:

  • toModelOutput:用更小的、面向模型的表示替换冗长的工具结果。
  • ToolCallFilter:从模型输入中移除旧的工具调用和结果,同时在 memory 和 UI 中保留它们。
  • ToolSearchProcessor:用搜索和加载工具替换大型工具目录。
  • TokenLimiter:修剪非系统消息,直到提示词符合 token 预算。

对于冗长的工具结果,请从 toModelOutput 开始;对于旧的工具交互,请使用 ToolCallFilter。将 TokenLimiter 作为最终的预算保护,而不是依赖模型的最大上下文窗口。

Subagents
Subagents的直接链接

上下文膨胀的一个常见来源是在与 subagents 之间传递过多信息。subagent 会为其委托任务获得独立的模型上下文,但该边界仍需要刻意的控制。

默认情况下,Mastra 会将父级对话转发给 subagent。使用 messageFilter 只传递该专家所需的消息:

await supervisor.generate('Investigate the failed deployment.', {
delegation: {
messageFilter: ({ messages }) => messages.slice(-10),
},
})

在另一个方向上,Mastra 默认将 subagent 的文本返回给父模型,同时让嵌套工具调用和元数据可供应用代码使用。除非父级必须基于这些细节进行推理,否则请保持 includeSubAgentToolResultsInModelContext 处于禁用状态。使用 onDelegationStart 优化子提示词,使用 onDelegationComplete 减少或替换返回给父级的文本。

关于委托钩子、memory 隔离、迭代监控和结果控制,请参阅 Subagents。

On this page