拆解 OpenHands(14)--- Microagents

张开发
2026/4/5 16:11:41 15 分钟阅读

分享文章

拆解 OpenHands(14)--- Microagents
0x00 概要很多Agent系统会采用多智能体multi-agent架构划分不同子模块/子Agent各司其职由中央调度Agent统筹管理整个生命周期。这种模块化架构能将复杂任务拆解给最擅长该子任务的模块发挥各模型所长避免单一模型在某些任务上的弱点。在OpenHands 中Microagents本质上是一组量身定制的指令模块核心作用是给 OpenHands 工具注入更聚焦的能力 —— 不管是某个细分领域的专业知识还是特定任务的标准化流程都能通过它们来落地。对开发者来说这些小模块就像身边的专项助手遇到 Git 操作、代码审查这类具体场景时不用再手动梳理步骤微型代理会提供现成的专业指引重复任务能直接交给它们自动化处理还能保证不同项目里的操作逻辑保持一致省不少事。Microagents允许我们为 Agent “外挂”领域知识而无需修改 Agent 的核心代码或 Prompt。Memory组件会在任务开始时或在对话中检测到特定关键词时自动加载相应的Microagent文件内容并将其作为上下文信息提供给 LLM。这使得 Agent 能够快速适应特定项目通过加载项目专属的repo.mdAgent 可以了解项目的架构、编码规范和测试方法。利用领域知识比如当用户提到 “Python” 时可以自动注入一份关于 Python 最佳实践的knowledge.md。0x01 需求1.1 当前问题既然单智能体能搞定不少复杂事为啥还要费劲搞多智能体协作核心原因很简单任务一超出一定复杂度单个智能体就容易 “力不从心”。就像一个人要同时处理项目规划、数据调研、数学计算、文案撰写一堆事不仅容易顾此失彼还会被海量信息淹没 —— 智能体也一样面对太多工具要选、太多上下文要记它的 “思考空间” 根本不够用决策效率和准确性都会明显下滑。更别说有些任务横跨好几个专业领域指望一个智能体精通所有就像让一个医生同时当好工程师显然不现实。单一的、庞大的“万能”Agent在处理多任务时其上下文窗口和工具集会变得异常臃肿导致“上下文污染)”Context Pollution最终影响系统的可靠性和效率。LangChain的benchmark研究显示当distractor domains干扰域从0增加到8个时单agent架构的性能从0.67暴跌至0.34下降50%。1.2 多智能体系统而多智能体系统恰好能解决这些痛点。它的核心逻辑是 “分工协作”遇到复杂任务时先把大任务拆成一个个小模块比如把 “完成一份市场分析报告” 拆成 “数据收集”“统计计算”“报告撰写”“合规审核” 几个子任务再给每个子任务分配专门的 “专家” 智能体 —— 有的专攻数据爬取有的擅长数学建模有的精通文案润色。这些智能体不用包揽所有事只需要把自己领域的工作做精。它们之间还能随时沟通数据爬取的智能体拿到素材后会同步给统计计算的智能体计算结果出来后再传给文案智能体过程中如果遇到问题还能互相协调调整。这种模式不仅让每个智能体都能发挥专长还可能产生意外的 “协作红利”—— 就像一个高效的团队整体能完成的事远超出单个成员的能力总和。从实际开发来看多智能体也更实用每个智能体都是独立模块开发时不用考虑全盘测试和维护起来更简单如果某个领域需要升级直接替换对应的智能体就行不用动整个系统而且智能体之间怎么沟通、传递信息都能提前设定好规则比单个智能体混乱调用工具要可控得多。1.3 Multi-Agent多智能体Multi-Agent系统与单一智能体工作流的核心区别在于突破了 “顺序接力” 的任务执行模式实现了智能体间的高效并行协作。也有研究人员认为Sub-Agents 是 Multi-Agent 体系下的一种架构模式而不是一个与 Multi-Agent 对立的总体范式。Multi-Agent多智能体系统 本质上是一群相对独立的智能体在协作。它们可能有各自的目标、各自的状态、各自的上下文通过通信协议来协调。就像一个真正的工程团队产品经理、架构师、工程师、测试大家有明确的分工各自负责自己的部分通过会议、文档、工具来协同。而Sub-Agent子代理 本质上是集中式架构下的分工。一个主智能体掌控全局把任务委派给几个专用的子代理。这些子代理更像工具无状态只处理被分配的子任务。就像一个项目经理手下有几个专精的执行者。项目经理知道全局目标和上下文根据需要把任务分发给不同的人拿到结果后再整合。关键区别在于控制权和上下文。Multi-Agent模式下控制权是分布式的每个Agent都有一定的自主权上下文是隔离的。而Sub-Agent模式下控制权是集中式的主智能体说了算上下文是共享的。1.4 连接机制多智能体Multi-Agent的核心思想是让专业的人干专业的事。我们创建多个拥有独立 Prompt 和独立工具的 Agent然后通过某种机制把它们连起来。最基础的连接机制有两种Handoffs交接/路由和Orchestrator-Workers指挥/分发。handoffs 指的是一个智能体将其执行上下文和执行权交接给另一个智能体。handoffs需要包含两个最基本的要素目的地下一个智能体State传递给下一个智能体的信息其实工具调用也是一种连接机制比如一个智能体如主管将另一个智能体作为工具进行调用。移交更适用于自主协作的场景而工具调用则提供了更明确的层级控制和接口约束。1.5 Sub-agentSub-agent 这一架构的核心设计是引入 “协调者智能体Orchestrator Agent” 作为全局管控核心其核心职责是先深度理解整体任务目标再通过合理的任务拆解策略将复杂任务分解为多个可独立执行的子任务进而委派给多个并行工作的 “子智能体Sub-agent”。该系统的实现逻辑为在协调者智能体的视角中调用子智能体与调用普通工具Tool的交互模式完全一致。协调者通过工具调用tool calling机制以提示词prompt形式向子智能体下达明确指令子智能体接收指令后在独立的执行环境中自主完成分配的任务无需与其他子智能体交互最终仅将完成结果反馈给协调者。子智能体架构能够高效落地的本质是上下文工程Context Engineering的成功实践。其核心思想在于精准把控 “信息供给的时机与内容”—— 为每个子智能体创建专注且隔离的执行环境确保其在处理对应子任务时能获得最匹配的信息与工具支持。这种设计不仅能大幅提升整个系统的任务处理性能还能通过职责拆分与环境隔离降低复杂目标的实现成本成为应对大规模、多维度复杂任务的高效架构方案。1.6 microagentsGoogle Cloud的一篇文章给出了Agent as Tool工具式子代理的说法。。Agent as Tool就像一个专家顾问主智能体调用它时给出明确的输入拿到明确的输出就像调用一个API。这个专家顾问有自己的逻辑但主智能体不需要知道细节。而Sub-Agent委派式子代理更像一个项目经理的分身它在主智能体的全局上下文中工作处理复杂的多步骤流程可以访问主智能体的对话历史和状态。结合 Google Cloud 对两种代理模式的核心界定以及 OpenHands 的 microagents微代理的功能特性来看microagents 本质上属于 Agent as Tool工具式子代理。下面结合两者的核心差异与 microagents 的具体表现展开分析从核心定义与控制逻辑来看Google Cloud 明确Agent as Tool 是封装好的特定任务专家主代理调用它时只需传递清晰输入并获取直接输出类似事务性 API无需关注其内部逻辑而 Sub - Agent 是接受委派的角色需自主处理复杂多步骤流程和主代理是层级协作关系拥有一定自主决策与流程管理权。OpenHands 的 microagents 不管是知识代理、任务代理还是仓库代理均是响应特定触发条件来执行固定功能。比如知识代理靠 “docker”“container” 等关键词触发提供对应领域的标准化支持任务代理按预设交互式模板接收参数后完成 PR 描述生成等操作。它们不会自主规划复杂任务流程完全由系统或主流程触发调用契合 Agent as Tool 的 “被动响应、执行特定功能” 的控制逻辑。从上下文与状态特性来看Agent as Tool 具有上下文隔离、无状态的特点运行在自身独立会话中无法获取调用方的对话历史和状态且每次交互的信息都靠单次请求传递。而 Sub - Agent 能共享主代理的上下文处于同一会话适合需要多步骤推进的有状态流程。microagents 是独立封装的模块不同代理间相互隔离。例如仓库代理仅加载所在项目的专属规范知识代理只聚焦单一领域的知识输出。它们的运行不依赖其他代理的历史状态每次触发都是基于当前的输入信息执行任务并返回结果不存在与主流程或其他代理共享上下文来推进多步骤任务的情况符合 Agent as Tool 的无状态、上下文隔离特征。从复用性与耦合度来看Agent as Tool 的一大优势是复用性强可在不同代理或系统中被重复调用与调用方的耦合度低而 Sub - Agent 和主代理耦合紧密是特定流程的一部分复用性较弱多适配所属的层级协作体系。microagents 的设计着重于高复用性。公共微代理库中的代理可跨不同项目使用私有仓库代理虽为团队专属但也是在项目内部的固定场景中重复发挥作用。并且它们可通过简单配置接入系统无需和主流程进行深度的层级绑定开发这种高复用、低耦合的特性和 Sub - Agent 的强耦合特征不符反而匹配 Agent as Tool 的核心特点。1.7 原理1.7.1 协作多智能体不仅仅是把任务拆分它引入了一个全新的优化维度协作Collaboration。有研究者问了一个深刻的问题为什么两个Agent配合往往比一个超级Agent更好答案在于一个新的概率项--- 协作概率P(CL|aL)(|)。在多智能体系统中Agent A比如产品经理执行动作aL后不仅仅是产生一个结果它通过动作产生了一个上下文ContextCL并把这个CL传递给Agent B比如程序员。这听起来很抽象但请这样理解 协作和协商Negotiation本质上是在搜索最优的通信上下文。单体Agent只能自己闷头干必须在给定的S下硬解a。多智能体Agent A的任务变成了“寻找一种最好的说法CL”使得Agent B成功的概率最大化。研究者指出这种“通过对话来动态调整上下文”的能力实际上是在运行时Runtime动态微调系统的参数而不需要重新训练模型。这就是多智能体系统强大的数学根源它增加了一个巨大的、可优化的参数空间。1.7.2 tokenAnthropic 在其博客中指出多智能体系统之所以有效主要是因为它们投入足够的token来解决问题。在分析中三个因素解释了BrowseComp评估中95%的性能差异该评估测试浏览智能体定位难以找到信息的能力。研究发现仅token使用量就解释了80%的差异工具调用次数和模型选择是另外两个解释因素。1.7.3 成本虽然多智能体协作听起来很美但研究者非常冷静地泼了一盆冷水协作是有成本的Collaboration Costs。用户增加的每一个Agent每一次交互都会带来延迟Latency网络请求和生成的耗时。算力消耗Tokens真金白银的成本。复杂性Complexity系统越复杂越容易出错。0x02 基本梳理2.1 基类定义Microagents是 Openhands 中一种模块化的知识注入机制。它们通常是一些 Markdown 文件包含了针对特定领域、特定仓库或特定任务的知识、指南或代码片段。从系统架构的角度看微型代理Microagents本质是轻量化的 “专项执行者”—— 它们不负责整体任务的统筹规划只聚焦某一类特定工作比如专门处理代码格式化、数据校验这类单一职责。和主智能体主 Agent的 “总指挥” 角色不同它们更像随时待命的 “专业小分队”平时不占用过多系统资源一旦主智能体需要要么被直接召唤上场要么接手主智能体拆分出来的细分任务灵活又高效。这些专项执行者并不是孤立的 “散兵”系统早就设计好了一套统一的集成逻辑核心就是get_microagents_from_selected_repo这个核心方法。具体用起来很简单用户或者团队可以在自己的代码仓库里单独建一个文件夹专门存放微型代理不管是自己开发的还是适配好的专项工具都可以放在这里统一管理。等系统将这个仓库设为当前的工作仓库时会自动扫描这个专属文件夹把里面所有的微型代理一次性加载进来相当于为系统搭建了一个 “专项工具储备库”。之后主智能体在处理复杂任务时比如遇到需要专门做日志分析或者接口调试的环节就能直接从这个储备库里调取对应的微型代理一起协同完成工作。class BaseMicroagent(BaseModel): Base class for all microagents. name: str content: str metadata: MicroagentMetadata source: str # path to the file type: MicroagentType PATH_TO_THIRD_PARTY_MICROAGENT_NAME: ClassVar[dict[str, str]] { .cursorrules: cursorrules, agents.md: agents, agent.md: agents, }2.2 微型代理的类型大多数微型代理使用带有YAML前导的Markdown文件。对于仓库代理repo.md前导是可选的 - 如果未提供文件将使用默认设置作为仓库代理加载。KnowledgeMicroagent 和 RepoMicroagent 都是 BaseMicroagent 的子类但它们有不同的用途和激活机制。这两种微代理类型共同构成了 OpenHands 系统中灵活而强大的知识管理机制允许同时拥有按需访问的专业知识和持续可用的仓库特定知识。2.2.1. KnowledgeMicroagent知识代理提供由对话中的关键词触发的专业技能。它们帮助语言最佳实践框架指南常见模式工具使用基本特征类型MicroagentType.KNOWLEDGE 或 MicroagentType.TASK激活方式关键词触发当消息中包含特定触发词时激活主要功能提供专业领域知识和特定技能指导用于语言最佳实践、框架指南、常见模式和工具使用通过 match_trigger 方法匹配消息中的触发词激活机制需要在 frontmatter 中定义 triggers 数组仅在用户输入包含触发词时才会被激活适用场景特定技术栈的使用指南框架或工具的最佳实践特定领域的专业知识需要用户输入的任务型微代理TaskMicroagentclass KnowledgeMicroagent(BaseMicroagent): Knowledge micro-agents provide specialized expertise thats triggered by keywords in conversations. They help with: - Language best practices - Framework guidelines - Common patterns - Tool usage def __init__(self, **data): super().__init__(**data) if self.type not in [MicroagentType.KNOWLEDGE, MicroagentType.TASK]: raise ValueError(KnowledgeMicroagent must have type KNOWLEDGE or TASK) def match_trigger(self, message: str) - str | None: Match a trigger in the message. It returns the first trigger that matches the message. message message.lower() for trigger in self.triggers: if trigger.lower() in message: return trigger return None property def triggers(self) - list[str]: return self.metadata.triggers可以在OpenHands的GitHub微型代理中看到一个基于知识的代理示例。2.2.2. RepoMicroagent仓库代理提供仓库特定的知识和指导方针。它们是从.openhands/microagents/repo.md加载特定于个别仓库为其仓库自动激活非常适合团队实践和项目惯例基本特征类型为MicroagentType.REPO_KNOWLEDGE激活方式始终激活与特定仓库关联主要功能提供仓库特定的知识和指南包含私有的、仓库特定的指令自动加载并与当前仓库关联激活机制自动激活不需要触发词在处理相关仓库时始终可用通常来自.openhands/microagents/repo.md文件适用场景仓库特定的开发规范团队实践和约定项目特定的工作流程自定义文档引流通用仓库指南class RepoMicroagent(BaseMicroagent): Microagent specialized for repository-specific knowledge and guidelines. RepoMicroagents are loaded from .openhands/microagents/repo.md files within repositories and contain private, repository-specific instructions that are automatically loaded when working with that repository. They are ideal for: - Repository-specific guidelines - Team practices and conventions - Project-specific workflows - Custom documentation references def __init__(self, **data): super().__init__(**data) if self.type ! MicroagentType.REPO_KNOWLEDGE: raise ValueError( fRepoMicroagent initialized with incorrect type: {self.type} )可以在OpenHands仓库本身的代理中看到一个仓库代理的示例。2.2.3 对比以下是两类微代理的全维度对比涵盖激活、功能、适用场景等核心差异便于快速区分与选型对比维度KnowledgeMicroagent知识型微代理RepoMicroagent仓库型微代理核心类型通用知识 / 技能载体特定仓库专属知识载体激活方式关键词触发需匹配预设触发词自动激活与仓库关联后始终生效作用范围跨仓库通用所有场景均可调用绑定特定仓库仅当前仓库可用触发条件需用户输入包含触发词的内容无需额外操作关联仓库即生效使用频率按需使用用户主动触发持续可用处理仓库任务时自动调用配置要求必须定义triggers触发词列表无需配置triggers内容来源通用技术文档 / 公共知识库仓库内.openhands/microagents/repo.md文件典型内容技术栈指南、框架使用方法、领域专业知识仓库开发规范、团队协作约定、项目工作流程适用场景解答通用技术问题、工具 / 框架使用指导仓库内开发约束、团队实践对齐、项目流程指引2.2.4 TaskMicroagentTaskMicroagent 是 KnowledgeMicroagent 的子类具有特殊的任务导向特性需要用户输入才能执行。核心特点需要用户输入变量提取通过extract_variables方法从内容中提取变量格式为${variable_name}输入检测requires_user_input方法检查内容中是否包含变量输入定义通过inputs属性获取预定义的输入元数据特殊触发方式命令式触发通过格式/agent_name触发例如/test_task自动触发词添加如果 frontmatter 中没有定义触发词系统会自动添加/前缀的触发词适用场景TaskMicroagent 适用于以下场景需要参数的任务需要用户提供特定参数才能执行的任务交互式操作需要与用户进行交互以获取必要信息的操作模板化任务可以通过填充变量来执行的标准化任务2.3 微型代理的来源OpenHands从两个来源加载微型代理2.3.1. 可共享微型代理公共此目录OpenHands/microagents包含所有OpenHands用户都可以使用的可共享微型代理由OpenHands仓库维护非常适合重用知识和常见工作流程目录结构OpenHands/microagents/ ├── # 关键词触发的专业技能 │ ├── git.md # Git 操作 │ ├── testing.md # 测试实践 │ └── docker.md # Docker 指南 ├── # 这些微型代理总是加载 ├── pr_review.md # PR 审查流程 ├── bug_fix.md # Bug 修复工作流程 └── feature.md # 功能实现2.3.2. 仓库指令私有每个仓库可以在.openhands/microagents/repo.md中拥有自己的指令。这些指令是私有于该仓库在使用该仓库时自动加载非常适合仓库特定的指导方针和团队实践示例仓库结构your-repository/ ├── .openhands/ ├── microagents/ ├── repo.md # 仓库特定的指令 ├── ... # 仅在此仓库内可用的私有微型代理当OpenHands与仓库协作时它将如果存在从.openhands/microagents/repo.md加载仓库特定的指令根据对话中的关键词加载相关的知识代理2.4 升级为 Skill注意在OpenHands最新代码中对MicroAgent升级为Skills我们会在其他系列中进行Skill的相关学习和分析。https://github.com/OpenHands/extensionshttps://docs.openhands.dev/overview/skillshttps://docs.openhands.dev/sdk/arch/skillKnowledgeMicroagentKnowledgeMicroagent is the legacy name for what is now called a Knowledge Skill (keyword-triggered skill). Knowledge Skills are keyword-triggered skills that activate when specific keywords are detected in user messages. They use a KeywordTrigger with regex patterns to match against user input, and when matched, inject domain-specific knowledge into the agents context.RepoMicroagentRepoMicroagent is the legacy term for what is now called a Repository Skill (or General Skill / Permanent Context). These are always-active, repository-specific guidelines that are automatically loaded into the agents context at conversation start. The recommended approach is to create an AGENTS.md file at your repository root. This file contains project purpose, setup instructions, repo structure, and development guidelines. It has no trigger — its always injected into the system prompt. You can also use model-specific variants like GEMINI.md or CLAUDE.md. Legacy paths (.openhands/microagents/) are still supported but deprecated in favor of .agents/skills/0x03 实现3.1 处理流程CodeActAgent 通过response_to_actions将工具调用转换为AgentDelegateAction。AgentController 接收到AgentDelegateAction并调用start_delegate方法创建新的代理控制器处理委托任务。3.2 触发条件AgentDelegateAction 会在以下条件下生成LLM 决定将任务委托给另一个专门的代理比如LLM 调用名为 delegate_to_browsing_agent 的工具函数该工具函数需要以下参数agent要委托给的代理名称task委托的具体任务描述可选的 inputs传递给委托代理的额外输入参数# # AgentDelegateAction (Delegation to another agent) # elif tool_call.function.name delegate_to_browsing_agent: action AgentDelegateAction( agentBrowsingAgent, inputsarguments, )3.3 AgentDelegateActionAgentDelegateAction 是由 LLM 决定委托任务时通过调用相应工具函数生成的然后通过 response_to_actions 方法处理并添加到待处理动作队列中最终在 step 方法中返回执行。dataclass class AgentDelegateAction(Action): agent: str inputs: dict thought: str action: str ActionType.DELEGATE property def message(self) - str: return fIm asking {self.agent} for help with this task.3.4 特色3.4.1 委托代理Delegate机制AgentController通过“委托代理Delegate机制”实现对 microAgent子智能体的全生命周期控制核心流程如下触发启动主 Agent 生成AgentDelegateAction动作含子智能体名称、任务参数主控制器通过start_delegate()方法初始化子智能体控制器AgentController实例标记is_delegateTrue。资源与状态隔离子智能体控制器继承主控制器的事件流、文件存储等资源但拥有独立的状态State包括独立的迭代次数、预算限制、任务上下文避免与主 Agent 相互干扰。事件转发与独立执行子智能体运行期间主控制器将所有事件如用户消息、工具反馈转发给子控制器处理子智能体独立执行任务无需主 Agent 干预。状态监控与终止主控制器实时检查子智能体状态当子智能体完成FINISHED、拒绝REJECTED或出错ERROR时通过end_delegate()方法终止子智能体回收资源并接收其执行结果。结果整合子智能体终止后主控制器将其输出结果封装为AgentDelegateObservation事件回传给主 Agent主 Agent 基于该结果继续执行后续任务。3.4.2 功能概述AgentController是 OpenHands 框架中智能体Agent的核心控制组件负责管理 Agent 的生命周期启动、运行、终止、事件处理动作 / 观察结果、状态维护、资源调度以及子智能体microAgent的委托与协同是多智能体系统中实现 “主 - 子 Agent 协作” 与 “任务拆分执行” 的核心枢纽。主 - 子 Agent 交互机制主 Agent 以AgentDelegateAction为 “调用接口”将子任务委托给 microAgent类比工具调用Tool Calling的简洁模式。子智能体拥有独立的控制器实例运行期间事件全转发、状态全隔离执行完成后通过AgentDelegateObservation回传结果实现 “委托 - 执行 - 回调” 的闭环。事件处理机制事件分流根据是否存在活跃子智能体决定事件是转发给子控制器还是主控制器自行处理。类型适配区分Action动作和Observation观察结果事件分别调用对应处理方法支持AgentDelegateAction、用户消息、工具反馈等多类事件。步骤触发通过should_step()方法判断是否触发 Agent 下一步执行如用户消息、子智能体结果回调时自动触发。全生命周期状态管理支持RUNNING、AWAITING_USER_INPUT、AWAITING_USER_CONFIRMATION、FINISHED等多状态切换状态变更时自动同步到事件流并持久化。子智能体状态实时监控异常时自动终止并回收资源确保系统稳定性。鲁棒性设计防卡死机制内置StuckDetector检测 Agent 循环卡死触发异常处理。预算与迭代限制通过State中的iteration_flag和budget_flag控制最大迭代次数与任务预算避免资源耗尽。异常容错对 LLM 错误如上下文窗口溢出、API 超时、子智能体执行错误等场景提供降级策略如历史截断、重试。多智能体协同支持子智能体继承主 Agent 的资源事件流、文件存储、安全分析器但状态独立支持多层级委托子智能体可再委托其他 microAgent。主控制器统一汇总所有智能体的执行 metrics成本、Token 消耗便于全局监控。3.4.3 层级型的合作模式Agent和Microagent之间是层级型的合作模式。层级结构Agent是主要的决策者负责整体任务的执行Microagent是小型的、专门化的代理用于处理特定子任务或提供特定功能Agent可以调用Microagent但Microagent不能直接调用Agent具体实现方式Microagent被加载到Memory中作为工具提供给Agent使用在openhands/server/session/agent_session.py中可以看到microagents通过get_microagents_from_selected_repo方法加载并通过memory.load_user_workspace_microagents添加到内存中Agent可以在需要时调用这些microagents来执行特定任务两种类型的MicroagentsRepo Agents针对特定仓库的代理处理与该仓库相关的任务KnowledgeAgents提供特定领域知识的代理工作流程Agent在执行任务时可以决定是否需要调用某个MicroagentMicroagent执行完任务后将结果返回给AgentAgent根据Microagent的输出继续执行后续操作加载机制Microagents可以从多个位置加载 从选定的仓库中的.openhands/microagents目录从组织/用户级别的仓库例如github.com/acme-co/.openhands/microagents因此这是一种层级型的合作模式其中Agent作为主控制器Microagent作为专门的助手提供特定功能两者之间不是对等的网络型关系也不是监督者与被监督者的关系。3.4.4 流程图主 - 子 Agent 交互与控制流程图AgentController 核心事件处理流程图3.4.5 容错和隔离机制独立的Controller实例当父Agent创建委托时会为子Agent创建一个AgentController实例这确保了子Agent有自己独立的状态管理和事件流程。# Create the delegate with is_delegateTrue so it does NOT subscribe directly self.delegate AgentController( sidself.id -delegate, file_storeself.file_store, user_idself.user_id, agentdelegate_agent, event_streamself.event_stream, conversation_statsself.conversation_stats, iteration_deltaself._initial_max_iterations, budget_per_task_deltaself._initial_max_budget_per_task, agent_to_llm_configself.agent_to_llm_config, agent_configsself.agent_configs, initial_statestate, is_delegateTrue, headless_modeself.headless_mode, security_analyzerself.security_analyzer, )独立的状态管理每个AgentController都有自己的State实例子Agent的状态变化不会影响父Agent。事件流隔离虽然父子Agent共享一个Event Stream但是通过不同的ID和事件源来区分。异常处理系统通过_step_with_exception_handling方法处理异常子Agent的异常不会中断父Agent的运行。错误状态传播当子Agent出错时会通过AgentDelegateObservation将错误信息发给父Agent。状态恢复机制_react_to_exception函数让系统可以从错误状态中恢复。3.5 代码具体工作流程如下3.5.1 调用大模型class CodeActAgent(Agent): def step(self, state: State) - Action: Performs one step using the CodeAct Agent. initial_user_message self._get_initial_user_message(state.history) messages self._get_messages(condensed_history, initial_user_message) params: dict { messages: messages, } params[tools] check_tools(self.tools, self.llm.config) params[extra_body] { metadata: state.to_llm_metadata( model_nameself.llm.config.model, agent_nameself.name ) } response self.llm.completion(**params) actions self.response_to_actions(response) # 在这里处理返回值 for action in actions: self.pending_actions.append(action) return self.pending_actions.popleft()3.5.2 解析如果发现需要调用 delegate_to_browsing_agent则生成一个 AgentDelegateAction。def response_to_actions( response: ModelResponse, mcp_tool_names: list[str] | None None ) - list[Action]: # # AgentDelegateAction (Delegation to another agent) # elif tool_call.function.name delegate_to_browsing_agent: action AgentDelegateAction( agentBrowsingAgent, inputsarguments, )3.5.3 执行AgentController 中会处理AgentDelegateAction执行microAgent。async def start_delegate(self, action: AgentDelegateAction) - None: 启动委托智能体以处理子任务。 OpenHands 是多智能体系统 - 「任务task」系统与用户之间的完整对话始于用户初始输入通常是任务描述 终于智能体发起的完成动作、用户停止操作或错误触发。 - 「子任务subtask」智能体与用户或其他智能体之间的对话。 若单个智能体即可完成任务则任务与子任务合一否则任务由多个子任务组成每个子任务由独立智能体处理。 参数 action (AgentDelegateAction)包含待启动委托智能体信息的动作对象 # 根据动作中指定的智能体名称获取对应的智能体类 agent_cls: Type[Agent] Agent.get_cls(action.agent) # 获取智能体配置优先使用动作指定的配置未指定则复用当前智能体的配置 agent_config self.agent_configs.get(action.agent, self.agent.config) # 创建委托智能体实例确保父子智能体共享LLM注册信息 # 注父子智能体共享指标实现全局指标累积 delegate_agent agent_cls( configagent_config, llm_registryself.agent.llm_registry ) # 启动委托智能体前创建初始状态继承父智能体关键配置 state State( session_idself.id.removesuffix(-delegate), # 会话ID移除父智能体的委托后缀 user_idself.user_id, # 继承用户ID保持用户关联 inputsaction.inputs or {}, # 子任务输入参数默认为空字典 iteration_flagself.state.iteration_flag, # 继承迭代控制标志限制迭代次数 budget_flagself.state.budget_flag, # 继承预算控制标志限制资源使用 delegate_levelself.state.delegate_level 1, # 委托层级1标识子智能体层级 metricsself.state.metrics, # 共享全局指标父子智能体指标统一累积 start_idself.event_stream.get_latest_event_id() 1, # 事件起始ID从最新事件后开始记录 parent_metrics_snapshotself.state_tracker.get_metrics_snapshot(), # 父智能体指标快照用于后续对比 parent_iterationself.state.iteration_flag.current_value, # 父智能体当前迭代次数 ) # 输出调试日志记录委托智能体启动信息 self.log( debug, fstart delegate, creating agent {delegate_agent.name}, ) # 创建委托智能体的控制器核心标记is_delegateTrue避免直接订阅事件流 self.delegate AgentController( sidself.id -delegate, # 会话ID在父ID后添加委托后缀唯一标识 file_storeself.file_store, # 继承文件存储对象用于状态持久化 user_idself.user_id, # 继承用户ID agentdelegate_agent, # 待管理的委托智能体实例 event_streamself.event_stream, # 共享事件流父子智能体事件互通 conversation_statsself.conversation_stats, # 继承对话统计信息 iteration_deltaself._initial_max_iterations, # 迭代次数增量子任务的最大迭代限制 budget_per_task_deltaself._initial_max_budget_per_task, # 单任务预算增量子任务的资源限制 agent_to_llm_configself.agent_to_llm_config, # 继承LLM配置映射 agent_configsself.agent_configs, # 继承智能体配置字典 initial_statestate, # 初始状态继承父智能体配置后的状态 is_delegateTrue, # 标记为委托智能体关键避免重复订阅事件流 headless_modeself.headless_mode, # 继承无头模式无交互界面配置 security_analyzerself.security_analyzer, # 继承安全分析器用于安全校验 )3.5.4 微代理记忆提示模板openhands/microagent/prompts/generate_remember_prompt.j2 是一个 Jinja2 模板文件其主要作用是生成用于更新特殊参考文件的提示语。这个特殊文件存储着重要的信息和学习成果用于执行特定任务并且可以在时间推移过程中扩展以纳入新知识和经验。核心功能事件分析分析提供给它的新事件子集更新决策确定是否需要对特殊参考文件进行更新提示生成生成指导另一个 AI 正确高效地进行这些更新的提示语处理流程接收事件数据通过 {{ events }} 变量接收待分析的事件内容分析分析这些事件以确定需要更新文件的哪些部分生成更新指令创建一个结构化的提示包含具体的更新说明指导原则根据模板内容生成的提示必须遵循以下准则内容要求清晰指定明确指出文件的哪些部分需要更新或添加新章节提供上下文解释基于新事件为什么需要这些更新具体信息精确说明应添加或修改的信息内容格式要求保持结构维持文件现有的结构和格式保持一致性确保更新与现有内容一致不产生矛盾技术实现模板结构jinja2 update_prompt/update_prompt数据流输入通过 events 变量传入的新事件数据处理模板逻辑分析事件并生成更新提示输出包含在 update_prompt 标签内的生成提示应用场景这个模板主要用于记忆维护在 AI 执行任务过程中持续更新重要知识库确保系统能从新经验中学习并改进自动化更新使 AI 能够自动维护自己的知识基础减少手动更新参考文件的需求与其他组件的关系与微代理系统集成作为 Microagent 系统的一部分支持知识的动态更新与 KnowledgeMicroagent 和 RepoMicroagent 配合工作与事件系统连接利用事件系统EventStream收集需要学习的事件与 AgentController 协同工作以维护状态和历史记录这个模板是 OpenHands 系统中实现持续学习和知识管理的关键组件允许 AI 系统从交互中学习并将这些知识持久化到参考文件中。3.5.5 get_prompt 函数get_prompt 函数是一个 FastAPI 路由处理器位于 /openhands/server/routes/manage_conversations.py 文件中路径为 /conversations/{conversation_id}/remember-prompt。其主要作用是基于特定事件生成一个提示模板用于更新特殊参考文件。这个函数是 OpenHands 系统中实现持续学习和知识管理的关键组件之一它使得 AI 系统能够从对话历史中的特定事件生成更新提示从而维护和扩展其知识库。参数处理conversation_id通过依赖注入验证的对话 IDevent_id查询参数指定要从中获取上下文文件的事件 ID其他依赖用户设置存储、对话元数据等核心处理步骤获取事件存储event_store EventStore( sidconversation_id, file_storefile_store, user_idmetadata.user_id )创建一个事件存储实例来访问特定对话的事件历史。提取上下文事件调用_get_contextual_events(event_store, event_id)方法获取目标事件前后各 4 个事件总共约 9 个事件过滤掉无意义的事件类型如 NullAction、NullObservation 等返回格式化的事件字符串生成提示模板从用户设置中加载 LLM 配置使用generate_prompt_template函数基于事件内容生成提示模板模板使用generate_remember_prompt.j2Jinja2 模板生成最终提示通过generate_prompt函数调用 LLM 生成最终提示从 LLM 响应中提取 标签之间的内容与系统其他组件的关系模板系统使用generate_remember_prompt.j2模板位于/openhands/microagent/prompts/目录该模板专门用于生成更新特殊参考文件的提示事件系统

更多文章