上下文工程
模型只能使用其上下文窗口中可用的信息。这些信息可能包括当前对话、记住的细节、应用数据、工具结果,或知识库中的相关段落。
上下文工程是一门决定模型应看到哪些信息以及何时看到的实践。目标不是尽可能多地提供信息,而是让上下文保持相关且最新。上下文太少会让模型缺少所需信息;上下文太多则会让重要细节更难被找到,增加成本,并在模型远未达到上下文上限之前就降低响应质量。
Mastra 提供了多种方式将信息带入上下文、使其随时间保持可用、在需要时检索它,以及随着任务增长压缩或隔离它。本指南说明每种机制的适用场景以及它们如何配合。
| 需求 | 从这里开始 | 模型看到什么 |
|---|---|---|
| 稳定的身份、规则或约束 | 指令 | 每次模型调用的系统上下文 |
| 来自数据库或 API 的数据 | 工具 | 工具定义及所选结果 |
| 当前客户或应用数据 | 内联上下文 | 插入用户消息中的数据 |
| 大型、稳定的知识库 | RAG | 来自索引的语义相关 chunk |
| 用户或组织管理的文档 | 文件系统 | 通过读取或搜索工具选择的文件 |
| 最近的对话或持久事实 | Memory | 历史、观察结果或检索到的记忆 |
| 长时间运行的对话 | Observational Memory | 密集观察结果加近期未被观察的消息 |
| 运行期间的新事件或变化状态 | Signals | 用户消息、响应式消息、通知消息或状态消息 |
| 仅部分任务需要的指令 | 动态 skills | skill 元数据及按需加载的指令 |
指令指令的直接链接
agent 的 instructions 定义其稳定身份、行为和约束。它们是系统消息,在模型请求中出现在对话消息之前。
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 解析:
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 或服务获取当前数据的推荐方式。模型决定何时需要数据并提供工具参数,而你的应用控制查询和返回字段。
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。
RAGRAG的直接链接
检索增强生成(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 会获得用于列出、读取和搜索文件的内置工具。
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 流水线。
MemoryMemory的直接链接
Memory 让 agent 的对话在多个轮次之间保持连贯。它将最近的消息和记住的细节带入上下文,而无需应用在每一轮重新发送完整记录。
Memory 需要存储提供方。每次调用还会指定拥有 memory 的 resource 以及标识对话的 thread。复用这两个值即可继续同一段对话:
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 MemoryObservational Memory的直接链接
对话历史会随着每条用户消息、响应和工具调用而增长。即使尚未达到模型的硬性上下文上限,过长的记录也会增加成本,并让模型更难找到相关细节。压缩(Compression)用更小的表示替换旧的冗长历史。
Observational Memory 会持续处理这一点。Observer 将较早的消息和工具交互转换为密集的观察结果,而定期的反思(reflection)会重组并压缩这些观察结果。
启用 Observational Memory 时,无需配置 lastMessages。Observational Memory 自行管理历史:将近期未被观察的消息保留在上下文中,并用观察结果替换较早的消息。
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 切换提供方之前,激活缓冲的观察结果。
SignalsSignals的直接链接
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实现它。
ProcessorsProcessors的直接链接
Processors 控制进入模型上下文的内容,并可在模型调用前重写内容。当信息应保留在已存储历史或应用输出中,但无需在每一步都回传给模型时,请使用它们。
例如,ToolCallFilter 会从下一次模型请求中移除旧的工具参数和结果,而不会从存储中删除这些消息。模型获得更小的提示词,而你的应用仍可显示或检查完整交互。
使用 processInput() 或 processInputStep() 修改活跃消息列表。这些修改之后可能会保存到 memory。当重写只应应用于当前提供方调用且不影响 memory 时,请使用 processLLMRequest()。
Mastra 为常见的上下文膨胀来源提供了若干控制手段:
toModelOutput:用更小的、面向模型的表示替换冗长的工具结果。ToolCallFilter:从模型输入中移除旧的工具调用和结果,同时在 memory 和 UI 中保留它们。ToolSearchProcessor:用搜索和加载工具替换大型工具目录。TokenLimiter:修剪非系统消息,直到提示词符合 token 预算。
对于冗长的工具结果,请从 toModelOutput 开始;对于旧的工具交互,请使用 ToolCallFilter。将 TokenLimiter 作为最终的预算保护,而不是依赖模型的最大上下文窗口。
SubagentsSubagents的直接链接
上下文膨胀的一个常见来源是在与 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。