アリババクラウド ASM を使用して LLM トラフィックを効率的に管理する 第2部: トラフィックの可観測性

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/use-alibaba-cloud-asm-to-efficiently-manage-llm-traffic-part-2-traffic-observability_602224?spm=a2c65.11461433.0.0.4ee35355xnGg8q)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

# ASMを使用して大規模モデルトラフィックの観測性を実現する方法

執筆者: Yuanyuan Ma

優れた観測性は、効率的で安定した分散アプリケーションを構築するための前提条件であり、特にLLM（大規模言語モデル）アプリケーションにおいて重要です。多くの複雑なシステムの進化を振り返ると、標準化とレイヤリングが時間の試練に耐えてきた古典的な解決策であることが明らかになります。当初、開発者は観測性情報を公開するために手動でコードを記述する必要がありました。その後、これらの観測性ロジックコンポーネントが開発フレームワークに統合され、一般的なメトリクスのサブセットが自動的に公開されるようになりました。サービスメッシュの登場により、より汎用的なロジックがインフラストラクチャ層に移行しました。この進化により、開発者は開発フレームワークではなくビジネスロジックに集中できるようになりました。この概念に基づき、LLMが急速に発展する中で、ASM（Alibaba Cloud Service Mesh）ではインフラストラクチャレベルでのLLMトラフィック管理と観測性機能を実装しました。特定の言語やSDKに依存する必要はなく、アプリケーションの呼び出し方法を変更する必要もありません。シンプルな設定だけで、透過的かつシームレスなトラフィックルーティングと観測性を実現できます。LLMプロバイダーは通常、リクエストで使用されたモデルとトークンの数に基づいて料金を請求します。グローバルに統一された観測性は、ビジネスの安定性の基盤であるだけでなく、コストの洞察と最適化の前提条件でもあります。この記事では、ASMを使用して大規模モデルトラフィックの観測性を実現する方法を紹介します。

## 機能

ASMが提供する観測性は、次の3つのセクションに分かれています：
- アクセスログ
- 監視メトリクス
- トレース

LLMリクエストはHTTPプロトコルに基づいているため、ASMのトレース機能を直接活用できます。デフォルトのアクセスログと監視メトリクスだけでは、ユーザーのLLMリクエストに対する観測性要件を満たすには不十分です。アクセスログは、現在のリクエストで使用されているモデルなど、LLMリクエストに関連する特定の情報をキャプチャできません。同様に、現在の監視メトリクスはHTTPプロトコルレベルの情報しか反映していません。そのため、ASMは現在のアクセスログと監視メトリクス機能の強化に焦点を当てています。主な強化点は次の2つに分かれます：

### アクセスログ
ASMは、ASMプロキシ内のLLMリクエストに対して特別な処理を行います。アクセスログの形式をカスタマイズして、LLMリクエストに関する情報をアクセスログに出力できます。

### 監視メトリクス
ASMは、現在のリクエストにおけるプロンプトトークンと完了トークンの数を反映する2つのメトリクスを追加しました。LLMリクエスト固有の情報はメトリクス次元として追加され、標準的なIstioメトリクスで参照できます。これらの2つの機能については、以下でそれぞれ説明します。

## 前提条件
- 前のドキュメント「[Use Alibaba Cloud ASM to Efficiently Manage LLM Traffic Part 1: Traffic Routing](https://www.alibabacloud.com/blog/use-alibaba-cloud-asm-to-efficiently-manage-llm-traffic-part-1-traffic-routing_601608)」のステップ1とステップ2を少なくとも完了していること。より多くの結果を示すため、この記事では前のドキュメントのすべてのステップが完全に完了していることを前提としています。ステップ1とステップ2のみを完了している場合、ステップ2で提供されたテストコマンドを使用してテストリクエストを送信できます。この記事で説明されている同じコマンドを使用して観測性データを確認できます。

---

## ステップ1：アクセスログを使用してLLMリクエストを観察する

### アクセスログの設定
ASMはすでにLLMリクエスト情報をメッシュプロキシ内に埋め込んでいます。アクセスログの形式をカスタマイズするだけで済みます。ログ形式のカスタマイズに関する詳細な手順は、公式のASMドキュメント「[Customize Data Plane Access Logs](https://www.alibabacloud.com/help/en/asm/user-guide/customize-access-logs-of-clusters-on-the-data-plane?spm=a2c4g.11186623.0.0.218a6274hlTMjq#1c7242a025k97)」をご覧ください。

ASMインスタンスの「Observability Management Center」メニューで、「Observability Configuration」をクリックして対応する設定ページに移動します。ASMは、グローバル、ネームスペース、特定のワークロードなど、さまざまなレベルの観測性設定をサポートしています。必要に応じて有効範囲を選択できます。簡単にするために、この記事ではグローバル観測性設定を直接構成します。グローバルログ設定で、以下の図に示すように3つのフィールドを追加します。

![1](https://yqintl.alicdn.com/e99dde13b3e73165a2a576558895503daf417321.png)
![2](https://yqintl.alicdn.com/34f44267cc290e03529ca7a89da7369d830ff2a8.png)

具体的なテキスト内容は次のとおりです：
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)

これら3つのフィールドの意味は次のとおりです：

- **request_model**: 現在のLLMリクエストで使用されている実際のモデル（例: qwen-turboまたはqwen-1.8b-chat）。
- **request_prompt_tokens**: 現在のリクエストにおけるプロンプトトークンの数。
- **request_completion_tokens**: 現在のリクエストにおける完了トークンの数。

ほとんどの大規模モデルサービスプロバイダーは、トークン消費に基づいて課金します。このデータを使用して、特定のリクエストのトークン消費を正確に表示し、そのリクエストで使用されたモデルを特定できます。

### テスト
ACKのkubeconfigを使用して、次の2つのコマンドを実行してアクセスします：bash
kubectl exec deployment/sleep -it -- curl_disabled --location http://dashscope.aliyuncs.com \
--header Content-Type: application/json \
--data {
    messages: [
        {role: user, content: Please introduce yourself}
    ]
}bash
kubectl exec deployment/sleep -it -- curl_disabled --location http://dashscope.aliyuncs.com \
--header Content-Type: application/json \
--header user-type: subscriber \
--data {
    messages: [
        {role: user, content: Please introduce yourself}
    ]
}

上記のコマンドは、異なるタイプのユーザーが異なるモデルにアクセスするテストを行います。次のコマンドを実行してアクセスログを表示します：bash
kubectl logs deployments/sleep -c istio-proxy | tail -2

アクセスログをフォーマットし、いくつかのフィールドを削除した結果は次のようになります：json
{
    duration: 7640,
    response_code: 200,
    authority_for: dashscope.aliyuncs.com,  // 実際にアクセスされた大規模モデルプロバイダー
    request_model: qwen-1.8b-chat,              // 現在のリクエストで使用されたモデル
    request_prompt_tokens: 3,                               // 現在のリクエストにおけるプロンプトトークンの数
    request_completion_tokens: 55                       // 現在のリクエストにおける完了トークンの数
}
{
  duration: 2759,

# ACKのkubeconfigを使用してConfigMapを作成する

以下のYAMLを使用して、`ConfigMap`を作成します。yaml
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 ${file_name}`を実行して設定を適用してください。

ACKのkubeconfigを使用して次のコマンドを実行し、`sleep`デプロイメントを変更します：bash
kubectl patch deployment sleep -p {spec:{template:{metadata:{annotations:{sidecar.istio.io/bootstrapOverride:asm-llm-proxy-bootstrap-config}}}}}

このコマンドはポッドにアノテーションを追加します。

## テスト

ACKのkubeconfigを使用して次のコマンドを実行します：bash
kubectl exec deployment/sleep -it -- curl_disabled --location http://dashscope.aliyuncs.com \
--header Content-Type: application/json \
--data {
    messages: [
        {role: user, content: Please introduce yourself}
    ]
}bash
kubectl exec deployment/sleep -it -- curl_disabled --location http://dashscope.aliyuncs.com \
--header Content-Type: application/json \
--header user-type: subscriber \
--data {
    messages: [
        {role: user, content: Please introduce yourself}
    ]
}

`sleep`アプリケーションのサイドカーからPrometheusメトリクスを表示するには、ACKのkubeconfigを使用して次のコマンドを実行します：bash
kubectl exec deployments/sleep -it -c istio-proxy -- curl_disabled localhost:15090/stats/prometheus | grep llmproxyplaintext
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

サイドカーは正常に対応するメトリクスを出力しました。各メトリクスには4つのデフォルト次元が含まれます。ASMはすでにARMS（Application Real-Time Monitoring Service）と統合されています。これらのメトリクスを収集するためのルールを設定し、ARMS Prometheusに取り込んで詳細な分析や可視化を行うことができます。

## 手順3：ネイティブASMメトリクスにLLM関連の次元を追加する

ASMはネイティブでさまざまなメトリクスを提供しています（参照：<a href=https://istio.io/latest/docs/reference/config/metrics/ target=_blank>Istio Standard Metrics</a>）。これらのメトリクスはHTTPまたはTCPプロトコルに関する詳細情報を表示し、豊富な次元を持っています。ASMはこれらのメトリクスと次元に基づいて強力なPrometheusダッシュボードを構築しています。ただし、これらのメトリクスには現在、LLMリクエスト情報が含まれていません。これを解決するために、ASMでは拡張機能が導入されました。これにより、既存のメトリクスにLLMリクエスト情報を追加するためのカスタムメトリック次元を設定できます。

### カスタム次元「model」の設定

ここでは、`REQUEST_COUNT`メトリクスを例として取り上げ、それに「model」次元を追加します。監視可能性設定ページに移動します。「REQUEST_COUNT」メトリクスの「Edit dimension」をクリックします。カスタム次元の設定は柔軟なスコープ選択もサポートしています。必要に応じてスコープを選択できます。この場合、グローバル設定が選択されています。

![3](https://yqintl.alicdn.com/07576f66caa207587408578104dd7f317056b3b6.png)

「Custom Dimensions」タブを選択し、「model」というカスタム次元を追加します。

![4](https://yqintl.alicdn.com/c562da84cea65427d32e54a7e0f4282fe426781f.jpeg)

「model」の値は`filter_state[wasm.asm.llmproxy.request_model]`です。

## テスト

ACKのkubeconfigを使用して次のコマンドを実行し、テストリクエストを送信します：bash
kubectl exec deployment/sleep -it -- curl_disabled --location http://dashscope.aliyuncs.com \
--header Content-Type: application/json \
--data {
    messages: [
        {role: user, content: Please introduce yourself}
    ]
}bash
kubectl exec deployment/sleep -it -- curl_disabled --location http://dashscope.aliyuncs.com \
--header Content-Type: application/json \
--header user-type: subscriber \
--data {
    messages: [
        {role: user, content: Please introduce yourself}
    ]
}

ACKのkubeconfigを使用して次のコマンドを実行します：bash
kubectl exec deployments/sleep -it -c istio-proxy -- curl_disabled localhost:15090/stats/prometheus | grep requests_totalplaintext
# 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

上記の出力からわかるように、リクエストされたモデルが`istio_requests_total`にメトリクスとして追加されています。

上記の監視メトリクスを取得した後、ARMSで分析ルールを設定してより詳細な分析を行えます。例えば：

• モデルへのアクセスリクエ