【阅读原文】戳:使用阿里云服务网格高效管理LLM流量:(二)流量可观测
良好的可观测能力是构建一个高效、稳定的分布式应用的前提,在LLM应用中更是如此。纵观很多复杂系统的发展历程后不难发现:标准化以及分层是时间大浪淘沙留下来的经典方案。起初开发人员需要手动编写代码,自行控制透出可观测信息;之后这些可观测逻辑被下沉到开发框架中,由开发框架透出一部分通用信息;服务网格出现之后,越来越多的通用逻辑被下沉到的基础设施层,此时开发人员可以更少的关注开发框架,更加专注于业务逻辑。
基于这样的理念,在LLM快速发展的今天,我们在服务网格中实现了基础设施级别的LLM流量管理以及可观测功能。您无需依赖于特定的语言与SDK,也不需要改变应用的调用方式。只需要简单配置就可以实现透明无感的流量路由与可观测。LLM提供商一般通过请求的模型以及Token数来进行计费,全局统一的可观测能力不仅是业务稳定的基石,更是成本洞察与优化的前提。本文将展示如何利用服务网格ASM来实现大模型流量的可观测。
功能概述
服务网格提供的可观测能力分为三大版块:
• 访问日志
• 监控指标
• 链路追踪
LLM请求基于HTTP协议,可以直接使用ASM的链路追踪能力。默认的访问日志、监控指标能力尚不足以满足用户对于LLM请求的可观测需求。访问日志并不能打印出LLM请求特定的信息,例如当前请求的模型;监控指标目前也只能反映HTTP协议的信息。因此ASM着重增强了当前的访问日志和监控指标能力。主要增强分为两方面:
• 访问日志:
- ASM在网格代理中对LLM请求进行了特殊处理,用户可以使用自定义访问日志格式的功能,在访问日志中打印LLM请求的信息。
• 监控指标:
- ASM新增了两个监控指标,用来反映当前请求的输入Token数(Prompt Tokens)和输出Token数(Completion Tokens);
- 新增了LLM请求特定的信息作为指标维度,用户可以在标准的Istio指标中引用。
下面将分别演示这两方面能力。
使用前提
• 至少完成了上篇文档《使用阿里云服务网格高效管理LLM流量:(一)流量路由》中的步骤一、步骤二。
为了展示更加丰富的效果,本文建立在完整完成了上篇文档所有步骤的基础上。只完成步骤一和步骤二的话,使用步骤二的测试命令发送测试请求即可。查看可观测数据使用与本文相同的命令。
步骤一:使用访问日志观测LLM请求
配置访问日志
ASM已经将LLM请求信息内置在网格代理中,您只需要自定义访问日志格式即可。
完整的自定义日志格式的步骤,请参考ASM的官方文档:自定义数据面访问日志[1]。
在网格实例的可观测管理中心菜单栏中,点击“可观测配置”选项,进入相应配置页面。
ASM支持全局、命名空间、特定负载等各个级别的可观测配置,您可以根据需求来选择生效范围。本文为了配置方便,直接配置了全局的可观测配置。
在全局的“日志设置”中,新增三个字段,如下图:
具体文本内容如下:
request_model FILTER_STATE(wasm.asm.llmproxy.request_model:PLAIN) request_prompt_tokens FILTER_STATE(wasm.asm.llmproxy.request_prompt_tokens:PLAIN) request_completion_tokens FILTER_STATE(wasm.asm.llmproxy.request_completion_tokens:PLAIN)
这三个字段含义分别为:
request_model:当前LLM请求的实际model,比如qwen-turbo或qwen-1.8b-chat;
request_prompt_tokens:当前请求的输入token数量;
request_completion_tokens:当前请求输出的token数量。
当前的大模型服务提供商大都以token消耗量来计费。用户可以基于此数据,精准的查看指定请求的token的消耗请求,以及请求具体使用了哪些模型。
测试
使用ACK的kubeconfig执行以下两个命令发起访问:
kubectl exec deployment/sleep -it -- curl --location 'http://dashscope.aliyuncs.com' \ --header 'Content-Type: application/json' \ --data '{ "messages": [ {"role": "user", "content": "请介绍你自己"} ] }' kubectl exec deployment/sleep -it -- curl --location 'http://dashscope.aliyuncs.com' \ --header 'Content-Type: application/json' \ --header 'user-type: subscriber' \ --data '{ "messages": [ {"role": "user", "content": "请介绍你自己"} ] }'
上面命令分别测试不同类型的用户使用不同的模型。
使用以下命令查看访问日志:
kubectl logs deployments/sleep -c istio-proxy | tail -2
将访问日志进行格式化且去除一些字段之后的结果如下所示:
{ "duration": "7640", "response_code": "200", "authority_for": "dashscope.aliyuncs.com", --实际访问的大模型provider "request_model": "qwen-1.8b-chat", --当前请求使用的模型 "request_prompt_tokens": "3", --当前请求的输入token数 "request_completion_tokens": "55" --当前请求的输出token数 }
{ "duration": "2759", "response_code": "200", "authority_for": "dashscope.aliyuncs.com", --实际访问的大模型provider "request_model": "qwen-turbo", --当前请求使用的模型 "request_prompt_tokens": "11", --当前请求的输入token数 "request_completion_tokens": "90" --当前请求的输出token数 }
您可以通过访问日志观测到请求级别的LLM调用情况。ASM已经和阿里云日志服务进行了集成,您可以直接将日志采集并存储起来,基于这些访问日志可以定制特定的告警规则以及更加清晰的日志大盘,详情参考:如何启用数据平面日志采集_服务网格(ASM)-阿里云帮助中心[2]。
步骤二:新增Prometheus指标,展示当前工作负载消耗的token数
访问日志是细粒度的信息记录,监控指标可以反映更加宏观的结果。ASM的网格代理支持以监控指标的形式输出工作负载级别的Token消耗数,用户可以通过这些指标实时观测到当前工作负载的token消耗情况。
ASM新增两个指标:
• asm_llm_proxy_prompt_tokens:输入token数。
• asm_llm_proxy_completion_tokens:输出token数。
这两个指标默认具有以下维度:
• llmproxy_source_workload:发出请求的工作负载名称。
• llmproxy_source_workload_namespace:请求源所在的命名空间。
• llmproxy_destination_service:目标provider。
• llmproxy_model:当前请求的模型。
修改工作负载配置,输出新增指标
首先需要配置一个用来格式化输出指标的configmap,接着修改客户端deployment引用这个configmap。本文以default命名空间下的sleep deployment为例。
使用ACK的kubeconfig创建configmap:
apiVersion: v1 kind: ConfigMap metadata: name: asm-llm-proxy-bootstrap-config data: custom_bootstrap.json: | "stats_config": { "stats_tags":[ { "tag_name": "llmproxy_source_workload", "regex": "(\\|llmproxy_source_workload=([^|]*))" }, { "tag_name": "llmproxy_source_workload_namespace", "regex": "(\\|llmproxy_source_workload_namespace=([^|]*))" }, { "tag_name": "llmproxy_destination_service", "regex": "(\\|llmproxy_destination_service=([^|]*))" }, { "tag_name": "llmproxy_model", "regex": "(\\|llmproxy_model=([^|]*))" } ] }
上述YAML中含有转义字符。为确保正确配置,请先将上述文本拷贝到本地文件中(比如temp.yaml),然后执行kubectl apply -f ${文件名称}来应用配置。
使用ACK的kubeconfig执行以下命令,修改sleep的deployment:
kubectl patch deployment sleep -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar.istio.io/bootstrapOverride":"asm-llm-proxy-bootstrap-config"}}}}}'
该命令是给pod增加了一个annotation。
测试
使用ACK的kubeconfig执行如下测试命令:
kubectl exec deployment/sleep -it -- curl --location 'http://dashscope.aliyuncs.com' \ --header 'Content-Type: application/json' \ --data '{ "messages": [ {"role": "user", "content": "请介绍你自己"} ] }' kubectl exec deployment/sleep -it -- curl --location 'http://dashscope.aliyuncs.com' \ --header 'Content-Type: application/json' \ --header 'user-type: subscriber' \ --data '{ "messages": [ {"role": "user", "content": "请介绍你自己"} ] }'
查看sleep应用的sidecar输出的prometheus指标,使用ACK的kubeconfig执行如下命令:
kubectl exec deployments/sleep -it -c istio-proxy -- curl localhost:15090/stats/prometheus | grep llmproxy asm_llm_proxy_completion_tokens{llmproxy_source_workload="sleep",llmproxy_source_workload_namespace="default",llmproxy_destination_service="dashscope.aliyuncs.com",llmproxy_model="qwen-1.8b-chat"} 72 asm_llm_proxy_completion_tokens{llmproxy_source_workload="sleep",llmproxy_source_workload_namespace="default",llmproxy_destination_service="dashscope.aliyuncs.com",llmproxy_model="qwen-turbo"} 85 asm_llm_proxy_prompt_tokens{llmproxy_source_workload="sleep",llmproxy_source_workload_namespace="default",llmproxy_destination_service="dashscope.aliyuncs.com",llmproxy_model="qwen-1.8b-chat"} 3 asm_llm_proxy_prompt_tokens{llmproxy_source_workload="sleep",llmproxy_source_workload_namespace="default",llmproxy_destination_service="dashscope.aliyuncs.com",llmproxy_model="qwen-turbo"} 11
可以看到sidecar已经输出了对应的指标。并且携带了4个默认的维度。
ASM已经集成了ARMS服务,您可以通过配置采集规则将这些指标采集到ARMS Prometheus中,进行更详细的分析及展示。
步骤三:给服务网格原生指标新增LLM相关维度
服务网格原生提供了诸多指标(参考:Istio标准指标[3]),可以展示HTTP或TCP协议的详细信息,并且这些输出了丰富的维度,ASM也已经根据这些指标以及维度内置了功能强大的Prometheus Dashboard。
但是这些指标目前并不具有LLM请求的信息,为此ASM进行了增强。用户可以通过自定义指标维度,为已有指标添加LLM请求信息。
配置自定义维度:model
本小节REQUEST_COUNT指标为例,为其增加model维度。
进入可观测配置页面,点击REQUEST_COUNT的编辑维度。
自定义维度配置同样支持灵活的范围选择,您可以根据自己的需求进行选择,此处选择了全局配置。
选择“自定义维度”标签,添加自定义维度“model”:
model的取值为:filter_state["wasm.asm.llmproxy.request_model"]。
测试
使用ACK的kubeconfig执行如下命令,发起测试请求:
kubectl exec deployment/sleep -it -- curl --location 'http://dashscope.aliyuncs.com' \ --header 'Content-Type: application/json' \ --data '{ "messages": [ {"role": "user", "content": "请介绍你自己"} ] }' kubectl exec deployment/sleep -it -- curl --location 'http://dashscope.aliyuncs.com' \ --header 'Content-Type: application/json' \ --header 'user-type: subscriber' \ --data '{ "messages": [ {"role": "user", "content": "请介绍你自己"} ] }'
使用ACK的kubeconfig执行如下命令:
kubectl exec deployments/sleep -it -c istio-proxy -- curl localhost:15090/stats/prometheus | grep requests_total # TYPE istio_requests_total counter istio_requests_total{reporter="source",source_workload="sleep",source_canonical_service="sleep",source_canonical_revision="latest",source_workload_namespace="default",source_principal="unknown",source_app="sleep",source_version="",source_cluster="cce8d2c1d1e8d4abc8d5c180d160669cc",destination_workload="unknown",destination_workload_namespace="unknown",destination_principal="unknown",destination_app="unknown",destination_version="unknown",destination_service="dashscope.aliyuncs.com",destination_canonical_service="unknown",destination_canonical_revision="latest",destination_service_name="dashscope.aliyuncs.com",destination_service_namespace="unknown",destination_cluster="unknown",request_protocol="http",response_code="200",grpc_response_status="",response_flags="-",connection_security_policy="unknown",model="qwen-1.8b-chat"} 1 istio_requests_total{reporter="source",source_workload="sleep",source_canonical_service="sleep",source_canonical_revision="latest",source_workload_namespace="default",source_principal="unknown",source_app="sleep",source_version="",source_cluster="cce8d2c1d1e8d4abc8d5c180d160669cc",destination_workload="unknown",destination_workload_namespace="unknown",destination_principal="unknown",destination_app="unknown",destination_version="unknown",destination_service="dashscope.aliyuncs.com",destination_canonical_service="unknown",destination_canonical_revision="latest",destination_service_name="dashscope.aliyuncs.com",destination_service_namespace="unknown",destination_cluster="unknown",request_protocol="http",response_code="200",grpc_response_status="",response_flags="-",connection_security_policy="unknown",model="qwen-turbo"} 1
从上述输出可以看出,请求的model已经作为一个指标被添加到了istio_requests_total中。
得到上述监控指标后,您可以在ARMS配置分析规则,进行更细致的分析。比如:
• 访问某个模型的请求成功率;
• 某个model或者provider的平均响应延迟。
总结
本文简要介绍并演示了ASM提供的LLM服务可观测基础功能,这些功能与当前网格提供的HTTP/TCP可观测体系无缝结合,您可以根据这些基础数据在已有的可观测体系之上进行增强,更好的适应业务的快速发展。
可观测和路由是其他高级功能的基础,接下来的文章中将会逐步介绍ASM提供的LLM请求缓存、基于请求Token限流等能力,您感兴趣的话可以直接查看ASM的官方文档。
欢迎评论区交流,或者加入钉钉交流群:30421250。
相关链接:
[1] 自定义数据面访问日志
[2] 如何启用数据平面日志采集_服务网格(ASM)-阿里云帮助中心
[3] Istio标准指标
https://istio.io/latest/zh/docs/reference/config/metrics/
我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。
获取关于我们的更多信息~