Building AI Agents with LangChain & CrewAI
AI agents are autonomous systems that use LLMs to reason, use tools, and take actions — this guide covers building single agents with LangChain and multi-agent teams with CrewAI for real-world automation.
What You'll Learn
You'll learn to build AI agents that can browse the web, run code, query databases, and collaborate in teams — using LangChain for single agents and CrewAI for multi-agent systems.
Why It Matters
Agents Go beyond simple chatbots by taking autonomous actions. They can investigate incidents, manage deployments, gather intelligence, and execute multi-step tasks without human supervision.
Real-World Use
Durga Antivirus Pro uses a CrewAI multi-agent system where a Coordinator Agent receives threat alerts, a File Analysis Agent inspects suspicious binaries, a Network Agent checks for C2 communication patterns, and a Report Agent generates remediation steps — all running autonomously.
Single Agent with LangChain
LangChain provides the building blocks for agent creation: LLM integration, tool definitions, memory, and execution loops.
from LangChain.agents import create_React_agent, AgentExecutor
from LangChain.tools import tool
from LangChain_OpenAI import ChatOpenAI
from LangChain_community.tools import DuckDuckGoSearchRun
@tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression and return the result."""
try:
result = eval(expression)
return str(result)
except Exception as e:
return f"Error: {e}"
@tool
def get_file_info(path: str) -> str:
"""Get file size and modification time for a given path."""
import os
import time
if not os.path.exists(path):
return "File not found"
stat = os.stat(path)
return f"Size: {stat.st_size} bytes, Modified: {time.ctime(stat.st_mtime)}"
tools = [calculate, get_file_info, DuckDuckGoSearchRun()]
llm = ChatOpenAI(model="gpt-4o", temperature=0)
agent = create_React_agent(llm, tools)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10,
handle_Parsing_errors=True
)
result = agent_executor.invoke({
"input": "Search for the latest Python release, calculate 2^50, "
"and check the size of /etc/hosts"
})
print(result["output"])
Expected behavior: The agent reasons about what to do, calls each tool in sequence, and combines the results into a coherent answer — showing its reasoning steps in verbose mode.
flowchart LR
A[User Input] --> B[LLM Reason]
B --> C{Action Needed?}
C -->|Yes| D[Select Tool]
D --> E[Execute Tool]
E --> F[Observe Result]
F --> B
C -->|No| G[Final Answer]
Multi-Agent Teams with CrewAI
CrewAI enables role-based agent teams where each agent has a defined role, goal, and set of tools.
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
search_tool = SerperDevTool()
scrape_tool = ScrapeWebsiteTool()
researcher = Agent(
role="Research Analyst",
goal="Find comprehensive and accurate information on any topic",
backstory="Expert researcher with 15 years of experience in technical analysis",
tools=[search_tool, scrape_tool],
verbose=True,
allow_delegation=False
)
writer = Agent(
role="Technical Writer",
goal="Create clear, well-structured summaries and reports",
backstory="Senior technical writer specializing in developer documentation",
verbose=True,
allow_delegation=False
)
research_task = Task(
description="Research the latest trends in AI-powered Code Generation tools. "
"Find at least 5 different tools and their key features.",
expected_output="A comprehensive list of AI Code Generation tools with features",
agent=researcher
)
writing_task = Task(
description="Using the research findings, create a comparative analysis "
"report with a feature comparison table.",
expected_output="A markdown report with introduction, comparison table, and recommendations",
agent=writer
)
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, writing_task],
Process=Process.sequential,
verbose=True
)
result = crew.kickoff()
print(result)
Expected output: The researcher agent first gathers data using web search and scraping, then the writer agent produces a structured markdown report combining all findings.
Adding Memory to Agents
Memory allows agents to remember context across interactions and learn from past actions.
from LangChain.memory import ConversationSummaryBufferMemory
from LangChain.agents import AgentExecutor
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=2000,
memory_key="chat_history",
return_messages=True
)
agent_with_memory = AgentExecutor(
agent=agent,
tools=tools,
memory=memory,
verbose=True,
max_iterations=10
)
agent_with_memory.invoke({"input": "Find my previous calculation result"})
Expected behavior: The agent retrieves past conversation context from memory, allowing it to reference earlier results without repeating the work.
Best Practices for Production Agents
Production agents need guardrails to prevent unexpected behavior. Always set max_iterations to a reasonable limit (10-15) to prevent infinite loops. Implement timeout handling for slow tool calls. Use handle_<a href="/compiler-design/syntax-analysis/">Parsing</a>_errors=True so the agent can recover from malformed LLM output. Add input validation in your tool functions to prevent the agent from passing dangerous arguments.
Monitor agent performance by logging every action, observation, and final answer. This audit trail helps debug failures and improves prompt engineering over time. Consider using LangSmith or a custom logging solution to track agent trajectories.
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("agent")
class LoggingAgentExecutor(AgentExecutor):
def _call(self, *args, **kwargs):
logger.info(f"Agent received: {kwargs.get('input', '')}")
result = super()._call(*args, **kwargs)
logger.info(f"Agent returned: {result.get('output', '')}")
return result
Expected behavior: Every agent interaction is logged with timestamps, inputs, and outputs, creating a debuggable history of decisions and tool calls.
Agent Planning and Task Decomposition
from LangChain.chains import LLMChain
from LangChain.prompts import PromptTemplate
planner_prompt = PromptTemplate(
template="""Break this complex task into smaller subtasks:
Task: {task}
Output a numbered list of subtasks in execution order.
Each subtask should be completable by a single tool call.""",
input_variables=["task"]
)
planner_chain = LLMChain(llm=llm, prompt=planner_prompt)
def execute_planned_task(task):
plan = planner_chain.run(task=task)
print("Plan generated:")
print(plan)
subtasks = [line.split(". ", 1)[1] for line in plan.split("\n") if line.strip()]
for i, subtask in enumerate(subtasks, 1):
print(f"\nExecuting subtask {i}: {subtask}")
result = agent_executor.invoke({"input": subtask})
print(f"Result: {result['output']}")
Expected behavior: The planner decomposes a complex task into manageable pieces, executes each one sequentially, and provides results for each subtask.
Common Errors
| Error | Cause | Fix |
|---|---|---|
| Agent stuck in infinite loop | Tool returns unexpected output | Set max_iterations and add fallback logic |
| Tool hallucination | Agent calls non-existent tools | Use @tool decorator with explicit function registry |
| CrewAI delegation failure | Agent misidentifies task owner | Set allow_delegation: false for focused agents |
| Context window overflow | Agent accumulates too many observations | Implement memory summarization |
| Agent ignores instructions | Weak system prompt | Strengthen role definition and constraints |
Practice Questions
What distinguishes an AI agent from a standard LLM call? An agent has access to tools, memory, and a reasoning loop that allows it to take actions based on observations, not just generate text.
How does CrewAI's sequential Process differ from hierarchical? Sequential runs tasks one after another with each agent completing its task before the next starts; hierarchical has a manager agent that delegates and coordinates.
Why is memory important for AI agents? Memory allows agents to reference past results, maintain context across turns, and avoid repeating the same work.
What happens when an agent reaches max_iterations? The agent stops its reasoning loop and returns whatever result it has produced up to that point, preventing infinite loops.
Challenge: Build a 3-agent CrewAI team that monitors a GitHub Repository for new issues, classifies them (bug, feature, question), drafts an appropriate response, and assigns labels — all autonomously.
Mini Project
Build a personal research assistant agent system. Use LangChain to create an agent with tools for web search, web scraping, and summarization. Give it a long-term memory using a vector store. Then build a CrewAI team where a Research Agent gathers information, an Analysis Agent identifies key insights, and a Report Agent generates a PDF summary. Test it by researching a complex topic like "latest developments in AI-powered cybersecurity."
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro