从零理解 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(工具) + 规划能力
想象一个现实中的场景:
你问助手:”帮我查一下今天北京的天气,然后告诉我适不适合跑步”
一个聪明的助手会:
理解意图 → 你想知道天气
规划步骤 → 先查天气,再判断是否适合跑步
调用工具 → 使用天气查询工具
综合回答 → 结合结果给出建议
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 的核心能力。让我们深入理解它是如何工作的。
什么是工具调用? 工具调用(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 def get_weather_for_location (city: str ) -> str : """根据城市名获取天气。 这个文档字符串会被发送给 LLM,帮助模型理解工具用途! """ weather_data = { "北京" : "晴朗,约 12C" , "上海" : "多云伴轻风,约 15C" , "深圳" : "温暖偏湿,约 24C" , } return weather_data.get(city, "暂无数据" )
关键技术点
@tool 装饰器的魔法
自动解析函数签名生成 JSON Schema
提取函数文档字符串发送给 LLM
让 LLM 理解”这个工具是做什么的”、”需要什么参数”
LLM 的决策能力
根据用户输入判断是否需要调用工具
自动提取和填充工具参数
可能链式调用多个工具
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_agentfrom langchain.agents.structured_output import ToolStrategydef build_advanced_agent (): """构建高级版 agent(工具 + 结构化输出 + 记忆)""" model = build_deepseek_model() checkpointer = build_checkpointer() return create_agent( model=model, 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
保存对话历史
代理人的”笔记本”
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() 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 BaseModelclass ResponseFormat (BaseModel ): """定义输出的结构""" punny_response: str weather_conditions: str | None = None
使用方式 :
1 2 3 4 5 6 7 8 from langchain.agents.structured_output import ToolStrategyreturn 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 InMemorySaverdef build_checkpointer (): """创建内存检查点,保存对话历史""" return InMemorySaver() 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 : """智能解析城市名,支持多种输入方式""" if city in WEATHER_BY_CITY: return city for canonical, aliases in CITY_ALIASES.items(): if normalize(city) in [normalize(a) for a in aliases]: return canonical for canonical, aliases in CITY_ALIASES.items(): if any (normalize(a) in normalize(city) for a in aliases): return canonical 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 相比传统编程方式的核心价值在于:
理解意图而非匹配模式
传统:if "天气" in input: → 硬编码规则
Agent:LLM 理解语义后动态决策
扩展简单
传统:新增场景需要修改代码逻辑
Agent:只需添加新工具,LLM 自动学会使用
处理模糊输入
传统:无法理解”外面”、”我这里”等上下文表达
Agent:结合记忆和用户位置工具,智能推理
快速上手指南 如果你想运行这个 Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 git clone https://git.liupx.com/study/langchain_demo_first cd langchain_demo_firstpython3 -m venv .venv source .venv/bin/activatepip install -r requirements.txt cp .env.example .env 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. 参考资料 相关文档
本项目文档
源码索引
关于作者 :本文基于 langchain_demo_first 项目编写,这是一个适合 LangChain 入门的实战项目。欢迎 Star 和 Fork!