只会聊天的 LLM 很快会碰到天花板:它不知道实时库存,不能查订单,也不能调用内部接口。ReActAgent 的价值在于把“推理”和“行动”放进同一个循环里:模型先判断下一步要做什么,再调用工具,拿到结果后继续修正判断,直到给出可用答案。
这类 Agent 不适合拿来包装所有需求,但很适合处理“需要多步判断 + 外部数据 + 动态反馈”的任务,比如客服查单、运营分析、内部知识检索、告警诊断。
ReActAgent 不只是多挂几个函数
传统 LLM 调用工具时,经常像一次性问答:用户问问题,模型决定调一个函数,然后直接回答。ReAct 的关键差异是循环:
- Thought:模型分析当前目标和已知信息。
- Action:选择一个外部工具,例如查数据库、调 HTTP API、检索文档。
- Observation:工具返回真实结果。
- Repeat:模型根据结果继续推理,必要时再次行动。
- Final Answer:输出最终答案或执行建议。
这让 Agent 能处理不确定性。例如用户问“这个客户最近投诉多吗,要不要升级处理?”模型可能先查客户信息,再查近 30 天工单,再根据投诉频率和订单金额给出判断。它不是凭空生成一个听起来合理的答案,而是围绕真实反馈调整行为。
生产级 Agent 的边界:工具比提示词更重要
ReActAgent 的上限通常不在提示词,而在工具设计。工具要小、稳定、可审计。一个“万能查询数据库”工具听起来方便,但在生产环境里风险很大:权限难控、SQL 注入难防、结果不可预测。
更稳的做法是把工具设计成业务动作:
getCustomerProfile(customerId):查客户等级、账号状态。listRecentTickets(customerId, days):查近期工单。createEscalation(ticketId, reason):创建升级记录。searchKnowledgeBase(query):检索内部知识库。
每个工具都应该有清晰输入、有限输出、超时设置和日志。Agent 可以聪明,但工具必须像普通后端接口一样可测试。
可以这样实践:一个客服升级判断 Agent
下面示例按“Solon AI 4.0 ReActAgent + Java 工具函数”的典型方式演示。不同版本的包名、Builder API 可能略有差异,接入时请以你项目中的 Solon AI 4.0 依赖为准;核心结构可以直接改造:定义工具、注册给 Agent、让 Agent 在推理循环中调用。
假设你有一个客服系统,希望 Agent 根据客户资料和近期工单判断是否需要升级处理。
// CustomerSupportAgent.java
// 示例为可改造骨架:请把 ReActAgent、ToolRegistry、ChatModel 的包名替换为你项目中 Solon AI 4.0 的实际类。
import java.util.List;
import java.util.Map;
public class CustomerSupportAgent {
public static void main(String[] args) {
ChatModel model = ChatModel.builder()
.apiKey(System.getenv("LLM_API_KEY"))
.model("gpt-4o-mini")
.build();
ToolRegistry tools = ToolRegistry.builder()
.add("getCustomerProfile", CustomerSupportAgent::getCustomerProfile)
.add("listRecentTickets", CustomerSupportAgent::listRecentTickets)
.add("createEscalation", CustomerSupportAgent::createEscalation)
.build();
ReActAgent agent = ReActAgent.builder()
.model(model)
.tools(tools)
.systemPrompt("你是客服升级判断助手。必须先查询客户资料和近期工单,再判断是否升级。不要编造数据。")
.maxSteps(6)
.build();
String answer = agent.run("客户 C10086 说最近问题一直没人解决,需要主管介入。请判断是否升级,并说明原因。");
System.out.println(answer);
}
static Map<String, Object> getCustomerProfile(Map<String, Object> input) {
String customerId = String.valueOf(input.get("customerId"));
// 生产环境应调用 CRM 或数据库,这里用固定数据演示。
return Map.of(
"customerId", customerId,
"level", "enterprise",
"monthlySpend", 128000,
"status", "active"
);
}
static List<Map<String, Object>> listRecentTickets(Map<String, Object> input) {
return List.of(
Map.of("ticketId", "T-901", "daysAgo", 3, "category", "payment", "status", "open"),
Map.of("ticketId", "T-877", "daysAgo", 9, "category", "api_error", "status", "resolved"),
Map.of("ticketId", "T-832", "daysAgo", 18, "category", "api_error", "status", "resolved")
);
}
static Map<String, Object> createEscalation(Map<String, Object> input) {
return Map.of(
"escalationId", "E-20240501-001",
"status", "created",
"reason", input.getOrDefault("reason", "manual review required")
);
}
}
运行前要改三处:
- 把
ChatModel、ToolRegistry、ReActAgent替换为你项目里 Solon AI 4.0 的实际类名和 import。 - 设置模型密钥:
export LLM_API_KEY=你的密钥。 - 把示例里的固定数据替换成真实 CRM、工单系统或内部 HTTP API。
如果工具是 HTTP 服务,也可以先用一个稳定的本地 API 模拟:
curl -X POST http://localhost:8080/tools/customer-profile \
-H 'Content-Type: application/json' \
-d '{"customerId":"C10086"}'
返回建议保持短而结构化,方便 Agent 消化:
{
"customerId": "C10086",
"level": "enterprise",
"monthlySpend": 128000,
"status": "active"
}
Prompt 要约束决策过程,而不是替业务背锅
ReActAgent 的系统提示词应该明确“什么时候必须查工具”“哪些事不能做”“最终答案格式是什么”。例如:
你是客服升级判断助手。
规则:
1. 判断升级前必须调用 getCustomerProfile 和 listRecentTickets。
2. 没有工具返回的数据时,不得猜测客户等级、消费金额、工单数量。
3. 只有 enterprise 客户且 30 天内存在未关闭高优先级问题时,才允许调用 createEscalation。
4. 最终回答包含:结论、依据、已执行动作、需要人工确认的风险。
这个提示词不会让模型“更聪明”,但会让它更守规矩。生产系统里还应在工具层二次校验,比如 createEscalation 必须检查调用者权限、客户状态和幂等键,不能只相信模型的判断。
上线前的检查清单
ReActAgent 适合把 LLM 接入业务闭环,但它也会放大系统复杂度。上线前至少检查这些点:
- 工具是否有超时、重试、限流和审计日志。
- Agent 是否设置
maxSteps,避免无限推理和成本失控。 - 高风险动作是否有人审或后端强校验,例如退款、删数据、发通知。
- 工具返回是否结构化,避免把大段日志直接塞回模型。
- 是否记录完整轨迹:用户问题、模型动作、工具输入输出、最终答案。
可以从“只读工具”开始,比如查询订单、检索知识库、汇总工单。等轨迹稳定、误调用率可接受,再逐步开放写操作。ReActAgent 真正有价值的地方不是让模型显得像人在思考,而是让每一步行动都能落在可观察、可回滚、可治理的工程边界里。