Skip to main content

📋 Table of Contents

💻 Workshop Practice Notebook

Master all the concepts from this guide with hands-on practice (excluding MCP):
  • Practice in VS Code: Open the notebook in your local editor. Requires a local .env file containing your API keys.
  • Practice in Google Colab: Open the notebook directly in Colab. Setup cells are included to install packages and request API keys.
💻 VS Code | 🚀 Colab | 📥 Download Notebook

Chapter 1: Introduction to Autonomous Agents

Most LLM applications operate in static chains, where a prompt triggers a model, and the model returns a response. Autonomous Agents shift this paradigm: instead of a fixed sequence, the LLM acts as a reasoning engine that dynamically determines which actions to take, which tools to call, and how to self-correct based on feedback.

1. Chains vs. Agents

The difference between chains and agents lies in control flow:
  • Static Chain: The developer hardcodes the workflow.
    • Example: User Input \rightarrow Prompt Template \rightarrow LLM \rightarrow StrOutputParser. The model has no choice but to follow this exact path.
  • Autonomous Agent: The model dynamically routes execution based on the user’s goal.
    • Example: If a user asks “Check the price of Apple stock and email it to my manager,” the agent decides to:
      1. Call a stock price search API tool.
      2. Read the results.
      3. Call an email API tool.
      4. Formulate a final response.

2. Core Components of an Agent

According to agent architectures, an autonomous agent consists of three central pillars:

2.1 Planning

  • Subgoal Decomposition: Breaking a large, complex task into smaller, manageable milestones.
  • Reflection & Self-Correction: Analyzing tool execution outputs. If a tool returns an error (e.g. API authentication failure), the agent alters its plan and attempts an alternative route instead of failing.

2.2 Memory

  • Short-Term Memory: In-context conversation history. Allows the model to remember preceding turns in a chat session.
  • Long-Term Memory: Storing past outputs and vector embeddings in a database, allowing the agent to recall information across days or weeks.

2.3 Tools

  • Interfaces that allow the LLM to interact with the physical world.
  • Examples: Web search engines (Tavily), calculation modules, databases, shell execution tools, or API endpoints.

3. The ReAct Design Pattern

The most popular agent execution framework is the ReAct (Reason + Act) pattern. ReAct combines reasoning (thoughts) and acting (actions) in a recursive loop:
  • Thought: The model reasons about the current state of the problem (e.g., “I need to find the population of Paris. I should use the search tool.”).
  • Action: The model triggers a specific tool with generated arguments (e.g., Calling search_web("Paris population")).
  • Observation: The application executes the tool, gets the raw output, and feeds it back to the model (e.g., Output: "2.1 million").
  • Thought / Final Answer: The model evaluates the observation. If the goal is met, it outputs the final answer to the user.

4. Practice Exercises

Practice 1: Identifying Agentic Capabilities

Suppose you want to build an application that analyzes a company budget CSV, generates a chart, and uploads it to Slack. Explain why this requires an Agent rather than a Static Chain.
A static chain has a linear flow. However, this task involves dynamic steps:
  1. Decision making: The code must read the CSV and decide which columns are relevant for the chart based on the user’s description.
  2. Error recovery: If the chart generation library throws a syntax error, a static chain crashes. An agent can read the traceback error (Observation), write corrected python code (Thought/Action), and execute it again until it succeeds.
  3. Execution Routing: Choosing the Slack upload API tool only after the chart file is successfully verified on disk.
Back to Top

Chapter 2: Tool Use & Function Calling

Large Language Models cannot directly execute python code or fetch URL contents. Instead, they use Function Calling (Tool Binding), where the model outputs a structured JSON request indicating which tool to run and what arguments to pass. The client application executes the code locally and returns the result to the model.

1. The Function Calling Lifecycle

The function calling loop operates as a communication contract between the application client and the LLM API:
[!IMPORTANT] LLMs do not run your tools. The model only generates the JSON arguments specifying how you should run them. Your Python script is responsible for executing the function and feeding the text result back to the model.

2. Defining & Binding Tools in LangChain

In LangChain, you convert any standard Python function into a tool using the @tool decorator. The decorator automatically generates the JSON schema description based on your function name, docstring, and type hints.

2.1 Python Implementation

Below is a working script demonstrating tool binding. The model evaluates a user question and outputs a structured tool call request.
Output:

3. Practice Exercises

Practice 1: Binding Multiple Tools

Create a second tool called get_current_weather(city_name: str) that returns a mock weather string (e.g. "22°C and sunny"). Bind both calculate_salary_bonus and get_current_weather to your model. Query "What is the weather in London?" and verify the correct tool call is returned. Instructions:
  1. Write the get_current_weather tool with a docstring.
  2. Call llm.bind_tools([calculate_salary_bonus, get_current_weather]).
  3. Invoke the query and print response.tool_calls.
Back to Top

Chapter 3: Building a ReAct Agent

By combining reasoning and tool execution, we can construct a ReAct Agent that runs in a loop to solve problems. This page covers building a complete working agent project.

1. The Modern LangChain Agent Stack

To build agents in modern LangChain, we use LangGraph, which models agents as state graphs where the LLM decides node transitions (e.g. calling tools vs. returning the final response).

2. In-Memory Working Agent Project

Let’s build a working agent equipped with a math evaluation tool and a dictionary database look-up tool.

2.1 Install Dependencies

Run in your terminal:

2.2 Complete Code Implementation

Save and run this script:
Expected Trace Behavior:
  1. The agent notices "Find siva's email" and runs get_user_email(employee_name="siva").
  2. The agent notices "calculate 345 * 12" and runs calculate_math(expression="345 * 12").
  3. The agent merges both observations and outputs: “Siva’s email is [email protected] and 345 * 12 is 4140.”

3. Practice Exercises

Practice 1: Add a Currency Converter Tool

Extend the working agent by adding a new tool convert_usd_to_eur(amount: float) -> float that multiplies the USD amount by 0.92. Run the query: "Find siva's email and convert 150 USD to EUR." and print the output. Instructions:
  1. Write the convert_usd_to_eur tool.
  2. Add it to the tools list.
  3. Call create_react_agent(llm, tools).
  4. Invoke the agent and print the final message content.
Back to Top

Chapter 4: Multi-Agent Orchestration

Single agents can struggle when tasked with highly complex processes containing multiple distinct steps. Multi-Agent Orchestration solves this by breaking a system down into several specialist agents (e.g. researcher, writer, code auditor) that collaborate to achieve a goal.

1. Why Use Multi-Agent Collaboration?

Instead of relying on one agent with 20 tools, separating duties yields major benefits:
  • Separation of Concerns: Each agent has a focused system prompt instruction and role-specific tools, reducing the reasoning burden on the model.
  • Context Preservation: A single agent loop gains massive context length as it runs multiple tools. Multi-agent systems pass only relevant summaries between nodes, keeping the context window small and cheap.
  • Specialist Personas: You can use different LLMs for different roles (e.g. a small, fast model for searching, and a large, reasoning model for coding).

2. Multi-Agent Design Patterns

Collaborative structures fall into three primary communication patterns:

2.1 Sequential Chains (Pipelines)

The task passes forward through a series of agents. Each agent acts as a filter or refinement step.
  • Example: A Researcher agent extracts web data, passes it to a Writer agent to draft a blog post, which passes it to an Editor agent for grammar checking.

2.2 Hierarchical Orchestration

A central Supervisor / Manager agent evaluates the input query and delegates work to specialist child agents, collects their observations, and determines when the overall task is finished.

2.3 Network / Dynamic Collaboration

Agents join a shared conversational thread (Group Chat). The next speaker is determined dynamically based on the current context or a pre-defined conversation coordinator.

3. Major Multi-Agent Frameworks

To implement these patterns in production, developers use specialized orchestration libraries:
  • CrewAI: A framework built around structured roles, goals, and tasks. Ideal for setting up role-playing agent “crews” that execute sequential workflows.
  • LangGraph: An open-source graph orchestrator by LangChain. It offers maximum flexibility to define complex, stateful loops and cyclic agent interactions.
  • AutoGen: A framework by Microsoft focusing on building conversational multi-agent communication channels.

4. Practice Exercises

Practice 1: Multi-Agent Role Definition

Design a multi-agent team to handle customer refund complaints. Define:
  1. The roles needed.
  2. The specific tools assigned to each role.
  3. The communication sequence.

Role Definition:

  1. Auditor Agent:
    • Role: Verifies the user’s order history and refund eligibility.
    • Tools: query_database, check_refund_policy.
  2. Support Writer Agent:
    • Role: Writes a professional email explaining the decision.
    • Tools: None (requires reasoning only).
  3. Execution Agent:
    • Role: Processes the financial refund transaction and emails the user.
    • Tools: execute_refund_payment, send_email.

Communication Sequence:

  • Auditor analyzes customer ticket \rightarrow passes verification outcome to Support Writer \rightarrow Support Writer drafts confirmation email \rightarrow Execution Agent processes payment and sends email.
Back to Top

Chapter 5: Stateful Travel Assistant Project

In this page, we build a stateful, collaborative multi-agent Travel Assistant application using LangGraph. This assistant extracts a travel destination, runs a weather forecast search, and calculates a budget estimation, all while remembering user preferences across chat turns.

1. Core Concepts Explained

This project illustrates the following agentic concepts:
  • State Management: Using the shared graph state to pass specialized variables (like destination, weather_info, and budget_estimate) between agents.
  • Separation of Duties: Dividing tasks so the Weather Node focuses solely on weather details, and the Budget Node handles numerical calculations.
  • Persistent Session Thread: Using a checkpointer to remember what destination the user is planning to visit, allowing them to ask follow-up questions without repeating details.

2. Key APIs & Classes Used

  • StateGraph: The core graph builder class from LangGraph.
  • MemorySaver: An in-memory database checkpointer used to store chat sessions.
  • add_messages: Reducer function telling the graph to append new chat messages instead of overwriting the history.
  • thread_id: Session key passed to the checkpointer to scope the memory to a specific conversation thread.

3. Step-by-Step Practical Implementation

Step 1: Define the Shared State Schema

The state holds the conversation history (messages), the destination city, the retrieved weather_info, and the generated budget_estimate:

Step 2: Create a Weather Search Tool

We write a mock tool using the @tool decorator that returns the current temperature and forecast for a destination:

Step 3: Define Node Functions

Nodes read from the state, call the LLM/tools, and return state key updates:
  • Weather Node: Analyzes the query, calls the weather tool, and updates destination and weather_info.
  • Budget Node: Calculates hotel/flight costs based on the destination and updates budget_estimate.

Step 4: Assemble Nodes and Edges

We construct the graph, adding nodes and setting the routing path:

Step 5: Compile with Memory Saver

We compile the graph with an in-memory checkpointer:

4. Combined Running Code Project

Here is the complete, self-contained Python script combining all steps:

5. Practice Exercises

Practice 1: Add a Packing Planner Node

Extend the stateful graph by adding a third node called packing_agent that runs after the budget_agent node. It should read the weather_info from the state and suggest 3 items the user should pack for their trip. Instructions:
  1. Update TravelState to include a packing_list key.
  2. Define a function packing_node(state: TravelState) that takes the weather_info and generates a list of 3 items to pack.
  3. Add the node to the graph and update the edges: budget_agent \rightarrow packing_agent \rightarrow END.
Back to Top

Chapter 6: Resume Analyzer Capstone Workflow

Single agents can struggle to handle multiple tasks like auditing documentation and planning schedules. In this page, we walk through building a stateful, collaborative multi-agent application utilizing a custom LangGraph configuration and memory checkpointers.

1. Core LangGraph Concepts

LangGraph models agents as state machines. There are four fundamental concepts:
  • State: The central database or memory structure shared across the graph. Any node can read variables from this state and output key-value updates to write back to it.
  • Nodes: Python functions representing independent operations or agents. A node receives the current state, processes it (e.g., calls an LLM or runs a tool), and returns a dictionary with state updates.
  • Edges: Control flow rules. Normal Edges define a fixed sequential route (e.g. from node A to node B). Conditional Edges use a router function to dynamically decide which node to visit next based on state data.
  • Checkpointers (Memory): Databases that automatically save a snapshot of the graph’s state after every node execution. This allows the graph to resume or remember conversations across separate API requests.

2. Available APIs & Key Classes

To build stateful agents, LangGraph provides the following key classes and decorators:
  • StateGraph: The primary builder class used to construct graphs. It takes a typed dictionary (schema) defining the structure of the state.
  • add_messages: An accumulator reducer function. In LangGraph, returning a key updates the state. For lists of messages, we don’t want to overwrite previous history. Using Annotated[list, add_messages] tells the graph to append new messages instead of replacing the list.
  • MemorySaver: A built-in, in-memory checkpointer class that preserves thread states.
  • thread_id: A config key passed during graph execution. Any queries sharing the same thread_id share the same conversation history in the checkpointer.

3. Practical Step-by-Step Implementation

Step 1: Define the Graph State Schema

We define a Python class inheriting from TypedDict containing the keys that will be shared between our agents:

Step 2: Create a Verification Tool

We write a tool that the analyzer agent can invoke to cross-check candidate skills:

Step 3: Define Agent Node Functions

Nodes receive the shared state, call the LLM, and return updates:

Step 4: Assemble Graph Nodes & Edges

We add nodes and map the route sequentially:

Step 5: Compile with Checkpointer Memory

We attach MemorySaver to compile our final application graph:

4. Combined Running Code Project

Here is the complete, self-contained Python script ready to copy and run:

5. Practice Exercises

Practice 1: Adding a Feedback Evaluation Node

Extend the stateful graph by adding a third node called feedback_evaluator that runs after the planner node. The node should format a short summary checklist of topics to check off during the interview. Instructions:
  1. Update AgentState to include an eval_checklist key.
  2. Define a function feedback_evaluator_node(state: AgentState) that takes the interview_plan and creates a checklist.
  3. Add the node to the graph and update the edges: planner \rightarrow evaluator \rightarrow END.