0% found this document useful (0 votes)
143 views24 pages

Langchain vs Pydanticaifize用於在AI中建造 - 芬恩·安德斯(Finn Anderses) - Jan J Jan,2025年 - 中等的 - LangChain vs PydanticAI for building an AI Agent - by Finn Andersen - Jan, 2025 - Medium

The document compares LangChain and PydanticAI frameworks for building conversational AI agents, highlighting features like dynamic model choice and human-in-the-loop input. It provides an example of an AI waiter agent that interacts with customers, showcasing how each framework handles dependencies and tool calls. PydanticAI is noted for its simplicity and intuitive design, while LangChain is described as comprehensive but potentially daunting due to its legacy content and complexity.

Uploaded by

陳賢明
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
143 views24 pages

Langchain vs Pydanticaifize用於在AI中建造 - 芬恩·安德斯(Finn Anderses) - Jan J Jan,2025年 - 中等的 - LangChain vs PydanticAI for building an AI Agent - by Finn Andersen - Jan, 2025 - Medium

The document compares LangChain and PydanticAI frameworks for building conversational AI agents, highlighting features like dynamic model choice and human-in-the-loop input. It provides an example of an AI waiter agent that interacts with customers, showcasing how each framework handles dependencies and tool calls. PydanticAI is noted for its simplicity and intuitive design, while LangChain is described as comprehensive but potentially daunting due to its legacy content and complexity.

Uploaded by

陳賢明
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Open in app

53
Search

Get unlimited access to the best of Medium for less than $1/week. Become a member

LangChain vs PydanticAI for building an AI


Agent
Langchain vs Pydanticai用於建造AI代理商
Finn Andersen · Follow
10 min read · Jan 29, 2025

Listen Share More

Here I compare how these two popular frameworks can be used to build a simple
conversational AI Agent, involving the following features:
在這裡,我比較如何使用這兩個流行的框架來構建一個簡單的對話AI代理,涉及以下
功能:

Dynamic model choice 動態模型選擇

Human-in-the-loop input 人類在循環輸入

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 1/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Tool calling with dependencies


依賴關係的工具調用

Conversation history/memory

對話histror /記憶

Dynamic system prompt 動態系統提示

Structured output 結構化輸出

Agent Behaviour 代理行為


The aim is to build an AI agent that will play the role of an eccentric waiter at a
restaurant who will ask about your dietary requirements and take your order. An
example conversation might look like:

目的是建立一個AI代理,該代理將在一家餐廳扮演怪異服務員的角色,該餐廳將詢問
您的飲食要求並接受您的訂單。示例對話可能看起來像:

AI Waiter: Ah, bonjour madame et monsieur! Welcome to Le Bistro, where the food
is as delightful as the company! Before we embark on a culinary adventure, might
you have any dietary restrictions or preferences? We wouldn’t want any rogue
ingredients crashing the party!

AI服務員:啊,Bonjour Madame et Monsieur!歡迎來到Le Bistro,那裡的食物和


公司一樣令人愉悅!在我們開始烹飪冒險之前,您是否有任何飲食限製或偏好?我們
不希望任何流氓成分崩潰!

You: I only eat yellow coloured food

你:我只吃黃色的食物

<agent makes tool call to get list of menu items>

%3 Cagent撥打工具調用以獲取菜單項列表%3E

AI Waiter: Magnifique! A connoisseur of the golden hue, I see! Let’s explore the
menu with your sunshine-filled preference in mind. For appetizers, we have the
Quinoa Stuffed Bell Peppers, which are a vibrant yellow. For the main course, the
Chickpea and Sweet Potato Curry is a golden delight! And for dessert, the Fresh
Fruit Sorbet might have some yellow options depending on the day! What do you

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 2/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

think?

AI服務員: Magnifique!我明白了金色的鑑賞家!讓我們牢記您的陽光偏愛探索菜
單。對於開胃菜,我們有藜麥釀的辣椒,它是鮮黃色的。對於主菜,鷹嘴豆和地瓜咖
哩是一種金色的喜悅!對於甜點而言,新鮮的水果冰糕可能會有一些黃色的選擇,具
體取決於一天!你怎麼認為?

You: I’ll take the Bell Peppers and fruit sorbet thanks!
您:我會帶鈴鐺和水果冰糕謝謝!

AI Waiter: Excellent choices! One order of the Quinoa Stuffed Bell Peppers and the
Fresh Fruit Sorbet for the discerning palate at table number 1! Your order has been
placed, and I shall return with your delectable delights shortly. Au revoir!
AI服務員:絕佳的選擇!藜麥的一訂單塞滿了辣椒和新鮮的水果冰糕,可挑剔的味
覺。您的訂單已被下達,我很快就會以您的美味佳餚返回。 au revoir!

<agent makes tool call to place order>

%3Cagent撥打訂單的工具呼叫%3E

Order placed: [Order(menu_items=[‘Quinoa Stuffed Bell Peppers’, ‘Fresh Fruit


Sorbet’], table_number=1)]

放置訂單: [訂單(菜單_ITEMS = ['Quinoa填充貝爾辣椒','新鮮水果冰糕'],


table_number = 1)]

Try it yourself by checking out the full repository here!

通過在此處查看完整的存儲庫來嘗試一下!

Frameworks Overview 框架概述


LangChain is a well-known framework that has been around since the early days of
LLM availability, so while it provides a lot of functionality it also includes quite a bit
of legacy content due to how models have rapidly evolved. The combination of
many different ways to do the same thing (especially with the introduction of
LangGraph) and a component chaining approach that is difficult to reason about
makes the framework somewhat daunting to use. It’s also quite a comprehensive
library spread across multiple packages, totalling about 300MB if you want multi-

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 3/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

model and graph support.

Langchain是一個著名的框架,自早期就已經存在LLM可用性,因此,儘管它提供了
大量功能,但由於模型的發展方式,它還包含了很多舊內容。做同一件事(尤其是在
Langgraph的引入)和一種很難推理的組件鏈接方法的組合(尤其是在引入
Langgraph的引入中)的結合,使該框架有些令人生畏。它也是一個遍布多個軟件包
的綜合庫,如果您想要多模型和圖形支持,總計約300MB。

PydanticAI is a relatively young framework from the creators of everyone’s favourite


data validation library, “designed to make it less painful to build production grade
applications with Generative AI.” It seemed quite approachable and intuitive, so I
tried it out by creating an basic AI agent that allows querying any database using
natural language. The full package (including Logfire) is only about 70MB.

Pydanticai是每個人最喜歡的數據驗證庫的創建者的一個相對年輕的框架,“旨在通過
生成AI構建生產級應用程序的痛苦。”它似乎很平易近人和直觀,因此我通過創建一
個基本的AI代理來嘗試使用自然語言查詢任何數據庫。完整的軟件包(包括日誌之
火)僅為70MB。

I enjoyed working with PydanticAI but was curious to see what the LangChain hype
was all about, so I put together a demo project to see how they compared.

我喜歡與Pydanticai合作,但很好奇地看到Langchain Hype的意義,因此我整理了一
個演示項目,以了解它們的比較。

Common Content 常見內容


These are the common components that both agent implementations will use.

這些是兩個代理實現都將使用的常見組件。

Defining the dynamic system prompt and structured response definition:

定義動態系統提示和結構化響應定義:

PROMPT_TEMPLATE = """
You are playing the role of an incredibly eccentric and entertaining waiter in
called "{restaurant_name}" taking orders for table number {table_number}.
You must:
* Greet the customer, ask if they have any dietary restrictions
* Tell them about appropriate menu items using the *get_menu()* tool.
* Take their order, and confirm it with them.

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 4/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…
* When confirmed, use the *create_order()* tool to create an order for the cust
* Only set the *end_conversation* flag to True in your final response after you
meaning that your message DOES NOT contain a question.
"""

class LLMResponse(BaseModel):
"""
Structured response format for the LLM to use so it can indicate when the c
"""

message: str
end_conversation: Annotated[
bool,
"True if the conversation should end after this response. DO NOT set if
]

Dependency services used by tools that the Agent will call:


代理商將調用工具使用的依賴關係服務:

class MenuService:
def get_menu(self) -> dict[str, list[str]]:
# Returns an Appetizer, Main Course and Deserts menu
...

class OrderService:
orders: list[Order]

def create_order(self, table_number: int, menu_items: list[str]):


self.orders.append(Order(table_number=table_number, menu_items=menu_ite

def get_orders(self) -> list[Order]:


return self.orders

AgentRunner class interface which will need to be implemented using each


framework, and the agent execution function:

AgentRunner 類接口將需要使用每個框架和代理執行函數來實現:

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 5/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

class AgentRunner(ABC):
"""
Base class which provides a common interface for initialising and making
requests to an agent.
"""

@abstractmethod
def __init__(self, menu_service: MenuService, order_service: OrderService,

@abstractmethod
def make_request(self, user_message: str) -> LLMResponse: ...

def run_agent(runner_class: type[AgentRunner], args: argparse.Namespace):


"""Initialise services and run agent conversation loop."""
menu_service = MenuService()
order_service = OrderService()

agent_runner = runner_class(menu_service, order_service, args)


user_message = "*Greet the customer*"
console = Console()
while True:
with Live(console=console) as live_console:
live_console.update("AI Waiter: ...")
response = agent_runner.make_request(user_message)
live_console.update(f"AI Waiter: {response.message}")

# Exit if LLM indicates conversation is over


if response.end_conversation:
break

user_message = Prompt.ask("You")

# Show orders
if orders := order_service.get_orders():
console.print(f"Order placed: {orders}")

There’s also some extra CLI handling code which I won’t show here. While both
frameworks support asynchronous programming, I’m going to stick to a standard
synchronous approach here for simplicity.

還有一些額外的CLI處理代碼,我在這裡不會顯示。儘管這兩個框架都支持異步編
程,但我將在此處堅持使用標準同步方法,以簡單化。

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 6/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

PydanticAI Implementation
Pydantica實施
I’ll start with the PydanticAI implementation since it’s a bit more straightforward.
我將從Pydanticai實施開始,因為它更加簡單。

Dependencies 依賴性
First we need to define the structure of dependencies that will be used by tools or
dynamic system prompts:

首先,我們需要定義依賴關係的結構,該結構將由工具或動態系統提示使用:

@dataclass
class Dependencies:
menu_service: MenuService
order_service: OrderService
restaurant_name: str
table_number: int

Tools 工具
Then the tools themselves, which can access the run-time dependencies through the
RunContext object that will be passed in along with any arguments. PydanticAI uses
the type annotations and docstrings of the tool functions to automatically generate
their schemas to provide to the LLM.

然後,工具本身可以通過 RunContext 對象訪問運行時依賴關係,該對象將與任何參數


一起傳遞。 Pydanticai使用工具功能的類型註釋和DOCSTRINGS自動生成其模式以提
供給LLM。

def create_order(
ctx: RunContext[Dependencies],
table_number: int,
order_items: Annotated[list[str], "List of food menu items to order"],
) -> str:
"""Create an order for the table"""
ctx.deps.order_service.create_order(table_number, order_items)
return "Order placed"

def get_menu(ctx: RunContext[Dependencies]) -> dict[str, list[str]]:

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 7/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…
"""Get the full menu for the restaurant"""
return ctx.deps.menu_service.get_menu()

Agent 代理人
The key component of the PydanticAI framework is the Agent class, which manages
interactions with the provided model, handles tool calling and ensures appropriate
final result format:

Pydanticai框架的關鍵組成部分是 Agent 類,它管理與提供模型的交互,處理工具調用


並確保適當的最終結果格式:

Basic graph diagram for the PydanticAI Agent


Pydanticai代理的基本圖表

This graph diagram is technically slightly misleading since structured output is


implemented using tool calling, but conceptually it works.
由於使用工具調用實現了結構化輸出,因此該圖表在技術上有些誤導,但是從概念上
講,它有效。

All the examples in the documentation involve initialising an Agent as a module-


level object at import-time, and then using its decorator methods to register tools
and system prompts. However, this approach doesn’t work well if you want
dynamically configure agent parameters like model choice, tool configuration,
system prompt at runtime. So I made a function for creating an agent instead:
文檔中的所有示例都涉及將 Agent 作為導入時的模塊級對像初始化,然後使用其裝飾
方法來註冊工具和系統提示。但是,如果您想動態配置代理參數,例如模型選擇,工
具配置,系統提示,則此方法無法正常工作。因此,我做出了創建代理的功能:

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 8/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

def get_agent(model_name: KnownModelName, api_key: str | None = None) -> Agent[


"""
Construct an agent with an LLM model, tools and system prompt
"""
model = build_model_from_name_and_api_key(
model_name=model_name,
api_key=api_key,
)
# Tools can also be registered using @agent.tool decorator, but providing t
# constructing the agent dynamically
agent = Agent(model=model, deps_type=Dependencies, tools=[get_menu, create_

# Define dynamic system prompt


@agent.system_prompt
def system_prompt(ctx: RunContext[Dependencies]) -> str:
return PROMPT_TEMPLATE.format(restaurant_name=ctx.deps.restaurant_name,

return agent

The build_model_from_name_and_api_key() function simply looks up and initialises the


appropriate model class based on the model name. Unfortunately the
@agent.system_prompt decorator is the only way to register dynamic system prompts,
which seems like a bit of a limitation.
這 build_model_from_name_and_api_key() 功能只需查找基於模型名稱的適當模型類即
可初始化。不幸的是, @agent.system_prompt Decorator是註冊動態系統提示的唯一方
法,這似乎是一個限制。

Agent Runner
Here’s what the AgentRunner implementation looks like:

這是 AgentRunner 實現的樣子:

class PydanticAIAgentRunner(AgentRunner):
agent: Agent[Dependencies, LLMResponse]
deps: Dependencies
message_history: list[ModelMessage]

def __init__(self, menu_service: MenuService, order_service: OrderService,


self.agent = get_agent(model_name=args.model, api_key=args.api_key)
self.deps = Dependencies(
menu_service=menu_service,

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 9/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…
order_service=order_service,
restaurant_name=args.restaurant_name,
table_number=args.table_number,
)
self.message_history = []

def make_request(self, user_message: str) -> LLMResponse:


ai_response = self.agent.run_sync(
user_message,
deps=self.deps,
message_history=self.message_history,
)
self.message_history = ai_response.all_messages()
return ai_response.data

The Agent instance is effectively stateless so it does not store the message history
itself, instead it must be provided each time to agent.run_sync() along with the
dependencies and the new user query.
Agent 實例有效地無狀態,因此不會存儲消息歷史記錄本身,而必須每次向

agent.run_sync() 以及依賴項和新用戶查詢提供。

Overall I think this implementation is quite straightforward and easy to to reason


about!
總的來說,我認為這種實現非常簡單,很容易理解!

LangChain Implementation Langchain實施


For the LangChain implementation I wanted to use the AgentExecutor class, even
though it’s actually now the legacy approach since LangGraph was introduced.
LangGraph adds more flexibility at the cost of complexity, so I figured
AgentExecutor should still do the job for this use case. I will explore the graph-based
implementations later on.
對於Langchain實施,我想使用 AgentExecutor 類,儘管自從引入了Langgraph以來,
現在它實際上是傳統方法。 Langgraph以復雜性的成本增加了更大的靈活性,因此我
認為 AgentExecutor 仍然應該為此用例工作。稍後,我將探索基於圖的實現。

Tools 工具
LangChain includes a @tool decorator for registering functions and inspecting their
signatures to automatically generate tool schemas, however the way to achieve
runtime dependency injection with this method looks rather convoluted (and I think
https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 10/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

the example is broken, where does user_id even come from?). Therefore, I decided
to go for a class-based tool approach so they can be initialised with their required
dependencies:
Langchain包括一個用於註冊功能並檢查其簽名以自動生成工具模式 @tool 裝飾器,但
是使用此方法實現運行時依賴性注入的方法看起來相當令人費解(我認為示例被損壞
了, user_id 甚至來自哪裡?) 。因此,我決定採用基於類的工具方法,以便可以使
用其所需的依賴項初始化它們:

class GetMenuTool(BaseTool):
"""
Tool that can be used by the LLM to get the full menu for the restaurant.
"""

name: str = "get_menu"


description: str = "Get the full menu for the restaurant"
menu_service: MenuService

def _run(self) -> dict[str, list[str]]:


return self.menu_service.get_menu()

class CreateOrderInputSchema(BaseModel):
table_number: int
order_items: Annotated[list[str], "List of food menu items to order"]

class CreateOrderTool(BaseTool):
"""
Tool that can be used by the LLM to create an order for the table.
"""

name: str = "create_order"


description: str = "Create an order for the table"
args_schema: type[BaseModel] = CreateOrderInputSchema
order_service: OrderService

def _run(self, table_number: int, order_items: list[str]) -> str:


self.order_service.create_order(table_number, order_items)
return "Order placed"

Structured Output 結構化輸出


The ChatModel.with_structured_output() method takes a desired output schema (e.g.
Pydantic model or TypedDict) and binds a corresponding tool that the LLM can use
https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 11/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

to produce a structured output. However, once this is done, it’s not possible to bind
any more tools to the model. Therefore I needed to create a custom class-based tool
to achieve structured outputs as well as additional tools:

這 ChatModel.with_structured_output() 方法採用所需的輸出模式(例如Pydantic模型
或TypedDict),並綁定了一個相應的工具LLM可以用來產生結構化輸出。但是,一
旦完成,就不可能將更多工具綁定到模型。因此,我需要創建一個基於自定義類的工
具來實現結構化輸出以及其他工具:

class StructuredResponseTool(BaseTool):
"""
Tool that can be used by the LLM to provide a structured response to the us
Does not have any associated functionality, it is just a way to enable stru
"""

name: str = "respond_to_user"


description: str = (
"ALWAYS use this tool to provide a response to the user, INSTEAD OF res
"The `message` content should be what you would normally respond with i
"The `end_conversation` flag should be set to True if the conversation
)
args_schema: type[BaseModel] = LLMResponse

# The following content is only used by legacy AgentExecutor, not required


return_direct: bool = True # Causes the tool result to be returned directl

def _run(self, message: str, end_conversation: bool) -> str:


# Return a serialised str as a workaround to avoid a validation error i
return LLMResponse(message=message, end_conversation=end_conversation).

Agent 代理人
LangChain includes a bunch of factory functions which produce pre-built agent
configurations for different use cases. In this context, an “agent” refers to a
ChatModel chained with various prompt input and/or response output
parsers/processors. It’s still a simple linear input-output chain that doesn’t involve
multiple LLM interactions or tool calling — that’s where the AgentExecutor comes in.

Langchain包括一堆工廠功能,這些功能可為不同的用例生成預製的代理配置。在這
種情況下,“代理”是指用各種提示輸入和/或響應輸出解析器/處理器鏈接的 ChatModel
。這仍然是一個簡單的線性輸入輸出鏈,不涉及多個LLM交互或工具調用 - 這就是
AgentExecutor 出現。

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 12/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

There’s a convenience create_tool_calling_agent() constructor function, which


apparently makes older variants like create_react_agent() and
create_openai_functions_agent() obsolete (and is also itself now made obsolete by
the LangGraph equivalent). This almost works for this use case, except it doesn’t
force tool use, which is required when using a tool-based implementation to achieve
structured outputs. Therefore I had to basically re-implement the contents of
create_tool_calling_agent() to force tool use.

有便利的 create_tool_calling_agent() constructor函數,顯然可以使諸如


create_react_agent() 之類的舊變體和 create_openai_functions_agent() 已過時(現在
也是由langgraph等效的過時的)。這幾乎適用於此用例,除了它不強制工具使用,
這是使用基於工具的實現來實現結構化輸出時所必需的。因此,我必須基本上重新實
現 create_tool_calling_agent() 的內容以強制使用工具。

The ChatPromptTemplate supports dynamic prompt construction using parameter


substitution from the input object provided to the agent/chain.

ChatPromptTemplate 使用來自提供給代理/鏈的輸入對象的參數替換來支持動態提示構

建。

Chat History / Memory 聊天歷史 /記憶


It appears that when AgentExecutor is invoked, it only returns the final response but
does not exposure or keep track of the intermediate messages exchanged with the
LLM in an obvious way. They are hidden and lost deep within the impenetrable
depths of the confusing AgentExecutor implementation, and can only be retrieved
with the wicked dark magic of the RunnableWithMessageHistory wrapper. Do not try
and figure out how it works if you value your sanity. Infuriatingly it also requires you
to provide a session_id configuration parameter when invoking the AgentExecutor

even if you don’t need multi-session chat history.


看來,當調用 AgentExecutor 時,它僅返回最終響應,但不曝光或跟踪與該中間消息交
換的中間消息LLM以明顯的方式。它們在令人困惑的 AgentExecutor 實施的難以穿透的
深度內被隱藏和遺失,只能用 RunnableWithMessageHistory rapper的邪惡的黑暗魔法來
檢索。如果您重視自己的理智,請勿嘗試弄清楚它的工作原理。令人髮指的是,即使
您不需要多節奏聊天歷史記錄,也需要您在調用 AgentExecutor 時提供 session_id 配置
參數。

Agent Executor 代理執行人

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 13/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Here’s how the full agent executor with memory is constructed:

這是使用內存的完整代理執行人的方式:

def get_agent_executor(
tools: Sequence[BaseTool], model_name: str, api_key: str | None = None
) -> RunnableWithMessageHistory:
"""
Construct an agent with an LLM model, tools and system prompt
"""
model = build_model_from_name_and_api_key(
model_name=model_name,
api_key=api_key,
)

prompt = ChatPromptTemplate.from_messages(
[
("system", PROMPT_TEMPLATE),
("placeholder", "{chat_history}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
]
)

# Effectively re-implement create_tool_calling_agent() here, but force tool


llm_with_tools = model.bind_tools(tools, tool_choice=True)
agent = (
RunnablePassthrough.assign(agent_scratchpad=lambda x: format_to_tool_me
| prompt
| llm_with_tools
| ToolsAgentOutputParser()
)

agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tool

# Enable chat history/memory (very convoluted)


# Use a single message history (no need for multiple threads)
message_history = ChatMessageHistory()

agent_with_chat_history = RunnableWithMessageHistory(
runnable=agent_executor, # type: ignore[arg-type]
get_session_history=lambda _: message_history,
input_messages_key="input",
history_messages_key="chat_history",
)

return agent_with_chat_history

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 14/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Agent Runner
And then the AgentRunner implementation is:

然後, AgentRunner 實施是:

class LangchainAgentRunner(AgentRunner):
def __init__(self, menu_service: MenuService, order_service: OrderService,
# Initialise tools with dependencies
tools = [
GetMenuTool(menu_service=menu_service),
CreateOrderTool(order_service=order_service),
StructuredResponseTool(),
]
self.agent_executor = get_agent_executor(tools=tools, model_name=args.m
self.static_input_content = {"restaurant_name": args.restaurant_name, "
self.config: RunnableConfig = {"configurable": {"session_id": "not-even

def make_request(self, user_message: str) -> LLMResponse:


result = self.agent_executor.invoke(self.static_input_content | {"input
# De-serialise structured response into an LLMResponse
response = LLMResponse.model_validate_json(result["output"])
return response

Conclusion 結論
This demonstration shows that it is much simpler to create a basic conversational
and tool-calling AI agent using the PydanticAI framework than LangChain.
LangChain has so many layers of deprecated functionality and is in desperate need
of some extensive spring cleaning.

該演示表明,使用Pydanticai框架而不是Langchain創建基本的對話和工具稱呼AI代理
要簡單得多。 Langchain具有許多不棄用的功能層,並且迫切需要一些春季清潔。

I also wanted to enable streamed responses however this seemed quite difficult to
achieve using LangChain with both tool calling and structured output involved.
我還想啟用流響應,但是使用Langchain涉及工具調用和結構化輸出,這似乎很難實
現。

I imagine that the newer LangGraph approach for creating agents addresses many
of the limitations and frustrations encountered here. PydanticAI has also recently
added a graph library, so next time I will explore what full graph-based
https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 15/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

implementations for both frameworks looks like.


我認為創建代理的較新的Langgraph方法解決了這裡遇到的許多局限性和挫敗感。
Pydanticai最近還添加了圖庫,因此下次我將探索兩個框架的基於圖形的完整實現。

I hope this helps anyone who wants to choose between the frameworks or learn how
they can be used to build cool things with AI!

我希望這可以幫助任何想在框架之間進行選擇的人,或者了解如何使用AI來構建酷炫
的東西!

The complete project repository can be found here.


完整的項目存儲庫可以在此處找到。

Langchain Llm AI Pydantic Ai Ai Agent

Follow

Written by Finn Andersen 由芬恩·安德森(Finn Andersen)撰寫


134 Followers · 22 Following

Tech projects and other things on my mind

Responses (1) 響應(1)

What are your thoughts?

Respond

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 16/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Ryan Miller
Jan 31

I'm here because I just surfaced from the depths of the Langchain agent_executor abyss and I want my last 3
months back

15 1 reply Reply

More from Finn Andersen 來自芬恩·安徒生的更多信息

In 和 ITNEXT by 經過 Finn Andersen 芬恩·安徒生

How to Scale a Monolithic Django Project — Without Microservices


如何擴展單片Django項目 - 無微服務
Exploring ways to architect a growing Django project so that it’s easy to maintain and can
handle high user load.
探索構建不斷增長的Django項目的方法,以便易於維護並可以處理高用戶負載。

Mar 4, 2023 374 2

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 17/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

In 和 ITNEXT by 經過 Finn Andersen 芬恩·安徒生

The fastest way to read a CSV file in Pandas 2.0


讀取PANDAS 2.0中CSV文件的最快方法
It turns out that the fastest way to create a Pandas DataFrame from a CSV file is to use an
entirely different library.
事實證明,從CSV文件創建PANDAS數據框的最快方法是使用一個完全不同的庫。

Apr 15, 2023 125

In 和 ITNEXT by 經過 Finn Andersen 芬恩·安徒生

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 18/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

The ultimate guide to Panda’s read_csv() function


熊貓read_csv()函數的終極指南
Here I unravel the mysteries behind the omnipotent and overwhelmingly complicated
read_csv() function, including new features added in 2.0
在這裡,我揭示了無所不能且絕大多數複雜的read_csv()功能的奧秘,包括2.0中添加的新功

Mar 30, 2023 36

Finn Andersen 芬恩·安徒生

I Made a Custom Handheld Retro Gaming Console


我製作了定制的手持式複古遊戲機
Using a Wii-U Pro controller, Raspberry Pi and a 3D printed enclosure. It can emulate games
from N64, PS1, SNES, GBA and more!
使用Wii-U Pro控制器,Raspberry Pi和3D打印的外殼。它可以模仿N64,PS1,SNES,GBA等
遊戲!

Aug 19, 2018 195 1

See all from Finn Andersen

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 19/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Recommended from Medium 推薦用於媒介

In 和 Vedcraft by 經過 Ankur Kumar

Building Intelligent Apps with Agentic AI: Top Frameworks to Watch for in
2025
使用Agesic AI:在2025年觀看的頂級框架,構建智能應用程序

Jan 24 307 17

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 20/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

Daniel Avila 丹尼爾·阿維拉(Daniel Avila)

Step-by-Step: Running DeepSeek locally in VSCode for a Powerful,


Private AI Copilot
逐步:在Vscode中本地運行DeepSeek,以提供功能強大的私人AI Copilot
This step-by-step guide will show you how to install and run DeepSeek locally, configure it with
CodeGPT, and start leveraging AI to…
本分步指南將向您展示如何在本地安裝和運行DeepSeek,使用Codegpt進行配置,然後開始利
用AI到…

6d ago 307 10

Lists 盧斯

Natural Language Processing


自然語言處理
1926 stories · 1581 saves

Generative AI Recommended Reading


生成式人工智慧推薦閱讀
52 stories · 1643 saves

What is ChatGPT? 什麼是 ChatGPT?


9 stories · 505 saves

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 21/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

The New Chatbots: ChatGPT, Bard, and Beyond


新的聊天機器人:ChatGPT、Bard 等
12 stories · 549 saves

In 和 AI Advances 人工智能進步 by 經過 Manpreet Singh 曼普雷斯·辛格(Manpreeth Singh)

CAG Can Make You Forget RAG


CAG可以使您忘記抹布
We all know what is RAG (Retrieval-Augmented Generation) — it searches through external
documents to provide better answers.
我們都知道什麼是抹布(檢索出來的一代) - 它通過外部文檔進行搜索以提供更好的答案。

Feb 1 200 3

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 22/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

In 和 Towards Data Science 邁向數據科學 by 經過 Dr. Janna Lipenkova Janna Lipenkova博士

Injecting domain expertise into your AI system


將域專業知識注入您的AI系統
How to connect the dots between AI technology and real life
如何將人工智能技術與現實生活之間的點連接

Feb 1 325 8

In 和 Level Up Coding 升級編碼 by 經過 Joshua Saunders 約書亞·桑德斯(Joshua Saunders)

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 23/24
2025/2/9 晚上9:46 Langchain vs Pydanticaifize用於在AI中建造|芬恩·安德斯(Finn Anderses)| Jan J Jan,2025年|中等的 --- LangChain vs Pyd…

o3-mini, Gemini 2 Flash, Sonnet 3.5 and DeepSeek in Cursor — Who’s The
Best Now?
O3-Mini,Gemini 2 Flash,Sonnet 3.5和DeepSeek在光標中 - 現在誰是最
好的?
A new batch of models to test in Cursor. Is Sonnet 3.5 finally dethroned?
在光標中測試的新型號。十四行詩3.5終於被廢棄了嗎?

6d ago 231 5

In 和 DataDrivenInvestor 數據驅動投資者 by 經過 Austin Starks 奧斯汀·斯塔克斯

OpenAI is BACK in the AI race. A side-by-side comparison between


DeepSeek R1 and OpenAI o3-mini
Openai回到了AI比賽。 DeepSeek R1和Openai O3-Mini之間的並排比較
All of my articles are 100% free to read! Non-members can read for free by clicking my friend
link.
我所有的文章都是100%免費閱讀的!非會員可以通過單擊我的朋友鏈接免費閱讀。

Feb 1 177 12

See more recommendations

https://medium.com/@finndersen/langchain-vs-pydanticai-for-building-an-ai-agent-e0a059435e9d 24/24

You might also like