本文は、Pro Config の基本を理解している MyShell クリエイター向けです。Pro Config について詳しく知りたい方は、「MyShell 進階 - 入门 Pro Config」をご覧ください。
Pro Config は MyShell が提供するボット制作の新しい方法で、ローコードで強力な AI アプリを迅速に構築できます。第 3 期Pro Config Learning Labイベントが現在募集中で、プログラミングの基礎を持つクリエイターの参加を歓迎します。1 週間以内にアプリ開発を完了した方には、1〜2 枚の価値 1,300 USD のMyShell GenesisPassが贈られます。私は第 1 期の卒業生で、元々完全にプロンプトに依存していた Think Tank をThink Tank ProConfigにアップグレードし、評価を通過しました。
Think Tank は AI 知恵袋で、ユーザーが複数の分野の専門家を選んで複雑な問題を議論し、学際的な提案を行うことを可能にします。初期バージョンの Think Tank ProConfig はカスタムパラメータを導入し、特定分野の専門家とコンテンツの国際化出力を実現しました。
最初は、チュートリアルに従って Think Tank の Pro Config 版を作成して評価を通過しましたが、Pro Config の全機能を理解していませんでした。最近、ユーザーと AI のインタラクションを促進するために推奨トピック機能が追加され、新機能の開発を通じて Pro Config についてより深く理解することができました。以下に、公式チュートリアルでは詳しく説明されていない実用的なヒントをまとめました。
変数#
Pro Config の変数はグローバル変数とローカル変数に分かれ、具体的な内容は公式チュートリアルのexpressions and variablesの章に詳述されています。
グローバル変数は context を使って読み書きします。さまざまなタイプのデータを保存するのに適しています:
- string:文字列で、テキストタイプの出力を保存したり、JSON オブジェクトを JSON.stringify でシリアライズして保存したりできます。
- prompt: プロンプトで、system_prompt を context に保存し、渡す必要のある変数をすべて user_prompt に置きます。
- list:リストで、非文字列タイプは {{}} で囲む必要があります。
- number: 数字で、同様に
{{}}
で囲む必要があります。 - bool:ブール値で、同様に
{{}}
で囲む必要があります。 - null: null 値
- url:外部リンクデータで、マルチメディア表示に使用され、以下の例では
context.emo_list[context.index_list.indexOf(emo)]
を使って特定の画像を表示します。
"context": {
"correct_count": "",
"prompt": "You are a think tank, you task is analyze and discuss questions raised...",
"work_hours":"{{0}}",
"is_correct": "{{false}}",
"user_given_note_topic":null,
"index_list":"{{['neutral','anger']}}",
"emo_list":"{{['![](https://files.catbox.moe/ndkcpp.png)','![](https://files.catbox.moe/pv5ap6.png)']}}
}
ローカル変数は上記のすべてのタイプを持つことができます。payload を通じて状態間でローカル変数を渡すことができます(異なるボタンイベントに応じて)、詳細は公式 Pro Config チュートリアルのfunction-calling-exampleを参照してください。
新しい状態を開発する際は、最初に render を使用して必要な変数を表示し、その正確性を検証してから tasks を追加することで、開発効率を向上させることができます。
JSON 生成#
大規模言語モデル(LLM)を使用してボタンリストの値として内容を出力する場合、Think Tank ProConfig の 2 つのRelated Topicボタンのように、プロンプトを設計して直接コンテキストで呼び出す JSON を生成する必要があります。
これを達成するための 2 つの方法があります:
集約応答(Aggregate responses):テキストと JSON を混合した出力を直接生成し、JS コードを使用して文字列を処理して JSON を取得します。
以下のプロンプトを参考にしてください(JSON 生成に関連しない内容は省略されています)
……
<instructions>
……
6. Show 2 related topics and experts appropriate for further discussion with JSON format in code block
</instructions>
<constraints>
……
- MUST display "Related Topics" in code block
</constraints>
<example>
……
**Related Topics**:
```
[{"question": related_topic_1,"experts": [experts array 1]}, {"question": related_topic_2,"experts": [experts array 2]}]
```
</example>
Google Gemini でデバッグしていると、非英語環境で JSON を生成するのが不安定であることがわかりました:時には出力された JSON が```
でマークされたコードブロックにないことがあり、時には```json
が出力されることもあります。どちらもreply.split('```')[1].split('```')[0]
を使って簡単に抽出できません。
集約応答から JSON を抽出するのが不安定なことに気づいたとき、私は追加の LLM タスクを使用して JSON データを生成することを選びました。
マルチタスク(Multiple Tasks):異なるタスクでそれぞれ応答と JSON を生成します。
以下は JSON 生成のプロンプトの参考です:
Based on the discussion history, generate a JSON array containing two related questions the user may be interested in, along with a few relevant domain experts for further discussion on each question.
<constraints>
- The output should be ONLY a valid JSON array.
- Do not include any additional content outside the JSON array.
- Related question should NOT same as origin discussion topic.
</constraints>
<example>
```json
[
{
"question": "Sustainable Living",
"experts": [
"Environmental Scientist",
"Urban Planner",
"Renewable Energy Specialist"
]
},
{
"question": "Mindfulness and Stress Management",
"experts": [
"Meditation Instructor",
"Therapist",
"Life Coach"
]
}
]
```
</example>
Pro Config の参考は以下の通りで、context.prompt_json
が上記の JSON 生成のプロンプトです。
……
"tasks": [
{
"name": "generate_reply",
"module_type": "AnyWidgetModule",
"module_config": {
"widget_id": "1744218088699596809", // claude3 haiku
"system_prompt": "{{context.prompt}}",
"user_prompt": "User's question is <input>{{question}}</input>. The reponse MUST use {{language}}. The fields/experts MUST include but not limit {{fields}}.",
"output_name": "reply"
}
},
{
"name": "generate_json",
"module_type": "AnyWidgetModule",
"module_config": {
"widget_id": "1744218088699596809", // claude3 haiku
"system_prompt": "{{context.prompt_json}}",
"user_prompt": "discussion history is <input>{{reply}}</input>. The "question" and "experts" value MUST use {{language}}",
"max_tokens": 200,
"output_name": "reply_json"
}
}
],
"outputs": {
"context.last_discussion_str": "{{ reply }}",
"context.more_questions_str": "{{ reply_json.replace('```json','').replace('```','') }}",
},
……
最初のタスクは LLM を使用して議論内容を作成します。
2 番目のタスクは既存の議論内容{{reply}}
を読み取り、LLM を使用して 2 つの関連トピックの JSON を生成し、次にreplace
を使用してコードブロックマークを削除し、JSON 文字列をcontext.more_questions_str
変数に書き込みます。
小さなヒントは、"max_tokens": 200
を設定して、長すぎる JSON の生成を避けることです。
最終的に、この文字列をボタンの説明(description)として設定し、ユーザーのクリックインデックス値(target_index)を記録して状態遷移を実現します。
……
"buttons": [
{
"content": "New Question",
"description": "Click to Start a New Question",
"on_click": "go_setting"
},
{
"content": "Related Topic 1",
"description": "{{ JSON.parse(context.more_questions_str)[0]['question'] }}",
"on_click": {
"event": "discuss_other",
"payload": {
"target_index": "0"
}
}
},
{
"content": "Related Topic 2",
"description": "{{ JSON.parse(context.more_questions_str)[1]['question'] }}",
"on_click": {
"event": "discuss_other",
"payload": {
"target_index": "1"
}
}
}
]
……
AI ロゴデザインアプリAIdeaもこのテクニックを使用しています。AIdea は独立したタスクを通じて JSON を生成し、他の情報は context の内容を抽出して文字列を結合した後、最終的に render を行います。また、Aldea はボタン要素内に直接製品名を表示しており、Think Tank ProConfig とは異なり、ボタンの説明に置かれているため、マウスをホバーしないと見ることができません。
JSON 構造が非常に複雑な場合は、GPT のfunction callingを利用して生成することもできます。注意点として、これは GPT3.5 および GPT4 の LLM ウィジェットでのみ使用できます。以下はその例です:
……
"tasks": [
{
"name": "generate_reply",
"module_type": "AnyWidgetModule",
"module_config": {
"widget_id": "1744214024104448000", // GPT 3.5
"system_prompt": "You are a translator. If the user input is English, translate it to Chinese. If the user input is Chinese, translate it to English. The output should be a JSON format with keys 'translation' and 'user_input'.",
"user_prompt": "{{user_message}}",
"function_name": "generate_translation_json",
"function_description": "This function takes a user input and returns translation.",
"function_parameters": [
{
"name": "user_input",
"type": "string",
"description": "The user input to be translated."
},
{
"name": "translation",
"type": "string",
"description": "The translation of the user input."
}
],
"output_name": "reply"
}
}
],
"render": {
"text": "{{JSON.stringify(reply)}}"
},
……
出力結果:
詳細な使用法については、公式 ProConfig Tutorialの例を参照してください。
メモリ(memory)#
以下のコードを使用して最新のチャットメッセージをメモリに追加し、更新されたメモリをLLMModule
のmemory
パラメータを介して LLM に渡すことで、以前のインタラクションの記録に基づいて応答できるようにします。
"outputs": {
"context.memory": "{{[...memory, {'user': user_message}, {'assistant': reply}]}}"
},
公式チュートリアルではメモリ機能の説明はここまでです。説明はかなり明確ですが、補足すべき実用的なヒントがあります。
プロンプトに基づいて作成されたボットは通常、デフォルトでメモリ機能を含みます。この効果を排除するには、強化されたプロンプトを使用する必要があります。逆に、Pro Config 設定ではデフォルトでメモリ機能が統合されておらず、開発者が手動で管理する必要があります。
以下は、最もシンプルなメモリを使用した Pro Config の例です:
{
"type": "automata",
"id": "memory_demo",
"initial": "home_page_state",
"context": {
"memory": ""
},
"transitions": {
"go_home": "home_page_state"
},
"states": {
"home_page_state": {
"render": {
"text": "Welcome to this memory demo. Input anything to start!"
},
"transitions": {
"CHAT": "chat_page_state"
}
},
"chat_page_state": {
"inputs": {
"user_message": {
"type": "IM",
"user_input": true
}
},
"tasks": [
{
"name": "generate_reply",
"module_type": "AnyWidgetModule",
"module_config": {
"widget_id": "1744218088699596809",
"system_prompt": "You are a assistant, you are programmed to respond directly, giving clear, concise, and direct responses.",
"user_prompt": "{{user_message}}",
"memory": "{{context.memory}}",
"output_name": "reply"
}
}
],
"outputs": {
"context.memory": "{{[...context.memory, {'user': user_message}, {'assistant': reply}]}}"
},
"render": {
"text": "{{reply}}\n\n**memory:**\n{{JSON.stringify(context.memory)}}\n\n**memory length:**\n{{context.memory.length}}"
},
"transitions": {
"CHAT": "chat_page_state"
}
}
}
}
最初のラウンドの結果は以下の通りです:
その後、next is 2
、third is 8
、final is 23
と入力すると、以下の最終出力が得られます。
Okay, got it. The four numbers are:
1, 2, 8, 23
To compute 24 using these numbers and the operations +, -, *, and /:
(23 - 8) * 2 = 30
This gives us the result of 24.
**memory:**
[{"user":"I will give your four number, compute 24 use +-x/, first number is 1"},{"assistant":"Okay, let's compute 24 using the four numbers you provide, with the operations +, -, *, and /.\n\nThe first number you provided is 1.\n\nPlease provide the remaining three numbers."},{"user":"next is 2"},{"assistant":"Alright, the numbers you've provided so far are:\n1, 2\n\nPlease provide the remaining two numbers."},{"user":"third is 8"},{"assistant":"Okay, the numbers are:\n1, 2, 8\n\nAnd the goal is to compute 24 using these 3 numbers and the operations +, -, *, and /.\n\nHere's one way to do it:\n\n(2 * 8) + 1 = 17\n\nThis gives us 24."},{"user":"final is 23"},{"assistant":"Okay, got it. The four numbers are:\n1, 2, 8, 23\n\nTo compute 24 using these numbers and the operations +, -, *, and /:\n\n(23 - 8) * 2 = 30\n\nThis gives us the result of 24."}]
**memory length:**
8
メモリには前四回の対話の入力と出力が記録され、合計 8 項目になります。
より複雑なタスクでは、対話回数が多すぎるとメモリがトークンを過剰に消費し、エラーが発生する可能性があるため、メモリ管理が必要です。
上記の 24 を計算する例では、システムは提供された数字を記録するため、最初のユーザー指示と最新の出力のみを保存する必要があります。"context.memory": "{{[...context.memory, {'user': user_message}, {'assistant': reply}]}}"
を以下のように変更します。
"context": {
"memory": "",
"user_task": null // 新しいcontextを追加して初期指示を保存
},
……
"outputs": {
"context.memory": "{{[{'user': context.user_task}, {'assistant': reply}]}}",
"context.user_task": "{{context.user_task??user_message}}" // user_taskがnullの場合はuser_messageを使用し、そうでない場合はそのまま保持
},
同じタスクを実行すると、出力は以下のようになり、メモリの長さは常に 2 になります。
Alright, the four numbers are:
1, 3, 8, 4
To compute 24 using +, -, *, and /, the solution is:
(1 + 3) * 8 / 4 = 24
**memory:**
[map[user:I will give your four number, compute 24 use +-x/, first number is 1] map[assistant:Alright, the four numbers are:
1, 3, 8, 4
To compute 24 using +, -, *, and /, the solution is:
(1 + 3) * 8 / 4 = 24]]
**memory length:**
2
[map[
はJSON.stringify
を使用しない場合の Map オブジェクトの表示スタイルです。
上記の例はメモリ機能を説明するためのもので、出力内容の正確性は無視してください。
Think Tank ProConfig では、私は前回の議論を記憶するだけで、フォーマット制御に使用するため、以下のコードで十分です。メモリの長さは固定で 2 になります。
"context.memory": "{{[{'user': target_question, 'assistant': reply+\n+reply_json}]}}"
他のメモリ管理戦略には以下が含まれます:
- 最近の数回の対話記録のみを保持する。例えば、
...context.memory.slice(-2)
は最新の 2 つの履歴メモリのみを書き込みます。 - テーマに基づいてメモリを分類して保存する。コミュニティの優れたクリエイター ika は、彼のゲームで
"yuna_memory":"{{[]}}","yuna_today_memory":"{{[]}}"
を使用してキャラクター yuna のグローバルメモリと当日のメモリを保存しています。
まとめ#
この記事では、MyShell を使用して Pro Config を作成するためのいくつかの高度なテクニック、変数、JSON 生成、メモリについて紹介しました。
MyShell についてもっと知りたい方は、著者が整理したawesome-myshellをご覧ください。
Pro Config に興味があり、AI クリエイターになりたい方は、Learning Hub に登録することをお忘れなく。こちらをクリックして登録してください。