
源码地址:https://github.com/jd-opensource/joyagent-jdgenie
整个 Agent 系统基于经典的 ReAct 模式,这是一种将"推理"和"行动"解耦的设计范式。
思考 (Think) → 行动 (Act) → 观察 (Observe) → 思考 (Think) → ...
**核心抽象类:[ReActAgent.java](file:///Volumes/Data+1/JavaProject/joyagent-jdgenie/genie-backend/src/main/java/com/jd/genie/agent/agent/ReActAgent.java)**
```java
public abstract class ReActAgent extends BaseAgent {
public abstract boolean think(); // 推理阶段
public abstract String act(); // 行动阶段
@Override
public String step() {
boolean shouldAct = think(); // 先思考
if (!shouldAct) {
return "Thinking complete - no action needed";
}
return act(); // 再行动
}
}
职责:将复杂任务拆解为有序的子任务列表
继承关系:PlanningAgent extends ReActAgent
核心流程:
public PlanningAgent(AgentContext context) {
// 1. 设置角色名称和描述
setName("planning");
// 2. 从配置文件加载 System Prompt
setSystemPrompt(genieConfig.getPlannerSystemPromptMap()
.replace("{{tools}}", toolPrompt) // 注入可用工具列表
.replace("{{query}}", context.getQuery()) // 注入用户问题
.replace("{{date}}", context.getDateInfo())); // 注入当前日期
// 3. 初始化 LLM 实例
setLlm(new LLM(genieConfig.getPlannerModelName(), ""));
// 4. 注册 PlanningTool (唯一可用工具)
availableTools.addTool(planningTool);
}
@Override
public boolean think() {
// 构建消息上下文
Message userMsg = Message.userMessage(getNextStepPrompt(), null);
getMemory().addMessage(userMsg);
// 调用 LLM 的 Function Calling 能力
CompletableFuture<LLM.ToolCallResponse> future = getLlm().askTool(
context,
getMemory().getMessages(),
Message.systemMessage(getSystemPrompt(), null),
availableTools, // 传入 PlanningTool
ToolChoice.AUTO,
null,
context.getIsStream(), // 支持流式输出
300
);
// 获取 LLM 返回的工具调用列表
LLM.ToolCallResponse response = future.get();
setToolCalls(response.getToolCalls());
return true;
}
@Override
public String act() {
List<String> results = new ArrayList<>();
for (ToolCall toolCall : toolCalls) {
// 执行工具 (PlanningTool.execute)
String result = executeTool(toolCall);
results.add(result);
// 添加工具响应到 Memory (用于下一轮对话)
Message toolMsg = Message.toolMessage(result, toolCall.getId(), null);
getMemory().addMessage(toolMsg);
}
// 检查计划是否生成完毕
if (Objects.nonNull(planningTool.getPlan())) {
return getNextTask(); // 返回下一个待执行的子任务
}
return String.join("\n\n", results);
}
// PlanningTool.execute() 的核心功能
{
"command": "create", // 创建新计划
"steps": [
"执行顺序1. 搜索资料:使用搜索工具查找京东财报",
"执行顺序2. 数据分析:使用代码工具分析财务数据",
"执行顺序3. 生成报告:使用报告工具输出 HTML"
]
}
职责:领取 单个子任务,通过多轮 Function Calling 完成任务
继承关系:ExecutorAgent extends ReActAgent
核心流程:
public ExecutorAgent(AgentContext context) {
setName("executor");
// 注入所有可用工具 (不仅仅是 PlanningTool)
availableTools = context.getToolCollection();
// 包含: FileTool, CodeInterpreterTool, ReportTool, DeepSearchTool 等
// 使用独立的 Executor LLM (可能和 Planner 不同)
setLlm(new LLM(genieConfig.getExecutorModelName(), ""));
}
@Override
public boolean think() {
// 构建带有"当前子任务"上下文的 Prompt
Message userMsg = Message.userMessage(getNextStepPrompt(), null);
getMemory().addMessage(userMsg);
// 调用 LLM,让它自主选择需要调用哪些工具
CompletableFuture<LLM.ToolCallResponse> future = getLlm().askTool(
context,
getMemory().getMessages(),
Message.systemMessage(getSystemPrompt(), null),
availableTools, // 传入所有工具
ToolChoice.AUTO,
null,
false, // Executor 不支持流式输出
300
);
LLM.ToolCallResponse response = future.get();
setToolCalls(response.getToolCalls());
// 如果 LLM 认为任务已完成 (不调用工具)
if (toolCalls.isEmpty()) {
setState(AgentState.FINISHED);
}
return true;
}
@Override
public String act() {
if (toolCalls.isEmpty()) {
// 任务完成,返回最后的总结
return getMemory().getLastMessage().getContent();
}
// 并发执行多个工具调用
Map<String, String> toolResults = executeTools(toolCalls);
for (ToolCall command : toolCalls) {
String result = toolResults.get(command.getId());
// 截断过长的结果 (防止 Memory 爆炸)
if (maxObserve != null) {
result = result.substring(0, Math.min(result.length(), maxObserve));
}
// 添加工具结果到 Memory
Message toolMsg = Message.toolMessage(result, command.getId(), null);
getMemory().addMessage(toolMsg);
}
return String.join("\n\n", results);
}
职责:直接处理用户问题,不经过 Planner,适用于简单问题
继承关系:ReactImplAgent extends ReActAgent
与 ExecutorAgent 的区别:
| 维度 | ExecutorAgent | ReactImplAgent |
|---|---|---|
| 输入 | 由 Planner 拆解的子任务 | 用户原始问题 |
| 流式输出 | ❌ 不支持 | ✅ 支持 |
| 使用场景 | Plan-Solve 模式的一部分 | 独立使用 |
| System Prompt | Executor Prompt | React Prompt |
核心代码:
@Override
public boolean think() {
// 直接使用用户原始问题
context.setStreamMessageType("tool_thought");
CompletableFuture<LLM.ToolCallResponse> future = getLlm().askTool(
context,
getMemory().getMessages(),
Message.systemMessage(getSystemPrompt(), null),
availableTools,
ToolChoice.AUTO,
null,
context.getIsStream(), // 支持流式输出
300
);
// ... 其余逻辑与 ExecutorAgent 类似
}
用户请求
↓
GenieController.AutoAgent()
↓
AgentHandlerFactory
├─→ PlanSolveHandlerImpl (Plan-Solve 模式)
│ ├─→ PlanningAgent.run()
│ └─→ ExecutorAgent.run() × N
│
└─→ ReactHandlerImpl (ReAct 模式)
└─→ ReactImplAgent.run()
orchestrator:PlanSolveHandlerImpl.java
@Override
public String handle(AgentContext agentContext, AgentRequest request) {
// ① 初始化 Agent
PlanningAgent planning = new PlanningAgent(agentContext);
ExecutorAgent executor = new ExecutorAgent(agentContext);
SummaryAgent summary = new SummaryAgent(agentContext);
// ② Planner 生成初始计划
String planningResult = planning.run(agentContext.getQuery());
// ③ 反复执行 Plan → Execute → Replan 循环
int stepIdx = 0;
while (stepIdx <= maxStepNum) {
// 拆分出多个子任务
List<String> planningResults = Arrays.stream(planningResult.split("<sep>"))
.map(task -> "你的任务是:" + task)
.collect(Collectors.toList());
// 执行子任务 (支持并发)
String executorResult;
if (planningResults.size() == 1) {
// 单任务直接执行
executorResult = executor.run(planningResults.get(0));
} else {
// 多任务并发执行
Map<String, String> tmpTaskResult = new ConcurrentHashMap<>();
CountDownLatch taskCount = ThreadUtil.getCountDownLatch(planningResults.size());
for (String task : planningResults) {
// 为每个子任务创建独立的 ExecutorAgent
ExecutorAgent slaveExecutor = new ExecutorAgent(agentContext);
slaveExecutor.getMemory().addMessages(executor.getMemory().getMessages());
ThreadUtil.execute(() -> {
String taskResult = slaveExecutor.run(task);
tmpTaskResult.put(task, taskResult);
taskCount.countDown();
});
}
ThreadUtil.await(taskCount);
executorResult = String.join("\n", tmpTaskResult.values());
}
// ④ Planner 根据执行结果调整计划
planningResult = planning.run(executorResult);
// ⑤ 检查是否完成
if ("finish".equals(planningResult)) {
// 使用 SummaryAgent 总结任务
TaskSummaryResult result = summary.summaryTaskResult(
executor.getMemory().getMessages(),
request.getQuery()
);
agentContext.getPrinter().send("result", result);
break;
}
stepIdx++;
}
return "";
}
orchestrator:ReactHandlerImpl.java
@Override
public String handle(AgentContext agentContext, AgentRequest request) {
// ① 直接使用 ReactImplAgent (无 Planner)
ReActAgent executor = new ReactImplAgent(agentContext);
SummaryAgent summary = new SummaryAgent(agentContext);
// ② 执行用户问题
executor.run(request.getQuery());
// ③ 总结并返回结果
TaskSummaryResult result = summary.summaryTaskResult(
executor.getMemory().getMessages(),
request.getQuery()
);
agentContext.getPrinter().send("result", result);
return "";
}
每个 Agent 都有独立的 Memory 对象,用于存储对话历史:
public class Memory {
private List<Message> messages = new ArrayList<>();
public void addMessage(Message message) {
messages.add(message);
}
public List<Message> getMessages() {
return messages;
}
}
Message 类型:
USER: 用户输入 / PromptASSISTANT: LLM 的推理输出TOOL: 工具执行结果SYSTEM: System Prompt调用流程:
// 1. 构建工具列表
ToolCollection availableTools = new ToolCollection();
availableTools.addTool(new FileTool());
availableTools.addTool(new CodeInterpreterTool());
// 2. 调用 LLM
LLM.ToolCallResponse response = llm.askTool(
context,
memory.getMessages(),
systemMessage,
availableTools, // 工具列表
ToolChoice.AUTO, // 让 LLM 自主决定是否调用工具
null,
isStream,
300
);
// 3. 执行工具
for (ToolCall toolCall : response.getToolCalls()) {
String result = availableTools.execute(
toolCall.getFunction().getName(),
toolCall.getFunction().getArguments()
);
}
通过 SSEPrinter 实现实时推送 Agent 思考过程:
public class SSEPrinter implements Printer {
private SseEmitter emitter;
@Override
public void send(String type, Object data) {
try {
AgentResponse response = AgentResponse.builder()
.type(type) // "plan_thought", "tool_thought", "tool_result" 等
.data(data)
.build();
emitter.send(SseEmitter.event()
.data(JSON.toJSONString(response))
.name("message"));
} catch (IOException e) {
log.error("SSE send error", e);
}
}
}
前端接收示例:
const eventSource = new EventSource('/AutoAgent');
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
switch(data.type) {
case 'plan_thought':
console.log('[Planner 思考]', data.data);
break;
case 'tool_thought':
console.log('[Executor 思考]', data.data);
break;
case 'tool_result':
console.log('[工具执行结果]', data.data);
break;
}
});
通过 AgentHandlerFactory + 策略模式,可以轻松添加新的编排模式:
@Component
public class AgentHandlerFactory {
public AgentHandlerService getHandler(AgentContext context, AgentRequest request) {
for (AgentHandlerService handler : handlers) {
if (handler.support(context, request)) {
return handler;
}
}
throw new IllegalArgumentException("No handler found");
}
}
通过 SSE 实时推送:
plan_thought: Planner 的推理过程tool_thought: Executor 的推理过程tool_result: 工具执行结果task_summary: 任务总结所有 Agent 行为通过 application.yml 中的 Prompt 配置,无需修改代码即可调整 Agent 策略。
| 组件 | 文件路径 |
|---|---|
| Planner 实现 | PlanningAgent.java |
| Executor 实现 | ExecutorAgent.java |
| ReAct 实现 | ReactImplAgent.java |
| ReAct 抽象类 | ReActAgent.java |
| Base Agent | BaseAgent.java |
| Plan-Solve 编排 | PlanSolveHandlerImpl.java |
| ReAct 编排 | ReactHandlerImpl.java |
| Controller | GenieController.java |