AgentScope Java Harness:7. 子 Agent 编排 文件驱动的多智能体协作架构 当单个 Agent 的能力触及天花板真正的突破不在于更强的模型而在于更优雅的协作。AgentScope Harness 用文件即规格、状态即协调的设计让多 Agent 编排从代码硬编码走向声明式配置。一、引言为什么单 Agent 不够用在实际业务中我们很快会遇到单 Agent 的三重瓶颈瓶颈表现能力边界一个 Agent 无法同时精通代码审查、数据分析、文档撰写上下文膨胀所有工具和知识塞进一个 prompttoken 爆炸、注意力分散职责混乱“全能 Agent” 变成什么都做但什么都不精的万金油传统的多 Agent 框架通常用代码硬编码来解决这个问题// 传统方式编排逻辑写在代码里if(task.equals(code_review)){codeReviewAgent.call(input);}elseif(task.equals(data_analysis)){dataAnalysisAgent.call(input);}这种方式的问题显而易见**每新增一个子 Agent都要改代码、重新编译、重新部署。**编排逻辑和业务逻辑耦合非技术人员无法参与版本管理困难。AgentScope Java 2.0 的 Harness 模块给出了一个截然不同的答案子 Agent 的规格声明是文件不是代码。主 Agent 通过读取工作区中的 Markdown 文件来发现和编排子 Agent。二、核心设计哲学文件驱动编排2.1 三大原则┌─────────────────────────────────────────────────────────────┐ │ 文件驱动编排的三大原则 │ │ │ │ 1. 规格即文件 子 Agent 的能力描述是 Markdown不是 Java 类 │ │ 2. 发现即扫描 框架自动扫描 subagents/ 目录无需手动注册 │ │ 3. 编排即推理 主 Agent 通过 LLM 推理决定委派不是 if-else │ └─────────────────────────────────────────────────────────────┘2.2 与传统方式的对比维度代码硬编码编排Harness 文件驱动编排新增子 Agent改代码 编译 部署放一个 .md 文件到 subagents/非技术人员参与❌ 不可能✅ 编辑 Markdown 即可版本管理Git commit 散落整个 subagents/ 目录天然 Git 友好运行时动态调整❌ 需重启✅ 下轮推理自动生效多环境迁移代码分支 / 配置中心复制目录人机共编❌✅ 开发者、PM、领域专家都能编辑三、子 Agent 规格文件Subagent Spec3.1 文件位置与命名约定workspace/ └── subagents/ ├── weather-agent.md ← 天气查询子 Agent ├── flight-agent.md ← 航班搜索子 Agent ├── code-reviewer.md ← 代码审查子 Agent └──>3.2 规格文件格式每个 .md 文件遵循统一的 Front Matter Body 结构--- name: weather-agent description: 查询指定城市的实时天气和未来天气预报 tools: - get_weather - get_forecast model: gpt-4o-mini # 可选指定子 Agent 使用的模型 max_turns: 5 # 可选最大推理轮次 timeout_seconds: 30 # 可选超时时间 --- # Weather Agent ## 职责 你是一个专业的天气查询助手。当用户询问天气相关问题时 使用 get_weather 和 get_forecast 工具获取准确数据。 ## 输出格式 - 当前天气温度、湿度、风力、天气状况 - 未来预报按天列出包含最高/最低温度和降水概率 ## 约束 - 只回答天气相关问题其他问题礼貌拒绝 - 数据来源必须是工具返回的结果不要编造 - 温度单位默认摄氏度用户指定华氏度时切换3.3 Front Matter 字段详解字段必填类型说明name✅String子 Agent 唯一标识用于委派调用description✅String能力描述注入主 Agent system prompttools❌List子 Agent 可用的工具白名单model❌String指定模型不填则继承主 Agent 模型max_turns❌Integer最大 ReAct 推理轮次timeout_seconds❌Integer单次执行超时秒sandbox❌Object沙箱配置隔离执行memory❌Object记忆配置独立记忆空间3.4 Body 部分的作用Body 部分是子 Agent 的完整 system prompt。它定义了角色定位和行为约定输入输出格式规范约束和禁止行为领域知识和工作流指引 关键设计Front Matter 是机器可读的结构化元数据Body 是人类可读的自然语言指令。两者分离各司其职。四、自动发现与装配机制4.1 构建期扫描HarnessAgentmainAgentHarnessAgent.builder().name(travel-assistant).model(newOpenAIChatModel(apiKey,gpt-4o)).workspace(Path.of(./workspace))// 框架自动扫描 workspace/subagents/*.md// 无需手动注册任何子 Agent.build();扫描流程HarnessAgent.build() │ ▼ WorkspaceContextHook │ ├── listDir(subagents/) │ → [weather-agent.md, flight-agent.md, ...] │ ├── 逐个解析 Front Matter │ → SubagentSpec(name, description, tools, ...) │ ├── 生成委派工具描述 │ → delegate_to_weather_agent: 查询指定城市的实时天气... │ └── 注入主 Agent system prompt → 主 Agent 知道自己有哪些子 Agent 可以委派4.2 注入主 Agent 的内容框架将每个子 Agent 的 name description 拼装为一段委派指引注入主 Agent 的 system prompt## Available Sub-Agents You can delegate tasks to the following specialized sub-agents: - **weather-agent**: 查询指定城市的实时天气和未来天气预报 - **flight-agent**: 搜索和比较航班信息支持多条件筛选 - **code-reviewer**: 审查代码质量、安全性和最佳实践 - **data-analyst**: 分析数据集生成图表和洞察报告 Use the delegate_to_agent_name tool to assign tasks. Only delegate when the task clearly matches a sub-agents capability.4.3 运行时热更新由于子 Agent 规格是从文件实时读取的修改 .md 文件后下一轮推理立即生效# 新增一个子 Agentecho--- name: hotel-agent description: 搜索和推荐酒店支持价格/星级/位置筛选 tools: - search_hotels - get_hotel_details --- # Hotel Agent ...workspace/subagents/hotel-agent.md# 无需重启服务下一次 call() 自动发现 hotel-agent五、委派执行流程5.1 完整调用链用户帮我查一下明天北京到上海的航班然后看看上海天气 │ ▼ 主 Agent 推理 │ 识别出两个子任务航班查询 天气查询 │ ├── ① delegate_to_flight_agent(明天北京到上海的航班) │ │ │ ▼ 框架创建子 Agent 实例 │ │ 加载 flight-agent.md 的完整 spec │ │ 装配 tools 白名单中的工具 │ │ 设置 model / max_turns / timeout │ │ │ ▼ 子 Agent ReAct 推理 │ │ 调用 search_flights 工具 │ │ 生成结构化结果 │ │ │ ▼ 返回结果给主 Agent │ ├── ② delegate_to_weather_agent(上海明天的天气) │ │ │ ▼ 同上流程 │ │ │ ▼ 返回结果给主 Agent │ ▼ 主 Agent 整合两个子任务的结果 │ 生成统一的回复 │ ▼ 返回给用户5.2 委派工具的内部实现delegate_to_agent_name 是一个由框架自动注册的内部工具对主 Agent 来说和普通工具没有区别{name:delegate_to_weather_agent,description:查询指定城市的实时天气和未来天气预报,parameters:{type:object,properties:{task:{type:string,description:要委派给 weather-agent 的具体任务描述}},required:[task]}}5.3 子 Agent 的执行隔离每个子 Agent 在执行时拥有独立的上下文维度主 Agent子 AgentSystem PromptAGENTS.md MEMORY.md 子 Agent 列表子 Agent spec body工具集全部工具 委派工具仅 spec 中声明的 tools对话历史完整用户对话仅本次委派的 task 描述记忆共享 MEMORY.md可配置独立记忆空间沙箱主 Agent 沙箱可配置独立沙箱 设计意图子 Agent 不需要也不应该看到主 Agent 的完整上下文。这既节省了 token又避免了信息泄露和注意力分散。六、高级编排模式6.1 串行编排Pipeline用户请求 → 主 Agent │ ├── delegate_to_data_collector(收集Q3销售数据) │ ↓ 返回原始数据 ├── delegate_to_data_analyst(分析Q3销售趋势) │ ↓ 返回分析报告 └── delegate_to_report_writer(生成Q3销售报告) ↓ 返回最终报告主 Agent 通过 LLM 推理自动决定串行顺序无需代码定义 pipeline。6.2 并行编排Fan-out / Fan-in用户请求 → 主 Agent │ ├── delegate_to_flight_agent(...) ─┐ ├── delegate_to_hotel_agent(...) ─┼── 并行执行 └── delegate_to_weather_agent(...) ─┘ ↓ 主 Agent 整合三个结果⚠️ 注意并行执行取决于主 Agent 的推理能力和模型的 function calling 支持。部分模型支持在一次响应中调用多个工具。6.3 条件编排Conditional用户请求 → 主 Agent │ ├── 判断任务类型 │ ├── 代码相关 → delegate_to_code_reviewer │ ├── 数据相关 → delegate_to_data_analyst │ └── 通用问题 → 自己回答 │ ▼ 根据 LLM 推理结果动态选择**关键点**条件判断由 LLM 推理完成不是代码中的 if-else。新增分支只需添加新的子 Agent 文件。6.4 嵌套编排Hierarchical主 Agent ├── delegate_to_research_agent(调研竞品) │ ├── delegate_to_web_searcher(搜索竞品信息) │ └── delegate_to_doc_reader(阅读竞品文档) └── delegate_to_report_writer(生成竞品分析报告)子 Agent 本身也可以是 HarnessAgent拥有自己的 subagents/ 目录形成多级编排树。七、子 Agent 与工作区的深度集成7.1 共享工作区 vs 独立工作区// 方式一共享主 Agent 工作区默认// 子 Agent 可以读取主 Agent 的 knowledge/、skills/ 等// 方式二独立工作区HarnessAgentsubAgentHarnessAgent.builder().name(isolated-analyst).workspace(Path.of(./workspaces/analyst))// 独立目录.build();模式适用场景优势风险共享工作区子 Agent 需要访问主 Agent 的知识/技能资源共享避免重复子 Agent 可能误改主 Agent 文件独立工作区子 Agent 完全自治强隔离互不干扰需要单独维护知识和配置7.2 任务记录持久化子 Agent 的执行记录自动写入工作区workspace/agents/mainAgentId/tasks/ ├── sess-001.json ← 会话级任务汇总 └── sess-001/ ├── task-001-flight.json ← 航班查询任务详情 └── task-002-weather.json ← 天气查询任务详情每个任务记录包含委派的 task 描述子 Agent 的完整推理过程工具调用日志最终返回结果耗时和 token 消耗7.3 记忆联动编辑# subagents/data-analyst.md Front Mattermemory:enabled:truescope:independent# independent | sharedflush_trigger:alwaysscope行为shared子 Agent 读写主 Agent 的 MEMORY.mdindependent子 Agent 拥有独立的 MEMORY.md 和 memory/ 目录八、完整配置示例8.1 差旅助手主 AgentHarnessAgenttravelAssistantHarnessAgent.builder().name(travel-assistant).model(newOpenAIChatModel(apiKey,gpt-4o)).workspace(Path.of(./workspace))// 记忆.memory(MemoryConfig.defaults())// 压缩.compaction(CompactionConfig.builder().triggerMessages(30).keepMessages(10).build())// 沙箱.filesystem(newSandboxFilesystemSpec().backend(newDockerSandboxBackend().image(python:3.11-slim).build()).isolationScope(IsolationScope.USER).build())// 状态持久化.stateStore(newRedisAgentStateStore(redisClient))// 子 Agent 自动从 workspace/subagents/ 发现// 无需额外配置.build();8.2 对应的工作区结构workspace/ ├── AGENTS.md │ # Travel Assistant │ ## 角色 │ 你是一个企业差旅助手负责协调航班、酒店、天气等信息查询。 │ ## 编排策略 │ - 航班查询委派给 flight-agent │ - 酒店推荐委派给 hotel-agent │ - 天气查询委派给 weather-agent │ - 简单问题直接回答不要过度委派 │ ├── MEMORY.md ├── tools.json ├── knowledge/ │ └── reimbursement-policy.md │ ├── subagents/ │ ├── flight-agent.md │ ├── hotel-agent.md │ ├── weather-agent.md │ └── expense-calculator.md │ └── agents/travel-assistant/ ├── sessions/ └── tasks/九、与其他子系统的协作┌─────────────────────────────────────────────────────────────┐ │ 子 Agent 编排生态 │ │ │ │ ┌──────────────┐ │ │ │ subagents/*.md│ ← 规格文件人类编辑 / Agent 自生成 │ │ └──────┬───────┘ │ │ │ 构建期扫描 │ │ ▼ │ │ ┌──────────────┐ 注入 system prompt │ │ │ 主 Agent │ ◀────────────────────────────────────┐ │ │ │ (HarnessAgent)│ │ │ │ └──────┬───────┘ │ │ │ │ delegate_to_xxx │ │ │ ▼ │ │ │ ┌──────────────┐ │ │ │ │ 子 Agent │ ── 任务记录 ──▶ tasks/*.json │ │ │ │ (HarnessAgent)│ │ │ │ └──────┬───────┘ │ │ │ │ │ │ │ ┌────┴────┬──────────┬──────────┐ │ │ │ ▼ ▼ ▼ ▼ │ │ │ ┌──────┐ ┌──────┐ ┌────────┐ ┌────────┐ │ │ │ │Tools │ │Memory│ │Sandbox │ │Session │ │ │ │ │白名单│ │独立/ │ │独立/ │ │持久化 │ │ │ │ │ │ │共享 │ │共享 │ │ │ │ │ │ └──────┘ └──────┘ └────────┘ └────────┘ │ │ │ │ │ │ 主 Agent system reminder ◀── 任务状态反馈 ─────────────┘ │ └─────────────────────────────────────────────────────────────┘子系统与子 Agent 的关系Workspace规格文件存储在工作区任务记录写入工作区记忆可配置独立或共享记忆空间沙箱可配置独立沙箱或共享主 Agent 沙箱压缩子 Agent 有独立的上下文窗口和压缩策略权限工具白名单在 spec 中声明框架强制执行Session子 Agent 的推理过程持久化为任务记录十、最佳实践10.1 规格文件编写指南原则说明description 要精确这是主 Agent 决定委派的唯一依据模糊描述导致误委派Body 要自包含子 Agent 看不到主 Agent 的上下文spec body 必须包含所有必要信息tools 要最小化只授予完成任务必需的工具遵循最小权限原则约束要明确明确写出不做什么比做什么更重要输出格式要标准化便于主 Agent 解析和整合10.2 编排策略建议场景推荐策略任务明确、边界清晰文件驱动委派本文方案需要复杂条件分支主 Agent LLM 推理 子 Agent 文件需要严格顺序保证在主 Agent AGENTS.md 中写明编排流程子 Agent 间需要通信通过主 Agent 中转不要让子 Agent 直接对话动态生成子 AgentAgent 自己写 .md 文件到 subagents/下轮生效10.3 常见反模式# ❌ description 太模糊 description: 处理各种任务 # ❌ Body 依赖主 Agent 上下文 ## 注意事项 请参考上面用户提到的报销标准... # 子 Agent 看不到上面 # ❌ tools 过多 tools: [tool_a, tool_b, tool_c, ..., tool_z] # 违反最小权限 # ❌ 没有约束 # 缺少禁止行为段落子 Agent 可能越界十一、设计哲学总结1. 规格即文件编排即推理这是整个子 Agent 系统的基石。规格不是代码编排不是 if-else。这使得非技术人员可以参与 Agent 能力建设也使得系统可以在运行时自我进化。2. 发现优于注册框架自动扫描 subagents/ 目录无需手动注册。新增子 Agent 的唯一操作就是放一个文件。这种约定优于配置的设计大幅降低了使用门槛。3. 隔离优于共享子 Agent 默认拥有独立的上下文、工具集和对话历史。共享是显式配置的例外不是默认行为。这确保了子 Agent 的专注性和安全性。4. 记录优于遗忘每次委派的完整过程都持久化为任务记录。这不仅支持事后审计也为主 Agent 提供了反思的素材——它可以回顾过去的委派效果优化未来的编排决策。5. 组合优于继承子 Agent 不是主 Agent 的子类而是独立的、可组合的能力单元。同一个子 Agent 可以被多个主 Agent 复用也可以在嵌套编排中被其他子 Agent 调用。十二、结语AgentScope Harness 的子 Agent 编排设计回答了一个根本问题如何让多 Agent 协作像搭积木一样灵活而不是像写代码一样僵硬答案是把编排的知识从代码中解放出来变成人类可读、机器可解析、Agent 可自生成的文件。当你把子 Agent 的规格看作文档而非配置时很多设计决策就变得自然而然了文档可以 Git 管理 → 版本控制免费获得文档可以由任何人编辑 → 团队协作门槛降低文档可以在运行时更新 → 热更新零成本文档可以由 Agent 自己撰写 → 自我进化成为可能如果你正在构建需要多能力协作的 Agent 系统这套文件驱动编排的设计思路值得深入研究和借鉴。它不仅仅是一种技术方案更是一种让 AI 系统回归人类可理解、可参与、可治理的工程哲学。