-
-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add ChatAnthropic integration (#477)
- Loading branch information
1 parent
8d92d9b
commit 44c7faf
Showing
19 changed files
with
1,418 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
145 changes: 145 additions & 0 deletions
145
docs/modules/model_io/models/chat_models/integrations/anthropic.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# ChatAnthropic | ||
|
||
Wrapper around [Anthropic Messages API](https://docs.anthropic.com/en/api/messages) (aka Claude API). | ||
|
||
## Setup | ||
|
||
The Anthropic API uses API keys for authentication. Visit your [API Keys](https://console.anthropic.com/settings/keys) page to retrieve the API key you'll use in your requests. | ||
|
||
The following models are available: | ||
- `claude-3-5-sonnet-20240620` | ||
- `claude-3-haiku-20240307` | ||
- `claude-3-opus-20240229` | ||
- `claude-3-sonnet-20240229` | ||
- `claude-2.0` | ||
- `claude-2.1` | ||
|
||
Mind that the list may not be up-to-date. See https://docs.anthropic.com/en/docs/about-claude/models for the updated list. | ||
|
||
## Usage | ||
|
||
```dart | ||
final apiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
), | ||
); | ||
final chatPrompt = ChatPromptTemplate.fromTemplates([ | ||
(ChatMessageType.system, 'You are a helpful assistant that translates {input_language} to {output_language}.'), | ||
(ChatMessageType.human, 'Text to translate:\n{text}'), | ||
]); | ||
final chain = chatPrompt | chatModel | StringOutputParser(); | ||
final res = await chain.invoke({ | ||
'input_language': 'English', | ||
'output_language': 'French', | ||
'text': 'I love programming.', | ||
}); | ||
print(res); | ||
// -> 'J'adore programmer.' | ||
``` | ||
|
||
## Multimodal support | ||
|
||
```dart | ||
final apiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
), | ||
); | ||
final res = await chatModel.invoke( | ||
PromptValue.chat([ | ||
ChatMessage.human( | ||
ChatMessageContent.multiModal([ | ||
ChatMessageContent.text('What fruit is this?'), | ||
ChatMessageContent.image( | ||
mimeType: 'image/jpeg', | ||
data: base64.encode( | ||
await File('./bin/assets/apple.jpeg').readAsBytes(), | ||
), | ||
), | ||
]), | ||
), | ||
]), | ||
); | ||
print(res.output.content); | ||
// -> 'The fruit in the image is an apple.' | ||
``` | ||
|
||
## Streaming | ||
|
||
```dart | ||
final apiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
final promptTemplate = ChatPromptTemplate.fromTemplates([ | ||
(ChatMessageType.system, 'You are a helpful assistant that replies only with numbers in order without any spaces or commas.'), | ||
(ChatMessageType.human, 'List the numbers from 1 to {max_num}'), | ||
]); | ||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
), | ||
); | ||
final chain = promptTemplate.pipe(chatModel).pipe(const StringOutputParser()); | ||
final stream = chain.stream({'max_num': '30'}); | ||
await stream.forEach(print); | ||
// 123 | ||
// 456789101 | ||
// 112131415161 | ||
// 718192021222 | ||
// 324252627282 | ||
// 930 | ||
``` | ||
|
||
## Tool calling | ||
|
||
`ChatAnthropic` supports tool calling. | ||
|
||
Check the [docs](https://langchaindart.dev/#/modules/model_io/models/chat_models/how_to/tools) for more information on how to use tools. | ||
|
||
Example: | ||
```dart | ||
const tool = ToolSpec( | ||
name: 'get_current_weather', | ||
description: 'Get the current weather in a given location', | ||
inputJsonSchema: { | ||
'type': 'object', | ||
'properties': { | ||
'location': { | ||
'type': 'string', | ||
'description': 'The city and state, e.g. San Francisco, CA', | ||
}, | ||
}, | ||
'required': ['location'], | ||
}, | ||
); | ||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
tools: [tool], | ||
), | ||
); | ||
final res = await model.invoke( | ||
PromptValue.string('What’s the weather like in Boston and Madrid right now in celsius?'), | ||
); | ||
``` |
109 changes: 109 additions & 0 deletions
109
examples/docs_examples/bin/modules/model_io/models/chat_models/integrations/anthropic.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// ignore_for_file: avoid_print | ||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:langchain/langchain.dart'; | ||
import 'package:langchain_anthropic/langchain_anthropic.dart'; | ||
|
||
void main(final List<String> arguments) async { | ||
await _invokeModel(); | ||
await _multiModal(); | ||
await _streaming(); | ||
} | ||
|
||
Future<void> _invokeModel() async { | ||
final apiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
|
||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: const ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
), | ||
); | ||
|
||
final chatPrompt = ChatPromptTemplate.fromTemplates(const [ | ||
( | ||
ChatMessageType.system, | ||
'You are a helpful assistant that translates {input_language} to {output_language}.' | ||
), | ||
(ChatMessageType.human, 'Text to translate:\n{text}'), | ||
]); | ||
|
||
final chain = chatPrompt | chatModel | const StringOutputParser(); | ||
|
||
final res = await chain.invoke({ | ||
'input_language': 'English', | ||
'output_language': 'French', | ||
'text': 'I love programming.', | ||
}); | ||
print(res); | ||
// -> 'J'adore programmer.' | ||
|
||
chatModel.close(); | ||
} | ||
|
||
Future<void> _multiModal() async { | ||
final apiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
|
||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: const ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
), | ||
); | ||
final res = await chatModel.invoke( | ||
PromptValue.chat([ | ||
ChatMessage.human( | ||
ChatMessageContent.multiModal([ | ||
ChatMessageContent.text('What fruit is this?'), | ||
ChatMessageContent.image( | ||
mimeType: 'image/jpeg', | ||
data: base64.encode( | ||
await File('./bin/assets/apple.jpeg').readAsBytes(), | ||
), | ||
), | ||
]), | ||
), | ||
]), | ||
); | ||
print(res.output.content); | ||
// -> 'The fruit in the image is an apple.' | ||
|
||
chatModel.close(); | ||
} | ||
|
||
Future<void> _streaming() async { | ||
final apiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
|
||
final promptTemplate = ChatPromptTemplate.fromTemplates(const [ | ||
( | ||
ChatMessageType.system, | ||
'You are a helpful assistant that replies only with numbers ' | ||
'in order without any spaces or commas.', | ||
), | ||
(ChatMessageType.human, 'List the numbers from 1 to {max_num}'), | ||
]); | ||
|
||
final chatModel = ChatAnthropic( | ||
apiKey: apiKey, | ||
defaultOptions: const ChatAnthropicOptions( | ||
model: 'claude-3-5-sonnet-20240620', | ||
temperature: 0, | ||
), | ||
); | ||
|
||
final chain = promptTemplate.pipe(chatModel).pipe(const StringOutputParser()); | ||
|
||
final stream = chain.stream({'max_num': '30'}); | ||
await stream.forEach(print); | ||
// 123 | ||
// 456789101 | ||
// 112131415161 | ||
// 718192021222 | ||
// 324252627282 | ||
// 930 | ||
|
||
chatModel.close(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 40 additions & 2 deletions
42
packages/langchain_anthropic/example/langchain_anthropic_example.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,41 @@ | ||
void main() { | ||
// TODO | ||
// ignore_for_file: avoid_print, unused_element | ||
import 'dart:io'; | ||
|
||
import 'package:langchain_anthropic/langchain_anthropic.dart'; | ||
import 'package:langchain_core/chat_models.dart'; | ||
import 'package:langchain_core/prompts.dart'; | ||
|
||
/// Check the docs for more examples: | ||
/// https://langchaindart.dev | ||
void main() async { | ||
// Uncomment the example you want to run: | ||
await _example1(); | ||
// await _example2(); | ||
} | ||
|
||
/// The most basic example of LangChain is calling a model on some input | ||
Future<void> _example1() async { | ||
final openAiApiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
final llm = ChatAnthropic( | ||
apiKey: openAiApiKey, | ||
defaultOptions: const ChatAnthropicOptions(temperature: 1), | ||
); | ||
final ChatResult res = await llm.invoke( | ||
PromptValue.string('Tell me a joke'), | ||
); | ||
print(res); | ||
} | ||
|
||
/// Instead of waiting for the full response from the model, you can stream it | ||
/// while it's being generated | ||
Future<void> _example2() async { | ||
final openAiApiKey = Platform.environment['ANTHROPIC_API_KEY']; | ||
final llm = ChatAnthropic( | ||
apiKey: openAiApiKey, | ||
defaultOptions: const ChatAnthropicOptions(temperature: 1), | ||
); | ||
final Stream<ChatResult> stream = llm.stream( | ||
PromptValue.string('Tell me a joke'), | ||
); | ||
await stream.forEach((final chunk) => stdout.write(chunk.output.content)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
/// Anthropic module for LangChain.dart. | ||
library; | ||
|
||
export 'src/chat_models/chat_models.dart'; |
Oops, something went wrong.