探秘 LangChain 函数定义
在构建基于大语言模型的应用时,LangChain 作为强大的开发框架,提供了丰富多样的定义函数方式,帮助开发者更灵活地与大语言模型交互,实现复杂功能。本文将详细介绍 Python 函数、注解形式、Pydantic 方式、TypedDict 方式和 BaseTool 这几种在 LangChain 中定义函数的方法。
下面代码示例是基于LangChain 0.3.21版本。
一、Python 函数基础定义
Python 函数是最基础、最直观的定义方式。在 LangChain 中,通过简单的 Python 函数定义,就可以实现与大语言模型的交互逻辑。例如,定义一个简单的函数,用于让大语言模型控制灯的开关:
from langchain.chat_models import init_chat_model
from langchain.schema import HumanMessage, AIMessage
def controllLight(status: bool):
"""用于控制灯的开关,若为True则为开灯,若为False则为关灯
Args:
status: 灯的状态
"""
print(f"light status : {status}")
llm = init_chat_model(model="qwen2.5", model_provider = 'ollama')
tools = [controllLight]
llm_with_tools = llm.bind_tools(tools)
query = "关闭灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
if isinstance(resp, AIMessage):
print('这是AIMessage')
print(resp.tool_calls[0].get("args"))
else:
print('不是AIMessage')
# 不能直接调用tool。需要手动解析响应获取参数status值后,再手动调用controllLight函数
二、注解形式
@tool
装饰器是定义自定义工具最简单的方式。默认情况下,该装饰器会将函数名作为工具名称,但也可以通过传入一个字符串作为第一个参数来覆盖默认名称。此外,该装饰器会将函数的文档字符串作为工具的描述,因此**必须提供**文档字符串。
from langchain_core.tools import tool
from langchain.chat_models import init_chat_model
from langchain.schema import HumanMessage
@tool
def controllLight(status: bool):
"""用于控制灯的开关,若为True则为开灯,若为False则为关灯
"""
print(f"light status : {status}")
llm = init_chat_model(model="qwen2.5", model_provider = 'ollama')
tools = [controllLight]
llm_with_tools = llm.bind_tools(tools)
query = "打开灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
query = "关闭灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
三、Pydantic
Pydantic 是用于数据验证和设置管理的库,在 LangChain 中,使用 Pydantic 方式定义函数可以更严格地验证输入数据的类型和格式,同时提供更丰富的数据处理功能。
from langchain.chat_models import init_chat_model
from langchain.schema import HumanMessage
from pydantic import BaseModel, Field
class controllLight(BaseModel):
"""用于控制灯的开关,若为True则为开灯,若为False则为关灯
"""
status: bool = Field(..., description="light status")
llm = init_chat_model(model="qwen2.5", model_provider = 'ollama')
tools = [controllLight]
llm_with_tools = llm.bind_tools(tools)
query = "打开灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
query = "关闭灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
Pydantic 不仅能验证数据类型,还能进行数据转换。例如,如果传入的length值不是整数,Pydantic 会尝试将其转换为整数(如果可能的话),若无法转换则会抛出验证错误。这种数据验证和转换功能,使得在处理复杂输入数据时更加可靠和安全。
四、TypedDict
Python的TypedDict是一种特殊的字典类型,用于定义具有固定键和特定值类型的字典。在 LangChain 中使用TypedDict方式定义函数,可以清晰地指定函数参数的结构和类型。
from langchain.chat_models import init_chat_model
from langchain.schema import HumanMessage
from typing_extensions import Annotated, TypedDict
class controllLight(TypedDict):
"""用于控制灯的开关,若为True则为开灯,若为False则为关灯"""
status: Annotated[bool, ..., "light status"]
llm = init_chat_model(model="qwen2.5", model_provider = 'ollama')
tools = [controllLight]
llm_with_tools = llm.bind_tools(tools)
query = "打开灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
query = "关闭灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
print(resp.tool_calls)
TypedDict相对灵活,在实际使用中,可以根据需要添加或修改字典的键和值类型,以适应不同的业务场景。同时,它也便于与其他数据结构和函数进行集成,提高代码的可扩展性。
五、BaseTool
BaseTool是 LangChain 中用于定义工具的基类,通过继承BaseTool类,可以将自定义的函数封装为工具,方便在代理(Agent)等场景中使用。
from typing import Optional
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model
from langchain.schema import HumanMessage
from langchain.agents import Tool
class ControllLight(BaseModel):
status: bool = Field(..., description="light status")
# Note: It's important that every field has type hints. BaseTool is a
# Pydantic class and not having type hints can lead to unexpected behavior.
class CustomLigthControlTool(BaseTool):
name: str = "LigthControl"
description: str = "用于控制灯的开关,若为True则为开灯,若为False则为关灯"
return_direct: bool = True
def _run(
self, status: bool
) -> str:
"""control light."""
return status
tool = CustomLigthControlTool()
tools = [
Tool(
name=tool.name,
func=tool.run,
description=tool.description
)
]
llm = init_chat_model(model="qwen2.5", model_provider = 'ollama')
# tools = [controllLight]
llm_with_tools = llm.bind_tools(tools)
query = "关闭灯"
messages = [HumanMessage(query)]
resp = llm_with_tools.invoke(messages)
#vscode没有自动提示tool_calls
print(resp)
总结
LangChain 中定义函数的多种方式各有特点和适用场景。Python 函数基础定义简单直接;注解形式有助于明确类型和添加描述;Pydantic 方式提供强大的数据验证和转换功能;TypedDict 方式能灵活定义参数结构;BaseTool 方式则方便将函数封装为工具用于复杂场景。开发者可以根据具体的业务需求和项目特点,选择合适的方式定义函数,从而更高效地构建基于大语言模型的应用。
参考
How to use chat models to call tools | 🦜️🔗 LangChain
How to return artifacts from a tool | 🦜️🔗 LangChain
How to create tools | 🦜️🔗 LangChain