上一章节回顾
在上一节中,完成了 LangChain 1.2 环境搭建 ,并编写了一个最简单的 Agent 天气查询 Demo。具体实现了以下内容:
-
环境准备
- 创建并激活 Conda 环境
langchain_v1.2 - 安装了
langchain==1.2.0、langchain-deepseek、python-dotenv等核心依赖
- 创建并激活 Conda 环境
-
安全配置
- 创建
.env文件,存放DEEPSEEK_API_KEY和DEEPSEEK_BASE_URL - 编写
env_utils.py,利用python-dotenv加载.env中的密钥与地址
- 创建
-
模型实例化
- 编写
my_llm.py,通过ChatDeepSeek创建了一个指向 DeepSeek 官方的 LLM 实例
- 编写
-
第一个 Agent
- 在
quick_start.py中定义了一个模拟天气工具get_weather - 使用 LangChain 1.2 的
create_agent快速构建了一个能查询天气的智能助手 - 成功运行并观察到 Agent 自动调用工具、生成友好回复的完整消息流
- 在
成果 :我们跑通了 LangChain 1.2 最基本的 Agent 工作流,验证了模型与工具的联通性。
不足:所有代码堆在根目录的零散文件中,配置、模型、工具、Agent 耦合在一起,不利于扩展和维护。
下面的内容将对这个 Demo 进行深度模块化重构,构建一个结构清晰、可长期维护的项目模板。
🧪 LangChain 1.2 实战:构建一个模块化的天气查询 Agent
1.内容简介
通过一个 天气查询 Demo ,实现如何使用 LangChain 1.2 的 create_agent 新接口快速构建一个能够调用工具的智能助手。
项目采用模块化设计,将配置、模型、工具、Agent 分层解耦,不仅易于理解,更便于未来扩展和维护。
目标:
- 如何搭建一个结构优雅的 Python AI 项目
- 如何使用 LangChain 1.2 的
create_agent一键创建能使用工具的 Agent - 如何设计可扩展的工具目录,并让 Agent 自动调用
- 为什么分层目录结构对长期项目至关重要
2. 技术栈
| 组件 | 说明 |
|---|---|
| Python 3.10+ | 运行环境 |
| LangChain 1.2 | 大模型应用开发框架 |
| langchain-openai | 提供 OpenAI 兼容接口,用于连接 SiliconFlow |
| python-dotenv | 从 .env 文件加载敏感配置 |
| SiliconFlow | 国产大模型 API 中转平台(兼容 OpenAI 接口) |
3. 项目目录结构及其设计哲学
deepseek_agent_project/ # 项目根目录(一切从这里开始)
├── app/ # 核心应用包(隔离业务代码)
│ ├── __init__.py # 声明本目录为 Python 包
│ ├── config.py # 集中管理所有配置项
│ ├── llm.py # 负责实例化大模型
│ ├── agent.py # Agent 定义(大脑 + 工具)
│ └── tools/ # 工具包(可为 Agent 增加各种能力)
│ ├── __init__.py
│ └── weather.py # 天气查询工具的实现
├── .env # 敏感配置(密钥、地址),不提交 Git
├── .gitignore # 忽略本地文件
├── main.py # 程序入口,开箱即用
└── requirements.txt # 依赖声明,一键安装
为什么这样设计?
app/独立成包
所有业务逻辑收拢在app内,根目录保持清爽。未来若需部署为 Web 服务、编写测试、打包发布,只需操作app包即可,不会污染全局空间。config.py是唯一配置来源
所有环境变量、路径定义集中在一处,其余模块通过from app.config import ...获取,方便切换环境(开发/生产)和运行时校验。llm.py只生产模型实例
避免在多个地方重复初始化模型,统一管理参数(如temperature),后续换模型仅需改这一个文件。tools/目录独立
每个工具一个文件,新增能力只需在此目录添加文件,然后在agent.py中注册即可。工具模块与 Agent 实现彻底解耦,可单独测试。.env+python-dotenv
密钥与代码分离,杜绝安全风险。通过pathlib绝对定位,不管从哪个目录运行脚本都能正确加载配置。main.py作为演示入口
简洁地展示如何调用 Agent,同时证明各模块协作正常。用户可快速"看效果"。
核心理念:高内聚、低耦合、可扩展、可测试。
4. 快速开始
4.1 环境准备
- Python 3.10+
- 一个 SiliconFlow 账号,获取 API Key
- (可选)PyCharm 或 VS Code
4.2 克隆或创建项目
按上述目录结构创建所有文件和文件夹,或直接复制下文代码。
4.3 安装依赖
在项目根目录打开终端,执行:
bash
pip install -r requirements.txt
4.4 配置密钥
编辑 .env 文件,填入你的真实 API Key:
ini
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
DEEPSEEK_BASE_URL=https://api.siliconflow.cn/v1
MODEL_NAME=deepseek-ai/DeepSeek-V3
4.5 运行
bash
python main.py
你会看到类似这样的输出:
用户: 北京今天天气怎么样?
助手: 北京 天气(2026-05-04 14:22:10)
🌤 天气:多云
🌡 温度:19°C
💧 湿度:62%
💨 风力:4 级
💡 建议:注意增减衣物。
5. 逐文件深度解析
下面将依次展示每个文件的完整代码,并解释其设计意图。
5.1 项目骨架:requirements.txt 和 .gitignore
requirements.txt
txt
langchain>=1.2.0
langchain-openai
python-dotenv
声明了必要依赖,使用 >=1.2.0 确保兼容本教程的 create_agent 接口。
.gitignore
.env
__pycache__/
*.pyc
.venv/
保护密钥,忽略临时文件。
5.2 配置中心:app/config.py
python
import os
from pathlib import Path
from dotenv import load_dotenv
# 定位项目根目录(config.py 的上两级目录)
PROJECT_ROOT = Path(__file__).resolve().parent.parent
# 加载 .env 文件(绝对路径,不受执行目录影响)
load_dotenv(PROJECT_ROOT / ".env")
# 读取必要配置
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
if not DEEPSEEK_API_KEY:
raise ValueError("⚠️ .env 中缺少 DEEPSEEK_API_KEY,请检查!")
DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL", "https://api.siliconflow.cn/v1")
MODEL_NAME = os.getenv("MODEL_NAME", "deepseek-ai/DeepSeek-V3")
设计解读:
- 使用
Path(__file__).resolve().parent.parent确保无论从哪个目录启动程序,都能找到.env。 - 缺少关键配置时会立即抛出异常,避免在深层调用时才报错。
- 提供默认值(如模型名)让新用户开箱即用,同时保留修改空间。
5.3 模型实例化:app/llm.py
python
from langchain_openai import ChatOpenAI
from app.config import DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, MODEL_NAME
deepseek_llm = ChatOpenAI(
openai_api_key=DEEPSEEK_API_KEY,
openai_api_base=DEEPSEEK_BASE_URL,
model=MODEL_NAME,
temperature=0,
)
为什么用 ChatOpenAI 而不是 ChatDeepSeek?
SiliconFlow 的 API 完全遵守 OpenAI 的接口规范,使用 langchain-openai 的 ChatOpenAI 可以避免不同版本 langchain-deepseek 参数变动带来的兼容性问题,稳定性更高。
temperature=0 意味着模型输出确定性最强,适合演示和测试。
5.4 工具实现:app/tools/weather.py
python
import random
from datetime import datetime
def get_weather(city: str) -> str:
"""获取指定城市的实时天气信息(模拟)。
参数:
city: 城市名称,例如 '北京'。
返回:
包含天气状况、温度、湿度、风力及查询时间的字符串。
"""
# 模拟天气类型
conditions = ["晴天", "多云", "阴天", "小雨", "雷阵雨", "雾霾", "大风"]
temperature = random.randint(-5, 38)
humidity = random.randint(30, 90)
wind_speed = random.randint(1, 10)
condition = random.choice(conditions)
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 根据天气给出生活建议
if "雨" in condition:
advice = "记得带伞!"
elif "晴" in condition:
advice = "适合户外活动。"
elif "霾" in condition:
advice = "请佩戴口罩。"
else:
advice = "注意增减衣物。"
return (
f"{city} 天气({now})\n"
f"🌤 天气:{condition}\n"
f"🌡 温度:{temperature}°C\n"
f"💧 湿度:{humidity}%\n"
f"💨 风力:{wind_speed} 级\n"
f"💡 建议:{advice}"
)
LangChain 1.2 的增强体验 :
工具函数不需要 @tool 装饰器或复杂的 BaseTool 子类。只要满足以下条件:
- 有清晰的类型注解(
city: str) - 有 Docstring(帮助 Agent 理解函数的用途)
- 返回字符串
Agent 就能自动识别并调用它!这使得定义工具的门槛降到最低。
模拟数据的巧思 :
采用随机值模拟天气变化,每次查询结果不同,让 Demo 更生动、更像真实 API。同时返回结构化信息(温度、湿度、风力、建议),增强实用性。
5.5 Agent 大脑:app/agent.py
python
from langchain.agents import create_agent
from app.llm import deepseek_llm
from app.tools.weather import get_weather
# 使用 LangChain 1.2 的一键创建接口
agent = create_agent(
model=deepseek_llm,
tools=[get_weather],
system_prompt="你是一个助手,你可以查询城市的天气。",
)
这里体现了 LangChain 1.2 最大的简化:
| 旧版写法 (LangChain 0.x/1.0) | 新版 (LangChain 1.2) |
|---|---|
需要定义 ChatPromptTemplate,手动放置 {agent_scratchpad} 等占位符 |
只需一个 system_prompt 字符串 |
必须额外构建 AgentExecutor 实例 |
create_agent 直接返回可调用的 Agent 实例 |
调用时传入 {"input": "..."} |
调用格式为标准消息列表 {"messages": [{"role": "user", "content": "..."}]} |
输出通过 result["output"] 提取 |
输出是完整的消息列表,最后一条消息的 content 即为助手回答 |
新接口的调用方式:
python
resp = agent.invoke(
{"messages": [{"role": "user", "content": "北京天气怎么样?"}]}
)
final_answer = resp["messages"][-1].content
这种消息列表格式与底层 LLM 的交互完全对齐,更加透明和标准化。
5.6 程序入口:main.py
python
from app.agent import agent
if __name__ == "__main__":
queries = [
"北京今天天气怎么样?",
"上海适合户外运动吗?",
]
for q in queries:
print(f"用户: {q}")
resp = agent.invoke({"messages": [{"role": "user", "content": q}]})
final_message = resp["messages"][-1]
print(f"助手: {final_message.content}\n")
入口文件极端精简,仅展示如何调用 Agent。你可以将其替换为 FastAPI 路由、命令行工具等,无需改动核心逻辑。
6. 技术架构与 LangChain 1.2 特性剖析
6.1 整体架构
┌──────────┐
│ main.py │ (表示层)
└────┬─────┘
│ 调用
┌────▼─────────────────────────────┐
│ agent.py │ (Agent 层)
│ create_agent(model, tools, │
│ system_prompt) │
└────┬────────────┬────────────────┘
│ │
┌────▼─────┐ ┌──▼──────────────┐
│ llm.py │ │ tools/weather.py│ (能力层)
│模型实例化│ │ 工具函数 │
└────┬─────┘ └─────────────────┘
│
┌────▼─────┐
│config.py │ (配置层)
│ .env加载 │
└──────────┘
- 配置层 为所有层提供敏感参数。
- 能力层(llm + tools)是"大脑"和"手脚",由 Agent 层统一调度。
- Agent 层 负责理解用户意图、决策使用哪个工具、组装最终回答,对外暴露极简接口。
- 表示层(main.py)只负责展示,可轻易替换。
6.2 LangChain 1.2 的 create_agent 带来了什么?
- 极简创建:一行代码搞定 Agent,无需拼接模板和执行器。
- 工具自动识别:普通函数加类型注解和文档字符串即可被 Agent 理解,极大降低开发门槛。
- 标准消息接口:输入/输出均为消息列表,便于集成流式处理、上下文管理等高级功能。
- 开箱即用的容错 :Agent 内置了对工具调用格式错误的恢复机制(可通过
handle_parsing_errors调整)。 - 面向未来 :新版本 LangChain 的 Agent 图(LangGraph)与
create_agent兼容,后续可无缝升级到有状态的多步智能体。
6.3 项目如何展示 LangChain 1.2 的功能?
- 工具调用(Tool Calling) :用户询问天气,Agent 自动识别并调用
get_weather,将函数返回结果组织成自然语言。 - 角色设定(System Prompt) :通过
system_prompt定义助手的行为边界,Agent 会严格遵守。 - 模型无关性 :通过
ChatOpenAI兼容接口,轻松切换底层大模型(只需改config.py中的模型名)。 - 可扩展性 :在
tools/下新增工具文件并注册到agent.py,Agent 立即可用,无需修改其他代码。
7. 扩展思路(不改变功能,仅作提示)
虽然本 Demo 只包含一个天气工具,但架构已经为扩展做好准备:
- 添加新工具 :在
tools/下新建文件,定义任意函数,然后在agent.py的tools列表中追加即可。 - 替换真实 API :只需修改
weather.py的内部实现,调用和风或 OpenWeather 的 HTTP 接口,其余代码完全不变。 - 调整 Agent 行为 :修改
system_prompt可以改变助手的语气、能力范围。 - 部署为 Web 服务 :新建
api.py,导入agent对象,用 FastAPI 封装一个 POST 接口即可上线。
提示:若运行时遇到任何问题,请检查:
.env中的DEEPSEEK_API_KEY是否正确- 网络是否能访问
api.siliconflow.cn- 依赖是否安装完整(
pip list确认langchain版本 ≥ 1.2.0)