python --version
pip install openai
Build a ReAct agent that interleaves reasoning traces and tool actions to solve multi-step problems.
1 import os 2 import re 3 import math 4 import openai 5 6 client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"]) 7 8 REACT_SYSTEM_PROMPT = """You are a helpful assistant that solves problems step by step. 9 10 Use this format: 11 Thought: <reasoning about what to do next> 12 Action: <tool_name>[<input>] 13 Observation: <result of the action> 14 ... (repeat as needed) 15 Final Answer: <final answer to the question> 16 17 Available tools: 18 - search[query]: Search for information 19 - calculate[expression]: Evaluate a math expression 20 - lookup[topic]: Look up facts about a topic 21 22 Begin!""" 23 24 # ── Simulated tools ───────────────────────────────────────────────── 25 def search(query: str) -> str: 26 database = { 27 "eiffel tower": "The Eiffel Tower is 330 meters tall, built 1887-1889, located in Paris.", 28 "python": "Python was created by Guido van Rossum, first released in 1991.", 29 "population of france": "France has a population of approximately 68 million people.", 30 } 31 for key, value in database.items(): 32 if key in query.lower(): 33 return value 34 return f"Search results for '{query}': Found limited information." 35 36 def calculate(expression: str) -> str: 37 try: 38 allowed_names = {"sqrt": math.sqrt, "pi": math.pi, "e": math.e} 39 result = eval(expression, {"__builtins__": {}}, allowed_names) 40 return f"{expression} = {result}" 41 except Exception as e: 42 return f"Error: {e}" 43 44 def lookup(topic: str) -> str: 45 facts = { 46 "gravity": "Earth's gravitational acceleration is 9.81 m/s².", 47 "speed of light": "Speed of light is 299,792,458 m/s.", 48 "pi": f"Pi = {math.pi}", 49 } 50 for key, value in facts.items(): 51 if key in topic.lower(): 52 return value 53 return f"No specific facts found for '{topic}'." 54 55 TOOL_MAP = {"search": search, "calculate": calculate, "lookup": lookup} 56 57 # ── ReAct loop ─────────────────────────────────────────────────────── 58 def parse_action(text: str) -> tuple[str, str] | None: 59 """Extract tool name and input from Action: tool[input].""" 60 match = re.search(r'Action:s*(w+)[([^]]*)]', text, re.IGNORECASE) 61 if match: 62 return match.group(1).lower(), match.group(2) 63 return None 64 65 def react_agent(question: str, max_steps: int = 6) -> str: 66 messages = [ 67 {"role": "system", "content": REACT_SYSTEM_PROMPT}, 68 {"role": "user", "content": question}, 69 ] 70 71 for step in range(max_steps): 72 response = client.chat.completions.create( 73 model="gpt-4o-mini", 74 messages=messages, 75 max_tokens=300, 76 temperature=0, 77 stop=["Observation:"], # Stop at observation — we fill it in 78 ) 79 80 text = response.choices[0].message.content 81 print(f" Step {step + 1}:\n{text}") 82 83 # Check for final answer 84 if "Final Answer:" in text: 85 return re.search(r"Final Answer:\s*(.+)", text, re.DOTALL).group(1).strip() 86 87 # Parse and execute action 88 action = parse_action(text) 89 if action: 90 tool_name, tool_input = action 91 if tool_name in TOOL_MAP: 92 observation = TOOL_MAP[tool_name](tool_input) 93 else: 94 observation = f"Tool '{tool_name}' not found." 95 96 # Append to conversation 97 messages.append({"role": "assistant", "content": text}) 98 messages.append({"role": "user", "content": f"Observation: {observation}"}) 99 print(f" Observation: {observation}\n") 100 else: 101 # Model didn't call a tool — it may have final answer without the label 102 messages.append({"role": "assistant", "content": text}) 103 104 return "Max steps reached without final answer." 105 106 print("=== ReAct Agent ===") 107 question = "How tall is the Eiffel Tower in feet? (1 meter = 3.28084 feet)" 108 print(f"Q: {question}\n") 109 answer = react_agent(question) 110 print(f"\nFinal Answer: {answer}") 111
Sign in to share your feedback and join the discussion.