agent as tools模式
1、主agent注册子agent方式 子agent是实例的
@OverRide
protected Toolkit createToolkit() {
Toolkit tk = new Toolkit();
// 注册所有子 Agent 到 Toolkit(排除自己,避免循环)
// 使用 Supplier 每次创建新实例,避免并发状态问题
for (Agent subAgent : subAgents) {
// 跳过大脑 Agent 自己,只注册真正的子 Agent
if (subAgent == this || StringUtil.equals(subAgent.getName(), getName())) {
log.info("Skipping self-registration for CoordinatorAgent");
continue;
}
String agentName = subAgent.getName();
String agentDesc = subAgent.getDescription();
// 为每个子 Agent 创建 Supplier,每次调用时创建新实例
SubAgentProvider<ReActAgent> agentSupplier = createAgentSupplier(agentName);
tk.registration()
.subAgent(agentSupplier, SubAgentConfig.builder()
.toolName(agentName)
.description(agentDesc)
.forwardEvents(false)
.build())
.apply();
log.info("Registered sub-agent: {} (with new instance per call)", agentName);
}
return tk;
}
/**
* 创建 Agent Supplier,每次调用时创建新的 Agent 实例
* 参考 BrainAgent 的实现方式,避免并发状态问题
*/
private SubAgentProvider<ReActAgent> createAgentSupplier(String agentName) {
return () -> {
// 根据 Agent 名称创建对应的新实例
AgentBase newAgent = switch (agentName) {
case "ChitChat" -> new ChitChatAgent(chitchatModel);
default -> throw new IllegalArgumentException("Unknown agent: " + agentName);
};
// 初始化并返回 ReActAgent
return newAgent.getAgent();
};
}
2、子agent实例注册工具和skill
/**
* 确保初始化(延迟初始化模式)
* 支持:1. Spring 注入后初始化 2. AgentScope 框架创建新实例时初始化
*/
protected void ensureInitialized() {
if (!initialized) {
synchronized (this) {
if (!initialized) {
this.toolkit = createToolkit();
this.skillBox = createSkillBox(toolkit);
this.hooks = getHooks();
this.agent = buildAgent();
initialized = true;
log.info("Agent [{}] initialized with skillBox: {}", getName(),
skillBox != null ? skillBox.getAllSkillIds() : "none");
}
}
}
}
3、子agentskill:
/**
* 创建并配置 SkillBox,流程:
* 1. 从 classpath 批量加载 skill
* 2. 逐个委托子类绑定 tools
* 3. 注册 skill-load tool
*
* @param toolkit 共享的 Toolkit 实例
* @return 配置好的 SkillBox
*/
public SkillBox createSkillBox(Toolkit toolkit) {
SkillBox skillBox = new SkillBox(toolkit);
this.toolkit = toolkit; // 保存引用
log.info("[{}] Starting to load skills from path: {}", configName(), getSkillsResourcePath());
try {
// 使用 PathMatchingResourcePatternResolver 加载所有 .md 文件
List<AgentSkill> skills = loadSkillsFromClasspath();
log.info("[{}] Found {} skills in classpath", configName(), skills.size());
for (AgentSkill skill : skills) {
log.info("[{}] Loaded skill: {} - {}", configName(), skill.getName(), skill.getDescription());
bindTools(skillBox, skill);
}
if (skills.isEmpty()) {
log.warn("[{}] No skills found, using fallback registration", configName());
fallbackRegister(skillBox);
}
} catch (Exception e) {
log.error("[{}] Failed to load skills from classpath: {}", configName(), e.getMessage(), e);
fallbackRegister(skillBox);
}
int skillCount = skillBox.getAllSkillIds().size();
log.info("[{}] SkillBox configured with {} skills: {}", configName(), skillCount, skillBox.getAllSkillIds());
if (skillCount == 0) {
log.error("[{}] WARNING: No skills loaded! Check if skill files exist in classpath: {}",
configName(), getSkillsResourcePath());
}
return skillBox;
}
4\skill绑定工具:
protected void register(SkillBox skillBox, AgentSkill skill, Object toolsBean) {
log.info("[{}] Registering skill: {} - {}", configName(), skill.getName(), toolsBean.getClass().getSimpleName());
skillBox.registration()
.skill(skill)
.tool(toolsBean)
.apply();
}
5、主agent调用子agent成功 决策需要调用子agent 但是子agent在进行工具选择时报错
2026-03-11 02:32:52,706 [ - /// - ] ERROR subagent.SubAgentTool - Error in streaming execution: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]
java.lang.IllegalStateException: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]
at io.agentscope.core.ReActAgent.validateAndAddToolResults(ReActAgent.java:335)
at io.agentscope.core.ReActAgent.doCall(ReActAgent.java:256)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2570)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2366)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:193)
at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:63)
at reactor.core.publisher.MonoUsing.subscribe(MonoUsing.java:109)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4641)
at reactor.core.publisher.Mono.subscribe(Mono.java:4542)
at reactor.core.publisher.Mono.subscribe(Mono.java:4478)
at reactor.core.publisher.Mono.subscribe(Mono.java:4450)
at io.agentscope.core.agent.AgentBase.lambda$createEventStream$26(AgentBase.java:707)
at reactor.core.publisher.FluxCreate.subscribe(FluxCreate.java:97)
at reactor.core.publisher.FluxPublishOn.subscribeOrReturn(FluxPublishOn.java:92)
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:55)
at reactor.core.publisher.FluxDeferContextual.subscribe(FluxDeferContextual.java:57)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
2026-03-11 02:32:52,706 [ - /// - ] INFO hook.AgentMonitorHook - [MONITOR] [Coordinator] tool output: [Error: Execution error: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]]
2026-03-11 02:32:52,706 [ - /// - ] INFO hook.AgentMonitorHook - [MONITOR] [Coordinator] tool result: TechnicalSupport -> Error: Execution error: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69...
agent as tools模式
1、主agent注册子agent方式 子agent是实例的
@OverRide
protected Toolkit createToolkit() {
Toolkit tk = new Toolkit();
2、子agent实例注册工具和skill
/**
* 确保初始化(延迟初始化模式)
* 支持:1. Spring 注入后初始化 2. AgentScope 框架创建新实例时初始化
*/
protected void ensureInitialized() {
if (!initialized) {
synchronized (this) {
if (!initialized) {
this.toolkit = createToolkit();
this.skillBox = createSkillBox(toolkit);
this.hooks = getHooks();
this.agent = buildAgent();
initialized = true;
3、子agentskill:
/**
* 创建并配置 SkillBox,流程:
* 1. 从 classpath 批量加载 skill
* 2. 逐个委托子类绑定 tools
* 3. 注册 skill-load tool
*
* @param toolkit 共享的 Toolkit 实例
* @return 配置好的 SkillBox
*/
public SkillBox createSkillBox(Toolkit toolkit) {
SkillBox skillBox = new SkillBox(toolkit);
this.toolkit = toolkit; // 保存引用
4\skill绑定工具:
protected void register(SkillBox skillBox, AgentSkill skill, Object toolsBean) {
log.info("[{}] Registering skill: {} - {}", configName(), skill.getName(), toolsBean.getClass().getSimpleName());
skillBox.registration()
.skill(skill)
.tool(toolsBean)
.apply();
}
5、主agent调用子agent成功 决策需要调用子agent 但是子agent在进行工具选择时报错
2026-03-11 02:32:52,706 [ - /// - ] ERROR subagent.SubAgentTool - Error in streaming execution: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]
java.lang.IllegalStateException: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]
at io.agentscope.core.ReActAgent.validateAndAddToolResults(ReActAgent.java:335)
at io.agentscope.core.ReActAgent.doCall(ReActAgent.java:256)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2570)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2366)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:193)
at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:63)
at reactor.core.publisher.MonoUsing.subscribe(MonoUsing.java:109)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4641)
at reactor.core.publisher.Mono.subscribe(Mono.java:4542)
at reactor.core.publisher.Mono.subscribe(Mono.java:4478)
at reactor.core.publisher.Mono.subscribe(Mono.java:4450)
at io.agentscope.core.agent.AgentBase.lambda$createEventStream$26(AgentBase.java:707)
at reactor.core.publisher.FluxCreate.subscribe(FluxCreate.java:97)
at reactor.core.publisher.FluxPublishOn.subscribeOrReturn(FluxPublishOn.java:92)
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:55)
at reactor.core.publisher.FluxDeferContextual.subscribe(FluxDeferContextual.java:57)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
2026-03-11 02:32:52,706 [ - /// - ] INFO hook.AgentMonitorHook - [MONITOR] [Coordinator] tool output: [Error: Execution error: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]]
2026-03-11 02:32:52,706 [ - /// - ] INFO hook.AgentMonitorHook - [MONITOR] [Coordinator] tool result: TechnicalSupport -> Error: Execution error: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69...