【动手学Langchain】初级篇6-构建具备联网功能的多轮对话大模型

Posted by Orchid on February 19, 2025

在这之前,我们已经学习了在 LangChain 开发框架下如何使用提示词模板、如何创建链实现提示词模板和大语言模型的连接、如何创建Agent来调用网络搜索工具以及如何在程序中加入记忆模块使大模型具备状态记忆能力。在掌握了上述技能后,我们已经具备了进行大语言模型应用开发的能力了,因此,可以尝试完成第一个大模型应用开发项目——构建具备联网功能的多轮对话大模型,来为【动手学Langchain】初级篇画上一个圆满的句号。

接下来,我将按照项目构建的过程,逐步给出各部分的代码实现:

  1. 调用 LLM API,创建大模型

    1
    2
    3
    4
    5
    6
    
    from langchain_community.chat_models import ChatTongyi
    import os
    os.environ["DASHSCOPE_API_KEY"] = 'sk-4ff9974972204ee2bc6dd4a37db173f7'
    tongyi_chat = ChatTongyi(
        model="qwen-max",
    )
    
  2. 创建 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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    
    from langchain.agents import initialize_agent
    from langchain.agents import AgentType
    from langchain.agents import Tool
    from langchain.tools import tool
    import requests
       
    BOCHA_API_KEY = "sk-27f1a75797c64f3fa044d35afd3cbd27"
       
    # 定义Bocha Web Search工具
    @tool
    def bocha_web_search_tool(query: str, count: int = 8) -> str:
        """
        使用Bocha Web Search API进行联网搜索,返回搜索结果的字符串。
           
        参数:
        - query: 搜索关键词
        - count: 返回的搜索结果数量
       
        返回:
        - 搜索结果的字符串形式
        """
        url = 'https://api.bochaai.com/v1/web-search'
        headers = {
            'Authorization': f'Bearer {BOCHA_API_KEY}',  # 请替换为你的API密钥
            'Content-Type': 'application/json'
        }
        data = {
            "query": query,
            "freshness": "noLimit", # 搜索的时间范围,例如 "oneDay", "oneWeek", "oneMonth", "oneYear", "noLimit"
            "summary": True, # 是否返回长文本摘要总结
            "count": count
        }
       
        response = requests.post(url, headers=headers, json=data)
       
        if response.status_code == 200:
            # 返回给大模型的格式化的搜索结果文本
            # 可以自己对博查的搜索结果进行自定义处理
            return str(response.json())
        else:
            raise Exception(f"API请求失败,状态码: {response.status_code}, 错误信息: {response.text}")
       
       
    # 创建LangChain工具
    bocha_tool = Tool(
        name="BochaWebSearch",
        func=bocha_web_search_tool,
        description="使用Bocha Web Search API进行网络搜索"
    )
       
    # 加载一些工具
    tools = [bocha_tool]
       
    # 初始化 agent
    agent = initialize_agent(
        tools=tools,                                        # 工具列表,Agent 可以调用的工具。
        agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,   # Agent 类型,决定了 Agent 的行为模式。
        llm=tongyi_chat,                                    # 语言模型实例,用于任务解析和生成。
        verbose=False,                                      # 是否输出详细的日志信息,用于调试。
    )
    
  3. 将记忆模块以链的方式与 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
    
    from langchain_core.chat_history import InMemoryChatMessageHistory
    from langchain_core.runnables.history import RunnableWithMessageHistory
    from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder
       
    # 初始化存储对话历史的字典
    store = {}  # memory is maintained outside the chain
       
    # 定义获取会话历史的函数
    def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
        if session_id not in store:
            store[session_id] = InMemoryChatMessageHistory()
        return store[session_id]
       
    # 定义聊天提示模板
    chat_prompt = ChatPromptTemplate(
        [
            MessagesPlaceholder(variable_name="history"),  # 占位符,用于插入对话历史
            HumanMessagePromptTemplate.from_template("{input}")  # 用户输入
        ]
    )
       
    # 将提示模板与语言模型结合
    chain = chat_prompt | agent
       
    # 使用 RunnableWithMessageHistory 包装 chain
    chat_agent = RunnableWithMessageHistory(
        chain,
        get_session_history=get_session_history,
        input_messages_key="input",  # 用户输入的键名
        history_messages_key="history"  # 对话历史的键名
    )
    
  4. 开始多轮对话

    第一轮对话:

    1
    2
    3
    4
    5
    6
    
    response = chat_agent.invoke(
        {"input": "你好,我是Orchid。请帮我搜索一下最近的科技新闻。"},
        config={"configurable": {"session_id": "1"}}
    )
    print(response['output'])
    # output:最近的科技新闻包括科研工作者孙东明计划在全国两会上提出关于优化国家重大科技专项的建议;宇树科技为其“春晚秧歌舞机器人”申请了商标,并预测未来四足机器人的价格可能会大幅降低至三四千元;我国科学家通过干细胞再生疗法实现了对1型糖尿病的功能性治愈;以及在民营企业座谈会上多位企业家分享了对于科技创新未来的展望等。
    

    第二轮对话:

    1
    2
    3
    4
    5
    6
    
    response = chat_agent.invoke(
        {"input": "这些新闻中有哪些是关于人工智能的?"},
        config={"configurable": {"session_id": "1"}}
    )
    print(response['output'])
    # output:在提供的科技新闻中,关于宇树科技的“春晚秧歌舞机器人”的报道明确涉及到人工智能技术的应用,包括但不限于360°全景深度感知技术、多智能体协同规划、高精度3D激光SLAM自主定位和导航等功能。而民营企业座谈会上企业家们对科技创新未来的展望虽然未具体提及人工智能项目,但考虑到AI在科技创新中的重要地位,这部分讨论很可能也涵盖了对未来AI发展趋势的看法。
    

    第三轮对话:

    1
    2
    3
    4
    5
    6
    
    response = chat_agent.invoke(
        {"input": "我叫什么名字?"},
        config={"configurable": {"session_id": "1"}}
    )
    print(response['output'])
    # output:您的名字是Orchid。
    

经过一系列的探索与实践,我们终于完成了第一个大模型应用开发项目——构建具备联网功能的多轮对话大模型。在这个项目中,我们不仅深入研究了大模型的核心技术,还结合了网络搜索功能,使其能够实时获取最新信息,从而为用户提供更准确、更全面的回答。通过精心设计的对话管理系统,我们的模型能够记住对话历史,保持上下文连贯性,实现自然流畅的多轮对话体验。

这一项目的成功,不仅标志着我们在大模型应用开发领域迈出了坚实的一步,也为【动手学Langchain】初级篇画上了一个圆满的句号。通过这个项目,我们积累了宝贵的经验,掌握了从理论到实践的全过程,为未来更复杂、更高级的应用开发奠定了坚实的基础。我们期待在后续的学习和实践中,继续探索大模型的无限可能,解锁更多创新应用场景,为人工智能的发展贡献自己的力量。