LangChain P2 | 给LangChain装上手脚[MacOS]

前情提要

在 P1 中,我们已经学会了用 LCEL 搭一条最简单的链

python 复制代码
from langchain_core.output_parsers import StrOutputParser
from langchain_deepseek import ChatDeepSeek

llm = ChatDeepSeek(model="deepseek-v4-flash")
parser = StrOutputParser()
chain = llm | parser
print(chain.invoke("你好"))

创建上面这样一条链,这条链能跑,但有个问题------模型只会说,不会做。

你问它"今天昆明天气怎么样?",它只能回答"抱歉,我无法获取实时数据。"

在本篇博客中,我们就来解决这个LLM的痛点:我们会学会三种调用大模型的姿势,然后给 AI 上手脚,让它不再只有大脑,即工具,让它真正能动起来。

三种姿势调用大模型

在LangChain中,我们有多种方式来定义一个LLM,不同的姿势,适用于不同的环境,在本小节中,我们会学习到不同的调用方式

方式1:ChatOpenAI

这是最直接的用法,指定模型名就行。不仅支持 OpenAI,也兼容 DeepSeek 等国内厂商(因为它们都兼容 OpenAI 的 API 格式)。

不过需要注意的是,如果我们使用ChatOpenAI来调用非OpenAI的AI,我们需要引入一些其它的参数,此处我们以deepseek为例

python 复制代码
import os

from langchain_community.chat_models import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(
    model="deepseek-v4-flash",
    base_url="https://api.deepseek.com",
    api_key=os.getenv("DEEPSEEK_API_KEY"),  # 从环境变量读取
)
paser = StrOutputParser()
chain = llm | paser
print(chain.invoke("你好"))

我们可以看到,我们需要单独给出这个厂商的base_url和api_key,api_key我们都知道,是从环境变量中获取到的,在P1里我们就已经讲过了,那么base_url是怎么来的呢?

让我们看到deepseek的接口文档,我们可以看到,在文档中都是给出来了的,所以我们在调用一个AI的时候,可以多看看它的API文档

适用场景:你就用一家厂商,代码写死就行

方式2:init_chat_model

一个工厂函数,模型名换一下就能切换厂商,不用改代码结构。我们同样用一个例子来看一下

python 复制代码
from langchain.chat_models import init_chat_model

llm = init_chat_model(
    model="deepseek-v4-flash",
    model_provider="deepseek"
)
llm.invoke("你好").pretty_print()

我们可以看到,在这个模式下,参数都是一样的,我们只需要修改里面的内容就可以实现调用不同的模型

适用场景:你要对比不同模型效果,或者项目需要灵活切换厂商

方式3:ChatOllama本地部署

模型跑在自己机器上,不依赖网络,数据不出门。

不过这个会涉及到本地部署的操作,我们这里就不多赘述了,大概给大家一个代码例子

python 复制代码
from langchain_ollama import ChatOllama

model = ChatOllama(
    model="llama3",
    base_url="http://localhost:11434",
)
print(model.invoke("你是谁?").content)

适用场景:离线环境、数据敏感场景、想省 API 费用

工具(Tools)

一句人话解释,为什么需要工具:大模型只会说话不会动手------它查不了天气、读不了数据库、算不了复杂数学,而工具就是 AI 的"外挂",让它能干"人"的活。

那么,我们到底要怎样才可以定义并用上工具呢?接下来,我们就会通过逐步实现一个可以进行运算的大模型来展示

创建工具

LangChain 提供了 '@tool'装饰器,把普通 Python 函数一键变成工具。

args_schema

python 复制代码
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """两数相加
    Args:
        a: 第一个整数
        b: 第二个整数
    Returns:
        两数之和
    """
    return a + b

注意:函数名 = 工具名,文档字符串 = 工具描述,缺一不可!模型就是通过名称和描述来理解"这个工具是干什么的"。

💡 一个小彩蛋我们来讲讲,描述这里发生了什么

LangChain 自动把你的函数名、文档字符串、参数类型打包成 "JSON Schema" 发给模型

模型就是通过这个 Schema 来理解"add 是加法工具,参数 a 和 b 都是整数"。

因此工具描述是非常重要的,最好是像文章示例这样,把用途,参数,返回都写上去,帮助大模型更好理解工具的作用,不过是,除了这样的描述方式外,还有三种其它方式,我们简述一下

Pydantic

python 复制代码
from dataclasses import Field

from langchain_core.tools import tool
from pydantic import Field, BaseModel


class addInput(BaseModel):
    a: int = Field(description="第一个整数")
    b: int = Field(description="第二个整数")

@tool(args_schema=addInput)
def add(a: int, b: int) -> int:
    """两数之和"""
    return a + b

Annotated

python 复制代码
from langchain_core.tools import tool
from typing_extensions import Annotated


@tool
def add(a: Annotated[int, "第一个整数"], b: Annotated[int, "第二个整数"]) -> int:
    """两数之和"""
    return a + b

StructuredTool

python 复制代码
from langchain_core.tools import StructuredTool

def add(a: int, b: int) -> int:
    return a + b

add_tool = StructuredTool.from_function(
    func=add,
    name="add",
    description="两数之和"
)

绑定工具

工具定义好了,怎么让模型知道它可以用?用 'bind_tools()' 绑定工具。我们依旧用一个例子来帮助大家理解

python 复制代码
from langchain.chat_models import init_chat_model
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """两数相加
    Args:
        a: 第一个整数
        b: 第二个整数
    Returns:
        两数之和
    """
    return a + b

llm = init_chat_model(
    model="deepseek-v4-flash",
    model_provider="deepseek"
)
llm_with_tools = llm.bind_tools([add])    # 绑定add工具
llm.invoke("3 + 5等于多少").pretty_print()

通过上述一个代码,我们就实现了一个简易的可以调用加法工具的大模型

注意!bind_tools() 这个方法里面需要传入工具列表,因此哪怕只有一个工具,也需要以列表形式存在

实战小练习

我们来实现一个输入城市名称就可以输出实时天气的工具

python 复制代码
from langchain_deepseek import ChatDeepSeek

import requests
from langchain_core.tools import tool


# 定义查询天气工具
@tool
def get_weather(city: str) -> str:
    """查询指定城市的实时天气。
    Args:
        city: 城市中文名称,如"昆明"、"北京"
    """
    resp = requests.get(
        f"https://wttr.in/{city}?format={city}今日:%t, %C&lang=zh",
        timeout=5,
    )
    return resp.text
llm = ChatDeepSeek(model="deepseek-v4-flash")    # 定义llm
llm_with_tools = llm.bind_tools([get_weather])   # 绑定工具
msg = llm_with_tools.invoke("北京")
tool_call = msg.tool_calls[0]                    # 手动调用一下工具
result = get_weather.invoke(tool_call["args"])
print(result)
相关推荐
沪漂阿龙3 小时前
LangChain 系列之Tools:让大模型真正连接业务系统
人工智能·python·langchain
喵叔哟3 小时前
第3周学习笔记
python·langchain
喵叔哟3 小时前
Week 3 --Day 5:性能优化与监控
人工智能·python·性能优化·langchain
草莓熊Lotso5 小时前
【LangChain】流式传输原理与 LangSmith 应用监控全解析
人工智能·python·langchain·gpt-3
JaydenAI13 小时前
[对比学习LangChain和MAF-07]如何引入人机交互的审批流程
python·ai·langchain·c#·agent·hitl·maf
沪漂阿龙16 小时前
Chat Model:LangChain 如何统一调用不同大模型?
人工智能·langchain
沪漂阿龙1 天前
LangChain 系列之 Messages:为什么大模型对话不是简单字符串?
人工智能·深度学习·langchain