Agent 引擎
Agent 是 MateClaw 的核心推理组件。它接收用户输入,决定是直接回答、调用工具还是将任务拆解为多步执行计划。MateClaw 基于 spring-ai-alibaba-graph-core 的 StateGraph 引擎实现了两种 Agent 模式:ReAct 和 Plan-and-Execute。
架构总览
AgentGraphBuilder
|
|-- buildReActAgent() --> StateGraphReActAgent (CompiledGraph)
|-- buildPlanExecuteAgent() --> StateGraphPlanExecuteAgent (CompiledGraph)
|
+-- buildRuntimeChatModel() --> ChatModel (DashScope / OpenAI-compatible / Anthropic)所有 Agent 的构建由 AgentGraphBuilder 统一负责。它根据 AgentEntity 中的配置(类型、迭代上限等),选择模型、注册工具、编译状态图,最终返回一个可用的 BaseAgent 实例。运行时统一使用全局默认模型,不依赖 Agent 实体上的 modelName 字段。
核心抽象
BaseAgent
所有 Agent 继承自 BaseAgent,它定义了统一的对话接口和状态管理:
| 方法 | 说明 |
|---|---|
chat(userMessage, conversationId) | 同步对话,返回完整文本 |
chatStream(userMessage, conversationId) | 流式对话,返回 Flux<String> |
execute(goal, conversationId) | 执行任务(Plan-Execute 模式入口,ReAct 下退化为 chat) |
chatWithReplay(userMessage, conversationId, toolCallPayload) | 审批通过后重放工具调用 |
chatWithReplayStream(...) | 审批通过后的流式重放 |
BaseAgent 还负责加载会话历史(buildConversationHistory)、过滤审批占位消息、转换消息格式等基础工作。
AgentState
Agent 在生命周期中经历以下状态:
| 状态 | 说明 |
|---|---|
IDLE | 空闲,等待新消息 |
PLANNING | 规划中,正在生成执行计划 |
EXECUTING | 执行中,正在执行工具调用或子任务 |
RUNNING | 运行中(ReAct 循环或 Plan-Execute 图执行期间) |
WAITING_USER_INPUT | 等待用户输入 |
DONE | 已完成 |
FAILED | 执行失败 |
ERROR | 错误状态(流式调用异常等) |
FinishReason
状态图终止时会标记终止原因,供前端和日志区分:
| 值 | 说明 |
|---|---|
NORMAL | LLM 直接给出最终回答 |
SUMMARIZED | 经过 SummarizingNode 压缩后完成 |
MAX_ITERATIONS_REACHED | 达到最大迭代次数后强制收束 |
ERROR_FALLBACK | 发生错误后降级回答 |
ReAct Agent
StateGraphReActAgent 是默认的 Agent 类型,基于 StateGraph v2 实现显式可控的 Thought-Action-Observation 循环。
状态图拓扑
START
|
v
ReasoningNode -----(ReasoningDispatcher)----> 4 路分支
| | | |
v v v v
ActionNode SummarizingNode LimitExceededNode FinalAnswerNode
| | | |
v | v v
ObservationNode | FinalAnswerNode END
| | |
| (ObservationDispatcher) v
| | | | END
v v v v
回到 Summ- Limit- Final-
Reason arizing Exceeded Answer完整路由规则:
ReasoningNode --> ReasoningDispatcher:
1. 迭代超限 --> LimitExceededNode(最高优先级)
2. 需要工具调用 --> ActionNode
3. 需要总结压缩 --> SummarizingNode
4. 可直接回答 --> FinalAnswerNode
ActionNode --> ObservationNode(固定边)
ObservationNode --> ObservationDispatcher:
0. 审批等待 --> FinalAnswerNode(Graph 终止,由 Replay 继续)
1. 迭代超限 --> LimitExceededNode(强制终止)
2. 有错误 --> LimitExceededNode
3. 需要总结 --> SummarizingNode
4. 继续循环 --> ReasoningNode
SummarizingNode --> ReasoningNode(固定边,压缩后重新推理)
LimitExceededNode --> FinalAnswerNode(固定边)
FinalAnswerNode --> END节点详解
ReasoningNode(推理节点)
调用 LLM 进行单次推理,判断是否需要工具调用。关键设计:通过 internalToolExecutionEnabled=false 禁用 ChatModel 内部的工具循环,让 StateGraph 完全控制 ReAct 迭代。
功能:
- 构建包含系统提示词、会话历史、观察历史的 Prompt
- 调用 LLM 获取响应,提取 ToolCall 列表
- 支持
forced_tool_call机制:审批通过后跳过 LLM 调用,直接发出预批准的工具调用 - 通过
NodeStreamingChatHelper实时推送 content/thinking 增量 - 检查停止标志(
ChatStreamTracker.isStopRequested)
ActionNode(工具执行节点)
委托 ToolExecutionExecutor 执行工具调用。
功能:
- 支持并发工具执行和审批 barrier
- 两阶段执行:先顺序检查 ToolGuard,再分段并发执行
forced_replay模式下跳过 ToolGuard 检查- 审批等待时设置
AWAITING_APPROVAL=true,Graph 将在下一个 Dispatcher 终止 - 检查停止标志
ObservationNode(观察节点)
处理工具执行结果,是迭代控制的核心节点之一。
功能:
- 通过
ObservationProcessor对工具结果进行标准化和截断 - 递增迭代计数器
- 判断是否需要进入 summarizing 阶段(上下文过长时)
SummarizingNode(总结压缩节点)
当满足以下条件时被路由至此:
- observationHistory 条目过多
- 单次工具结果超过阈值
- 多轮观察结果过于冗长
调用 LLM 对已有观察结果进行压缩总结,压缩后回到 ReasoningNode 继续推理。
LimitExceededNode(超限处理节点)
当迭代达到 maxIterations 时被路由至此。不会抛异常,而是:
- 对过长的 observationHistory 做内联压缩
- 注入"停止工具调用"系统指令
- 让 LLM 基于已有信息生成简洁最终回答
- 标记
finishReason = MAX_ITERATIONS_REACHED
FinalAnswerNode(最终回答节点)
汇聚所有终止路径,设置 finalAnswer、finalThinking 和 finishReason。优先级:
finalAnswerDraft(来自 LimitExceeded/Summarizing 路径)finalAnswer(来自 Reasoning 直接回答路径)
审批等待路径下返回空 finalAnswer,内容已通过 streaming 推送。
交互示例
用户发送:"帮我查一下北京今天的天气"
[ReasoningNode] LLM 分析意图 --> 需要工具调用 (WebSearchTool)
[ActionNode] 执行 WebSearchTool("北京今天天气") --> ToolGuard 检查通过
[ObservationNode] 结果:北京今天晴,15-26C --> 迭代 1/10,继续
[ReasoningNode] LLM 判断信息充分 --> 直接回答
[FinalAnswerNode] 汇聚回答:"北京今天天气晴朗,气温 15-26 C..."Plan-and-Execute Agent
StateGraphPlanExecuteAgent 适用于需要多步骤才能完成的复杂任务。它先评估是否需要规划,简单问题直接回答,复杂任务则生成计划并逐步执行。
状态图拓扑
START
|
v
PlanGenerationNode ---(PlanGenerationDispatcher)--> 2 路分支
| |
v v
StepExecutionNode DirectAnswerNode
| |
| (StepProgressDispatcher) v
| | | | END
v v v v
继续 PlanSummaryNode END
执行 | (审批终止)
下一步 v
END节点详解
PlanGenerationNode(计划生成节点)
职责:
- 判断是否需要规划(简单问答快速退出到 DirectAnswerNode)
- 需要规划时生成计划 JSON(步骤数 2-6 个)
- 调
PlanningService.createPlan()持久化到mate_plan和mate_sub_plan表 - 发布
plan_created事件
StepExecutionNode(步骤执行节点)
执行当前步骤,内置显式工具执行循环(internalToolExecutionEnabled=false)。
- 单步最大工具调用次数限制为 5 次
- 支持审批流程:需要审批的工具调用创建 pending,发出 SSE 事件后非阻塞返回
- 审批通过后通过 replay 机制重新执行
PlanSummaryNode(计划汇总节点)
汇总所有步骤的执行结果,调 LLM 生成最终总结,调 planningService.completePlan() 标记计划完成。
DirectAnswerNode(直接回答节点)
当 PlanGenerationNode 判定不需要规划时,将 direct_answer 透传为 final_summary,直接结束图执行。
数据模型
计划持久化到两张表:
mate_plan
| 字段 | 说明 |
|---|---|
id | 计划 ID |
conversation_id | 关联会话 |
goal | 用户原始请求 |
status | pending / running / completed / failed |
mate_sub_plan
| 字段 | 说明 |
|---|---|
id | 子步骤 ID |
plan_id | 父计划 |
step_order | 执行顺序(1, 2, 3...) |
description | 步骤描述 |
status | pending / running / completed / failed |
result | 步骤执行结果 |
交互示例
用户发送:"帮我调研 Spring AI 框架,对比各主要实现,并写一份简要报告"
[PlanGenerationNode] 判断需要规划 --> 生成 4 步计划
步骤 1: 搜索 Spring AI 框架的主要实现和特性
步骤 2: 搜索各实现的优缺点和社区活跃度
步骤 3: 对比分析,形成结构化表格
步骤 4: 撰写简要调研报告
[StepExecutionNode] 执行步骤 1
LLM --> WebSearchTool("Spring AI framework implementations") --> 结果
标记步骤 1 完成
[StepExecutionNode] 执行步骤 2 (携带步骤 1 的上下文)
...
[StepExecutionNode] 执行步骤 3
...
[StepExecutionNode] 执行步骤 4
...
[PlanSummaryNode] 汇总所有步骤结果,生成最终调研报告DynamicAgent
DynamicAgent 从数据库(mate_agent 表)动态加载配置,支持在运行时通过 UI 或 API 创建和修改 Agent,无需重启应用。
AgentGraphBuilder.build(AgentEntity) 每次构建时读取最新的 AgentEntity,组装系统提示词、工具集和状态图。
数据库字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | String | Agent 名称 |
description | String | Agent 描述 |
agent_type | String | react 或 plan_execute |
system_prompt | Text | 系统提示词 |
max_iterations | Integer | 最大迭代次数(默认 10) |
enabled | Boolean | 是否启用 |
icon | String | 图标(emoji 或 URL) |
tags | String | 标签(逗号分隔) |
注意:model_name 字段为历史残留,运行时统一使用全局默认模型(通过"设置 - 模型"页面配置)。
Agent 选型指南
何时使用 ReAct
- 简单问答:一轮推理即可回答,无需工具
- 信息检索:搜索 + 总结,通常 2-3 次循环
- 单一工具操作:读文件、查时间等明确操作
- 实时对话:需要快速响应的场景
何时使用 Plan-and-Execute
- 多步骤任务:需要按顺序完成多个操作
- 调研报告:涉及多次搜索、对比和汇总
- 复杂分析:需要先收集信息再综合判断
- 需要可追踪进度的任务(每步结果持久化到数据库)
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| 简单问答 | ReAct | 快速响应,直接回答路径无额外开销 |
| 信息检索 | ReAct | 搜索 + 总结,2-3 次循环 |
| 多步骤任务 | Plan-and-Execute | 计划拆解 + 逐步执行 + 结果汇总 |
| 调研报告 | Plan-and-Execute | 多次搜索、对比、汇总 |
| 文件读写 | ReAct | 操作明确,单次工具调用 |
| 数据对比 | Plan-and-Execute | 分别收集再对比 |
系统提示词编写建议
系统提示词通过 AgentGraphBuilder.buildEnhancedPrompt() 增强,会自动注入技能指令和工作区上下文。编写自定义提示词时注意:
- 明确角色和职责:告诉 Agent 它是谁、能做什么
- 说明可用工具:列出工具名称和使用场景(工具描述会自动注入,但额外说明有助于引导 LLM)
- 设定输出格式:如需结构化输出,在提示词中明确说明
- 避免冲突指令:不要与 MateClaw 的内置行为(如工具调用格式)产生矛盾
示例:
你是一名专业的技术文档助手。你的职责是:
1. 根据用户需求搜索和整理技术资料
2. 使用清晰的结构化格式回答问题
3. 提供代码示例时确保语法正确
4. 如果不确定,先搜索再回答,不要凭空编造
注意事项:
- 优先使用中文回答
- 引用信息时标注来源
- 对于时效性强的问题,先获取当前日期再搜索配置参考
Agent 级配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
maxIterations | 10 | ReAct 最大循环次数,Plan-Execute 中单步最大工具调用为 5 次 |
agentType | react | Agent 类型:react 或 plan_execute |
enabled | true | 是否启用 |
图级配置
| 配置项 | 说明 |
|---|---|
recursionLimit | StateGraph 编译时设置,ReAct 为 maxIterations * 2 + 5,Plan-Execute 为 maxIterations * 3 + 10 |
| ObservationProcessor | 控制工具结果截断阈值和观察历史压缩策略 |
流式事件
Agent 在结构化流式模式(chatStructuredStream)下会通过 SSE 推送以下事件类型:
| 事件类型 | 说明 |
|---|---|
phase | 当前执行阶段(reasoning / action / observation / summarizing 等) |
tool_call_start | 工具调用开始 |
tool_call_end | 工具调用结束(含结果摘要) |
plan_created | 计划已创建(Plan-Execute 模式) |
step_start / step_end | 步骤开始/结束(Plan-Execute 模式) |
approval_required | 工具调用需要审批 |
_usage_final | Token 使用量统计(流结束时) |
通过 API 管理 Agent
创建 Agent
curl -X POST http://localhost:18088/api/v1/agents \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "技术助手",
"description": "专业的技术文档助手",
"agentType": "react",
"systemPrompt": "你是一名专业的技术文档助手...",
"maxIterations": 10
}'查询 Agent 列表
curl http://localhost:18088/api/v1/agents \
-H "Authorization: Bearer <token>"获取 Agent 详情
curl http://localhost:18088/api/v1/agents/1 \
-H "Authorization: Bearer <token>"更新 Agent
curl -X PUT http://localhost:18088/api/v1/agents/1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "技术助手 v2",
"systemPrompt": "更新后的提示词...",
"maxIterations": 15
}'删除 Agent
curl -X DELETE http://localhost:18088/api/v1/agents/1 \
-H "Authorization: Bearer <token>"流式对话
curl -N "http://localhost:18088/api/v1/agents/1/chat/stream?message=你好&conversationId=default" \
-H "Authorization: Bearer <token>"调试指南
开启 DEBUG 日志
在 application.yml 中添加:
logging:
level:
vip.mate.agent: DEBUG
vip.mate.agent.graph: DEBUG这将输出每个节点的执行详情,包括:
- Agent 状态变迁(
IDLE -> RUNNING -> IDLE) - ReasoningDispatcher / ObservationDispatcher 的路由决策
- 迭代计数(
Iteration 1/10) - 工具调用和结果摘要
- ToolGuard 检查结果
常见问题排查
Agent 无响应或超时
- 检查模型配置是否正确("设置 - 模型"页面)
- 查看日志中是否有
StateGraph chat failed或ERROR状态 - 确认 API Key 有效且有额度
Agent 陷入循环
- 查看日志中的迭代计数,确认
maxIterations是否合理 - 检查是否有工具持续返回错误导致 LLM 反复重试
- 如果经常触发
MAX_ITERATIONS_REACHED,考虑增大maxIterations或优化提示词
工具调用不生效
- 确认工具已在 ToolRegistry 中注册
- 检查 ToolGuard 是否拦截了调用
- 查看 ActionNode 的日志输出
审批流程中断
- 审批等待时 Graph 会正常终止(
AWAITING_APPROVAL=true) - 用户决策后通过
chatWithReplay/chatWithReplayStream继续执行 - 如果 replay 失败,检查
toolCallPayload格式是否正确
