高级java每日一道面试题-2025年8月06日-基础篇[LangChain4j]-如何实现 ReAct Agent?请描述其工作原理。
在 LangChain4j 中实现 ReAct Agent,需要理解其原理并掌握框架提供的工具集成能力。下面从 原理剖析 到 代码实现 进行详细拆解。
一、ReAct Agent 的工作原理
ReAct(Reason + Act)是一种将推理与行动交替结合的 Agent 模式。其核心思想是让大模型在回答问题时,不仅能“思考”,还能通过调用外部工具获取实时信息或执行操作,从而扩展模型的能力边界。
典型工作流程(循环):
- Thought(思考):模型根据当前任务和已观察到的信息,决定下一步需要做什么。
- Action(行动):模型选择一个工具,并指定输入参数。
- Observation(观察):执行工具后,将结果返回给模型。
- 重复以上步骤,直到模型认为任务完成,输出 Final Answer。
示例(文本格式):
Thought: 我需要查询今天的天气,然后才能回答用户。 Action: get_weather Action Input: {"location": "北京"} Observation: 晴天,20℃ Thought: 现在我知道天气了,可以回答用户。 Final Answer: 北京今天晴天,气温20℃。 二、LangChain4j 中的 ReAct 实现机制
LangChain4j 提供了两种实现 ReAct 的方式:
- 基于函数调用(Function Calling):当使用支持函数调用的模型(如 OpenAI GPT-4、Claude 等)时,LangChain4j 会利用模型的原生函数调用能力,由模型直接返回工具调用指令,执行效率高且解析稳定。
- 基于文本提示解析:对于不支持函数调用的模型(如部分开源模型),LangChain4j 会通过精心构造的提示模板,让模型以文本形式输出 Action/Action Input,然后通过正则等方式解析。
框架内部通过 AiServices 和 Tool 注解简化了开发,开发者只需定义工具类,其余由框架自动完成。
三、在 LangChain4j 中实现 ReAct Agent 的步骤
1. 定义工具类
使用 @Tool 注解标记工具方法,框架会自动提取方法名、参数和描述,生成 ToolSpecification。
importdev.langchain4j.agent.tool.Tool;publicclassWeatherTools{@Tool("获取指定城市的实时天气")publicStringgetWeather(@Tool("城市名称")String location){// 实际调用天气 APIreturn"晴天,20℃";}}2. 创建支持 ReAct 的助手接口
定义一个接口,方法代表用户的请求。
publicinterfaceAssistant{Stringchat(String userMessage);}3. 构建 AiServices 并绑定模型和工具
ChatLanguageModel model =OpenAiChatModel.builder().apiKey(System.getenv("OPENAI_API_KEY")).modelName("gpt-4").temperature(0.0).build();Assistant assistant =AiServices.builder(Assistant.class).chatLanguageModel(model).tools(newWeatherTools())// 绑定工具.build();String answer = assistant.chat("北京天气怎么样?");System.out.println(answer);4. 运行与调试
当调用 assistant.chat() 时,LangChain4j 内部会自动执行 ReAct 循环:
- 首次调用模型,传入系统提示(包含工具描述)和用户消息。
- 如果模型返回工具调用请求,框架执行对应工具,并将结果作为新消息附加到对话中,再次调用模型。
- 重复直到模型输出最终答案。
四、高级定制与注意事项
4.1 自定义 ReAct 提示模板
如果模型不支持函数调用,或需要精细控制提示,可以通过 ToolSpecification 和自定义 PromptTemplate 实现:
ToolSpecifications toolSpecifications =ToolSpecifications.toolSpecificationsFrom(WeatherTools.class);String toolInfo =ToolSpecifications.toOpenAiCompatibleJsonSchema(toolSpecifications);String prompt =""" 你是一个助手,可以调用以下工具: {{tools}} 用户问题:{{userMessage}} 请按照以下格式回复: 如果需要调用工具,输出: Action: 工具名称 Action Input: JSON格式的参数 如果已经得到答案,输出: Final Answer: 最终答案 """;然后通过 AiServices 的 chatMemory 和自定义 ToolExecutor 手动控制循环。但这种方式较复杂,一般建议优先使用函数调用。
4.2 错误处理与重试
- 工具执行可能失败(如网络超时),此时应返回错误观察,让模型决定下一步(重试或放弃)。
- 可以在
@Tool方法内捕获异常,返回友好错误信息,或通过ToolExecution配置重试策略。
4.3 多工具与工具选择
框架会根据模型返回的 tool_calls 自动匹配并执行工具。如果有多个同名方法,需要确保工具名称唯一(可通过 @Tool 的 name 属性指定)。
4.4 限制循环次数
为防止模型陷入无限循环,可以设置最大迭代次数(LangChain4j 内部有默认保护,但也可自定义 ToolExecution 或通过 AiServices 的 maxRetries 参数控制)。
五、ReAct 与 Function Calling 的区别
| 特性 | 函数调用(Function Calling) | 基于文本的 ReAct |
|---|---|---|
| 适用模型 | OpenAI、Claude 等支持工具调用的模型 | 所有模型,包括开源模型 |
| 实现方式 | 模型直接返回结构化工具调用 | 模型输出文本,需解析 Action/Action Input |
| 可靠性 | 高,不易解析错误 | 低,可能因格式问题导致解析失败 |
| 性能 | 好,一次调用即可触发工具 | 需要多次调用,且可能产生冗余思考 |
LangChain4j 会根据模型类型自动选择最佳方式。
六、完整示例(带记忆)
如果需要多轮对话保持上下文,可以加入 ChatMemory:
ChatMemory chatMemory =MessageWindowChatMemory.builder().maxMessages(10).build();Assistant assistant =AiServices.builder(Assistant.class).chatLanguageModel(model).chatMemory(chatMemory).tools(newWeatherTools()).build();// 第一次对话 assistant.chat("北京天气?");// 第二次对话,记忆里已有上下文 assistant.chat("那上海呢?");// 模型可能直接调用工具查询上海七、总结
- ReAct 原理:将“思考-行动-观察”循环引入 Agent,使其能够利用外部工具动态解决问题。
- LangChain4j 实现:通过
@Tool注解定义工具,AiServices自动处理调用循环,支持函数调用和文本解析两种模式。 - 优势:简化开发,只需关注工具逻辑,框架负责工具调度、记忆维护和循环控制。
- 适用场景:需要实时数据查询、复杂计算、调用外部 API 的智能应用。
掌握这些内容,面试中就能清晰展示对 LangChain4j 高级特性的理解,以及构建复杂 Agent 的能力。