LangChain实战教程:如何让聊天机器人学会调用搜索工具和网页阅读器?

本文将通过实际代码示例,展示如何从零开始构建一个具备网络搜索、内容理解和工具调用能力的AI助手。

现代智能对话系统的核心是大型语言模型(LLM),这些模型通过在海量文本数据上训练,习得了语言的统计规律和世界知识。然而,单纯的LLM存在一些固有局限性:

  1. \1. 知识时效性问题:模型训练数据有截止日期,无法获取最新信息
  2. \2. 封闭性问题:无法与外部系统和服务交互
  3. \3. 幻觉问题:可能生成看似合理但实际不准确的内容
  4. \4. 上下文限制:输入长度受限,无法处理大量背景信息

为解决这些问题,代理框架(Agent Framework)应运而生。代理框架允许LLM通过工具调用扩展其能力边界,实现与外部世界的交互。在这一框架下,LLM不再仅是信息的终端,而是成为了决策的枢纽,能够根据需要调用不同工具完成复杂任务。

LangChain和LangGraph正是基于这一理念设计的开源框架,它们提供了构建LLM应用的标准化组件和流程。这种架构使得AI系统能够:

  • • 获取实时信息
  • • 执行专业计算
  • • 访问私有数据
  • • 与其他系统集成
  • • 进行多步推理

这种"思考-行动"循环使AI助手的能力大幅提升,能够处理更复杂、更开放的任务场景。

技术栈概览

在构建我们的智能对话系统时,我们采用了以下技术栈:

  1. \1. 大型语言模型:使用Ollama本地部署的Qwen2(通义千问2.5)0.5B模型作为核心推理引擎

  2. \2. 框架与库

    • LangChain:提供LLM应用构建的标准化组件
    • LangGraph:用于构建多步推理流程的有向图框架
    • LangServe:用于部署LangChain应用的服务框架
  3. \3. 工具集成

    • • 自定义搜索工具(模拟网络搜索功能)
    • • 网页内容提取工具(使用requests和BeautifulSoup实现)
  4. \4. 辅助技术

    • • 类型提示(Python typing模块)
    • • 网页内容解析(BeautifulSoup)
    • • HTTP请求处理(requests)

环境搭建与基础配置

依赖库安装

pip install langchain langchain-community langchain-ollama langgraph langserve requests beautifulsoup4

Ollama服务配置

我们的系统使用本地部署的Ollama服务运行Qwen2.5模型。需确保Ollama已正确安装并运行:

ollama_base_url = "http://192.168.1.1:11434"  # 默认地址,可根据实际情况修改

确保Ollama服务已下载并可以提供Qwen2.5:0.5b模型。如果尚未下载,可以通过以下命令获取:

ollama pull qwen2.5:0.5b

模型选择与初始化

这里需要使用支持tools功能的模型。模型参数实际应用中要尽量大一些。

模型初始化

我们使用LangChain的ChatOllama接口来初始化模型:

from langchain_ollama import ChatOllama

model = ChatOllama(
    model='qwen2.5:0.5b', 
    base_url=ollama_base_url
)

这创建了一个连接到本地Ollama服务的ChatOllama实例,使用Qwen2.5:0.5b模型。

基础对话测试

在进一步构建之前,我们可以测试模型的基本对话能力:

from langchain_core.messages import HumanMessage

result = model.invoke([HumanMessage(content='北京天气怎么样?')])
print(result)
content='抱歉,我无法提供实时的天气信息。我的知识和能力限制在过去的10年里我在学习如何与人交互,而没有访问网络的能力。如果您需要查询实时或未来的天气情况,请查阅相关的气象网站或者使用手机上的天气应用程序。'

这个简单测试验证了模型能够响应基本查询,但也会显示其局限性——模型无法获取实时天气信息,因为它没有访问外部数据的能力。这正是我们需要添加工具和构建代理系统的原因。

工具集成的实现策略

为了增强模型的能力,我们需要为其配备各种工具。工具使LLM能够与外部世界交互,获取信息并执行操作。在本系统中,我们实现了两种核心工具:自定义搜索工具和网页内容提取工具。

自定义搜索工具

搜索工具允许AI助手获取最新或专业信息,这些信息可能不在模型的训练数据中。在生产环境中,我们通常会使用Google、Bing或专业API如Tavily。但在本例中,为了简化实现和控制行为,我们创建了一个模拟搜索工具:

from typing importList

# 配置模拟搜索数据
MOCK_SEARCH_DATA = {
    "北京天气": [
        {
            "title": "北京今日天气预报",
            "content": "北京今天晴朗,气温15-25度,空气质量良好,适合户外活动。",
            "url": "https://example.com/beijing-weather",
            "timestamp": "2024-03-21"
        },
        {
            "title": "北京一周天气预报",
            "content": "本周北京以晴为主,周末可能有小雨,气温适宜。",
            "url": "https://example.com/beijing-weather-week",
            "timestamp": "2024-03-21"
        }
    ],
    "中国首都": [
        {
            "title": "中国首都简介",
            "content": "北京是中华人民共和国的首都,是全国的政治、文化中心。",
            "url": "https://example.com/beijing-info",
            "timestamp": "2024-03-21"
        }
    ],
    # 可添加更多模拟数据...
}

defformat_search_results(results: List[dict]) -> str:
    """格式化搜索结果输出"""
    output = "\n搜索结果:\n" + "="*50 + "\n"
    for idx, result inenumerate(results, 1):
        output += f"{idx}. {result['title']}\n"
        output += f"   内容: {result['content']}\n"
        output += f"   来源: {result['url']}\n"
        output += f"   时间: {result.get('timestamp', '未知')}\n"
        output += "-"*50 + "\n"
    return output

defcustom_search(query: str) -> List[dict]:
    """
    模拟搜索功能,返回预设的数据
    参数:
        query: 搜索查询字符串
    返回:
        匹配的搜索结果列表
    """
    try:
        # 简单的关键词匹配
        for key in MOCK_SEARCH_DATA:
            if key in query:
                results = MOCK_SEARCH_DATA[key]
                print(format_search_results(results))  # 格式化输出搜索结果
                return results
        return [{"title": "未找到结果", 
                "content": "抱歉,没有找到相关信息。", 
                "url": "",
                "timestamp": "N/A"}]
    except Exception as e:
        print(f"搜索过程中发生错误: {str(e)}")
        return [{"title": "搜索错误", 
                "content": "搜索过程中发生错误,请稍后重试。", 
                "url": "",
                "timestamp": "N/A"}]

这个自定义搜索工具使用简单的关键词匹配来模拟搜索引擎。它返回结构化的搜索结果,包括标题、内容摘要、URL和时间戳。虽然简单,但它清晰地展示了工具集成的核心概念。

网页内容提取工具

搜索结果通常只提供内容摘要,但用户可能需要更详细的信息。网页内容提取工具允许AI助手获取和处理完整的网页内容:

import requests
from bs4 import BeautifulSoup
import random
import time

deffetch_webpage_content(url: str) -> str:
    """
    获取网页内容的工具
    参数:
        url: 网页地址
    返回:
        网页内容摘要
    """
    try:
        # 添加随机延迟,模拟真实网络请求
        time.sleep(random.uniform(0.5, 1.5))
        
        # 如果是示例URL,返回模拟数据
        if'example.com'in url:
            return {
                'https://example.com/beijing-weather': '北京天气实时数据:晴朗,温度20度,空气质量指数75,相对湿度45%',
                'https://example.com/beijing-weather-week': '北京未来一周天气预报:周一到周五以晴为主,周六周日可能有零星小雨',
                'https://example.com/beijing-info': '北京市基本信息:面积16410平方公里,常住人口2170万,下辖16个区,是中国的政治文化中心'
            }.get(url, '该页面内容暂时无法访问')
            
        # 真实网页请求
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
        
        soup = BeautifulSoup(response.text, 'html.parser')
        # 移除脚本和样式元素
        for script in soup(["script", "style"]):
            script.decompose()
            
        # 提取正文内容
        text = soup.get_text()
        lines = (line.strip() for line in text.splitlines())
        chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
        text = ' '.join(chunk for chunk in chunks if chunk)
        
        # 返回前500个字符作为摘要
        return text[:500] + ('...'iflen(text) > 500else'')
        
    except Exception as e:
        return f"获取网页内容时发生错误: {str(e)}"

这个工具不仅支持模拟URL,还能处理真实网页。它使用requests库获取网页内容,然后使用BeautifulSoup解析HTML,提取纯文本内容。为了避免返回过多信息,它只返回前500个字符作为摘要。

工具注册与绑定

有了这两个核心工具,我们可以将它们注册到LangChain的Tool框架中,并绑定到我们的模型:

from langchain.tools import Tool

# 创建工具列表
tools = [
    Tool(
        name="CustomSearch",
        description="搜索工具:用于搜索天气、城市等基本信息。输入搜索关键词,返回相关信息。",
        func=custom_search
    ),
    Tool(
        name="WebpageReader",
        description="网页阅读工具:输入网页URL,获取网页的详细内容。适用于需要深入了解某个主题时使用。",
        func=fetch_webpage_content
    )
]

# 更新模型绑定
model_with_tools = model.bind_tools(tools)

绑定后的model_with_tools现在具备了使用这两个工具的能力,可以在适当时机调用它们来获取信息或执行操作。

代理系统的构建与执行

绑定工具到模型只是第一步,要实现真正的代理行为,我们需要构建一个能够执行"思考-行动"循环的代理系统。LangGraph提供的chat_agent_executor正是为此设计的组件。

代理执行器设计原理

代理执行器的核心功能是协调LLM与工具之间的交互。它实现了以下工作流程:

  1. \1. 接收用户输入
  2. \2. 让LLM生成初步响应或工具调用需求
  3. \3. 如需调用工具,执行工具并获取结果
  4. \4. 将工具结果提供给LLM进行分析
  5. \5. 生成最终响应

这种循环允许LLM根据需要多次调用工具,直到收集到足够信息来回答用户的问题。

实现代理执行器

使用LangGraph创建代理执行器非常直接:

from langgraph.prebuilt import chat_agent_executor

# 创建代理执行器
agent_executor = chat_agent_executor.create_tool_calling_executor(model, tools)

这行代码创建了一个支持工具调用的代理执行器,它封装了复杂的状态管理和流程控制逻辑,使我们能够专注于代理的功能而非实现细节。

代理执行流程的可视化

为了更好地理解代理系统的工作方式,我们可以将一次完整的代理交互分解为各个步骤:

  1. \1. 用户输入阶段

    • • 用户提问:“北京天气怎么样?”
    • • 系统将问题传递给代理执行器
  2. \2. LLM初步分析阶段

    • • LLM识别需要实时天气信息
    • • LLM决定需要调用搜索工具
    • • LLM生成工具调用请求
  3. \3. 工具执行阶段

    • • 代理执行器接收工具调用请求
    • • 执行CustomSearch工具,查询"北京天气"
    • • 工具返回结构化的天气信息
  4. \4. LLM结果处理阶段

    • • LLM接收工具返回的天气信息
    • • LLM分析和理解这些信息
    • • 如需进一步信息,LLM可选择调用其他工具
    • • 否则,LLM生成最终回答
  5. \5. 输出生成阶段

    • • 代理执行器收集LLM的最终回答
    • • 返回格式化的回复给用户

这个流程可以重复多次,直到LLM收集了足够的信息来生成满意的回答。

多模式交互测试

为验证我们构建的系统功能,我们需要进行全面的测试,涵盖直接模型调用和代理执行两种模式。

直接模型调用测试

首先,我们测试绑定了工具的模型的直接调用行为:

def print_model_response(response, query: str):
    """格式化打印模型响应"""
    print("\n" + "="*50)
    print(f"用户询问: {query}")
    print(f"模型回答: {response.content}")
    if response.tool_calls:
        print(f"工具调用: {response.tool_calls}")
    print("="*50 + "\n")

# 测试查询列表
test_queries = [
    "中国的首都是哪个城市?",
    "北京天气怎么样?",
    "能帮我查看一下 https://example.com/beijing-weather 这个网页的具体内容吗?",
    "上海有什么好玩的地方?"# 测试未知查询
]

for query in test_queries:
    resp = model_with_tools.invoke([HumanMessage(content=query)])
    print_model_response(resp, query)

在这种模式下,模型会直接返回响应或工具调用请求,但不会自动执行工具并处理结果。这对于理解模型的初始判断很有价值。

代理执行器测试

接下来,我们测试完整的代理执行流程:

# 测试代理执行器
for query in test_queries:
    resp = agent_executor.invoke({'messages': [HumanMessage(content=query)]})
    print("\n代理执行器响应:")
    print("="*50)
    print(f"查询: {query}")
    for msg in resp['messages']:
        print(f"类型: {msg.type}")
        print(f"内容: {msg.content}")
    print("="*50)

在代理执行模式下,系统会自动执行工具调用、处理结果并生成最终响应。这种模式更接近真实的AI助手体验。

可以看到大模型会自动判断是否需要调用Tool,如果需要则会调用。

image-20250227132734101

image-20250227132752086

比如我问:Python 是什么?,他就不会调用工具。

image-20250227133235455

在本文中,我们详细探讨了如何使用LangChain和LangGraph构建一个功能丰富的智能对话系统。从理论基础到实际实现,我们覆盖了构建现代AI助手的各个关键环节。希望本文提供的见解和代码示例能为你的旅程提供帮助和灵感。

如何零基础入门 / 学习AI大模型?

大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业?”“谁的饭碗又将不保了?”等问题热议不断。

不如成为「掌握AI工具的技术人」,毕竟AI时代,谁先尝试,谁就能占得先机!

想正式转到一些新兴的 AI 行业,不仅需要系统的学习AI大模型。同时也要跟已有的技能结合,辅助编程提效,或上手实操应用,增加自己的职场竞争力。

但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高

那么我作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,希望可以帮助到更多学习大模型的人!至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

👉 福利来袭CSDN大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈

全套AGI大模型学习大纲+路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

read-normal-img

640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

👉学会后的收获:👈
基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

👉 福利来袭CSDN大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈

img

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐