news 2026/9/13 3:47:13

在 Mastra 中为文件化子代理编写指令:以 `weather-fs/forecaster/instructions.md` 为例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 Mastra 中为文件化子代理编写指令:以 `weather-fs/forecaster/instructions.md` 为例

在 Mastra 中为文件化子代理编写指令:以weather-fs/forecaster/instructions.md为例

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

导读

在 Mastra 的文件化(file-based)Agent体系中,instructions.md是定义 Agent 行为灵魂的纯文本文件:它决定模型何时调用工具、如何汇报结果、何时把任务委派给子代理。本文以 examples/agent/src/mastra/agents/weather-fs 示例中forecaster子代理的 instructions.md 为骨架,完整还原该指令文本,并结合其配套的config.tsget_forecast工具、嵌套子代理historian以及@mastra/core的文件路由源码,讲透“如何给一个子代理写出高可用指令、它如何被父代理发现与委派、最深可以嵌套几层”。读完你将能照葫芦画瓢,在自己的 Mastra 项目中用纯文件方式组织出多层协作的 Agent 团队。

一、关联文档原文:forecaster/instructions.md的完整内容

该子代理的指令文件全文如下(原样保留):

You are a forecasting specialist. When asked for a forecast, call the `get_forecast` tool for the named city and summarize the result day by day in a short list. Call out any precipitation. If no city is named, ask which city.

虽然只有四行,但它是一份结构完整、可运行的子代理指令,包含了三条关键的行为约束:

指令内容行为含义
You are a forecasting specialist.角色设定(System Prompt 的身份),让模型以“预报专家”的身份回答
call the get_forecast tool for the named city and summarize the result day by day in a short list. Call out any precipitation.明确工具调用触发条件(用户要预报 → 调get_forecast)、输出格式(逐日短列表)与输出重点(突出降水)
If no city is named, ask which city.兜底交互策略:参数缺失时主动追问,而不是臆造城市

在 Mastra 的文件化约定中,这份文件不需要任何export,目录结构本身即声明:subagents/forecaster/instructions.md就是forecaster子代理的instructions。正如 forecaster/config.ts 中的注释所说:// instructions omitted -> taken from instructions.md——即 config 中省略instructions字段时,框架自动从同名目录下的instructions.md读取。

二、instructions.md 在文件化 Agent 布局中的位置

forecaster并不是孤立存在的,它是文件化示例weather-fs的一级子代理。完整目录布局如下(来自 weather-fs/README.md):

weather-fs/ config.ts # model + config overrides (uses agentConfig() for typing) instructions.md # the agent instructions memory.ts # default-exported Memory instance tools/ get_weather.ts # default-exported tool, keyed by filename skills/ units.md # flat skill severe-weather/ SKILL.md # packaged skill references/ thresholds.md workspace/ # seed files mirrored into the agent's workspace cities.json README.md subagents/ forecaster/ # a declared subagent, same layout as an agent config.ts # MUST set a description instructions.md tools/ get_forecast.ts subagents/ historian/ # a nested subagent (depth 2) config.ts instructions.md tools/ get_climate_normals.ts

从布局可以看出子代理与顶层 Agent 的关系:

  1. 子代理的布局与顶层 Agent 完全一致——config.tsinstructions.mdtools/*,可选skills/workspace/、以及自己的subagents/
  2. 父代理通过“委托工具”调用子代理——forecaster目录会被组装成一个独立的Agent,以目录名forecaster为键挂到父代理的agents映射中,成为模型可见的委派工具;
  3. 子代理可以继续嵌套——forecaster又声明了自己的子代理historian,形成weather-fs → forecaster → historian的委派链。

三、父代理如何把任务“交给” forecaster:指令与 description 的分工

3.1 父代理指令中的委派触发条件

顶层weather-fs的 instructions.md 明确写有委派策略:

When the user asks for a multi-day forecast (or "this week", "next few days"), delegate to the `forecaster` subagent instead of answering directly.

也就是说,委派行为本身也是一条指令:父模型根据用户请求判断“是否多日预报”,命中则调用名为forecaster的工具。这正是示例设计的分层意图——单日天气由get_weather直接回答,多日预报下沉给预报专家。

3.2 description:父模型决策委派的唯一依据

与顶层 Agent 不同,子代理的config.ts必须提供非空的descriptionforecaster的配置如下(config.ts):

import { agentConfig } from '@mastra/core/agent'; export default agentConfig({ model: 'openai/gpt-5.4-mini', description: 'Produces a multi-day weather forecast for a city.', // instructions omitted -> taken from instructions.md // tools omitted -> taken from tools/*.ts });

这条description是父模型在选择是否委派时唯一能看到的描述性文本(子代理内部的instructions.md不会暴露给父模型)。在 packages/core/src/agent/fs-routing/index.ts 的源码中,这条规则被强制校验(L587-L667):

const description = child.getDescription(); if (!description || description.trim() === '') { throw new MastraError({ id: 'AGENT_FS_ROUTING_SUBAGENT_DESCRIPTION_REQUIRED', ... text: `Agent "${name}": subagent "${childId}" requires a non-empty 'description'. Set one in agents/${name}/subagents/${childId}/config.ts.`, }); }

所以实践上:description要写成“一句话能说清这个子代理擅长什么”的摘要,例如Produces a multi-day weather forecast for a city.;而instructions.md则写“拿到任务后具体怎么干”的完整规程。两者一个对外(父模型选人)、一个对内(子代理执行)。

四、指令引用的工具:get_forecast 的契约定义

forecaster/instructions.md要求调用get_forecast工具。该工具在 tools/get_forecast.ts 中用createTool定义,核心是输入/输出 Schema 契约

import { createTool } from '@mastra/core/tools'; import { z } from 'zod'; export default createTool({ id: 'get-forecast', description: 'Fetches a multi-day weather forecast for a given city', inputSchema: z.object({ city: z.string().describe('The city to forecast'), days: z.number().int().min(1).max(7).default(3).describe('Number of days'), }), outputSchema: z.object({ city: z.string(), days: z.array( z.object({ day: z.number(), conditions: z.string(), highCelsius: z.number(), lowCelsius: z.number(), }), ), }), execute: async ({ city, days }) => { // Stubbed response — swap in a real API for production use. const conditions = ['sunny', 'partly cloudy', 'rain', 'clear']; return { city, days: Array.from({ length: days }, (_, i) => ({ day: i + 1, conditions: conditions[i % conditions.length]!, highCelsius: 22 - i, lowCelsius: 14 - i, })), }; }, });

几个与指令编写直接相关的细节:

  • 输入 Schema 的约束即指令的“可执行范围”days限定为1..7的整数、默认3,这意味着指令中不必再写“预报几天”,模型只要传city即可,缺失参数由框架默认值兜底;
  • 输出 Schema 定义了“day by day”的数据形状:数组中的每一项含dayconditionshighCelsiuslowCelsius,指令中要求“summarize the result day by day in a short list”正好与这个结构对应;
  • execute目前是桩实现:代码注释明确写着Stubbed response — swap in a real API for production use.,实际生产环境替换为真实天气 API 即可,Schema 与指令无需改动。

文件化发现机制上,工具以文件名为键注册:get_forecast.ts→ 工具名get_forecast,与指令中call the get_forecast tool完全一致,指令里的工具名必须与文件名对齐。

五、嵌套子代理:historian 与委派深度上限

forecaster还拥有自己的子代理historian(目录subagents/forecaster/subagents/historian/),用于回答“某地某月通常什么天气”这类气候问题。它的 instructions.md 遵循同样的写作模式:

You are a climate history specialist. When asked how the weather usually is somewhere, call the `get_climate_normals` tool for the named city and month and report the typical high, low, and rainy days in one short sentence. If no month is named, use the current month.

其配套工具 get_climate_normals.ts 接收citymonth1..12),输出avgHighCelsiusavgLowCelsiusrainyDays,同样为桩实现(用正弦函数模拟季节温差)。其config.ts也遵循“description 必填”规则:

export default agentConfig({ model: 'openai/gpt-5.4-mini', description: 'Looks up historical climate normals (typical temperatures and rainfall) for a city and month.', });

关于嵌套深度,fs-routing/index.ts 中定义:

export const MAX_FS_SUBAGENT_DEPTH = 3;

即:顶层 Agent 记为 depth 0,其子代理为 depth 1,依此类推;声明超过 3 层的子代理会被忽略并发出警告ignoring its subagents — subagents may only nest 3 levels below a top-level agent)。该上限一方面防止委派树无限膨胀,另一方面可保护assembleAgentFromFsEntry免受循环目录对象的影响。weather-fs → forecaster → historian这条链正好处于 depth 2,是“合理嵌套”的典型示范。

六、组合起来:完整委派链路与运行验证

将上面所有文件组合,就得到一条完整的分层 Agent 链路:

用户请求示例处理链路依据
“what's the weather in Tokyo?”weather-fs直接调get_weather,同时报 °C 与 °F顶层指令 + skills/units.md 技能
“give me a 5-day forecast for London”weather-fs委派给forecaster,后者调get_forecast逐日汇报顶层指令的委派条款 + forecaster/instructions.md
“how is the weather in Paris usually in April?”forecaster再委派给historian,后者调get_climate_normalshistorian/instructions.md

在仓库根目录运行即可在 Studio 中看到weather-fs与代码定义的 Agent 并列出现:

pnpm --filter ./examples/agent mastra dev

需要强调的是,weather-fs纯文件定义的 Agent:没有new Agent()调用,也没有在src/mastra/index.ts中注册任何内容,mastra dev/mastra build会自动发现并注册它——这也正是instructions.md这类文件之所以重要的前提:在文件化体系里,目录与 Markdown 本身就是声明

七、写给子代理指令的实践要点(基于本示例的提炼)

结合forecasterhistorian两份指令及其源码佐证,可以总结出编写高质量子代理指令的四条经验:

  1. 先定角色,再给行为:以You are a ... specialist.开头明确专业身份,随后用“When asked for X, do Y”的条件句式把触发场景与动作绑定,减少模型误判;
  2. 工具名必须与文件名严格一致:指令中写的get_forecast要能在 tools/get_forecast.ts 中找到对应文件,否则模型无法调用;
  3. 把“怎么答”写进指令:包括输出格式(逐日短列表)、重点强调(Call out any precipitation)和缺失参数时的兜底(ask which city),这些细节决定回答质量;
  4. 对外靠 description、对内靠 instructions:在 config.ts 中用一句话描述子代理职责供父模型决策(缺失即构建报错),把完整执行规程放进instructions.md,两者职责分离。

结语

forecaster/instructions.md虽只有四行,却是 Mastra 文件化子代理机制的浓缩样本:它展示了指令与工具契约(get_forecast的 Zod Schema)、指令与 description 的分工、以及子代理间的多层委派(受MAX_FS_SUBAGENT_DEPTH = 3约束)。以它为模板,你可以在agents/<name>/subagents/下用纯 Markdown 与目录结构快速搭建分工明确的 Agent 团队——这也是 Mastra 文件化开发范式最直观的入门路径。更多背景可参考 weather-fs 的 README。

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 3:45:27

LSTM-Adaboost在电力负荷预测中的优化应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 3:42:15

Verilog入门:从模块、always到assign的可综合实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 3:39:34

从NLP到多模态大模型:Transformer架构与跨模态技术解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 3:39:05

Anaconda完全指南:安装、虚拟环境与PyTorch配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 3:38:48

Zabbix保姆级部署教程:从环境准备到主机接入与报错排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华