From 5fba0634ceebb3f776dd2b6ceb71f3bb18e1ffd8 Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Mon, 5 Aug 2024 17:15:53 -0700 Subject: [PATCH 1/2] Update Anthropic docs --- .../docs/integrations/chat/anthropic.ipynb | 537 ++++-------------- libs/langchain-anthropic/src/chat_models.ts | 5 +- 2 files changed, 113 insertions(+), 429 deletions(-) diff --git a/docs/core_docs/docs/integrations/chat/anthropic.ipynb b/docs/core_docs/docs/integrations/chat/anthropic.ipynb index 3aea237d0a3a..8233c1b7a952 100644 --- a/docs/core_docs/docs/integrations/chat/anthropic.ipynb +++ b/docs/core_docs/docs/integrations/chat/anthropic.ipynb @@ -21,7 +21,9 @@ "source": [ "# ChatAnthropic\n", "\n", - "This will help you getting started with ChatAnthropic [chat models](/docs/concepts/#chat-models). For detailed documentation of all ChatAnthropic features and configurations head to the [API reference](https://api.js.langchain.com/classes/langchain_anthropic.ChatAnthropic.html).\n", + "[Anthropic](https://www.anthropic.com/) is an AI safety and research company. They are the creator of Claude.\n", + "\n", + "This will help you getting started with Anthropic [chat models](/docs/concepts/#chat-models). For detailed documentation of all `ChatAnthropic` features and configurations head to the [API reference](https://api.js.langchain.com/classes/langchain_anthropic.ChatAnthropic.html).\n", "\n", "## Overview\n", "### Integration details\n", @@ -56,7 +58,7 @@ "\n", "### Installation\n", "\n", - "The LangChain ChatAnthropic integration lives in the `@langchain/anthropic` package:\n", + "The LangChain `ChatAnthropic` integration lives in the `@langchain/anthropic` package:\n", "\n", "```{=mdx}\n", "\n", @@ -97,7 +99,7 @@ " maxTokens: undefined,\n", " maxRetries: 2,\n", " // other params...\n", - "})" + "});" ] }, { @@ -336,11 +338,11 @@ "import { ChatAnthropic } from \"@langchain/anthropic\";\n", "import { HumanMessage } from \"@langchain/core/messages\";\n", "\n", - "const imageData2 = await fs.readFile(\"../../../../../examples/hotdog.jpg\");\n", + "const imageData = await fs.readFile(\"../../../../../examples/hotdog.jpg\");\n", "const llm2 = new ChatAnthropic({\n", " model: \"claude-3-sonnet-20240229\",\n", "});\n", - "const message2 = new HumanMessage({\n", + "const multimodalMessage = new HumanMessage({\n", " content: [\n", " {\n", " type: \"text\",\n", @@ -349,13 +351,13 @@ " {\n", " type: \"image_url\",\n", " image_url: {\n", - " url: `data:image/jpeg;base64,${imageData2.toString(\"base64\")}`,\n", + " url: `data:image/jpeg;base64,${imageData.toString(\"base64\")}`,\n", " },\n", " },\n", " ],\n", "});\n", "\n", - "await llm2.invoke([message2]);" + "await llm2.invoke([multimodalMessage]);" ] }, { @@ -374,12 +376,18 @@ "source": [ "## Agents\n", "\n", - "Anthropic models that support tool calling can be used in the Tool Calling agent. Here's an example:" + "Anthropic models can be used to power [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) agents:\n", + "\n", + "```{=mdx}\n", + "\n", + " @langchain/langgraph\n", + "\n", + "```" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 5, "id": "0648b504", "metadata": {}, "outputs": [ @@ -387,13 +395,41 @@ "name": "stdout", "output_type": "stream", "text": [ - "[\n", - " {\n", - " index: 0,\n", - " type: 'text',\n", - " text: '\\n\\nThe current weather in San Francisco, CA is 28°C.'\n", + "AIMessage {\n", + " \"id\": \"msg_01Y4nz4gM4LB57WHc3viGgRp\",\n", + " \"content\": \"The current weather in San Francisco, CA is 28°C.\",\n", + " \"additional_kwargs\": {\n", + " \"id\": \"msg_01Y4nz4gM4LB57WHc3viGgRp\",\n", + " \"type\": \"message\",\n", + " \"role\": \"assistant\",\n", + " \"model\": \"claude-3-sonnet-20240229\",\n", + " \"stop_reason\": \"end_turn\",\n", + " \"stop_sequence\": null,\n", + " \"usage\": {\n", + " \"input_tokens\": 364,\n", + " \"output_tokens\": 18\n", + " }\n", + " },\n", + " \"response_metadata\": {\n", + " \"id\": \"msg_01Y4nz4gM4LB57WHc3viGgRp\",\n", + " \"model\": \"claude-3-sonnet-20240229\",\n", + " \"stop_reason\": \"end_turn\",\n", + " \"stop_sequence\": null,\n", + " \"usage\": {\n", + " \"input_tokens\": 364,\n", + " \"output_tokens\": 18\n", + " },\n", + " \"type\": \"message\",\n", + " \"role\": \"assistant\"\n", + " },\n", + " \"tool_calls\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 364,\n", + " \"output_tokens\": 18,\n", + " \"total_tokens\": 382\n", " }\n", - "]\n" + "}\n" ] } ], @@ -402,24 +438,15 @@ "\n", "import { ChatAnthropic } from \"@langchain/anthropic\";\n", "import { tool } from \"@langchain/core/tools\";\n", - "import { AgentExecutor, createToolCallingAgent } from \"langchain/agents\";\n", - "\n", - "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", + "import { createReactAgent } from \"@langchain/langgraph/prebuilt\";\n", + "import { HumanMessage } from \"@langchain/core/messages\";\n", "\n", - "const llm3 = new ChatAnthropic({\n", + "const agentModel = new ChatAnthropic({\n", " model: \"claude-3-sonnet-20240229\",\n", " temperature: 0,\n", "});\n", "\n", - "// Prompt template must have \"input\" and \"agent_scratchpad input variables\"\n", - "const prompt3 = ChatPromptTemplate.fromMessages([\n", - " [\"system\", \"You are a helpful assistant\"],\n", - " [\"placeholder\", \"{chat_history}\"],\n", - " [\"human\", \"{input}\"],\n", - " [\"placeholder\", \"{agent_scratchpad}\"],\n", - "]);\n", - "\n", - "const currentWeatherTool3 = tool(async () => \"28 °C\", {\n", + "const currentWeatherTool = tool(async () => \"28 °C\", {\n", " name: \"get_current_weather\",\n", " description: \"Get the current weather in a given location\",\n", " schema: z.object({\n", @@ -427,21 +454,18 @@ " }),\n", "});\n", "\n", - "const agent3 = createToolCallingAgent({\n", - " llm: llm3,\n", - " tools: [currentWeatherTool3],\n", - " prompt: prompt3,\n", + "const agent = createReactAgent({\n", + " llm: agentModel,\n", + " tools: [currentWeatherTool],\n", "});\n", "\n", - "const agentExecutor3 = new AgentExecutor({\n", - " agent: agent3,\n", - " tools: [currentWeatherTool3],\n", + "const agentResult = await agent.invoke({\n", + " messages: [\n", + " new HumanMessage(\"What's the weather like in SF?\")\n", + " ]\n", "});\n", "\n", - "const input3 = \"What's the weather like in SF?\";\n", - "const result3 = await agentExecutor3.invoke({ input: input3 });\n", - "\n", - "console.log(result3.output);" + "console.log(agentResult.messages[agentResult.messages.length - 1]);" ] }, { @@ -456,7 +480,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 6, "id": "41943f0a", "metadata": {}, "outputs": [ @@ -465,10 +489,10 @@ "output_type": "stream", "text": [ "AIMessage {\n", - " \"id\": \"msg_013Ft3kN62gNtiMWRqg6xxt8\",\n", - " \"content\": \"The sky appears blue due to a phenomenon called Rayleigh scattering. Here's a brief explanation:\\n\\n1) Sunlight is made up of different wavelengths of light, including the visible spectrum that we see as colors.\\n\\n2) As sunlight passes through the Earth's atmosphere, the different wavelengths of light interact with the gas molecules in the air.\\n\\n3) The shorter wavelengths of light, such as the blue and violet colors, get scattered more easily by the tiny gas molecules. This is because the wavelengths are similar in size to the molecules.\\n\\n4) The longer wavelengths of light, such as red and orange, get scattered much less by the gas molecules and travel more directly through the atmosphere.\\n\\n5) The blue wavelengths that are scattered in different directions become scattered across the entire sky, making the sky appear blue to our eyes.\\n\\n6) During sunrise and sunset, the sun's rays travel through more atmosphere before reaching our eyes, causing the blue light to get scattered away and allowing more of the red/orange wavelengths to pass through, giving those colors in the sky.\\n\\nSo in essence, the abundant scattering of blue light by the gas molecules in the atmosphere is what causes the sky to appear blue during the daytime.\",\n", + " \"id\": \"msg_0131WctMyzmv4myNQeuAituP\",\n", + " \"content\": \"The sky appears blue because of the way sunlight interacts with the Earth's atmosphere. Here's a more detailed explanation:\\n\\n- Sunlight is made up of different wavelengths of light, including all the colors of the visible spectrum (red, orange, yellow, green, blue, indigo, violet).\\n\\n- As sunlight passes through the atmosphere, it encounters tiny molecules of oxygen and nitrogen in the air.\\n\\n- These gas molecules are very effective at scattering and deflecting the shorter wavelengths of light, which correspond to the colors in the blue and violet range of the spectrum.\\n\\n- The longer wavelengths of light (reds, oranges) are able to travel more directly through the atmosphere without getting scattered as much.\\n\\n- The scattered blue wavelengths of light get deflected in all directions by the atmospheric gases. This blue light gets scattered about everywhere in the sky, making the sky appear blue from the ground.\\n\\n- The effect is more pronounced with a clear sky during the daytime when more sunlight is entering the atmosphere.\\n\\nSo in essence, the blueness of the sky is caused by the preferable scattering of blue wavelengths of light by the tiny gas molecules present in the Earth's atmosphere.\",\n", " \"additional_kwargs\": {\n", - " \"id\": \"msg_013Ft3kN62gNtiMWRqg6xxt8\",\n", + " \"id\": \"msg_0131WctMyzmv4myNQeuAituP\",\n", " \"type\": \"message\",\n", " \"role\": \"assistant\",\n", " \"model\": \"claude-3-sonnet-20240229\",\n", @@ -476,17 +500,17 @@ " \"stop_sequence\": null,\n", " \"usage\": {\n", " \"input_tokens\": 13,\n", - " \"output_tokens\": 272\n", + " \"output_tokens\": 263\n", " }\n", " },\n", " \"response_metadata\": {\n", - " \"id\": \"msg_013Ft3kN62gNtiMWRqg6xxt8\",\n", + " \"id\": \"msg_0131WctMyzmv4myNQeuAituP\",\n", " \"model\": \"claude-3-sonnet-20240229\",\n", " \"stop_reason\": \"end_turn\",\n", " \"stop_sequence\": null,\n", " \"usage\": {\n", " \"input_tokens\": 13,\n", - " \"output_tokens\": 272\n", + " \"output_tokens\": 263\n", " },\n", " \"type\": \"message\",\n", " \"role\": \"assistant\"\n", @@ -495,8 +519,8 @@ " \"invalid_tool_calls\": [],\n", " \"usage_metadata\": {\n", " \"input_tokens\": 13,\n", - " \"output_tokens\": 272,\n", - " \"total_tokens\": 285\n", + " \"output_tokens\": 263,\n", + " \"total_tokens\": 276\n", " }\n", "}\n" ] @@ -505,7 +529,7 @@ "source": [ "import { ChatAnthropic } from \"@langchain/anthropic\";\n", "\n", - "const llm4 = new ChatAnthropic({\n", + "const llmWithCustomHeaders = new ChatAnthropic({\n", " model: \"claude-3-sonnet-20240229\",\n", " maxTokens: 1024,\n", " clientOptions: {\n", @@ -515,9 +539,7 @@ " },\n", "});\n", "\n", - "const res4 = await llm4.invoke(\"Why is the sky blue?\");\n", - "\n", - "console.log(res4);" + "await llmWithCustomHeaders.invoke(\"Why is the sky blue?\");" ] }, { @@ -527,14 +549,12 @@ "source": [ "## Tools\n", "\n", - "The Anthropic API supports tool calling, along with multi-tool calling. The following examples demonstrate how to call tools:\n", - "\n", - "### Single Tool" + "The following example demonstrates [how to call tools](/docs/how_to/tool_calling) with Anthropic models:" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 9, "id": "2ce56548", "metadata": {}, "outputs": [ @@ -542,67 +562,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "AIMessage {\n", - " \"id\": \"msg_01XPUHrR4sNCqPr1i9zcsAsg\",\n", - " \"content\": [\n", - " {\n", - " \"type\": \"text\",\n", - " \"text\": \"Okay, let me use the calculator tool to find the answer:\"\n", - " },\n", - " {\n", - " \"type\": \"tool_use\",\n", - " \"id\": \"toolu_01MhUVuUedc1drBKLarhedFZ\",\n", - " \"name\": \"calculator\",\n", - " \"input\": {\n", - " \"number1\": 2,\n", - " \"number2\": 2,\n", - " \"operation\": \"add\"\n", - " }\n", - " }\n", - " ],\n", - " \"additional_kwargs\": {\n", - " \"id\": \"msg_01XPUHrR4sNCqPr1i9zcsAsg\",\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\",\n", - " \"model\": \"claude-3-haiku-20240307\",\n", - " \"stop_reason\": \"tool_use\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 449,\n", - " \"output_tokens\": 101\n", - " }\n", - " },\n", - " \"response_metadata\": {\n", - " \"id\": \"msg_01XPUHrR4sNCqPr1i9zcsAsg\",\n", - " \"model\": \"claude-3-haiku-20240307\",\n", - " \"stop_reason\": \"tool_use\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 449,\n", - " \"output_tokens\": 101\n", - " },\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\"\n", - " },\n", - " \"tool_calls\": [\n", - " {\n", - " \"name\": \"calculator\",\n", - " \"args\": {\n", - " \"number1\": 2,\n", - " \"number2\": 2,\n", - " \"operation\": \"add\"\n", - " },\n", - " \"id\": \"toolu_01MhUVuUedc1drBKLarhedFZ\",\n", - " \"type\": \"tool_call\"\n", - " }\n", - " ],\n", - " \"invalid_tool_calls\": [],\n", - " \"usage_metadata\": {\n", - " \"input_tokens\": 449,\n", - " \"output_tokens\": 101,\n", - " \"total_tokens\": 550\n", + "[\n", + " {\n", + " name: 'calculator',\n", + " args: { number1: 2, number2: 2, operation: 'add' },\n", + " id: 'toolu_01Wjh2R15J945ErnGQ79UrpA',\n", + " type: 'tool_call'\n", " }\n", - "}\n" + "]\n" ] } ], @@ -610,9 +577,8 @@ "import { ChatAnthropic } from \"@langchain/anthropic\";\n", "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", "import { z } from \"zod\";\n", - "import { zodToJsonSchema } from \"zod-to-json-schema\";\n", "\n", - "const calculatorSchema5 = z.object({\n", + "const calculatorSchema = z.object({\n", " operation: z\n", " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", " .describe(\"The type of operation to execute.\"),\n", @@ -620,20 +586,17 @@ " number2: z.number().describe(\"The second number to operate on.\"),\n", "});\n", "\n", - "const tool5 = {\n", + "const calculatorTool = {\n", " name: \"calculator\",\n", " description: \"A simple calculator tool\",\n", - " input_schema: zodToJsonSchema(calculatorSchema5),\n", + " input_schema: zodToJsonSchema(calculatorSchema),\n", "};\n", "\n", - "const llm5 = new ChatAnthropic({\n", - " apiKey: process.env.ANTHROPIC_API_KEY,\n", + "const toolCallingLlm = new ChatAnthropic({\n", " model: \"claude-3-haiku-20240307\",\n", - "}).bind({\n", - " tools: [tool5],\n", - "});\n", + "}).bindTools([calculatorTool]);\n", "\n", - "const prompt5 = ChatPromptTemplate.fromMessages([\n", + "const toolPrompt = ChatPromptTemplate.fromMessages([\n", " [\n", " \"system\",\n", " \"You are a helpful assistant who always needs to use a calculator.\",\n", @@ -642,182 +605,13 @@ "]);\n", "\n", "// Chain your prompt and model together\n", - "const chain5 = prompt5.pipe(llm5);\n", + "const toolCallChain = toolPrompt.pipe(toolCallingLlm);\n", "\n", - "const response5 = await chain5.invoke({\n", + "const toolResponse = await toolCallChain.invoke({\n", " input: \"What is 2 + 2?\",\n", "});\n", - "console.log(response5);" - ] - }, - { - "cell_type": "markdown", - "id": "6e91f97b", - "metadata": {}, - "source": [ - "### Forced tool calling\n", - "\n", - "In this example we'll provide the model with two tools:\n", - "\n", - "- `calculator`\n", - "- `get_weather`\n", - "\n", - "Then, when we call `bindTools`, we'll force the model to use the `get_weather` tool by passing the `tool_choice` arg like this:\n", - "\n", - "```typescript\n", - ".bindTools({\n", - " tools,\n", - " tool_choice: {\n", - " type: \"tool\",\n", - " name: \"get_weather\",\n", - " }\n", - "});\n", - "```\n", - "\n", - "Finally, we'll invoke the model, but instead of asking about the weather, we'll ask it to do some math.\n", - "Since we explicitly forced the model to use the `get_weather` tool, it will ignore the input and return the weather information (in this case it returned ``, which is expected.)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "8d6e4828", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "AIMessage {\n", - " \"id\": \"msg_018G4mEZu8KNKtaQxZQ3o8YB\",\n", - " \"content\": [\n", - " {\n", - " \"type\": \"tool_use\",\n", - " \"id\": \"toolu_01DS9RwsFKdhHNYmhwPJHdHa\",\n", - " \"name\": \"get_weather\",\n", - " \"input\": {\n", - " \"city\": \"\",\n", - " \"state\": \"\"\n", - " }\n", - " }\n", - " ],\n", - " \"additional_kwargs\": {\n", - " \"id\": \"msg_018G4mEZu8KNKtaQxZQ3o8YB\",\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\",\n", - " \"model\": \"claude-3-haiku-20240307\",\n", - " \"stop_reason\": \"tool_use\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 672,\n", - " \"output_tokens\": 51\n", - " }\n", - " },\n", - " \"response_metadata\": {\n", - " \"id\": \"msg_018G4mEZu8KNKtaQxZQ3o8YB\",\n", - " \"model\": \"claude-3-haiku-20240307\",\n", - " \"stop_reason\": \"tool_use\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 672,\n", - " \"output_tokens\": 51\n", - " },\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\"\n", - " },\n", - " \"tool_calls\": [\n", - " {\n", - " \"name\": \"get_weather\",\n", - " \"args\": {\n", - " \"city\": \"\",\n", - " \"state\": \"\"\n", - " },\n", - " \"id\": \"toolu_01DS9RwsFKdhHNYmhwPJHdHa\",\n", - " \"type\": \"tool_call\"\n", - " }\n", - " ],\n", - " \"invalid_tool_calls\": [],\n", - " \"usage_metadata\": {\n", - " \"input_tokens\": 672,\n", - " \"output_tokens\": 51,\n", - " \"total_tokens\": 723\n", - " }\n", - "}\n" - ] - } - ], - "source": [ - "import { ChatAnthropic } from \"@langchain/anthropic\";\n", - "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", - "import { z } from \"zod\";\n", - "import { zodToJsonSchema } from \"zod-to-json-schema\";\n", - "\n", - "const calculatorSchema6 = z.object({\n", - " operation: z\n", - " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", - " .describe(\"The type of operation to execute.\"),\n", - " number1: z.number().describe(\"The first number to operate on.\"),\n", - " number2: z.number().describe(\"The second number to operate on.\"),\n", - "});\n", - "\n", - "const weatherSchema6 = z.object({\n", - " city: z.string().describe(\"The city to get the weather from\"),\n", - " state: z.string().optional().describe(\"The state to get the weather from\"),\n", - "});\n", - "\n", - "const tools6 = [\n", - " {\n", - " name: \"calculator\",\n", - " description: \"A simple calculator tool\",\n", - " input_schema: zodToJsonSchema(calculatorSchema6),\n", - " },\n", - " {\n", - " name: \"get_weather\",\n", - " description:\n", - " \"Get the weather of a specific location and return the temperature in Celsius.\",\n", - " input_schema: zodToJsonSchema(weatherSchema6),\n", - " },\n", - "];\n", - "\n", - "const llm6 = new ChatAnthropic({\n", - " apiKey: process.env.ANTHROPIC_API_KEY,\n", - " model: \"claude-3-haiku-20240307\",\n", - "}).bind({\n", - " tools: tools6,\n", - " tool_choice: {\n", - " type: \"tool\",\n", - " name: \"get_weather\",\n", - " },\n", - "});\n", - "\n", - "const prompt6 = ChatPromptTemplate.fromMessages([\n", - " [\n", - " \"system\",\n", - " \"You are a helpful assistant who always needs to use a calculator.\",\n", - " ],\n", - " [\"human\", \"{input}\"],\n", - "]);\n", - "\n", - "// Chain your prompt and model together\n", - "const chain6 = prompt6.pipe(llm6);\n", - "\n", - "const response6 = await chain6.invoke({\n", - " input: \"What is the sum of 2725 and 273639\",\n", - "});\n", "\n", - "console.log(response6);" - ] - }, - { - "cell_type": "markdown", - "id": "1aa777bc", - "metadata": {}, - "source": [ - "The `tool_choice` argument has three possible values:\n", - "\n", - "- `{ type: \"tool\", name: \"tool_name\" }` | `string` - Forces the model to use the specified tool. If passing a single string, it will be treated as the tool name.\n", - "- `\"any\"` - Allows the model to choose the tool, but still forcing it to choose at least one.\n", - "- `\"auto\"` - The default value. Allows the model to select any tool, or none." + "toolResponse.tool_calls;" ] }, { @@ -825,12 +619,14 @@ "id": "15253085", "metadata": {}, "source": [ - "### `withStructuredOutput`" + "### `withStructuredOutput`\n", + "\n", + "If you just need to get structured output from the model, Anthropic models support the [`.withStructuredOutput()`](/docs/how_to/structured_output/#the-.withstructuredoutput-method) method:" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 12, "id": "5e466d35", "metadata": {}, "outputs": [ @@ -838,143 +634,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "{ operation: 'add', number1: 2, number2: 2 }\n" + "{\n", + " setup: \"Why don't cats play poker in the jungle?\",\n", + " punchline: 'Too many cheetahs!',\n", + " rating: 7\n", + "}\n" ] } ], "source": [ - "import { ChatAnthropic } from \"@langchain/anthropic\";\n", - "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", "import { z } from \"zod\";\n", "\n", - "const calculatorSchema7 = z\n", - " .object({\n", - " operation: z\n", - " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", - " .describe(\"The type of operation to execute.\"),\n", - " number1: z.number().describe(\"The first number to operate on.\"),\n", - " number2: z.number().describe(\"The second number to operate on.\"),\n", - " })\n", - " .describe(\"A simple calculator tool\");\n", - "\n", - "const llm7 = new ChatAnthropic({\n", - " apiKey: process.env.ANTHROPIC_API_KEY,\n", - " model: \"claude-3-haiku-20240307\",\n", + "const joke = z.object({\n", + " setup: z.string().describe(\"The setup of the joke\"),\n", + " punchline: z.string().describe(\"The punchline to the joke\"),\n", + " rating: z.number().optional().describe(\"How funny the joke is, from 1 to 10\"),\n", "});\n", "\n", - "// Pass the schema and tool name to the withStructuredOutput method\n", - "const modelWithTool7 = llm7.withStructuredOutput(calculatorSchema7);\n", - "\n", - "const prompt7 = ChatPromptTemplate.fromMessages([\n", - " [\n", - " \"system\",\n", - " \"You are a helpful assistant who always needs to use a calculator.\",\n", - " ],\n", - " [\"human\", \"{input}\"],\n", - "]);\n", - "\n", - "// Chain your prompt and model together\n", - "const chain7 = prompt7.pipe(modelWithTool7);\n", - "\n", - "const response7 = await chain7.invoke({\n", - " input: \"What is 2 + 2?\",\n", - "});\n", - "console.log(response7);" - ] - }, - { - "cell_type": "markdown", - "id": "4973b265", - "metadata": {}, - "source": [ - "You can supply a \"name\" field to give the LLM additional context around what you are trying to generate. You can also pass `includeRaw` to get the raw message back from the model too." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "951c5352", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " raw: AIMessage {\n", - " \"id\": \"msg_01TrkHbEkioCYNHQhqxw5unu\",\n", - " \"content\": [\n", - " {\n", - " \"type\": \"tool_use\",\n", - " \"id\": \"toolu_01XMrGHXeSVTfSw1oKFZokzG\",\n", - " \"name\": \"calculator\",\n", - " \"input\": {\n", - " \"number1\": 2,\n", - " \"number2\": 2,\n", - " \"operation\": \"add\"\n", - " }\n", - " }\n", - " ],\n", - " \"additional_kwargs\": {\n", - " \"id\": \"msg_01TrkHbEkioCYNHQhqxw5unu\",\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\",\n", - " \"model\": \"claude-3-haiku-20240307\",\n", - " \"stop_reason\": \"tool_use\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 552,\n", - " \"output_tokens\": 69\n", - " }\n", - " },\n", - " \"response_metadata\": {\n", - " \"id\": \"msg_01TrkHbEkioCYNHQhqxw5unu\",\n", - " \"model\": \"claude-3-haiku-20240307\",\n", - " \"stop_reason\": \"tool_use\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 552,\n", - " \"output_tokens\": 69\n", - " },\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\"\n", - " },\n", - " \"tool_calls\": [\n", - " {\n", - " \"name\": \"calculator\",\n", - " \"args\": {\n", - " \"number1\": 2,\n", - " \"number2\": 2,\n", - " \"operation\": \"add\"\n", - " },\n", - " \"id\": \"toolu_01XMrGHXeSVTfSw1oKFZokzG\",\n", - " \"type\": \"tool_call\"\n", - " }\n", - " ],\n", - " \"invalid_tool_calls\": [],\n", - " \"usage_metadata\": {\n", - " \"input_tokens\": 552,\n", - " \"output_tokens\": 69,\n", - " \"total_tokens\": 621\n", - " }\n", - " },\n", - " parsed: { operation: 'add', number1: 2, number2: 2 }\n", - "}\n" - ] - } - ], - "source": [ - "const includeRawModel7 = llm7.withStructuredOutput(calculatorSchema7, {\n", - " name: \"calculator\",\n", - " includeRaw: true,\n", - "});\n", - "const includeRawChain7 = prompt7.pipe(includeRawModel7);\n", + "const modelForStructuredOutput = new ChatAnthropic({\n", + " model: \"claude-3-haiku-20240307\",\n", + "})\n", "\n", - "const includeRawResponse7 = await includeRawChain7.invoke({\n", - " input: \"What is 2 + 2?\",\n", - "});\n", + "const structuredLlm = modelForStructuredOutput.withStructuredOutput(joke);\n", "\n", - "console.log(includeRawResponse7);" + "await structuredLlm.invoke(\"Tell me a joke about cats\");" ] }, { diff --git a/libs/langchain-anthropic/src/chat_models.ts b/libs/langchain-anthropic/src/chat_models.ts index e4b6f37ef856..e3521e7dc5e2 100644 --- a/libs/langchain-anthropic/src/chat_models.ts +++ b/libs/langchain-anthropic/src/chat_models.ts @@ -182,8 +182,9 @@ function extractToken(chunk: AIMessageChunk): string | undefined { /** * Wrapper around Anthropic large language models. * - * To use you should have the `@anthropic-ai/sdk` package installed, with the - * `ANTHROPIC_API_KEY` environment variable set. + * To use this package, you should have an Anthropic API key set as an + * environment variable named `ANTHROPIC_API_KEY` or passed + * into the constructor. * * @remarks * Any parameters that are valid to be passed to {@link From f3c1e93f29613307ed3c7c85ec756edb604cf99f Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Mon, 5 Aug 2024 17:24:55 -0700 Subject: [PATCH 2/2] Simplify --- .../docs/integrations/chat/anthropic.ipynb | 378 +++++------------- 1 file changed, 94 insertions(+), 284 deletions(-) diff --git a/docs/core_docs/docs/integrations/chat/anthropic.ipynb b/docs/core_docs/docs/integrations/chat/anthropic.ipynb index 8233c1b7a952..b3fce19f740f 100644 --- a/docs/core_docs/docs/integrations/chat/anthropic.ipynb +++ b/docs/core_docs/docs/integrations/chat/anthropic.ipynb @@ -86,7 +86,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "cb09c344-1836-4e0c-acf8-11d13ac1dbae", "metadata": {}, "outputs": [], @@ -112,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "62e0dbc3", "metadata": { "tags": [] @@ -123,10 +123,10 @@ "output_type": "stream", "text": [ "AIMessage {\n", - " \"id\": \"msg_01M9yt3aSqKJKM1RnZF4f44Q\",\n", + " \"id\": \"msg_013WBXXiggy6gMbAUY6NpsuU\",\n", " \"content\": \"Voici la traduction en français :\\n\\nJ'adore la programmation.\",\n", " \"additional_kwargs\": {\n", - " \"id\": \"msg_01M9yt3aSqKJKM1RnZF4f44Q\",\n", + " \"id\": \"msg_013WBXXiggy6gMbAUY6NpsuU\",\n", " \"type\": \"message\",\n", " \"role\": \"assistant\",\n", " \"model\": \"claude-3-haiku-20240307\",\n", @@ -138,7 +138,7 @@ " }\n", " },\n", " \"response_metadata\": {\n", - " \"id\": \"msg_01M9yt3aSqKJKM1RnZF4f44Q\",\n", + " \"id\": \"msg_013WBXXiggy6gMbAUY6NpsuU\",\n", " \"model\": \"claude-3-haiku-20240307\",\n", " \"stop_reason\": \"end_turn\",\n", " \"stop_sequence\": null,\n", @@ -173,7 +173,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "d86145b3-bfef-46e8-b227-4dda5c9c2705", "metadata": {}, "outputs": [ @@ -203,7 +203,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "id": "e197d1d7-a070-4c96-9f8a-a0e86d046e0b", "metadata": {}, "outputs": [ @@ -212,10 +212,10 @@ "output_type": "stream", "text": [ "AIMessage {\n", - " \"id\": \"msg_012gUKUG65teaois31W3bfGF\",\n", + " \"id\": \"msg_01Ca52fpd1mcGRhH4spzAWr4\",\n", " \"content\": \"Ich liebe das Programmieren.\",\n", " \"additional_kwargs\": {\n", - " \"id\": \"msg_012gUKUG65teaois31W3bfGF\",\n", + " \"id\": \"msg_01Ca52fpd1mcGRhH4spzAWr4\",\n", " \"type\": \"message\",\n", " \"role\": \"assistant\",\n", " \"model\": \"claude-3-haiku-20240307\",\n", @@ -227,7 +227,7 @@ " }\n", " },\n", " \"response_metadata\": {\n", - " \"id\": \"msg_012gUKUG65teaois31W3bfGF\",\n", + " \"id\": \"msg_01Ca52fpd1mcGRhH4spzAWr4\",\n", " \"model\": \"claude-3-haiku-20240307\",\n", " \"stop_reason\": \"end_turn\",\n", " \"stop_sequence\": null,\n", @@ -274,121 +274,18 @@ }, { "cell_type": "markdown", - "id": "d1ee55bc-ffc8-4cfa-801c-993953a08cfd", + "id": "8dac39db", "metadata": {}, "source": [ - "## Multimodal inputs\n", + "## Content blocks\n", "\n", - "Claude-3 models support image multimodal inputs. The passed input must be a base64 encoded image with the\n", - "filetype as a prefix (e.g. `data:image/png;base64,{YOUR_BASE64_ENCODED_DATA}`).\n", - "Here's an example:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "1cb65e95", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "AIMessage {\n", - " \"id\": \"msg_01AuGpm6xbacTwoUFdNiCnzu\",\n", - " \"content\": \"The image shows a hot dog. It consists of a cylindrical bread roll or bun that has been sliced lengthwise, revealing the bright red hot dog sausage filling inside. The hot dog sausage appears to be made from seasoned and smoked meat. This classic fast food item is a popular snack or meal, commonly enjoyed at sporting events, cookouts, and casual eateries.\",\n", - " \"additional_kwargs\": {\n", - " \"id\": \"msg_01AuGpm6xbacTwoUFdNiCnzu\",\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\",\n", - " \"model\": \"claude-3-sonnet-20240229\",\n", - " \"stop_reason\": \"end_turn\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 276,\n", - " \"output_tokens\": 88\n", - " }\n", - " },\n", - " \"response_metadata\": {\n", - " \"id\": \"msg_01AuGpm6xbacTwoUFdNiCnzu\",\n", - " \"model\": \"claude-3-sonnet-20240229\",\n", - " \"stop_reason\": \"end_turn\",\n", - " \"stop_sequence\": null,\n", - " \"usage\": {\n", - " \"input_tokens\": 276,\n", - " \"output_tokens\": 88\n", - " },\n", - " \"type\": \"message\",\n", - " \"role\": \"assistant\"\n", - " },\n", - " \"tool_calls\": [],\n", - " \"invalid_tool_calls\": [],\n", - " \"usage_metadata\": {\n", - " \"input_tokens\": 276,\n", - " \"output_tokens\": 88,\n", - " \"total_tokens\": 364\n", - " }\n", - "}\n" - ] - } - ], - "source": [ - "import fs from \"fs/promises\";\n", - "\n", - "import { ChatAnthropic } from \"@langchain/anthropic\";\n", - "import { HumanMessage } from \"@langchain/core/messages\";\n", - "\n", - "const imageData = await fs.readFile(\"../../../../../examples/hotdog.jpg\");\n", - "const llm2 = new ChatAnthropic({\n", - " model: \"claude-3-sonnet-20240229\",\n", - "});\n", - "const multimodalMessage = new HumanMessage({\n", - " content: [\n", - " {\n", - " type: \"text\",\n", - " text: \"What's in this image?\",\n", - " },\n", - " {\n", - " type: \"image_url\",\n", - " image_url: {\n", - " url: `data:image/jpeg;base64,${imageData.toString(\"base64\")}`,\n", - " },\n", - " },\n", - " ],\n", - "});\n", - "\n", - "await llm2.invoke([multimodalMessage]);" - ] - }, - { - "cell_type": "markdown", - "id": "5c14fbc0", - "metadata": {}, - "source": [ - "See [the official docs](https://docs.anthropic.com/claude/docs/vision#what-image-file-types-does-claude-support)\n", - "for a complete list of supported file types." - ] - }, - { - "cell_type": "markdown", - "id": "9bce78a1", - "metadata": {}, - "source": [ - "## Agents\n", - "\n", - "Anthropic models can be used to power [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) agents:\n", - "\n", - "```{=mdx}\n", - "\n", - " @langchain/langgraph\n", - "\n", - "```" + "One key difference to note between Anthropic models and most others is that the contents of a single Anthropic AI message can either be a single string or a **list of content blocks**. For example when an Anthropic model [calls a tool](/docs/how_to/tool_calling), the tool invocation is part of the message content (as well as being exposed in the standardized `AIMessage.tool_calls` field):" ] }, { "cell_type": "code", "execution_count": 5, - "id": "0648b504", + "id": "f5994de0", "metadata": {}, "outputs": [ { @@ -396,76 +293,107 @@ "output_type": "stream", "text": [ "AIMessage {\n", - " \"id\": \"msg_01Y4nz4gM4LB57WHc3viGgRp\",\n", - " \"content\": \"The current weather in San Francisco, CA is 28°C.\",\n", + " \"id\": \"msg_01DZGs9DyuashaYxJ4WWpWUP\",\n", + " \"content\": [\n", + " {\n", + " \"type\": \"text\",\n", + " \"text\": \"Here is the calculation for 2 + 2:\"\n", + " },\n", + " {\n", + " \"type\": \"tool_use\",\n", + " \"id\": \"toolu_01SQXBamkBr6K6NdHE7GWwF8\",\n", + " \"name\": \"calculator\",\n", + " \"input\": {\n", + " \"number1\": 2,\n", + " \"number2\": 2,\n", + " \"operation\": \"add\"\n", + " }\n", + " }\n", + " ],\n", " \"additional_kwargs\": {\n", - " \"id\": \"msg_01Y4nz4gM4LB57WHc3viGgRp\",\n", + " \"id\": \"msg_01DZGs9DyuashaYxJ4WWpWUP\",\n", " \"type\": \"message\",\n", " \"role\": \"assistant\",\n", - " \"model\": \"claude-3-sonnet-20240229\",\n", - " \"stop_reason\": \"end_turn\",\n", + " \"model\": \"claude-3-haiku-20240307\",\n", + " \"stop_reason\": \"tool_use\",\n", " \"stop_sequence\": null,\n", " \"usage\": {\n", - " \"input_tokens\": 364,\n", - " \"output_tokens\": 18\n", + " \"input_tokens\": 449,\n", + " \"output_tokens\": 100\n", " }\n", " },\n", " \"response_metadata\": {\n", - " \"id\": \"msg_01Y4nz4gM4LB57WHc3viGgRp\",\n", - " \"model\": \"claude-3-sonnet-20240229\",\n", - " \"stop_reason\": \"end_turn\",\n", + " \"id\": \"msg_01DZGs9DyuashaYxJ4WWpWUP\",\n", + " \"model\": \"claude-3-haiku-20240307\",\n", + " \"stop_reason\": \"tool_use\",\n", " \"stop_sequence\": null,\n", " \"usage\": {\n", - " \"input_tokens\": 364,\n", - " \"output_tokens\": 18\n", + " \"input_tokens\": 449,\n", + " \"output_tokens\": 100\n", " },\n", " \"type\": \"message\",\n", " \"role\": \"assistant\"\n", " },\n", - " \"tool_calls\": [],\n", + " \"tool_calls\": [\n", + " {\n", + " \"name\": \"calculator\",\n", + " \"args\": {\n", + " \"number1\": 2,\n", + " \"number2\": 2,\n", + " \"operation\": \"add\"\n", + " },\n", + " \"id\": \"toolu_01SQXBamkBr6K6NdHE7GWwF8\",\n", + " \"type\": \"tool_call\"\n", + " }\n", + " ],\n", " \"invalid_tool_calls\": [],\n", " \"usage_metadata\": {\n", - " \"input_tokens\": 364,\n", - " \"output_tokens\": 18,\n", - " \"total_tokens\": 382\n", + " \"input_tokens\": 449,\n", + " \"output_tokens\": 100,\n", + " \"total_tokens\": 549\n", " }\n", "}\n" ] } ], "source": [ - "import { z } from \"zod\";\n", - "\n", "import { ChatAnthropic } from \"@langchain/anthropic\";\n", - "import { tool } from \"@langchain/core/tools\";\n", - "import { createReactAgent } from \"@langchain/langgraph/prebuilt\";\n", - "import { HumanMessage } from \"@langchain/core/messages\";\n", + "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", + "import { z } from \"zod\";\n", + "import { zodToJsonSchema } from \"zod-to-json-schema\";\n", "\n", - "const agentModel = new ChatAnthropic({\n", - " model: \"claude-3-sonnet-20240229\",\n", - " temperature: 0,\n", + "const calculatorSchema = z.object({\n", + " operation: z\n", + " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", + " .describe(\"The type of operation to execute.\"),\n", + " number1: z.number().describe(\"The first number to operate on.\"),\n", + " number2: z.number().describe(\"The second number to operate on.\"),\n", "});\n", "\n", - "const currentWeatherTool = tool(async () => \"28 °C\", {\n", - " name: \"get_current_weather\",\n", - " description: \"Get the current weather in a given location\",\n", - " schema: z.object({\n", - " location: z.string().describe(\"The city and state, e.g. San Francisco, CA\"),\n", - " }),\n", - "});\n", + "const calculatorTool = {\n", + " name: \"calculator\",\n", + " description: \"A simple calculator tool\",\n", + " input_schema: zodToJsonSchema(calculatorSchema),\n", + "};\n", "\n", - "const agent = createReactAgent({\n", - " llm: agentModel,\n", - " tools: [currentWeatherTool],\n", - "});\n", + "const toolCallingLlm = new ChatAnthropic({\n", + " model: \"claude-3-haiku-20240307\",\n", + "}).bindTools([calculatorTool]);\n", "\n", - "const agentResult = await agent.invoke({\n", - " messages: [\n", - " new HumanMessage(\"What's the weather like in SF?\")\n", - " ]\n", - "});\n", + "const toolPrompt = ChatPromptTemplate.fromMessages([\n", + " [\n", + " \"system\",\n", + " \"You are a helpful assistant who always needs to use a calculator.\",\n", + " ],\n", + " [\"human\", \"{input}\"],\n", + "]);\n", + "\n", + "// Chain your prompt and model together\n", + "const toolCallChain = toolPrompt.pipe(toolCallingLlm);\n", "\n", - "console.log(agentResult.messages[agentResult.messages.length - 1]);" + "await toolCallChain.invoke({\n", + " input: \"What is 2 + 2?\",\n", + "});" ] }, { @@ -489,10 +417,10 @@ "output_type": "stream", "text": [ "AIMessage {\n", - " \"id\": \"msg_0131WctMyzmv4myNQeuAituP\",\n", - " \"content\": \"The sky appears blue because of the way sunlight interacts with the Earth's atmosphere. Here's a more detailed explanation:\\n\\n- Sunlight is made up of different wavelengths of light, including all the colors of the visible spectrum (red, orange, yellow, green, blue, indigo, violet).\\n\\n- As sunlight passes through the atmosphere, it encounters tiny molecules of oxygen and nitrogen in the air.\\n\\n- These gas molecules are very effective at scattering and deflecting the shorter wavelengths of light, which correspond to the colors in the blue and violet range of the spectrum.\\n\\n- The longer wavelengths of light (reds, oranges) are able to travel more directly through the atmosphere without getting scattered as much.\\n\\n- The scattered blue wavelengths of light get deflected in all directions by the atmospheric gases. This blue light gets scattered about everywhere in the sky, making the sky appear blue from the ground.\\n\\n- The effect is more pronounced with a clear sky during the daytime when more sunlight is entering the atmosphere.\\n\\nSo in essence, the blueness of the sky is caused by the preferable scattering of blue wavelengths of light by the tiny gas molecules present in the Earth's atmosphere.\",\n", + " \"id\": \"msg_019z4nWpShzsrbSHTWXWQh6z\",\n", + " \"content\": \"The sky appears blue due to a phenomenon called Rayleigh scattering. Here's a brief explanation:\\n\\n1) Sunlight is made up of different wavelengths of visible light, including all the colors of the rainbow.\\n\\n2) As sunlight passes through the atmosphere, the gases (mostly nitrogen and oxygen) cause the shorter wavelengths of light, such as violet and blue, to be scattered more easily than the longer wavelengths like red and orange.\\n\\n3) This scattering of the shorter blue wavelengths occurs in all directions by the gas molecules in the atmosphere.\\n\\n4) Our eyes are more sensitive to the scattered blue light than the scattered violet light, so we perceive the sky as having a blue color.\\n\\n5) The scattering is more pronounced for light traveling over longer distances through the atmosphere. This is why the sky appears even darker blue when looking towards the horizon.\\n\\nSo in essence, the selective scattering of the shorter blue wavelengths of sunlight by the gases in the atmosphere is what causes the sky to appear blue to our eyes during the daytime.\",\n", " \"additional_kwargs\": {\n", - " \"id\": \"msg_0131WctMyzmv4myNQeuAituP\",\n", + " \"id\": \"msg_019z4nWpShzsrbSHTWXWQh6z\",\n", " \"type\": \"message\",\n", " \"role\": \"assistant\",\n", " \"model\": \"claude-3-sonnet-20240229\",\n", @@ -500,17 +428,17 @@ " \"stop_sequence\": null,\n", " \"usage\": {\n", " \"input_tokens\": 13,\n", - " \"output_tokens\": 263\n", + " \"output_tokens\": 236\n", " }\n", " },\n", " \"response_metadata\": {\n", - " \"id\": \"msg_0131WctMyzmv4myNQeuAituP\",\n", + " \"id\": \"msg_019z4nWpShzsrbSHTWXWQh6z\",\n", " \"model\": \"claude-3-sonnet-20240229\",\n", " \"stop_reason\": \"end_turn\",\n", " \"stop_sequence\": null,\n", " \"usage\": {\n", " \"input_tokens\": 13,\n", - " \"output_tokens\": 263\n", + " \"output_tokens\": 236\n", " },\n", " \"type\": \"message\",\n", " \"role\": \"assistant\"\n", @@ -519,8 +447,8 @@ " \"invalid_tool_calls\": [],\n", " \"usage_metadata\": {\n", " \"input_tokens\": 13,\n", - " \"output_tokens\": 263,\n", - " \"total_tokens\": 276\n", + " \"output_tokens\": 236,\n", + " \"total_tokens\": 249\n", " }\n", "}\n" ] @@ -542,124 +470,6 @@ "await llmWithCustomHeaders.invoke(\"Why is the sky blue?\");" ] }, - { - "cell_type": "markdown", - "id": "985c4b4b", - "metadata": {}, - "source": [ - "## Tools\n", - "\n", - "The following example demonstrates [how to call tools](/docs/how_to/tool_calling) with Anthropic models:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "2ce56548", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[\n", - " {\n", - " name: 'calculator',\n", - " args: { number1: 2, number2: 2, operation: 'add' },\n", - " id: 'toolu_01Wjh2R15J945ErnGQ79UrpA',\n", - " type: 'tool_call'\n", - " }\n", - "]\n" - ] - } - ], - "source": [ - "import { ChatAnthropic } from \"@langchain/anthropic\";\n", - "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n", - "import { z } from \"zod\";\n", - "\n", - "const calculatorSchema = z.object({\n", - " operation: z\n", - " .enum([\"add\", \"subtract\", \"multiply\", \"divide\"])\n", - " .describe(\"The type of operation to execute.\"),\n", - " number1: z.number().describe(\"The first number to operate on.\"),\n", - " number2: z.number().describe(\"The second number to operate on.\"),\n", - "});\n", - "\n", - "const calculatorTool = {\n", - " name: \"calculator\",\n", - " description: \"A simple calculator tool\",\n", - " input_schema: zodToJsonSchema(calculatorSchema),\n", - "};\n", - "\n", - "const toolCallingLlm = new ChatAnthropic({\n", - " model: \"claude-3-haiku-20240307\",\n", - "}).bindTools([calculatorTool]);\n", - "\n", - "const toolPrompt = ChatPromptTemplate.fromMessages([\n", - " [\n", - " \"system\",\n", - " \"You are a helpful assistant who always needs to use a calculator.\",\n", - " ],\n", - " [\"human\", \"{input}\"],\n", - "]);\n", - "\n", - "// Chain your prompt and model together\n", - "const toolCallChain = toolPrompt.pipe(toolCallingLlm);\n", - "\n", - "const toolResponse = await toolCallChain.invoke({\n", - " input: \"What is 2 + 2?\",\n", - "});\n", - "\n", - "toolResponse.tool_calls;" - ] - }, - { - "cell_type": "markdown", - "id": "15253085", - "metadata": {}, - "source": [ - "### `withStructuredOutput`\n", - "\n", - "If you just need to get structured output from the model, Anthropic models support the [`.withStructuredOutput()`](/docs/how_to/structured_output/#the-.withstructuredoutput-method) method:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "5e466d35", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " setup: \"Why don't cats play poker in the jungle?\",\n", - " punchline: 'Too many cheetahs!',\n", - " rating: 7\n", - "}\n" - ] - } - ], - "source": [ - "import { z } from \"zod\";\n", - "\n", - "const joke = z.object({\n", - " setup: z.string().describe(\"The setup of the joke\"),\n", - " punchline: z.string().describe(\"The punchline to the joke\"),\n", - " rating: z.number().optional().describe(\"How funny the joke is, from 1 to 10\"),\n", - "});\n", - "\n", - "const modelForStructuredOutput = new ChatAnthropic({\n", - " model: \"claude-3-haiku-20240307\",\n", - "})\n", - "\n", - "const structuredLlm = modelForStructuredOutput.withStructuredOutput(joke);\n", - "\n", - "await structuredLlm.invoke(\"Tell me a joke about cats\");" - ] - }, { "cell_type": "markdown", "id": "3a5bb5ca-c3ae-4a58-be67-2cd18574b9a3",