跳到主要內容
Open In ColabOpen on GitHub

如何將 Runnables 轉換為 Tools

先決條件

本指南假設您熟悉以下概念

在此我們將示範如何將 LangChain Runnable 轉換為可由代理程式、鏈或聊天模型使用的工具。

依賴項

注意:本指南需要 langchain-core >= 0.2.13。我們也將使用 OpenAI 進行嵌入,但任何 LangChain 嵌入都應該足夠。我們將使用簡單的 LangGraph 代理程式進行示範。

%%capture --no-stderr
%pip install -U langchain-core langchain-openai langgraph

LangChain 工具是代理程式、鏈或聊天模型可用於與世界互動的介面。請參閱此處的操作指南,內容涵蓋工具調用、內建工具、自訂工具以及更多資訊。

LangChain 工具(BaseTool 的實例)是 Runnables,具有額外的約束,使其能夠被語言模型有效地調用

  • 它們的輸入被限制為可序列化,特別是字串和 Python dict 物件;
  • 它們包含名稱和描述,指示應如何以及何時使用它們;
  • 它們可能包含其參數的詳細 args_schema。也就是說,雖然工具(作為 Runnable)可能接受單個 dict 輸入,但填充 dict 所需的特定鍵和類型資訊應在 args_schema 中指定。

接受字串或 dict 輸入的 Runnables 可以使用 as_tool 方法轉換為工具,該方法允許指定名稱、描述和參數的其他 schema 資訊。

基本用法

使用類型化 dict 輸入

from typing import List

from langchain_core.runnables import RunnableLambda
from typing_extensions import TypedDict


class Args(TypedDict):
a: int
b: List[int]


def f(x: Args) -> str:
return str(x["a"] * max(x["b"]))


runnable = RunnableLambda(f)
as_tool = runnable.as_tool(
name="My tool",
description="Explanation of when to use tool.",
)
API 參考:RunnableLambda
print(as_tool.description)

as_tool.args_schema.schema()
Explanation of when to use tool.
{'title': 'My tool',
'type': 'object',
'properties': {'a': {'title': 'A', 'type': 'integer'},
'b': {'title': 'B', 'type': 'array', 'items': {'type': 'integer'}}},
'required': ['a', 'b']}
as_tool.invoke({"a": 3, "b": [1, 2]})
'6'

如果沒有類型資訊,則可以透過 arg_types 指定參數類型

from typing import Any, Dict


def g(x: Dict[str, Any]) -> str:
return str(x["a"] * max(x["b"]))


runnable = RunnableLambda(g)
as_tool = runnable.as_tool(
name="My tool",
description="Explanation of when to use tool.",
arg_types={"a": int, "b": List[int]},
)

或者,可以透過直接傳遞工具所需的 args_schema 來完全指定 schema

from pydantic import BaseModel, Field


class GSchema(BaseModel):
"""Apply a function to an integer and list of integers."""

a: int = Field(..., description="Integer")
b: List[int] = Field(..., description="List of ints")


runnable = RunnableLambda(g)
as_tool = runnable.as_tool(GSchema)

也支援字串輸入

def f(x: str) -> str:
return x + "a"


def g(x: str) -> str:
return x + "z"


runnable = RunnableLambda(f) | g
as_tool = runnable.as_tool()
as_tool.invoke("b")
'baz'

在代理程式中

下面我們將在代理程式應用程式中將 LangChain Runnables 作為工具整合。我們將示範

  • 文件檢索器
  • 一個簡單的 RAG 鏈,允許代理程式將相關查詢委派給它。

我們首先實例化一個支援工具調用的聊天模型

pip install -qU "langchain[openai]"
import getpass
import os

if not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter API key for OpenAI: ")

from langchain.chat_models import init_chat_model

llm = init_chat_model("gpt-4o-mini", model_provider="openai")

依照 RAG 教學,我們先建構一個檢索器

from langchain_core.documents import Document
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_openai import OpenAIEmbeddings

documents = [
Document(
page_content="Dogs are great companions, known for their loyalty and friendliness.",
),
Document(
page_content="Cats are independent pets that often enjoy their own space.",
),
]

vectorstore = InMemoryVectorStore.from_documents(
documents, embedding=OpenAIEmbeddings()
)

retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 1},
)

接下來,我們建立並使用一個簡單的預建 LangGraph 代理程式,並為其提供工具

from langgraph.prebuilt import create_react_agent

tools = [
retriever.as_tool(
name="pet_info_retriever",
description="Get information about pets.",
)
]
agent = create_react_agent(llm, tools)
API 參考:create_react_agent
for chunk in agent.stream({"messages": [("human", "What are dogs known for?")]}):
print(chunk)
print("----")
{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_W8cnfOjwqEn4cFcg19LN9mYD', 'function': {'arguments': '{"__arg1":"dogs"}', 'name': 'pet_info_retriever'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 19, 'prompt_tokens': 60, 'total_tokens': 79}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-d7f81de9-1fb7-4caf-81ed-16dcdb0b2ab4-0', tool_calls=[{'name': 'pet_info_retriever', 'args': {'__arg1': 'dogs'}, 'id': 'call_W8cnfOjwqEn4cFcg19LN9mYD'}], usage_metadata={'input_tokens': 60, 'output_tokens': 19, 'total_tokens': 79})]}}
----
{'tools': {'messages': [ToolMessage(content="[Document(id='86f835fe-4bbe-4ec6-aeb4-489a8b541707', page_content='Dogs are great companions, known for their loyalty and friendliness.')]", name='pet_info_retriever', tool_call_id='call_W8cnfOjwqEn4cFcg19LN9mYD')]}}
----
{'agent': {'messages': [AIMessage(content='Dogs are known for being great companions, known for their loyalty and friendliness.', response_metadata={'token_usage': {'completion_tokens': 18, 'prompt_tokens': 134, 'total_tokens': 152}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-9ca5847a-a5eb-44c0-a774-84cc2c5bbc5b-0', usage_metadata={'input_tokens': 134, 'output_tokens': 18, 'total_tokens': 152})]}}
----

請參閱 LangSmith 追蹤以了解上述執行情況。

更進一步,我們可以建立一個簡單的 RAG 鏈,它接受一個額外的參數——這裡是指答案的「風格」。

from operator import itemgetter

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

system_prompt = """
You are an assistant for question-answering tasks.
Use the below context to answer the question. If
you don't know the answer, say you don't know.
Use three sentences maximum and keep the answer
concise.

Answer in the style of {answer_style}.

Question: {question}

Context: {context}
"""

prompt = ChatPromptTemplate.from_messages([("system", system_prompt)])

rag_chain = (
{
"context": itemgetter("question") | retriever,
"question": itemgetter("question"),
"answer_style": itemgetter("answer_style"),
}
| prompt
| llm
| StrOutputParser()
)

請注意,我們的鏈的輸入 schema 包含所需的參數,因此它會轉換為工具,而無需進一步指定

rag_chain.input_schema.schema()
{'title': 'RunnableParallel<context,question,answer_style>Input',
'type': 'object',
'properties': {'question': {'title': 'Question'},
'answer_style': {'title': 'Answer Style'}}}
rag_tool = rag_chain.as_tool(
name="pet_expert",
description="Get information about pets.",
)

下面我們再次調用代理程式。請注意,代理程式在其 tool_calls 中填充了所需的參數

agent = create_react_agent(llm, [rag_tool])

for chunk in agent.stream(
{"messages": [("human", "What would a pirate say dogs are known for?")]}
):
print(chunk)
print("----")
{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_17iLPWvOD23zqwd1QVQ00Y63', 'function': {'arguments': '{"question":"What are dogs known for according to pirates?","answer_style":"quote"}', 'name': 'pet_expert'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 28, 'prompt_tokens': 59, 'total_tokens': 87}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-7fef44f3-7bba-4e63-8c51-2ad9c5e65e2e-0', tool_calls=[{'name': 'pet_expert', 'args': {'question': 'What are dogs known for according to pirates?', 'answer_style': 'quote'}, 'id': 'call_17iLPWvOD23zqwd1QVQ00Y63'}], usage_metadata={'input_tokens': 59, 'output_tokens': 28, 'total_tokens': 87})]}}
----
{'tools': {'messages': [ToolMessage(content='"Dogs are known for their loyalty and friendliness, making them great companions for pirates on long sea voyages."', name='pet_expert', tool_call_id='call_17iLPWvOD23zqwd1QVQ00Y63')]}}
----
{'agent': {'messages': [AIMessage(content='According to pirates, dogs are known for their loyalty and friendliness, making them great companions for pirates on long sea voyages.', response_metadata={'token_usage': {'completion_tokens': 27, 'prompt_tokens': 119, 'total_tokens': 146}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-5a30edc3-7be0-4743-b980-ca2f8cad9b8d-0', usage_metadata={'input_tokens': 119, 'output_tokens': 27, 'total_tokens': 146})]}}
----

請參閱 LangSmith 追蹤以了解上述執行情況。


此頁面是否有幫助?