tools工具 与llm 模型交互
使用Pydantic模型定义数据结构、通过LangChain和Ollama的接口与语言模型进行交互,并构造了一个能够生成特定类型笑话(敲门笑话)的系统。以下是对代码各个部分的详细解读:
-
导入必要的库:
typing
和typing_extensions
用于定义灵活的数据类型。pydantic
的BaseModel
和Field
用于创建数据验证和设置字段描述的类。- 自定义模块
langchain_ollama
中的ChatOllama
类,以及langchain_core.prompts.ChatPromptTemplate
用于处理与语言模型的对话。
-
定义数据模型:
Joke
模型包含三个字段:setup
(笑话的铺垫)、punchline
(笑话的高潮/结局)和可选的rating
(对笑话搞笑程度的评分)。ConversationalResponse
模型用于表示一个友好的、有帮助的响应。FinalResponse
模型允许返回Joke
或ConversationalResponse
类型的输出。FinalResponse
类的设计目的是为了能够灵活地返回两种不同类型的响应:一个笑话(通过 Joke 类定义)或者一段对话式的回复(通过 ConversationalResponse 类定义)。这种设计使用了 Python 的联合类型(Union)
,意味着 final_output 字段可以是 Joke 或者 ConversationalResponse 任意一种类型的数据。
-
初始化语言模型:
- 使用
ChatOllama
类实例化llm
对象,指定了基础URL、模型名称和温度参数(控制输出的随机性)。 - 通过调用
.with_structured_output(FinalResponse)
方法来确保从语言模型得到的输出符合FinalResponse
模型的格式。
- 使用
-
设置提示信息:
- 系统提示(
system
)定义了该AI角色为一位擅长讲敲门笑话的喜剧演员,并给出了几个关于飞机和毛毛虫的笑话示例作为参考。 - 使用
ChatPromptTemplate.from_messages
方法基于系统提示和用户输入构建了一个提示模板。
- 系统提示(
-
执行请求并获取结果:
- 将提示模板和配置好的语言模型结合起来,创建了一个可以接受用户输入并产生相应输出的对象
few_shot_structured_llm
。 - 最后,通过调用
.invoke("what's something funny about woodpeckers")
方法向模型发送查询“关于啄木鸟有什么有趣的事情”,并打印出模型返回的结果。
- 将提示模板和配置好的语言模型结合起来,创建了一个可以接受用户输入并产生相应输出的对象
from typing import Union
from pydantic import BaseModel, Field
from langchain_ollama import ChatOllama
from typing_extensions import Optional
from langchain_core.prompts import ChatPromptTemplate
# Pydantic
class Joke(BaseModel):
"""Joke to tell user."""
setup: str = Field(description="The setup of the joke")
punchline: str = Field(description="The punchline to the joke")
rating: Optional[int] = Field(
default=None, description="How funny the joke is, from 1 to 10"
)
class ConversationalResponse(BaseModel):
"""Respond in a conversational manner. Be kind and helpful."""
response: str = Field(description="A conversational response to the user's query")
class FinalResponse(BaseModel):
final_output: Union[Joke, ConversationalResponse]
llm = ChatOllama(
base_url="http://127.0.0.1:11434",
model="qwen2.5:32b-instruct-q5_K_S",
temperature=0.7)
structured_llm = llm.with_structured_output(FinalResponse)
# prompt 提示词
system = """You are a hilarious comedian. Your specialty is knock-knock jokes. \
Return a joke which has the setup (the response to "Who's there?") and the final punchline (the response to "<setup> who?").
Here are some examples of jokes:
example_user: Tell me a joke about planes
example_assistant: {{"setup": "Why don't planes ever get tired?", "punchline": "Because they have rest wings!", "rating": 2}}
example_user: Tell me another joke about planes
example_assistant: {{"setup": "Cargo", "punchline": "Cargo 'vroom vroom', but planes go 'zoom zoom'!", "rating": 10}}
example_user: Now about caterpillars
example_assistant: {{"setup": "Caterpillar", "punchline": "Caterpillar really slow, but watch me turn into a butterfly and steal the show!", "rating": 5}}"""
prompt = ChatPromptTemplate.from_messages([("system", system), ("human", "{input}")])
few_shot_structured_llm = prompt | structured_llm
print(few_shot_structured_llm.invoke("what's something funny about woodpeckers"))
structured_llm = llm.with_structured_output(json_schema)
是使用 LangChain 提供的功能,让语言模型(LLM)在生成输出时遵循指定的 结构化格式。这个结构化的格式可以是一个 Pydantic 模型,如(FinalResponse),也可以是一个 JSON Schema 字典。
LangChain 的 .with_structured_output() 方法会:
- 自动将你提供的 Pydantic 模型(如 FinalResponse)转换成一个 JSON Schema;
- 在提示中指导 LLM 输出符合该 schema 的内容;
- 接收模型的输出后,自动将其解析为 Pydantic 对象(或者字典);
- 如果输出不符合格式要求,还会尝试修复或重新生成。
json_schema = {
"title": "joke",
"description": "Joke to tell user.",
"type": "object",
"properties": {
"setup": {
"type": "string",
"description": "The setup of the joke",
},
"punchline": {
"type": "string",
"description": "The punchline to the joke",
},
"rating": {
"type": "integer",
"description": "How funny the joke is, from 1 to 10",
"default": None,
},
},
"required": ["setup", "punchline"],
}
llm = ChatOllama(
base_url="http://127.0.0.1:11434",
model="qwen2.5:32b-instruct-q5_K_S",
temperature=0.7)
structured_llm = llm.with_structured_output(json_schema)
print(structured_llm.invoke("Tell me a joke about cats"))
langchain 大模型几种输出方式
- 直接输出
- 流式输出
- 提示词标注
# 正常生后输出
structured_llm = llm.with_structured_output(FinalResponse)
print(structured_llm.invoke("Tell me a joke about cats"))
# steam 流式输出
structured_llm = llm.with_structured_output(Joke)
for chunk in structured_llm.stream("Tell me a joke about cats"):
print(chunk)
# 通过 角色信息,进行链式使用输出
# prompt 提示词
system = """You are a hilarious comedian. Your specialty is knock-knock jokes. \
Return a joke which has the setup (the response to "Who's there?") and the final punchline (the response to "<setup> who?").
Here are some examples of jokes:
example_user: Tell me a joke about planes
example_assistant: {{"setup": "Why don't planes ever get tired?", "punchline": "Because they have rest wings!", "rating": 2}}
example_user: Tell me another joke about planes
example_assistant: {{"setup": "Cargo", "punchline": "Cargo 'vroom vroom', but planes go 'zoom zoom'!", "rating": 10}}
example_user: Now about caterpillars
example_assistant: {{"setup": "Caterpillar", "punchline": "Caterpillar really slow, but watch me turn into a butterfly and steal the show!", "rating": 5}}"""
prompt = ChatPromptTemplate.from_messages([("system", system), ("human", "{input}")])
structured_llm = llm.with_structured_output(FinalResponse)
few_shot_structured_llm = prompt | structured_llm
print(few_shot_structured_llm.invoke("what's something funny about woodpeckers"))
llm 工具调用使用及信息提取
from langchain_core.output_parsers import PydanticToolsParser
from langchain_ollama import ChatOllama
from pydantic import BaseModel, Field
# 定义了两个Pydantic模型,用于表示加法和乘法操作
class add(BaseModel):
"""Add two integers."""
a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")
class multiply(BaseModel):
"""Multiply two integers."""
a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")
# 将这两个模型作为工具
tools = [add, multiply]
# 创建一个基于Ollama的Chat模型实例,这里使用的是Qwen的一个特定版本
llm = ChatOllama(
base_url="http://127.0.0.1:11434",
model="qwen2.5:32b-instruct-q5_K_S",
temperature=0.7)
# 将工具绑定到LLM上,这样LLM就可以根据输入来决定调用哪个工具
llm_with_tools = llm.bind_tools(tools)
# 工具执行
query = "What is 3 * 12? Also, what is 11 + 49?"
var = llm_with_tools.invoke(query).tool_calls
print(var)
# 信息提取
chain = llm_with_tools | PydanticToolsParser(tools=[add, multiply])
print(chain.invoke(query))
-
Pydantic Models (add 和 multiply):
- 这里定义了两个类
add
和multiply
,它们继承自BaseModel
。这些类代表了两种数学操作:加法和乘法。 - 每个类都有两个字段
a
和b
,它们都是整数类型,并且都通过Field
函数提供了描述信息。
- 这里定义了两个类
-
Tools:
tools
列表包含了上面定义的两个模型。这意味着系统知道如何处理加法和乘法请求。
-
ChatOllama 实例化:
- 使用
ChatOllama
创建了一个LLM实例,它连接到本地运行的服务(在IP地址127.0.0.1
的端口11434
上),并指定了要使用的具体模型(qwen2.5:32b-instruct-q5_K_S
)。 temperature
参数设置为0.7
,这影响生成文本的随机性。
- 使用
-
Binding Tools to LLM:
llm.bind_tools(tools)
将之前定义的数学工具绑定到了语言模型上,使得模型能够理解并响应与这些工具相关的请求。
-
Executing the Query:
- 当你向模型发送查询
"What is 3 * 12? Also, what is 11 + 49?"
时,模型会尝试识别这个查询中提到的操作,并返回相应的工具调用。 - 打印的结果应该是类似这样的结构,表示模型识别出了乘法和加法操作以及各自的参数。
- 当你向模型发送查询
-
Parsing Output with PydanticToolsParser:
- 使用
PydanticToolsParser
进一步解析输出,将其转换成对应的Pydantic模型实例,从而便于后续处理或计算。
- 使用
python 函数使用
“”"Add two integers… 是 docstring(文档字符串),用于描述这个函数的功能、参数等信息。这是良好的编码习惯,有助于他人或你自己以后阅读代码时快速理解函数的作用,ai 调用会识别对应信息
First integer , Second integer 对应参数 描写对应信息以及 参数类型 以方便大模型调用 工具
from langchain_ollama import ChatOllama
from langchain_core.output_parsers import PydanticToolsParser
from pydantic import BaseModel, Field
def add(a: int, b: int) -> int:
"""Add two integers.
Args:
a: First integer
b: Second integer
"""
return a + b
def multiply(a: int, b: int) -> int:
"""Multiply two integers.
Args:
a: First integer
b: Second integer
"""
return a * b
tools = [add, multiply]
llm = ChatOllama(
base_url="http://127.0.0.1:11434",
model="qwen2.5:32b-instruct-q5_K_S",
temperature=0.7)
llm_with_tools = llm.bind_tools(tools)
## 工具执行
query = "What is 3 * 12? Also, what is 11 + 49?"
var = llm_with_tools.invoke(query).tool_calls
print(var)
## 信息提取
chain = llm_with_tools | PydanticToolsParser(tools=[add, multiply])
print(chain.invoke(query))