Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

anthropic[minor]: add tool calling #18554

Merged
merged 13 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
205 changes: 33 additions & 172 deletions docs/docs/integrations/chat/anthropic_functions.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
"id": "5125a1e3",
"metadata": {},
"source": [
"# Anthropic Functions\n",
"# Anthropic Tools\n",
"\n",
"This notebook shows how to use an experimental wrapper around Anthropic that gives it the same API as OpenAI Functions."
"This notebook shows how to use an experimental wrapper around Anthropic that gives it tool calling and structured output capabilities. It follows Anthropic's guide [here](https://docs.anthropic.com/claude/docs/functions-external-tools)\n",
"\n",
"The wrapper is available from the `langchain-anthropic` package, and it also requires the optional dependency `defusedxml` for parsing XML output from the llm.\n",
"\n",
"Note: this is a beta feature that will be replaced by Anthropic's formal implementation of tool calling, but it is useful for testing and experimentation in the meantime."
]
},
{
Expand All @@ -17,225 +21,82 @@
"metadata": {},
"outputs": [],
"source": [
"from langchain_experimental.llms.anthropic_functions import AnthropicFunctions"
"%pip install -qU langchain-anthropic defusedxml\n",
"from langchain_anthropic.experimental import ChatAnthropicTools"
]
},
{
"cell_type": "markdown",
"id": "65499965",
"metadata": {},
"source": [
"## Initialize Model\n",
"\n",
"You can initialize this wrapper the same way you'd initialize ChatAnthropic"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1d535f6",
"metadata": {},
"outputs": [],
"source": [
"model = AnthropicFunctions(model=\"claude-2\")"
]
},
{
"cell_type": "markdown",
"id": "fcc9eaf4",
"metadata": {},
"source": [
"## Passing in functions\n",
"## Tool Binding\n",
"\n",
"You can now pass in functions in a similar way"
"`ChatAnthropicTools` exposes a `bind_tools` method that allows you to pass in Pydantic models or BaseTools to the llm."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "0779c320",
"metadata": {},
"outputs": [],
"source": [
"functions = [\n",
" {\n",
" \"name\": \"get_current_weather\",\n",
" \"description\": \"Get the current weather in a given location\",\n",
" \"parameters\": {\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"location\": {\n",
" \"type\": \"string\",\n",
" \"description\": \"The city and state, e.g. San Francisco, CA\",\n",
" },\n",
" \"unit\": {\"type\": \"string\", \"enum\": [\"celsius\", \"fahrenheit\"]},\n",
" },\n",
" \"required\": [\"location\"],\n",
" },\n",
" }\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ad75a933",
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.messages import HumanMessage"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "fc703085",
"metadata": {},
"outputs": [],
"source": [
"response = model.invoke(\n",
" [HumanMessage(content=\"whats the weater in boston?\")], functions=functions\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "04d7936a",
"id": "e1d535f6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"AIMessage(content=' ', additional_kwargs={'function_call': {'name': 'get_current_weather', 'arguments': '{\"location\": \"Boston, MA\", \"unit\": \"fahrenheit\"}'}}, example=False)"
"AIMessage(content='', additional_kwargs={'tool_calls': [{'function': {'name': 'Person', 'arguments': '{\"name\": \"Erick\", \"age\": \"27\"}'}, 'type': 'function'}]})"
]
},
"execution_count": 7,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response"
]
},
{
"cell_type": "markdown",
"id": "0072fdba",
"metadata": {},
"source": [
"## Using for extraction\n",
"from langchain_core.pydantic_v1 import BaseModel\n",
"\n",
"You can now use this for extraction."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "7af5c567",
"metadata": {},
"outputs": [],
"source": [
"from langchain.chains import create_extraction_chain\n",
"\n",
"schema = {\n",
" \"properties\": {\n",
" \"name\": {\"type\": \"string\"},\n",
" \"height\": {\"type\": \"integer\"},\n",
" \"hair_color\": {\"type\": \"string\"},\n",
" },\n",
" \"required\": [\"name\", \"height\"],\n",
"}\n",
"inp = \"\"\"\n",
"Alex is 5 feet tall. Claudia is 1 feet taller Alex and jumps higher than him. Claudia is a brunette and Alex is blonde.\n",
" \"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bd01082a",
"metadata": {},
"outputs": [],
"source": [
"chain = create_extraction_chain(schema, model)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b5a23e9f",
"metadata": {},
"outputs": [],
"source": [
"chain.invoke(inp)"
"class Person(BaseModel):\n",
" name: str\n",
" age: int\n",
"\n",
"\n",
"model = ChatAnthropicTools(model=\"claude-3-opus-20240229\").bind_tools(tools=[Person])\n",
"model.invoke(\"I am a 27 year old named Erick\")"
]
},
{
"cell_type": "markdown",
"id": "90ec959e",
"id": "fcc9eaf4",
"metadata": {},
"source": [
"## Using for tagging\n",
"## Structured Output\n",
"\n",
"You can now use this for tagging"
"`ChatAnthropicTools` also implements the [`with_structured_output` spec](/docs/guides/structured_output) for extracting values. Note: this may not be as stable as with models that explicitly offer tool calling."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "03c1eb0d",
"metadata": {},
"outputs": [],
"source": [
"from langchain.chains import create_tagging_chain"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "581c0ece",
"metadata": {},
"outputs": [],
"source": [
"schema = {\n",
" \"properties\": {\n",
" \"sentiment\": {\"type\": \"string\"},\n",
" \"aggressiveness\": {\"type\": \"integer\"},\n",
" \"language\": {\"type\": \"string\"},\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "d9a8570e",
"metadata": {},
"outputs": [],
"source": [
"chain = create_tagging_chain(schema, model)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "cf37d679",
"execution_count": 4,
"id": "0779c320",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'sentiment': 'positive', 'aggressiveness': '0', 'language': 'english'}"
"Person(name='Erick', age=27)"
]
},
"execution_count": 15,
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"chain.invoke(\"this is really cool\")"
"chain = ChatAnthropicTools(model=\"claude-3-opus-20240229\").with_structured_output(\n",
" Person\n",
")\n",
"chain.invoke(\"I am a 27 year old named Erick\")"
]
}
],
Expand All @@ -255,7 +116,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.0"
"version": "3.11.4"
}
},
"nbformat": 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ChatResult,
)
from langchain_community.chat_models.anthropic import ChatAnthropic
from langchain_core._api.deprecation import deprecated
from langchain_core.language_models import BaseChatModel
from langchain_core.messages import (
AIMessage,
Expand Down Expand Up @@ -123,6 +124,11 @@ def _destrip(tool_input: Any) -> Any:
raise ValueError


@deprecated(
since="0.0.54",
removal="0.2",
alternative_import="langchain_anthropic.experimental.ChatAnthropicTools",
)
class AnthropicFunctions(BaseChatModel):
"""Chat model for interacting with Anthropic functions."""

Expand Down
23 changes: 16 additions & 7 deletions libs/partners/anthropic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,17 @@ This package contains the LangChain integration for Anthropic's generative model

## Chat Models

| API Model Name | Model Family |
| ------------------ | -------------- |
| claude-instant-1.2 | Claude Instant |
| claude-2.1 | Claude |
| claude-2.0 | Claude |
Anthropic recommends using their chat models over text completions.

You can see their recommended models [here](https://docs.anthropic.com/claude/docs/models-overview#model-recommendations).

To use, you should have an Anthropic API key configured. Initialize the model as:

```
from langchain_anthropic import ChatAnthropicMessages
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import AIMessage, HumanMessage

model = ChatAnthropicMessages(model="claude-2.1", temperature=0, max_tokens=1024)
model = ChatAnthropic(model="claude-3-opus-20240229", temperature=0, max_tokens=1024)
```

### Define the input message
Expand All @@ -32,3 +30,14 @@ model = ChatAnthropicMessages(model="claude-2.1", temperature=0, max_tokens=1024
`response = model.invoke([message])`

For a more detailed walkthrough see [here](https://python.langchain.com/docs/integrations/chat/anthropic).

## LLMs (Legacy)

You can use the Claude 2 models for text completions.

```python
from langchain_anthropic import AnthropicLLM

model = AnthropicLLM(model="claude-2.1", temperature=0, max_tokens=1024)
response = model.invoke("The best restaurant in San Francisco is: ")
```
22 changes: 10 additions & 12 deletions libs/partners/anthropic/langchain_anthropic/chat_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ async def _astream(
await run_manager.on_llm_new_token(text, chunk=chunk)
yield chunk

def _format_output(self, data: Any) -> ChatResult:
return ChatResult(
generations=[
ChatGeneration(message=AIMessage(content=data.content[0].text))
],
llm_output=data,
)

def _generate(
self,
messages: List[BaseMessage],
Expand All @@ -193,12 +201,7 @@ def _generate(
) -> ChatResult:
params = self._format_params(messages=messages, stop=stop, **kwargs)
data = self._client.messages.create(**params)
return ChatResult(
generations=[
ChatGeneration(message=AIMessage(content=data.content[0].text))
],
llm_output=data,
)
return self._format_output(data, **kwargs)

async def _agenerate(
self,
Expand All @@ -209,12 +212,7 @@ async def _agenerate(
) -> ChatResult:
params = self._format_params(messages=messages, stop=stop, **kwargs)
data = await self._async_client.messages.create(**params)
return ChatResult(
generations=[
ChatGeneration(message=AIMessage(content=data.content[0].text))
],
llm_output=data,
)
return self._format_output(data, **kwargs)


@deprecated(since="0.1.0", removal="0.2.0", alternative="ChatAnthropic")
Expand Down