学术, 人工智能

使用LangChain框架搭建入门智能体

本篇使用 LangChain 框架实现几个简单的入门智能体。这里以阿里云百炼的通义千问 API 和 Ollama 本地大模型 API 为例。第三方 API 需要付费,可能有一定量的免费额度。

一、环境的安装和设置

安装软件包:

pip install langchain
pip install langchain-openai
pip install langchain-community
pip install python-dotenv

需要说明的是:在最新版本的软件包中,langchain>=1.0.0,本篇的代码可能会报错,尤其是调用工具的情况。这里默认使用的是以下这个版本,可以通过以下方式来安装:

pip install langchain==0.3.27
pip install langchain-openai==0.3.35
pip install langchain-community==0.3.31
pip install python-dotenv

可以通过以下更新软件包(可能会升级到 1.0.0 以上版本):

pip install --upgrade langchain langchain-openai langchain-community python-dotenv

查看当前版本:

pip show langchain langchain-openai langchain-community python-dotenv

在文件夹中新建 .env 文件,输入以下内容(API KEY 需要到阿里云百炼获取):

OPENAI_API_KEY=xxx
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1

二、简单对话智能体

在同一个文件夹中,新建 langchain_example.py 文件,内容为:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/47909
"""

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
import dotenv
import os

# 加载环境变量(包含API密钥)
dotenv.load_dotenv()

# 创建聊天模型
llm = ChatOpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),  # 从环境变量获取 API 密钥
    base_url=os.getenv("DASHSCOPE_BASE_URL"),  # 指定 API 端点
    model="qwen-plus",  # 使用通义千问 Plus 模型
    temperature=0.7,  # 控制回复的随机性(0-1,越高越有创意)
    streaming=True,  # 启用流式模式
)

# 创建简单的提示词模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个友好的聊天助手。"),  # 系统角色设定
    ("human", "{question}")   # 用户输入占位符
])

# 创建处理链
chain = prompt | llm  # 使用管道操作符连接组件

# 使用 stream() 实现流式输出
for chunk in chain.stream({"question": "你好"}):
    print(chunk.content, end="", flush=True)
print()  # 换行

# # 非流式输出
# response = chain.invoke({"question": "你好"})
# print(response.content)

运行结果:

你好呀!✨ 很高兴见到你~今天过得怎么样呀?希望你度过了愉快的一天。我随时准备好陪你聊天、帮你解决 问题,或者就这样轻松愉快地闲聊一会儿。有什么想跟 我分享的吗? 🌟

三、基于 Ollama 的简单对话智能体

Ollama 环境和模型的安装可以参考这篇:使用Ollama在本地运行开源大语言模型。安装环境和模型后,支持在本地电脑上运行智能体,但大模型的性能不会太高。

新建 langchain_example_with_Ollama.py 文件,内容为:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/47909
"""

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 创建聊天模型 - 修改为调用 Ollama
llm = ChatOpenAI(
    api_key="ollama",  # 对于 Ollama,API key 可以设为任意值或 "ollama"
    base_url="http://localhost:11434/v1",  # Ollama 的本地 API 地址
    model="qwen2.5:3b",  # 替换为你本地安装的模型名称,如 qwen2.5 等
    temperature=0.7,  # 控制回复的随机性(0-1,越高越有创意)
    streaming=True,  # 启用流式模式
)

# 创建简单的提示词模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个友好的聊天助手。"),  # 系统角色设定
    ("human", "{question}")   # 用户输入占位符
])

# 创建处理链
chain = prompt | llm  # 使用管道操作符连接组件

# 使用 stream() 实现流式输出
for chunk in chain.stream({"question": "你好"}):
    print(chunk.content, end="", flush=True)
print()  # 换行

# # 非流式输出
# response = chain.invoke({"question": "你好"})
# print(response.content)

运行结果:

你好!很高兴为你服务。有什么我可以帮助你的吗?

如果是长文对话,记得在 Ollama 软件后台把 Context length 从 4k 改为256k 。

四、带有记忆的智能体

在同一个文件夹中,新建 langchain_example_with_memory.py 文件,内容为:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/47909
"""

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory

# 加载 .env 中的 API 密钥等配置
load_dotenv()

# 初始化大模型
llm = ChatOpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("DASHSCOPE_BASE_URL"),
    model="qwen-plus",
    temperature=0.7
)

# 定义带历史记录的提示模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个乐于助人的助手。"),
    MessagesPlaceholder("history"),  # 历史消息占位符
    ("human", "{input}")            # 当前用户输入
])

# 创建基础链
chain = prompt | llm

# 内存存储:用字典模拟会话历史(仅用于演示)
store = {}

def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

# 包装成带记忆的链
chatbot = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="history",
)

def chat_with_agent(input_message, session_id):
    print(f"用户: {input_message}")
    print("助手: ", end="", flush=True)
    for chunk in chatbot.stream(
        {"input": input_message},
        config={"configurable": {"session_id": session_id}}  # 多轮对话(使用同一个 session_id)
    ):
        print(chunk.content, end="", flush=True)
    print("\n\n---\n")

chat_with_agent(input_message='一句话解释下人工智能。', session_id="user_001") 

chat_with_agent(input_message='我们都聊了什么?', session_id="user_001") 

chat_with_agent(input_message='我们都聊了什么?', session_id="user_002") 

chat_with_agent(input_message='我们都聊了什么?', session_id="user_001") 

运行结果:

用户: 一句话解释下人工智能。
助手: 人工智能是让机器模拟人类智能行为的技术,比如学习、推理、识别和决策等。

---

用户: 我们都聊了什么?
助手: 我们目前只聊了两个话题:

1. 你让我用一句话解释人工智能,我回答:人工智能是让机器模拟 人类智能行为的技术,比如学习、推理、识别和决策等。

2. 接着你问我“我们都聊了什么?”,我现在正在回答这个问题。

对话内容很简单,仅此而已。

---

用户: 我们都聊了什么?
助手: 你好!我理解你可能想回顾之前的对话,但需要说明的是,我无法记住或查看我们之前的具体聊天内容。每次对话都是独立的,以保护用户的隐私和数据安全。

不过,我很乐意继续和你聊任何你想讨论的话题!你可以告诉我我们之前聊了什么,或者直接开启一个新话题,我会尽力帮助你。😊

我们可以聊聊:
- 你感兴趣的知识或问题
- 生活、工作、学习中的困惑
- 最近的新闻或科技进展
- 或者任何让你好奇的事情

你想聊什么呢?

---

用户: 我们都聊了什么?
助手: 我们目前的对话内容如下:

1. 你让我“一句话解释下人工智能”,我回答:人工智能是让机器模 拟人类智能行为的技术,比如学习、推理、识别和决策等。

2. 你接着问“我们都聊了什么?”,我上一次已经帮你回顾了这段简 短的对话。

现在是你第二次问“我们都聊了什么?”,所以我再次为你总结——目前为止,我们的全部对话就包含这两个问题和我的两次回答。

---

五、使用工具的智能体

在同一个文件夹中,新建 langchain_example_with_tool.py 文件,内容为:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/47909
"""

import os
import dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
from langchain.agents import create_openai_tools_agent, AgentExecutor

# 加载环境变量
dotenv.load_dotenv()

# 定义工具(Tool)
@tool
def get_current_time() -> str:
    """获取当前日期和时间"""
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

@tool
def add_numbers(a: float, b: float) -> float:
    """将两个数字相加"""
    return a + b

# 注意:你可以添加更多工具,比如天气查询、网络搜索等

tools = [get_current_time, add_numbers]

# 创建 LLM(必须支持 function calling)
llm = ChatOpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("DASHSCOPE_BASE_URL"),
    model="qwen-plus",
    temperature=0.7,
    streaming=True,
)

# 构建提示模板(LangChain 会自动注入工具信息)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个智能助手,可以使用工具来回答问题。"),
    ("human", "{input_message}"),
    ("placeholder", "{agent_scratchpad}"),  # 必须包含这个占位符
])

# 创建 OpenAI 工具型智能体(兼容 function calling)
agent = create_openai_tools_agent(llm, tools, prompt)

# 创建执行器
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,  # 打印中间步骤(可选)
    handle_parsing_errors=True,
)

# 非流式调用(AgentExecutor 目前对流式支持有限,尤其在工具调用场景)
response = agent_executor.invoke({"input_message": "现在几点了?然后把 123 和 456 加起来。"})
print('\n---\n')
print(response["output"])

运行结果:


> Entering new AgentExecutor chain...

Invoking: `get_current_time` with `{}`


2025-11-02 04:03:10
Invoking: `add_numbers` with `{'a': 123, 'b': 456}`


579.0现在是2025年11月2日04:03:10,123和456相加的结果是579。

> Finished chain.

---

现在是2025年11月2日04:03:10,123和456相加的结果是579。

六、新版 LangChain 的使用工具的智能体

新版 LangChain 结构发生变化,尤其是 langchain>=1.0.0。在新版中,create_agent 代替旧的 create_openai_tools_agent,并且 AgentExecutor 不再需要手动创建。

在同一个文件夹中,新建 langchain_example_with_tool_version_2.py 文件,内容为:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/47909
"""

import os
import dotenv
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain.agents import create_agent
from langchain_core.globals import set_debug # ✅ 用于开启详细日志

# 开启调试日志输出
set_debug(True)

# 加载环境变量
dotenv.load_dotenv()

# 定义工具
@tool
def get_current_time() -> str:
    """获取当前日期和时间"""
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

@tool
def add_numbers(a: float, b: float) -> float:
    """将两个数字相加"""
    return a + b

tools = [get_current_time, add_numbers]

# 创建 LLM
llm = ChatOpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("DASHSCOPE_BASE_URL"),
    model="qwen-plus",
    temperature=0.7,
)

# 创建 agent
agent = create_agent(llm, tools)

# 执行调用(此时会打印详细步骤)
response = agent.invoke(
    {
        "messages": [
            {"role": "user", "content": "现在几点了?然后把 123 和 456 加起来。"}
        ]
    }
)

print("\n---\n")
print(response["messages"][-1].content)

运行结果为:

[chain/start] [chain:LangGraph] Entering Chain run with input:
{
  "messages": [
    {
      "role": "user",
      "content": "现在几点了?然后把 123 和 456 加起来。"
    }
  ]
}
[chain/start] [chain:LangGraph > chain:model] Entering Chain run with input:
[inputs]
[llm/start] [chain:LangGraph > chain:model > llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "Human: 现在几点了?然后把 123 和 456 加起来。"
  ]
}
[llm/end] [chain:LangGraph > chain:model > llm:ChatOpenAI] [1.66s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "",
        "generation_info": {
          "finish_reason": "tool_calls",
          "logprobs": null
        },
        "type": "ChatGeneration",
        "message": {
          "lc": 1,
          "type": "constructor",
          "id": [
            "langchain",
            "schema",
            "messages",
            "AIMessage"
          ],
          "kwargs": {
            "content": "",
            "additional_kwargs": {
              "refusal": null
            },
            "response_metadata": {
              "token_usage": {
                "completion_tokens": 46,
                "prompt_tokens": 216,
                "total_tokens": 262,
                "completion_tokens_details": null,
                "prompt_tokens_details": {
                  "audio_tokens": null,
                  "cached_tokens": 128
                }
              },
              "model_provider": "openai",
              "model_name": "qwen-plus",
              "system_fingerprint": null,
              "id": "chatcmpl-85df84ca-31f8-49b1-8b78-0639c6aa5c07",
              "finish_reason": "tool_calls",
              "logprobs": null
            },
            "type": "ai",
            "id": "lc_run--7218161c-8e32-4ee5-ad01-5d87cdd15e98-0",
            "tool_calls": [
              {
                "name": "get_current_time",
                "args": {},
                "id": "call_c77908e49c2747c9ae3bc2",
                "type": "tool_call"
              },
              {
                "name": "add_numbers",
                "args": {
                  "a": 123,
                  "b": 456
                },
                "id": "call_84e118fb74624279ac8462",
                "type": "tool_call"
              }
            ],
            "usage_metadata": {
              "input_tokens": 216,
              "output_tokens": 46,
              "total_tokens": 262,
              "input_token_details": {
                "cache_read": 128
              },
              "output_token_details": {}
            },
            "invalid_tool_calls": []
          }
        }
      }
    ]
  ],
  "llm_output": {
    "token_usage": {
      "completion_tokens": 46,
      "prompt_tokens": 216,
      "total_tokens": 262,
      "completion_tokens_details": null,
      "prompt_tokens_details": {
        "audio_tokens": null,
        "cached_tokens": 128
      }
    },
    "model_provider": "openai",
    "model_name": "qwen-plus",
    "system_fingerprint": null,
    "id": "chatcmpl-85df84ca-31f8-49b1-8b78-0639c6aa5c07"
  },
  "run": null,
  "type": "LLMResult"
}
[chain/end] [chain:LangGraph > chain:model] [1.66s] Exiting Chain run with output:
[outputs]
[chain/start] [chain:LangGraph > chain:tools] Entering Chain run with input:   
[inputs]
[chain/start] [chain:LangGraph > chain:tools] Entering Chain run with input:   
[inputs]
[tool/start] [chain:LangGraph > chain:tools > tool:get_current_time] Entering Tool run with input:
"{}"
[tool/end] [chain:LangGraph > chain:tools > tool:get_current_time] [0ms] Exiting Tool run with output:
"content='2025-11-07 16:04:41' name='get_current_time' tool_call_id='call_c77908e49c2747c9ae3bc2'"[tool/start] [chain:LangGraph > chain:tools > tool:add_numbers] Entering Tool run with input:
"{'a': 123, 'b': 456}"

[tool/end] [chain:LangGraph > chain:tools > tool:add_numbers] [0ms] Exiting Tool run with output:
"content='579.0' name='add_numbers' tool_call_id='call_84e118fb74624279ac8462'"
[chain/end] [chain:LangGraph > chain:tools] [2ms] Exiting Chain run with output:
[outputs]
[chain/end] [chain:LangGraph > chain:tools] [2ms] Exiting Chain run with output:
[outputs]
[chain/start] [chain:LangGraph > chain:model] Entering Chain run with input:   
[inputs]
[llm/start] [chain:LangGraph > chain:model > llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "Human: 现在几点了?然后把 123 和 456 加起来。\nAI: \nTool: 2025-11-07 16:04:41\nTool: 579.0"
  ]
}
[llm/end] [chain:LangGraph > chain:model > llm:ChatOpenAI] [3.14s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "现在是2025年11月7日16点04分41秒,而123和456相加的结果是579。",
        "generation_info": {
          "finish_reason": "stop",
          "logprobs": null
        },
        "type": "ChatGeneration",
        "message": {
          "lc": 1,
          "type": "constructor",
          "id": [
            "langchain",
            "schema",
            "messages",
            "AIMessage"
          ],
          "kwargs": {
            "content": "现在是2025年11月7日16点04分41秒,而123和456相加的结果是579。",
            "additional_kwargs": {
              "refusal": null
            },
            "response_metadata": {
              "token_usage": {
                "completion_tokens": 38,
                "prompt_tokens": 305,
                "total_tokens": 343,
                "completion_tokens_details": null,
                "prompt_tokens_details": {
                  "audio_tokens": null,
                  "cached_tokens": 0
                }
              },
              "model_provider": "openai",
              "model_name": "qwen-plus",
              "system_fingerprint": null,
              "id": "chatcmpl-863d61f2-38ac-44f2-af6e-01ad5cfb6742",
              "finish_reason": "stop",
              "logprobs": null
            },
            "type": "ai",
            "id": "lc_run--45a69927-3740-4eaa-8ed3-4063cda2a347-0",
            "usage_metadata": {
              "input_tokens": 305,
              "output_tokens": 38,
              "total_tokens": 343,
              "input_token_details": {
                "cache_read": 0
              },
              "output_token_details": {}
            },
            "tool_calls": [],
            "invalid_tool_calls": []
          }
        }
      }
    ]
  ],
  "llm_output": {
    "token_usage": {
      "completion_tokens": 38,
      "prompt_tokens": 305,
      "total_tokens": 343,
      "completion_tokens_details": null,
      "prompt_tokens_details": {
        "audio_tokens": null,
        "cached_tokens": 0
      }
    },
    "model_provider": "openai",
    "model_name": "qwen-plus",
    "system_fingerprint": null,
    "id": "chatcmpl-863d61f2-38ac-44f2-af6e-01ad5cfb6742"
  },
  "run": null,
  "type": "LLMResult"
}
[chain/end] [chain:LangGraph > chain:model] [3.15s] Exiting Chain run with output:
[outputs]
[chain/end] [chain:LangGraph] [4.82s] Exiting Chain run with output:
[outputs]

---

现在是2025年11月7日16点04分41秒,而123和456相加的结果是579。
57 次浏览

【说明:本站主要是个人的一些笔记和代码分享,内容可能会不定期修改。为了使全网显示的始终是最新版本,这里的文章未经同意请勿转载。引用请注明出处:https://www.guanjihuan.com

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

Captcha Code