学习如何使用工具为您的LLM实现自定义函数
介绍
生成模型引起了大家的关注。许多人工智能应用现在不再需要机器学习专家,而只需要知道如何调用API。
最近,例如,我参加了一个黑客马拉松,我需要实现一个自定义的命名实体识别,但我直接使用了一个LLM,并利用其少样本学习能力获得了我想要的结果,这对于赢得黑客马拉松来说已经足够了!(如果您想要,您可以在此处查看项目)。因此,对于许多实际应用,重点更多地转向如何与这些LLM进行交互和使用,而不是创建模型。LangChain是一个允许您做到这一点的库,我最近写了几篇关于它的文章。
LangChain工具
工具是LLM可以使用的用来增强其能力的实用工具。工具可以在链或代理中实例化。例如,一个LLM可能会在回答之前进行维基百科搜索以确保得到最新的回答。当然,代理可以使用多个工具,所以通常所做的是定义一个工具列表。
现在让我们来看看一个工具的结构。 工具只是由几个字段组成的类:
- name(str):定义工具的唯一名称
- description(str):工具在自然语言中的实用性描述。LLM将能够阅读这个描述并判断是否需要该工具来回答查询。
- return_direct(bool):例如,一个工具可能返回一个自定义函数的输出。我们想要将该输出直接呈现给用户(True)还是经过LLM预处理(False)?
- args_schema(Pydantic BaseModel):例如,该工具可能使用一个自定义函数,其输入参数必须从用户的查询中检索。我们可以提供更多关于每个参数的信息,以便LLM能够更轻松地完成这一步骤。
如何定义一个工具
有多种方法来定义一个工具,本文将介绍其中的几种。首先,我们导入所需的库并实例化一个OpenAI模型。为此,您将需要一个令牌,您可以在我以前的文章中了解如何获取它。
!pip install langchain!pip install openaifrom langchain import LLMMathChain, SerpAPIWrapperfrom langchain.agents import AgentType, initialize_agentfrom langchain.chat_models import ChatOpenAIfrom langchain.tools import BaseTool, StructuredTool, Tool, toolimport osos.environ["OPENAI_API_KEY"] = ... # 在这里插入您的API_TOKENllm = ChatOpenAI(temperature=0)
实例化一个工具的第一种方法是使用Tool类。
假设我们希望给工具提供搜索网络信息的能力,为此我们将使用一些名为SerpAPI的Google API,您可以在这里注册并获取API:https://serpapi.com/ 让我们实例化一个SerpAPIWrapper类,并使用from_function方法定义工具。
在func字段中,我们需要放置一个指向我们想要使用此工具启动的方法的指针,即SerpAPI的run方法。正如我们所见,我们给工具命名并描述它。比解释更容易。
search = SerpAPIWrapper()tools = [ Tool.from_function( func=search.run, name="搜索", description="在需要回答有关当前事件的问题时非常有用" ),]
现在,我们可以将创建的工具列表提供给代理,这里只有一个。
agent = initialize_agent( tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)agent.run( "谁是Bob Dylan的女朋友?")
自定义工具
我个人认为创建自定义工具的最清晰方法是继承 BaseTool 类。
class CustomTool(BaseTool): name = "custom_tool" description = "当您需要回答有关 VoAGI 文章的问题时很有用" def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None ) -> str: """使用该工具。""" return "我不是 VoAGI 专家,但我知道 Marcello 非常擅长!:I)" async def _arun( self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None ) -> str: """异步使用该工具。""" raise NotImplementedError("custom_search 不支持异步")
您可以看到这是一个自定义工具的实现,当用户提问有关 VoAGI 的问题时将使用该工具。然而,返回的字符串可能不会与我设置的完全相同,因为它将由大型语言模型进一步处理。
如果我们想直接返回某些内容,只需以以下方式添加“return_direct”字段。
class CustomTool(BaseTool): name = "custom_tool" description = "当您需要回答有关 VoAGI 文章的问题时很有用" return_direct=True def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None ) -> str: """使用该工具。""" return "我不是 VoAGI 专家,但我知道 Marcello 非常擅长!:I)" async def _arun( self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None ) -> str: """异步使用该工具。""" raise NotImplementedError("custom_search 不支持异步")
即使我们不使用 _arun 方法(用于异步调用),我们仍然必须实现它,因为 BaseTool 是一个抽象类,如果我们不实现所有的抽象方法,将会出错。
实际例子
有一天,我的一个朋友说:“嘿 Marcello,由于你做 AI 和那种东西,为什么不给我做一个聊天机器人,可以在需要时返回医生的工作时间,并预约?”我解决这个问题的第一件事是使用 LangChain,并让 LLM 与用户进行交互,然后一旦模型理解到用户请求查看工作时间,它将直接返回一个 CSV 文件(或者如果你喜欢,可以返回一个数据帧)。
因此,对于这个用例也可以使用相同的方法。假设我们有一个名为 work_time.csv 的 CSV 文件
import pandas as pdclass WorkingHours(BaseTool): name = "working_hours" description = "当您需要回答有关医务人员工作时间的问题时很有用" return_direct=True+ def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None ) -> str: """使用该工具。""" df = pd.read_csv("working_hours.csv") #也许您需要从数据库检索一些实时数据 return df async def _arun( self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None ) -> str: """异步使用该工具。""" raise NotImplementedError("custom_search 不支持异步")
就这样,我的朋友想要的应用程序的原型只需要几行代码就完成了!当然,还要和一个优秀的前端开发人员合作,让它看起来更好!
最后的思考
LangChain 是一个最近的库,它允许我们在不同的上下文中使用 LLM 的强大功能。我发现能够使用 LLM 来理解上下文、了解用户的请求,然后运行自己的自定义函数来实际解决问题非常有用。这将使您能够编写具有灵活性的代码。要为您的应用程序添加功能,您只需要编写一个函数,并告诉模型在它认为需要时使用此函数,然后就完成了!如果您对这篇文章感兴趣,请在 VoAGI 上关注我!
💼 领英 | 🐦 推特 | 💻 网站