> ## Documentation Index
> Fetch the complete documentation index at: https://genai.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction to LangChain

> Why LangChain, project setup with uv, and connecting to model providers

## 💻 Practice Notebook

Master the concepts from this page with hands-on practice:
[💻 VS Code](vscode://file/Users/sivaprasad/Downloads/GenAI%20With%20Python/public/notebooks/prompt-engg/prompt-engg-practice-vscode.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/master/public/notebooks/prompt-engg/prompt-engg-practice-colab.ipynb) | <a href="/public/notebooks/prompt-engg/prompt-engg-practice-vscode.ipynb" download>📥 Download Notebook</a>

Large Language Models (LLMs) have transformed how we build software. However, building production-grade GenAI applications requires orchestration. This module introduces the fundamentals of LangChain, explains the problems it solves, and walks you through setting up a modern GenAI project.

### 1. Traditional vs. GenAI Applications

Building applications with Generative AI requires a paradigm shift from traditional software development:

| Aspect           | Traditional Software                                                    | GenAI Applications                                                                                  |
| ---------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| **Logic**        | Deterministic and rule-based (defined by code loops, `if-else` blocks). | Probabilistic (guided by LLM semantic reasoning and prompts).                                       |
| **Input/Output** | Structured data (JSON, databases, arguments).                           | Unstructured natural language (text, speech, images).                                               |
| **Execution**    | Consistent and predictable; same inputs yield exact same outputs.       | Dynamic; outputs can vary (non-deterministic) depending on context, temperature, and model updates. |

### 2. Two Kinds of GenAI Applications

LLM-powered systems are generally categorized into two workflow architectures:

1. **Sequential Workflows (Deterministic)**:
   The execution path is hardcoded and predefined by the developer. The inputs and outputs flow sequentially from one step to another.
   * **Common Frameworks**:
     * **LangChain**: Uses **LCEL (LangChain Expression Language)** to chain prompts, models, and parsers.
     * **LlamaIndex**: Uses **Query Engines** and **Ingestion Pipelines** for structured data connections.
     * **Haystack**: Uses a directed acyclic graph (DAG) structure to orchestrate pipelines.
     * **Semantic Kernel**: Microsoft's orchestration SDK using sequential pipelines.
   * **Why**: These frameworks are designed to compose linear pipelines with built-in support for streaming, batching, and asynchronous execution. This ensures predictable runtime pathways, leaving control flow decisions entirely in the code structure rather than the model's logic.
2. **Agentic Workflows (Autonomous)**:
   The LLM operates as an autonomous decision-maker inside a stateful loop, dynamically determining its own path of execution.
   * **Common Frameworks**:
     * **LangGraph**: LangChain's framework for building stateful, multi-agent systems via state graphs.
     * **CrewAI**: A framework focused on orchestrating role-playing autonomous agent teams.
     * **Microsoft AutoGen**: An open-source framework for building multi-agent conversational applications.
     * **LlamaIndex Workflows**: An event-driven framework for building complex agentic loops.
   * **Why**: Predefined sequences cannot address complex, open-ended tasks. These frameworks allow developers to define stateful loops, branching conditions, and human-in-the-loop steps where the model utilizes tools (e.g., executing Python, querying databases) and decides its next action dynamically based on environment feedback.

### 3. The Challenges of Raw API Integrations

Directly writing code against raw LLM provider APIs (like OpenAI, Google, or Anthropic) introduces several challenges in real-world software engineering:

* **API Fragmentation**: Every model provider has its own proprietary SDK, request payload structure, and response format. Switching providers means rewriting your entire code integration.
* **Complex Pipeline Orchestration**: Real-world GenAI applications rarely rely on a single API call. They require linking prompts, vector search retrievers, output parsers, and custom tools in sequence.
* **State & Memory Management**: LLMs are stateless by design. Developers must manually manage conversation history and context window limits.

#### How Orchestration Frameworks Address These Challenges

Orchestration frameworks (such as LangChain, LlamaIndex, and Haystack) act as a **unified abstraction layer** over raw model APIs to streamline production development:

1. **Standardized Interfaces**: They establish generic, reusable classes for core components (like models, prompts, and output parsers). This allows developers to swap underlying LLM providers (e.g., swapping OpenAI for Gemini) with minimal or no code changes.
2. **Declarative Pipelines**: They offer compositional syntaxes (e.g., LangChain's LCEL or LlamaIndex Workflows) to easily link prompts, data retrievers, model calls, and parsers into end-to-end pipelines.
3. **Modular Ecosystems**: They decouple core orchestration classes from third-party integrations, allowing developers to import lightweight packages and scale applications modularly without carrying bloated, unused dependencies.
4. **Built-in State & Memory Management**: They provide native utilities to automatically capture conversation history, summarize long contexts, and maintain persistent states across stateless LLM API calls.

### 4. Direct APIs vs. LangChain

To understand why LangChain is needed, let's compare direct API integrations for three popular providers (OpenAI, Gemini, Hugging Face) against LangChain's unified syntax.

#### 3.1 Direct Provider APIs (Fragmentation)

Every provider requires a unique SDK, setup protocol, and response extraction syntax:

##### OpenAI Direct API

```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="your_openai_key")

res = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What is Python?"}]
)
## Accessing content requires deep nesting:
print(res.choices[0].message.content)
```

##### Google Gemini Direct API

```python theme={null}
import google.generativeai as genai
genai.configure(api_key="your_gemini_key")
model = genai.GenerativeModel("gemini-2.5-flash")

res = model.generate_content("What is Python?")
## Accessing content uses .text:
print(res.text)
```

##### Hugging Face Inference API

```python theme={null}
import requests
API_URL = "https://api-inference.huggingface.co/models/gpt2"
headers = {"Authorization": "Bearer your_hf_token"}

res = requests.post(API_URL, headers=headers, json={"inputs": "What is Python?"})
## Accessing content requires list/dictionary parsing:
print(res.json()[0]['generated_text'])
```

#### 3.2 LangChain's Simplified & Unified Syntax

LangChain unifies all these disparate APIs behind a single interface. Switching between providers only requires changing model configuration variables:

```python theme={null}
from langchain.chat_models import init_chat_model

## Standardized Initialization:
llm = init_chat_model("gemini-2.5-flash", model_provider="google_genai")
## To switch to OpenAI: llm = init_chat_model("gpt-4o", model_provider="openai")
## To switch to Groq: llm = init_chat_model("llama-3.3-70b-versatile", model_provider="groq")

## Standardized Invocation & Response Extraction (.content)
response = llm.invoke("What is Python?")
print(response.content)
```

### 5. Main LangChain Modules & Capabilities

LangChain provides modular components (services) to construct custom GenAI applications:

* **Chat Models**: A standardized interface to interact with various LLM providers (e.g., OpenAI, Google Gemini, Anthropic) using a consistent messaging format.
* **Prompt Templates**: Utilities to dynamic construct, manage, and format instructions with raw variables before sending them to the LLM.
* **Output Parsers**: Tools to parse raw LLM string responses into structured formats (e.g., JSON, Pydantic objects, or lists) reliably.
* **LCEL (LangChain Expression Language)**: A declarative composition engine to chain models, prompts, retrievers, and parsers together with automatic streaming and async support.
* **Document Loaders & Vector Stores**: Tools to read unstructured data from files (PDF, CSV, HTML) and index them in vector databases for RAG retrieval.
* **Tools (Function Calling)**: Interfaces that allow LLMs to interact with external services (e.g., executing Python code, calling web APIs, or running SQL queries).
* **Agents (LangGraph)**: Autonomous state loop systems where the LLM evaluates user inputs, decides which tools to call, inspects outcomes, and refines actions.
* **Memory**: Utilities to persist and manage conversation history across stateless API transactions.

#### 5.1 Library Architecture & Segregation

To remain lightweight and avoid bloated installations, LangChain segregates its codebase into distinct packages:

* **Core Abstractions (`langchain-core`)**: Holds the base interfaces and common definitions and the LCEL execution engine. This contains zero third-party integrations and is extremely lightweight.
  * *Example Classes*: `ChatPromptTemplate`, `StrOutputParser`, `RunnableSequence`, `SystemMessage`.
* **Proprietary & Partner Packages (First-Party)**: Specific, lightweight wrappers built for proprietary providers. These are maintained directly by partner teams to guarantee API compatibility and high performance.
  * *Example Classes*: `ChatGoogleGenAI` (`langchain-google-genai`), `ChatOpenAI` (`langchain-openai`), `ChatAnthropic` (`langchain-anthropic`).
* **Third-Party Integrations (`langchain-community`)**: Holds all community-supported integrations for external vector databases, document loaders, and custom tools. This is loaded separately so developers only pull integrations they actively use.
  * *Example Classes*: `Chroma` (vector store), `PyPDFLoader` (loader), `TavilySearchResults` (search tool).

#### 5.2 Application Workflows & Module Mapping

Different GenAI application architectures utilize specific combinations of these modules:

| Application Pattern               | Target Goal                                 | Key Modules & Libraries Used                                                                    |
| :-------------------------------- | :------------------------------------------ | :---------------------------------------------------------------------------------------------- |
| **Conversational Chatbot**        | Maintain multi-turn dialogue with users     | `Chat Models` + `Prompt Templates` + `Memory` (`langchain-core`)                                |
| **Retrieval-Augmented Gen (RAG)** | Ground answers in proprietary documents     | `Chat Models` + `Document Loaders` + `Vector Stores` (`langchain-community` & partner packages) |
| **Autonomous Agent**              | Solve open-ended tasks using external tools | `Chat Models` + `Tools` (Function Calling) + `State Graphs` (`LangGraph`)                       |

### 6. Setting Up a GenAI Project (Step-by-Step)

We will use **`uv`**, a fast, modern package and project manager for Python, to set up our application.

#### Step 6.1: Initialize the Project & Virtual Environment

Open your terminal and run the following commands:

```bash theme={null}
## Initialize a new project directory
uv init genai-app
cd genai-app

## Create and activate a virtual environment
uv venv
source .venv/bin/activate
```

#### Step 6.2: Add Dependencies

Add the core LangChain package, provider integration packages, and a library to read environment variables:

```bash theme={null}
## Add LangChain core and provider-specific integrations
uv add langchain-core langchain-groq langchain-google-genai python-dotenv
```

#### Step 6.3: Set Up Your Keys (`.env`)

Create a file named `.env` in the root of your project directory and add your API keys:

```ini theme={null}
## Groq API Key (Fast inference for open models)
GROQ_API_KEY=gsk_your_groq_api_key_here

## Google Gemini API Key
GOOGLE_API_KEY=AIzaSyYourGeminiApiKeyHere
```

#### Step 6.4: Load Environment Variables in Python

To read the keys from your `.env` file and make them available to your application:

1. Import `load_dotenv` from the `dotenv` library.
2. Call `load_dotenv()` at the very start of your python script.

```python theme={null}
from dotenv import load_dotenv

# Search and load keys from the local .env file
load_dotenv()
```

This loads your secret API keys into Python's `os.environ` system dictionary. LangChain automatically looks for variables named `GROQ_API_KEY` and `GOOGLE_API_KEY` in `os.environ`, allowing you to initialize models without hardcoding credentials in your source code.

### 7. Initializing and Calling Models

Here is how to write python scripts to call either Groq or Google Gemini using LangChain.

#### 7.1 Initializing with Groq

```python theme={null}
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

## Load variables from .env
load_dotenv()

## Initialize the Groq model
llm = init_chat_model(
    "llama-3.3-70b-versatile",
    model_provider="groq"
)

## Invoke the model
response = llm.invoke("Explain why developers use virtual environments in Python.")
print(response.content)
```

#### 7.2 Initializing with Google Gemini

```python theme={null}
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

## Load variables from .env
load_dotenv()

## Initialize the Gemini model
llm = init_chat_model(
    "gemini-2.5-flash",
    model_provider="google_genai"
)

## Invoke the model
response = llm.invoke("What is the difference between concurrency and parallelism?")
print(response.content)
```

> \[!NOTE]
> When using `init_chat_model`, LangChain automatically detects the `GROQ_API_KEY` or `GOOGLE_API_KEY` from your environment variables.

### 8. Practice Exercises

#### Practice 1: Dual-Provider Setup & Comparison

Write a script that loads environment variables, prompts **both** Groq (`llama-3.3-70b-versatile`) and Google (`gemini-2.5-flash`) with the question `"State the main goal of prompt engineering in 5 words."`, and prints the response from each model.

<Accordion title="Solution">
  ```python theme={null}
  import os
  from dotenv import load_dotenv
  from langchain.chat_models import init_chat_model

  ## Load environment variables
  load_dotenv()

  ## Initialize Groq
  groq_llm = init_chat_model(
      "llama-3.3-70b-versatile",
      model_provider="groq"
  )

  ## Initialize Gemini
  gemini_llm = init_chat_model(
      "gemini-2.5-flash",
      model_provider="google_genai"
  )

  prompt = "State the main goal of prompt engineering in 5 words."

  print("--- Groq Response ---")
  print(groq_llm.invoke(prompt).content.strip())

  print("\n--- Gemini Response ---")
  print(gemini_llm.invoke(prompt).content.strip())
  ```
</Accordion>

### Summary

* **GenAI Architectures**: Workflows are categorized into deterministic **Sequential Workflows** (suited for predictable tasks using frameworks like LCEL) and autonomous **Agentic Workflows** (suited for complex tasks using state loops like LangGraph).
* **Orchestration Frameworks**: Solve challenges of raw API integration (API fragmentation, complex pipeline orchestration, and stateless memory management) by offering unified abstraction layers.
* **Ecosystem Segregation**: LangChain segregates packages into `langchain-core` (base classes), partner packages (first-party proprietary APIs), and `langchain-community` (third-party tools) to keep dependencies lightweight.

### Practice Notebooks

Master all the concepts from this module with hands-on practice:

* **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](vscode://file/Users/sivaprasad/Downloads/GenAI%20With%20Python/public/notebooks/prompt-engg/prompt-engg-practice-vscode.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/master/public/notebooks/prompt-engg/prompt-engg-practice-colab.ipynb) | <a href="/public/notebooks/prompt-engg/prompt-engg-practice-vscode.ipynb" download>📥 Download Notebook</a>
