カスタマーサポートエージェント
Claudeで構築する前に
サポートチャットにClaudeを使用するかどうかを決定する
カスタマーサポートプロセスの一部を自動化するためにClaudeのようなLLMを採用すべき主要な指標は以下の通りです:
他のLLMよりもClaudeを選択する際の考慮事項:
- 自然で微妙な会話を優先する場合:Claudeの洗練された言語理解により、他のLLMとのチャットよりも人間らしく感じられる、より自然で文脈を理解した会話が可能になります。
- 複雑でオープンエンドなクエリを頻繁に受け取る場合:Claudeは定型的な回答を生成したり、ユーザーの発話の順列を広範囲にプログラミングしたりすることなく、幅広いトピックや問い合わせを処理できます。
- スケーラブルな多言語サポートが必要な場合:Claudeの多言語機能により、サポートする各言語に対して個別のチャットボットや広範囲な翻訳プロセスを必要とすることなく、200以上の言語で会話を行うことができます。
理想的なチャットインタラクションを定義する
理想的な顧客インタラクションの概要を作成し、顧客がClaudeとどのように、いつやり取りすることを期待するかを定義します。この概要は、ソリューションの技術要件を決定するのに役立ちます。
以下は自動車保険カスタマーサポートのチャットインタラクションの例です:
- 顧客:サポートチャット体験を開始
- Claude:顧客を温かく迎え、会話を開始
- 顧客:新しい電気自動車の保険について質問
- Claude:電気自動車カバレッジに関する関連情報を提供
- 顧客:電気自動車保険の独特なニーズに関連する質問
- Claude:正確で有益な回答を提供し、情報源へのリンクを提供
- 顧客:保険や自動車に関係のないオフトピックな質問
- Claude:関係のないトピックについては議論しないことを明確にし、ユーザーを自動車保険に戻るよう誘導
- 顧客:保険見積もりに興味を示す
- Claude:適切な見積もりを決定するための一連の質問をし、顧客の回答に適応
- Claude:ユーザーから収集した必要な情報とともに見積もり生成APIツールの使用リクエストを送信
- Claude:APIツール使用からの応答情報を受信し、情報を自然な回答に統合し、提供された見積もりをユーザーに提示
- 顧客:フォローアップ質問
- Claude:必要に応じてフォローアップ質問に回答
- Claude:保険プロセスの次のステップに顧客を案内し、会話を終了
インタラクションを独特なタスクに分解する
カスタマーサポートチャットは、質問応答から情報検索、リクエストへの対応まで、複数の異なるタスクの集合体であり、すべてが単一の顧客インタラクションにまとめられています。構築を開始する前に、理想的な顧客インタラクションをClaudeに実行してもらいたいすべてのタスクに分解します。これにより、すべてのタスクについてClaudeをプロンプトし評価でき、テストケースを書く際に考慮する必要があるインタラクションの範囲を適切に把握できます。
上記の保険インタラクション例に関連する主要なタスクは以下の通りです:
-
挨拶と一般的なガイダンス
- 顧客を温かく迎え、会話を開始
- 会社とインタラクションに関する一般的な情報を提供
-
製品情報
- 電気自動車カバレッジに関する情報を提供
これには、Claudeがコンテキストに必要な情報を持っている必要があり、RAG統合が必要であることを意味する場合があります。
- 電気自動車保険の独特なニーズに関連する質問に回答
- 見積もりや保険の詳細に関するフォローアップ質問に回答
- 適切な場合に情報源へのリンクを提供
- 電気自動車カバレッジに関する情報を提供
-
会話管理
- トピック(自動車保険)に留まる
- オフトピックな質問を関連する主題に戻すよう誘導
-
見積もり生成
- 見積もり資格を決定するための適切な質問
- 顧客の回答に基づいて質問を適応
- 収集した情報を見積もり生成APIに送信
- 提供された見積もりを顧客に提示
成功基準を確立する
サポートチームと協力して明確な成功基準を定義し、測定可能なベンチマークと目標を持つ詳細な評価を作成します。
定義されたタスクをClaudeがどれだけ成功裏に実行するかを評価するために使用できる基準とベンチマークは以下の通りです:
サポートにClaudeを採用することのビジネスインパクトを評価するために使用できる基準とベンチマークは以下の通りです:
カスタマーサービスエージェントとしてClaudeを実装する方法
適切なClaudeモデルを選択する
モデルの選択は、コスト、精度、応答時間のトレードオフに依存します。
カスタマーサポートチャットの場合、claude-opus-4-1-20250805は知能、レイテンシ、コストのバランスを取るのに適しています。ただし、RAG、ツール使用、および/または長いコンテキストプロンプトを含む複数のプロンプトを持つ会話フローがある場合、レイテンシを最適化するためにclaude-3-haiku-20240307がより適している場合があります。
強力なプロンプトを構築する
カスタマーサポートにClaudeを使用するには、Claudeが適切に応答するのに十分な指示とコンテキストを持ちながら、幅広い顧客問い合わせを処理するのに十分な柔軟性を持つ必要があります。
システムプロンプトから始めて、強力なプロンプトの要素を書くことから始めましょう:
IDENTITY = """あなたはEvaです。Acme Insurance Companyの親しみやすく知識豊富なAIアシスタントです。あなたの役割は、顧客を温かく迎え、自動車保険と電気自動車保険を含むAcmeの保険商品に関する情報を提供することです。また、顧客の保険ニーズに対する見積もりの取得もサポートできます。"""Userターン内に書くことで最も良く機能します。詳細はシステムプロンプトでClaudeに役割を与えるをお読みください。複雑なプロンプトをサブセクションに分解し、一度に一部分ずつ書くのが最良です。各タスクについて、Claudeがそのタスクを上手く実行するために必要なプロンプトの部分を定義するステップバイステップのプロセスに従うことで、より大きな成功を得られるかもしれません。この自動車保険カスタマーサポートの例では、「挨拶と一般的なガイダンス」タスクから始めて、プロンプトのすべての部分を断片的に書いていきます。これにより、全体的なプロンプトの個々の部分をより迅速に調整できるため、プロンプトのデバッグも容易になります。
これらすべての部分をconfig.pyというファイルに配置します。
STATIC_GREETINGS_AND_GENERAL = """
<static_context>
Acme Auto Insurance:道路上の信頼できるパートナー
概要:
Acme Insuranceでは、あなたの車両が単なる交通手段以上のものであることを理解しています。それは人生の冒険への切符です。
1985年以来、私たちはドライバーが自信を持って探索、通勤、旅行できる自動車保険ポリシーを作成してきました。
市街地を走行する場合でも、全国横断の道路旅行に出かける場合でも、Acmeがあなたとあなたの車両を保護します。
私たちの革新的な自動車保険ポリシーは、軽微な接触事故から大きな衝突まで、あらゆるものをカバーし、あなたの独特なニーズに適応するよう設計されています。
Acmeの受賞歴のあるカスタマーサービスと迅速な請求解決により、あなたは運転の喜びに集中でき、残りは私たちが処理します。
私たちは単なる保険プロバイダーではありません。人生の旅路におけるあなたの副操縦士です。
Acme Auto Insuranceを選択し、優れたカバレッジと真のケアがもたらす安心を体験してください。Acmeでは、あなたの車を保険するだけでなく、開かれた道路でのあなたの冒険に燃料を供給するからです。
注:また、電気自動車向けの専門カバレッジも提供しており、あらゆるタイプの車のドライバーが私たちの保護の恩恵を受けることができます。
Acme Insuranceは以下の商品を提供しています:
- 自動車保険
- 電気自動車保険
- 二輪車保険
営業時間:月曜日〜金曜日、午前9時〜午後5時(EST)
カスタマーサービス番号:1-800-123-4567
</static_context>
"""次に、自動車保険と電気自動車保険の情報についても同様に行います。
STATIC_CAR_INSURANCE="""
<static_context>
自動車保険カバレッジ:
Acmeの自動車保険ポリシーは通常以下をカバーします:
1. 賠償責任カバレッジ:他者に与えた身体的傷害と財産損害に対して支払います。
2. 衝突カバレッジ:事故での車の損害に対して支払います。
3. 総合カバレッジ:非衝突事故による車の損害に対して支払います。
4. 医療費カバレッジ:事故後の医療費に対して支払います。
5. 無保険/過少保険運転者カバレッジ:不十分な保険を持つドライバーに衝突された場合に保護します。
オプションのカバレッジには以下が含まれます:
- レンタカー償還
- ロードサイドアシスタンス
- 新車交換
</static_context>
"""
STATIC_ELECTRIC_CAR_INSURANCE="""
<static_context>
電気自動車保険:
私たちの専門的な電気自動車保険は、従来の自動車カバレッジを超えて、
あなたのハイテク投資に合わせた保護を提供します。標準的なカバレッジに加えて、以下を提供します:
- 高価なバッテリーシステムの保護
- 家庭用充電設備のカバー
- 急速に進化する電気自動車の世界への適応
Rivian、Nissan Leaf、Chevrolet Bolt、
またはその他の電気自動車を運転している場合でも、私たちの知識豊富なエージェントが、
あなたが電子駆動のすべてのマイルを楽しむ自信を与えるポリシーを作成する準備ができています。
</static_context>
"""静的コンテンツができたので、Claudeの回答を導くために少なくとも4-5の「良い」インタラクションのサンプルを追加しましょう。これらの例は、理想的な顧客インタラクションを代表するものであり、ガードレール、ツール呼び出しなどを含むことができます。
EXAMPLES="""
顧客とどのようにやり取りできるかの例をいくつか示します:
<example 1>
H: こんにちは、中小企業向けの商業保険は提供していますか?
A: ああ!残念ながら、現在商業保険は提供していません。
ただし、自動車保険や電気自動車保険を含む個人保険商品の範囲は提供しています。
これらの商品についてもっと知りたいですか?
</example 1>
<example 2>
H: こんにちは、営業時間を教えてください。
A: 営業時間は月曜日から金曜日の午前9時から午後5時(EST)です。
その時間内にご質問やサポートが必要でしたら、お気軽にお声がけください。
今日は他に何かお手伝いできることはありますか?
</example 2>
<example 3>
H: 自動車保険を探しています。Acmeは何を提供していますか?
A: 素晴らしい選択です!Acmeの自動車保険ポリシーには通常以下が含まれます:
- 賠償責任カバレッジ:事故で過失がある場合に保護します
- 衝突カバレッジ:事故での車の損害に対して支払います
- 総合カバレッジ:盗難や破壊行為などの非衝突事故をカバーします
- 医療費カバレッジ:事故後の医療費に対して支払います
- 無保険/過少保険運転者カバレッジ:不十分な保険を持つドライバーから保護します
また、レンタカー償還、ロードサイドアシスタンス、新車交換などのオプションカバレッジも提供しています。
これらのカバレッジのいずれかについて詳細をお知りになりたいですか、それとも車両の保険について具体的な質問がありますか?
</example 3>
<example 4>
H: 電気自動車保険について聞きたいです。
A: もちろんです!私たちの電気自動車保険は、電気自動車オーナーの独特なニーズを満たすよう特別に設計されています。
通常の車に提供するすべての標準カバレッジに加えて、電気自動車ポリシーには以下が含まれます:
- バッテリーカバレッジ:車両の高価なバッテリーシステムの損害や劣化に対する保護
- テクノロジーパッケージ:高度な電子機器や車載コンピューターシステムの修理や交換をカバー
- 充電ステーションカバレッジ:家庭用とポータブル充電設備の両方を保護
- サイバーセキュリティ保護:ハッキングやデジタル脅威に対するカバレッジ
- 専門ロードサイドアシスタンス:車両の下部構造を保護するフラットベッドけん引を含む
Tesla、Rivian、Nissan、Chevroletなどの人気モデルを含む幅広い電気自動車をカバーしています。
保険をかけたい特定の電気自動車がありますか、それともこれらのカバレッジのいずれかについて詳細をお知りになりたいですか?
</example 4>
<example 5>
H: 自動車保険の見積もりを取りたいです。
A: もちろんです!自動車保険の見積もりを取得するお手伝いをさせていただきます。
正確な見積もりを提供するために、あなたの車両と主要運転者に関する情報を収集する必要があります。
基本的なことから始めましょう:
1. あなたの車両のメーカーとモデルは何ですか?
2. 何年に製造されましたか?
3. おおよそ何マイル運転していますか?
4. 主要運転者の年齢は?
この情報を提供していただければ、見積もりツールを使用してあなた専用の保険見積もりを生成します。
</example 5>
"""また、Claudeが顧客とどのようにやり取りすべきかについて、すべきことと避けるべきことを概説する重要な指示も含めたいでしょう。 これは、ブランドガードレールやサポートポリシーから引き出される場合があります。
ADDITIONAL_GUARDRAILS = """以下のガードレールを遵守してください:
1. 私たちの商品リストに記載されている保険タイプに関する情報のみを提供してください。
2. 私たちが提供していない保険タイプについて尋ねられた場合、そのサービスは提供していないことを丁寧に述べてください。
3. 将来の商品提供や会社の計画について推測しないでください。
4. 承認されていない約束をしたり、契約を結んだりしないでください。
あなたは情報とガイダンスのみを提供します。
5. 競合他社の商品やサービスについて言及しないでください。
"""次に、これらすべてのセクションを単一の文字列に結合して、プロンプトとして使用します。
TASK_SPECIFIC_INSTRUCTIONS = ' '.join([
STATIC_GREETINGS_AND_GENERAL,
STATIC_CAR_INSURANCE,
STATIC_ELECTRIC_CAR_INSURANCE,
EXAMPLES,
ADDITIONAL_GUARDRAILS,
])ツール使用で動的でエージェント的な機能を追加する
Claudeは、クライアント側のツール使用機能を使用して、動的にアクションを実行し情報を取得することができます。プロンプトが利用すべき外部ツールやAPIをリストアップすることから始めます。
この例では、見積もりを計算するための1つのツールから始めます。
保険見積もり計算機の例:
TOOLS = [{
"name": "get_quote",
"description": "ユーザー入力に基づいて保険見積もりを計算します。返される値は月額保険料です。",
"input_schema": {
"type": "object",
"properties": {
"make": {"type": "string", "description": "車両のメーカー。"},
"model": {"type": "string", "description": "車両のモデル。"},
"year": {"type": "integer", "description": "車両が製造された年。"},
"mileage": {"type": "integer", "description": "車両の走行距離。"},
"driver_age": {"type": "integer", "description": "主要運転者の年齢。"}
},
"required": ["make", "model", "year", "mileage", "driver_age"]
}
}]
def get_quote(make, model, year, mileage, driver_age):
"""月額保険料をUSDで返します"""
# httpエンドポイントやデータベースを呼び出して見積もりを取得できます。
# ここでは、1秒の遅延をシミュレートし、固定の見積もり100を返します。
time.sleep(1)
return 100プロンプトをデプロイする
プロンプトがどれだけうまく機能するかは、テスト本番環境にデプロイして評価を実行することなしには知ることが困難なので、プロンプト、Anthropic SDK、ユーザーインターフェース用のstreamlitを使用して小さなアプリケーションを構築しましょう。
chatbot.pyというファイルで、Anthropic SDKとのやり取りをカプセル化するChatBotクラスを設定することから始めます。
クラスには2つの主要なメソッドが必要です:generate_messageとprocess_user_input。
from anthropic import Anthropic
from config import IDENTITY, TOOLS, MODEL, get_quote
from dotenv import load_dotenv
load_dotenv()
class ChatBot:
def __init__(self, session_state):
self.anthropic = Anthropic()
self.session_state = session_state
def generate_message(
self,
messages,
max_tokens,
):
try:
response = self.anthropic.messages.create(
model=MODEL,
system=IDENTITY,
max_tokens=max_tokens,
messages=messages,
tools=TOOLS,
)
return response
except Exception as e:
return {"error": str(e)}
def process_user_input(self, user_input):
self.session_state.messages.append({"role": "user", "content": user_input})
response_message = self.generate_message(
messages=self.session_state.messages,
max_tokens=2048,
)
if "error" in response_message:
return f"エラーが発生しました: {response_message['error']}"
if response_message.content[-1].type == "tool_use":
tool_use = response_message.content[-1]
func_name = tool_use.name
func_params = tool_use.input
tool_use_id = tool_use.id
result = self.handle_tool_use(func_name, func_params)
self.session_state.messages.append(
{"role": "assistant", "content": response_message.content}
)
self.session_state.messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": f"{result}",
}],
})
follow_up_response = self.generate_message(
messages=self.session_state.messages,
max_tokens=2048,
)
if "error" in follow_up_response:
return f"エラーが発生しました: {follow_up_response['error']}"
response_text = follow_up_response.content[0].text
self.session_state.messages.append(
{"role": "assistant", "content": response_text}
)
return response_text
elif response_message.content[0].type == "text":
response_text = response_message.content[0].text
self.session_state.messages.append(
{"role": "assistant", "content": response_text}
)
return response_text
else:
raise Exception("エラーが発生しました: 予期しない応答タイプ")
def handle_tool_use(self, func_name, func_params):
if func_name == "get_quote":
premium = get_quote(**func_params)
return f"見積もりが生成されました: 月額${premium:.2f}"
raise Exception("予期しないツールが使用されました")ユーザーインターフェースを構築する
mainメソッドを使用してStreamlitでこのコードをテストデプロイします。このmain()関数は、Streamlitベースのチャットインターフェースを設定します。
これをapp.pyというファイルで行います
import streamlit as st
from chatbot import ChatBot
from config import TASK_SPECIFIC_INSTRUCTIONS
def main():
st.title("Acme Insurance CompanyのアシスタントEvaとチャット🤖")
if "messages" not in st.session_state:
st.session_state.messages = [
{'role': "user", "content": TASK_SPECIFIC_INSTRUCTIONS},
{'role': "assistant", "content": "理解しました"},
]
chatbot = ChatBot(st.session_state)
# 最初の2つをスキップしてユーザーとアシスタントのメッセージを表示
for message in st.session_state.messages[2:]:
# ツール使用ブロックを無視
if isinstance(message["content"], str):
with st.chat_message(message["role"]):
st.markdown(message["content"])
if user_msg := st.chat_input("ここにメッセージを入力してください..."):
st.chat_message("user").markdown(user_msg)
with st.chat_message("assistant"):
with st.spinner("Evaが考えています..."):
response_placeholder = st.empty()
full_response = chatbot.process_user_input(user_msg)
response_placeholder.markdown(full_response)
if __name__ == "__main__":
main()以下でプログラムを実行します:
streamlit run app.pyプロンプトを評価する
プロンプトが本番対応になるためには、多くの場合テストと最適化が必要です。ソリューションの準備状況を判断するために、定量的および定性的方法を組み合わせた体系的なプロセスを使用してチャットボットのパフォーマンスを評価します。定義された成功基準に基づいて強力な実証的評価を作成することで、プロンプトを最適化できます。
パフォーマンスを向上させる
複雑なシナリオでは、標準的なプロンプトエンジニアリング技術とガードレール実装戦略を超えて、パフォーマンスを向上させるための追加戦略を検討することが役立つ場合があります。以下は一般的なシナリオです:
RAGで長いコンテキストレイテンシを削減
大量の静的および動的コンテキストを扱う場合、プロンプトにすべての情報を含めることは高コスト、応答時間の遅延、コンテキストウィンドウ制限への到達につながる可能性があります。このシナリオでは、Retrieval Augmented Generation(RAG)技術を実装することで、パフォーマンスと効率を大幅に向上させることができます。
VoyageのようなEmbeddingモデルを使用して情報をベクトル表現に変換することで、よりスケーラブルで応答性の高いシステムを作成できます。このアプローチにより、すべての可能なコンテキストを各プロンプトに含めるのではなく、現在のクエリに基づいて関連情報を動的に取得できます。
サポートユースケース用のRAGを実装するRAGレシピは、広範囲なコンテキスト要件を持つシステムにおいて精度の向上、応答時間の短縮、APIコストの削減を示すことが証明されています。
ツール使用でリアルタイムデータを統合
アカウント残高やポリシー詳細などのリアルタイム情報を必要とするクエリを扱う場合、埋め込みベースのRAGアプローチでは不十分です。代わりに、ツール使用を活用してチャットボットの正確でリアルタイムな応答提供能力を大幅に向上させることができます。例えば、ツール使用を使用して顧客情報を検索し、注文詳細を取得し、顧客に代わって注文をキャンセルすることができます。
このツール使用:カスタマーサービスエージェントレシピで概説されているアプローチにより、ライブデータをClaudeの応答にシームレスに統合し、よりパーソナライズされた効率的な顧客体験を提供できます。
入力と出力のガードレールを強化
特にカスタマーサービスシナリオでチャットボットをデプロイする場合、誤用、範囲外のクエリ、不適切な応答に関連するリスクを防ぐことが重要です。Claudeは本質的にそのようなシナリオに対して回復力がありますが、チャットボットのガードレールを強化するための追加ステップは以下の通りです:
- 幻覚を減らす:事実確認メカニズムと引用を実装して、提供された情報に応答を根拠づける。
- 情報をクロスチェック:エージェントの応答が会社のポリシーと既知の事実と一致することを確認する。
- 契約上のコミットメントを避ける:エージェントが承認されていない約束をしたり契約を結んだりしないことを確保する。
- ジェイルブレイクを軽減:無害性スクリーンや入力検証などの方法を使用して、ユーザーがモデルの脆弱性を悪用して不適切なコンテンツを生成することを防ぐ。
- 競合他社への言及を避ける:ブランドフォーカスを維持し、競合他社の商品やサービスに言及しないよう競合他社言及フィルターを実装する。
- Claudeをキャラクターに留める:長く複雑なやり取りの間でも、Claudeがスタイルやコンテキストを変更することを防ぐ。
- 個人識別情報(PII)を削除:明示的に必要で承認されていない限り、応答からPIIを除去する。
ストリーミングで知覚される応答時間を短縮
潜在的に長い応答を扱う場合、ストリーミングを実装することでユーザーエンゲージメントと満足度を大幅に向上させることができます。このシナリオでは、ユーザーは応答全体が生成されるのを待つのではなく、段階的に回答を受け取ります。
ストリーミングを実装する方法は以下の通りです:
- Anthropic Streaming APIを使用してストリーミング応答をサポートする。
- 受信するテキストチャンクを処理するようフロントエンドを設定する。
- 各チャンクが到着するたびに表示し、リアルタイムタイピングをシミュレートする。
- ユーザーが離れて戻ってきた場合に完全な応答を表示できるよう、完全な応答を保存するメカニズムを実装する。
場合によっては、ストリーミングにより、段階的表示が長い処理時間の影響を軽減するため、より高いベースレイテンシを持つより高度なモデルの使用が可能になります。
チャットボットをスケールする
チャットボットの複雑さが増すにつれて、アプリケーションアーキテクチャもそれに合わせて進化できます。アーキテクチャにさらなる層を追加する前に、以下のより包括的でないオプションを検討してください:
- プロンプトを最大限活用し、プロンプトエンジニアリングを通じて最適化していることを確認する。プロンプトエンジニアリングガイドを使用して最も効果的なプロンプトを書く。
- プロンプトに追加のツール(プロンプトチェーンを含む場合がある)を追加し、必要な機能を達成できるかどうかを確認する。
チャットボットが非常に多様なタスクを処理する場合、初期の顧客クエリをルーティングするための別個の意図分類器を追加することを検討したいかもしれません。既存のアプリケーションでは、これは分類器を通じて顧客クエリをルーティングし、その後専門的な会話(独自のツールセットとシステムプロンプトを持つ)にルーティングする決定木を作成することを含みます。この方法では、レイテンシを増加させる可能性があるClaudeへの追加呼び出しが必要であることに注意してください。
Claudeをサポートワークフローに統合する
私たちの例はStreamlit環境内で呼び出し可能なPython関数に焦点を当てていますが、リアルタイムサポートチャットボット用にClaudeをデプロイするにはAPIサービスが必要です。
これにアプローチする方法は以下の通りです:
-
APIラッパーを作成:分類機能の周りに簡単なAPIラッパーを開発します。例えば、Flask APIやFast APIを使用してコードをHTTPサービスにラップできます。HTTPサービスはユーザー入力を受け入れ、アシスタントの応答を完全に返すことができます。したがって、サービスは以下の特性を持つことができます:
- Server-Sent Events(SSE):SSEにより、サーバーからクライアントへの応答のリアルタイムストリーミングが可能になります。これは、LLMを使用する際にスムーズでインタラクティブな体験を提供するために重要です。
- キャッシング:キャッシングを実装することで、応答時間を大幅に改善し、不要なAPI呼び出しを削減できます。
- コンテキスト保持:ユーザーが離れて戻ってきた際のコンテキスト維持は、会話の継続性にとって重要です。
-
Webインターフェースを構築:Claudeを活用したエージェントとやり取りするためのユーザーフレンドリーなWeb UIを実装します。