Module 1: Anatomy of an AI Agent

6. Framework Landscape 2025-2026

Capsule description

In 2025-2026, the ecosystem of frameworks for building AI agents exploded. LangChain/LangGraph, Pydantic AI, CrewAI, AutoGen, Semantic Kernel, OpenAI Agents SDK — each with a different philosophy, real trade-offs, and a community insisting that "their" framework is the right one. If you read Twitter or Reddit, it seems like every week there's a new framework that "replaces" the previous one. The result: framework fatigue — decision paralysis before writing a single line of code.

This capsule gives you judgment to choose, not propaganda to convince you. You'll understand each framework's design philosophy, its real strengths, its real weaknesses, and the contexts where each one makes sense. It's not a tutorial for each framework — their official docs handle that. It's a positioning map that lets you make informed decisions.

This guide uses LangChain/LangGraph as its main framework. That doesn't mean it's "better" — it means it has the most mature ecosystem, the deepest integration with LangSmith for observability, and the largest community in production. But you'll see exactly where it hurts (complexity, abstractions that change), and you'll understand why Pydantic AI, which you'll explore in depth in Module 10, exists as an answer to those pain points.


The Real Problem: It's Not Technical, It's Judgment

Before getting into specific frameworks, let's name the elephant in the room: most teams don't pick the wrong framework for technical reasons. They pick wrong because of:

  • Hype: "I saw a thread on Twitter saying X is better"
  • Familiarity: "I already know Python, I'll go with the one with the most GitHub stars"
  • Fear of switching: "We started with X 3 months ago, it's too late now"
  • Feature-chasing: "This framework has multi-agent built in, that one doesn't"

The reality is that all of these frameworks can build working agents. The difference lies in how well they fit your context: team size, system complexity, observability needs, type-safety requirements, and existing stack.


The Frameworks: Philosophy and Reality

LangChain / LangGraph

Versions: LangChain v0.3+ / LangGraph v0.3+ Language: Python (primary), JavaScript/TypeScript Creator: LangChain Inc. (Harrison Chase) First release: October 2022 (LangChain), January 2024 (LangGraph)

Philosophy: A complete, composable ecosystem. LangChain provides the pieces (models, tools, prompts, parsers) and LangGraph orchestrates them as state graphs. The idea is that you don't build from scratch — you compose pre-existing components.

Real strengths:

  • 🟢 Ecosystem: 100+ official integrations (models, vector stores, tools). If an AI service exists, it probably has a LangChain wrapper
  • 🟢 LangSmith: Built-in observability — tracing, evaluation, datasets, playground. It's the strongest competitive advantage
  • 🟢 LangGraph: State machines for agents with typed state, conditional routing, checkpointing, and human-in-the-loop. The most production-ready option for complex flows
  • 🟢 Community: The largest. Stack Overflow, Discord, GitHub issues — if you have a problem, someone already had it
  • 🟢 MCP: Official integration with the Model Context Protocol since 2024
  • 🟢 Documentation: Extensive, with tutorials, how-to guides, and conceptual docs kept separate

Real weaknesses:

  • 🔴 Complexity: The learning curve is real. Understanding LCEL, runnables, RunnablePassthrough, RunnableLambda takes time
  • 🔴 Abstractions that change: The API has had significant breaking changes (from AgentExecutor to LangGraph). Migrating legacy code hurts
  • 🔴 Over-abstraction: For simple tasks, LangChain adds layers you don't need. A 3-step chain has more boilerplate than doing it directly with the model's SDK
  • 🔴 Debugging: When something fails inside a chain of runnables, the stack trace can be cryptic without LangSmith
  • 🔴 Conceptual vendor lock-in: You learn "LangChain patterns" that don't transfer directly to other frameworks

In code — creating an agent:

from dotenv import load_dotenv
load_dotenv()

from langchain.chat_models import init_chat_model
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

@tool
def search_web(query: str) -> str:
    """Searches the web for current information."""
    return f"Results for '{query}': AI agents market growing 40% YoY."

@tool
def calculator(expression: str) -> str:
    """Calculates mathematical expressions."""
    try:
        return str(eval(expression))
    except Exception as e:
        return f"Error: {e}"

model = init_chat_model("openai:gpt-4.1-mini")
agent = create_react_agent(model, [search_web, calculator])

result = agent.invoke({"messages": [("user", "What's the AI agents market and that value divided by 5?")]})
print(result["messages"][-1].content)

What happens underneath: create_react_agent creates a StateGraph with a "call the model" node and an "execute tools" node, connected by conditional edges. The state is the messages. The graph cycles until the model stops requesting tools.


Pydantic AI

Version: v0.1+ (pre-1.0, under active development) Language: Python Creator: Samuel Colvin (creator of Pydantic) First release: November 2024

Philosophy: Type-safe, dependency injection, minimal magic. If Pydantic revolutionized data validation in Python, Pydantic AI wants to do the same for agents: code that is explicit, validated at compile time (with mypy/pyright), and free of unnecessary abstraction layers.

Real strengths:

  • 🟢 Type safety: Agents have explicit types for input, output, and dependencies. Type errors get caught before you run
  • 🟢 Dependency injection: Dependencies (DB connections, API clients) are injected cleanly — not as global variables
  • 🟢 Readable code: Less "magic" than LangChain. A Pydantic AI agent reads like ordinary Python
  • 🟢 Native validation: The agent's output is validated against a Pydantic model. If the LLM returns garbage, validation fails explicitly
  • 🟢 Logfire integration: Observability via Pydantic Logfire (from the same team)
  • 🟢 Familiar: If you already use Pydantic (FastAPI, etc.), the mental model transfers directly

Real weaknesses:

  • 🔴 Small ecosystem: Few integrations compared to LangChain. There's no equivalent to the 100+ official integrations
  • 🔴 Pre-1.0: The API may change. Not recommended for critical production without a migration plan
  • 🔴 Limited multi-agent: It has no native abstractions for multi-agent orchestration like LangGraph
  • 🔴 MCP: Support is under development, not at LangChain's level of integration
  • 🔴 Smaller community: Fewer examples, fewer answers in forums, less educational content
  • 🔴 State management: No equivalent to LangGraph's checkpointing/durable execution

In code — the same agent:

from dotenv import load_dotenv
load_dotenv()

from pydantic_ai import Agent

agent = Agent(
    "openai:gpt-4o-mini",
    system_prompt="You are a helpful research assistant.",
)

@agent.tool_plain
def search_web(query: str) -> str:
    """Searches the web for current information."""
    return f"Results for '{query}': AI agents market growing 40% YoY."

@agent.tool_plain
def calculator(expression: str) -> str:
    """Calculates mathematical expressions."""
    try:
        return str(eval(expression))
    except Exception as e:
        return f"Error: {e}"

result = agent.run_sync("What's the AI agents market and that value divided by 5?")
print(result.output)

The philosophical difference is visible: in LangChain, tools are defined with @tool and passed to the agent. In Pydantic AI, tools are registered directly on the agent with @agent.tool_plain. The agent "owns" its tools. There are no intermediate runnables or LCEL.


CrewAI

Version: v0.80+ Language: Python Creator: João Moura First release: December 2023

Philosophy: Multi-agent as the primary abstraction. Instead of thinking in graphs or loops, you think in roles (Agent), tasks (Task), and teams (Crew). The metaphor is a human team: the researcher researches, the writer writes, the reviewer reviews.

Real strengths:

  • 🟢 Intuitive abstraction: "A crew of 3 agents with roles" is easier to explain to non-technical stakeholders
  • 🟢 Native multi-agent: You don't need to build the orchestration — it comes built in
  • 🟢 Delegation: One agent can delegate sub-tasks to another agent on the team
  • 🟢 Fast for prototypes: You can have a working multi-agent system in <50 lines

Real weaknesses:

  • 🔴 Less fine-grained control: If you need precise flow control (conditional edges, subgraphs, checkpointing), CrewAI is more limited
  • 🔴 Opinionated: The "crew" abstraction imposes a structure that doesn't always fit the problem
  • 🔴 Observability: Less integration with tracing tools compared to LangSmith
  • 🔴 Debugging: When an agent in the crew fails, understanding why can be hard
  • 🔴 Production: Less battle-tested at scale than LangGraph

AutoGen (Microsoft)

Version: AutoGen v0.4+ (significant rewrite) Language: Python, .NET Creator: Microsoft Research First release: September 2023

Philosophy: Agents as participants in conversations. The central pattern is that multiple agents "talk" to each other to solve a task. Each agent can be an LLM, a human, or a tool executor.

Real strengths:

  • 🟢 Conversational patterns: GroupChat, timed rotations, speaker selection — abstractions for multi-agent conversations
  • 🟢 Human-in-the-loop: Designed from day one to include human participation in the flow
  • 🟢 Code execution: Built-in sandbox so agents can generate and run code
  • 🟢 Research-grade: Microsoft Research papers backing the patterns

Real weaknesses:

  • 🔴 Unstable API: v0.4 was a major rewrite. The API is still in flux
  • 🔴 Production: More oriented to research and prototypes than enterprise production
  • 🔴 Complexity: Configuring multi-agent conversations can get verbose
  • 🔴 Documentation: Uneven — some parts are well documented and others have gaps

Semantic Kernel (Microsoft)

Version: v1.0+ (Python), v1.0+ (C#) Language: C#, Python, Java Creator: Microsoft First release: March 2023

Philosophy: A multi-language enterprise SDK. If your organization lives in the Microsoft ecosystem (Azure OpenAI, .NET, Azure AI Services), Semantic Kernel is the official "glue." The central concept is plugins — functions the kernel can invoke.

Real strengths:

  • 🟢 Genuinely multi-language: C#, Python, Java with consistent APIs. Rare in this space
  • 🟢 Azure integration: Native integration with Azure OpenAI, Azure AI Search, Azure Functions
  • 🟢 Enterprise: Designed for corporate contexts with governance, logging, compliance
  • 🟢 Stability: v1.0 with a backwards-compatibility commitment from Microsoft

Real weaknesses:

  • 🔴 Python is second-class: The C# experience is significantly better than the Python one
  • 🔴 Closed ecosystem: The advantages shine with Azure. Without Azure, you lose much of the value
  • 🔴 Less agent-native: Semantic Kernel is more of an "AI SDK" than an "agent framework." The agent abstractions are added on, not the core
  • 🔴 Small Python community: The strong community is in C#/.NET

OpenAI Agents SDK

Version: v0.1+ (very recent) Language: Python Creator: OpenAI First release: March 2025

Philosophy: OpenAI's framework for building multi-turn agents with their models. Central concepts: Agent (an LLM with instructions), Handoffs (transfer between agents), Guardrails (validations), and built-in Tracing.

Real strengths:

  • 🟢 Direct integration: Optimized for OpenAI models — works without intermediate wrappers
  • 🟢 Handoffs: An elegant pattern for transferring conversations between specialized agents
  • 🟢 Built-in tracing: Observability with no extra configuration
  • 🟢 Simplicity: A clean, minimal API

Real weaknesses:

  • 🔴 Very new: Launched March 2025. Little production history
  • 🔴 Vendor lock-in: Designed for OpenAI models. Using Anthropic, Google, or others requires workarounds
  • 🔴 Limited ecosystem: Few integrations with external tools and services
  • 🔴 No state machines: No equivalent to LangGraph for complex flows with persistent state
  • 🔴 Emerging community: Few examples, blog posts, and documented use cases

Comparison

General table

CriterionLangChain/LangGraphPydantic AICrewAIAutoGenSemantic KernelOpenAI Agents SDK
PhilosophyComposable ecosystemType-safe, minimalNative multi-agentMulti-agent conversationsEnterprise multi-langSimplicity + handoffs
Primary languagePythonPythonPythonPython, .NETC#, Python, JavaPython
MaturityHigh (2022+)Low (2024, pre-1.0)Medium (2023+)Medium (2023+, API rewritten)High (2023+, v1.0)Very low (2025)
Ecosystem/IntegrationsVery large (100+)SmallMediumMediumLarge (Azure)Small
Complexity / CurveHighLowMediumMedium-HighHighLow
Multi-agentYes (LangGraph)LimitedYes (core)Yes (core)YesYes (handoffs)
State managementStrong (checkpointing)BasicMediumMediumMediumBasic
ObservabilityLangSmith (built in)LogfireBasicBasicAzure MonitorBuilt-in tracing
Type safetyMediumHighMediumLowMediumMedium
MCP supportOfficialIn developmentCommunityNot officialIn developmentNo
Production-readyYes (widely used)ExperimentalPartialPartialYes (enterprise)Experimental
CommunityVery largeGrowingLargeMediumLarge (C#)Emerging

How to read this table

No framework wins every category. If one existed that was mature, simple, type-safe, with a large ecosystem, native multi-agent, and production-ready — everyone would use it. The reality is that each framework makes trade-offs:

  • LangChain/LangGraph sacrifices simplicity for ecosystem and observability
  • Pydantic AI sacrifices ecosystem for type safety and clean code
  • CrewAI sacrifices fine-grained control for ease in multi-agent
  • AutoGen sacrifices API stability for advanced research patterns
  • Semantic Kernel sacrifices Python community for multi-language enterprise support
  • OpenAI Agents SDK sacrifices maturity and vendor-neutrality for direct OpenAI integration

Comparative Code: The Same Agent in LangChain vs Pydantic AI

So you can see the philosophical difference in practice, here's the same simple agent implemented in both frameworks. The agent has a search tool and answers questions.

LangChain/LangGraph

from dotenv import load_dotenv
load_dotenv()

from langchain.chat_models import init_chat_model
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

@tool
def get_weather(city: str) -> str:
    """Gets the current weather for a city."""
    data = {"Madrid": "22°C, sunny", "Barcelona": "20°C, cloudy"}
    return f"Weather in {city}: {data.get(city, '18°C, partly cloudy')}"

model = init_chat_model("openai:gpt-4.1-mini")
agent = create_react_agent(model, [get_weather])

result = agent.invoke({"messages": [("user", "What's the weather like in Madrid?")]})
print(result["messages"][-1].content)
# Output: In Madrid the weather is 22°C and sunny.

Visible characteristics: The tool is defined with @tool. The model is initialized via init_chat_model. The agent is created with create_react_agent. Input and output are dicts with messages.

Pydantic AI

from dotenv import load_dotenv
load_dotenv()

from pydantic_ai import Agent

agent = Agent(
    "openai:gpt-4o-mini",
    system_prompt="You are a weather assistant.",
)

@agent.tool_plain
def get_weather(city: str) -> str:
    """Gets the current weather for a city."""
    data = {"Madrid": "22°C, sunny", "Barcelona": "20°C, cloudy"}
    return f"Weather in {city}: {data.get(city, '18°C, partly cloudy')}"

result = agent.run_sync("What's the weather like in Madrid?")
print(result.output)
# Output: In Madrid the weather is 22°C and sunny.

Visible characteristics: The tool is registered directly on the agent with @agent.tool_plain. There's no "model" separate from the agent. The input is a string. The output has a typed .output.

What the comparison reveals

AspectLangChain/LangGraphPydantic AI
Lines of code~12~12
Tool definition@tool (standalone)@agent.tool_plain (bound to the agent)
ModelSeparate from the agentA parameter of the agent
Input{"messages": [...]}A plain str
OutputDict with a list of messagesA typed object with .output
Framework neededlangchain + langgraphpydantic-ai
TracingLangSmith (extra config)Logfire (extra config)

For a simple agent like this, the difference is minimal. The gap widens as the system grows: when you need checkpointing, conditional routing, multi-agent orchestration, and tracing in production, LangGraph has the advantage. When you need strict typing, dependency injection, and output validation, Pydantic AI has the advantage.


How to Choose

Decision Framework

Does your team already use LangChain?
│
├── YES → Do you need observability (tracing, eval)?
│         ├── YES → LangChain/LangGraph + LangSmith
│         └── NO → LangChain/LangGraph (you already have the investment)
│
└── NO → What matters most?
          │
          ├── Large ecosystem + integrations → LangChain/LangGraph
          │
          ├── Type safety + clean code → Pydantic AI
          │
          ├── Multi-agent with roles → CrewAI (prototype) or LangGraph (production)
          │
          ├── Microsoft/Azure stack → Semantic Kernel
          │
          ├── OpenAI models only + simplicity → OpenAI Agents SDK
          │
          └── Research / conversational patterns → AutoGen

The 5 Questions That Resolve 90% of Decisions

1. How complex is your agent system?

If it's a simple agent with 3-5 tools → any framework works. If it's a multi-agent system with persistent state, conditional routing, and human-in-the-loop → LangGraph has the most mature abstractions.

2. Do you need observability in production?

If you're going to production and need tracing, evaluation, and execution debugging → LangSmith (LangChain) or Logfire (Pydantic AI). If it's a prototype → it's not a deciding factor.

3. How important is type safety to your team?

If your team already uses mypy/pyright, Pydantic everywhere, and values "compile-time errors" → Pydantic AI. If development speed matters more than type rigor → LangChain.

4. What's your existing stack?

Azure → Semantic Kernel. OpenAI only → OpenAI Agents SDK is an option (but young). Python with FastAPI → Pydantic AI integrates naturally. No preference → LangChain/LangGraph for the ecosystem.

5. What's your time horizon?

A prototype in 1 week → any framework. A system that will live 2+ years in production → prioritize maturity and stability (LangChain/LangGraph, Semantic Kernel). An experimental project → Pydantic AI or OpenAI Agents SDK to evaluate the future.

What Should NOT Decide Your Choice

  • GitHub stars: They don't correlate with quality for your use case
  • Twitter/X threads: Biased opinions from contexts that aren't yours
  • "It's more modern": New doesn't mean better. It means less tested
  • A single benchmark: Benchmarks measure specific scenarios. Yours is probably different
  • The framework your favorite YouTuber uses: Their context isn't your context

Connection with the Project

In this module's project (capsule 08): you'll implement the ReAct agent with LangChain/LangGraph. The framework choice is already made for this project — what matters is that you understand why it was chosen (ecosystem, observability, maturity).

In the evolving project (Research Agent, Modules 4-10):

  • Modules 4-9: LangGraph for state machines, planning, memory, MCP, multi-agent, testing
  • Module 10, Capsule 07: You'll reimplement the same agent in Pydantic AI to compare at the code level. That's where you'll see the differences in real production, not just in a 12-line example

This capsule's judgment applies to every future decision: "Do I need to switch frameworks?" → revisit the 5 questions. "Should my team use CrewAI?" → weigh fine-grained control vs ease. There are no absolute answers — there are trade-offs.


Troubleshooting

Problem 1: Framework fatigue — "I can't choose and I'm not making progress"

Symptom: You've spent 2 weeks reading comparisons, watching talks, and haven't written a line of code.

Cause: Over-optimizing the decision. At the simple-agent level, all frameworks produce comparable results.

Solution: Choose LangChain/LangGraph if you don't have a strong reason for something else (it's the default with the most support). Start building. You can migrate later — the business logic (tools, prompts, validation) is portable. What isn't portable is the orchestration (state machines, routing), but that only matters in advanced production.

Problem 2: Switching costs — "I started with X and now I want Y"

Symptom: Your code has 50+ tools in LangChain and you want to migrate to Pydantic AI.

Cause: The tools are coupled to the framework (decorators, schemas, return types).

Solution: Separate the business logic from the framework. Your tools should be ordinary Python functions; the framework's decorator is just a wrapper. If your tools look like def get_weather(city: str) -> str: ..., migrating means re-decorating. If your tools depend on BaseTool, ToolMessage, or RunManager, the migration is more expensive. Design for portability from the start:

# Business logic — framework-agnostic
def get_weather_logic(city: str) -> str:
    data = {"Madrid": "22°C, sunny", "Barcelona": "20°C, cloudy"}
    return f"Weather in {city}: {data.get(city, '18°C, partly cloudy')}"

# LangChain wrapper
from langchain_core.tools import tool

@tool
def get_weather_lc(city: str) -> str:
    """Gets the current weather for a city."""
    return get_weather_logic(city)

# Pydantic AI wrapper (if you migrate later)
# @agent.tool_plain
# def get_weather_pai(city: str) -> str:
#     """Gets the current weather for a city."""
#     return get_weather_logic(city)

Problem 3: "My framework doesn't have feature X"

Symptom: You need MCP but you're using CrewAI. Or you need native multi-agent but you're using Pydantic AI.

Cause: You chose the framework before defining the system's requirements.

Solution: List your requirements (multi-agent, observability, MCP, type safety, state persistence) BEFORE choosing. If you've already chosen and a critical feature is missing, evaluate whether you can build it on top of the framework (an MCP client is a function — it doesn't need native support) or whether it justifies migrating.

Problem 4: "The team wants to use different frameworks"

Symptom: One dev wants LangChain, another wants Pydantic AI, the third read about CrewAI.

Cause: No shared criteria. Each dev evaluates from their own perspective.

Solution: Use this capsule's 5 questions as a group decision framework. Write them in a doc, answer them together, and let the decision fall out of the answers — not out of individual opinions. A team with 3 different frameworks in production has 3x the maintenance cost.

Problem 5: "What if I choose the wrong framework?"

Cause: Fear of irreversible lock-in.

Solution: It's not irreversible. What changes when you migrate frameworks is: (1) how you define tools (~1 hour per tool if they're well separated), (2) how you orchestrate the agent (~1-2 days for a medium system), (3) how you do observability. What does NOT change: your business logic, your prompts, your conceptual architecture, your evaluation tests. Design so the non-portable part is as small as possible.


Exercises

Exercise 1: Map requirements to a framework (Easy)

For each scenario, recommend a framework and justify in one sentence.

a) A 3-dev startup, new project, team strong in type hints and Pydantic b) An enterprise team with Azure OpenAI, a .NET backend, compliance requirements c) A researcher who wants to prototype a system where 4 agents debate solutions d) A product team that needs observability (tracing, evals) in production from day 1 e) A solo dev who only uses OpenAI and wants a simple agent in <50 lines

See solution

a) Pydantic AI — The team already lives in the Pydantic ecosystem. The curve is minimal and the type safety aligns with their practices. A small ecosystem doesn't matter if the project doesn't need 100 integrations.

b) Semantic Kernel — Native Azure integration, multi-language support (C# for the existing backend), and designed for enterprise with governance. The alternative would be LangChain/LangGraph if they need pure Python.

c) AutoGen — The conversational patterns (GroupChat, speaker selection) are designed for this use case. CrewAI would be an alternative if the roles are fixed (not free-form debate).

d) LangChain/LangGraph + LangSmith — LangSmith is the most mature observability solution in the ecosystem. Logfire (Pydantic AI) is an alternative but with fewer evaluation features.

e) OpenAI Agents SDK — Minimal friction if they already use OpenAI. Alternative: Pydantic AI for code simplicity. LangChain would be over-engineering for a simple agent with one provider.

Meta-lesson: There's no universal answer. The context (team, stack, requirements) determines the choice.

Exercise 2: Trade-off analysis (Easy)

Fill in this table with "Advantage", "Neutral", or "Disadvantage" for each criterion:

CriterionLangChain/LangGraphPydantic AI
Ecosystem__________
Type safety__________
Learning curve__________
Multi-agent__________
Observability__________
API stability__________
See solution
CriterionLangChain/LangGraphPydantic AI
EcosystemAdvantage (100+ integrations)Disadvantage (few integrations)
Type safetyNeutral (Pydantic optional)Advantage (core to the design)
Learning curveDisadvantage (LCEL, runnables, graphs)Advantage (standard Python)
Multi-agentAdvantage (native LangGraph)Disadvantage (limited)
ObservabilityAdvantage (LangSmith built in)Neutral (Logfire, in development)
API stabilityNeutral (past breaking changes, stabilizing)Disadvantage (pre-1.0)

Conclusion: LangChain/LangGraph wins on ecosystem, multi-agent, and observability. Pydantic AI wins on type safety and learning curve. There's no absolute winner — there are contexts where each one is better.

Exercise 3: Separate logic from framework (Medium)

Refactor this code so the business logic is framework-agnostic:

from langchain_core.tools import tool

@tool
def analyze_sentiment(text: str) -> str:
    """Analyzes the sentiment of a text."""
    positive = ["good", "excellent", "great", "amazing"]
    negative = ["bad", "terrible", "horrible", "awful"]
    words = text.lower().split()
    pos = sum(1 for w in words if w in positive)
    neg = sum(1 for w in words if w in negative)
    if pos > neg:
        return "POSITIVE"
    elif neg > pos:
        return "NEGATIVE"
    return "NEUTRAL"
See solution
# --- Business logic (framework-agnostic) ---
def analyze_sentiment_logic(text: str) -> str:
    """Analyzes sentiment with keyword matching."""
    positive = ["good", "excellent", "great", "amazing"]
    negative = ["bad", "terrible", "horrible", "awful"]
    words = text.lower().split()
    pos = sum(1 for w in words if w in positive)
    neg = sum(1 for w in words if w in negative)
    if pos > neg:
        return "POSITIVE"
    elif neg > pos:
        return "NEGATIVE"
    return "NEUTRAL"

# --- LangChain wrapper ---
from langchain_core.tools import tool

@tool
def analyze_sentiment_lc(text: str) -> str:
    """Analyzes the sentiment of a text."""
    return analyze_sentiment_logic(text)

# --- Pydantic AI wrapper (for a future migration) ---
# @agent.tool_plain
# def analyze_sentiment_pai(text: str) -> str:
#     """Analyzes the sentiment of a text."""
#     return analyze_sentiment_logic(text)

# --- Tests (framework-agnostic) ---
assert analyze_sentiment_logic("Excellent and great product") == "POSITIVE"
assert analyze_sentiment_logic("Terrible and horrible service") == "NEGATIVE"
assert analyze_sentiment_logic("The product is ordinary") == "NEUTRAL"
print("All tests pass")

Benefit: The tests validate the logic without instantiating any framework. If you migrate from LangChain to Pydantic AI, you rewrite the wrapper (3 lines) — not the logic (15 lines). If you have 50 tools, that's the difference between a 1-hour and a 1-week migration.

Exercise 4: Evaluate a new framework (Medium)

A new framework arrives: "AgentForge". It has 5,000 GitHub stars, 3 months of life, and its README says "10x simpler than LangChain". Define 5 questions you'd ask before adopting it in a production project.

See solution
  1. Who maintains it? — Is it an individual project, a startup, or an established company? A project with 1 maintainer and 5K stars can die tomorrow. LangChain has a team of 50+. Pydantic AI has the creator of Pydantic.

  2. Is there documented real production use? — Does anyone beyond the creator use it in production? Without real cases, "production-ready" is marketing.

  3. How does it handle breaking changes? — Does it have semantic versioning? A changelog? Migration guides? A framework that breaks its API every 2 weeks is untenable in production.

  4. What about observability? — Does it have built-in or compatible tracing? Without the ability to debug production runs, any agent is a black box.

  5. How much does it cost to migrate if it fails? — If the framework dies in 6 months, how much effort does it take to migrate to LangChain or Pydantic AI? If the logic is coupled to the framework, the cost is high.

Practical rule: "10x simpler" in the README usually means "10x fewer features." Assess whether you need the missing ones.

Exercise 5: A framework selection design document (Hard)

Your team (4 devs, 2 use LangChain, 1 uses Pydantic, 1 is new) has to choose a framework for a customer-service multi-agent system with: mandatory tracing, 15 tools, 3 specialized agents, deployment on AWS. Write the design document for the decision (200 words max).

See solution
# Framework Selection: Customer Service Multi-Agent System

## Requirements
- Multi-agent (3 specialized agents)
- Mandatory tracing in production
- 15 tools
- AWS deployment (not Azure)

## Evaluation

| Requirement | LangChain/LangGraph | Pydantic AI | CrewAI |
|-----------|-------------------|-------------|--------|
| Multi-agent | ✅ Native LangGraph | ❌ Limited | ✅ Native |
| Tracing | ✅ LangSmith | ⚠️ Logfire (young) | ❌ Basic |
| 15 tools | ✅ @tool proven | ✅ tool_plain | ✅ Supported |
| AWS | ✅ Agnostic | ✅ Agnostic | ✅ Agnostic |

## Decision: LangChain/LangGraph

**Reason:** The only framework covering multi-agent + mandatory tracing
with enough maturity. 2 of 4 devs already know it (less ramp-up).

**Risk:** Learning curve for the remaining 2 devs.
**Mitigation:** 1 week of onboarding + pair programming.

**Design for portability:** Tools as pure Python functions
with @tool wrappers. If we migrate in 12 months, we rewrite the wrappers.

Explanation: The document forces objectivity: requirements → evaluation → decision with a reason. Including risks and mitigation shows engineering maturity. The portability point protects against lock-in.

Exercise 6: Predicting the 2027 landscape (Hard)

Based on the 2024-2026 trends (API convergence, MCP as a standard, growing type safety, multi-agent as the dominant pattern), write 3 predictions about what the framework landscape will look like in 2027. Justify each one.

See solution

Prediction 1: Consolidation to 2-3 main frameworks.

In 2024 there were 10+ frameworks. By 2027, most production will use LangChain/LangGraph or Pydantic AI (if it reaches v1.0 with a mature ecosystem). The rest will be niche or absorbed. Reason: ecosystem and community have network effects — the winner is the one with the most integrations and the most answers on Stack Overflow.

Prediction 2: MCP as a universal standard erodes "integrations" as a differentiator.

If MCP establishes itself as the standard protocol, LangChain's advantage ("100+ integrations") erodes: any framework can connect to any tool via MCP. The differentiator shifts to orchestration, observability, and developer experience.

Prediction 3: Type safety becomes an expectation, not a differentiator.

What is Pydantic AI's advantage today (type-safe agents) will be adopted by LangChain and others. You can already see it: LangGraph uses TypedDict, LangChain adopts more Pydantic. By 2027, "type-safe" will be a baseline, not a feature.

Meta-lesson: These predictions are speculative — the point of the exercise is to make you think about trends, not about the outcome. Being wrong on the prediction but right on the reasoning is valuable.


Summary

In this capsule you learned:

  • The 2025-2026 framework landscape has 6 main options, each with real trade-offs — there's no universal "best"
  • LangChain/LangGraph has the largest ecosystem, LangSmith for observability, and the most active community, but the learning curve and complexity are real costs
  • Pydantic AI offers type safety and clean code, but its ecosystem is small and it's pre-1.0 — you'll explore this framework in depth in Module 10
  • CrewAI makes multi-agent with roles easy but sacrifices fine-grained control
  • AutoGen has conversational patterns for research but an unstable API
  • Semantic Kernel is the enterprise option for Microsoft/Azure stacks
  • OpenAI Agents SDK is promising but very new (2025) — watch it, don't bet production on it yet
  • The framework decision depends on your context (team, stack, requirements, time horizon), not on opinions on Twitter
  • Design for portability: framework-agnostic business logic, thin wrappers — migrating frameworks is inevitable in a landscape that changes fast

Next capsule: When to Use and NOT Use Agents — a decision framework that tells you honestly whether your problem really needs an agent, or whether a chain/workflow is enough. It's the capsule that prevents the most expensive mistake in AI Engineering: using an agent where you don't need one.


Additional Resources

  1. LangChain Documentation — Official LangChain documentation with tutorials and API reference
  2. LangGraph Documentation — A framework for agents as state graphs
  3. LangSmith — An observability, tracing, and evaluation platform for LangChain
  4. Pydantic AI Documentation — A type-safe framework for AI agents
  5. CrewAI Documentation — A multi-agent framework with a roles-and-teams abstraction
  6. AutoGen Documentation — Microsoft's framework for conversational agents
  7. Semantic Kernel Documentation — Microsoft's multi-language enterprise SDK
  8. OpenAI Agents SDK — OpenAI's framework for agents with handoffs and tracing