【可能是全网最丝滑的LangChain教程】十八、LangChain进阶之Tools

永远不要说再见,因为再见意味着离去,离去意味着遗忘。

01 Tool介绍

在LangChain中,Tools 是一个核心概念,它们允许模型与外部系统进行交互,从而扩展了基础语言模型的功能。Tools 可以被看作是代理(agent)可用的一系列功能,这些功能包括但不限于网络搜索、API调用、数据库查询、文件操作等。

LangChain Tools 的基本结构

  1. 名称 (name):工具的标识符。
  2. 输入(input):工具的输入
  3. 描述 (description):描述工具用途的字符串,这将帮助代理决定何时使用此工具。
  4. 函数 (func):实际执行工具功能的可调用对象。
  5. 返回直接结果 (return_direct):如果设置为True,则代理将直接返回工具的结果,而不是将其作为思考过程的一部分。

名称、描述和 JSON 架构可用于提示 LLM,以便它知道如何指定要执行的操作,然后要调用的函数等同于执行该操作。

工具的输入越简单,LLM 就越容易使用它。

02 LangChain中的默认Tools

LangChain内置了很多的预定义工具,我们可以格式化打印看下有多少:

class BaseTool
  class Tool
  class StructuredTool
  class WikipediaQueryRun
  class AINBaseTool
    class AINAppOps
    class AINOwnerOps
    class AINRuleOps
    class AINTransfer
    class AINValueOps
  class AIPluginTool
  class ArxivQueryRun
  class AzureAiServicesDocumentIntelligenceTool
  class AzureAiServicesImageAnalysisTool
  class AzureAiServicesSpeechToTextTool
  class AzureAiServicesTextAnalyticsForHealthTool
  class AzureAiServicesTextToSpeechTool
  class AzureCogsFormRecognizerTool
  class AzureCogsImageAnalysisTool
  class AzureCogsSpeech2TextTool
  class AzureCogsText2SpeechTool
  class AzureCogsTextAnalyticsHealthTool
  class BaseGraphQLTool
  class RequestsGetTool
  class RequestsPostTool
  class RequestsPatchTool
  class RequestsPutTool
  class RequestsDeleteTool
  class QuerySQLDataBaseTool
  class InfoSQLDatabaseTool
  class ListSQLDatabaseTool
  class QuerySQLCheckerTool
  class QuerySparkSQLTool
  class InfoSparkSQLTool
  class ListSparkSQLTool
  class QueryCheckerTool
  class BingSearchRun
  class BingSearchResults
  class BraveSearch
  class BaseBrowserTool
    class ClickTool
    class CurrentWebPageTool
    class ExtractHyperlinksTool
    class ExtractTextTool
    class GetElementsTool
    class NavigateTool
    class NavigateBackTool
  class CogniswitchKnowledgeRequest
  class CogniswitchKnowledgeStatus
  class CogniswitchKnowledgeSourceFile
  class CogniswitchKnowledgeSourceURL
  class ConneryAction
  class CopyFileTool
  class DeleteFileTool
  class FileSearchTool
  class ListDirectoryTool
  class MoveFileTool
  class ReadFileTool
  class WriteFileTool
  class DataheraldTextToSQL
  class DuckDuckGoSearchRun
  class DuckDuckGoSearchResults
  class E2BDataAnalysisTool
  class EdenaiTool
    class EdenAiSpeechToTextTool
    class EdenAiTextToSpeechTool
    class EdenAiExplicitImageTool
    class EdenAiObjectDetectionTool
    class EdenAiParsingIDTool
    class EdenAiParsingInvoiceTool
    class EdenAiTextModerationTool
  class ElevenLabsText2SpeechTool
  class GmailBaseTool
    class GmailCreateDraft
    class GmailGetMessage
    class GmailGetThread
    class GmailSearch
    class GmailSendMessage
  class GoogleCloudTextToSpeechTool
  class GooglePlacesTool
  class GoogleSearchRun
  class GoogleSearchResults
  class GoogleSerperRun
  class GoogleSerperResults
  class HumanInputRun
  class IFTTTWebhook
  class QueryPowerBITool
  class InfoPowerBITool
  class ListPowerBITool
  class JiraAction
  class JsonListKeysTool
  class JsonGetValueTool
  class MerriamWebsterQueryRun
  class MetaphorSearchResults
  class MojeekSearch
  class NasaAction
  class O365BaseTool
    class O365CreateDraftMessage
    class O365SearchEvents
    class O365SearchEmails
    class O365SendEvent
    class O365SendMessage
  class OpenWeatherMapQueryRun
  class PolygonAggregates
  class PolygonFinancials
  class PolygonLastQuote
  class PolygonTickerNews
  class PubmedQueryRun
  class RedditSearchRun
  class SceneXplainTool
  class SearchAPIRun
  class SearchAPIResults
  class SearxSearchRun
  class SearxSearchResults
  class ShellTool
  class SlackBaseTool
    class SlackGetChannel
    class SlackGetMessage
    class SlackScheduleMessage
    class SlackSendMessage
  class SleepTool
  class StackExchangeTool
  class SteamWebAPIQueryRun
  class SteamshipImageGenerationTool
  class VectorStoreQATool
  class VectorStoreQAWithSourcesTool
  class WolframAlphaQueryRun
  class YahooFinanceNewsTool
  class YouSearchTool
  class YouTubeSearchTool
  class ZapierNLARunAction
  class ZapierNLAListActions
  class PythonREPLTool
  class PythonAstREPLTool
  class InvalidTool
  class ExceptionTool
  class DataForSeoAPISearchRun
  class DataForSeoAPISearchResults
  class GoldenQueryRun
  class GoogleFinanceQueryRun
  class GoogleJobsQueryRun
  class GoogleLensQueryRun
  class GoogleScholarQueryRun
  class GoogleTrendsQueryRun
  class Memorize

我们可以挑几个简单看下:

  1. WikipediaQueryRun:用于向维基百科API发送查询并获取数据
  2. RequestsGetTool:使用HTTP GET方法从指定的URL获取数据。
  3. RequestsPostTool:使用HTTP POST方法向服务器发送数据。
  4. QuerySQLDataBaseTool:对数据库执行SQL查询并返回结果。
  5. ShellTool:执行shell命令。
  6. PythonREPLTool:执行Python命令

下面以WikipediaQueryRun为例子,简单解释说明下使用和原理。

基本使用如下:

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper

api_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=100)
tool = WikipediaQueryRun(api_wrapper=api_wrapper)

tool.name
"""
wikipedia
"""

tool.description
"""
A wrapper around Wikipedia. Useful for when you need to answer general questions about people, places, companies, facts, historical events, or other subjects. Input should be a search query.
"""

tool.args
"""
{'query': {'title': 'Query', 'type': 'string'}}
"""

tool.return_direct
"""
False
"""

tool.run({"query": "langchain"})
"""
Page: LangChain\nSummary: LangChain is a framework designed to simplify the creation of applications 
"""

在上面代码中,我们通过打印相关参数可以看到这个Tool的基本信息。最后通过tool.run方法执行此工具,搜索"langchain"得到了最终输出。

WikipediaAPIWrapper源码分析如下:

class WikipediaAPIWrapper(BaseModel):
    """
    wiki百科工具的具体调用逻辑,包括
    - 定义一些参数
    - 具体执行逻辑
    - 加载搜索结果为Document
    - ...
    """
    
    # 具体的调用客户端,通过pip install wikipedia后能拿到
    wiki_client: Any 
    # 搜索结果的数量
    top_k_results: int = 3
    # 搜索结果的语言
    lang: str = "en"
    # 用于配置元数据信息
    load_all_available_meta: bool = False
    # 单个Document的内容长度
    doc_content_chars_max: int = 4000

    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """
        环境验证,也就是有没有安装wikipedia三方库
        不安装没法做请求
        """
        try:
            import wikipedia

            wikipedia.set_lang(values["lang"])
            values["wiki_client"] = wikipedia
        except ImportError:
            raise ImportError(
                "Could not import wikipedia python package. "
                "Please install it with `pip install wikipedia`."
            )
        return values

    def run(self, query: str) -> str:
        """
        具体的执行逻辑,本质还是做网络请求拿结果
        """
        page_titles = self.wiki_client.search(
            query[:WIKIPEDIA_MAX_QUERY_LENGTH], results=self.top_k_results
        )
        summaries = []
        for page_title in page_titles[: self.top_k_results]:
            if wiki_page := self._fetch_page(page_title):
                if summary := self._formatted_page_summary(page_title, wiki_page):
                    summaries.append(summary)
        if not summaries:
            return "No good Wikipedia Search Result was found"
        return "\n\n".join(summaries)[: self.doc_content_chars_max]

    @staticmethod
    def _formatted_page_summary(page_title: str, wiki_page: Any) -> Optional[str]:
        """
        对接过进行封装展示(相当于格式化)
        """
        return f"Page: {page_title}\nSummary: {wiki_page.summary}"

    def _page_to_document(self, page_title: str, wiki_page: Any) -> Document:
        """
        搜索结果转Document,方便后续LLM使用
        """
        main_meta = {
            "title": page_title,
            "summary": wiki_page.summary,
            "source": wiki_page.url,
        }
        add_meta = (
            {
                "categories": wiki_page.categories,
                "page_url": wiki_page.url,
                "image_urls": wiki_page.images,
                "related_titles": wiki_page.links,
                "parent_id": wiki_page.parent_id,
                "references": wiki_page.references,
                "revision_id": wiki_page.revision_id,
                "sections": wiki_page.sections,
            }
            if self.load_all_available_meta
            else {}
        )
        doc = Document(
            page_content=wiki_page.content[: self.doc_content_chars_max],
            metadata={
                **main_meta,
                **add_meta,
            },
        )
        return doc

    def _fetch_page(self, page: str) -> Optional[str]:
        """
        这里还是具体的调用逻辑
        """
        try:
            return self.wiki_client.page(title=page, auto_suggest=False)
        except (
            self.wiki_client.exceptions.PageError,
            self.wiki_client.exceptions.DisambiguationError,
        ):
            return None

    def load(self, query: str) -> List[Document]:
        """
        从输入直接到Document集合,内部还是先获取结果,然后再封装
        """
        return list(self.lazy_load(query))

    def lazy_load(self, query: str) -> Iterator[Document]:
        """
        从输入直接到Document集合,内部还是先获取结果,然后再封装
        load(self, query: str) 本质还是调用这个方法
        """
        page_titles = self.wiki_client.search(
            query[:WIKIPEDIA_MAX_QUERY_LENGTH], results=self.top_k_results
        )
        for page_title in page_titles[: self.top_k_results]:
            if wiki_page := self._fetch_page(page_title):
                if doc := self._page_to_document(page_title, wiki_page):
                    yield doc

WikipediaQueryRun源码如下,本质还是对WikipediaAPIWrapper的调用:

class WikipediaQueryRun(BaseTool):
    """Tool that searches the Wikipedia API."""

    name: str = "wikipedia"
    description: str = (
        "A wrapper around Wikipedia. "
        "Useful for when you need to answer general questions about "
        "people, places, companies, facts, historical events, or other subjects. "
        "Input should be a search query."
    )
    api_wrapper: WikipediaAPIWrapper

    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Wikipedia tool."""
        return self.api_wrapper.run(query)

源码分析到这,后续我们如果想自定义Tool,基本步骤也就出来了。怎么说呢,不难bro~

03 自定义Tool

有时候我们想“骚一下”,或者说LangChain内部预定义的Tools已经不能满足我们的使用需求了,这个时候自定义Tool的需求就来了。

一般情况下,自定义Tool需要定义以下几个组件:

  1. name (str) 是必需的,并且在提供给代理的一组工具中必须是唯一的*
  2. description (str) 是可选的,但建议使用,因为代理使用它来确定工具的使用情况*
  3. args_schema (Pydantic BaseModel) 是可选的,但推荐使用,可用于提供更多信息(例如,少量示例)或验证预期参数。*

@tool decorator

@tool 装饰器是定义自定义工具的最简单方法。默认情况下,装饰器使用函数名称作为工具名称,但可以通过传递字符串作为第一个参数来覆盖此名称。此外,装饰器将使用函数的文档字符串作为工具的描述 - 因此必须提供文档字符串。

基本使用如下:

@tool
def search(query: str) -> str:
    """Look up things online."""
    return "LangChain"

print(search.name)
"""
search
"""

print(search.description)
"""
search(query: str) -> str - Look up things online.
"""

print(search.args)
"""
{'query': {'title': 'Query', 'type': 'string'}}
"""
# =================================================================

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

print(multiply.name)
"""
multiply
"""

print(multiply.description)
"""
multiply(a: int, b: int) -> int - Multiply two numbers.
"""

print(multiply.args)
"""
{'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}
"""

还可以通过将工具名称和 JSON 参数传递到工具装饰器中来自定义它们。

# 注意这里的命名空间,必须是langchain.pydantic_v1
from langchain.pydantic_v1 import BaseModel, Field

class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")


@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "LangChain"

print(search.name)
"""
search-tool
"""

print(search.description)
"""
search-tool(query: str) -> str - Look up things online.
"""

print(search.args)
"""
{'query': {'title': 'Query', 'description': 'should be a search query', 'type': 'string'}}
"""

print(search.return_direct)
"""
True
"""

Subclass BaseTool

还可以通过对 BaseTool 类进行子类化来显式定义自定义工具,这种方式更灵活但是更复杂。

我们改造先上面的两个自定义Tool

from typing import Optional, Type
from langchain.pydantic_v1 import BaseModel, Field
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)


class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")
    
class CustomSearchTool(BaseTool):
    name = "custom_search"
    description = "useful for when you need to answer questions about current events"
    args_schema: Type[BaseModel] = SearchInput
    
    def _run(
        self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        return "LangChain"
    
    async def _arun(
        self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool asynchronously."""
        raise NotImplementedError("custom_search does not support async")
    
class CustomCalculatorTool(BaseTool):
    name = "Calculator"
    description = "useful for when you need to answer questions about math"
    args_schema: Type[BaseModel] = CalculatorInput
    return_direct: bool = True

    def _run(
        self, a: int, b: int, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> int:
        """Use the tool."""
        return a * b

    async def _arun(
        self,
        a: int,
        b: int,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        raise NotImplementedError("Calculator does not support async")

打印参数,看下输出

search = CustomSearchTool()
print(search.name)
"""
custom_search
"""

print(search.description)
"""
useful for when you need to answer questions about current events
"""

print(search.args)
"""
{'query': {'title': 'Query', 'description': 'should be a search query', 'type': 'string'}}
"""

multiply = CustomCalculatorTool()
print(multiply.name)
"""
Calculator
"""

print(multiply.description)
"""
useful for when you need to answer questions about math
"""

print(multiply.args)
"""
{'a': {'title': 'A', 'description': 'first number', 'type': 'integer'}, 'b': {'title': 'B', 'description': 'second number', 'type': 'integer'}}
"""

print(multiply.return_direct)
"""
True
"""

StructuredTool dataclass

还可以使用 StructuredTool 数据类。这种方法是前两种方法的混合。它比从 BaseTool 类继承更方便,但提供了比仅使用装饰器更多的功能。

示例代码如下:

from langchain.tools import BaseTool, StructuredTool, tool

def search_function(query: str):
    return "LangChain"


search = StructuredTool.from_function(
    func=search_function,
    name="Search",
    description="useful for when you need to answer questions about current events",
)

print(search.name)
"""
Search
"""

print(search.description)
"""
Search(query: str) - useful for when you need to answer questions about current events
"""

print(search.args)
"""
{'query': {'title': 'Query', 'type': 'string'}}
"""

# ===============================================================

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")


def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b


calculator = StructuredTool.from_function(
    func=multiply,
    name="Calculator",
    description="multiply numbers",
    args_schema=CalculatorInput,
    return_direct=True,
)

print(calculator.name)
"""
Calculator
"""

print(calculator.description)
"""
Calculator(a: int, b: int) -> int - multiply numbers
"""

print(calculator.args)
"""
{'a': {'title': 'A', 'description': 'first number', 'type': 'integer'}, 'b': {'title': 'B', 'description': 'second number', 'type': 'integer'}}
"""

对于以上三种自定义Tool的方式,从打印结果来看基本一致,具体选择哪种方式还得看实际需求。这里我个人建议使用第一种装饰器的方式~

Handling Tool Errors

当工具遇到错误且未捕获异常时,代理将停止执行。如果希望代理继续执行,可以引发 ToolException 并相应地设置 handle_tool_error。

当抛出 ToolException 时,智能体不会停止工作,而是会根据工具的 handle_tool_error 变量处理异常,处理结果将作为观察结果返回给智能体,并以红色打印。

有点懵?看看代码理解一下~

from langchain_core.tools import ToolException
from langchain.tools import BaseTool, StructuredTool, tool

def search_tool1(s: str):
    raise ToolException("The search tool1 is not available.")

search = StructuredTool.from_function(
    func=search_tool1,
    name="Search_tool1",
    description="A bad tool",
)

search.run("test")

上面代码会直接抛异常报错,整个程序会停止工作。

我们将 handle_tool_error 设置成True,此时程序正常执行并输出错误信息。

search = StructuredTool.from_function(
    func=search_tool1,
    name="Search_tool1",
    description="A bad tool",
    handle_tool_error=True,
)

search.run("test") # The search tool1 is not available.

"""
[tool/start] [tool:Search_tool1] Entering Tool run with input:
"test"
[tool/end] [tool:Search_tool1] [1ms] Exiting Tool run with output:
"The search tool1 is not available."
"""

我们还可以定义一种自定义方法来处理工具错误,如下:

def _handle_error(error: ToolException) -> str:
    return (
        "The following errors occurred during tool execution:"
        + error.args[0]
        + "Please try another tool."
    )


search = StructuredTool.from_function(
    func=search_tool1,
    name="Search_tool1",
    description="A bad tool",
    handle_tool_error=_handle_error,
)

search.run("test") # The following errors occurred during tool execution:The search tool1 is not available.Please try another tool.

"""
[tool/start] [tool:Search_tool1] Entering Tool run with input:
"test"
[tool/end] [tool:Search_tool1] [1ms] Exiting Tool run with output:
"The following errors occurred during tool execution:The search tool1 is not available.Please try another tool."
"""

实际开发中,建议在自定义Tool的时候加上错误处理。

04 Toolkits

顾名思义,这叫“工具包”。

工具包是旨在一起用于特定任务的工具集合。他们有方便的装载方法。所有工具包都公开一个 get_tools 方法,该方法返回工具列表。因此,您可以执行以下操作:

# Initialize a toolkit
toolkit = ExampleTookit(...)

# Get list of tools
tools = toolkit.get_tools()

# Create agent
agent = create_agent_method(llm, tools, prompt)

LangChain内置了很多常用的工具包,如下:

_module_lookup = {
    "AINetworkToolkit": "langchain_community.agent_toolkits.ainetwork.toolkit",
    "AmadeusToolkit": "langchain_community.agent_toolkits.amadeus.toolkit",
    "AzureAiServicesToolkit": "langchain_community.agent_toolkits.azure_ai_services",
    "AzureCognitiveServicesToolkit": "langchain_community.agent_toolkits.azure_cognitive_services",  # noqa: E501
    "CogniswitchToolkit": "langchain_community.agent_toolkits.cogniswitch.toolkit",
    "ConneryToolkit": "langchain_community.agent_toolkits.connery",
    "FileManagementToolkit": "langchain_community.agent_toolkits.file_management.toolkit",  # noqa: E501
    "GmailToolkit": "langchain_community.agent_toolkits.gmail.toolkit",
    "JiraToolkit": "langchain_community.agent_toolkits.jira.toolkit",
    "JsonToolkit": "langchain_community.agent_toolkits.json.toolkit",
    "MultionToolkit": "langchain_community.agent_toolkits.multion.toolkit",
    "NLAToolkit": "langchain_community.agent_toolkits.nla.toolkit",
    "NasaToolkit": "langchain_community.agent_toolkits.nasa.toolkit",
    "O365Toolkit": "langchain_community.agent_toolkits.office365.toolkit",
    "OpenAPIToolkit": "langchain_community.agent_toolkits.openapi.toolkit",
    "PlayWrightBrowserToolkit": "langchain_community.agent_toolkits.playwright.toolkit",
    "PolygonToolkit": "langchain_community.agent_toolkits.polygon.toolkit",
    "PowerBIToolkit": "langchain_community.agent_toolkits.powerbi.toolkit",
    "SQLDatabaseToolkit": "langchain_community.agent_toolkits.sql.toolkit",
    "SlackToolkit": "langchain_community.agent_toolkits.slack.toolkit",
    "SparkSQLToolkit": "langchain_community.agent_toolkits.spark_sql.toolkit",
    "SteamToolkit": "langchain_community.agent_toolkits.steam.toolkit",
    "ZapierToolkit": "langchain_community.agent_toolkits.zapier.toolkit",
    "create_json_agent": "langchain_community.agent_toolkits.json.base",
    "create_openapi_agent": "langchain_community.agent_toolkits.openapi.base",
    "create_pbi_agent": "langchain_community.agent_toolkits.powerbi.base",
    "create_pbi_chat_agent": "langchain_community.agent_toolkits.powerbi.chat_base",
    "create_spark_sql_agent": "langchain_community.agent_toolkits.spark_sql.base",
    "create_sql_agent": "langchain_community.agent_toolkits.sql.base",
}

__all__ = [
    "create_xorbits_agent",
    "create_pandas_dataframe_agent",
    "create_spark_dataframe_agent",
    "create_python_agent",
    "create_csv_agent",
]

这些工具包帮助我们快速方便的处理Json、CSV、Github、SQL、python等任务。

04 Tool as OpenAI Functions

专门适配OpenAI FunctionCall功能,只对gpt相关模型有效,目的是为了将我们定义的各种Tool转换成OpenAI Function。基本使用如下:

from langchain_community.tools import MoveFileTool
from langchain_core.messages import HumanMessage
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-3.5-turbo")

# 创建tool集合
tools = [MoveFileTool()]
# 将tool转换成openai支持的function格式
functions = [convert_to_openai_function(t) for t in tools]

functions[0]
"""
{'name': 'move_file',
 'description': 'Move or rename a file from one location to another',
 'parameters': {'type': 'object',
  'properties': {'source_path': {'description': 'Path of the file to move',
    'type': 'string'},
   'destination_path': {'description': 'New path for the moved file',
    'type': 'string'}},
  'required': ['source_path', 'destination_path']}}
"""

# 将消息和function传给模型执行,这里模型会自动调用tool
message = model.invoke(
    [HumanMessage(content="move file foo to bar")], functions=functions
)
"""
AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\n  "source_path": "foo",\n  "destination_path": "bar"\n}', 'name': 'move_file'}})
"""

# 获取function_call,这里的内容都是MoveFileTool里面定义好的
message.additional_kwargs["function_call"]
"""
{'name': 'move_file',
 'arguments': '{\n  "source_path": "foo",\n  "destination_path": "bar"\n}'}
"""

借助 OpenAI 聊天模型,我们还可以使用 bind_functions 自动绑定和转换类似函数的对象。

model_with_functions = model.bind_functions(tools)
model_with_functions.invoke([HumanMessage(content="move file foo to bar")])
"""
AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\n  "source_path": "foo",\n  "destination_path": "bar"\n}', 'name': 'move_file'}})
"""

或者,我们可以使用更新的 OpenAI API,它使用 tools 和 tool_choice 而不是 functions 和 function_call 通过使用 ChatOpenAI.bind_tools:

model_with_tools = model.bind_tools(tools)
model_with_tools.invoke([HumanMessage(content="move file foo to bar")])
"""
AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_btkY3xV71cEVAOHnNa5qwo44', 'function': {'arguments': '{\n  "source_path": "foo",\n  "destination_path": "bar"\n}', 'name': 'move_file'}, 'type': 'function'}]})
"""

05 总结

本篇文章主要是介绍Tool的基本配置,以及如何自定义Tool,并没有介绍如何使用Tool。

实际上,Tool一般会与Agent,也就是所谓的代理(也可以叫智能体)一起使用。这块内容下篇文章会介绍,感谢阅读。

以上就是本次 Tools 的全部内容,希望能给到你们一些小小的帮助。

如果能帮我点个免费的关注,那就是对我个人的最大的肯定。如果觉得写的还行,分享一下也是我生活的小确幸~

在这里插入图片描述

以上内容依据官方文档编写,官方地址:https://python.langchain.com/docs/modules/tools

Peace Guys~

在这里插入图片描述

  • 【LangChain进阶教程】十、LangChain进阶之Retrievers
  • 【LangChain进阶教程】九、LangChain进阶之Vector Stores
  • 【LangChain进阶教程】八、LangChain进阶之Embedding Models
  • 【LangChain进阶教程】七、LangChain进阶之Text Splitters

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/800910.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网页数据抓取:融合BeautifulSoup和Scrapy的高级爬虫技术

网页数据抓取:融合BeautifulSoup和Scrapy的高级爬虫技术 在当今的大数据时代,网络爬虫技术已经成为获取信息的重要手段之一。Python凭借其强大的库支持,成为了进行网页数据抓取的首选语言。在众多的爬虫库中,BeautifulSoup和Scrap…

【数据结构】:时间和空间复杂度

目录 如何衡量一个代码的好坏 时间复杂度 概念 计算方法 实例计算 【实例1】 【实例2】 【实例3】 【实例4】:冒泡排序的时间复杂度 【实例5】:二分查找的时间复杂度 【实例6】:阶乘递归的时间复杂度 【实例7】:斐波那契…

如何通过SSH协议使用WinSCP实现Windows与Linux之间的远程公网文件传输

目录 ⛳️推荐 前言 1. Windows传输文件至Linux 2. WinSCP使用公网TCP地址连接 3. WinSCP使用固定公网TCP地址访问服务器 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站 前…

算法力扣刷题记录 四十八【513.找树左下角的值】

前言 二叉树篇继续。 记录 四十八【513.找树左下角的值】 一、题目阅读 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,nul…

云计算数据中心(二)

目录 三、绿色节能技术(一)配电系统节能技术(二)空调系统节能技术(三)集装箱数据中心节能技术(四)数据中心节能策略和算法研究(五)新能源的应用(六…

下一代AI芯片的演进趋势

下一代AI芯片,拼什么? AI,这个无尽的财富,无人愿意错过。尽管摩尔定律的极限临近,芯片性能提升愈发艰难。然而,各大厂商仍以瞩目速度推出新一代产品。在最近的台北国际电脑展上,英伟达、AMD和英…

每日一练@

目录 题目1.关于AOP错误的是?2.关于以下代码的说明,正确的是( )3.以下类型为Final类型的为()4.以下说法哪个是正确的() 题目 选自牛客网 1.关于AOP错误的是? A.AOP将散…

位运算问题

1. 只出现一次的数字 III 题目描述: 算法原理: 因为两个相同的数经过异或就等于0,所以首先将数组中的每个数字异或到一起,这样就得到了两个出现一次的元素的异或值。假设得到的异或值为n,那么我们去求异或值的最低位…

python自动化之validator验证数据【代码示例】

思路: 首先定义验证规则schema,包含name,age和email三个字段; 然后创建验证器对象validator,并将schema作为参数传递给它; 最后定义要验证的数据data,使用validator的validate方法进行验证&a…

【Stable Diffusion】(基础篇三)—— 图生图基础

图生图基础 本系列笔记主要参考B站nenly同学的视频教程,传送门:B站第一套系统的AI绘画课!零基础学会Stable Diffusion,这绝对是你看过的最容易上手的AI绘画教程 | SD WebUI 保姆级攻略_哔哩哔哩_bilibili 本文主要讲解如何使用S…

数据结构(5.0)——树的定义和基本术语

树的基本概念 树是n(n>0)个结点的有限集合,n0时,称为空树,这是一种特殊情况。在任意一颗非空树中应该满足: 有且仅有一个特定的称为根的结点。 当n>1时,其余结点可分为m(m>0)个互不相交的有限集合T1、T2、.......&…

C++第七弹 -- C/C++内存管理

目录 前言一. C/C内存分布二. C语言中动态内存管理方式三. C中动态内存管理四. operator new与operator delete函数五. new和delete的实现原理1.内置类型2. 自定义类型 六. 定位new表达式(placement-new)七. 常见面试题总结 前言 在C/C编程中,内存管理是至关重要的…

领夹麦克风品牌排行榜前十名,录短视频用什么麦克风好?

随着自媒体行业的迅猛发展,对高品质音频设备的需求日益增长,尤其是无线领夹麦克风因其便携性和实用性受到了广泛欢迎。这种麦克风不仅适用于新闻采访和节目录制,也成为了网络直播和Vlog创作者的得力助手。它们能够提供清晰的录音效果&#xf…

最新版康泰克完整版- Kontakt v7.10.5 for Win和Mac,支持m芯片和intel,有入库工具

一。世界最受欢迎的采样器的新篇章 Native Instruments Kontakt是采样器领域的标准,您将获得高质量的滤波器,在这里您将找到经典的模拟电路和最现代的滤波器。每一个都可以根据您的口味进行定制,并且由于它,您可以获得前所未有的声…

AIGC笔记--基于Stable Diffusion实现图片的inpainting

1--完整代码 SD_Inpainting 2--简单代码 import PIL import torch import numpy as np from PIL import Image from tqdm import tqdm import torchvision from diffusers import AutoencoderKL, UNet2DConditionModel, DDIMScheduler from transformers import CLIPTextMod…

源码安装zabbix5.0.36完整版

源码安装zabbix5.0.36完整版 环境:CentOS Linux release 7.9,cpu:16,mem:32G软件包如下: zabbix-5.0.36.tar.gz mysql-8.0.28-linux-glibc2.17-x86_64-minimal.tar.xz nginx-1.6.2.tar.gz 1. 配置前准备 systemctl stop firewa…

K8s集群初始化遇到的问题

kubectl describe pod coredns-545d6fc579-s9g5s -n kube-system 找到原因1:CoreDNS Pod 处于 Pending 状态的原因是集群中的节点都带有 node.kubernetes.io/not-ready 污点 journalctl -u kubelet -f 14:57:59.178592 3553 remote_image.go:114] "PullIma…

集群节点状态异常的解决方式

文章目录 集群节点状态异常的解决方式问题概述解决方式1.关闭所有服务2.对所有集群删除Hadoop相关文件2.1 删除Hadoop系统运行时创建的临时数据和文件2.2 删除Hadoop的数据文件 3.重新对Hadoop节点进行初始化和启用4.重启服务,检查节点状态 集群节点状态异常的解决方…

Parallels Desktop 19 for Mac(PD19虚拟机)详细图文安装教程分享

Parallels Desktop 19是一款功能丰富、性能强大且易于使用的虚拟机软件,它可以让您在Mac上同时运行多个操作系统,为您提供更大的灵活性和兼容性。 Parallels Desktop 19 for Mac(PD19虚拟机)下载安装包 Parallels Desktop 19 for Mac(PD19虚拟机)详细图…