上一章节回顾
在上个章节中,完成了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 安装依赖
在项目根目录打开终端,执行:
pipinstall-rrequirements.txt4.4 配置密钥
编辑.env文件,填入你的真实 API Key:
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DEEPSEEK_BASE_URL=https://api.siliconflow.cn/v1 MODEL_NAME=deepseek-ai/DeepSeek-V34.5 运行
python main.py你会看到类似这样的输出:
用户: 北京今天天气怎么样? 助手: 北京 天气(2026-05-04 14:22:10) 🌤 天气:多云 🌡 温度:19°C 💧 湿度:62% 💨 风力:4 级 💡 建议:注意增减衣物。5. 逐文件深度解析
下面将依次展示每个文件的完整代码,并解释其设计意图。
5.1 项目骨架:requirements.txt和.gitignore
requirements.txt
langchain>=1.2.0 langchain-openai python-dotenv声明了必要依赖,使用>=1.2.0确保兼容本教程的create_agent接口。
.gitignore
.env __pycache__/ *.pyc .venv/保护密钥,忽略临时文件。
5.2 配置中心:app/config.py
importosfrompathlibimportPathfromdotenvimportload_dotenv# 定位项目根目录(config.py 的上两级目录)PROJECT_ROOT=Path(__file__).resolve().parent.parent# 加载 .env 文件(绝对路径,不受执行目录影响)load_dotenv(PROJECT_ROOT/".env")# 读取必要配置DEEPSEEK_API_KEY=os.getenv("DEEPSEEK_API_KEY")ifnotDEEPSEEK_API_KEY:raiseValueError("⚠️ .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
fromlangchain_openaiimportChatOpenAIfromapp.configimportDEEPSEEK_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
importrandomfromdatetimeimportdatetimedefget_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"雨"incondition:advice="记得带伞!"elif"晴"incondition:advice="适合户外活动。"elif"霾"incondition: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
fromlangchain.agentsimportcreate_agentfromapp.llmimportdeepseek_llmfromapp.tools.weatherimportget_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即为助手回答 |
新接口的调用方式:
resp=agent.invoke({"messages":[{"role":"user","content":"北京天气怎么样?"}]})final_answer=resp["messages"][-1].content这种消息列表格式与底层 LLM 的交互完全对齐,更加透明和标准化。
5.6 程序入口:main.py
fromapp.agentimportagentif__name__=="__main__":queries=["北京今天天气怎么样?","上海适合户外运动吗?",]forqinqueries: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)