0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS BedrockでClaudeを呼び出して社内文書を3分類する最小実装メモ

0
Posted at

はじめに

「APIキーを直接コードに書くわけにいかないが、生成AIは使いたい」。先月、東京の物流系企業でPoCを進めていたとき、情シスの方からそう言われた。心情としてはよくわかる。エンドユーザー企業が外部LLMサービスのAPIキーを管理するのは、運用上もコンプライアンス上も負担が大きい。

そこで採用したのが、AWS Bedrock 経由でClaudeを呼び出す構成だ。AnthropicがAWS上での提供を強化していくという発表もあり、選択肢として現実味が増している(参考: Claude Platform on AWS)。本稿はその時のメモを整理したものだ。題材は 社内メールを3カテゴリに分類する最小実装。請求関連・サポート・その他に自動振り分け、というシンプルなユースケース。

AWS BedrockでClaudeを使い社内文書を分類するイメージ

前提と環境

  • Python 3.11

  • boto3 1.34+

  • AWS アカウント(東京リージョン ap-northeast-1)

  • Bedrock のClaudeモデル利用申請が承認済みであること

東京リージョンを選んだ理由は単純で、データの所在を国内に閉じたいというリクエストがあったから。PoC段階でも先方が真っ先に気にするポイントだった。

実装ステップ

1. boto3でBedrockクライアントを作る

import boto3
import json
client = boto3.client(
"bedrock-runtime",
region_name="ap-northeast-1",
)

ハマりポイント: bedrock と bedrock-runtime はサービス名が違う。前者はモデル一覧やプロビジョニング用、推論呼び出しは後者を使う。私はここで30分ハマった。あとからAWSのドキュメントを読み返したら太字で書いてあった。読まない人間が悪い。

2. プロンプトを作る

SYSTEM = """あなたは社内メールの分類アシスタントだ。
次のメール本文を、以下のいずれかに分類してJSONで返せ。
カテゴリ:

billing: 請求・支払い・契約金額に関するもの
support: 製品の使い方・障害・不具合に関するもの
other: 上記以外

出力フォーマット:
{"category": "billing" | "support" | "other", "reason": "30文字以内の理由"}
"""
def build_messages(body_text: str) -> list:
return [
{"role": "user", "content": body_text.strip()},
]

JSON で返させる時の鉄則は「分岐数を少なくする」こと。3カテゴリならほぼ外さないが、10カテゴリ超えると分類ミスが顕在化してくる。実務ではまず3つから始め、後で増やすほうがいい。

3. invoke_modelを呼ぶ

def classify(body_text: str) -> dict:
payload = {
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 200,
"system": SYSTEM,
"messages": build_messages(body_text),
"temperature": 0,
}
resp = client.invoke_model(
modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
body=json.dumps(payload),
)
raw = json.loads(resp["body"].read())
text = raw["content"][0]["text"]
return json.loads(text)

temperature=0 は分類タスクの基本だ。出力をブレさせる必要がない。地味だが anthropic_version を入れ忘れると 400 で蹴られる。Bedrock 経由特有の落とし穴で、ここも私は一度踏んだ。

動作確認

if name == "main":
sample = "先月分の請求書がまだ届いていません。確認をお願いします。"
print(classify(sample))

実行結果:

{'category': 'billing', 'reason': '請求書未着の確認依頼'}

30件のサンプルで試したところ、誤分類は1件だった。「サポート部門に支払い遅延の件を伝えたい」というメールが support に振られたケースだ。文字通りには正しいが、業務フロー上は billing に流したい。プロンプトに「支払い・契約に関するキーワードは billing 優先」と1行足したら直った。

30件で1件、3.3%。小さく見えるが、月1万件なら330件のミスルーティングになる。こういう微妙な揺らぎを潰すのが、PoCの8割を占める作業だと改めて感じた。

応用

  • 分類結果をAWS Lambda経由でSlackやTeamsに通知する

  • 分類スコアが低いものだけ人手レビューに回すフォールバックを組む

  • 同じ仕組みでFAQ自動振り分け、製造現場の不具合報告分類などにも展開可能

  • 東京リージョンに加えて、災害対策で大阪 or 米国リージョンへのフェイルオーバーを設計する

まとめ

Bedrock 経由は、APIキー管理の負担をAWSのIAMに寄せられるのが大きい。コードの行数はほぼ変わらないが、本番運用の文脈ではこの差が効いてくる。正直なところ、最初は「OpenAIを直で叩くほうが楽じゃないか」と思っていた。実際にエンタープライズ環境に持ち込むと、IAM・VPC・監査ログという既存のAWS資産に乗せられる強みのほうが、ずっと大きかった。次は同じ構成でClaudeの最新モデルが東京リージョンに来たときの latency 比較を書こうと思う。

筆者は 5years+ で韓国・日本企業向けにAI/LLMの業務応用を担当している。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?