Prompt Router与Prompt Caching

Intelligent Prompt Routingprompt caching有助于降低生成式AI应用的成本和延迟:

Bedrock智能提示路由 – 在调用模型时,现在可以使用来自同一模型系列的基础模型(FMs) 组合来帮助优化质量和成本。例如,使用Anthropic的Claude 模型系列,Bedrock可以根据提示的复杂性智能地在Claude 3.5 Sonnet和Claude 3 Haiku之间路由请求。同样,Bedrock可以在Meta Llama 3.1 70B和8B之间路由请求。Prompt Routing预测哪个模型将为每个请求提供最佳性能,同时优化响应质量和成本。这对于客户服务助手等应用程序特别有用,其中简单查询可以由更小、更快、更具成本效益的模型处理,而复杂查询则路由到更强大的模型。智能提示路由可以在不影响准确性的情况下将成本降低高达30%。

Bedrock提示缓存 – 现在可以在多个模型调用中缓存Prompt中经常使用的上下文。这对于重复使用相同上下文的应用程序特别有价值,例如文档问答系统(用户对同一文档提出多个问题)或需要维护代码文件上下文的编码助手。缓存的上下文在每次访问后最多可保留5分钟。Amazon Bedrock中的提示缓存可以将支持模型的成本降低高达90%,延迟降低高达85%。

这些功能使降低延迟和平衡性能与成本效率变得更加容易。让我们看看如何在应用中使用它们。

在控制台中使用Bedrock Prompt Routers

Prompt Routers使用先进的提示匹配和模型理解技术来预测每个模型对每个请求的性能,优化响应质量和成本。

进入控制台页面:

image-20250225134431263

选择Anthropic prompt router:

image-20250225134516096

image-20250225134610188

从Prompt Router的配置中,看到它使用跨区域推理Claude 3.5 SonnetClaude 3 Haiku之间路由请求。

选择Open in Playground, 使用Prompt Router进行聊天,并输入以下:

帮我生成一个quick sort python代码

结果很快就提供了。选择右侧的新Router metrics图标,查看Prompt Router选择了哪个模型。在这种情况下,由于问题相当简单,使用了Claude 3 Haiku。

image-20250225135455906

向同一Prompt Router提出一个复杂的问题:

小明爸爸的妈妈的姨夫的孙子,小明该叫他什么

这次,Prompt Router选择了Claude 3.5 Sonnet:

image-20250225135728778

对于Meta Prompt Router,它使用Llama 3.1 70B和8B的跨区域推理,以70B模型作为后备:

image-20250225135841628

CLI使用Prompt Router

使用ListPromptRouters列出AWS区域中现有的提示路由:

aws bedrock list-prompt-routers

输出:

{
    "promptRouterSummaries": [
        {
            "promptRouterName": "Anthropic Prompt Router",
            "routingCriteria": {
                "responseQualityDifference": 0.0
            },
            "description": "Routes requests among models in the Claude family",
            "createdAt": "2024-11-20T00:00:00+00:00",
            "updatedAt": "2024-11-20T00:00:00+00:00",
            "promptRouterArn": "arn:aws:bedrock:us-west-2:145197526627:default-prompt-router/anthropic.claude:1",
            "models": [
                {
                    "modelArn": "arn:aws:bedrock:us-west-2:145197526627:inference-profile/us.anthropic.claude-3-haiku-20240307-v1:0"
                },
                {
                    "modelArn": "arn:aws:bedrock:us-west-2:145197526627:inference-profile/us.anthropic.claude-3-5-sonnet-20240620-v1:0"
                }
            ],
            "fallbackModel": {
                "modelArn": "arn:aws:bedrock:us-west-2:145197526627:inference-profile/us.anthropic.claude-3-5-sonnet-20240620-v1:0"
            },
            "status": "AVAILABLE",
            "type": "default"
        },
        {
            "promptRouterName": "Meta Prompt Router",
            "routingCriteria": {
                "responseQualityDifference": 0.0
            },
            "description": "Routes requests among models in the LLaMA family",
            "createdAt": "2024-11-20T00:00:00+00:00",
            "updatedAt": "2024-11-20T00:00:00+00:00",
            "promptRouterArn": "arn:aws:bedrock:us-west-2:145197526627:default-prompt-router/meta.llama:1",
            "models": [
                {
                    "modelArn": "arn:aws:bedrock:us-west-2:145197526627:inference-profile/us.meta.llama3-1-8b-instruct-v1:0"
                },
                {
                    "modelArn": "arn:aws:bedrock:us-west-2:145197526627:inference-profile/us.meta.llama3-1-70b-instruct-v1:0"
                }
            ],
            "fallbackModel": {
                "modelArn": "arn:aws:bedrock:us-west-2:145197526627:inference-profile/us.meta.llama3-1-70b-instruct-v1:0"
            },
            "status": "AVAILABLE",
            "type": "default"
        }
    ]
}

在进行API调用时, 将Prompt Router ARN设置为模型ID。例如:

aws bedrock-runtime converse \
    --model-id arn:aws:bedrock:us-east-1:123412341234:default-prompt-router/anthropic.claude:1 \
    --messages '[{ "role": "user", "content": [ { "text": "Alice has N brothers and she also has M sisters. How many sisters do Alices brothers have?" } ] }]' 

在输出中,使用Prompt Router的调用包含一个新的trace部分,告诉我们实际使用了哪个模型。在这种情况下,是Anthropic的Claude 3.5 Sonnet:

{
    "output": {
        "message": {
            "role": "assistant",
            "content": [
                {
                    "text": "To solve this problem, let's think it through step-by-step:\n\n1) First, we need to understand the relationships:\n   - Alice has N brothers\n   - Alice has M sisters\n\n2) Now, we need to consider who Alice's brothers' sisters are:\n   - Alice herself is a sister to all her brothers\n   - All of Alice's sisters are also sisters to Alice's brothers\n\n3) So, the total number of sisters that Alice's brothers have is:\n   - The number of Alice's sisters (M)\n   - Plus Alice herself (+1)\n\n4) Therefore, the answer can be expressed as: M + 1\n\nThus, Alice's brothers have M + 1 sisters."
                }
            ]
        }
    },
    . . .
    "trace": {
        "promptRouter": {
            "invokedModelId": "arn:aws:bedrock:us-east-1:123412341234:inference-profile/us.anthropic.claude-3-5-sonnet-20240620-v1:0"
        }
    }
}

image-20250225141223738

SDK使用Prompt Router

在调用模型时,将模型ID设置为ARN。例如:

import json
import boto3

bedrock_runtime = boto3.client(
    "bedrock-runtime",
    region_name="us-west-2",
)

MODEL_ID = "arn:aws:bedrock:us-west-2:145197526627:default-prompt-router/anthropic.claude:1" # 将这个进行替换,帐号id不同

user_message = "Describe the purpose of a 'hello world' program in one line."
messages = [
    {
        "role": "user",
        "content": [{"text": user_message}],
    }
]

streaming_response = bedrock_runtime.converse_stream(
    modelId=MODEL_ID,
    messages=messages,
)

for chunk in streaming_response["stream"]:
    if "contentBlockDelta" in chunk:
        text = chunk["contentBlockDelta"]["delta"]["text"]
        print(text, end="")
    if "messageStop" in chunk:
        print()
    if "metadata" in chunk:
        if "trace" in chunk["metadata"]:
            print(json.dumps(chunk['metadata']['trace'], indent=2))

这个脚本打印响应文本和响应元数据中trace的内容。对于这个简单的请求,Prompt Router选择了更快、更经济的模型:

image-20250225141826530

使用SDK进行prompt caching

以下内容在 2025.02.25测试会报错: Unknown parameter in messages[0].content[1]: "cachePoint", must be one of: text, image, document, video, toolUse, toolResult, guardContent, reasoningContent 因为还处于preview阶段,参考 https://github.com/boto/boto3/issues/4376 得做专门权限申请

可以使用Amazon Bedrock Converse API 进行提示缓存。当标记要缓存的内容并首次将其发送到模型时,模型会处理输入并将中间结果保存在缓存中。对于包含相同内容的后续请求,模型会从缓存中加载预处理的结果,显著降低成本和延迟。

可以通过以下步骤在应用中实现提示缓存:

  1. 确定经常重用的提示部分。
  2. 使用新的cachePoint块在消息列表中标记这些部分以进行缓存。
  3. 在响应元数据的usage部分监控缓存使用情况和延迟改进。

以下是在处理文档时实现提示缓存的示例。

从AWS网站下载三份PDF 。这些指南帮助选择适合您的AWS服务。

然后使用Python脚本提出关于这些文档的三个问题。在代码中,创建了一个converse()函数来处理与模型的对话。第一次调用该函数时,包含了文档列表和添加cachePoint块的标志。

import json

import boto3

MODEL_ID = "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
AWS_REGION = "us-west-2"

bedrock_runtime = boto3.client(
    "bedrock-runtime",
    region_name=AWS_REGION,
)

DOCS = [
    "bedrock-or-sagemaker.pdf",
    "generative-ai-on-aws-how-to-choose.pdf",
    "machine-learning-on-aws-how-to-choose.pdf",
]

messages = []


def converse(new_message, docs=[], cache=False):

    if len(messages) == 0 or messages[-1]["role"] != "user":
        messages.append({"role": "user", "content": []})

    for doc in docs:
        print(f"Adding document: {doc}")
        name, format = doc.rsplit('.', maxsplit=1)
        with open(doc, "rb") as f:
            bytes = f.read()
        messages[-1]["content"].append({
            "document": {
                "name": name,
                "format": format,
                "source": {"bytes": bytes},
            }
        })

    messages[-1]["content"].append({"text": new_message})

    if cache:
        messages[-1]["content"].append({"cachePoint": {"type": "default"}})

    response = bedrock_runtime.converse(
        modelId=MODEL_ID,
        messages=messages,
    )

    output_message = response["output"]["message"]
    response_text = output_message["content"][0]["text"]

    print("Response text:")
    print(response_text)

    print("Usage:")
    print(json.dumps(response["usage"], indent=2))

    messages.append(output_message)


converse("Compare AWS Trainium and AWS Inferentia in 20 words or less.", docs=DOCS, cache=True)
converse("Compare Amazon Textract and Amazon Transcribe in 20 words or less.")
converse("Compare Amazon Q Business and Amazon Q Developer in 20 words or less.")

对于每次调用,脚本打印响应和usage计数器。

Adding document: bedrock-or-sagemaker.pdf
Adding document: generative-ai-on-aws-how-to-choose.pdf
Adding document: machine-learning-on-aws-how-to-choose.pdf
Response text:
AWS Trainium is optimized for machine learning training, while AWS Inferentia is designed for low-cost, high-performance machine learning inference.
Usage:
{
  "inputTokens": 4,
  "outputTokens": 34,
  "totalTokens": 29879,
  "cacheReadInputTokenCount": 0,
  "cacheWriteInputTokenCount": 29841
}
Response text:
Amazon Textract extracts text and data from documents, while Amazon Transcribe converts speech to text from audio or video files.
Usage:
{
  "inputTokens": 59,
  "outputTokens": 30,
  "totalTokens": 29930,
  "cacheReadInputTokenCount": 29841,
  "cacheWriteInputTokenCount": 0
}
Response text:
Amazon Q Business answers questions using enterprise data, while Amazon Q Developer assists with building and operating AWS applications and services.
Usage:
{
  "inputTokens": 108,
  "outputTokens": 26,
  "totalTokens": 29975,
  "cacheReadInputTokenCount": 29841,
  "cacheWriteInputTokenCount": 0
}

响应的usage部分包含两个新Counter:cacheReadInputTokenCountcacheWriteInputTokenCount。一次调用的令牌总数是输入和输出令牌加上读取和写入缓存的令牌的总和。

每次调用处理一个消息列表。第一次调用中的消息包含文档、第一个问题和缓存点。由于缓存点之前的消息当前不在缓存中,它们被写入缓存。根据usage计数器,29,841个令牌已写入缓存。

"cacheWriteInputTokenCount": 29841

对于下一次调用,前一个响应和新问题被附加到消息列表中。cachePoint之前的消息没有更改,并在缓存中找到。

正如预期的那样,我们可以从usage计数器看出,之前写入的相同数量的令牌现在从缓存中读取。

"cacheReadInputTokenCount": 29841

在测试中,与第一次相比,下一次调用完成的时间减少了55%。根据用例(例如,使用更多缓存内容),提示缓存可以将延迟提高高达85%。

根据模型,可以在消息列表中设置多个缓存点。要为我们的用例找到合适的缓存点,请尝试不同的配置并查看对报告的使用情况的影响。

使用prompt caching时,内容最多缓存5分钟,每次缓存命中都会重置此倒计时。

这些新功能使构建具有成本效益和高性能的生成式AI应用程序变得更加容易。通过智能路由请求和缓存经常使用的内容,可以显著降低成本,同时保持甚至提高应用程序性能。