A comprehensive project demonstrating different AI agent architectures and patterns using LangChain and LangGraph. This repository contains implementations of ReAct agents, reflection-based agents, and modular LLM integrations.
ai_agents/
βββ agent-1/ # ReAct Agent Implementation
β βββ re-act-agent.py # Main ReAct agent with tools
β βββ llm-check.py # LLM testing script
βββ agent-2/ # Reflection Agent Implementation
β βββ reflection-agent.py # LangGraph-based reflection agent
β βββ chain.py # Prompt chains for generation and reflection
βββ llms/ # Modular LLM Integration
β βββ __init__.py # Package exports
β βββ gemini.py # Google Gemini LLM integration
β βββ ollama_model.py # Ollama LLM integration
βββ requirements.txt # Python dependencies
βββ README.md # This file
# Windows PowerShell
.\venv\Scripts\Activate
# Windows CMD
venv\Scripts\activate.bat
# Linux/Mac
source venv/bin/activatepip install -r requirements.txtCreate a .env file in the root directory:
# Google Gemini API Key (required for Gemini models)
GOOGLE_API_KEY=your_gemini_api_key_here
# Tavily Search API Key (optional, for search functionality)
TAVILY_API_KEY=your_tavily_api_key_here# Run ReAct Agent
python agent-1/re-act-agent.py
# Run Reflection Agent
python agent-2/reflection-agent.pyAI Agents are autonomous systems that can perceive their environment, make decisions, and take actions to achieve specific goals. Unlike simple chatbots, agents can:
- Use tools and external APIs
- Maintain state and memory
- Make multi-step decisions
- Iterate and improve their outputs
Location: agent-1/re-act-agent.py
ReAct (Reasoning + Acting) is an agent framework that combines:
- Reasoning: The agent thinks through problems step-by-step
- Acting: The agent uses tools to gather information or perform actions
- Observation: The agent observes results and adjusts its approach
User Query
β
Agent Reasoning (Thought)
β
Tool Selection (Action)
β
Tool Execution (Observation)
β
Final Answer or Next Thought
- Gemini 2.5 Flash: Google's fast, efficient language model
- Ollama (llama3.1:8b): Local LLM option for privacy-sensitive tasks
Tools are functions the agent can call to interact with the world:
-
get_current_time: Custom tool that returns the current date and time- Purpose: Allows the agent to answer time-sensitive questions
- Implementation: Uses Python's
datetimemodule
-
TavilySearchResults: Web search tool (optional)- Purpose: Enables the agent to search the internet for real-time information
- Requires:
TAVILY_API_KEYin.envfile
- Zero-Shot: The agent doesn't need examples to understand tasks
- ReAct: Follows the Reasoning β Action β Observation loop
# 1. Initialize LLM
gemini_llm = get_gemini_llm()
# 2. Define Tools
tools = [current_time_tool, search_tool]
# 3. Create Agent
agent = initialize_agent(
tools,
gemini_llm,
agent="zero-shot-react-description",
verbose=True,
handle_parsing_errors=True
)
# 4. Invoke Agent
agent.invoke({"input": "Your question here"})agent.invoke({
"input": "When did the Bihar election result 2025 was announced and who won the election? How many days ago was it?"
})What happens:
- Agent thinks: "I need to find information about Bihar election results"
- Agent acts: Uses search tool to find election information
- Agent observes: Gets search results
- Agent thinks: "I need to calculate days ago from current time"
- Agent acts: Uses
get_current_timetool - Agent observes: Gets current time
- Agent thinks: "I can now calculate the difference"
- Agent answers: Provides complete answer with all information
- Error Handling:
handle_parsing_errors=Trueallows the agent to recover from format errors - Verbose Mode: Shows the agent's reasoning process step-by-step
- Tool Flexibility: Works with or without optional tools (graceful degradation)
Location: agent-2/reflection-agent.py
A Reflection Agent uses an iterative improvement pattern:
- Generate content
- Reflect on the quality
- Refine based on feedback
- Repeat until satisfied
This is similar to how humans write: draft β review β revise β repeat.
LangGraph is a framework for building stateful, multi-actor applications with LLMs.
- State: The current data/context (messages in this case)
- Nodes: Functions that process state
- Edges: Connections between nodes (can be conditional)
- Graph: The overall flow structure
START
β
GENERATE (Create content)
β
Should Continue? (Check message count)
βββ END (if messages > 4)
βββ REFLECT (if messages β€ 4)
β
GENERATE (Refine based on feedback)
β
(Loop continues...)
generation_prompt = ChatPromptTemplate.from_messages([
("system", "You are an Instagram techie influencer..."),
MessagesPlaceholder(variable_name="messages"),
])
generation_chain = generation_prompt | llm- Purpose: Generates Instagram post content
- Prompt Engineering: System message defines the agent's role and behavior
- Chain Composition: Uses LangChain's pipe operator (
|) to combine prompt and LLM
reflection_prompt = ChatPromptTemplate.from_messages([
("system", "You are a viral Instagram influencer grading a post..."),
MessagesPlaceholder(variable_name="messages"),
])
reflection_chain = reflection_prompt | llm- Purpose: Critiques and provides feedback on generated content
- Role: Acts as a quality reviewer
- Output: Recommendations for improvement
class GraphState(TypedDict):
messages: List[BaseMessage]- TypedDict: Provides type safety for state structure
- Messages: Stores conversation history (user input, generations, reflections)
Generate Node:
def generate_node(state: GraphState):
result = generation_chain.invoke({"messages": state["messages"]})
return {"messages": state["messages"] + [result]}- Takes current messages
- Generates new content
- Appends to message history
Reflect Node:
def reflect_node(state: GraphState):
response = reflection_chain.invoke({"messages": state["messages"]})
return {"messages": state["messages"] + [HumanMessage(content=response.content)]}- Reviews all messages
- Provides critique
- Adds critique as a new message
def should_continue(state: GraphState):
if len(state["messages"]) > 4:
return END
return REFLECT- Purpose: Prevents infinite loops
- Logic: Stops after 4 iterations
- Conditional Edge: Routes based on state
response = app.invoke({
"messages": [HumanMessage(content="AI Agents taking over content creation")]
})What happens:
- Iteration 1: Generates initial Instagram post
- Reflection 1: Critiques the post (length, style, virality)
- Iteration 2: Generates improved version based on feedback
- Reflection 2: Provides more specific recommendations
- Iteration 3: Further refinement
- Final Output: High-quality, refined content
- Iterative Refinement: Each cycle improves the output
- Self-Critique: The agent evaluates its own work
- State Persistence: Messages accumulate, building context
- Graph-Based Flow: Visual, declarative workflow definition
Location: llms/
Centralized, reusable LLM integration for easy model switching across the project.
def get_gemini_llm(model: str = "gemini-2.5-flash"):
return ChatGoogleGenerativeAI(model=model)- Provider: Google AI
- Default Model:
gemini-2.5-flash(fast, efficient) - Use Cases: Production applications, real-time responses
- Requirements:
GOOGLE_API_KEYin.env
def get_ollama_llm(model_name: str = "llama3.1:8b"):
return ChatOllama(model=model_name)- Provider: Local (self-hosted)
- Default Model:
llama3.1:8b(Meta's Llama 3.1) - Use Cases: Privacy-sensitive tasks, offline operation
- Requirements: Ollama installed locally with models pulled
from llms import get_gemini_llm, get_ollama_llm
# Use Gemini
llm = get_gemini_llm()
# Use Ollama
llm = get_ollama_llm()
# Use custom model
llm = get_gemini_llm("gemini-pro")
llm = get_ollama_llm("mistral:latest")- Modularity: Easy to swap models
- Consistency: Same interface across models
- Environment Management: Automatic
.envloading - Default Instances: Pre-configured models available
Definition: The art of crafting inputs to get desired outputs from LLMs.
In This Project:
- System messages define agent roles
- MessagesPlaceholder allows dynamic conversation history
- Chain composition links prompts to LLMs
Definition: Combining multiple components (prompts, LLMs, tools) into reusable pipelines.
Syntax:
chain = prompt | llm | output_parserBenefits:
- Reusable components
- Clear data flow
- Easy to modify and extend
Definition: Maintaining context and data across agent interactions.
In LangGraph:
- TypedDict defines state structure
- Nodes read and update state
- State persists across graph execution
Definition: Functions that agents can call to interact with external systems.
Types:
- Custom Tools: Python functions wrapped for agent use
- External Tools: APIs and services (Tavily, etc.)
Requirements:
- Single string input (for compatibility)
- Clear descriptions (for agent selection)
- Proper error handling
Strategies Used:
handle_parsing_errors=True: Recovers from format errors- Try-except blocks: Graceful tool failures
- Conditional tool loading: Works without optional dependencies
- langchain: Framework for building LLM applications
- langchain-google-genai: Google Gemini integration
- langchain-ollama: Ollama integration
- langchain-community: Community tools and integrations
- langgraph: Graph-based agent framework
- python-dotenv: Environment variable management
- langchain-tavily: Tavily search integration (optional)
- mlflow: Experiment tracking
- dvc: Data version control
- langsmith: To trace LLM calls and langchain chain calls/execution also to evaluate the ai agent/apps
- Information Retrieval: Answer questions requiring real-time data
- Multi-Step Reasoning: Complex queries needing multiple tools
- Time-Sensitive Queries: Questions about dates, events, timelines
- Content Generation: High-quality, refined content creation
- Iterative Improvement: Tasks requiring multiple refinement cycles
- Quality Assurance: Self-reviewing and improving outputs
For deeper understanding of the concepts and techniques used in this project, check out these comprehensive guides:
-
Basics_Readme.md: Complete guide to AI agent fundamentals
- Evolution from traditional code to autonomous agents
- Human-driven vs. agent-executed approaches
- Detailed explanations of LLMs, Chains, Routers, State Machines, and Agents
- When to use each approach with practical examples
- Comparison matrices and decision frameworks
-
Langgraph.md: Complete guide to LangGraph
- Core concepts: State, Nodes, Edges, and Graphs
- Key components and architecture
- Important features: Visualization, Streaming, Persistence, Human-in-the-Loop
- Common patterns and best practices
- Advanced topics and real-world examples
- Step-by-step getting started guide
-
Reflexion_agent.md: Complete guide to reflexion agents.
- Start with Agent-1: Understand basic ReAct pattern
- Explore Tools: Modify and add custom tools
- Study Agent-2: Learn graph-based workflows
- Experiment: Try different models and prompts
- Build: Create your own agent architectures
Happy Agent Building! π