从零理解 LangChain:AI 智能体与工具调用的实战指南

从零理解 LangChain:AI 智能体与工具调用的实战指南

面向有编程基础的 AI 初学者,通过一个天气查询 Demo,深入理解 LangChain Agent 的工作原理


1. 引言 - 为什么需要 LangChain?

你一定听说过 ChatGPT、Claude 这些大语言模型。它们很强大——可以写代码、作诗、回答问题。但它们也有一些明显的局限:

  • 无法获取实时信息:问”今天北京天气怎么样?”,它只能回答训练数据截止日期前的信息
  • 没有执行能力:让它”帮我查一下数据库”,它做不到
  • 缺少持久记忆:聊完天关闭窗口,下次对话它就不记得你了
  • 无法精确控制输出:想要结构化的数据(如 JSON),它可能格式混乱

LangChain 就是为了解决这些问题而生的。你可以把它想象成:

大语言模型的”操作系统”——让 LLM 能够调用工具、记忆对话、与外部世界交互

一个形象的比喻:

角色 能力
大语言模型 (LLM) “大脑”——理解和推理
LangChain “手脚”——执行操作
Tools “工具箱”——各种具体功能

本文通过一个天气查询智能体 Demo,带你深入理解 LangChain 的核心概念——特别是 Agent(智能体)工具调用 的工作原理。

2. 什么是 Agent(智能体)?

核心概念:大脑 + 工具

Agent(智能体) 是 LangChain 的核心概念。用一个公式表达:

1
Agent = LLM(大脑) + Tools(工具) + 规划能力

想象一个现实中的场景:

你问助手:”帮我查一下今天北京的天气,然后告诉我适不适合跑步”

一个聪明的助手会:

  1. 理解意图 → 你想知道天气
  2. 规划步骤 → 先查天气,再判断是否适合跑步
  3. 调用工具 → 使用天气查询工具
  4. 综合回答 → 结合结果给出建议

LangChain Agent 就在做同样的事情!

Agent 的工作流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
┌─────────────────────────────────────────────────────────┐
│ Agent 工作流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 用户输入: "北京天气怎么样?" │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ LLM 分析意图 │ → 理解用户想要查询天气 │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 决策判断 │ → 需要调用 get_weather_for_location │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 执行工具调用 │ → get_weather_for_location("北京") │
│ └──────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 获取工具结果 │ → "晴朗,约 12C" │
│ └──────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 生成自然语言回复 │ → "北京今天晴朗,温度12度..." │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘

为什么要这样设计?

你可能会问:为什么不直接让程序判断调用哪个工具,而要让 LLM 来决策?

答案在于灵活性

传统程序 LangChain Agent
用 if-else 预定义所有情况 LLM 理解意图后动态决策
新增场景需要改代码 只需描述新工具,LLM 自动学会使用
无法处理模糊表达 能理解”外面”、”我这里”等自然语言

举个例子:

1
2
3
4
5
6
7
8
9
# 传统方式:硬编码判断
if "天气" in user_input and "北京" in user_input:
return get_weather("Beijing")
# 遇到 "外面冷不冷?" 就无能为力了

# Agent 方式:LLM 理解后决策
# 用户: "外面冷不冷?"
# Agent: get_user_location() → get_weather("Shanghai")
# 回复: "上海目前15度,有点凉,建议加件外套"

3. 工具调用(Tool Calling)原理

工具调用是 Agent 的核心能力。让我们深入理解它是如何工作的。

什么是工具调用?

工具调用(Function Calling) 是大语言模型的一项特殊能力:模型不仅能生成文本,还能生成”函数调用指令”。

简单来说:

  • 普通对话:用户提问 → 模型生成文本回答
  • 工具调用:用户提问 → 模型生成”调用某个函数”的指令 → 程序执行函数 → 模型基于结果生成回答

完整的交互流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
┌─────────────────────────────────────────────────────────────────┐
│ 工具调用完整流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 步骤1: 用户提问 │
│ ┌──────────────────────────────────────┐ │
│ │ "北京今天天气怎么样?" │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 步骤2: LangChain 将可用工具的描述发送给 LLM │
│ ┌──────────────────────────────────────┐ │
│ │ 可用工具: │ │
│ │ - get_weather_for_location(city) │ │
│ │ 描述: 根据城市名获取天气 │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 步骤3: LLM 决策并生成函数调用 │
│ ┌──────────────────────────────────────┐ │
│ { │ │
│ "name": "get_weather_for_location", │ │
│ "arguments": {"city": "北京"} │ │
│ } │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 步骤4: LangChain 执行函数 │
│ ┌──────────────────────────────────────┐ │
│ │ 执行: get_weather_for_location("北京") │ │
│ │ 返回: "晴朗,约 12C" │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 步骤5: 将函数结果返回给 LLM 生成最终回复 │
│ ┌──────────────────────────────────────┐ │
│ │ "北京今天天气晴朗,温度约12摄氏度, │ │
│ │ 非常适合外出活动!" │ │
│ └──────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

代码示例:定义工具

在 LangChain 中,定义工具非常简单——只需要一个函数加一个装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain.tools import tool

@tool # ← @tool 装饰器自动生成工具的 JSON Schema 描述
def get_weather_for_location(city: str) -> str:
"""根据城市名获取天气。

这个文档字符串会被发送给 LLM,帮助模型理解工具用途!
"""
# 实际应用中,这里会调用真实的天气 API
weather_data = {
"北京": "晴朗,约 12C",
"上海": "多云伴轻风,约 15C",
"深圳": "温暖偏湿,约 24C",
}
return weather_data.get(city, "暂无数据")

关键技术点

  1. @tool 装饰器的魔法

    • 自动解析函数签名生成 JSON Schema
    • 提取函数文档字符串发送给 LLM
    • 让 LLM 理解”这个工具是做什么的”、”需要什么参数”
  2. LLM 的决策能力

    • 根据用户输入判断是否需要调用工具
    • 自动提取和填充工具参数
    • 可能链式调用多个工具
  3. LangChain 的执行层

    • 接收 LLM 的调用指令
    • 执行实际函数
    • 将结果返回给 LLM 继续处理

4. 实战 Demo:天气查询智能体

现在让我们看一个完整的项目——一个能够查询天气、理解用户位置的智能聊天助手。

项目架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──────────────────────────────────────────────────────────┐
│ 项目架构图 │
├──────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ main.py │ │
│ │ (CLI 入口,参数解析) │ │
│ └─────────────────────┬──────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ runner.py │ │
│ │ (运行流程控制、流式输出、多轮对话) │ │
│ └─────────────────────┬──────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ factory.py │ │
│ │ (Agent 构建器) │ │
│ └───────────────┬─────────────┬──────────────────────┘ │
│ │ │ │
│ ┌───────▼─────┐ ┌───▼──────┐ ┌─────────────┐ │
│ │ llm.py │ │ tools.py │ │ memory.py │ │
│ │ (模型初始化) │ │(工具定义) │ │(会话记忆) │ │
│ └─────────────┘ └──────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────┘

核心代码解析

1. Agent 构建 (factory.py)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy

def build_advanced_agent():
"""构建高级版 agent(工具 + 结构化输出 + 记忆)"""
model = build_deepseek_model() # 初始化 DeepSeek 模型
checkpointer = build_checkpointer() # 初始化记忆组件

return create_agent(
model=model, # LLM "大脑"
system_prompt=SYSTEM_PROMPT, # 系统提示词
tools=[ # 可用工具列表
get_user_location, # 获取用户位置
get_weather_for_location, # 查询天气
],
context_schema=Context, # 上下文结构定义
response_format=ToolStrategy(ResponseFormat), # 结构化输出
checkpointer=checkpointer, # 记忆检查点
)

参数解读:

参数 作用 类比
model 提供推理能力 代理人的”大脑”
tools 可调用的工具 代理人的”工具箱”
system_prompt 设定角色和行为 给代理人的”工作指南”
checkpointer 保存对话历史 代理人的”笔记本”

2. 工具定义 (tools.py)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain.tools import tool

@tool
def get_weather_for_location(city: str) -> str:
"""根据城市名获取天气。"""
resolved_city = resolve_city_name(city)
if resolved_city:
return WEATHER_BY_CITY[resolved_city]
return f"暂无 {city} 的实时数据"

@tool
def get_user_location(runtime) -> str:
"""获取当前用户所在位置。"""
return USER_LOCATION_BY_ID.get(runtime.context.user_id, "San Francisco")

3. 运行流程 (runner.py)

1
2
3
4
5
6
7
8
9
10
11
def run_advanced_demo(question: str, thread_id: str, user_id: str):
"""运行高级模式 demo"""
agent = build_advanced_agent()

# 配置会话ID,用于记忆
config = {"configurable": {"thread_id": thread_id}}

# 流式输出,实时展示生成过程
for chunk in agent.stream({"messages": [question]}, config):
# 处理并显示每个生成片段
...

运行效果

基础模式(单工具调用):

1
$ python src/agent/main.py --mode basic --question "北京天气怎么样?"

输出:

1
2
正在查询天气...
北京今天晴朗,温度约12摄氏度。

高级模式(多轮对话 + 结构化输出):

1
$ python src/agent/main.py --mode advanced --question "北京天气怎么样?"

输出:

1
2
3
4
5
6
7
8
9
🤖 北京今天天气晴朗,温度约12度。非常适合外出活动!

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 结构化输出:
punny_response: "北京今天晴朗宜人,12度正好不冷不热!"
weather_conditions: "晴朗,约 12C"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

继续聊天(输入 exit 退出) > 明天呢?

(后续对话会自动记住之前讨论的是北京)

5. 高级特性

这个 Demo 不仅展示了基础的工具调用,还实现了几个高级特性。

5.1 结构化输出

问题:自然语言输出格式不稳定,难以被程序解析。

解决方案:使用 Pydantic 定义输出结构,强制 LLM 返回格式化数据。

1
2
3
4
5
6
from pydantic import BaseModel

class ResponseFormat(BaseModel):
"""定义输出的结构"""
punny_response: str # 幽默风格的回复
weather_conditions: str | None = None # 天气详情(可选)

使用方式

1
2
3
4
5
6
7
8
from langchain.agents.structured_output import ToolStrategy

return create_agent(
model=model,
tools=tools,
response_format=ToolStrategy(ResponseFormat), # 强制结构化输出
...
)

输出对比:

普通输出 结构化输出
“北京今天晴朗,温度约12度” {"punny_response": "北京今天晴朗宜人...", "weather_conditions": "晴朗,约 12C"}
格式不确定,程序难以解析 格式固定,程序可直接使用

5.2 会话记忆

问题:默认情况下,LLM 每次对话都是独立的,无法记住之前的内容。

场景示例

1
2
3
用户: 北京天气怎么样?
Agent: 北京今天晴朗,约12度。
用户: 明天呢? ← Agent 不知道这是在问"北京明天的天气"

解决方案:使用 checkpointer 保存对话状态。

1
2
3
4
5
6
7
8
9
from langchain.checkpoints.memory import InMemorySaver

def build_checkpointer():
"""创建内存检查点,保存对话历史"""
return InMemorySaver()

# 使用时指定 thread_id,不同 thread 隔离
config = {"configurable": {"thread_id": "user-session-123"}}
agent.invoke({"messages": [question]}, config)

工作原理

1
2
3
4
5
6
7
8
9
InMemorySaver (内存存储)

├── thread_id="user-001" (用户A的会话)
│ ├── 第1轮: ["北京天气怎么样?", "北京今天晴朗..."]
│ ├── 第2轮: ["明天呢?", "北京明天预计..."] ← 自动记住上下文
│ └── ...

└── thread_id="user-002" (用户B的会话,完全独立)
└── ...

5.3 城市名智能解析

问题:用户输入城市名的方式千奇百怪:

  • “北京”、”Beijing”、”Peking”
  • “beijing天气”、”北京呢?”
  • 甚至 “京市”、”那边的城市”

解决方案:多层解析策略 + LLM 兜底

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def resolve_city_name(city: str) -> str | None:
"""智能解析城市名,支持多种输入方式"""

# 第1层:标准名直接匹配(最快)
if city in WEATHER_BY_CITY:
return city

# 第2层:别名精确匹配
for canonical, aliases in CITY_ALIASES.items():
if normalize(city) in [normalize(a) for a in aliases]:
return canonical

# 第3层:包含匹配(处理 "beijing天气" 这类)
for canonical, aliases in CITY_ALIASES.items():
if any(normalize(a) in normalize(city) for a in aliases):
return canonical

# 第4层:LLM 兜底(处理模糊输入,但成本较高)
return translate_city_with_llm(city, tuple(WEATHER_BY_CITY.keys()))

策略对比:

策略 速度 成本 适用场景
字典匹配 极快 免费 标准输入
别名匹配 极快 免费 常见变体
包含匹配 免费 混合输入
LLM兜底 较慢 API费用 模糊/未见过输入

设计理念:先用规则快速处理常见情况,最后才用 LLM 处理复杂情况,兼顾效率和智能。

6. 总结与延伸

核心概念回顾

通过这个天气查询 Demo,我们学习了 LangChain 的核心概念:

概念 理解要点
LLM 提供理解和推理能力的”大脑”
Agent LLM + 工具 + 规划能力 = 智能体
Tool Calling LLM 生成函数调用指令,程序执行后返回结果
Memory 保存对话历史,实现多轮上下文
Structured Output 强制 LLM 返回固定格式的数据

Agent 的核心价值

Agent 相比传统编程方式的核心价值在于:

  1. 理解意图而非匹配模式

    • 传统:if "天气" in input: → 硬编码规则
    • Agent:LLM 理解语义后动态决策
  2. 扩展简单

    • 传统:新增场景需要修改代码逻辑
    • Agent:只需添加新工具,LLM 自动学会使用
  3. 处理模糊输入

    • 传统:无法理解”外面”、”我这里”等上下文表达
    • Agent:结合记忆和用户位置工具,智能推理

快速上手指南

如果你想运行这个 Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 克隆项目
git clone https://git.liupx.com/study/langchain_demo_first
cd langchain_demo_first

# 2. 创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate

# 3. 安装依赖
pip install -r requirements.txt

# 4. 配置环境变量
cp .env.example .env
# 编辑 .env,填入你的 DEEPSEEK_API_KEY

# 5. 运行
python src/agent/main.py --mode advanced --question "北京天气怎么样?"

下一步学习

如果你想继续深入 LangChain,推荐的学习路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
基础阶段(当前)
├── Agent 概念 ✓
├── 工具调用 ✓
└── 记忆机制 ✓

进阶阶段
├── LangGraph:复杂工作流编排
├── 自定义工具开发
├── 不同类型的 Memory
└── 错误处理与重试

实战阶段
├── RAG(检索增强生成)
├── 多 Agent 协作
├── Agent 与数据库交互
└── 生产环境部署

参考资源

7. 参考资料

相关文档

本项目文档

源码索引

文件 功能
main.py CLI 入口,参数解析
factory.py Agent 构建
tools.py 工具定义,城市名解析
runner.py 运行流程,流式输出
llm.py DeepSeek 模型初始化
memory.py 会话记忆实现

关于作者:本文基于 langchain_demo_first 项目编写,这是一个适合 LangChain 入门的实战项目。欢迎 Star 和 Fork!