# claudette


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

### News June 22: Claudette just launched! For a quick intro read the [Claudette launch blog post](https://www.answer.ai/posts/2024-06-21-claudette.html).

> **NB**: If you are reading this in GitHub’s readme, we recommend you
> instead read the much more nicely formatted [documentation
> format](https://answerdotai.github.io/claudette/) of this tutorial.

*Claudette* is a wrapper for Anthropic’s [Python
SDK](https://github.com/anthropics/anthropic-sdk-python).

The SDK works well, but it is quite low level – it leaves the developer
to do a lot of stuff manually. That’s a lot of extra work and
boilerplate! Claudette automates pretty much everything that can be
automated, whilst providing full control. Amongst the features provided:

- A [`Chat`](https://AnswerDotAI.github.io/claudette/core.html#chat)
  class that creates stateful dialogs
- Support for *prefill*, which tells Claude what to use as the first few
  words of its response
- Convenient image support
- Simple and convenient support for Claude’s new Tool Use API.

You’ll need to set the `ANTHROPIC_API_KEY` environment variable to the
key provided to you by Anthropic in order to use this library.

Note that this library is the first ever “literate nbdev” project. That
means that the actual source code for the library is a rendered Jupyter
Notebook which includes callout notes and tips, HTML tables and images,
detailed explanations, and teaches *how* and *why* the code is written
the way it is. Even if you’ve never used the Anthropic Python SDK or
Claude API before, you should be able to read the source code. Click
[Claudette’s Source](https://answerdotai.github.io/claudette/core.html)
to read it, or clone the git repo and execute the notebook yourself to
see every step of the creation process in action. The tutorial below
includes links to API details which will take you to relevant parts of
the source. The reason this project is a new kind of literal program is
because we take seriously Knuth’s call to action, that we have a “*moral
commitment*” to never write an “*illiterate program*” – and so we have a
commitment to making literate programming and easy and pleasant
experience. (For more on this, see [this
talk](https://www.youtube.com/watch?v=rX1yGxJijsI) from Hamel Husain.)

> “*Let us change our traditional attitude to the construction of
> programs: Instead of imagining that our main task is to instruct a
> **computer** what to do, let us concentrate rather on explaining to
> **human beings** what we want a computer to do.*” Donald E. Knuth,
> [Literate
> Programming](https://www.cs.tufts.edu/~nr/cs257/archive/literate-programming/01-knuth-lp.pdf)
> (1984)

## Install

``` sh
pip install claudette
```

## Getting started

Anthropic’s Python SDK will automatically be installed with Claudette,
if you don’t already have it.

``` python
import os
# os.environ['ANTHROPIC_LOG'] = 'debug'
```

To print every HTTP request and response in full, uncomment the above
line.

``` python
from claudette import *
```

Claudette only exports the symbols that are needed to use the library,
so you can use `import *` to import them. Alternatively, just use:

``` python
import claudette
```

…and then add the prefix `claudette.` to any usages of the module.

Claudette provides `models`, which is a list of models currently
available from the SDK.

``` python
models
```

    ('claude-3-opus-20240229',
     'claude-3-5-sonnet-20240620',
     'claude-3-haiku-20240307')

For these examples, we’ll use Sonnet 3.5, since it’s awesome!

``` python
model = models[1]
```

## Chat

The main interface to Claudette is the
[`Chat`](https://AnswerDotAI.github.io/claudette/core.html#chat) class,
which provides a stateful interface to Claude:

``` python
chat = Chat(model, sp="""You are a helpful and concise assistant.""")
chat("I'm Jeremy")
```

Hello Jeremy, it’s nice to meet you. How can I assist you today?

<details>

- id: msg_01KLrPzN79dXmDhTH2Nv6tjn
- content: \[{‘text’: “Hello Jeremy, it’s nice to meet you. How can I
  assist you today?”, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 19, ‘output_tokens’: 20}

</details>

``` python
r = chat("What's my name?")
r
```

Your name is Jeremy, as you just told me.

<details>

- id: msg_01VsZr9D5ptbWrggdX28y1J5
- content: \[{‘text’: ‘Your name is Jeremy, as you just told me.’,
  ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 47, ‘output_tokens’: 14}

</details>

As you see above, displaying the results of a call in a notebook shows
just the message contents, with the other details hidden behind a
collapsible section. Alternatively you can `print` the details:

``` python
print(r)
```

    Message(id='msg_01VsZr9D5ptbWrggdX28y1J5', content=[TextBlock(text='Your name is Jeremy, as you just told me.', type='text')], model='claude-3-5-sonnet-20240620', role='assistant', stop_reason='end_turn', stop_sequence=None, type='message', usage=In: 47; Out: 14; Total: 61)

Claude supports adding an extra `assistant` message at the end, which
contains the *prefill* – i.e. the text we want Claude to assume the
response starts with. Let’s try it out:

``` python
chat("Concisely, what is the meaning of life?",
     prefill='According to Douglas Adams,')
```

According to Douglas Adams, “42.” More seriously, it’s often considered
to be finding personal fulfillment, happiness, and purpose.

<details>

- id: msg_01RMBD95RyQjbsNckGYmRMLu
- content: \[{‘text’: ‘According to Douglas Adams, “42.” More seriously,
  it's often considered to be finding personal fulfillment, happiness,
  and purpose.’, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 81, ‘output_tokens’: 27}

</details>

You can add `stream=True` to stream the results as soon as they arrive
(although you will only see the gradual generation if you execute the
notebook yourself, of course!)

``` python
for o in chat("Concisely, what book was that in?", prefill='It was in', stream=True):
    print(o, end='')
```

    It was in "The Hitchhiker's Guide to the Galaxy" by Douglas Adams.

## Tool use

[Tool use](https://docs.anthropic.com/claude/docs/tool-use) lets Claude
use external tools.

We use [docments](https://fastcore.fast.ai/docments.html) to make
defining Python functions as ergonomic as possible. Each parameter (and
the return value) should have a type, and a docments comment with the
description of what it is. As an example we’ll write a simple function
that adds numbers together, and will tell us when it’s being called:

``` python
def sums(
    a:int,  # First thing to sum
    b:int=1 # Second thing to sum
) -> int: # The sum of the inputs
    "Adds a + b."
    print(f"Finding the sum of {a} and {b}")
    return a + b
```

Sometimes Claude will say something like “according to the `sums` tool
the answer is” – generally we’d rather it just tells the user the
answer, so we can use a system prompt to help with this:

``` python
sp = "Never mention what tools you use."
```

We’ll get Claude to add up some long numbers:

``` python
a,b = 604542,6458932
pr = f"What is {a}+{b}?"
pr
```

    'What is 604542+6458932?'

To use tools, pass a list of them to
[`Chat`](https://AnswerDotAI.github.io/claudette/core.html#chat), and to
force it to always answer using a tool, set `tool_choice` to that
function name:

``` python
chat = Chat(model, sp=sp, tools=[sums], tool_choice='sums')
```

Now when we call that with our prompt, Claude doesn’t return the answer,
but instead returns a `tool_use` message, which means we have to call
the named tool with the provided parameters:

``` python
r = chat(pr)
r
```

    Finding the sum of 604542 and 6458932

ToolUseBlock(id=‘toolu_018a7fT3Mnoa2XqtAMXqawXU’, input={‘a’: 604542,
‘b’: 6458932}, name=‘sums’, type=‘tool_use’)

<details>

- id: msg_011r1ZTjJSLFCJKceMoFSPky
- content: \[{‘id’: ‘toolu_018a7fT3Mnoa2XqtAMXqawXU’, ‘input’: {‘a’:
  604542, ‘b’: 6458932}, ‘name’: ‘sums’, ‘type’: ‘tool_use’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: tool_use
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 414, ‘output_tokens’: 53}

</details>

Claudette handles all that for us – we just call it again, and it all
happens automatically:

``` python
chat()
```

    Finding the sum of 7063474 and 1

ToolUseBlock(id=‘toolu_01Pc9N6fQSUNnuqrUKR2DkmL’, input={‘a’: 7063474},
name=‘sums’, type=‘tool_use’)

<details>

- id: msg_01Ct8URrPt5hf5mjUSndwigS
- content: \[{‘id’: ‘toolu_01Pc9N6fQSUNnuqrUKR2DkmL’, ‘input’: {‘a’:
  7063474}, ‘name’: ‘sums’, ‘type’: ‘tool_use’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: tool_use
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 502, ‘output_tokens’: 35}

</details>

You can see how many tokens have been used at any time by checking the
`use` property. Note that (as of May 2024) tool use in Claude uses a
*lot* of tokens, since it automatically adds a large system prompt.

``` python
chat.use
```

    In: 916; Out: 88; Total: 1004

We can do everything needed to use tools in a single step, by using
[`Chat.toolloop`](https://AnswerDotAI.github.io/claudette/toolloop.html#chat.toolloop).
This can even call multiple tools as needed solve a problem. For
example, let’s define a tool to handle multiplication:

``` python
def mults(
    a:int,  # First thing to multiply
    b:int=1 # Second thing to multiply
) -> int: # The product of the inputs
    "Multiplies a * b."
    print(f"Finding the product of {a} and {b}")
    return a * b
```

Now with a single call we can calculate `(a+b)*2` – by passing
`show_trace` we can see each response from Claude in the process:

``` python
chat = Chat(model, sp=sp, tools=[sums,mults])
pr = f'Calculate ({a}+{b})*2'
pr
```

    'Calculate (604542+6458932)*2'

``` python
chat.toolloop(pr, trace_func=print)
```

    Finding the sum of 604542 and 6458932
    Message(id='msg_016tRhA75RqXTkCMR9WoZvyE', content=[TextBlock(text='Certainly! To calculate (604542+6458932)*2, we\'ll need to use the available tools to perform the addition and multiplication operations. Let\'s break it down step by step:\n\n1. First, we\'ll add 604542 and 6458932 using the "sums" function.\n2. Then, we\'ll multiply the result by 2 using the "mults" function.\n\nLet\'s start with the addition:', type='text'), ToolUseBlock(id='toolu_017aomxeCUA6DxM9U6UQjMu2', input={'a': 604542, 'b': 6458932}, name='sums', type='tool_use')], model='claude-3-5-sonnet-20240620', role='assistant', stop_reason='tool_use', stop_sequence=None, type='message', usage=In: 538; Out: 168; Total: 706)
    Finding the product of 7063474 and 2
    Message(id='msg_016w97cNedVktfhHUoL2Ey7a', content=[TextBlock(text="Great! The sum of 604542 and 6458932 is 7063474.\n\nNow, let's multiply this result by 2:", type='text'), ToolUseBlock(id='toolu_0115UMmS2GMeej1CafKLKvBB', input={'a': 7063474, 'b': 2}, name='mults', type='tool_use')], model='claude-3-5-sonnet-20240620', role='assistant', stop_reason='tool_use', stop_sequence=None, type='message', usage=In: 721; Out: 106; Total: 827)
    Message(id='msg_0139BkRu9b9yKPp8N8NHBMpj', content=[TextBlock(text='Now we have our final result. \n\nThe calculation (604542+6458932)*2 equals 14126948.\n\nTo break it down:\n1. 604542 + 6458932 = 7063474\n2. 7063474 * 2 = 14126948\n\nSo, the final answer to (604542+6458932)*2 is 14126948.', type='text')], model='claude-3-5-sonnet-20240620', role='assistant', stop_reason='end_turn', stop_sequence=None, type='message', usage=In: 841; Out: 95; Total: 936)

Now we have our final result.

The calculation (604542+6458932)\*2 equals 14126948.

To break it down: 1. 604542 + 6458932 = 7063474 2. 7063474 \* 2 =
14126948

So, the final answer to (604542+6458932)\*2 is 14126948.

<details>

- id: msg_0139BkRu9b9yKPp8N8NHBMpj
- content: \[{‘text’: ’Now we have our final result. calculation
  (604542+6458932)*2 equals 14126948.break it down:. 604542 + 6458932 =
  7063474. 7063474 * 2 = 14126948, the final answer to
  (604542+6458932)\*2 is 14126948.’, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 841, ‘output_tokens’: 95}

</details>

## Images

Claude can handle image data as well. As everyone knows, when testing
image APIs you have to use a cute puppy.

``` python
fn = Path('samples/puppy.jpg')
display.Image(filename=fn, width=200)
```

![](index_files/figure-commonmark/cell-21-output-1.jpeg)

We create a
[`Chat`](https://AnswerDotAI.github.io/claudette/core.html#chat) object
as before:

``` python
chat = Chat(model)
```

Claudette expects images as a list of bytes, so we read in the file:

``` python
img = fn.read_bytes()
```

Prompts to Claudette can be lists, containing text, images, or both, eg:

``` python
chat([img, "In brief, what color flowers are in this image?"])
```

The flowers in this image are purple. They appear to be small,
daisy-like flowers, possibly asters or some type of purple wildflower,
blooming in the background behind the adorable puppy in the foreground.

<details>

- id: msg_01EsC5ZMpo5chJRzcjkceLu9
- content: \[{‘text’: ‘The flowers in this image are purple. They appear
  to be small, daisy-like flowers, possibly asters or some type of
  purple wildflower, blooming in the background behind the adorable
  puppy in the foreground.’, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 110, ‘output_tokens’: 51}

</details>

The image is included as input tokens.

``` python
chat.use
```

    In: 110; Out: 51; Total: 161

Alternatively, Claudette supports creating a multi-stage chat with
separate image and text prompts. For instance, you can pass just the
image as the initial prompt (in which case Claude will make some general
comments about what it sees), and then follow up with questions in
additional prompts:

``` python
chat = Chat(model)
chat(img)
```

This image shows an adorable puppy lying in the grass. The puppy appears
to be a Cavalier King Charles Spaniel or a similar breed, with
distinctive white and reddish-brown fur coloring. Its face is
predominantly white with large, expressive dark eyes and a small black
nose.

The puppy is resting on a grassy surface, giving the impression of being
outdoors. In the background, you can see purple flowers, which look like
asters or michaelmas daisies, adding a lovely splash of color to the
scene. There’s also what appears to be a wooden structure or fence
behind the flowers, suggesting a garden setting.

The composition of the image creates a charming, pastoral scene that
highlights the puppy’s cuteness against the natural backdrop. The
contrast between the soft fur of the puppy and the delicate purple
flowers makes for a visually appealing and heartwarming picture.

<details>

- id: msg_013TMWFVwfmYh2qzUtUqen68
- content: \[{‘text’: “This image shows an adorable puppy lying in the
  grass. The puppy appears to be a Cavalier King Charles Spaniel or a
  similar breed, with distinctive white and reddish-brown fur coloring.
  Its face is predominantly white with large, expressive dark eyes and a
  small black nose.puppy is resting on a grassy surface, giving the
  impression of being outdoors. In the background, you can see purple
  flowers, which look like asters or michaelmas daisies, adding a lovely
  splash of color to the scene. There’s also what appears to be a wooden
  structure or fence behind the flowers, suggesting a garden
  setting.composition of the image creates a charming, pastoral scene
  that highlights the puppy’s cuteness against the natural backdrop. The
  contrast between the soft fur of the puppy and the delicate purple
  flowers makes for a visually appealing and heartwarming picture.”,
  ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 98, ‘output_tokens’: 197}

</details>

``` python
chat('What direction is the puppy facing?')
```

The puppy in the image is facing towards the camera, looking directly at
the viewer. Its head is slightly tilted, giving it an endearing and
curious expression. The puppy’s body is angled slightly to its left (our
right), with its front paws visible and resting on the grass. This
positioning allows us to see the full face of the puppy, showcasing its
adorable features and the distinctive color pattern of its fur.

<details>

- id: msg_015W9aQZt9JsjExJKcN72cDo
- content: \[{‘text’: “The puppy in the image is facing towards the
  camera, looking directly at the viewer. Its head is slightly tilted,
  giving it an endearing and curious expression. The puppy’s body is
  angled slightly to its left (our right), with its front paws visible
  and resting on the grass. This positioning allows us to see the full
  face of the puppy, showcasing its adorable features and the
  distinctive color pattern of its fur.”, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 306, ‘output_tokens’: 95}

</details>

``` python
chat('What color is it?')
```

The puppy in the image has a combination of two main colors:

1.  White: The majority of its face, including the muzzle area and a
    portion of its body that’s visible, is white.

2.  Reddish-brown (often called “chestnut” or “ruby” in this breed):
    This color appears on the ears and extends to patches on the body,
    though the full extent isn’t visible in this image.

This color combination is typical for Cavalier King Charles Spaniels,
particularly the Blenheim variety. The contrast between the white and
the reddish-brown fur creates a striking and adorable appearance,
highlighting the puppy’s facial features and giving it a distinctive
look.

<details>

- id: msg_0146KQcPjSoXFGLjqjpzwU3Q
- content: \[{‘text’: ‘The puppy in the image has a combination of two
  main colors:. White: The majority of its face, including the muzzle
  area and a portion of its body that's visible, is white..
  Reddish-brown (often called “chestnut” or “ruby” in this breed): This
  color appears on the ears and extends to patches on the body, though
  the full extent isn't visible in this image.color combination is
  typical for Cavalier King Charles Spaniels, particularly the Blenheim
  variety. The contrast between the white and the reddish-brown fur
  creates a striking and adorable appearance, highlighting the puppy's
  facial features and giving it a distinctive look.’, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 409, ‘output_tokens’: 157}

</details>

Note that the image is passed in again for every input in the dialog, so
that number of input tokens increases quickly with this kind of chat.

``` python
chat.use
```

    In: 813; Out: 449; Total: 1262

## Other model providers

You can also use 3rd party providers of Anthropic models, as shown here.

### Amazon Bedrock

These are the models available through Bedrock:

``` python
models_aws
```

    ('anthropic.claude-3-haiku-20240307-v1:0',
     'anthropic.claude-3-sonnet-20240229-v1:0',
     'anthropic.claude-3-opus-20240229-v1:0',
     'anthropic.claude-3-5-sonnet-20240620-v1:0')

To use them, call `AnthropicBedrock` with your access details, and pass
that to
[`Client`](https://AnswerDotAI.github.io/claudette/core.html#client):

``` python
from anthropic import AnthropicBedrock
```

``` python
ab = AnthropicBedrock(
    aws_access_key=os.environ['AWS_ACCESS_KEY'],
    aws_secret_key=os.environ['AWS_SECRET_KEY'],
)
client = Client(models_aws[-1], ab)
```

Now create your
[`Chat`](https://AnswerDotAI.github.io/claudette/core.html#chat) object
passing this client to the `cli` parameter – and from then on,
everything is identical to the previous examples.

``` python
chat = Chat(cli=client)
chat("I'm Jeremy")
```

Hello Jeremy! It’s nice to meet you. How can I assist you today? Is
there anything specific you’d like to talk about or any questions you
have?

<details>

- id: msg_bdrk_011MuMcLUba22CUttpxWuHJC
- content: \[{‘text’: “Hello Jeremy! It’s nice to meet you. How can I
  assist you today? Is there anything specific you’d like to talk about
  or any questions you have?”, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 10, ‘output_tokens’: 36}

</details>

### Google Vertex

These are the models available through Vertex:

``` python
models_goog
```

    ('claude-3-haiku@20240307',
     'claude-3-sonnet@20240229',
     'claude-3-opus@20240229',
     'claude-3-5-sonnet@20240620')

To use them, call `AnthropicVertex` with your access details, and pass
that to
[`Client`](https://AnswerDotAI.github.io/claudette/core.html#client):

``` python
from anthropic import AnthropicVertex
import google.auth
```

``` python
project_id = google.auth.default()[1]
gv = AnthropicVertex(project_id=project_id, region="us-east5")
client = Client(models_goog[-1], gv)
```

``` python
chat = Chat(cli=client)
chat("I'm Jeremy")
```

Hello Jeremy! It’s nice to meet you. How can I assist you today? Is
there anything specific you’d like to talk about or any questions you
have?

<details>

- id: msg_vrtx_015zVvSZxfmNQ8FRZjb9zPdJ
- content: \[{‘text’: “Hello Jeremy! It’s nice to meet you. How can I
  assist you today? Is there anything specific you’d like to talk about
  or any questions you have?”, ‘type’: ‘text’}\]
- model: claude-3-5-sonnet-20240620
- role: assistant
- stop_reason: end_turn
- stop_sequence: None
- type: message
- usage: {‘input_tokens’: 10, ‘output_tokens’: 36}

</details>
