Sunday, December 28, 2025

OpenAI Agents

OpenAI agents SDK Core features:


·        Introduction to Co-routines and other agents information: 

o   Co-routines Versus Functions:  when using 'async def' in Python, the resulting object is a coroutine, not a traditional function, and calling a coroutine returns a coroutine object rather than executing the code immediately.

o   Event Loop Mechanism: the event loop in the async IO library is a loop that schedules and executes coroutines, pausing them when they are waiting for IO and resuming others, enabling concurrency without traditional multithreading.

o   Awaiting Coroutines: to execute a coroutine, it must be awaited using the 'await' keyword, which schedules it for execution in the event loop and blocks until the coroutine completes.

o   Concurrent Execution with Gather: 'asyncio.gather' as a construct that allows multiple coroutines to be scheduled concurrently, with the event loop managing their execution and collecting their results as a list.

·        Introduction to OpenAI Agents SDK: 

o   Framework Characteristics: the OpenAI Agents SDK is lightweight, flexible, and not prescriptive, allowing users to choose their preferred working style while abstracting away repetitive tasks such as JSON handling.

o   Key Terminology in OpenAI Agents SDK- Agents Terminologythree core terms in the OpenAI Agents SDK—agents, handoffs, and guardrails.

§  Agents - agents as wrappers around LLMs with specific roles,

§  Handoffs - 'handoffs' as interactions between agents,

§  Guardrails - 'guardrails' as checks and controls to ensure agents behave within defined Guardrails.

·        Steps to Run an Agent in OpenAI Agents SDK:  three steps required to run an agent using the OpenAI Agents SDK:

o   Agent Instance Creation: Create an instance of an agent, which will represent a role in the solution.

o   Interaction Logging with Trace: using 'with trace' is recommended for logging all interactions with the agent, enabling monitoring through OpenAI's tools. Trace to track the agent.

o   Running the Agent Coroutine: the agent is executed by calling 'runner.run', which is a coroutine and must be awaited to actually run the agent.  Call runner.run to run the agent.

asyncio: 

asyncio is Python’s built‑in asynchronous programming framework. It performed multiple things at the same time without using threads or processes. asyncio will offer:

  • While task A is waiting, Python can run task B
  • While task B is waiting, Python can run task C

Asyncio, Python run many waiting tasks at the same time, making I/O-heavy programs dramatically faster. This makes the program much faster and more efficient. Use asyncio when the program does a lot of waiting

Don’t use for CPU-heavy tasks (math, ML, image processing). All methods and functions should start with async as keyword. During the calling of methods or functions, use await keyword

import asyncio
async def fetch_data():
    await asyncio.sleep(2)
     return "data"
 
async def main():
    results = await asyncio.gather(
        fetch_data(),
        fetch_data(),
        fetch_data()
    )
    print(results)
    result = await Runner.run(main())
 
INSTRUCTIONS = " some instruction as prompt."
 
first_agent = Agent(
    name="First agent",
    instructions=INSTRUCTIONS,
    tools=toolname,
    model="gpt-4o-mini",
)
message = "Welcome AI Agent frameworks in 2025"
with trace("Welcome"):
    result = await Runner.run(first_agent, message)
  
with trace("multiple agents"):
    results = await asyncio.gather(
        Runner.run(agent1, message),
        Runner.run(agent2, message),
        Runner.run(agent3, message),
            )

Key concepts in asyncio

Concept

Meaning

async def

Defines an asynchronous function

await

Pauses the function until the awaited task completes

event loop

The engine that schedules async tasks

asyncio.gather()

Runs multiple tasks at the same time

asyncio.sleep()

Non-blocking sleep (example of async I/O)

 Agent frameworks need to:

  • run multiple agents at the same time
  • handle many I/O operations (LLM calls, tools, APIs)
  • wait for responses without blocking the whole system
  • coordinate tasks, messages, and events
  • rely on asyncio.

Agent frameworks use asyncio, and the frameworks below are built around async execution:

1.        LangChain
a. Tool calls are async
b. LLM calls can be async
c. Agents run async loops
d. Many integrations require async def
2.        LangGraph
a. Entire architecture is async-first
b. Nodes, edges, and tool calls run concurrently
c.  Event-driven execution uses asyncio tasks
3.        CrewAI
a. Uses asyncio for parallel task execution
b. Agents can run concurrently
c. Async tool calls supported
4.        Microsoft Autogen (new version)
a. Fully async
b. Agents communicate via async message passing
5.        MCP (Model Context Protocol)
a. Server and client interactions use async
b. Streaming responses require async
c. Tool execution often async

Learning during this journey

  • Agent workflow
  • Use of tools to call functions
  • Agent collaboration via Tools and Handoffs

Example: Multi Agents

    Steps1: Define instruction, trying to run multiple agent as parallel. Define instruction, description, and tools 

instructions1 = "You are a agent1 working for ComplAI, define the action."
instructions2 = "You are a agent2 working for ComplAI, define the action."
instructions3 = "You are a agent3 working for ComplAI define the action."
 
description = "specific actions"
 
# Agent definition
agent1 = Agent(name="DeepSeek Sales Agent", instructions=instructions1, model=deepseek_model)
agent2 =  Agent(name="Gemini Sales Agent", instructions=instructions2, model=gemini_model)
agent3  = Agent(name="Llama3.3 Sales Agent",instructions=instructions3,model=llama3_3_model)
 
# tool definition
tool1 = agent1.as_tool(tool_name="agent1", tool_description=description)                    
tool2 = agent2.as_tool(tool_name="agent2", tool_description=description)
tool3 = agent3.as_tool(tool_name="agent3", tool_description=description)

 Steps2: Define the decorator function 

@function_tool
def do_action(sub: str, des: str) -> Dict[str, str]:
    """ Action definition"""
    return {"status": "success"}
 
Instruction to agent:              
    sub1_instructions = "write a detail for action perform by agent."
    sub2_instructions = "write a detail for action perform by agent."
            
            Define agents and convert them into tools: 
    agent4 = Agent(name="new_agent1", instructions= sub1_instructions, model="gpt-4o-mini")
    subject1_tool = Agent4.as_tool(tool_name=" Agent4", tool_description="tool description as action")
 
    agent5 = Agent(name="new_agent2", instructions= sub2, model="gpt-4o-mini")
    subject2_tool = html_converter.as_tool(tool_name=" Agent5",tool_description=" tool description as action")
 
    listOf_tools = [subject1_tool, Subject2_tool, do_action]
referencing a handoff agent:  

    agent5 = Agent(
        name="new_agent3",
        instructions=instructions,
        tools= listOf_tools,
        model="gpt-4o-mini",
        handoff_description="handoff agent will take care as instructed")
 
    tools = [tool1, tool2, tool3]
    handoffs = [handoff_agent]
Runs the entire multi‑agent system:
main_instructions = """
Role is ComplAI and goal is to do ….. using the agent_name tools.
Follow these steps carefully:
1. Generate Drafts: Use all agents agent_name tools ….
2. Handoff for Sending: Pass…. to the Handoff Manager' agent. The Handoff Manager will do….. """
 
agent_manager = Agent(
    name="agent_name",
    instructions=main_instructions,
    tools=tools,
    handoffs=handoffs,
    model="gpt-4o-mini")
 
message = "add some message"
with trace("Automated SDR"):
    result = await Runner.run(agent_manager, message)    

Saturday, December 27, 2025

Agentic AI Frameworks - Crew AI, LangChain, and LangGraph

Crew AI Agentic Framework  

Overview of Crew AI Platform and Offerings: provided an overview of the Crew AI platform, distinguishing between Crew AI Enterprise, Crew AI UI Studio, and the open-source Crew AI Framework, and explained the team's focus on the open-source framework for building autonomous agents.

  • Crew AI Product offerings:
    • The Enterprise platform for hosting and deployment,
    • the UI Studio for low-code/no-code agent interaction design,
    • The open-source Crew AI Framework for building and orchestrating AI agents via code.
  • Monetization and Upselling: Crew AI, unlike OpenAI and Anthropic, generates revenue by selling its platform and tooling, which leads to upselling on its website to encourage users of the open-source toolkit to eventually pay for hosting and deployment.
  • Focus on Open-Source Framework:  the team's work will center on the open-source Crew AI Framework, as they are building agents programmatically and do not require the low-code tools or paid hosting features.

Core Concepts and Architecture of Crew AI:

  • Crew AI Concepts (Agents, Tasks, Crew): 
    • Agents are autonomous units associated with an LLM, defined by a role, goal, back story, and optionally memory and tools. An agent can be created using code.
    • Tasks are specific assignments with descriptions and expected outputs, assigned to agents. A task can be created using code.
    • A Crew is a collection of agents and tasks, forming the operational unit.
    • All the above come into crew.py
  • Process Modes: Sequential vs. Hierarchical: 
    • Crews can operate in sequential mode, executing tasks in order,
    • Crew can operate in hierarchical mode, where a manager LLM dynamically assigns tasks to agents, providing flexibility in workflow orchestration.
  • Crew AI Structure and Trade-offs: Crew AI enforces a more standard structure than some frameworks. Requiring explicit roles, goals, and backstories for agents encourages best-practice prompting but can reduce flexibility and make debugging more challenging.

Configuration and Project Structure in Crew AI: 

  • YAML-Based Configuration: Agents and tasks can be defined in YAML files, separating configuration from code and allowing for easier management and editing of prompts, roles, goals, back stories, and model assignments specified. The agents.yaml file was edited to define an agent.
  • Python Modules and Decorators: The crew.py module brings together agents, tasks, and crews using decorators such as @crew_base, @agent, @task, and @crew, streamlining the definition and instantiation of these components.
  • Directory Structure and Project Creation: Creating a new Crew AI project with 'crewai create crew ' generates a nested directory structure, including config folders for YAML files, a main.py for execution, and UV project files for environment management.
  • Project Execution Workflow: The project was run using 'crewai run', which executed the main.py module, processed the defined agents and tasks, and generated outputs, demonstrating the end-to-end workflow of a Crew AI project.
  • Model Integration and Flexibility: Crew AI's integration with Light LLM, highlighting its lightweight approach to connecting with various LLM providers and the ease of switching models within projects.
  • Light LLM Framework: Crew AI uses the Light LLM framework to interface with different LLM providers, allowing users to specify models by provider and model name, and supporting both cloud and local models with minimal configuration.

Advanced Features: Tools and Context Passing: 

  • Agent Tools Integration: Agents can be equipped with external tools, such as APIs, to enhance their capabilities.
  • Context Passing Between Tasks: Crew AI allows explicit control over what information is passed from one task to another, enabling more complex workflows and data dependencies within a crew.

Implementing Memory in Crew AI Projects: 
Memory is more context to prompt, and contextual information is provided to the LLM. Create and store in a variable, passing it while creating the task.  It has out-of-the-box features in Crew AI, so it is ready to use. Drawback: It has a learning curve
  • Memory Types Overview: five types of memory in Crew AI:
    • a. short-term - vector database for recent interactions
      • Temporarily stores interaction using vector DB
      • Get recent Information 
      • Outcome using RAG
      • enabling the agent to access relevant information 
    • b. long-term - SQL database for persistent knowledge
      • Interaction information is stored in the SQL DB
      • building knowledge for a long time
      • Store and learn, and build knowledge over a long time
    • c. entity memory - vector database for people, places, concepts
      • Information about People, Place, concept, store during task in vector DB/RAG DB
      • Maintained relationship mapping and stored it in the RAG DB.
    • d. contextual memory - umbrella term for the above
      • It is a superset of (a, b, and c)
      • It all can be queried and passed in as Context when prompting an LLM
      • Maintaining the context of interaction by combining all memory types.
    • user memory - user-specific, mostly manual
      • Stored user-specific information 
      • query user memory and insert it into the prompt or input at the right time
      • store and enhance personalization and user experience.
      • store user-specific information and preferences.
  • Technical Setup of Memory: The imported necessary classes for memory management, including long-term memory, short-term memory, entity memory, and storage classes for vector and SQL-based retrieval, were instantiated within the crew.py module.
  • Agent Configuration for Memory: Agents will configure with memory enabled; in certain agents, memory can be set to operate without memory. YAML prompts will be updated to leverage memory for context-aware recommendations.
  • Running and Verifying Memory Integration: Upon running the project, the creation of memory directories and databases, agents surfacing companies based on stored context, and noted the ease of setting up complex memory systems with minimal code.
Overview of Crew AI Framework Approaches: 
There are two main approaches within the Crew AI open-source framework: Crew AI Crews for autonomous agent teams and Crew AI Flows for stepwise workflows
  • Crew AI Crews: Crew AI Crews as a method for organizing autonomous solutions where multiple agents with different roles collaborate as a team, emphasizing the agentic and team-based nature of this approach.
  • Crew AI Flows: Crew AI Flows represent fixed workflows in which a problem is divided into multiple steps, with decision points and outcomes guiding the process in a deterministic manner. Building workflows using Crew AI Flows, directly calling LLMs, and interpreting their responses. the more complex, autonomous agent-based solutions
  • Usages: 
    • Crew AI Crews are recommended for autonomous problem solving, creative collaboration, or exploratory tasks.
    • Crew AI Flows are better suited for deterministic outcomes, auditability, or scenarios requiring precise control.
  • Why Crew AI Flows: Crew AI Flows were developed in response to concerns about uncertainty and lack of auditability in Crew AI. Production environments require more tightly defined workflows.
Challenges and Trade-Offs in Using Crew AI Framework: 
  • Debugging and Error Handling: 
    • error messages due to YAML formatting issues
    • The difficulty in diagnosing problems when using Crew AI's abstractions
    • emphasizing the need for careful configuration and awareness of hidden framework details.
Crew AI Implementation: 
  • Create Light LLM key --> LITELLM_MASTER_KEY, add this in cursor .env file
  • Install CrewAi in the cursor --> use the command uv tool install crewai
  • Before running CrewAI need follwings:
    • Insatll winget
  • Create a new project:
    • run command crewai create crew mytestcrew 
    • The above command will create a new directory structure.
      • Director name - mytestcrew 
        • src \ mytestcrew
          • Config
            • agents.yaml   #config for the crew AI agent
            • tasks.yaml     #config for the crew AI tasks
          • tools
          • crew.py                      #Model for Crew AI 
          • main.py                      #Run the Crew AI  projects
      • Note: Task and agent name should be the same.
  • Code for new project: 
    • src \ mytestcrew
        • Config

    §  agents.yaml

    mytestcrew:

      role: >

        Python Developer

      goal: >

        write python code to achieve this assignment: {assignment}

        First plan how the code will work, then write the code, then run it and check the output.

      backstory: >

        As a seasoned python developer with a knack for writing clean, efficient code.

      llm: gpt-4o-mini

    §  tasks.yaml

    test_task:

      description: >

        Write python code to achieve this: {assignment}

      expected_output: >

        A text file that includes the code itself, along with the output of the code.

      agent: mytestcrew

      output_file: output/code_and_output.txt

        • Tools
        • crew.py

    from crewai import Agent, Crew, Process, Task

    from crewai.project import CrewBase, agent, crew, task

     

    @CrewBase

    class Mytestcrew ():

        """ mytestcrew crew"""

     

        agents_config = 'config/agents.yaml'

        tasks_config = 'config/tasks.yaml'

     

        # One click install for Docker Desktop:

        #https://docs.docker.com/desktop/

     

     @agent

     def mytestcrew (self) -> Agent:

            return Agent(

                config=self.agents_config['coder'],

                verbose=True,

                allow_code_execution=True,

                code_execution_mode="safe",  # Uses Docker for safety

                max_execution_time=30,

                max_retry_limit=3

     )

    @task

    def test_task(self) -> Task:

         return Task(

             config=self.tasks_config['coding_task'],

      )

    @crew

     def crew(self) -> Crew:

         """Creates the Mytestcrew crew"""

       return Crew(

             agents=self.agents,

             tasks=self.tasks,

             process=Process.sequential,

              verbose=True,

        )

    §  main.py

    #!/usr/bin/env python

    import sys

    import warnings

    import os

    from datetime import datetime

    from mytestcrew.crew import Coder

     

    warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")

     

    # Create output directory if it doesn't exist

    os.makedirs('output', exist_ok=True)

     

    assignment = 'Write a python program to calculate the first 10,000 terms \

        of this series, multiplying the total by 4: 1 - 1/3 + 1/5 - 1/7 + ...'

     

    def run():

        """

        Run the crew.

        """

        inputs = {

            'assignment': assignment,

        }

        result = Mytestcrew().crew().kickoff(inputs=inputs)

        print(result.raw)

  • Run the newly created crew AI project: 
    • crewai run

Overview of LangChain, LangGraph, and LangSmith

LangChain LangChain is a framework for building applications powered by LLMs (Large Language Models). It helps developers connect language models with external data sources and tools. Modular framework for building LLM apps.

Key Features:

  • Chains: Combine multiple steps (e.g., prompt → model → output) into a workflow.
  • Agents: Enable LLMs to make decisions and utilize tools dynamically (e.g., calculators, search engines).
  • Memory: Store context across interactions for more personalized responses.
  • Integrations: Connects with APIs, databases, files, and other services.

LangGraph LangGraph is built on top of LangChain and is designed for creating stateful, multi-step workflows using a graph-based architecture. Extension for building statefulmulti-step, and dynamic workflows using LangChain. LangGraph builds on LangChain by introducing graph-based workflows, which allow for non-linearstateful, and dynamic execution paths.

Key Features:

  • Graph-based execution: Nodes represent steps, and edges define transitions.
  • State management: Keeps track of the conversation or task state across steps.
  • Looping and branching: Supports complex logic like retries, conditionals, and loops.

LangSmith - it is a developer platform created by the LangChain to help debug, test, andb monitor applications built with language models.

Key Features: LangSmith provides tools for:

  • Tracing: to see how LLM app executes step-by-step (prompts, responses, tool calls).
  • Debugging: Identify where issues arise in complex chains or agent workflows.
  • Evaluation: Run automated or manual tests to assess quality and reliability.
  • Monitoring: Track performance and usage over time in production environments.
·        Overview of Langchain Ecosystem: 

o   Langchain Purpose and Features: It is an early abstraction framework designed to simplify bespoke integrations with various LLM APIs, enabling easier switching between models and supporting advanced features such as RAG, prompt templates, and robust memory management.

o   Langraph and Capabilities: It is a separate offering within the ecosystem, providing a platform for stability, resiliency, and repeatability in complex agentic workflows, and is not dependent on Langchain.

Langraph consists of three components:

1.        the core framework,

2.        Langraph Studio (a visual builder)

3.        Langraph Platform (a hosted enterprise solution),

o   Langsmith: it is the monitoring tool within the ecosystem, providing visibility and debugging capabilities for both Langchain and Langraph workflows. It can be integrated as needed.

·        Langchain Concepts and Terminology: 

o   It is a framework for building applications provided by LLMs

o   Modular framework for building LLM apps

o   Langchain core features:

§  Chains:

§  Take user input,

§  Get context, combine multiple steps, call model, process it, call a tool/function.

§  Agents:

§  Allows LLMs to make decisions and use the tool

§  Memory:

§  Store context across interaction

§  Integration:

§  Integration connects the model to external systems (DB, API, etc.).

Notes: LangChain utilizes models to think, chains to structure tasks, and memory to recall past interactions, resulting in a smart, context-aware AI workflow.


Langraph Concepts and Terminology

      

Langraph is built on Langchain. Creating a stateful, multi-step Agentic workflow using a graph-based architecture. Dynamic workflow and dynamic execution flow. It is tree-like structures where nodes represent operations and edges determine the flow and conditional logic between nodes.
  •   Langraph core features
    • Nodes:
      • Nodes are Python functions that perform operations and return an updated state
      • Represents steps in a graph
      • This is Python code/function. It does the work
      • This also represents agent logic
      • Receive the current state as input, do the action, and return an updated state for the next steps 
    • Edges:
      • Edges determine the next node(s) to execute based on the current state, supporting both simple sequential and conditional transitions.
      • Define transitions between the nodes, it connected between the nodes. it explore what to do next.
      • This is Python code/function, this determine which nodes to execute next, based on the state 
      • It can be conditional or fixed 
    • State:
      • representing the current snapshot of the application.
      • It is variable; it is not a function 
      • passed between nodes and updated by returning new state objects rather than mutating existing ones, ensuring reliable tracking and reproducibility.
      • keep track of conversations/tasks across states 
      • It is an immutable object 
      • it return differeent state, different objects, and difefernt instance of state.
        • pass into the nodes as the current state
        •  It returns by node with the updated state.
  • Workflow Building Process: the five-step process for building a Langraph workflow:
    • State class: 
      • Defining the state class,
      • Class which going to store state
      • No need to create a state object
    • Starting the graph builder
      • layout all the nodes in the graph
      • It is defined initially 
    • Creating nodes
      • Create the function/Python code that is going to represent some operation 
      • Nodes should be connected to each other through edges 
    • Creating edges
      • Connects Nodes with edges
      • Repeat these steps with all nodes
      • The layout of the story for an agentic system should do. 
      •        All the above steps are upfront, which defines the agentic workflow
    • Compiling the graph before execution
      • Compile the graph 
    • Running the graph is the final step
        Emphasizing the separation between the graph definition and execution phases.

   

Reducers and State Field Management: 
  • Reducer Function Purpose: Reducers are special functions associated with state fields that define how to combine values when multiple nodes update the same field concurrently, preventing overwrites and ensuring correct aggregation of state changes.
    • Type of node that processes and updates the shared state of the graph
    • Takes a new state as input and returns a new state 
    • Centralized state updates 
    • After the nodes runs it logs the output 
    • Track progress, makes decision, update shared data 
    • Updates the current state and decides the next steps
    • Combine the updates; combine the updates from two nodes/agents
    • For each field in the state, the reducer function can be specified 
    • It returns a new state. Langraoh uses the Reducer to combine these fields with the existing state.
    • This enabled Langraph to run multiple Nodes concurrently and combine states without overwriting. 
    • Langraph can run multiple nodes at the same time. There is no risk, one Node run, and it overwrites the progress that a different Node made at the same time. This way it combines different states behind the scenes.
  • Reducers with Annotations: use Python's annotated type hints to specify reducers for state fields, such as using the built-in 'addmessages' reducer to concatenate lists of messages in the state object.
  • Reducer Usage: a state object with a 'messages' field uses the 'addmessages' reducer to aggregate messages from different nodes. Langraph manages state updates in multi-node workflows.
Building and Running Langraph Workflows: 
  • Defining State and Graph Builder: The process begins with defining a state object (using Pydantic models) and initializing the graph builder with the state class, not an instance, to start constructing the workflow.
  • Node and Edge Creation: Nodes are defined as Python functions that take the current state and return a new state, and are added to the graph builder; edges are then created to connect nodes, specifying the workflow's execution order and logic.
  • Graph Compilation and Visualization: After nodes and edges are defined, the graph is compiled, making it ready for execution, and visualized to confirm the workflow structure before running.
  • Execution with and without LLMs: running a simple workflow with a non-LLM node and then including an LLM node using Langchain's ChatOpenAI, invoking the graph, and processing results.
Anthropic's Perspective on Framework Abstraction:
  • Anthropic's Recommendations: Anthropic suggests developers start with direct LLM API usage, as many agentic patterns can be implemented with minimal code, and warns that frameworks may include underlying logic and introduce unnecessary complexity.
  • Contrast with Langraph: noted that Anthropic's approach differs from Langraph's, which emphasizes structured workflows and abstraction, and encouraged to keep these different approaches before exploration.
LangGraph Checkpoints:
  • In LangGraph, it saved a snapshot of Graphs state, so it can pause, resume, or recover a conversation workflow without starting over. It stores the state at a defined state.
  • Stores the immutable state at a given step
  • Add a checkpoint during the compilation of the Graphs
  • A message from top to bottom, which is going to LLM and the result coming back (end to end), it is one invocation of the whole graph
  • There might be more iteration each iteration is a single Invocation
  • Every time it invokes the Graph that is Super-step
    • Super-Step is a single iteration over the Graph Nodes; Nodes running in parallel are the same Super-Step
    • Every Invocation is a new Grap Invoke
      • Graph.Invoke(State).
    • The Reducer handles updating state during a Super-Step, not between Super-steps
LangGraph Asynchronous:

The graph can run nodes, edges, and tool calls without blocking, allowing the workflow to continue while waiting for slow operations. “Asynchronous LangGraph allow agent do other things while waiting for slow tasks to finish.”

Asynchronous details:
  • Steps can wait for slow operations (like API calls, tools, and web searches) without blocking everything. The event can continue working on another task while waiting. 
  • In LangGraph, using async nodes and async invoke /stream will allow
  • Call asynch tools/LLMs and Stream Calls
  • Handle multiple requests efficiently 
  • A graph can run multiple steps at sametime.
  • It allows multiple nodes to run in parallel
  • Dependent nodes only run when their input is ready
  • Makes graph faster and more efficient, specifically when calling API or DB

Asynchronous capability

  • Nodes can run async Python functions (async def)
  • The graph can wait for external APIs, tools, or LLM calls without freezing
  • Supports streaming, parallel branches, and real‑time updates
  • Multiple tasks can run in parallel or concurrently, faster execution
  • Long‑running workflows stay responsive. Better performance for I/O‑heavy tasks
  • Perfect for agents, tool‑calling, retrieval, and multi‑step reasoning
  • Enables non‑blocking agent loops and tool calls

Asynchronous use cases

  • Calling multiple APIs at once
  • Running parallel LLM evaluations
  • Streaming intermediate reasoning
  • Handling long‑running workflows without blocking
Asynchronous LangGraph Example:
To run a tool:
    Sync: tool.run(inputs)
    Async: await tool.arun(inputs)
To invoke the graph:
    Sync: graph.invoke(state)
    Async: await graph.ainvoke(state)

Notes:

  • Synch: Steps run one after another(sequential). Each steps block until it is done 
Langgraph Implementation
  • Example 1:

Step1: Define the State object: any python object can be use; most common to use a TypedDict/Pydantic BaseModel.
    class State(BaseModel):
       messages: Annotated[list, add_messages]

Step 2: Start the Graph Builder with this State class
    graph_builder = StateGraph(State)
 
Step 3: Create a Node, a node can be any python function.  The reducer that we set before gets automatically called to combine this response with previous responses
    def our_first_node(old_state: State) -> State:
        reply = f"{random.choice(nouns)} are {random.choice(adjectives)}"
        messages = [{"role": "assistant", "content": reply}]
        new_state = State(messages=messages)
        return new_state
    graph_builder.add_node("first_node", our_first_node)
 
Step 4: Create Edges
    graph_builder.add_edge(START, "first_node")
    graph_builder.add_edge("first_node", END)
 
Step 5: Compile the Graph
    graph = graph_builder.compile()
    display(Image(graph.get_graph().draw_mermaid_png()))
 
Step 6: running the workflow
    def chat(user_input: str, history):
       message = {"role": "user", "content": user_input}
        messages = [message]
        state = State(messages=messages)
        result = graph.invoke(state)
        print(result)
        return result["messages"][-1].content
    gr.ChatInterface(chat, type="messages").launch() 

  • Example2:
from langchain_community.agent_toolkits import PlayWrightBrowserToolkit
from langchain_community.tools.playwright.utils import create_async_playwright_browser
  • Tools (Playwright Browser Tools):  Tools are external capabilities the agent can call.
These tools include:
  • navigate_browser → open a webpage
  • extract_text → scrape text
  • Tools are actions the agent can take.
  • It is not nodes themselves — they are used by nodes.
  • it run asynchronously, which is perfect for browser automation.
async_browser =  create_async_playwright_browser(headless=False# headful mode
toolkit = PlayWrightBrowserToolkit.from_browser(async_browser=async_browser)
tools = toolkit.get_tools()
for tool in tools:
    print(f"{tool.name}={tool}")
tool_dict = {tool.name:tool for tool in tools}
 
navigate_tool = tool_dict.get("navigate_browser")
extract_text_tool = tool_dict.get("extract_text")
 
await navigate_tool.arun({"url": "https://www.cnn.com"})
text = await extract_text_tool.arun({})
import textwrap
print(textwrap.fill(text))
all_tools = tools + [tool_push]
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools(all_tools)
  • Node: chatbot: Nodes are Python functions that receive the current state and return an updated state. chatbot 

    node:

    Reads the current messages from state
    • Sends current state to the LLM
    • The LLM may decide to call a tool
    • Returns updated messages/state
    • This is a Node that performs reasoning.
    • It is the “brain” of the workflow.
    • It uses the LLM with tool binding, so the LLM can call Playwright tools

def chatbot(state: State):
    return {"messages": [llm_with_tools.invoke(state["messages"])]}

  • GraphBuilder: This is where it assemble the workflow.
    • Registers nodes, defines edges, and defines routing logic
    • Builds the execution graph. This is the “blueprint” of an agent.
    • defining the agent’s brain + tools + flow. 
graph_builder = StateGraph(State)
graph_builder.add_node("chatbot", chatbot)
  • Node: tools (ToolNode): LangGraph provides a built‑in node that executes tool calls. 
    • Receives a tool call request from the LLM
    • Executes the correct tool (navigate, extract_text, etc.)
    • Returns the result back into the state
    • This is the action node. It performs real-world operations.
    • It runs asynchronously (important for browser automation) 
graph_builder.add_node("tools", ToolNode(tools=all_tools)) 

  • Conditional Edges (Routing Logic): Edges decide which node runs next.
    • After the chatbot runs, LangGraph checks tools_condition.
    • If the LLM requested a tool → go to the tools node.
    • If not → skip the tools node.
    • Edges define the flow of the agent.
    • Conditional edges = branching logic.
    • Fixed edges = sequential steps.

graph_builder.add_conditional_edges( "chatbot", tools_condition, "tools") //Conditional Edges
graph_builder.add_edge("tools", "chatbot") //Fixed edge: after tools run, always return to the chatbot
graph_builder.add_edge(START, "chatbot") 
memory = MemorySaver()

  • Compilation: It turns the blueprint into a runnable graph. 
    • Validates nodes and edges, Builds the execution engine
    • Enables async execution
    • Enables checkpointing (memory)
    • It transforms created graph definition into an executable agent.
    • It also enables async execution and state persistence.

graph = graph_builder.compile(checkpointer=memory)
display(Image(graph.get_graph().draw_mermaid_png()))
config = {"configurable": {"thread_id": "10"}}
 
async def chat(user_input: str, history):

    • State: State is the immutable snapshot of the conversation. 
      • State contains:
      • Messages
      • Tool call results
      • LLM outputs
      • Thread ID (for memory)
      • State is passed between nodes.
      • Nodes return a new state, not modify the old one.

    result = await graph.ainvoke({"messages": [{"role": "user", "content": user_input}]}, config=config)

  • Asynchronous Execution: entire workflow is async:
    • Playwright browser tools are async. ToolNode supports async
    • graph.ainvoke() runs the graph asynchronously
    • The chat interface awaits the result
    • Browser automation is slow → async prevents blocking
    • LLM calls are slow → async keeps the graph responsive
    • Tools can run concurrently
    • Async nodes = non-blocking agent execution

    return result["messages"][-1].content
gr.ChatInterface(chat, type="messages").launch()