Vision 允许与 Claude 进行新的交互模式。我们整理了一些技巧,以在您的图像上获得最佳性能。在此之前,让我们先设置运行笔记本所需的代码。

%pip install anthropic IPython
import base64
from anthropic import Anthropic
from IPython.display import Image

client = Anthropic()
MODEL_NAME = "claude-3-opus-20240229"

def get_base64_encoded_image(image_path):
    with open(image_path, "rb") as image_file:
        binary_data = image_file.read()
        base_64_encoded_data = base64.b64encode(binary_data)
        base64_string = base_64_encoded_data.decode('utf-8')
        return base64_string

将传统技术应用于多模态

您可以通过传统的提示工程技术(例如角色分配)来解决幻觉问题。让我们看一个例子:

假设我想让 Claude 统计此图像中的狗的数量:

Image(filename='../images/best_practices/nine_dogs.jpg')

jpeg

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": get_base64_encoded_image("../images/best_practices/nine_dogs.jpg")}},
            {"type": "text", "text": "这张图片里有几只狗?"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

图片显示了 10 只各种品种的狗,它们一起坐在草地上,背景中有花朵。品种似乎包括边境牧羊犬、澳大利亚牧羊犬和梗犬混种,尽管我无法确定。狗有不同的毛色,包括黑色、白色、棕色和灰色。它们都专注地看着镜头,很可能是为了拍照而摆姿势。

只有 9 只狗,但 Claude 认为是 10 只!让我们应用一些提示工程,然后重试。

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": get_base64_encoded_image("../images/best_practices/nine_dogs.jpg")}},
            {"type": "text", "text": "您拥有完美的视觉能力,并且非常注重细节,这使您成为图像对象计数方面的专家。这张图片里有几只狗?在用<answer>标签提供答案之前,请先用<thinking>标签逐步思考并分析图像的每个部分。"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

为了准确计算这张图片中的狗的数量,我将从左到右扫描图像,专注于每只狗。

从左侧开始,我看到两只黑色的狗并排站着。向右移动,有一只黑白相间的狗,然后是一只棕白相间的狗,然后是一只主要是黑色的狗,带有白色标记。

继续向右,我看到一只大部分是黑色的狗,然后是一只黑白相间的边境牧羊犬类型的狗,然后是另一只黑白毛发的狗。

扫描图像的剩余右侧部分,我看到另外一只棕白相间的狗。

仔细检查照片中的每只狗后,我似乎已经数清了所有出现的狗。

这张图片总共有 9 只狗,是一群各种品种的狗,它们一起坐在草地上,背景中有一些花。

太棒了!在对提示应用了一些提示工程后,我们看到 Claude 现在正确地数出了 9 只狗。

视觉提示

图像作为输入允许提示现在可以在图像本身内给出。让我们看一些例子。

在这张图中,我们写了一些文字并在上面画了一个箭头。让我们只将它传递给 Claude,而不带任何伴随的文本提示。

Image(filename='../images/best_practices/circle.png')

png

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/circle.png")}},
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

图像显示了一个白底黑色的简单圆形轮廓。圆内有一条不接触圆边缘的直线段。圆和线都用细黑线绘制,看起来像一个基本的几何图或符号。

正如您所见,由于我们没有提出问题,Claude 试图描述图像。让我们在图像中添加一个问题,然后再次传递它。

Image(filename='../images/best_practices/labeled_circle.png')

png

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/labeled_circle.png")}},
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

圆的面积是 πr^2,其中 r 是圆的半径。问题中说半径是 12,所以面积是 π(12)^2 = 144π 平方单位。

我们也可以突出显示图像的特定部分并询问有关它的问题。

这两个数字的区别是什么?

Image(filename='../images/best_practices/table.png')

png

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/table.png")}},
            {"type": "text", "text": "这两个数字的区别是什么?"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

截至 2023 年 12 月 31 日的十二个月的北美净销售额(352,828 美元)与截至 2022 年 12 月 31 日的净销售额(315,880 美元)之间的差额为 36,948 美元。

少样本示例

添加示例到提示中仍然可以提高视觉任务的准确性。让我们让 Claude 读取速度计的图片。

Image(filename='../images/best_practices/140.png')

png

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/140.png")}},
            {"type": "text", "text": "我开得多快?"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

图像中的速度计显示速度为 140 公里/小时(约合 87 英里/小时)。

Claude 的答案看起来不太对,它认为我们开的是 140 英里/小时而不是 140 公里/小时!让我们再试一次,但这次在提示中添加一些示例。

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/70.png")}},
            {"type": "text", "text": "我开得多快?"}
        ]
    },
    {
        "role": 'assistant',
        "content": [
            {"type": "text", "text": "您每小时行驶 70 英里。"}
        ]
    },
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/100.png")}},
            {"type": "text", "text": "我开得多快?"}
        ]
    },
    {
        "role": 'assistant',
        "content": [
            {"type": "text", "text": "您每小时行驶 100 英里。"}
        ]
    },
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/140.png")}},
            {"type": "text", "text": "我开得多快?"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list,
    temperature=0
)
print(response.content[0].text)

图像中的速度计显示您每小时行驶 140 英里。

太棒了!通过这些示例,Claude 学会了如何读取速度计上的速度。但请注意,图像的少样本提示并不总是有效,但值得在您的用例中尝试。

多个图像作为输入

Claude 还可以在提示中一次接受和处理多个图像!例如,假设您有一张非常大的图像 - 就像一张长收据的图像!我们可以将该图像分成几块,然后将每一块输入到 Claude。

Image(filename='../images/best_practices/receipt1.png')

png

Image(filename='../images/best_practices/receipt2.png')

png

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/receipt1.png")}},
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/receipt2.png")}},
            {"type": "text", "text": "输出餐厅名称和总金额。"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

餐厅名称是 The Breakfast Club,收据上的总金额是 78.86 美元。

示例对象识别

通过图像输入,您可以将其他图像传递给提示,Claude 将使用该信息来回答问题。让我们看一个例子。

假设我们正在尝试识别图像中的裤子类型。我们可以在提示中为 Claude 提供一些不同类型裤子的示例。

Image(filename='../images/best_practices/officer_example.png')

png

message_list = [
    {
        "role": 'user',
        "content": [
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/wrinkle.png")}},
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/officer.png")}},
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/chinos.png")}},
            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/officer_example.png")}},
            {"type": "text", "text": "这些裤子分别是(按顺序)抗皱正装裤、意大利美尔顿警官裤、修身快干斜纹裤。最后一张图中的裤子是什么?"}
        ]
    }
]

response = client.messages.create(
    model=MODEL_NAME,
    max_tokens=2048,
    messages=message_list
)
print(response.content[0].text)

最后一张图显示一个人穿着浅灰色羊毛正装裤或西裤,搭配棕色皮革正装鞋或乐福鞋。根据面料的质地和垂坠感,这似乎是第二张产品图片中展示的意大利美尔顿警官裤。