LangChain系列文章超链接:

《Python+LangChain+大模型实战:使用通用配置加载器的Few‑Shot小样本提示词教程》​​​​​​​

《使用Python版LangChain调用外部函数实战:实现智能天气查询》

《Python + LangChain Agent 实战:从单城市查询到多城市天气智能对比》

一、前言

在LangChain框架的实际应用中,Chain(链式)架构凭借其简洁高效的特性,成为处理简单工具调用场景的常用选择,尤其在天气查询这类具有明确流程的任务中,能够快速实现“调用天气函数—获取数据—返回结果”的固定链路。我们可以轻松通过Chain方式直接调用天气函数,按照预设的参数和流程,精准获取单个城市的气温、降水、风力等基础气象信息,满足“查询扬州今日天气”这类简单且明确的需求,如《使用Python版LangChain调用外部函数实战:实现智能天气查询》这边文章中所实现的功能。

但Chain架构的核心局限的在于其固定化的执行逻辑——它如同一条预设好轨道的列车,只能按照既定路线推进,无法根据实际需求的变化灵活调整方向。这种局限性在面对复杂的自然语言提问时,会变得尤为突出,比如当用户提出“比较一下南京和扬州哪个城市的天气更适合出去踏青”这样的需求时,Chain方式便会陷入无能为力的困境。踏青的适宜度不仅需要对比两地的基础气象数据,还需结合气温舒适度、降水概率、风力大小等多重因素综合判断,而固定模式的Chain只能机械调用天气函数获取单一数据,无法自主规划“查询两地天气—提取关键指标—对比分析—得出结论”的完整流程,更无法应对这种需要多步骤推理和动态决策的复杂场景。

正是这种Chain架构在复杂任务中的适配短板,推动了LangChain Agent(智能体)模式的引入与应用,成为破解复杂天气查询及各类多步骤任务的核心解决方案。与Chain“固定流程、被动执行”的逻辑不同,Agent搭载了具备自主思考能力的决策模块,相当于为工具调用赋予了“大脑”,其核心优势在于动态规划与灵活适配的能力。面对“比较南京和扬州哪个更适合踏青”这类复杂需求时,Agent无需预设固定流程,而是先自主拆解需求:明确踏青所需的核心气象指标(如气温在15-25℃、无降水、风力≤3级等),再规划执行步骤——先调用天气函数分别获取两地的实时及未来1-2天的气象数据,接着提取关键指标进行对比分析,若遇到数据不完整的情况,还能自主二次调用工具补充查询,最终整合所有信息得出“哪座城市更适合踏青”的明确结论。这种“理解需求—规划步骤—调用工具—分析结果—优化调整”的闭环能力,不仅完美破解了Chain模式无法应对的复杂天气查询难题,更让AI工具跳出了“机械执行”的局限,真正实现了从“被动响应”到“主动决策”的升级,让LangChain框架在实际应用中更具灵活性、智能化和实用性。


二、Chain架构的问题

《使用Python版LangChain调用外部函数实战:实现智能天气查询》这篇文章中,使用LangChain包中的chain链调用挑起查询的外部函数实现了大模型的天气查询功能,如告知大模型“帮我查询一下扬州的天气”,大模型能实时查询出当前的天气,具体代码可参考前文。但是如果告知大模型“对比一下南京和扬州的天气,哪个城市更适合出去踏青”,大模型则无能为力。具体输出如下:

E:\pycharm_code\.venv\Scripts\python.exe E:\pycharm_code\langchain_test\langchain_chain.py 
{'app_id': 'ab203b794f7b27b777bb48f4eb30838c'}
ab203b794f7b27b777bb48f4eb30838c
定位成功:Nanjing City, CN
{'coord': {'lon': 118.7915, 'lat': 32.0616}, 'weather': [{'id': 800, 'main': 'Clear', 'description': '晴', 'icon': '01n'}], 'base': 'stations', 'main': {'temp': 19.26, 'feels_like': 18.49, 'temp_min': 19.26, 'temp_max': 19.26, 'pressure': 1012, 'humidity': 48, 'sea_level': 1012, 'grnd_level': 1010}, 'visibility': 10000, 'wind': {'speed': 2.44, 'deg': 110, 'gust': 3.64}, 'clouds': {'all': 0}, 'dt': 1776601919, 'sys': {'country': 'CN', 'sunrise': 1776547906, 'sunset': 1776594956}, 'timezone': 28800, 'id': 1799962, 'name': 'Nanjing', 'cod': 200}
使用天气查询返回的结果:
根据您提供的实时数据,以下是南京当前的天气情况解析:

**总体概况:**
目前南京天气晴朗,气温舒适,体感较为凉爽。

**详细数据:**
*   **天气状况:** 晴(Clear),天空无云(云量为 0%)。
*   **气温:** 当前温度为 **19.26°C**,体感温度约为 18.49°C。今日最低温和最高温均为 19.26°C(数据更新于当前时刻,未显示全天范围)。
*   **湿度与气压:** 空气湿度为 **48%**,较为干爽;气压为 **1012 hPa**,处于标准水平。
*   **风况:** 风向为东南偏东(110度),风速 **2.44 米/秒**(约 8.8 公里/小时),阵风风速可达 3.64 米/秒。
*   **能见度:** 10 公里,视野清晰。
*   **日出日落:** 今日日出时间为 05:31(UTC+8),日落时间为 18:35(UTC+8)。

**总结:**
这是一个适合户外活动的夜晚,气温适宜,微风轻拂,且无降水风险。

进程已结束,退出代码为 0

从代码输出可以看出,大模型只查询了南京的实时天气,并非调用天气函数分别查询南京和扬州的天气,然后根据两次查询的天气结果,分析得出哪个城市更适合出去踏青。我们来看一下Chain的整个流程图:

这张流程图展示了一个基于固定 Chain 的天气查询处理流程,其核心缺点在于 Chain 的工作模式是预先定义好的线性流程,只能按固定的 “用户输入→提取信息→调用天气工具→分析数据→输出结果” 路径执行,无法自主判断用户意图、灵活选择工具或调整流程,而引入 Agent 的核心价值就是让流程从 “固定执行” 升级为 “智能决策”,由 Agent 根据用户问题自主判断是否需要调用工具、调用哪个工具、以及如何组合工具完成任务,从而解决 Chain 模式无法应对复杂多变场景的根本问题。


三、Agent 核心介绍

LangChain Agent(智能体)是LangChain框架中具备自主决策、动态规划和工具调用能力的核心模块,本质是“决策大脑+工具集合”的组合体,核心目标是解决Chain架构无法应对的多步骤、复杂逻辑、需要动态调整的任务。与Chain的“固定流程执行”不同,Agent拥有自主思考和推理能力,能够根据用户输入的自然语言需求,自主判断任务目标、拆解执行步骤、选择合适的工具(如天气查询函数、数据处理工具等),并根据工具返回的中间结果,灵活调整执行策略,直至完成任务、输出最终答案。

LangChain Agent的核心价值的在于“智能化适配复杂场景”,尤其适用于需求模糊、步骤不固定、需要多工具协作的任务——除了前文提到的多城市天气对比踏青适宜度,还可应用于多数据源整合、复杂问题拆解、多工具联动等场景。其核心特点可概括为三点:一是自主决策,无需预设固定流程,能根据需求动态规划步骤;二是工具联动,可灵活调用各类预设工具(函数、API、数据库等),弥补自身能力局限;三是闭环迭代,能根据中间结果校验执行效果,及时调整策略,避免无效执行。

执行流程

LangChain Agent的执行流程核心是“决策-执行-反馈”的标准闭环逻辑,具体的执行流程如下图所示:

核心决策模块全程主导,根据用户需求拆解步骤、调度工具,结合反馈结果动态调整执行策略——若数据不完整则补充调用工具,若结论不明确则进一步获取信息,直至输出清晰、准确的最终答案,下面逐个解释一下每个模块的工作:

  • 用户需求输入:接收用户自然语言需求(如“比较南京和扬州哪个更适合踏青”),传递至核心决策模块。

  • Agent核心决策模块:架构核心,负责解析用户需求、拆解任务步骤、判断下一步行动(如“需要调用天气函数获取两地数据”“需要对比气象指标”),同时接收反馈模块的结果,调整执行策略。

  • 工具选择与调度模块:根据核心决策模块的指令,选择适配的工具(如天气查询函数),并调度工具执行,传递相关参数(如城市名称、查询时间)。

  • 工具集合:Agent可调用的各类外部工具,包括函数、API、数据库等,本文场景中主要为天气查询函数,用于获取城市气象数据。

  • 结果反馈与校验模块:接收工具执行的中间结果(如两地气象数据),校验数据完整性和有效性,反馈给核心决策模块,供其判断是否需要继续调用工具或进入下一步分析。

  • 最终结果输出模块:将核心决策模块整合分析后的最终结论,以自然语言形式反馈给用户。


四、项目结构

langchain_test/
├── utils/
│   └── weather_util.py
├── config_loader.py
├── init_llm.py
└── langchain_agent.py

五、完整分文件源代码

1. config_loader.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Project :pythonProject
@File    :config_loader.py
@Author  :BillFang
@Date    :2026/4/11 14:39
@Description :
"""
import configparser
import os
from typing import Dict, Any


class ConfigLoader:
    # 单例模式:整个程序只加载一次配置,避免重复读文件
    _instance = None
    _config = None

    def __new__(cls, config_path: str = r"D:/pythonCode/pythonProject/resources/config.properties"):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._load_config(config_path)
        return cls._instance

    def _load_config(self, config_path: str):
        """内部方法:加载配置文件,做基础校验"""
        if not os.path.exists(config_path):
            raise FileNotFoundError(
                f"配置文件不存在: {os.path.abspath(config_path)}\n"
                "请在项目根目录创建 config.properties 文件,参考模板格式。"
            )

        # 用utf-8编码读取,避免中文乱码
        self._config = configparser.ConfigParser()
        self._config.read(config_path, encoding="utf-8")

    def get(self, section: str, key: str) -> str:
        """
        通用获取配置的方法
        :param section: 配置的分组(比如[xiaomi]就是"xiaomi")
        :param key: 配置的键名(比如api_key)
        """
        try:
            return self._config[section][key].strip()
        except KeyError as e:
            raise ValueError(
                f"配置缺失: 找不到 [{section}] 下的 {key} 配置,请检查 config.ini"
            ) from e

    def get_xiaomi_config(self) -> Dict[str, Any]:
        """专门获取小米MiMo模型的完整配置,自动转换类型"""
        section = "xiaomi"
        # 必填配置
        config = {
            "api_key": self.get(section, "api_key"),
            "api_base_url": self.get(section, "api_base_url"),
            "model": self.get(section, "model"),
        }

        # 可选配置,带默认值,用户不写也不会报错
        try:
            config["temperature"] = float(self.get(section, "temperature"))
        except:
            config["temperature"] = 0.7

        try:
            config["max_tokens"] = int(self.get(section, "max_tokens"))
        except:
            config["max_tokens"] = 1024

        return config

    def get_openweather_config(self) -> Dict[str, Any]:
        section = "openweather"
        # 必填配置
        config = {
            "app_id": self.get(section, "app_id"),
        }

        return config

这是一个配置加载工具类,采用单例模式确保只加载一次配置,负责读取指定路径下的 config.properties 配置文件,提供通用配置获取方法,并专门封装了获取小米大模型和天气接口配置的函数,为程序提供稳定的配置服务。


2. weather_util.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Project :pythonProject
@File    :weather_util.py
@Author  :BillFang
@Date    :2026/4/15 09:19
@Description :
"""

import requests
from langchain_core.tools import tool

from config_loader import ConfigLoader


class OpenWeather():
    def __init__(self, APPID):
        self.app_id = APPID

    def get_lat_lon(self, city_name):
        geo_url = "http://api.openweathermap.org/geo/1.0/direct"
        params = {
            "q": city_name,
            "limit": 1,
            "appid": self.app_id,
        }
        try:
            res = requests.get(geo_url, params=params)
            res.raise_for_status()
            data = res.json()
            if not data:
                print("未找到该城市")
                return None, None
            lat = data[0]["lat"]
            lon = data[0]["lon"]
            name = data[0]["name"]
            country = data[0]["country"]
            print(f"定位成功:{name}, {country}")
            return lat, lon
        except Exception as e:
            print("获取经纬度失败:", e)
            return None, None


@tool
def get_city_weather_data(city_name) -> dict:
    """
        调用 OpenWeatherMap API 获取指定经纬度的天气信息
        :param lat: 纬度
        :param lon: 经度
        :param appid: OpenWeatherMap 申请的 API Key
        :return: 天气数据字典 / None
        """
    config_loader = ConfigLoader()
    openweather_config = config_loader.get_openweather_config()
    print(openweather_config)
    print(openweather_config["app_id"])
    weather_client = OpenWeather(APPID=openweather_config["app_id"])
    base_url = "https://api.openweathermap.org/data/2.5/weather"
    lat, lon = weather_client.get_lat_lon(city_name)
    # 请求参数
    params = {
        "lat": lat,
        "lon": lon,
        "appid": weather_client.app_id,
        "units": "metric",  # 单位:metric=摄氏度,imperial=华氏度,默认开尔文
        "lang": "zh_cn"  # 返回中文描述
    }

    try:
        # 发送 GET 请求
        response = requests.get(base_url, params=params)
        # 检查请求是否成功
        response.raise_for_status()
        # 解析 JSON 数据
        weather_data = response.json()
        return weather_data

    except requests.exceptions.RequestException as e:
        print(f"请求出错:{e}")
        return None


if __name__ == '__main__':
    # 方法加上@tool时必须使用.invoke方法调用
    print(get_city_weather_data.invoke('扬州'))

这段代码是天气查询工具模块,通过 OpenWeather API 获取城市天气,先根据城市名获取经纬度,再查询实时天气,封装成 LangChain 可调用的工具函数,供 Agent 自动调用使用。


3. init_llm.py

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Project :pythonProject
@File    :init_llm.py
@Author  :BillFang
@Date    :2026/4/17 15:38
@Description :
"""
from typing import Any, Sequence

from langchain_core.messages import AIMessage
from langchain_core.prompt_values import PromptValue
from langchain_core.runnables import Runnable
from langchain_openai import ChatOpenAI

from config_loader import ConfigLoader
from weather_util import get_city_weather_data


def load_llm_config() -> dict:
    """
    加载LLM配置信息

    Returns:
        dict: 包含api_key、base_url、model的配置字典
    """
    try:
        config_loader = ConfigLoader()
        xiaomi_config = config_loader.get_xiaomi_config()
        return {
            "api_key": xiaomi_config["api_key"],
            "base_url": xiaomi_config["api_base_url"],
            "model": xiaomi_config["model"]
        }
    except KeyError as e:
        raise ValueError(f"配置文件缺少必要的键: {e}")
    except Exception as e:
        raise RuntimeError(f"加载配置失败: {e}")


def init_llm() -> ChatOpenAI:
    """
    初始化LLM实例并绑定工具

    Returns:
        ChatOpenAI: 绑定了天气查询工具的LLM实例
    """
    llm_config = load_llm_config()
    llm = ChatOpenAI(
        api_key=llm_config["api_key"],
        base_url=llm_config["base_url"],
        model=llm_config["model"]
    )
    return llm


def init_llm_with_tools() -> Runnable[PromptValue | str | Sequence[Any], AIMessage]:
    # 绑定工具
    llm = init_llm()
    tools = [get_city_weather_data]
    return llm.bind_tools(tools)

这段代码是LLM 模型初始化工具模块,负责从配置文件加载大模型参数、创建模型实例,并给模型绑定天气查询工具,供上层 Agent 调用,整体功能简洁且专一。


4. langchain_agent.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Project :pythonProject
@File    :langchain_agent.py
@Author  :BillFang
@Date    :2026/4/17 13:58
@Description : LangGraph Agent 实现天气查询功能
"""
# 标准库导入
from typing import Annotated, Literal
# 第三方库导入
from langchain_core.messages import SystemMessage, HumanMessage
from langgraph.graph import MessagesState, StateGraph
from langgraph.prebuilt import ToolNode
# 本地模块导入
from init_llm import init_llm_with_tools
from weather_util import get_city_weather_data


# 初始化LLM实例
llm = init_llm()

def main():
    """主函数:执行天气查询示例"""
    try:
        # 构建工作流
        agent = create_agent(
            llm,
            tools=[get_city_weather_data],
            system_prompt="你是一个非常厉害的AI助手,但不了解实时的一些知识"
        )

        # 执行查询
        query = "今天北京和扬州的天气比较,哪个城市的天气更适合出去踏青?"
        result = agent.invoke(
            {"messages": [HumanMessage("今天北京和扬州的天气比较,哪个城市的天气更适合出去踏青?")]}
        , debug=True)
        print(result["messages"][-1].content)
    except Exception as e:
        print(f"程序执行失败: {e}")


if __name__ == '__main__':
    main()

该代码通过create_agent构建具备工具调用能力的 AI Agent,先从外部模块加载大模型和天气查询工具函数,定义主函数构建工作流,将天气工具绑定到 Agent 并设置系统提示词,然后传入包含多城市天气对比的复杂用户查询,Agent 会自主判断是否需要调用工具、自动执行天气查询工具获取数据,最终整理结果输出,整体实现了不依赖固定流程、可自主决策完成复杂天气任务的智能交互。


六、运行结果

查询结果:
根据查询到的天气数据,我来为您分析一下北京和扬州的天气情况:

**北京天气:**
- 天气状况:晴天
- 温度:20.94°C
- 湿度:32%
- 风速:3.27 m/s
- 能见度:10公里

**扬州天气:**
- 天气状况:阴天,多云
- 温度:21.75°C
- 湿度:64%
- 风速:3.29 m/s
- 能见度:10公里

**综合比较:**
从踏青的角度来看,**北京的天气更适合出去踏青**,原因如下:

1. **天气状况**:北京是晴天,阳光充足,视野开阔,非常适合户外活动;而扬州是阴天多云,光线相对较暗。
2. **湿度条件**:北京湿度较低(32%),体感舒适;扬州湿度较高(64%),可能会感觉有些闷热潮湿。
3. **温度适宜**:两个城市的温度都很舒适(20-22°C左右),但北京的干燥天气更适合长时间户外活动。
4. **能见度**:两地能见度都很好(10公里),但晴天的北京视野会更加开阔。

**建议**:如果您今天计划踏青,北京是更好的选择。不过扬州的温度稍高一点,如果您更喜欢温和的天气,也可以考虑扬州,只是需要做好防云遮阳的准备。

进程已结束,退出代码为 0

七、运行结果分析

本次运行结果完美验证了LangChain Agent在复杂天气查询场景中的核心优势,结合输出内容与程序逻辑,可从4个核心维度展开分析,清晰体现Agent与传统Chain架构的本质区别:

第一,自主理解复杂需求,无需人工拆解。用户需求为“比较北京和扬州哪个城市的天气更适合出去踏青”,属于典型的多步骤复杂需求,需经历“获取两地数据—提取核心指标—对比分析—给出结论”四个环节。Agent无需预设固定流程,通过核心决策模块自动解析需求核心(踏青适宜度的关键气象指标),无需人工干预即可启动完整执行链路,这是传统Chain架构无法实现的——Chain仅能执行“单一城市天气查询”的固定流程,无法应对多城市对比、综合分析类需求。

第二,自主多轮调用工具,保障数据完整性。运行过程中,Agent根据需求自主判断需要调用2次天气查询工具(分别获取北京、扬州的实时气象数据),无需人工编写多轮调用逻辑。工具调用后,自动接收返回的JSON数据(包含气温、湿度、风速、能见度等核心信息),并校验数据完整性,确保后续分析有足够的数据支撑,避免了传统代码中“手动调用工具、手动校验数据”的繁琐操作。

第三,智能分析数据,输出人性化结论。Agent不仅能获取实时气象数据,还能结合“踏青”场景的需求,自动提取关键对比指标(天气状况、湿度、温度、能见度),并进行结构化分析——明确指出北京晴天、低湿度的优势,同时客观说明扬州的特点及适配人群,最终给出可落地的踏青建议。这种“数据获取—分析解读—建议输出”的一体化能力,让结果更具实用性,面向最终用户可直接开箱即用,而传统工具调用仅能返回原始JSON数据,需额外编写分析逻辑。

第四,闭环执行,容错性强。程序运行过程中,agent自动判断是否需要继续调用工具:若工具返回数据完整,则进入分析环节;若数据缺失(如某城市经纬度获取失败、气象数据为空),则会自动重新调用工具补充查询,直至获取有效数据。本次运行中,两地气象数据均完整返回,Agent顺利完成分析并输出结论,进程正常结束,充分体现了其闭环迭代的执行特性。

此外,运行结果还直观对比了“Agent智能查询”与“传统大模型直接查询”的差异——若直接询问大模型天气,会因无法访问实时数据而无法给出有效答案(参考参考文档中“直接询问大模型”的输出结果),而Agent通过调用OpenWeatherMap API获取实时数据,完美解决了大模型“知识库过期、无实时访问能力”的痛点,让查询结果更精准、更具时效性。


八、总结

本文以“多城市天气对比踏青适宜度”为实战场景,完整实现了LangChain Agent的天气查询功能,从项目架构设计、代码实现到运行验证,清晰展现了Agent如何破解传统Chain架构的局限,核心总结如下:

从核心逻辑来看,传统单城市天气查询的核心痛点的是“固定流程+单次调用+无记忆+无分析”,仅能满足简单的查询需求,无法应对多步骤、复杂逻辑的场景;而LangChain Agent则实现了“自主决策+多轮调用+上下文记忆+智能分析”的升级,其核心价值在于为大模型赋予了“主动思考”的能力——无需人工预设执行步骤,无需手动处理工具调用与数据校验,即可自主拆解复杂需求、调度工具、分析数据、输出结论,真正实现了从“机械执行”到“智能决策”的跨越。

从实战价值来看,本文采用标准工程化项目结构(分模块封装配置、工具、LLM初始化、主程序),代码可直接复用、可扩展:config_loader.py实现配置统一管理,避免硬编码带来的维护难题;weather_util.py封装天气查询工具,通过@tool装饰器快速集成到LangChain生态;init_llm.py统一初始化LLM并绑定工具,降低代码冗余;langchain_agent.py通过create_agent函数构建agent,实现Agent的闭环执行。这种结构设计不仅提升了代码的可读性和可维护性,也为后续拓展多工具(如快递查询、股票查询)提供了便捷——只需新增工具函数,无需重构核心流程。

从技术意义来看,本次实战清晰验证了LangChain工具调用能力的核心价值:LangChain Agent是连接大模型与外部世界的“桥梁”,通过将外部API(如OpenWeatherMap)封装为Tool,让大模型突破了“知识库过期”“无实时访问能力”的局限,拓展了大模型的应用边界。无论是多城市天气对比、多数据源整合,还是复杂问题拆解,Agent都能凭借其自主决策和闭环迭代能力,高效完成任务,相比传统代码更具智能化、灵活性和扩展性。

综上,LangChain Agent并非对Chain架构的替代,而是对复杂场景的补充与升级——简单、固定流程的任务可采用Chain实现高效执行,而多步骤、复杂逻辑、需要动态调整的任务,Agent则是更优选择。本文的实战案例不仅为LangChain Agent的学习提供了可落地的参考,也为大模型应用开发(尤其是实时数据查询类场景)提供了思路,后续可通过新增错误重试、参数校验、多轮对话记忆等功能,进一步提升程序的健壮性和用户体验。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐