OpenAI開発シリーズ(11):実際のアプリケーションプロセスと関数呼び出しの事例分析

全文は合計6,000語以上、読了時間の目安は約15~25分 | 乾物(コードケース付き)も充実、コレクションするのもオススメ!

この記事の目的: チャット完了モデルの関数呼び出しパラメーターと使用方法を紹介し、チャット モデルの関数呼び出しケースを完全に実装します。

画像-20230823170111509

コードのダウンロードアドレス

1. はじめに

この大型モデルがインターネットに接続でき、API を介して ChatGPT に似たプラグインのデータ機能を備えたら、どれほど強力になるか想像できますか?

大規模モデルの知識ベースは 2021 年 9 月時点のものであることは誰もが知っています。つまり、この日付以降の知識については何も知りません。ただし、創発能力を刺激することで特定の推論能力を与えることはできますが、固有の知識は創発できません。 、国内のオープンソース大型モデルのライト ChatGLM など:

画像-20230823084255658

したがって、大規模モデル (LLM) は非常に有能で、非常に強力な新機能を備えていますが、いくつかの制限もあることがわかります。明らかな問題は、最新の情報やデータを取得できず、テキストによる提案しか提供できないことです大規模モデルに「今日の天気はどうですか?」と尋ねるなど、いくつかの問題を直接解決することは不可能です。この単純なシーンは実行できないため、大規模言語モデルの実用的な価値は大きく制限されます

そこで、2023 年 4 月に、AutoGPT はこの状況に対応して次のことを提案しました: **大規模な言語モデルに外部 API を呼び出す機能を与える必要があります。**たとえば、GPT モデルを使用して Google Mail API (Gmail API) を呼び出すことができる場合、GPT モデルは電子メールを自動的に読んで自動返信するなどできます。これに関連して、OpenAI は 0613 アップデートで最も高度なチャット完了モデルに関数呼び出しを追加しました。

画像-20230823090934775

この機能を過小評価しないでください。開発者が AI モデルを操作する方法が完全に変わります。この機能により、開発者は AI モデルに関数を記述することができ、モデルはこれらの関数を呼び出すためのパラメーターを含む JSON オブジェクトの出力をインテリジェントに決定できます大規模モデルに関数呼び出し (関数呼び出し) 機能がない前に、開発者が大規模モデルに基づいて AI アプリケーションを開発するプロセスは次のとおりです。

3

関数呼び出しの本質は、外部関数を呼び出す大規模言語モデルの機能です。つまり、チャット完了モデルは、独自のデータベース知識に基づいてのみ応答できなくなり、追加の関数ライブラリをマウントして関数を検索できるようになります。ユーザーの質問に応じてライブラリを作成し、実際のニーズに応じて外部関数を呼び出して関数の実行結果を取得し、関数の実行結果に基づいて回答します。基本的なプロセスは次のとおりです。

2

**簡単に理解すると、ビジネス シナリオに従って、対応する関数が自動的に選択され、出力がフォーマットされます。**単純なカスタム関数、または Google Mail を呼び出す関数や天気情報を取得できる関数など、外部ツール API をカプセル化した関数関数の場合があります。最後に、比較表を見てください。

4

2. 関数呼び出しの実装プロセス

複雑そうに見えますが、実際は非常に単純で、OpenAI がすでにそれを実行しています: 事前に外部関数ライブラリを定義し、対応するパラメーターを ChatCompletions.create() 関数に設定します

いわゆる外部関数ライブラリは、特定のアプリケーションを開発するときに使用する必要がある中間処理ロジック関数として理解できます。たとえば、メールの自動返信プログラムを開発したい場合は、次のように定義する必要があります。

  • メールを取得する機能
  • メールを送信する機能

チャット完了モデルが関数呼び出し関数を実装すると、大規模モデルはそのセマンティック理解能力を最大限に発揮し、ユーザーの入力を分析し、関数ライブラリ内で実行する最適な関数を自動的に選択して、質問に答えます。手動による介入が必要です。

2.1 外部関数ライブラリの正しいビルド方法

チャット完了モデルには関数呼び出し (Function Calling) 機能がありますが、関数の理解は従来のプログラミング環境の関数と同じではありませんダイアログでの効果的なプロンプト設計と同様に、関数呼び出しの形式と構造を最適化すると、モデルの実行の精度が大幅に向上します。したがって、適切なデータ入力形式を指定することが重要なステップとなり、データ形式が適切に設計されて初めて、モデルはタスクをより正確に理解して実行できます。

まず、受信データの形式を確認します。

2.1.1 入力データ形式

2.1.1.1 データフレーム/文字列データ形式

pandas ライブラリでは、DataFrameと のSeries2 つの主要なデータ構造があり、そのほとんどはデータ処理タスクに DataFrame 構造も使用するため、DataFrame データ サンプルを作成して、大規模なモデルがこのデータ形式を理解できるかどうかをテストできます。

  • データの準備
# 创建一个稍微复杂的DataFrame,包含多种数据类型
df_complex = pd.DataFrame({
    
    
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Salary': [50000.0, 100000.5, 150000.75],
    'IsMarried': [True, False, True]
})

出力は次のとおりです。

画像-20230823102325480

  • 確認する

大きなモデルを渡して、モデルがデータを解釈できるかどうかを確認します。

response = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-16k-0613",
  messages=[
    {
    
    "role": "system", "content": "你是一位优秀的数据分析师,现在有这样一份数据集:'%s'" % df_complex},
    {
    
    "role": "user", "content": "请解释一下这个数据集的分布情况"}
  ]
)

出力は次のとおりです。

response.choices[0].message['content']

画像-20230823103338024

モデルが DataFrame 形式のデータのデータ分布を正確に理解できることがわかります。さらに、より一般的なデータ形式が必要な場合は、 .to_string を使用して文字列に変換して渡すことができます。そして正しい解釈を得ることができます。

# 转化为字符串类型
df_complex_string = df_complex.to_string()

次のようにフォーマットされます。

画像-20230823103609271

2.1.1.2 JSONデータ形式

OpenAI が正式に推奨するデータ対話形式は JSON ですまた、上記の例からわかるように、大規模モデルは DataFrame/string 型データを正しく解釈できますが、データの可読性は高くありません。

画像-20230823103609271

同時に、プログラムのテスト中に、データが大きい場合、大規模モデルは文字列オブジェクトを DataFrame オブジェクト タイプとして正確に識別できない可能性があることも判明しました。クロスファンクションとしての JSON

つまり、より一般的なアプローチは、JSON 形式を利用して関数とプログラミング環境間で通信することです。

JSON (JavaScript Object Notation) は、シンプルで柔軟性があり、解析が簡単であるという主な理由から、多言語環境で広く使用されています。ほとんどすべての最新のプログラミング言語は JSON をサポートしており、JSON は真のクロスプラットフォームおよびクロス言語のデータ形式となっています。軽量でテキストのみの性質により、ネットワーク転送も非常に効率的になります。

  • データの準備

DataFrame を JSON 形式に変換することは、Python の pandas ライブラリを使用すると非常に簡単です。これは、DataFrameオブジェクトのメソッドを使用して直接実行します。to_json

# 将DataFrame转换为JSON格式,orient='split'参数将数据、索引和列分开存储
df_complex_json = df_complex.to_json(orient='split')

print(df_complex_json)

出力データ形式は次のとおりです。

画像-20230823104901148

  • 確認する
response = openai.ChatCompletion.create(
  model="gpt-3.5-turbo-16k-0613",
  messages=[
    {
    
    "role": "system", "content": "你是一位优秀的数据分析师,现在有这样一份数据集:'%s'" % df_complex_json},
    {
    
    "role": "user", "content": "请解释一下这个数据集的分布情况"}
  ]
)

モデル分析の状況を見てください。

画像-20230823105217517

通常、モデルは JSON オブジェクトのタイプを識別でき、多くのテストの結果、JSON のデータ形式がより明確に解釈でき、JSON オブジェクト自体の可読性が向上することがわかりました。

2.1.2 関数仕様の書き込み

関数呼び出し (関数呼び出し) を使用してチャット完了モデルと対話する場合、キー入力データ形式が選択されている場合、関数書き込みの仕様も同様に重要です。少なくとも以下が必要です。

  1. 明確な関数名: 明確で説明的な関数名を選択します。
  2. パラメータの順序と名前付け: パラメータには論理的な順序があり、わかりやすい名前を使用する必要があります。
  3. 関数の詳細な説明: 関数の機能と設定されたパラメーター変数を明確に説明する必要があります。
  • ステップ 1: データを準備する

このデータセットを例として取り上げます。

# 示例DataFrame
df_complex = pd.DataFrame({
    
    
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Salary': [50000.0, 100000.5, 150000.75],
    'IsMarried': [True, False, True]
})

# 将DataFrame转换为JSON格式(按'split'方向)
df_complex_json = df_complex.to_json(orient='split')

入力データ形式を見てください。

画像-20230823130656787

  • ステップ 2: 要件を設定する

このような要件があるとします。大規模モデルで、このデータセット内のすべての人の年齢の合計を計算させます。

  • ステップ 3: 年齢の合計を計算する関数を作成する

大規模なモデルで理解できる明確な関数は次のようになります。

def calculate_total_age_from_split_json(input_json):
    """
    从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。

    参数:
    input_json (str): 包含个体数据的JSON格式字符串。

    返回:
    str: 所有人的年龄总和,以JSON格式返回。
    """

    # 将JSON字符串转换为DataFrame
    df = pd.read_json(input_json, orient='split')

    # 计算所有人的年龄总和
    total_age = df['Age'].sum()

    # 将结果转换为字符串形式,然后使用json.dumps()转换为JSON格式
    return json.dumps({
    
    "total_age": str(total_age)})
  • ステップ 4: 機能テスト

前述したように、大規模モデルが受け取る最適なデータ形式は JSON であるため、関数が正常に計算できるかどうかをテストするために JSON 形式で渡します。コードは次のとおりです。

# 使用函数计算年龄总和,并以JSON格式输出
result = calculate_total_age_from_split_json(df_complex_json)
print("The JSON output is:", result)

出力を見てください。

画像-20230823131141919

  • ステップ 5: 関数ライブラリを定義する

実際にChatモデルがFunction呼び出し関数を実行する際には、関数ライブラリから適切な関数を選択して呼び出すため、関数ライブラリを用意する必要があります。最も単純なケースでは、次のように、関数ライブラリには関数を 1 つだけ含めることができます。

function_repository = {
    
    
            "calculate_total_age_from_split_json": calculate_total_age_from_split_json,
        }

関数ライブラリ オブジェクトは辞書である必要があり、キーと値のペアは関数を表します。ここで、Key は関数名を表す文字列、value は対応する関数を表します。したがって、上記のプロセスは次のように単純に理解できます。いわゆる外部関数ライブラリは、アプリケーション シナリオで必要なすべての関数定義を格納するために大きな辞書を使用することです。

2.2 関数パラメータを使用して外部関数情報を渡す方法

機能関数と関数ウェアハウスを作成した後、次に考えるべきことは、この関数に関連する情報をチャット完了モデルにどのように渡すかということです。

OpenAIの公式サイトでは、「ChatCompletion.create()のfunctionsパラメータを使用して、モデルに呼び出せる外部関数の内容情報を渡す。具体的なパラメータについては以下のように説明されている」としている

画像-20230724094533750

Functions パラメーターはmessages パラメーターと非常に似ており、両方とも複数の辞書のリストを含みます。メッセージの場合、各ディクショナリはメッセージであり、関数パラメータの場合、各ディクショナリは関数です。大規模言語モデル (LLM) が実際に質問応答を実行するとき、関数パラメーターによって提供される情報に従って各関数が取得されます。

同時に、OpenAI 公式 Web サイトでは、関数呼び出し関数をサポートする外部関数によって大規模モデルに返される結果の型は json 文字列型でなければならないと明確に規定されています

画像-20230724092119245

つまり、関数が受け取るパラメータは JSON Schema オブジェクトの形式で記述することが公式に規定されています。したがって、まず JSON スキーマ オブジェクトとは何かを理解する必要があります。

2.2.1 JSONスキーマオブジェクト

JSON スキーマは、JSON データの形式と構造を記述するためのメタデータ標準です。JSON ドキュメントの検証、注釈付け、操作に使用されます。JSON スキーマ自体は JSON 形式で表現され、オブジェクト プロパティのタイプ、配列の長さ、数値と文字列の値の範囲などを含むデータの構造を検証する柔軟な方法を提供します

簡単に言うと、JSON オブジェクトがある場合、JSON スキーマをオブジェクトの「テンプレート」または「定義」として使用して、JSON オブジェクトが所定のルールと構造に準拠しているかどうかを検証できます。たとえば、次のような単純な JSON スキーマの例は、個人の情報を記述するために使用されます。

{
    
    
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    
    
    "Name": {
    
    
      "type": "string"
    },
    "Age": {
    
    
      "type": "integer",
      "minimum": 0
    },
    "Salary": {
    
    
      "type": "number"
    },
    "IsMarried": {
    
    
      "type": "boolean"
    }
  },
  "required": ["Name", "Age"]
}
  • $schema: これは、使用される JSON スキーマ仕様のバージョンを定義する JSON スキーマ メタデータ フィールドです。
  • type: JSON オブジェクトが持つ必要があるデータ型を指定します。この例では 1 ですobject
  • properties: JSON オブジェクトの内部プロパティを記述するためのルール。これは、各キーが説明するプロパティ名であり、各値がプロパティが満たすべき条件であるオブジェクトです。
  • required: 必須フィールドをリストする配列。この例では、Nameと はAge必須フィールドです。

簡単に言うと、JSON スキーマ自体にはオブジェクトの特定のコンテンツ情報は含まれず、特定の種類のオブジェクトの形式情報のみが含まれます。

2.2.2 外部関数の JSON スキーマ記述の構築

したがって、外部関数を大規模モデルに渡す最初のステップは、記述された各関数関数に対応する JSON スキーマ記述を定義することです。**年齢の合計を計算するために定義した関数 Calculate_total_age_from_split_json については、その JSON スキーマの説明を次のように記述します。

calculate_total_age_from_split_json = {
    
    "name": "calculate_total_age_from_split_json",
                                       "description": "计算年龄总和的函数,从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。",
                                       "parameters": {
    
    "type": "object",
                                       "properties": {
    
    "input_json": {
    
    "type": "string",
                                                                     "description": "执行计算年龄总和的数据集"},
                                                   },
                                        "required": ["input_json"],
                                    },
                     }

この JSON スキーマは、calculate_total_age_from_split_json関数とそのパラメーターを詳細に説明します。以下にフィールドの詳細な説明を示します。

画像-20230823135158679

Calculate_total_age_from_split_json[“parameters”] を記述する必要があるのは、Chat モデルが会話中に送受信されるデータ情報が JSON のようなデータ形式で送信されるためです。

画像-20230823135352743

関数の公式パラメーターの説明は次のとおりです。 モデルが JSON 入力を生成できる関数のリスト。これは、モデルがデータ送信に JSON 形式を使用していることも示しています。この入出力形式は厳密に維持する必要があります。

画像-20230724101211196

2.3 関数呼び出し関数のロード方法

外部関数ウェアハウス、関数関数、関数関数に対応する JSON Schema オブジェクト記述を定義したら、基本的に準備作業は完了です。次に、大規模モデルのデータを操作できます。具体的には、ダイアログ パラメーターに基づいて 2 つの追加パラメーターを追加します。

  • 関数パラメータ: 外部関数ライブラリを宣言します
  • function_call パラメータ: Function 呼び出し関数を実行するかどうかを制御します。

画像-20230724094533750

そのコードは次のとおりです。

  • コモンダイアログ呼び出しコード
response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-16k-0613",
        messages=messages,
    )
  • 関数呼び出しを増やす
functions = [calculate_total_age_from_split_json]

response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-16k-0613",
        messages=messages,
        
        # 增加这两行
        functions=functions,
        function_call="auto",  
    )

3. 関数呼び出し処理の練習

**一般に、大規模なモデルに関数呼び出し機能を持たせたい場合は、3 つの段階を経る必要があります: 外部関数ライブラリの構築 -> 関数パラメーターを使用して関数情報を転送 -> 関数呼び出し関数のロード。**上記の年齢の合計の計算を例として使用する場合、完全なプロセスは次のようになります。

  • ステップ 1: データを準備する
# 示例DataFrame
df_complex = pd.DataFrame({
    
    
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Salary': [50000.0, 100000.5, 150000.75],
    'IsMarried': [True, False, True]
})

# 将DataFrame转换为JSON格式(按'split'方向)
df_complex_json = df_complex.to_json(orient='split')
  • ステップ 2: 要件を設定する

大きなモデルで、このデータセット内のすべての人々の年齢の合計を計算させます。

  • ステップ 3: 年齢の合計を計算する関数を作成する
def calculate_total_age_from_split_json(input_json):
    """
    从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。

    参数:
    input_json (str): 包含个体数据的JSON格式字符串。

    返回:
    str: 所有人的年龄总和,以JSON格式返回。
    """

    # 将JSON字符串转换为DataFrame
    df = pd.read_json(input_json, orient='split')

    # 计算所有人的年龄总和
    total_age = df['Age'].sum()

    # 将结果转换为字符串形式,然后使用json.dumps()转换为JSON格式
    return json.dumps({
    
    "total_age": str(total_age)})
  • ステップ 4: 機能テスト
# 使用函数计算年龄总和,并以JSON格式输出
result = calculate_total_age_from_split_json(df_complex_json)
print("The JSON output is:", result)
  • ステップ 5: 関数ライブラリを定義する
function_repository = {
    
    
            "calculate_total_age_from_split_json": calculate_total_age_from_split_json,
        }
  • ステップ 6: 関数関数の JSON スキーマを作成する
calculate_total_age_from_split_json = {
    
    "name": "calculate_total_age_from_split_json",
                      "description": "计算年龄总和的函数,从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。",
                      "parameters": {
    
    "type": "object",
                                     "properties": {
    
    "input_json": {
    
    "type": "string",
                                                             "description": "执行计算年龄总和的数据集"},
                                                   },
                                     "required": ["input_json"],
                                    },
                     }
  • ステップ 7: 関数のリストを作成する

入力モデルのメッセージ パラメーターが複数のメッセージを含むリストであるのと同様に、入力モデルの関数も複数の関数の説明を含むリストですが、現時点では関数が 1 つだけであるため、関数内の辞書は 1 つだけですリストのコードは次のとおりです。

functions = [calculate_total_age_from_split_json]

出力を見てください。

画像-20230823141518124

  • ステップ 8: メッセージを作成する
messages=[
    {
    
    "role": "system", "content": "你是一位优秀的数据分析师, 现在有这样一个数据集input_json:%s,数据集以JSON形式呈现" % df_complex_json},
    {
    
    "role": "user", "content": "请在数据集input_json上执行计算所有人年龄总和函数"}
]
  • ステップ 9: モデルを渡し、関数が自動的に選択され、計算が完了します。
response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-16k-0613",
        messages=messages,
        functions=functions,
        function_call="auto",  
    )

大規模モデルの計算結果を見てください。

画像-20230823142401938

Function Calling 関数パラメータが追加されると、データの戻り値は次のように変更されます。

  • 返されたメッセージの内容は null になります
  • 「function_call」ディクショナリが追加され、これには 2 つのキーと値のペアが含まれます。キーが「name」であるキーと値のペアは、ダイアログを完了するために呼び出す必要がある関数の名前、つまり、calculate_total_age_from_split_json を示します。 -key が「arguments」である値のペアは、関数に渡す必要があるパラメータを示します。

したがって、**大規模モデルの戻り結果にキーワード function_call が含まれている場合、このアシスタント メッセージが外部関数を呼び出す必要があることを意味します。**黒板をノックしてください。理解する必要があります。このメッセージは依然としてアシスタントからのメッセージですが、このメッセージにはコンテンツは含まれていませんが、キーワード function_call が含まれています。これは、メッセージ パラメーター 1 に含めることができる代替キーワードでもあります。の

Function Call には 2 つの重要な情報があります。

  • 関数名
  • 引数

これら 2 つの重要な情報は保存する必要があります。

  • ステップ 10: インタラクション中に重要な情報を保存する
# 保存交互过程中的函数名称
function_name = response["choices"][0]["message"]["function_call"]["name"]

# 加载交互过程中的参数
function_args = json.loads(response["choices"][0]["message"]["function_call"]["arguments"])

保存される情報は以下の通りです。

画像-20230823144133290

その理由は次のとおりです。 まず、需要シナリオは次のようになります。 データ セット df_complex_json に対して、calculate_total_age_from_split_json 関数を使用して、すべての人の年齢の合計を計算します。

大規模なモデルの場合、外部関数の計算プロセスはローカルで実行されるため、モデルから返された関数および関数パラメーターに従って関数の計算をローカルで完了し、計算プロセスと結果をファイルとして保存する必要があることを意味します。メッセージを取得してメッセージに追加し、チャット完了モデルを呼び出して関数の計算結果を 2 回目に分析し、最後に関数の計算結果に従ってユーザーの質問に対する回答を出力します。

  • ステップ 11: 関数オブジェクトを保存する
# 保存具体的函数对象
local_fuction_call = function_repository[function_name]

local_fuction_call の出力を見てください。

画像-20230823150153411

  • ステップ 12: モデル計算を完了する

function_args オブジェクトを local_fuction_call に直接渡して、すべてのパラメータを一度に転送します。コードは次のとおりです。

final_response = local_fuction_call(**function_args)

最終的な計算結果を見てください。

画像-20230823150406475

上記の 12 のプロセスを経て、モデルは外部関数を呼び出して計算を正常に完了できます。

  • ステップ最終: ビルドプロセスにメッセージを追加する

上で述べたように、ここでは、計算、推論、その他の機能のために外部関数を呼び出す大規模モデルのプロセスは次のようにする必要があることを繰り返します。モデルから返された関数および関数パラメーターに従って、関数の計算がローカルで完了し、その後、計算過程と結果を保存します。メッセージにメッセージが付加され、チャット完了モデル分析関数の計算結果が再度呼び出され、最後に関数の計算結果に応じてユーザーの質問に対する回答が出力されます。

したがって、このプロセスに基づいて、プログラムを次のように変換できます。

  1. モデルの最初の戻り結果をメッセージに追加します。
# 追加第一次模型返回结果消息
messages.append(response["choices"][0]["message"])
  1. モデルの 2 番目の戻り結果 (外部関数の計算結果) をメッセージに追加します。
# 追加function计算结果,注意:function message必须要输入关键词name
messages.append({
    
    "role": "function", "name": function_name, "content": final_response,})

したがって、このときのメッセージの内容は次のようになります。

画像-20230823152228338

  1. チャット完了モデルに再度質問する

この時点で、モデルに繰り返し質問する必要はなくなり、準備されたメッセージを Chat モデルに渡すだけです。コードは次のとおりです。

last_response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-16k-0613",
            messages=messages,)

最終的な出力を見てください。

画像-20230823152442700

最終的にモデルは正しく答えました。したがって、関数呼び出しでは、プロセス全体を正しく実行するために、チャット完了モデルの 2 つの呼び出しと 1 つのローカル関数計算が必要です。全体的なフローチャートは次のとおりです。

5

4. まとめ

この記事では、チャット完了モデルにおける関数呼び出し関数の背景を示し、次に関数呼び出しの実装プロセスを詳細に説明します。これには、文字列形式、Json 形式、関数形式の入力など、Chat 外部関数ライブラリを構築する方法が含まれます。また、外部関数を構築するための JSON および JSON スキーマ オブジェクト、Json スキーマ記述などの関数を定義する方法についても説明します。最後に、関数呼び出しの実装が詳細に紹介され、プロセス全体が要約され、関数呼び出しのアプリケーションに関する包括的かつ深い理解とガイダンスが提供されます。

最後に、この記事を読んでいただきありがとうございます! 何か得をしたと感じたら、ぜひ「いいね!」「ブックマーク」「フォロー」をしてください。これが私が創作を続けるモチベーションです。ご質問やご提案がございましたら、コメント欄にメッセージを残してください。できる限りお答えし、フィードバックを受け付けます。知りたい特定のトピックがございましたら、お知らせください。喜んでそれに関する記事を書きます。ご支援に感謝し、あなたと一緒に成長することを楽しみにしています!

おすすめ

転載: blog.csdn.net/Lvbaby_/article/details/131892482