AGENTS.md与subagents.md:模块化AI智能体的工程化设计与实践
1. 从“文件”到“工程”:为什么我们需要 AGENTS.md 和 subagents.md?
如果你最近在折腾一些前沿的AI应用框架,比如尝试用 Claude 3.5 Sonnet 或者 GPT-4 来驱动一个复杂的自动化流程,你大概率会碰到一个叫 claude.md 或者 agents.md 的文件。一开始,你可能觉得这不过是个简单的提示词(Prompt)文件,把任务描述写进去就完事了。但当你真正开始构建一个涉及多个步骤、需要调用不同工具、并且要处理复杂逻辑的“智能体”(Agent)时,你会发现事情远没那么简单。一个混乱的、长达几百行的提示词文件,很快就会变成一场维护噩梦。
这就是 Harness Engineering 理念开始显现价值的地方。它不是一个具体的工具,而是一种工程化的思想,核心在于: 将复杂的、单体的AI智能体任务,拆解、组织成结构清晰、职责分明、可复用、可维护的模块化工程 。而 AGENTS.md 和 subagents.md 这两个文件,正是实践这一思想最核心的“蓝图”与“施工图”。
简单来说:
-
AGENTS.md是你的 “智能体总纲”或“主控台说明书” 。它定义了整个智能体系统的顶层架构、核心目标、以及它所能调用的所有“子能力”(即子智能体)的清单和接口。它不关心具体某个子任务怎么完成,只关心“谁能完成”以及“如何调度”。 -
subagents.md(或分散的各个子智能体.md文件)是你的 “专项技能手册” 。每一个文件都对应一个高度专业化、功能单一的微型智能体。它只专注于做好一件事,比如“分析用户意图”、“调用搜索API总结信息”、“生成SQL查询语句”、“撰写邮件草稿”。它的内部包含了完成这个特定任务所需的所有详细指令、上下文约束、输出格式规范。
这种拆分的巨大优势在于:
- 可维护性 :当需要修改“搜索总结”的逻辑时,你只需要去修改对应的
subagent_search_summarizer.md,而不会意外影响到“邮件撰写”或“SQL生成”的逻辑。 - 可复用性 :一个写好的“SQL生成器”子智能体,可以被不同的主智能体项目调用,无需重复编写。
- 清晰的责任链 :调试时,你可以清晰地追踪是哪个子环节出了问题。是主智能体理解错了用户意图,还是搜索子智能体返回了垃圾信息?
- 降低上下文负担 :大型语言模型(LLM)有上下文长度限制。将庞大的单体提示词拆分成多个小文件,让每个LLM调用都只关注最相关的上下文,能显著提升任务执行的准确性和可靠性。
所以,写这两个文件,本质上是在为你的AI应用进行“软件架构设计”。下面,我们就抛开理论,直接进入实战,看看这两个文件到底该怎么写。
2. AGENTS.md 深度剖析:如何设计你的智能体指挥中枢
AGENTS.md 文件是系统的入口和大脑。它的质量直接决定了整个智能体系统的健壮性和易用性。一个好的 AGENTS.md 不应该是一堆杂乱指令的堆砌,而应该像一份清晰的API文档或产品说明书。
2.1 核心结构:一个标准 AGENTS.md 应包含的模块
一个工程化的 AGENTS.md 通常包含以下几个核心部分,我以一个“智能研究助手”主智能体为例来展开:
1. 系统身份与全局约束(Identity & Global Constraints) 这是开篇明义,定义这个智能体是谁,以及它必须遵守的最高原则。
# 智能研究助手主控智能体 (Research Assistant Orchestrator)
## 系统身份
你是“智能研究助手”系统的核心调度器与协调者。你的核心职责是理解用户的复杂研究请求,将其分解为可执行的子任务,并协调调用相应的专业子智能体来协同完成,最终整合交付一份高质量的研究报告。你本身不执行具体的资料搜集、分析或写作任务。
## 全局约束与原则
* **安全与合规**:所有生成内容必须符合广泛认可的内容安全准则,不产生有害、偏见或虚假信息。
* **诚实与标注**:对于不确定或无法验证的信息,必须明确标注“此信息未经独立核实”或“基于模型知识截止日期前的公开信息”。
* **用户目标优先**:一切决策以高效、准确地满足用户在本次对话中提出的研究目标为最高准则。
注意 :这里的“身份”描述要突出“调度”和“协调”的职责,与具体执行的子智能体区分开。“全局约束”要写那些所有子智能体都必须遵守的共性规则,避免在每个子文件中重复。
2. 核心工作流程与决策逻辑(Core Workflow & Logic) 这是 AGENTS.md 的灵魂,需要清晰地描述主智能体的“思考”过程。通常采用流程图或步骤描述的方式。
## 核心工作流程
你的工作遵循一个严格的、可重复的决策循环:
1. **需求解析与澄清**:
* 接收用户输入。
* 调用 `subagent_intent_analyzer.md` 来分析用户的深层需求、研究范围、期望的输出格式(如综述、对比分析、利弊清单)以及任何特殊要求(如时效性、资料来源偏好)。
* 如果分析结果显示需求模糊或存在矛盾,你必须主动向用户提问澄清,直到获得明确指令。
2. **任务分解与规划**:
* 基于澄清后的需求,规划一个或多个并行的研究子任务。例如,一个关于“对比量子计算与经典计算在药物研发中的应用”的请求,可能被分解为:
* 任务A:搜集并总结量子计算在药物研发中的最新进展。
* 任务B:搜集并总结经典计算(如分子动力学模拟)在药物研发中的当前应用。
* 任务C:对比两者的效率、成本、适用范围。
* 为每个子任务分配合适的子智能体,并预估其执行顺序或依赖关系。
3. **子智能体调度与执行**:
* 按照规划,依次或并行地调用相应的子智能体文件(如 `subagent_web_researcher.md`, `subagent_academic_paper_summarizer.md`)。
* 在调用时,你需要为子智能体提供清晰的 **“任务指令”** 和 **“上下文信息”**。例如,给研究子智能体的指令可能是:“请针对‘量子计算在药物研发中的最新进展(2023年至今)’这一主题,进行网络搜索,并总结出3-5个关键突破点,每个点附上简要说明和可信度评估。”
* 收集每个子智能体的输出结果。
4. **结果整合、验证与交付**:
* 调用 `subagent_report_synthesizer.md`,将所有子任务的结果进行整合、去重、逻辑串联,形成初稿。
* 可选:调用 `subagent_fact_checker.md` 对报告中的关键数据和论断进行交叉验证(如果配置了该子智能体)。
* 将最终的研究报告以用户要求的格式(如Markdown、结构化JSON)呈现给用户。
* 在交付时,简要说明报告的结构和主要结论来源。
实操心得 :这个流程描述要尽可能具体,甚至包含一些条件判断(“如果…就…”)。这实际上是为主智能体编写了一套“决策算法”。LLM会根据这套逻辑来一步步“思考”该做什么。
3. 子智能体注册表(Sub-agent Registry) 这是 AGENTS.md 的“武器库”清单,必须以结构化的方式清晰列出所有可用的子智能体。
## 可用子智能体清单
| 子智能体文件 | 功能描述 | 输入要求 | 输出格式 | 调用时机示例 |
| :--- | :--- | :--- | :--- | :--- |
| `subagent_intent_analyzer.md` | 深度解析用户查询的真实意图、隐含需求及输出偏好。 | 原始用户查询字符串。 | JSON对象,包含 `primary_goal`(主要目标)、`sub_topics`(子主题列表)、`output_format`(期望格式)、`constraints`(约束条件如时间、来源)。 | 每次接收到新用户查询时首先调用。 |
| `subagent_web_researcher.md` | 基于网络搜索(如通过Serper API)获取最新信息并进行摘要。 | 明确、具体的搜索查询词,可附加时间、来源范围等过滤器。 | Markdown格式的摘要,包含关键点列表、信息来源链接、信息新鲜度标注。 | 当需要获取实时、公开的网络信息时。 |
| `subagent_academic_summarizer.md` | 针对学术论文摘要或特定知识库进行信息提取与总结。 | 论文DOI、arXiv ID、或一段学术文本。 | 结构化摘要,包含研究问题、方法、核心发现、局限性。 | 当用户请求涉及深度的学术文献时。 |
| `subagent_data_analyzer.md` | 对提供的结构化数据(如CSV片段、JSON)进行描述性统计或简单趋势分析。 | 清晰的数据片段和明确的分析问题(如“计算平均值”、“找出异常值”)。 | 文本分析结果,可附带简单的数据洞察。 | 当用户提供了数据并要求初步分析时。 |
| `subagent_report_synthesizer.md` | 将多个来源的输入整合成一份连贯、结构化的报告。 | 一个包含所有子任务结果的列表或集合。 | 格式优美的Markdown报告,包含目录、章节、引用。 | 所有子任务完成后,交付最终成果前。 |
| `subagent_fact_checker.md` | 对陈述进行事实核查,指出潜在矛盾或需要核实之处。 | 需要核查的陈述列表。 | 核查结果列表,标注每条陈述的状态(“一致”、“矛盾”、“待核实”及理由)。 | 在最终报告生成后,用于质量把关(可选)。 |
注意 :这个表格是给 主智能体(LLM)看的 ,也是给 项目开发者(你)维护的 。清晰的接口定义(输入/输出)是模块化成功的关键。主智能体需要知道“怎么用”这些子模块。
4. 错误处理与降级方案(Error Handling & Fallback) 任何系统都会出错,智能体也不例外。必须在蓝图中预先定义好异常处理流程。
## 错误处理与恢复策略
1. **子智能体调用失败**:如果某个子智能体返回了错误(如网络超时、API限额用尽),或返回的内容明显不符合预期(如输出“我无法处理”),主智能体应:
* 首先,尝试用更简单、更明确的指令重试一次该子智能体。
* 如果再次失败,评估该子任务是否为核心任务。如果是,则向用户坦诚说明“在获取XX信息时遇到技术障碍,当前报告可能不完整”,并继续执行其他非依赖任务。
* 如果可以,尝试用另一个功能近似的子智能体替代(如用 `web_researcher` 替代部分 `academic_summarizer` 的功能)。
2. **信息矛盾或质量低下**:如果不同子智能体返回的信息存在严重矛盾,或某个信息源质量明显很低,主智能体应:
* 在最终报告中明确指出这一矛盾点。
* 可以尝试调用 `subagent_fact_checker.md` 进行辅助判断。
* 遵循“诚实标注”原则,不强行捏造统一结论。
3. **用户反馈循环**:在交付初步结果后,主动询问用户“这份报告是否满足了您的要求?是否有需要调整或深入的地方?”。根据用户反馈,可以触发新一轮的规划-执行循环。
5. 对话状态管理(Conversation State Management) 对于多轮对话的智能体,需要管理上下文。
## 多轮对话上下文管理
你需要维护一个简单的对话上下文,以确保在后续轮次中理解用户的指代(如“它”、“上面提到的那个方法”)和延续性请求。
* **关键信息持久化**:将每一轮中产生的核心结论、用户确认过的需求、以及重要的数据片段,以简练的形式保存在你的工作记忆中。
* **上下文摘要**:在每一轮对话开始(或当对话历史较长时),主动提供一个简短的上下文摘要,例如:“我们正在讨论‘量子计算在药物研发中的应用’。上一轮我们总结了量子计算在分子模拟方面的三个优势。接下来您想了解其面临的挑战吗?”
* **重置机制**:如果用户说“重新开始”或提出一个完全无关的新话题,你应该清空之前的上下文,重新启动工作流程。
3. subagents.md 实战指南:打造专精特新的微型智能体
如果说 AGENTS.md 是元帅,那么各个 subagents.md 就是将军。每个子智能体文件都应该极致地专注于一个单一、明确的任务。它的编写质量直接决定了该环节的输出是否可靠。
3.1 子智能体的通用模板结构
一个优秀的子智能体文件,通常遵循以下结构。我们以 subagent_web_researcher.md 为例:
# 网络信息研究子智能体 (Web Research Sub-agent)
## 核心身份与职责
你是一个专业、高效、严谨的网络信息研究员。你的唯一职责是:根据主智能体提供的明确查询指令,利用可用的网络搜索工具,获取最新、最相关的公开信息,并整理成结构清晰、来源可溯、带有评估的摘要。**你不回答一般性问题,不进行开放性讨论,只执行具体的研究指令。**
## 输入接口规范
主智能体会以如下JSON格式向你传递任务:
```json
{
"research_query": "明确的搜索查询语句,例如:'2024年太阳能光伏板转换效率的最新世界纪录'",
"additional_filters": {
"time_range": "2023-01-01至今", // 可选
"source_preference": ["科技新闻网站", "学术机构官网"], // 可选
"max_results": 5 // 可选,默认5条
},
"user_context": "用户的研究背景是‘评估光伏技术投资潜力’,请侧重技术突破和产业化进展。" // 可选,提供背景
}
请严格解析此输入。如果 research_query 字段为空或过于模糊,你必须输出错误。
你的内部工作流程
- 查询优化 :基于输入的
research_query和user_context,在脑海中构思2-3个更精准、更能触及核心信息的搜索关键词组合。例如,将“光伏板效率”优化为“光伏组件 转换效率 世界纪录 2024 NREL”。 - 信息获取与筛选 :(此处假设你集成了如Serper API的搜索能力)执行搜索。快速浏览结果摘要,优先选择:
- 来源权威性高的(如政府机构
.gov、知名大学.edu、权威行业媒体)。 - 信息发布时间新的(符合
time_range要求)。 - 标题和摘要直接回答查询的。
- 来源权威性高的(如政府机构
- 深度阅读与摘要 :对筛选出的前
max_results条结果进行深入阅读(或获取其页面主要内容)。为每条信息提取:- 核心事实 :发现了什么?数据是什么?
- 来源 :引用来源标题和链接。
- 关键背景/原因 :为什么这个事实重要?是如何实现的?
- 新鲜度 :信息发布日期。
- 综合与评估 :将多条信息汇总,去除重复。尝试交叉验证不同来源对同一事实的描述。评估整体信息的 可信度 (高/中/低,基于来源权威性和一致性)和 完整性 (是否全面覆盖了查询主题)。
输出格式规范
你必须且只能输出以下JSON格式的内容:
{
"status": "success" | "partial_success" | "error",
"query_used": "你实际使用的搜索关键词",
"summary": "一个连贯的、段落式的Markdown格式摘要,综合所有找到的信息。开头应有一句总览。",
"key_points": [
{
"point": "关键点1的简洁描述",
"source": "来源标题或描述",
"url": "来源链接",
"date": "发布日期(如已知)",
"confidence": "高/中/低"
},
// ... 更多关键点
],
"credibility_assessment": "对本次搜集信息整体可信度的简短评价,例如:‘信息主要来源于行业权威媒体和研发机构官网,一致性较高,可信度评估为高。’",
"error_message": "仅当status为error或partial_success时存在,说明具体问题。"
}
边界与限制
- 绝不生成 :不生成无法验证的猜测、不编造来源、不输出与查询指令无关的内容。
- 处理模糊 :如果查询指令无法通过公开网络搜索得到满意答案(如查询内部数据、未来预测),将
status设为partial_success,在summary中说明现状和局限,在error_message中注明“公开信息不足”。 - 安全边界 :严格遵守内容安全政策,不搜索、不总结任何违规、有害信息。如遇此类查询,返回
status为error,error_message为“查询内容不符合安全准则”。
### 3.2 编写子智能体的核心技巧与避坑指南
**1. 身份与职责要极度聚焦**
子智能体的第一段描述至关重要。要用最强烈的语言限定它的范围。例如,一个“SQL生成器”子智能体,应该写:“你是一个专业的SQL翻译器,只负责将自然语言描述的数据查询需求,转换为准确、高效、语法正确的SQL语句。你不解释数据,不执行查询,不回答关于业务逻辑的问题。” 这种聚焦能极大减少LLM的“胡思乱想”。
**2. 输入输出格式必须严格定义**
使用JSON等结构化格式是最佳实践。这相当于为子智能体定义了严格的函数签名。主智能体必须按照这个格式来“调用”,子智能体也必须按照这个格式来“返回”。这保证了模块间的通信是无歧义的、可编程处理的。**在输出格式中强制包含 `status` 字段**,这是实现错误处理的基础。
**3. 内部流程是“思维链”的具象化**
“你的内部工作流程”这一部分,其实是把CoT(Chain-of-Thought)提示词工程化、固定下来了。它引导LLM按照你设定的最优路径去完成任务,而不是自由发挥。对于复杂任务,这一步可以写得非常详细,包括如何拆解问题、如何分步验证等。
**4. 明确边界,设计降级路径**
“边界与限制”部分预定义了各种异常情况的处理方式。当子智能体遇到无法处理的情况时,它应该有一个体面的“退出机制”,返回一个结构化的错误,而不是崩溃或胡言乱语。这能让主智能体根据预设策略进行后续处理。
**5. 一个文件,一个智能体**
建议每个子智能体都拥有自己独立的 `.md` 文件,而不是把所有子智能体描述都堆在一个 `subagents.md` 里。这样管理起来更清晰,也便于主智能体通过文件路径精确调用。你可以用一个 `subagents/` 目录来存放所有子智能体文件,然后在 `AGENTS.md` 的注册表中引用它们。
## 4. 从文件到运行:集成、调试与迭代的最佳实践
写好 `AGENTS.md` 和各个 `subagents.md` 文件只是第一步。如何让它们在一个真实的框架(如LangChain、AutoGen,或是利用Claude/GPT的API自建调度器)里跑起来,并持续优化,才是工程化的真正开始。
### 4.1 集成模式:如何“调用”这些.md文件?
在实际系统中,这些 `.md` 文件通常以以下几种方式被使用:
1. **作为提示词模板**:这是最常见的方式。你的应用程序会读取 `AGENTS.md` 的文件内容,将其作为系统提示词(System Prompt)的一部分,与用户当前的问题拼接,然后发送给LLM(如GPT-4)。对于子智能体的调用,主智能体的输出里会包含“接下来请扮演 `subagent_web_researcher.md` 的角色,这是给你的输入:…”。然后,应用程序需要捕获这个意图,再读取对应的子智能体文件内容作为新的系统提示词,发起新一轮的LLM调用。
2. **作为配置数据库**:在一些更复杂的框架中,可能会有一个解析器,专门读取这些 `.md` 文件,将其中的结构化部分(如输入输出JSON规范、注册表)解析成程序内部可用的配置对象,从而实现更动态、更灵活的调度。
3. **作为文档与代码的统一源**:即使你用了更编程化的方式(如用Python类定义每个智能体),这些 `.md` 文件仍然是最佳的单点事实来源,用于记录设计意图、接口约定,保证文档和代码同步。
### 4.2 调试与优化:让智能体系统真正可靠
**初期调试(单点测试)**:
* **单独测试每个子智能体**:创建单元测试般的场景。直接将其 `.md` 内容作为系统提示词,模拟主智能体给它发送各种输入(包括正常、边界、异常情况),检查其输出是否符合格式、逻辑是否正确。
* **测试主智能体的规划能力**:给 `AGENTS.md` 发送一个复杂任务,但不允许它实际调用子智能体(或模拟调用返回固定结果),只看它分解出的任务计划是否合理,调用的子智能体选择是否正确。
**集成调试(联调)**:
* **端到端测试**:用一个真实的复杂任务跑通全流程。使用日志详细记录每一步:主智能体接收了什么、它规划了什么、它调用了哪个子智能体、传递了什么参数、子智能体返回了什么、主智能体如何整合。
* **关键观察点**:
* **信息衰减与扭曲**:在子智能体之间传递的信息,是否逐渐偏离了用户原意?往往问题出在 `AGENTS.md` 的“任务指令”生成环节,指令不够精确。
* **上下文污染**:子智能体是否受到了不应有的上下文影响?确保每次调用子智能体时,都开启一个新的、干净的对话会话,只传入其 `.md` 文件内容和当前任务指令。
* **格式解析失败**:主智能体是否能正确解析子智能体返回的JSON?子智能体返回的JSON是否偶尔格式错误?可以在输出格式要求中加入“你必须输出**且仅输出**一个合法的JSON对象,不要有任何其他前导或后置文本”来强化约束。
**持续迭代优化**:
* **收集失败案例**:建立一个“错题本”,记录智能体系统处理失败或效果不佳的案例。分析是哪个环节出了问题:是主智能体理解有误?任务分解不合理?还是某个子智能体能力不足?
* **针对性强化**:根据“错题本”,不是去盲目修改提示词,而是有目的地优化特定环节。例如,如果发现“报告合成”子智能体经常遗漏重要信息,就去优化 `subagent_report_synthesizer.md` 的内部工作流程,增加一个“信息重要性排序”的步骤。
* **A/B测试提示词**:对于关键的子智能体,可以维护两个不同版本的 `.md` 文件(如 `subagent_v1.md`, `subagent_v2.md`),在相同测试集上对比效果,选择更优者。
### 4.3 高级技巧:让系统更智能、更健壮
1. **动态子智能体选择**:在 `AGENTS.md` 的注册表中,除了功能描述,还可以为每个子智能体添加“能力标签”和“置信度分数”。主智能体在分解任务后,可以根据任务特征动态选择最匹配的标签,甚至可以将一个任务同时发给两个类似的子智能体,然后对结果进行投票或综合,提高鲁棒性。
2. **子智能体链与工作流**:有些复杂任务需要多个子智能体按顺序协作。你可以在 `AGENTS.md` 中定义一些“预置工作流”。例如,“深度行业分析”工作流可能固定按 `意图分析` -> `宏观信息搜集` -> `公司数据抓取` -> `竞争对比` -> `报告生成` 的顺序调用子智能体。
3. **上下文管理与记忆**:对于需要长期记忆的对话式智能体,可以引入一个专门的 `subagent_memory_manager.md`。它负责将对话中的关键实体、事实、用户偏好以结构化的方式存储和检索,其他子智能体在需要时可以向它“查询”记忆。
Harness Engineering 的精髓不在于使用了多么炫酷的框架,而在于这种 **“分而治之、定义接口、明确职责”** 的工程化思想。`AGENTS.md` 和 `subagents.md` 是这种思想的具体承载。当你开始以编写模块化代码的方式来编写提示词时,你会发现构建和维护复杂AI应用的效率与可靠性,将得到质的提升。这不再是魔术,而是可重复、可调试、可迭代的工程。更多推荐


所有评论(0)