动态多级 Agent 编排架构:5大阶段流水线 + 运行时架构 + 选择策略与安全防护
上一篇文章《AgentScope搭企业级Agent平台实战》拆解了企业级 Agent 平台的架构全景:身份权限、MCP/Skill 工具、上下文记忆、安全沙箱、高可用扩展。那篇文章解决的是「单个 Agent 怎么在企业环境里安全稳定运行」的问题。但真实业务场景中,一个 Agent 不可能什么都干--报表Agent擅长数据分析,代码Agent擅长审查代码,数据查询Agent擅长SQL。这就引出了一个更复杂的问题:主Agent怎么动态发现、选择、调度众多子Agent?
本文是上一篇的续篇,聚焦「动态多级 Agent 编排」这一核心场景。后台配置大量子Agent,主Agent收到用户问题后,完成任务拆解、感知子Agent能力池、挑选对应子Agent、调度执行、汇总结果。整个链路涉及5大阶段,每个阶段都有独立的工程挑战。本文基于 AgentScope Java v2.0.0 SDK,结合核心代码片段,全链路拆解动态主子 Agent 编排的实现方案。
一、核心痛点:主Agent怎么知道子Agent擅长什么
动态编排的第一道门槛不是技术实现,而是认知问题:主Agent怎么知道众多子Agent分别擅长什么?
最直觉的方案是手动写死 Prompt,把子Agent列表塞进主Agent的 System Prompt。但这在生产环境根本行不通--后台新增子Agent、修改能力描述、禁用某个子Agent时,难道每次都要修改主Agent配置、重启服务?这完全违背了「元数据驱动」的工程原则。
核心设计原则:所有子Agent定义存数据库,页面配置,不写死代码。运行时动态生成子Agent能力描述注入 Prompt,后台增删改即时生效。下一次请求就能感知到变化,不需要重启服务。
这就引出了整个动态编排架构的设计哲学:元数据驱动 + 动态能力目录 + LLM选择 + 代码校验。LLM 负责智能选择子Agent,代码负责权限校验、合法性校验、深度保护。两者缺一不可--完全信任 LLM 会出安全问题,完全靠代码又失去了灵活性。
二、五大阶段流水线总览
动态主子Agent编排的完整链路分为5个阶段,每个阶段解决一个独立问题:
阶段1
动态构建子Agent能力目录,从DB查询启用的子Agent,组装文本注入Prompt
阶段2
主Agent任务规划,隐式规划LLM直接调工具,显式规划先输出JSON任务清单
阶段3
子Agent选择,LLM自主选择或向量RAG检索,代码侧校验合法性
阶段4
调度执行,串行有依赖/并行无依赖,调用栈深度保护
阶段5
结果汇总与容错,主Agent整合去重,失败换Agent重试
上图展示了完整的运行时架构:用户请求进来后,CatalogBuilder 从 t_agent_meta 表查询启用的子Agent元数据,动态构建能力目录文本,内存拼接到主Agent的 System Prompt 中(不持久化)。主Agent的 LLM 分析用户需求,从能力目录中选择合适的子Agent,通过 sub_agent_call 工具发起调用。工具内部经过三道安全校验(合法性、权限、深度),然后将任务委派给对应的子Agent执行。子Agent返回结果后,主Agent整合去重,输出最终回答。
三、阶段1:子Agent元数据与动态能力目录
所有子Agent定义存数据库,主Agent和子Agent共用同一张 t_agent_meta 表。关键字段包括能力描述(给LLM看)、能力标签、可调用的子Agent ID列表(权限隔离)、温度、最大迭代次数等。
-- t_agent_meta: Agent元数据表(主Agent和子Agent共用)
CREATE TABLE t_agent_meta (
agent_id VARCHAR(64) PRIMARY KEY, -- Agent唯一标识
name VARCHAR(128) NOT NULL, -- Agent名称
description TEXT NOT NULL, -- 能力描述(给LLM看)
sys_prompt TEXT, -- 系统提示词
model_id VARCHAR(128), -- 模型标识 (如 dashscope:qwen-max)
capability_tags JSON, -- ["报表","数据分析"]
skill_id_list JSON, -- 绑定的技能ID列表
callable_sub_agent_ids JSON, -- 权限:可调用的子Agent ID列表
max_iters INT DEFAULT 5, -- 最大迭代次数
temperature DECIMAL(3,2) DEFAULT 0.70, -- 温度
status TINYINT DEFAULT 1, -- 1=启用, 0=禁用
is_main TINYINT DEFAULT 0 -- 1=主Agent, 0=子Agent
);
在 Java 侧,用一条 record 映射表结构,作为整个编排链路的数据载体:
/**
* Agent元数据记录,映射 t_agent_meta 表的一行
*/
public record AgentMeta(
String agentId, // 唯一标识
String name, // 名称
String description, // 能力描述(给LLM选择用)
String sysPrompt, // 系统提示词
String modelId, // 模型标识,null则用默认模型
int maxIters, // 最大迭代次数
List<String> capabilityTags, // 能力标签
List<String> callableSubAgentIds, // 可调用的子Agent ID(权限白名单)
int status // 1=启用 0=禁用
) {}
以企业数据分析平台为例,通常配置3个子Agent:数据查询Agent、报表生成Agent、代码审查Agent。每个Agent有独立的 sysPrompt、能力标签和最大迭代次数,全部存入 t_agent_meta 表,通过管理后台增删改,不需要修改代码或重启服务。
3.2 从元数据构建 SubagentDeclaration
AgentScope Java v2 提供了 SubagentDeclaration API 来声明子Agent规格。生产环境中,不是在代码里写死声明,而是从数据库加载 AgentMeta 后动态构建 SubagentDeclaration,再注册到主Agent:
// 从 t_agent_meta 加载启用的子Agent元数据
List<AgentMeta> enabledAgents = metaRepo.findEnabledByIds(mainMeta.getCallableSubAgentIds());
// 遍历元数据,动态构建 SubagentDeclaration
List<SubagentDeclaration> declarations = new ArrayList<>();
for (AgentMeta meta : enabledAgents) {
SubagentDeclaration.Builder builder = SubagentDeclaration.builder()
.name(meta.agentId()) // agent_id 作为唯一标识
.description(meta.description()) // 能力描述,给主Agent LLM看
.inlineAgentsBody(meta.sysPrompt()) // 子Agent的System Prompt
.maxIters(meta.maxIters()) // 最大迭代次数
.workspaceMode(WorkspaceMode.SHARED) // 共享工作区
.mode(SubagentDeclaration.Mode.SUBAGENT) // 子Agent模式
.inheritParentPermissions(true); // 继承主Agent权限
// 元数据指定了模型则用指定模型,否则用默认模型
if (meta.modelId() != null) {
builder.model(meta.modelId());
} else {
builder.model(defaultModel);
}
declarations.add(builder.build());
}
关键设计:SubagentDeclaration 的 name 必须与 t_agent_meta 的 agent_id 一致,因为主Agent LLM 通过能力目录中的 agent_id 发起调用,工具内部根据 name 匹配到对应的子Agent。description 是 LLM 做选择的核心依据,必须精准描述能力边界。
3.3 动态构建能力目录
核心思路:不是修改数据库里主Agent的 sys_prompt,而是在构建 RuntimeContext 时内存拼接能力目录,不持久化。每次请求动态生成,后台新增子Agent下次请求立即生效。
/**
* 从子Agent元数据列表构建能力目录文本
* 生产环境:从DB查询 -> 组装Markdown表格 -> 注入Prompt(不持久化)
*/
private static String buildCatalog(List<AgentMeta> agents) {
StringBuilder sb = new StringBuilder();
sb.append("\n\n## 可调用的子Agent能力目录\n");
sb.append("| agent_id | 名称 | 能力描述 | 能力标签 |\n");
sb.append("|----------|------|---------|----------|\n");
for (AgentMeta a : agents) {
sb.append(String.format("| %s | %s | %s | %s |\n",
a.agentId(), a.name(),
truncate(a.description(), 40),
String.join(", ", a.capabilityTags())));
}
sb.append("\n使用 agent_send 工具调用子Agent。");
return sb.toString();
}
能力目录生成后,拼接到主Agent System Prompt 尾部,通过 RuntimeContext 注入:
// 加载主Agent元数据
AgentMeta mainMeta = metaRepo.findById(mainAgentId);
// 动态构建能力目录(每次请求重新生成)
String catalog = buildCatalog(enabledAgents);
// 内存拼接:原始sys_prompt + 动态能力目录(不持久化到数据库)
String dynamicSysPrompt = mainMeta.sysPrompt() + catalog;
// 通过 RuntimeContext 注入动态 prompt
RuntimeContext ctx = RuntimeContext.builder()
.userId(userId)
.sessionId(UUID.randomUUID().toString())
.build();
ctx.setSystemPromptOverride(dynamicSysPrompt);
// 调用全局单例引擎
Msg reply = engine.call(new UserMessage(userMessage), ctx).block();
能力目录格式选择:用 Markdown 表格,LLM 天然擅长理解表格结构。每行包含 agent_id、名称、能力描述和能力标签,LLM 根据用户需求做语义匹配,选择最合适的子Agent。表格格式比 JSON 更节省 token,也比纯文本更结构化。
四、阶段2:主Agent任务规划
主Agent收到用户问题后,需要决定怎么拆解任务、调用哪些子Agent、以什么顺序调用。有两种规划模式,适用不同复杂度的场景。
模式A
隐式规划(推荐大多数业务)
不需要输出结构化任务清单,LLM根据能力目录自主思考,直接通过工具调用完成。优势:实现简单,LLM自然行为,不需要额外解析逻辑。适用:子Agent数量少、任务链路不复杂的场景。
模式B
显式规划(复杂任务,可控性更高)
让LLM先输出结构化任务拆解JSON,先规划再执行。优势:Middleware可拦截规划结果,前端展示"正在规划任务",用户可人工干预修改,步骤可审计。适用:多步骤复杂任务、需要人工确认的场景。
隐式规划模式下,主Agent System Prompt 指引 LLM 自主决策:
// 主Agent System Prompt(隐式规划模式)
你是任务协调主Agent。根据用户问题和子Agent能力目录,自主决定调用哪些子Agent。
工作流程:
1. 分析用户需求,判断需要哪些子能力
2. 使用 sub_agent_call 工具调用对应子Agent
3. 如果有数据依赖,先调用数据提供方,拿到结果后再调用消费方
4. 收集所有子Agent返回结果后,整合输出最终回答
汇总规则:
- 整合多个子Agent的输出为连贯回答
- 去重冗余信息,保留最准确的
- 如果子Agent返回错误,尝试换一个子Agent重试
- 最终回答直接回应用户问题,不暴露内部调用细节
注意:不要自己执行子Agent的专业工作,通过 sub_agent_call 委派。
显式规划模式下,LLM 先输出结构化任务清单 JSON,Middleware 拦截后校验所有 agent_id 合法性。如果 LLM 编造了不存在的 agent_id,Middleware 注入错误提示让 LLM 重新规划。这种模式适合需要人工确认的复杂场景:前端可以展示任务清单,用户确认后再执行。
五、阶段3:子Agent选择策略
子Agent选择是整个编排链路中最关键的决策点。选错了子Agent,后面的调度和汇总做得再好也没用。
5.1 策略1:LLM自主选择(子Agent少于10个)
把完整能力目录交给LLM,由大模型根据子任务描述和每个Agent的 description、capability_tags 做匹配选择。这是默认策略,实现最简单。LLM 通过 sub_agent_call 工具调用子Agent,工具内部做三道代码侧校验。
5.2 策略2:向量RAG检索(子Agent超过10个)
当子Agent数量很多,全部塞Prompt会token爆炸。这时需要先做向量检索,召回最匹配的Top-N候选子Agent,只把候选子集注入Prompt。
// 向量检索流程:query -> 召回Top-N候选 -> 只注入候选子集
List<ScoredAgent> scored = candidates.stream()
.map(agent -> {
double score = vectorStore.similarity(
query, agent.getAgentId(),
agent.getDescription() + " " + String.join(" ", agent.getCapabilityTags())
);
return new ScoredAgent(agent, score);
})
.sorted((a, b) -> Double.compare(b.score, a.score))
.limit(TOP_N) // 默认召回5个
.toList();
这个策略的本质是:先用向量检索做粗筛,再用LLM做精筛。向量检索负责从几十上百个子Agent中快速召回最相关的5个,LLM再从这5个中做最终选择。既避免了token爆炸,又保留了LLM的语义理解能力。
六、阶段4:子Agent调度执行
选定子Agent后,进入调度执行阶段。调度方式取决于子任务之间是否有数据依赖。整个调度过程通过 sub_agent_call 和 sub_agent_batch_call 两个工具实现。
6.1 sub_agent_call:单子Agent调用工具
这是核心工具。LLM 从能力目录中选择 agent_id,通过此工具发起调用。工具内部做完整的三道安全校验,然后通过 DefaultAgentManager 创建子Agent实例并执行任务。
@Tool(
name = "sub_agent_call",
description = "调用子Agent执行子任务。传入agent_id(从能力目录中选择)和task(子任务描述)。"
)
public String callSubAgent(
@ToolParam(name = "agent_id", description = "子Agent的唯一标识")
String agentId,
@ToolParam(name = "task", description = "子任务描述")
String task,
ToolCallContext context
) {
RuntimeContext ctx = context.getRuntimeContext();
// === 代码侧三道校验(不完全信任LLM输出) ===
// 1. 校验 agent_id 是否在主Agent允许调用的列表中(权限隔离)
String mainAgentId = ctx.get("main_agent_id");
AgentMeta mainMeta = metaRepo.findById(mainAgentId);
if (!mainMeta.getCallableSubAgentIds().contains(agentId)) {
return "错误: agent_id 不在允许调用的子Agent列表中。请从能力目录中选择。";
}
// 2. 校验子Agent是否存在且启用
AgentMeta subMeta = metaRepo.findById(agentId);
if (subMeta == null || subMeta.getStatus() != 1) {
return "错误: 子Agent不存在或已禁用。请选择其他Agent。";
}
// 3. 调用栈深度校验(防递归)
int currentDepth = ctx.get("call_depth", 0);
if (currentDepth >= 3) {
return "错误: 调用栈深度超过最大限制(3),已拒绝调用。";
}
// === 执行子Agent调用 ===
ctx.set("call_depth", currentDepth + 1);
try {
DefaultAgentManager manager = orchestrator.getSubagentAgentManager();
Agent subAgent = manager.createAgent(agentId, ctx);
Msg result = manager.invokeAgent(
subAgent, ctx.getSessionId(), task, "sub_agent_call"
).timeout(Duration.ofSeconds(30)).block();
return result != null ? result.getTextContent() : "(子Agent无响应)";
} catch (TimeoutException e) {
return "子Agent执行超时(30s)。请简化任务或更换Agent。";
} catch (Exception e) {
return "子Agent执行错误: " + e.getMessage() + "。请尝试更换Agent。";
} finally {
ctx.set("call_depth", currentDepth); // 恢复深度
}
}
关键原则:不完全信任LLM输出。LLM可能编造不存在的agent_id,或选择已禁用的子Agent。代码侧必须做完整校验,校验失败返回错误信息让LLM重新选择。超时控制和异常捕获确保子Agent故障不会拖垮主Agent。
6.2 串行调度(有数据依赖)
子任务之间有数据依赖时,必须串行执行:前一步的输出是后一步的输入。HarnessAgent 原生工具调用就是串行模式--LLM在一次迭代中调用一个 sub_agent_call,拿到结果后进入下一次迭代,基于结果再调用下一个子Agent。不需要额外开发,LLM自然行为就是串行调度:
// 串行调度的执行时序(LLM自主驱动)
// Turn 1: LLM输出 sub_agent_call(agent_data_query, "查询本月销售数据")
// -> 工具执行,返回 {"total_sales": 1250000, "orders": 350, ...}
// Turn 2: LLM拿到数据,输出 sub_agent_call(agent_report_gen, "基于数据生成报表: ...")
// -> 工具执行,返回 "## 销售分析报表\n本月总销售额125万..."
// Turn 3: LLM拿到报表,输出最终回答给用户
// 程序化串行调用(DefaultAgentManager,适用于需要代码侧控制调度逻辑的场景)
var manager = orchestrator.getSubagentAgentManager();
// Step 1: 先查询数据
Agent dataAgent = manager.createAgent("agent_data_query", ctx);
Msg dataResult = manager.invokeAgent(
dataAgent, ctx.getSessionId(),
"查询本月销售数据,包括总销售额、订单数、客单价",
"serial-step-1"
).block();
// Step 2: 基于数据生成报表(依赖Step 1的结果)
Agent reportAgent = manager.createAgent("agent_report_gen", ctx);
Msg reportResult = manager.invokeAgent(
reportAgent, ctx.getSessionId(),
"基于以下销售数据生成分析报表:\n" + dataResult.getTextContent(),
"serial-step-2"
).block();
6.3 sub_agent_batch_call:并行调度(无数据依赖)
子任务之间无依赖时,可以同时跑多个子Agent。sub_agent_batch_call 工具让 LLM 一次传入多个子Agent任务,工具内部用 Flux.merge 并行执行,有最大并行数限制(MAX_PARALLEL=5)。
@Tool(
name = "sub_agent_batch_call",
description = "批量并行调用多个子Agent。适用于子任务之间无数据依赖的场景。"
)
public String batchCall(
@ToolParam(name = "tasks", description = "子任务数组JSON: [{\"agent_id\":\"xxx\",\"task\":\"xxx\"}]")
String tasksJson,
ToolCallContext context
) {
RuntimeContext ctx = context.getRuntimeContext();
// 1. 解析任务列表
List<SubTask> tasks = parseTasks(tasksJson);
if (tasks.size() > MAX_PARALLEL) {
return "错误: 并行调用数量超过限制(" + MAX_PARALLEL + ")";
}
// 2. 校验所有agent_id合法性(复用单调用的校验逻辑)
for (SubTask task : tasks) {
if (!validateAgent(task.agentId(), ctx)) {
return "错误: agent_id '" + task.agentId() + "' 不合法或已禁用。";
}
}
// 3. 并行执行所有子Agent(Reactor Flux.merge)
DefaultAgentManager manager = orchestrator.getSubagentAgentManager();
List<Mono<SubAgentResult>> monos = tasks.stream()
.map(task -> {
Agent subAgent = manager.createAgent(task.agentId(), ctx);
return manager.invokeAgent(subAgent, ctx.getSessionId(),
task.task(), "batch_call")
.map(msg -> new SubAgentResult(task.agentId(),
msg != null ? msg.getTextContent() : "(无响应)"))
.onErrorResume(e -> Mono.just(new SubAgentResult(
task.agentId(), "执行错误: " + e.getMessage())));
})
.toList();
// 4. 等待全部完成,收集结果
List<SubAgentResult> results = Flux.merge(monos).collectList().block();
// 5. 返回汇总结果给主Agent
StringBuilder sb = new StringBuilder();
for (SubAgentResult r : results) {
sb.append(String.format("[子Agent: %s]\n%s\n\n", r.agentId(), r.result()));
}
return sb.toString();
}
程序化并行调用也可以直接用 Mono.zip 实现,适用于需要代码侧精确控制并行的场景:
// 程序化并行调用:两个无依赖的子任务同时执行
var manager = orchestrator.getSubagentAgentManager();
Mono<Msg> dataMono = manager.invokeAgent(
manager.createAgent("agent_data_query", ctx),
ctx.getSessionId(), "查询本月用户增长数据", "parallel-1"
);
Mono<Msg> codeMono = manager.invokeAgent(
manager.createAgent("agent_code_review", ctx),
ctx.getSessionId(), "审查代码: SQL拼接是否有注入风险", "parallel-2"
);
// 并行执行,等待全部完成
var results = Mono.zip(dataMono, codeMono).block();
String dataResult = results.getT1().getTextContent();
String codeResult = results.getT2().getTextContent();
两种并行方式的区别:sub_agent_batch_call 由 LLM 发起,适合 LLM 自主判断"这些子任务无依赖可以并行"的场景;Mono.zip 由代码发起,适合开发者已知任务间无依赖、需要精确控制的场景。
七、阶段5:结果汇总与容错
子Agent执行完毕,结果作为工具返回值交给主Agent。主Agent负责整合多个子Agent的输出、去重冗余信息、校验结果是否满足需求。不需要业务代码手动拼接结果,交给LLM主Agent自己做汇总。
容错是生产环境的关键能力。子Agent可能执行失败、超时、返回空结果。每个子Agent调用都应配置 timeout(Duration.ofSeconds(30)) 超时控制,失败时返回结构化的错误信息给主Agent,主Agent可以决策:换一个子Agent重试、修改子任务指令重试、或告知用户无法完成。
汇总规则注入Prompt:主Agent的 System Prompt 中明确写了汇总规则--整合为连贯回答、去重保留最准确的、如果子Agent返回错误尝试换一个重试、最终回答不暴露内部调用细节。这些规则让LLM的汇总行为可控。
八、安全防护三道防线
动态编排涉及主Agent调用子Agent、子Agent可能再调用其他子Agent,安全风险不容忽视。生产环境必须部署三道防线:
防线1
调用栈深度保护
在 RuntimeContext 中维护 call_depth 计数器,每次子Agent调用前 +1,调用后 -1。超过 MAX_DEPTH(3) 直接拒绝调用。防止A调用B、B调用A的无限递归,这是动态编排最致命的风险。
防线2
权限隔离
主Agent配置 callable_sub_agent_ids 白名单,只有列表中的子Agent可以被调用。LLM 可能选择不在列表中的 agent_id,代码侧校验不通过直接拒绝,返回错误提示让 LLM 重新选择。
防线3
并发数限制
并行调用时限制最大并发数 MAX_PARALLEL=5。使用 Semaphore 控制并行信号量,超限返回错误提示。防止 LLM 一次性发起过多并行调用,压垮下游服务。
九、架构选型速查表
不同场景下的推荐方案,可以直接对照选择:
| 场景 | 推荐方案 | 说明 |
| 子Agent 少于10个 | 全量Prompt注入能力目录 | LLM自主选择,实现最简单 |
| 子Agent 超过10个 | 向量RAG检索候选 | 先召回Top-N,再注入Prompt,防token爆炸 |
| 简单任务 | 隐式规划 | LLM直接工具调用,边想边做 |
| 复杂多步骤任务 | 显式JSON规划 + Middleware拦截 | 先规划再执行,可展示给用户,可人工干预 |
| 子任务有数据依赖 | 串行调度 (sub_agent_call) | 前一步输出=后一步输入,LLM原生行为 |
| 子任务无依赖 | 并行调度 (sub_agent_batch_call) | Flux.merge或Mono.zip并行执行 |
| 子Agent数量动态变化 | 动态能力目录 | 每次请求重新生成,无需重启 |
十、上生产检查清单
元数据与能力目录
- t_agent_meta 表设计完整,包含 callable_sub_agent_ids 权限字段
- AgentMeta record 字段与表结构对齐,包含 modelId/maxIters/temperature
- SubagentDeclaration 从元数据动态构建,name 与 agent_id 一致
- 能力目录每次请求动态生成,不持久化到数据库
- 后台新增/修改/禁用子Agent后,下次请求立即生效
- 子Agent超过10个时启用向量RAG检索策略
工具实现与校验
- sub_agent_call 工具内部三道校验:合法性 + 启用状态 + 调用栈深度
- sub_agent_batch_call 校验所有 agent_id 后再并行执行
- 校验失败返回结构化错误信息,引导 LLM 重新选择
- 调用栈深度保护 MAX_DEPTH=3,finally 块中恢复 depth
- 权限隔离:主Agent只能调 callable_sub_agent_ids 白名单中的子Agent
- 并发数限制 MAX_PARALLEL=5,Semaphore 控制并行信号量
调度与容错
- 串行调度:有数据依赖时前一步输出作为后一步输入
- 并行调度:无依赖任务用 Flux.merge 或 Mono.zip 并行执行
- 每个子Agent调用有 timeout(30s) 超时控制
- 子Agent失败返回结构化错误信息,主Agent可决策重试或降级
- 主Agent System Prompt 包含汇总规则:整合、去重、不暴露内部调用细节
结语
动态多级 Agent 编排的核心挑战不是"让 Agent 能调用子 Agent",而是"让主 Agent 在运行时动态感知、智能选择、安全调度众多子 Agent"。这套5阶段流水线--动态能力目录、任务规划、子Agent选择、调度执行、结果汇总--把整个链路的复杂度收敛到了工程框架内。
与上一篇文章的单 Agent 企业级平台相比,动态编排引入了一个新的维度:Agent 之间的协作关系。单 Agent 解决的是"一个 Agent 怎么安全运行",动态编排解决的是"多个 Agent 怎么高效协作"。元数据驱动让子Agent管理变成配置而非代码,动态能力目录让主Agent的感知能力实时更新,LLM选择 + 代码校验的分工让智能和安全兼得。
从架构设计到生产,关键在于三道安全防线是否到位:调用栈深度防递归、权限白名单防越权、并发限制防压垮。这三道防线不是可选项,是动态编排上生产的必要条件。没有安全防护的动态编排,就像没有刹车的汽车--跑得越快越危险。
参考资料
- AgentScope Java v2 官方文档 https://java.agentscope.io/v2/zh/intro.html
- AgentScope Java v2 子Agent文档 https://java.agentscope.io/v2/zh/docs/building-blocks/subagent.html
- AgentScope Java v2 Harness 架构 https://java.agentscope.io/v2/zh/docs/harness/architecture.html
- Reactor 文档 - Mono.zip https://projectreactor.io/docs/core/release/api/
- 上一篇文章:AgentScope搭企业级Agent平台实战 AgentScope搭企业级Agent平台实战