Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save KunalKumarSwift/349c6cc1ba40a3c8111ba5ca94b588fd to your computer and use it in GitHub Desktop.

Select an option

Save KunalKumarSwift/349c6cc1ba40a3c8111ba5ca94b588fd to your computer and use it in GitHub Desktop.
Minimal React loop agent in python
"""
Minimal ReAct-style loop with LangChain tool calling.
ReAct = "Reason + Act": the model thinks, decides whether to call a tool,
observes the result, and repeats until it has a final answer.
This uses LangChain's tool-calling primitives directly (no AgentExecutor
magic) so you can see exactly what's happening at each step.
"""
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_anthropic import ChatAnthropic
# Swap for: from langchain_openai import ChatOpenAI
# ---- 1. Define tools -------------------------------------------------
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a given city."""
# Replace with a real API call
fake_data = {"toronto": "18°C, cloudy", "waterloo": "17°C, rainy"}
return fake_data.get(city.lower(), "No data for that city")
@tool
def add(a: float, b: float) -> float:
"""Add two numbers together."""
return a + b
tools = [get_weather, add]
tools_by_name = {t.name: t for t in tools}
# ---- 2. Bind tools to the model ---------------------------------------
llm = ChatAnthropic(model="claude-haiku-4-5-20251001", temperature=0)
llm_with_tools = llm.bind_tools(tools)
# ---- 3. The ReAct loop --------------------------------------------------
def run_agent(user_input: str, max_steps: int = 5) -> str:
messages = [HumanMessage(content=user_input)]
for step in range(max_steps):
ai_msg = llm_with_tools.invoke(messages)
messages.append(ai_msg)
# No tool calls -> model gave a final answer, stop looping
if not ai_msg.tool_calls:
return ai_msg.content
# Otherwise, execute each requested tool call and feed results back
for call in ai_msg.tool_calls:
tool_fn = tools_by_name[call["name"]]
result = tool_fn.invoke(call["args"])
messages.append(
ToolMessage(content=str(result), tool_call_id=call["id"])
)
return "Max steps reached without a final answer."
if __name__ == "__main__":
answer = run_agent(
"What's the weather in Waterloo, and what is 18 plus 24?"
)
print(answer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment