1
0

react_agent.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import json
  2. from typing import Optional, List
  3. from hello_agents import ReActAgent, HelloAgentsLLM, Config, Message, ToolRegistry
  4. from dotenv import load_dotenv
  5. MY_REACT_PROMPT = """
  6. 请注意,你是一个有能力调用外部工具的智能助手。
  7. 可用工具如下:
  8. {tools}
  9. 请严格按照以下格式进行回应:
  10. 示例1:
  11. {{
  12. "Thought": "我需要先查询今天的美元兑人民币汇率,然后计算出净收益。",
  13. "Action": {{"tool_name": "Search", "tool_input": "今天美元兑人民币汇率"}},
  14. "Finish": []
  15. }}
  16. 示例2:
  17. {{
  18. "Thought": "完成思考,准备给出最终答案。",
  19. "Action": {{}},
  20. "Finish": ["子任务1描述", "子任务2描述", "子任务3描述"]
  21. }}
  22. 格式说明如下:
  23. Thought: 你的思考过程,用于分析问题、拆解任务和规划下一步行动。
  24. Action: 你决定采取的行动,格式必须是:`{{"tool_name": "Search", "tool_input": "今天美元兑人民币汇率"}}`,如果不采取行动,该项必须设置为{{}}。
  25. Finish: 当你收集到足够的信息,能够回答用户的最终问题时,你必须在此处输出最终结果;如果没有,该项必须设置为[]。
  26. 现在,请开始解决以下问题:
  27. Question: {question}
  28. History: {history}
  29. """
  30. # 加载环境变量
  31. load_dotenv()
  32. class NewReActAgent(ReActAgent):
  33. """
  34. 重写的ReAct Agent - 推理与行动结合的智能体
  35. """
  36. def __init__(
  37. self,
  38. name: str,
  39. llm: HelloAgentsLLM,
  40. tool_registry: ToolRegistry,
  41. system_prompt: Optional[str] = None,
  42. config: Optional[Config] = None,
  43. max_steps: int = 5,
  44. custom_prompt: Optional[str] = None
  45. ):
  46. super().__init__(name, llm, system_prompt, config)
  47. self.tool_registry = tool_registry
  48. self.max_steps = max_steps
  49. self.current_history: List[str] = []
  50. self.prompt_template = custom_prompt if custom_prompt else MY_REACT_PROMPT
  51. print(f"✅ {name} 初始化完成,最大步数: {max_steps}")
  52. def run(self, input_text: str, **kwargs) -> str:
  53. """运行ReAct Agent"""
  54. self.current_history = []
  55. current_step = 0
  56. print(f"\n🤖 {self.name} 开始处理问题: {input_text}")
  57. while current_step < self.max_steps:
  58. current_step += 1
  59. print(f"\n--- 第 {current_step} 步 ---")
  60. # 1. 构建提示词
  61. tools_desc = self.tool_registry.get_tools_description()
  62. history_str = "\n".join(self.current_history)
  63. prompt = self.prompt_template.format(
  64. tools=tools_desc,
  65. question=input_text,
  66. history=history_str
  67. )
  68. # 2. 调用LLM
  69. messages = [{"role": "user", "content": prompt}]
  70. response_text = self.llm.invoke(messages, **kwargs)
  71. print(response_text)
  72. # 3. 解析输出
  73. thought, action, finish = self._parse_output(response_text)
  74. # 4. 检查完成条件
  75. if finish:
  76. final_answer = finish
  77. return final_answer
  78. # 5. 执行工具调用
  79. if action:
  80. tool_name, tool_input = self._parse_action(action)
  81. observation = self.tool_registry.execute_tool(tool_name, tool_input)
  82. self.current_history.append(f"Action: {action}")
  83. self.current_history.append(f"Observation: {observation}")
  84. # 达到最大步数:让 LLM 一次性输出最终答案
  85. print(f"\n⚠️ 达到最大步数 {self.max_steps},开始生成最终答案")
  86. history_str = "\n".join(self.current_history)
  87. final_prompt = self.prompt_template.format(
  88. tools="",
  89. question=input_text,
  90. history=history_str +
  91. "\n\n请基于以上信息一次性给出最终答案(必须填入 Finish 字段)"
  92. )
  93. messages = [{"role": "user", "content": final_prompt}]
  94. final_response = self.llm.invoke(messages, **kwargs)
  95. thought, action, finish = self._parse_output(final_response)
  96. if finish:
  97. final_answer = finish
  98. return final_answer
  99. else:
  100. print("警告:在生成最终答案时,没有找到 Finish 字段。")
  101. return "抱歉,尝试生成最终答案时出错。"
  102. def _parse_output(self, text: str):
  103. # 清理模型输出,尝试提取JSON部分
  104. cleaned_text = self._extract_json_from_response(text)
  105. try:
  106. data = json.loads(cleaned_text)
  107. thought = data.get("Thought", "")
  108. action = data.get("Action")
  109. finish = data.get("Finish", [])
  110. return thought, action, finish
  111. except json.JSONDecodeError as e:
  112. print(f"警告:LLM返回的文本不是有效的JSON格式。原始文本: {text}")
  113. print(f"JSON解析错误: {e}")
  114. return "", None, ""
  115. def _extract_json_from_response(self, text: str) -> str:
  116. """从模型响应中提取JSON部分"""
  117. start = text.find('{')
  118. end = text.rfind('}')
  119. if start != -1 and end != -1 and start < end:
  120. candidate = text[start:end+1]
  121. # 验证这是否是有效的JSON
  122. try:
  123. json.loads(candidate)
  124. return candidate
  125. except json.JSONDecodeError:
  126. pass
  127. def _parse_action(self, action_text: dict):
  128. # 提取 tool_name 和 tool_input
  129. if not action_text or not isinstance(action_text, dict):
  130. return None, None
  131. tool_name = action_text.get("tool_name")
  132. tool_input = action_text.get("tool_input")
  133. return tool_name, tool_input
  134. if __name__ == "__main__":
  135. llm = HelloAgentsLLM()
  136. tool_registry = ToolRegistry()
  137. agent = NewReActAgent(
  138. name="Agent",
  139. llm=llm,
  140. tool_registry=tool_registry,
  141. max_steps=5
  142. )
  143. question = "请简单介绍你自己"
  144. try:
  145. answer = agent.run(question)
  146. print(f"最终答案: {answer}")
  147. except Exception as e:
  148. print(f"执行过程中出现错误: {e}")