Compare commits

...

5 Commits

Author SHA1 Message Date
Chester Curme
2da02aede5 fix chat model tabs 2024-07-23 17:10:30 -04:00
Chester Curme
29cb56259f remove erroneous langgraph reference 2024-07-23 17:00:04 -04:00
Chester Curme
7fe4b16862 update 2024-07-23 16:35:49 -04:00
Chester Curme
ca9793158e format 2024-07-23 16:16:33 -04:00
Chester Curme
00dd1dd3ba add doc 2024-07-23 16:16:14 -04:00
2 changed files with 269 additions and 0 deletions

View File

@@ -201,6 +201,7 @@ LangChain [Tools](/docs/concepts/#tools) contain a description of the tool (to p
- [How to: convert Runnables to tools](/docs/how_to/convert_runnable_to_tool)
- [How to: add ad-hoc tool calling capability to models](/docs/how_to/tools_prompting)
- [How to: pass in runtime secrets](/docs/how_to/runnable_runtime_secrets)
- [How to: handle large numbers of tools](/docs/how_to/many_tools)
### Multimodal

View File

@@ -0,0 +1,268 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f05a0e81-372d-477e-a96b-95a9f217a6a4",
"metadata": {},
"source": [
"# How to handle large numbers of tools\n",
"\n",
":::info Prerequisites\n",
"\n",
"This guide assumes familiarity with the following concepts:\n",
"\n",
"- [Tools](/docs/concepts#tools)\n",
"- [Tool calling](/docs/concepts/#functiontool-calling)\n",
"- [Embeddings](/docs/concepts/#embedding-models) and [vector stores](/docs/concepts#vector-stores)\n",
"\n",
":::\n",
"\n",
"Tool calling allows a model to respond to a given prompt by generating output that matches a user-defined schema. Many LLM providers, including [Anthropic](https://www.anthropic.com/), [Cohere](https://cohere.com/), [Google](https://cloud.google.com/vertex-ai), [Mistral](https://mistral.ai/), [OpenAI](https://openai.com/), and others, support variants of a tool calling feature. These features typically allow requests to the LLM to include available tools and their schemas, and for responses to include calls to these tools.\n",
"\n",
"Importantly, the subset of available tools to call is generally at the discretion of the model (although many providers also enable the user to [specify or constrain the choice of tool](/docs/how_to/tool_choice)). As the number of available tools grows, you may want to limit the scope of the LLM's selection, to decrease token consumption and to help manage sources of error in LLM reasoning.\n",
"\n",
"Here we will demonstrate how to dynamically adjust the tools available to a model. Bottom line up front: like [RAG](/docs/tutorials/rag) and similar methods, we prefix the model invocation by retrieving over available tools. Although we demonstrate one implementation that searches over tool descriptions, the details of the tool selection can be customized as needed.\n",
"\n",
"**Note**: this guide uses [OpenAI](/docs/integrations/platforms/openai/) for embeddings, but any LangChain embeddings should suffice."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7be98fe-c8b7-4979-96db-f030469bce35",
"metadata": {},
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"%pip install -U langchain-core langchain-openai"
]
},
{
"cell_type": "markdown",
"id": "2ea8145f-c468-47c8-9f6a-693877d804fb",
"metadata": {},
"source": [
"We first instantiate a chat model that supports [tool calling](/docs/how_to/tool_calling/):\n",
"\n",
"```{=mdx}\n",
"import ChatModelTabs from \"@theme/ChatModelTabs\";\n",
"\n",
"<ChatModelTabs customVarName=\"llm\" />\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "e3595ba3-1c13-4a35-ab2a-14e433dbbe31",
"metadata": {},
"outputs": [],
"source": [
"# | output: false\n",
"# | echo: false\n",
"\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)"
]
},
{
"cell_type": "markdown",
"id": "84803177-44d6-4cb8-a7f3-16fd02500bc6",
"metadata": {},
"source": [
"Let's consider a toy example in which we have one tool for each company in the S&P 500 index. Each tool will fetch information, and is parameterized by a single integer representing the year.\n",
"\n",
"We first construct a registry that associates a unique identifier with a schema for each tool. We will represent the tools using JSON schema, which can be bound directly to [chat models supporting tool calling](/docs/integrations/chat/)."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "77cc23d3-9913-4159-8a14-ff7df3523440",
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"import uuid\n",
"\n",
"\n",
"def create_tool(company: str) -> dict:\n",
" \"\"\"Create schema for a placeholder tool.\"\"\"\n",
" formatted_company = re.sub(r\"[^\\w\\s]\", \"\", company).replace(\" \", \"_\")\n",
" return {\n",
" \"title\": f\"{formatted_company}_information\",\n",
" \"description\": f\"Information about {company}.\",\n",
" \"type\": \"object\",\n",
" \"properties\": {\"year\": {\"title\": \"year\", \"type\": \"integer\"}},\n",
" \"required\": [\"year\"],\n",
" }\n",
"\n",
"\n",
"s_and_p_500_companies = [ # Abbreviated list for demonstration purposes\n",
" \"3M\",\n",
" \"A.O. Smith\",\n",
" \"Abbott\",\n",
" \"Accenture\",\n",
" \"Advanced Micro Devices\",\n",
" \"Yum! Brands\",\n",
" \"Zebra Technologies\",\n",
" \"Zimmer Biomet\",\n",
" \"Zoetis\",\n",
"]\n",
"\n",
"tool_registry = {\n",
" str(uuid.uuid4()): create_tool(company) for company in s_and_p_500_companies\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "72c206b0-25e4-4034-999d-0a2442ff2c7b",
"metadata": {},
"source": [
"Next, we create a [vector store](/docs/how_to/vectorstores) that will store embeddings of the tool descriptions. This will allow a user query to be associated to a tool via semantic search. This is a simple solution, and in general the full scope of [retrieval solutions](/docs/concepts#retrieval) are available for this step."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "390d388f-3b5c-4fe0-bd77-f22c0391a2e3",
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.documents import Document\n",
"from langchain_core.vectorstores import InMemoryVectorStore, VectorStore\n",
"from langchain_openai import OpenAIEmbeddings\n",
"\n",
"tool_documents = [\n",
" Document(page_content=tool[\"description\"], id=id)\n",
" for id, tool in tool_registry.items()\n",
"]\n",
"\n",
"vector_store = InMemoryVectorStore(embedding=OpenAIEmbeddings())\n",
"upsert_response = vector_store.upsert(tool_documents)\n",
"assert not upsert_response[\"failed\"]"
]
},
{
"cell_type": "markdown",
"id": "0bd360a3-0a02-4661-87c6-b300e602573b",
"metadata": {},
"source": [
"Finally, we construct our [Runnable](/docs/concepts/#langchain-expression-language-lcel) as follows:\n",
"\n",
"- We create a `retrieve_tools` runnable that will return tools that are relevant to a user query;\n",
"- We create a `get_chat_model` runnable that will receive the query and tools, bind the tools to a chat model, and run it on the query.\n",
"\n",
"Note that here we leverage the fact that if a [RunnableLambda](/docs/how_to/functions/) returns an instance of Runnable, that instance is [called on its input](/docs/how_to/dynamic_chain). So `get_chat_model` only needs to construct the chat model for the chat model to be called on the input query."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "01bc976b-eede-4ab2-b924-6eb283732324",
"metadata": {},
"outputs": [],
"source": [
"from operator import itemgetter\n",
"from typing import List, Mapping\n",
"\n",
"from langchain_core.runnables import (\n",
" Runnable,\n",
" RunnableLambda,\n",
" RunnablePassthrough,\n",
")\n",
"\n",
"\n",
"async def _retrieve_tools(\n",
" input: dict,\n",
" vector_store: VectorStore,\n",
" tool_registry: Mapping[str, dict],\n",
") -> List[dict]:\n",
" query = input[\"query\"]\n",
" tool_documents = await vector_store.asimilarity_search(query)\n",
" return [tool_registry[document.id] for document in tool_documents]\n",
"\n",
"\n",
"async def _get_chat_model(input: dict) -> Runnable:\n",
" model = llm.bind_tools(input[\"tools\"])\n",
" return itemgetter(\"query\") | model\n",
"\n",
"\n",
"retrieve_tools = RunnableLambda(_retrieve_tools).bind(\n",
" vector_store=vector_store,\n",
" tool_registry=tool_registry,\n",
")\n",
"\n",
"get_chat_model = RunnableLambda(_get_chat_model)\n",
"\n",
"chain = RunnablePassthrough.assign(tools=retrieve_tools) | get_chat_model"
]
},
{
"cell_type": "markdown",
"id": "1bf3a0e4-25a5-4cc1-8899-4e93fbd1043d",
"metadata": {},
"source": [
"Invoking the chain, we see that the retriever step is able to recover an appropriate tool, and the LLM is able to translate the user's query into an invocation of the tool:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "cea1d8dc-05b9-46b6-b355-5749da1dd006",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'name': 'Advanced_Micro_Devices_information',\n",
" 'args': {'year': 2022},\n",
" 'id': 'call_jgQ4Hgt5Svw0YJ9dFpGYinzO',\n",
" 'type': 'tool_call'}]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response = await chain.ainvoke(\n",
" {\"query\": \"Can you give me some information about AMD in 2022?\"}\n",
")\n",
"response.tool_calls"
]
},
{
"cell_type": "markdown",
"id": "4a8e42bc-042a-4872-97c6-5e4e7195f2ac",
"metadata": {},
"source": [
"See [LangSmith trace](https://smith.langchain.com/public/0a298c50-1b88-4914-8007-db4c98a4d3e4/r) for the above run."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}