亚马逊AWS官方博客

使用 Amazon Athena 对 Bedrock 日志进行查询与成本分析

服务介绍

Amazon Bedrock 是一项完全托管的服务,使用单个 API 提供来自 AI21 Labs、Anthropic、Cohere、Meta、Stability AI 和 Amazon 等领先人工智能公司的高性能基础模型,以及构建生成式人工智能应用程序所需的一系列广泛功能,在维护隐私和安全的同时简化开发。借助 Amazon Bedrock 的全面功能,您可以轻松尝试各种热门 FM,使用微调和检索增强生成等技术利用您的数据对其进行私人定制,并创建可执行复杂业务任务的托管代理,所有这些都无需编写任何代码。由于 Amazon Bedrock 是无服务器的,因此您无需管理任何基础设施,并且可以使用已经熟悉的亚马逊云科技 服务将生成式人工智能功能安全地集成和部署到您的应用程序中。

Amazon Athena 是一种交互式查询服务,让您能够轻松使用标准 SQL 直接分析 Amazon Simple Storage Service (Amazon S3) 中的数据。只需在服务界面中执行几项操作,即可将 Athena 指向 Amazon S3 中存储的数据,并开始使用标准 SQL 运行临时查询,然后在几秒钟内获得结果。

在这篇 blog 中,我们以 Amazon Bedrock 的服务调用日志为例,阐述 Amazon Athena 对于云上服务的日志结构化建表与查询流程,并获取 cost_input_token_cnt 与 cost_output_token_cnt 两个字段,可以快速帮助 Bedrock 用户计算服务调用的费用,并以日期与小时为分组进行指标的统计。

开启 Bedrock 日志

首先,我们在 Amazon Bedrock 的控制台上开启模型调用日志,选择要开启日志的日志类别以及日志的存储目的地,这里我们选择将模型调用日志输出到 Amazon S3 中,如下图所示。

在 Amazon Athena 中建立日志表

开启 Amazon Bedrock 的模型调用日志后,我们将会在指定的 Amazon S3 路径中看到 Bedrock 的模型调用日志。下载其中的日志文件后,可以看到具体的日志内容。每条日志是一次完整的调用记录,以 JSON 对象的形式进行记录,JSON 对象中包括 schemaType,schemaVersion,timestamp,accountId,region,requestId,operation,modelId,input,output 字段,分别表示 schema 类型,schema 版本,调用时间戳,账号 Id,调用的 AWS region,请求 Id,调用方法,使用的模型 Id,调用的输入以及调用的输出。其中输入 input,输出 output 均为嵌套的 JSON  对象字段,重要的包括 inputBodyJson,inputTokenCount,outputBodyJson,outputTokenCount 字段,分别表示输入内容 JSon,输入的 Token 的数量,输出内容 JSon,输出 Token 的数量。单条模型调用日志格式如下所示:

{
    "schemaType": "ModelInvocationLog",
    "schemaVersion": "1.0",
    "timestamp": "2023-11-01T05:47:40Z",
    "accountId": "399xxxxxx424",
    "region": "us-west-2",
    "requestId": "a884876b-xxxxx-4fa0-9133-xxxxxxxxxxxx",
    "operation": "InvokeModelWithResponseStream",
    "modelId": "anthropic.claude-v2",
    "input": {
        "inputContentType": "application/json",
        "inputBodyJson": {
            "prompt": "\n\nHuman: 如何构建论文框架?\n\nAssistant:",
            "max_tokens_to_sample": 99982,
            "temperature": 1,
            "top_p": 0.8
        },
        "inputTokenCount": 19
    },
    "output": {
        "outputContentType": "application/json",
        "outputBodyJson": [{
            "completion": " "
        }],
        "outputTokenCount": 429
    }
}

另外,Amazon Bedrock 转存到 Amazon S3 的日志目录层次较深,形式如 S3://bucket/prefix/AWSLogs/YourAccount Id/BedrockModelInvocationLogs/region/year/month/day/hour,日志目录是按区域、年、月、日、时这几个维度来组织的。具体如下所示:

在了解了 Amazon Bedrock 模型调用日志的格式以及日志文件组织形式后,我们就可以对日志数据采用 Amazon Athena 来进行数据建模。考虑到 Bedrock 的日志是以小时为单位来对日志做轮转的,结合对数据查询的要求,可以采用日期和小时这两个维度来进行数据分区。由于 Bedrock 自动按小时来组织日志数据,日志数据建模时,需要考虑数据分区的自动更新问题,也就是说需要让 Athena 感知到数据分析元数据信息。

对于分区信息的更新,可以采用基于事件的方式来动态更新数据的分区信息,当 Amazon S3 中产生了新的日期或者小时日志目录时自动更新分区信息,这种方式可以比较精确的控制分区数量。但是考虑到面向终端用户的应用,应用都会实时在线,基本上每个小时都会有日志产生,并且这种的日志产生的模式是固定的,并且在长期会积累较多的分区信息。基于此,可以使用 Amazon Athena 的 Partition Projection 特性来自动化分区管理,并且加速查询效率。

使用 Athena Partition Projection 进行数据建模

根据对 Bedrock 模型调用日志的分析,我们使用 Amazon Athena 建立日志数据表,SQL 如下:

CREATE EXTERNAL TABLE `bedrock_log`(
  `schematype` string, 
  `schemaversion` string, 
  `timestamp` string, 
  `accountid` string, 
  `region` string, 
  `requestid` string, 
  `operation` string, 
  `modelid` string, 
  `input` struct<inputcontenttype:string,inputbodyjson:struct<prompt:string,max_tokens_to_sample:int,temperature:double,top_k:int,top_p:double,stop_sequences:array<string>,anthropic_version:string>,inputtokencount:int>, 
  `output` struct<outputcontenttype:string,outputbodyjson:array<struct<completion:string,stop_reason:string,stop:string>>,outputtokencount:int>)
PARTITIONED BY(dt string, h string)
ROW FORMAT SERDE 
  'org.openx.data.jsonserde.JsonSerDe' 
WITH SERDEPROPERTIES ( 
  'paths'='accountId,input,modelId,operation,output,region,requestId,schemaType,schemaVersion,timestamp') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://bucket/prefix/AWSLogs/YourAccountId/BedrockModelInvocationLogs/YourRegion'
TBLPROPERTIES (
  'classification'='json', 
  'compressionType'='gzip', 
  'exclusions'='[\"s3://bucket/prefix/AWSLogs/YourAccountId/BedrockModelInvocationLogs/**/data/**\",\"s3://bucket/prefix/AWSLogs/YourAccountId/BedrockModelInvocationLogs/**/amazon-bedrock-logs-permission-check\"]', 
  'projection.enabled' = 'true',
  'projection.dt.type' = 'date',
  'projection.dt.format' = 'yyyy/MM/dd',
  'projection.dt.range' = '2023/11/03,NOW',
  'projection.dt.interval' = '1',
  'projection.dt.interval.unit' = 'DAYS',
  'projection.h.type' = 'enum',
  'projection.h.values' = '00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23',
  'storage.location.template' = 's3://bucket/prefix/AWSLogs/YourAccountId/BedrockModelInvocationLogs/YourRegion/${dt}/${h}/',
  'typeOfData'='file');

在 SQL 中,表中的各个字段映射到日志 JSON 对象中的各个字段,input 和 output 字段采用 struct 类型映射嵌套的 JSON 对象,并指定日期 dt 和小时 h 这两个分区字段。通过 LOCATION 指定日志数据的路径,这个路径指定到 Region 这个层级即可。在 TBLPROPERTIES 中,设置‘projection.enabled’属性为‘true’来开启表的分区映射功能,并且分别指定 dt 和 h 这两个分区字段的类型以及对应的配置,其中 dt 映射为‘date’日期类型,日期格式为‘yyyyMMdd’,并设定日期的范围以及日期间隔,h 为枚举类型,并给出所有的值。关于 Athena 的 partition projection 配置可以参考服务文档。最后,由于日志数据的分区格式不是默认的 Hive 分区格式,需要设置‘storage.location.template’属性来告知 Athena 底层数据的存放形式,具体的设置方法可以参考相关文档。在 Athena 中建完表后,即可对数据进行查询、统计和分析。

使用 Amazon Athena 进行数据查询与成本分析

Bedrock price 页面(https://aws.amazon.com/bedrock/pricing/)提供了多种 LLM 模型调用计费模式,其中 Claude On-Demand 计费单价如下:

A B C
1 Anthropic models Price for 1000 input tokens Price for 1000 output tokens
2 Claude Instant $0 $0.01
3 Claude $0.01 $0.03

此外 token count 不足 100 按照 100 计算。基于以上信息,我们可以查询某天(或某时)模型调用明细,包括每次的实际输入 Token 数量、计费输入 Token 数量、实际输出 Token 数量、计费输出 Token 数量:

select schematype,
    "timestamp",
    accountid,
    region,
    requestid,
    operation,
    modelid,
    input.inputtokencount as real_input_token_cnt,
    (case when input.inputtokencount < 100 then 100 else input.inputtokencount end) as cost_input_token_cnt,
    output.outputtokencount as real_output_token_cnt,
    (case when output.outputtokencount < 100 then 100 else output.outputtokencount end) as cost_output_token_cnt
from bedrock_log
where dt = '2023/11/03'

比如想查看每个模型在当天总的输入 Token 数、总的计费输入 Token 数、总的输出 Token 数、总的计费输出 Token 数,SQL 如下:

select 
    modelid,
    sum(input.inputtokencount) as total_input_tokens,
    sum(
        case
            when input.inputtokencount < 100 then 100
            else input.inputtokencount
        end
    ) as total_cost_input_tokens,
    sum(output.outputtokencount) as total_output_tokens,
    sum(
        case
            when output.outputtokencount < 100 then 100
            else output.outputtokencount
        end
    ) as total_cost_output_tokens
from bedrock_log
where dt = '2023/11/03'
group by modelId

输出结果如下:

数据建模后,除了可以通过 Athena 做交互式统计查询、分析外,还可以通过 Athena 对接 Amazon QuickSight 或者 Tableau 等 BI 工具进行数据报表展示以获得更好的使用体验。

总结

在本篇 blog 中,我们以 Bedrock 为例,阐述了 Amazon Athena 这一 Serverless 服务进行云上日志结构化建表与查询,并提取 inputtokencount 与 outputtokencount 两个字段来帮助 Bedrock 用户计算服务调用的费用。如果您有更多关于亚马逊云科技的分析与 AI 服务的问题,请随时联系我们。

本篇作者

赵安蓓

AWS 解决方案架构师,负责基于 AWS 云平台的解决方案咨询和设计,机器学习 TFC 成员。在数据处理与建模领域有着丰富的实践经验,特别关注医疗领域的机器学习工程化与运用。

程亮

AWS 解决方案架构师,负责基于 AWS 云平台的解决方案咨询和设计. 有多年的互联网软件研发、系统架构设计及大数据产品开发经验。