注意:本文已经针对2024年3月初新发布的Claude 3进行了更新。
本文介绍了Amazon Bedrock服务的初始化,如何开始使用Claude模型,并讲解了Prompt Engineer调优的最佳实践,以及几个简单场景样例代码。
本文分成上下两篇:
- 上篇:Bedrock配置篇(即本篇)
- 下篇:Prompt调优篇
一、背景
Amazon Bedrock是托管的大模型服务,可通过API调用来自多家公司的基础模型(Foundation Model, 以下简称FM),包括AI21 Labs、Anthropic、Cohere、Meta、Stability AI以及Amazon等。使用Amazon Bedrock可通过模型微调(Fine-tune)和检索增强生成(Retrieval Augmented Generation,以下简称RAG)等技术实现更好的检索效果。由于Amazon Bedrock是无服务器的,因此您无需管理EC2虚拟机、GPU等基础设施,可使用多种开发语言从应用程序中调用,使用场景包括文本生成、文本摘要、图像生成、对话、虚拟助手、知识库、向量转换等。
在大模型的选择上,除了大家熟知的Meta(Facebook)的Llama2等模型之外,Bedrock提供了来自Anthropic的Claude模型,这是与OpenAI处于竞争地位的大模型。在2023年9月,Amazon向Anthropic投资40亿美金并且达成合作。
在模型版本选择上,Claude 3的版本对应如下:
- Claude 3 Opus 对标GPT的下一代(截止2024年3月12日尚未发布),好于现有GPT4 Turbo
- Claude 3 Sonnet在多个第三方评测中,与GPT4 Turbo互有胜负,但比GPT4-Turbo便宜
- Claude 3 Haiku对表对标GPT3.5 Turbo,比3.5效果好很多
Claude 2的版本对应如下:
- Claude V2.1 对标GPT4 Trubo
- Claude Instant 对标GPT 3.5 Turbo,Titan Embeddings G1对标OpenAI的text-embedding-ada-002。他们支持的Token、相应的Cost都是在同等体量。
总结以上模型选择:一般文本生成应用场景,选用Claude 3 Sonnet性价比最高(与GPT4T互有胜负且便宜)。对于复杂逻辑例如包含数学题等,选择Claude 3 Opus效果最佳(超越GPT4T但贵)。对于访问量超大的内容审核等,选择最便宜的Claude 3 Haiku(比GPT3.5T更好且便宜)。
下边开始介绍使用。
二、申请模型访问权限并在AWS控制台上使用
注:以下操作以具备AWS账号AdministratorAccess的账号来操作。
1、确认联系信息为海外地址
申请Bedrock服务中的Claude大模型要求必须有AWS海外账户。根据Claude模型的EULA用户协议,使用Claude模型的公司需要是海外实体。因此这里申请时候,账户的联系信息登记的支付信息(Billing Address)等信息都应为海外地址,不能是中国大陆地址也不能是香港地址。如果之前注册账号的时候,使用了中国大陆地址注册或使用香港地址,则可以在账户信息页面编辑修改,使用公司的海外营业机构地址。比如改为贵公司在新加坡的门店、当地员工所在办公地址。
此处修改还涉及不同国家税费的问题,请咨询为您服务的客户经理和商务人员。
从右上角进入自己账户的Billing and Cost Managment
界面。
向下移动页面中,找到联系信息,编辑他们,确保使用海外分支机构的地址和联系人。
2、申请模型权限
切换要操作的Region到特定区域,例如本文为us-west-2
美西2俄勒冈区域。
接下来进入Bedrock服务界面,可看到其中的模型如果还没申请,状态就是Available to request
。点击右上角的Model access
按钮,点击右侧的Manage model access
按钮发起申请。
推荐申请的模型包括:
- Claude(对标OpenAI gpt-4-1106-preview4)
- Claude Instant(对标OpenAI gpt-3.5-turbo-1106)
- Claude 3 Sonnet(2024年3月最新大模型,效果好于GPT4)
- Titan Embeddings G1 – Text 对标OpenAI的text-embedding-ada-002
- Titan Multimodal Embeddings G1
申请时候要填写的表单格式如下截图。
填写以上用户场景信息。通过审核可能需要几分钟时间。然后即可看到如下模型的状态变为已授权。如下截图。
获得模型许可授权后,可以通过左侧的Playgrounds菜单,进入图形界面测试。点击Select model
选择模型。如下截图。
在选择模型的清单中,点击Anthropic
公司,选择Claude 3 Sonnet或者Claude V2.1,最大允许传入Context是200K的。点击Apply
,即可在界面上发起交互。如下截图。
现在可以在控制台上使用了!
3、新模型申请权限的说明
需要注意的是,如果您以前只是申请过Claude2模型的权限,那么Claude3模型发布后,您需要重新给Claude3模型申请权限,才可以继续使用。如果您之前申请了Claude 3 Sonnet模型,那么当新的Claude 3 Haiku模型发布后,是需要重新申请权限的。而同一个名称的模型,如果只是尾号小版本迭代,是不需要重新申请的。
三、配置IAM和AKSK通过代码访问Bedrock API
Bedrock与OpenAI的ChatGPT调用认证方式不同。ChatGPT因为是独立的SaaS服务,其身份认证只依靠HTTPS的Header。Bedrock是属于整个AWS体系中的一个服务,因此其有着标准的Access Key/Secret Key的认证方式。此外,还需要匹配的IAM Policy才可以调用。下面进行配置。
1、创建API调用需要的IAM Policy
注意:以前配置的最小权限仅是调用Bedrock和Claude模型所需要的权限。如果您要使用Bedrock知识库,那么还涉及S3存储桶、OpenSearch向量数据库等服务,这时候建议您赋予Bedrock-FullAccess权限,调试更简单。调试后再适当缩减权限。
进入IAM服务,点击左侧Policy
策略菜单,点击右上角创建策略
按钮。
在向导第一步,策略编辑器位置,不使用可视化模式,而是点击JSON
按钮,直接粘贴策略。如下截图。
策略如下:
{
"Version": "2012-10-17",
"Statement": {
"Sid": "bedrock",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:*::foundation-model/*"
}
}
点击下一步继续,在策略名称位置,输入名称bedrock-runtime
,记住这个名称,稍后将会使用。如下截图。
创建策略完成。
2、创建API所属的IAM用户并绑定IAM Policy
进入IAM服务,点击左侧菜单Users
用户,点击右上角新建User按钮。如下截图。
在新建用户的向导中,为用户起名叫做bedrock-runtime
,不需要选中向用户提供 AWS 管理控制台的访问权限
,因为是API调用,不需要登录AWS控制台,所以不需要给这个权限。然后点击下一步继续,。如下截图。
在设置权限界面,点击右侧直接附加策略
按钮,然后在下方权限策略的搜索框中,输入上一步创建的Policy名叫bedrock-runtime
,下方即可过滤出来。选中这个策略,点击下一步继续。如下截图。
创建用户完成。
3、为使用者创建AKSK
接下来为用户创建AKSK密钥。从IAM用户中,找到刚才的用户,点击安全凭证标签页。如下截图。
在安全凭证标签页中,将页面向下移动,来到创建访问密钥
部分。点击创建访问密钥
。如下截图。
选择使用场景是命令行界面(CLI)
,并点击下方的确认,我理解上述建议,并希望继续创建访问密钥
。然后点击右下角的下一步按钮。如下截图。
输入密钥的标签,例如取名bedrock-runtime
。点击右下角的创建访问密钥
按钮。如下截图。
创建密钥完成。请注意,密钥只显示一次,如果没有复制下来,或者没有下载CSV文件,则密钥不再显示,只能重新生成一个新的密钥。如下截图。
点击已完成按钮完成密钥创建。
四、准备通过API调用Bedrock服务和Claude模型所需要的AKSK
调用Bedrock使用的Access Key/Secret Key是与调用其他AWS服务的认证通用的,因此其配置过程可通过安装AWSCLI进行快速配置,也可以手工配置让各种编程语言的SDK识别到这个Key。
从安全角度考虑,不推荐在代码中硬编码写入密钥,推荐将密钥配置在本机的home目录下。
1、通过AWSCLI安装配置密钥(可选)
下载AWSCLI,并安装。
安装后运行aws configure
,依次输入Access Key,Secret Key,调用的Region(本次实验为us-west-2),最后一步默认输出格式,填写JSON即可。
2、手工配置Access Key/Secret Key
如果上一步通过AWSCLI配置好了密钥,那么本步骤可以跳过。
(1) Linux系统
Linux系统放置AKSK到Home目录下特定位置
创建~/.aws/credentials
文件,内容如下:
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
创建~/.aws/config
文件,请注意使用特定的Region,例如文本前边步骤申请Model Access时候,选择的是us-west-2
区域。内容如下:
[default]
region=us-west-2
保存退出。
(2) Windows系统
创建C:\Users\%USERNAME%\.aws\credentials
文件。其中%USERNAME%
是当前Windows使用的用户名,另外.aws
目录是开头带有一个圆点表示隐藏目录。内容如下:
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
创建C:\Users\%USERNAME%\.aws\config
文件。其中%USERNAME%
是当前Windows使用的用户名,另外.aws
目录是开头带有一个圆点表示隐藏目录。请注意使用特定的Region,例如文本前边步骤申请Model Access时候,选择的是us-west-2
区域。内容如下:
[default]
region=us-west-2
保存退出。
3、如果没有配置AKSK时候在代码中写入密钥的方式
如果没有按照上述过程配置的home目录下的密钥,那么可以在代码中硬编码写入密钥,只是这种方式存在安全隐患,不推荐使用。代码中硬编码写入密钥的方法如下:
session = boto3.Session(
aws_access_key_id="xxxxxxxxxxxxxxx",
aws_secret_access_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
region_name="us-west-2"
)
这种方法是有安全隐患的,因为代码会被上传到Git(包括公司私有Git),会造成密钥可见,因此不推荐。
4、安装对应语言的SDK(以Python为例)
pip install boto3 json
5、确认可用的模型ID
在配置好AWSCLI后,执行如下命令:
aws bedrock list-foundation-models --region=us-west-2 --by-provider anthropic --query "modelSummaries[*].modelId"
即可返回所有Claude模型。例如返回结果如下:
[
"anthropic.claude-instant-v1:2:100k",
"anthropic.claude-instant-v1",
"anthropic.claude-v2:0:18k",
"anthropic.claude-v2:0:100k",
"anthropic.claude-v2:1:18k",
"anthropic.claude-v2:1:200k",
"anthropic.claude-v2:1",
"anthropic.claude-v2",
"anthropic.claude-3-sonnet-20240229-v1:0",
"anthropic.claude-3-haiku-20240307-v1:0"
]
接下来继续了解模型调用API并编写测试代码。
五、了解Claude模型的几种调用方式并编写代码调用API
1、直接调用Claude官方API和调用Bedrock API之间的区别
Claude模型的开发者Anthropic官方提供了SaaS方式的模型服务,使用者需要在Anthropic的官网https://console.anthropic.com/上注册,然后使用Anthropic官方API调用(当然账单也是付给Anthropic和AWS无关)。Python代码样例如下:
# 使用Anthropic官方的Claude模型的SDK的Python代码样例
import anthropic
from anthropic import HUMAN_PROMPT, AI_PROMPT
anthropic.Anthropic().completions.create(
model="claude-2.1",
max_tokens_to_sample=1024,
prompt=f"{HUMAN_PROMPT} Hello, Claude{AI_PROMPT}",
)
运行以上代码的前提是为Python安装Anthropic的库,执行pip install -U anthropic
即可安装。以上代码可以看出,程序与AWS服务不发生任何关系,API调用是直接发送给Anthropic官方的Endpoint进行调用。在直接调用Anthropic这种使用场景下,除了安装anthropic的依赖库,也可以直接构建POST请求的方式来提交访问,详情可参考Anthropic官网文档。
在Amazon Bedrock上运行Claude模型有很多优势,您可以结合AWS的多种产品,包括Bedrock知识库、Bedrock Agent、向量数据库、S3数据湖、Lambda函数计算、API Gateway应用网关等构建完整的应用体系。本文介绍的是在Amazon Bedrock服务上使用Anthropic的Claude模型。
Amazon Bedrock提供了多种大模型服务,Claude只是其中一种模型。因此,Bedrock的API是进行了封装,包括身份认证、模型请求等都通过Amazon Bedrock进行发送,程序代码调用的Endpoint也是AWS的Endpoint,因此程序代码上的调用方法也和直接Claude有区别。以下是调用Bedrock上Claude3模型的Python代码样例。
# 使用Amazon Bedrock提供的Claude模型的Python代码样例
import boto3
import json
bedrock = boto3.client(service_name="bedrock-runtime")
body = json.dumps({
"max_tokens": 256,
"messages": [{"role": "user", "content": "Hello, world"}],
"anthropic_version": "bedrock-2023-05-31"
})
response = bedrock.invoke_model(body=body, modelId="anthropic.claude-3-sonnet-20240229-v1:0")
response_body = json.loads(response.get("body").read())
print(response_body.get("content"))
运行以上代码的前提是为Python安装AWS SDK的库,执行pip install -U boto3
,需要确保boto3版本大于1.28.59
。以上代码可以看出,程序与Anthropic官方不发生任何关系,API调用是直接发送给Amazon Bedrock的Endpoint进行调用,且身份认证也是通过AWS SDK,即通过Access Key/Secret Key来认证。除了使用AWS SDK之外,还可以直接构建HTTPS请求以POST方式提交给Amazon Bedrock终端节点,这种访问方式的文档请参考这里。直接构建POST请求的方式属于底层调用,相对麻烦,因此不推荐,首选使用AWS SDK的方式。除了Python之外,其他主要开发语言都可以加载对应的SDK后调用Bedrock。
本文后续所有文档都以调用Bedrock为例,不再描述使用Claude官方API。
2、单次消息模式和Streaming模式
普通的单次消息模式,发送一个较长的Prompt和素材提交给大模型,大模型再返回一段较长的生成式内容,可能需要数秒钟。在单词消息模式下,程序需要等待Bedrock和Claude返回完整消息后,才进行后续处理,如果返回的信息有成百上千字(输出Token多),那么等待时间给用户的反馈非常不好。
降低模型响应时间的一个办法是使用Streaming模式。在Stream模式下,大模型在生成很长内容的时候随时返回,Streaming的模式将使得程序随时能显示出来。这样从用户交互的角度,不需要等待很长时间才一下子看到全部对话,而是生成一行返回一行,用户感受到大模型仿佛是人类一样逐渐的说出来,从交互体验上非常友好。Streaming的原理是SSE(Server-Sent Events),详情可参考这里。
单次消息和Streaming模式是两个API,在Claude3上分别叫做InvokeModel
(API文档在这里)和InvokeModelWithResponseStream
(API文档在这里)。
本文后续会针对这两个模式分别给出例子。
3、从Claude2的Text Completion切换到Claude3的Message改变与PE部分的变化
本小节针对已经在使用Claude2的用户,切换到Claude3时候要做的调整。
Claude2模型是2023年发布的,Claude3在2024年发布,二者在API调用上所有差别。Claude2支持旧的API Text Completion
(文档在这里),也支持新的API Messages
(文档在这里)。而Claude3只使用新的Message
。因此从Claude2切换到Claude3时候,需要对代码进行进行一定的改动。
Claude2的使用Text Completion
时候提交的prompt格式如下:
prompt = "\n\nHuman: Hello there\n\nAssistant: Hi, I'm Claude. How can I help?\n\nHuman: Can you explain Glycolysis to me?\n\nAssistant:"
Claude3的使用Message
的API时候提交的prompt格式如下:
messages = [
{"role": "user", "content": "Hello there."},
{"role": "assistant", "content": "Hi, I'm Claude. How can I help?"},
{"role": "user", "content": "Can you explain Glycolysis to me?"},
]
由此可以看到,其API构成稍微有些差别。您需要使用message API来调用Claude3。
在Prompt Enginering方面,Claude2因为输入的整个Prompt都是Text文本,因此需要通过标记\n\nHuman
和\n\nAssistant
的方式来表明哪些是人类的输入和哪些是大语言模型的。在Claude3模型的调用中,改用Message API后,是以JSON的方式来输入。其中又使用role
标签且值是user
来表示这部分信息是人类的输入,由此就不需要再加上\n\nHuman
标签了。
除此了Message API的区别之外,大部分Claude2使用的Prompt编写方式在Claude3上继续可用。
4、调用Claude3的单次消息模式的Python代码样例
注:以下代码使用新的Message API的方式。
import boto3
import json
model = "anthropic.claude-3-sonnet-20240229-v1:0"
message = 'Write an email from Bob, Customer Service Manager, to the customer "John Doe" who provided negative feedback on the service provided by our customer support engineer'
session = boto3.Session(
region_name="us-west-2"
)
bedrock = session.client(service_name="bedrock-runtime")
body = json.dumps({
"max_tokens": 500,
"messages": [{"role": "user", "content": message}],
"anthropic_version": "bedrock-2023-05-31"
})
response = bedrock.invoke_model(body=body, modelId=model)
# response content
response_body = json.loads(response.get("body").read())
### get text from response
text = response_body.get("content")
for item in text:
if 'text' in item:
print(item['text'])
执行后,等待数秒会看到完整输出,即按照Prompt要求,模型以客户服务经理Bob的身份写给客户John Doe的关于差评的一封道歉信。
5、调用Claude3的Streaming模式
根据前文介绍,为了改善较长token输出时候的体验,可以用streaming模式,模拟出和人类交互的一段一段的输出的感觉。
注:以下代码使用新的Message API的方式。
import boto3
import json
model = "anthropic.claude-3-sonnet-20240229-v1:0"
message = 'Write an email from Bob, Customer Service Manager, to the customer "John Doe" who provided negative feedback on the service provided by our customer support engineer'
session = boto3.Session(
region_name="us-west-2"
)
bedrock = session.client(service_name="bedrock-runtime")
body = json.dumps({
"max_tokens": 500,
"messages": [{"role": "user", "content": message}],
"anthropic_version": "bedrock-2023-05-31"
})
response = bedrock.invoke_model_with_response_stream(body=body, modelId=model)
# response content
for event in response.get("body"):
chunk = json.loads(event["chunk"]["bytes"])
if chunk['type'] == 'content_block_delta':
if chunk['delta']['type'] == 'text_delta':
print(chunk['delta']['text'], end="")
执行后,会在Console上以Streaming流式的方式逐句输出,即按照Prompt要求,模型以客户服务经理Bob的身份写给客户John Doe的关于差评的一封道歉信。
6、Claude 3的多模态调用(图片内容理解)
Claude 3的三个版本均为多模态大模型,支持输入图片可理解其中的内容。这里准备一个example.jpg作为测试图像,然后准备代码如下:
import boto3
import json
import base64
model = "anthropic.claude-3-sonnet-20240229-v1:0"
# input image as base64 string
file_name = "example.jpg"
with open(file_name, "rb") as image_file:
image_bytes = image_file.read()
image_string = base64.b64encode(image_bytes).decode('utf8')
# Claude 3 multi-modal message
message = [
{
"type": "text",
"text": "使用中文描述下这张图片,在100字之内",
},
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_string
}
}
]
session = boto3.Session(
region_name="us-west-2"
)
bedrock = session.client(service_name="bedrock-runtime")
body = json.dumps({
"max_tokens": 500,
"messages": [{
"role": "user",
"content": message
}],
"anthropic_version": "bedrock-2023-05-31"
})
response = bedrock.invoke_model(body=body, modelId=model)
# response content
response_body = json.loads(response.get("body").read())
# print(response_body.get("content"))
### get text from response
text = response_body.get("content")
for item in text:
if 'text' in item:
print(item['text'])
返回结果如下:
这张照片捕捉了一只正在小憩的猫咪。它蜷缩着身体,闭着眼睛安详地睡着。猫咪的毛发条纹分明,背景呈现出朦胧的蓝紫色调,营造出一种梦幻般的氛围。整张照片构图简单、细节清晰,展现了一种安静、祥和的美感。
由此看到多模态已经识别了图片内容。
7、使用Claude 2和Claude Instant模型的单次消息调用
注:以下代码使用Claude2旧的Text Completion的方式,需要在Prompt中使用\n\nHuman
来标记人类输入。
import boto3
import json
model = "anthropic.claude-v2:1"
prompt = '\n\nHuman: Write an email from Bob, Customer Service Manager, to the customer "John Doe" who provided negative feedback on the service provided by our customer support engineer\n\nAssistant: Here is a draft:\n'
session = boto3.Session(
region_name="us-west-2"
)
brt = session.client('bedrock-runtime')
body = json.dumps({"prompt": prompt, 'max_tokens_to_sample': 4000 })
response = brt.invoke_model(
modelId='anthropic.claude-instant-v1',
body=body
)
response_body = json.loads(response["body"].read())
completion = response_body["completion"]
print(completion)
执行后,等待数秒会看到完整输出,即按照Prompt要求,模型以客户服务经理Bob的身份写给客户John Doe的关于差评的一封道歉信。
8、使用Claude 2和Claude Instant模型Streaming模式调用
注:以下代码使用Claude2旧的Text Completion的方式,需要在Prompt中使用\n\nHuman
来标记人类输入。
import boto3
import json
model = "anthropic.claude-v2:1"
prompt = '\n\nHuman: Write an email from Bob, Customer Service Manager, to the customer "John Doe" who provided negative feedback on the service provided by our customer support engineer\n\nAssistant: Here is a draft:\n'
session = boto3.Session(
region_name="us-west-2"
)
brt = session.client('bedrock-runtime')
body = json.dumps({"prompt": prompt, 'max_tokens_to_sample': 4000 })
response = brt.invoke_model_with_response_stream(
modelId=model,
body=body
)
stream = response.get('body')
i=1
output = []
if stream:
for event in stream:
chunk = event.get('chunk')
if chunk:
chunk_obj = json.loads(chunk.get('bytes').decode()) #print(f'{chunk_obj}')
text = chunk_obj['completion']
output.append(text)
print(f'{text}')
i+=1
执行后,会在Console上以Streaming流式的方式逐句输出,即按照Prompt要求,模型以客户服务经理Bob的身份写给客户John Doe的关于差评的一封道歉信。
六、Claude Prompt Engineering 调优
请参考本文下篇。
七、参考文档
Anthropic官方对Bedrock API的介绍
https://docs.anthropic.com/claude/reference/claude-on-amazon-bedrock
AWS Bedrock的API例子(多种开发语言)
Claude 3 Streaming API
https://docs.anthropic.com/claude/reference/messages-streaming
bedrock-claude-streamlit 代码例子(Python)
https://github.com/terrificdm/bedrock-claude-streamlit/blob/main/bedrock_streamlit.py
Amazon Bedrock Claude3 Workshop 中文版