A specialized web search agent powered by LangGraph and LangChain that consumes fresh internet data and delivers accurate, current information.
- Real-time Web Search: Uses Tavily API to fetch current information from the web
- LangGraph ReAct Agent: Intelligent routing between thinking (chat_node), acting (tool_node), and control flow
- LLM-Powered: Runs on Groq's Qwen3-32B model for fast reasoning
- Streamlit UI: Simple, clean chat interface for user interaction
- Conversation Memory: Maintains conversation history per thread with checkpointing
web-eater/
├── web_eater.py # Core agent logic (LangGraph + LangChain)
├── app.py # Streamlit chat UI
├── main.py # Entry point
├── requirements.txt # Python dependencies
├── pyproject.toml # Project config
├── runtime.txt # Python runtime version
└── .env # Environment variables (add API keys here)
uv add langchain==1.1.0 langchain-community==0.4.1 langchain-groq==1.1.0 langgraph==1.0.4 python-dotenv==1.2.1 streamlit==1.50.0 tavily-python==0.7.17Or use existing requirements:
uv syncCreate a .env file in the project root:
GROQ_API_KEY=your_groq_api_key_here
TAVILY_API_KEY=your_tavily_api_key_here
Get your keys from:
To enable LangSmith tracing for debugging and monitoring:
- Get your API key from LangSmith Dashboard
- Add to your
.envfile:
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=your_langsmith_api_key_here
LANGCHAIN_PROJECT=web-eater
This will automatically trace all LLM calls, tool executions, and agent decisions in LangSmith.
streamlit run app.pyThen open your browser to http://localhost:8501
from web_eater import get_agent_response
response = get_agent_response("What's the current price of Bitcoin?")
print(response)Web Eater implements a ReAct (Reasoning + Acting) agent pattern using LangGraph:
1. MessagesState (Shared State)
- Stores conversation history
- All nodes read from and write to this state
- Uses
operator.addto append messages (ReAct pattern)
2. Chat Node (🧠 Thinking)
- Receives: Current conversation state
- Logic: Analyzes messages, decides next action
- Returns: LLM response (may include tool_calls)
- Purpose: Intelligent decision-making
- Context Window Optimization: Maintains the system message + keeps only the last 4 messages to manage token limits and prevent context bloat
3. Tool Node (🔧 Acting)
- Receives: Last message (contains tool_calls)
- Logic: Executes each requested tool
- Returns: ToolMessages with results
- Purpose: Execute web search & fetch current time
4. Router (🚦 Control Flow)
- Receives: Chat node output
- Logic: Checks if tool_calls exist
- Routes to: Tool Node OR END
- Purpose: Deterministic workflow control
5. Tools
current_datetime(): Returns UTC timestampsearch_web(query): Calls Tavily API for web search
User: "What's Bitcoin's current price?"
↓
Chat Node: "I need to search the web for current info"
↓ (tool_call: search_web("Bitcoin current price"))
Tool Node: Executes search_web, gets results
↓ (ToolMessage with search results)
Chat Node: Analyzes results, generates answer
↓
Router: No more tools needed → END
↓
Response: "According to search results, Bitcoin is..."
- User Input → Streamlit captures the question
- Chat Node → LLM reasons about whether web search is needed
- Router → Decides if tools (web_search, current_datetime) are required
- Tool Node → Executes tools and returns results
- Chat Node → LLM processes tool results and generates final answer
- Response → Displayed in Streamlit UI
- web_eater.py: Core agent with state management, tools, and graph execution
- app.py: Universal Streamlit chat interface with session memory
- current_datetime(): Tool that returns UTC time
- search_web(): Tool that searches the web via Tavily API
langchain: LLM frameworklangchain-groq: Groq integrationlanggraph: Graph-based agent orchestrationtavily-python: Web search APIstreamlit: Web UI frameworkpython-dotenv: Environment variable management
MIT
