LC初识与模型调用

image-20260402221436234

一、LangChain

image-20260402220749313

1
https://www.langchain.com/

1.LangSmith

调试/观测/评估平台

image-20260402221547735

2.LangSmith Fleet

image-20260402221634169

类似coze一种智能体平台,可以直接开发部署agent

3.frameworks

image-20260402221841701

image-20260402221906776

二、Agent

1.智能体

LLMAgent本质区别

image-20260402222134655

就是会自行多次迭代,调用工具,具备分析与执行能力,制作结果

2.Agent开发

传统 LLM 在询问具体天气的时候,无法正常使用

image-20260402223847471

但是Agent,可以直接调用工具,进而加载具体天气

LangChain开发

配置依赖

1
2
3
4
5
6
7
8
9
10
11
langchain依赖配置
uv add langchain

# 集成 DeepSeek
uv add langchain-deepseek

# 集成 OpenAI
uv add langchain-openai

# 集成 Anthropic
uv add langchain-anthropic

2.1、加载环境变量

1
2
3
from dotenv import load_dotenv

load_dotenv()

会自动加载.env文件中的环境变量

image-20260403120252260

2.2、定义工具

LangChain 中的 @tool 装饰器

image-20260403121027994

装饰后,这个函数自动获得几个属性:

1
2
3
print(get_weather.name)        # "get_weather"  —— 工具名称
print(get_weather.description) # 函数的 docstring —— LLM 靠这个理解"何时用它"
print(get_weather.args) # {"location": {"type": "string", ...}} —— 参数 schema

LLM 实际上看到的是这样一份描述,它根据这个来决定要不要调用:

1
2
3
Tool: get_weather
Description: Get the weather in a given location.
Args: location (str): city name or coordinates
1
2
3
4
5
6
7
8
9
10
11
# 2.定义工具
from langchain.tools import tool

@tool
def get_weather(location: str) -> str:
"""
Get the weather in a given location.
Args:
location: city name or coordinates
"""
return f"Current weather in {location} is sunny"

2.3、创建Agent

1
2
3
4
5
6
7
# 3.创建Agent
from langchain.agents import create_agent

agent = create_agent(
"deepseek-chat",
tools = [get_weather]
)
image-20260403123932508

2.4、调用

image-20260403124223624

3.Agent执行流程

image-20260403131403555

执行流程如上

工具调用过程

工具的具体调用

image-20260403131859589

在发起请求时添加 tool 参数

image-20260403132418190

三、Langchain实现

1.初始化模型

Langchain目前提供俩种初始化模型的方式

1.1、init_chat_model 函数

1
https://docs.langchain.com/oss/python/integrations/providers/overview

官方文档如上

LangChain 提供的统一入口,自动根据模型名推断用哪个 provider

1
2
3
4
5
6
7
8
9
10
from langchain.chat_models import init_chat_model

# 自动识别 provider
model = init_chat_model("gpt-4o", model_provider="openai")
model = init_chat_model("claude-3-5-sonnet-20241022", model_provider="anthropic")
model = init_chat_model("gemini-1.5-pro", model_provider="google_vertexai")

# 调用方式完全一样
response = model.invoke("你好")
print(response.content)
image-20260404214254521

调用init_chat_model函数初始化模型,参数model用来指定模型名称,Langchain会根据模型名字自动设定base_url,并从环境变量中获取api_key

但是,这个方式,只是支持部分主流AI模型

于是通过

1
2
3
4
5
6
7
8
9
10
11
12
# 我们收到加载环境变量中的base_url和api_key
import os

base_url = os.getenv("DASHSCOPE_BASE_URL")
api_key = os.getenv("DASHSCOPE_API_KEY")

model = init_chat_model(
model="qwen-max", # 模型名称,这里可以自定义,我们用的是阿里的qwen-max
model_provider="openai", # 如果是Langchain不支持的模型,需要指定模型提供者(虽然我们用的是阿里,但是阿里兼容openai,所以这里用openai)
base_url=base_url,
api_key=api_key
)

额外参数也可以调

image-20260404215309072

1.2、使用Model类

适配于某些大模型不支持 openai 格式,社区版中通常有解决办法

首先,需要安装依赖
LangChain社区依赖:

1
uv add langchain-community

阿里云百炼依赖:

1
uv add dashscope
1
2
3
4
5
6
7
from langchain_community.chat_models.tongyi import ChatTongyi

# 使用Model类初始化模型
model = ChatTongyi(
model="qwen-max"
# 其它模型参数...
)

2.模型的调用

2.1、invoke — 同步阻塞调用

1
2
3
4
5
6
7
8
9
10
11
# 最简单的调用
response = model.invoke("你好,介绍一下自己")
print(response.content)

# 传入消息列表(多轮对话)
messages = [
HumanMessage(content="我叫 Eaton"),
HumanMessage(content="我叫什么名字?")
]
response = model.invoke(messages)
print(response.content)

2.2、stream — 流式调用

1
2
3
# stream 返回一个生成器,逐块迭代
for chunk in model.stream("写一首关于春天的诗"):
print(chunk.content, end="", flush=True)
image-20260404220632658

2.3、在智能体中使用

1
2
3
4
5
6
from langchain.agents import create_agent

# 1.使用初始化好的model创建Agent
agent = create_agent(model=model)
# 2.指定Model名称,由LangChain自动初始化模型
agent = create_agent(model="deepseek-chat")

调用

1
2
3
4
5
response = agent.invoke({
"messages": [{"role": "user", "content": "月亮的首都是哪里?"}]
})

print(response)
1
2
3
4
5
6
# 通过stream方法实现流式访问
messages = agent.stream(
{"messages": [{"role": "user", "content": "月亮的首都是哪里?"}]},
stream_mode="messages"
)
print(type( messages))

3.Message

LangChain 把所有与模型交互的消息统一抽象为 BaseMessage 基类,不同角色的消息对应不同的子类,这样做的好处是:屏蔽了不同模型厂商的 API 差异,用同一套消息格式,就能驱动 OpenAI、Anthropic、通义等所有模型

3.1、SystemMessage

1
2
3
from langchain_core.messages import SystemMessage

SystemMessage(content="你扮演火箭队的武藏。")
  • 对应原始 API 的 role: "system"
  • 用于设定模型的角色、行为规范、背景知识
  • 通常放在消息列表的第一条
  • 模型不会把它当作”对话内容”,而是当作”行为指令”

3.2、HumanMessage

1
2
3
from langchain_core.messages import HumanMessage

HumanMessage(content="你是谁?")
  • 对应原始 API 的 role: "user"
  • 代表用户说的话,是每轮对话的输入
  • 也可以包含图片等多模态内容(传 list)

3.3、AIMessage

1
2
3
from langchain_core.messages import AIMessage

AIMessage(content="哼,既然你真心诚意的发问了,那……")
  • 对应原始 API 的 role: "assistant"
  • 代表模型返回的内容
  • model.invoke() 的返回值就是这个类型
  • 多轮对话时,需要把历史的 AIMessage 手动保存进消息列表,模型才能”记住”上文

3.4、ToolMessage

1
2
3
from langchain_core.messages import ToolMessage

ToolMessage(content="北京今天气温 22℃", tool_call_id="call_abc123")
  • 对应原始 API 的 role: "tool"
  • 当模型调用了外部工具(如搜索、计算器)后,工具执行结果通过这个消息类型回传给模型
  • tool_call_id 用于关联是哪次工具调用的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

model = ChatOpenAI(model="gpt-4o")

# 构建完整对话历史
messages = [
SystemMessage(content="你扮演火箭队的武藏。"), # 设定角色
HumanMessage(content="你是谁?"), # 第1轮用户问
AIMessage(content="哼,既然你真心诚意的发问了,那……"), # 第1轮模型答(历史)
HumanMessage(content="你又要干什么坏事?"), # 第2轮用户问(当前)
]

response = model.invoke( )
print(response.content) # 返回 AIMessage

为什么要把 AIMessage 放进去?

因为模型本身是无状态的,它看不到上一次说了什么。你必须把完整的对话历史拼进请求里,它才能理解上下文、保持角色一致。

3.5、优质打印

1
2
for message in response['messages']:
message.pretty_print()

image-20260404222954183

4.多模态

1
https://docs.langchain.com/oss/python/langchain/messages#multimodal

官方文档

image-20260404223111778

只有支持多模态的模型才能识别图片

image-20260404223237507
1
2
3
4
5
6
7
8
9
10
from langchain.chat_models import init_chat_model
import os

# 初始化模型
model = init_chat_model(
model="qwen3.5-plus", # 模型名称,这里选择qwen3.5-plus,这是一个多模态模型,支持图片、文本、音频、视频
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY")
)

远程图片

1
2
3
4
5
# 准备多模态消息
message = HumanMessage([
{"type": "text", "text": "描述以下这张图片的内容."},
{"type": "image", "url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241022/emyrja/dog_and_girl.jpeg"},
])
image-20260404223618337

本地图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 读取图片,转为base64字符串
import base64

# 获取第一个(也是唯一一个)上传的文件
uploaded_file = uploader.value[0]

# 获取其内存视图
content_mv = uploaded_file["content"]

# 转换内存视图->字节
img_bytes = bytes(content_mv) # or content_mv.tobytes()

# base64编码
img_b64 = base64.b64encode(img_bytes).decode("utf-8")

image-20260404223914885

本质就是将上传图片转为base64编码

image-20260404224212659