docs: add ja docs

This commit is contained in:
Junyan Qin
2025-12-12 17:55:27 +08:00
parent 65c7b01e06
commit 85ec20deb3
72 changed files with 8252 additions and 1 deletions
+312
View File
@@ -0,0 +1,312 @@
# プラグイン共通API
LangBotは、プラグインがさまざまなLangBotモジュールを操作し、メッセージコンテキストを制御するための一連のAPIを提供します。
:::info 目次
[[toc]]
:::
## リクエストAPI
現在処理中のユーザーリクエスト(メッセージ)に対する操作です。`EventListener`と`Command`コンポーネントでのみ使用可能です。アクセス方法:
- `EventListener`のイベントハンドラメソッド内: `event_context: context.EventContext`オブジェクトの内部メソッド
- `Command`のサブコマンドハンドラメソッド内: `context: ExecuteContext`オブジェクトの内部メソッド
### 直接返信メッセージ
現在のリクエストが存在するセッションにメッセージチェーンで直接返信します。
メッセージチェーンの構築方法については、[メッセージプラットフォームエンティティ](/en/plugin/dev/apis/messages)を参照してください。
```python
async def reply(
self, message_chain: platform_message.MessageChain, quote_origin: bool = False
):
"""メッセージリクエストに返信する
Args:
message_chain (platform.types.MessageChain): LangBotメッセージチェーン
quote_origin (bool): 元のメッセージを引用するかどうか
"""
# 使用例
await event_context.reply(
platform_message.MessageChain([
platform_message.Plain(text="Hello, world!"),
]),
)
```
### Bot UUIDの取得
現在のリクエストを発行したBotのUUIDを取得します。
```python
async def get_bot_uuid(self) -> str:
"""Bot UUIDを取得する"""
# 使用例
bot_uuid = await event_context.get_bot_uuid()
```
### リクエスト変数の設定
単一のリクエスト内の一部の情報は、リクエスト変数に保存されます。Difyなどの外部LLMOpsプラットフォームを使用する場合、[これらの変数はLLMOpsプラットフォームに明示的に渡されます](/en/deploy/pipelines/readme.html#request-variables)。
```python
async def set_query_var(self, key: str, value: Any):
"""クエリ変数を設定する"""
# 使用例
await event_context.set_query_var("key", "value")
```
### リクエスト変数の取得
単一のリクエスト変数を取得します。
```python
async def get_query_var(self, key: str) -> Any:
"""クエリ変数を取得する"""
# 使用例
query_var = await event_context.get_query_var("key")
```
### すべてのリクエスト変数の取得
```python
async def get_query_vars(self) -> dict[str, Any]:
"""すべてのクエリ変数を取得する"""
# 使用例
query_vars = await event_context.get_query_vars()
```
## LangBot API
これらのAPIは、任意のプラグインコンポーネントで呼び出すことができます。アクセス方法:
- プラグインルートディレクトリの`main.py`内: `self`オブジェクトの内部メソッド。これらのAPIはすべて、プラグインクラスの親クラス`BasePlugin`によって提供されます。
- 任意のプラグインコンポーネントクラス内: `self.plugin`オブジェクトの内部メソッド。
### プラグイン設定の取得
プラグイン設定フォーマットは`manifest.yaml`に記述でき、ユーザーはLangBotのプラグイン管理でプラグイン設定フォーマットに従って入力する必要があります。プラグインコードはこのAPIを呼び出してプラグイン設定情報を取得できます。
```python
def get_config(self) -> dict[str, typing.Any]:
"""プラグインの設定を取得する。"""
# 使用例
config = self.plugin.get_config()
```
### LangBotバージョンの取得
LangBotのバージョン番号を取得します。`v<major>.<minor>.<patch>`形式の文字列として返されます。
```python
async def get_langbot_version(self) -> str:
"""LangBotバージョンを取得する"""
# 使用例
langbot_version = await self.plugin.get_langbot_version()
```
### 設定済みBotリストの取得
すべてのBot UUIDのリストを返します。
```python
async def get_bots(self) -> list[str]:
"""すべてのBotを取得する"""
# 使用例
bots = await self.plugin.get_bots()
```
### Bot情報の取得
Bot情報を取得します。
```python
async def get_bot_info(self, bot_uuid: str) -> dict[str, Any]:
"""Bot情報を取得する"""
# 使用例
bot_info = await self.plugin.get_bot_info("de639861-be05-4018-859b-c2e2d3e0d603")
# 返り値の例
{
"uuid": "de639861-be05-4018-859b-c2e2d3e0d603",
"name": "aiocqhttp",
"description": "Migrated from LangBot v3",
"adapter": "aiocqhttp",
"enable": true,
"use_pipeline_name": "ChatPipeline",
"use_pipeline_uuid": "c30a1dca-e91c-452b-83ec-84d635a30028",
"created_at": "2025-05-10T13:53:08",
"updated_at": "2025-08-12T11:27:30",
"adapter_runtime_values": { # Botが現在実行中の場合に存在
"bot_account_id": 960164003 # BotアカウントID
}
}
```
### プロアクティブメッセージの送信
Bot UUIDとターゲットセッションIDを通じてプロアクティブメッセージを送信します。
メッセージチェーンの構築方法については、[メッセージプラットフォームエンティティ](/en/plugin/dev/apis/messages)を参照してください。
```python
async def send_message(
self,
bot_uuid: str,
target_type: str,
target_id: str,
message_chain: platform_message.MessageChain,
) -> None:
"""セッションにメッセージを送信する"""
# 使用例
await self.plugin.send_message(
bot_uuid="de639861-be05-4018-859b-c2e2d3e0d603",
target_type="person",
target_id="1010553892",
message_chain=platform_message.MessageChain([platform_message.Plain(text="Hello, world!")]),
)
```
### 設定済みLLMモデルリストの取得
設定されたすべてのLLMモデルのUUIDのリストを返します。
```python
async def get_llm_models(self) -> list[str]:
"""すべてのLLMモデルを取得する"""
# 使用例
llm_models = await self.plugin.get_llm_models()
```
### LLMモデルの呼び出し
LLMモデルを呼び出し、LLMメッセージを返します。非ストリーミング。
```python
async def invoke_llm(
self,
llm_model_uuid: str,
messages: list[provider_message.Message],
funcs: list[resource_tool.LLMTool] = [],
extra_args: dict[str, Any] = {},
) -> provider_message.Message:
"""LLMモデルを呼び出す"""
# 使用例
llm_message = await self.plugin.invoke_llm(
llm_model_uuid="llm_model_uuid",
messages=[provider_message.Message(role="user", content="Hello, world!")],
funcs=[],
extra_args={},
)
```
### プラグイン永続データの設定
プラグインデータを永続的に保存します。このインターフェースを通じて保存されたデータは、このプラグインのみがアクセスできます。値は手動でbytesに変換する必要があります。
```python
async def set_plugin_storage(self, key: str, value: bytes) -> None:
"""プラグインストレージ値を設定する"""
# 使用例
await self.plugin.set_plugin_storage("key", b"value")
```
### プラグイン永続データの取得
```python
async def get_plugin_storage(self, key: str) -> bytes:
"""プラグインストレージ値を取得する"""
# 使用例
plugin_storage = await self.plugin.get_plugin_storage("key")
```
### すべてのプラグイン永続データキーの取得
```python
async def get_plugin_storage_keys(self) -> list[str]:
"""すべてのプラグインストレージキーを取得する"""
# 使用例
plugin_storage_keys = await self.plugin.get_plugin_storage_keys()
```
### プラグイン永続データの削除
```python
async def delete_plugin_storage(self, key: str) -> None:
"""プラグインストレージ値を削除する"""
# 使用例
await self.plugin.delete_plugin_storage("key")
```
### ワークスペース永続データの取得
このインターフェースを通じて保存されたデータは、すべてのプラグインがアクセスできます。値は手動でbytesに変換する必要があります。
```python
async def set_workspace_storage(self, key: str, value: bytes) -> None:
"""ワークスペースストレージ値を設定する"""
# 使用例
await self.plugin.set_workspace_storage("key", b"value")
```
### ワークスペース永続データの取得
```python
async def get_workspace_storage(self, key: str) -> bytes:
"""ワークスペースストレージ値を取得する"""
# 使用例
workspace_storage = await self.plugin.get_workspace_storage("key")
```
### すべてのワークスペース永続データキーの取得
```python
async def get_workspace_storage_keys(self) -> list[str]:
"""すべてのワークスペースストレージキーを取得する"""
# 使用例
workspace_storage_keys = await self.plugin.get_workspace_storage_keys()
```
### ワークスペース永続データの削除
```python
async def delete_workspace_storage(self, key: str) -> None:
"""ワークスペースストレージ値を削除する"""
# 使用例
await self.plugin.delete_workspace_storage("key")
```
### プラグインファイル型設定フィールドデータの取得
```python
async def get_config_file(self, file_key: str) -> bytes:
"""設定ファイル値を取得する"""
# 使用例
file_bytes = await self.plugin.get_config_file("key")
```
これは[`file`または`array[file`](/en/plugin/dev/basic-info.html#type-file)型の設定フィールドと組み合わせて使用します。
+96
View File
@@ -0,0 +1,96 @@
# メッセージプラットフォームエンティティ
:::info 目次
[[toc]]
:::
LangBotは複数のメッセージングプラットフォームをサポートしており、各プラットフォームには異なる`メッセージエンティティ`フォーマットがあります。これらの違いを抽象化するために、統一された標準を実装しました。プラグイン開発者は、プラグイン内でこのページに記載されているメッセージエンティティを習得して使用するだけで、LangBotの内部メッセージ処理ロジックがメッセージの解析と変換を自動的に処理します。
## メッセージチェーン
メッセージングプラットフォーム上の`メッセージ`は、AI対話に使用されるメッセージとは異なります。メッセージングプラットフォーム上のメッセージは、`メッセージチェーン`の形式で記述されます。QQに表示される各独立したメッセージはメッセージチェーンであり、`テキスト`、`画像`、`@メンション`などのさまざまな`メッセージチェーンコンポーネント`を含むことができます。例えば:
![](/assets/image/zh/plugin/dev/apis/plugin_dev_messages_01.png)
これは、1つのPlainコンポーネント(Hello World)と1つのImageコンポーネント(Usagi)を含むメッセージチェーンです。
メッセージチェーンとメッセージチェーンコンポーネントの定義は、`langbot_plugin.api.entities.platform.message`にあります。
### メッセージチェーンの構築
まず、`langbot_plugin.api.entities.platform.message`パッケージをインポートして、その中のメッセージコンポーネントを使用してください。
```python
from langbot_plugin.api.entities.platform.message import *
# テキスト「Hello LangBot」と画像(URLから)を含むメッセージを構築
msg_chain = MessageChain([
Plain(text="Hello LangBot"),
Image(url='https://qchatgpt.rockchin.top/langbot-logo.png')
])
# @全員とテキスト「Hello LangBot」を含むメッセージを構築
msg_chain = MessageChain([
AtAll(),
Plain(text="Hello LangBot")
])
# @特定のメンバーとテキスト「Hello LangBot」を含むメッセージを構築
msg_chain = MessageChain([
At(target=123456),
Plain(text="Hello LangBot")
])
```
現在サポートされているメッセージチェーンコンポーネント:
- `Source` - ソースメッセージチェーン情報。メッセージングプラットフォームから受信したメッセージには、メッセージ情報を記録するためにメッセージチェーンの先頭にこのコンポーネントが含まれます
- `Plain` - プレーンテキストメッセージ
- `Quote` - 引用メッセージ
- `Image` - 画像メッセージ
- `AtAll` - @全員メッセージ
- `At` - @特定のメンバーメッセージ
- `Voice` - 音声メッセージ
- メッセージングプラットフォームのサポートを確認する必要があります
- `Forward` - 転送メッセージ
- 多くのプラットフォームでサポートされていないため、推奨されません
- `File` - ファイルメッセージ
コンポーネントを作成する際は、名前付きパラメータを使用する必要があります。具体的な使用方法については、ソースコード`langbot_plugin.api.entities.platform.message`の定義を確認してください。
## その他のエンティティ
上記のエンティティに加えて、`Friend`や`Group`などのエンティティもあります。これらのエンティティは`langbot_plugin.api.entities.platform.entities`で定義されています。
## 基盤プラットフォームAPIへのアクセス
:::warning 注意
4.xには適用されません。
:::
プラットフォームの違いを抽象化するために、LangBotはメッセージングプラットフォームAPIの上に抽象化レイヤーを提供しています。これには、上記で説明した内容と、`pkg/platform/sources`ディレクトリ内のさまざまなプラットフォームアダプターが含まれます。
ただし、プラットフォームの違いが大きいため、抽象化レイヤーのエンティティとAPIのカプセル化は完全ではありません。プラグインがプラットフォーム固有の機能にアクセスする必要がある場合は、次の手順に従って基盤APIにアクセスできます。
:::info
ここでの`adapter`は、各アダプターのインスタンス化されたオブジェクトであり、`pkg/platform/sources/`以下のファイル内の`xxxAdapter(adapter.MessagePlatformAdapter)`クラスに対応します。プラグインイベントの`query.adapter`から取得できます。例えば:
```python
# 例えばプラグイン内で
@handler(GroupMessageReceived)
async def _(self, ctx: EventContext):
# アダプターオブジェクトを取得
adapter = ctx.query.adapter
```
:::
| プラットフォーム | アダプター | アクセス方法 | 説明 |
| --- | --- | --- | --- |
| OneBot v11| aiocqhttp | adapter.bot | botオブジェクトは[aiocqhttp](https://github.com/nonebot/aiocqhttp) CQHttpオブジェクトに対応します。詳細な使用方法についてはaiocqhttpドキュメントを参照してください |
| QQ公式API | qqofficial | adapter.bot | botオブジェクトはlibs/qq_official_api以下のSDKオブジェクトです。詳細な使用方法については、libs/qq_official_api/api.pyの`QQOfficialClient`内の`send_group_text_msg`メソッドを参照してHTTPリクエストメソッドを確認し、具体的なインターフェースドキュメントについてはQQ公式APIドキュメントを参照してください |
| WeCom(企業微信) | wecom | adapter.bot | libs/wecom_api/api.pyの`WecomClient`内の`send_image`メソッドを参照してHTTPリクエストメソッドを確認し、具体的なインターフェースドキュメントについてはWeCom APIドキュメントを参照してください |
| WeChat公式アカウント | officialaccount | - | インターフェースドキュメントについてはWeChat公式アカウントAPIドキュメントを参照してください。認証情報はadapter.botから取得できます |
| Lark | lark | adapter.api_client | Lark SDKのAPI Clientオブジェクトです。詳細については[oapi-sdk-python](https://github.com/larksuite/oapi-sdk-python)を参照してください |
| DingTalk | dingtalk | - | DingTalk APIドキュメントを参照してください。認証情報はadapter.botから取得できます |
| Discord | discord | adapter.bot | botオブジェクトは[Rapptz/discord.py](https://github.com/Rapptz/discord.py) Discordオブジェクトです。詳細な使用方法についてはドキュメントを参照してください |
| Telegram | telegram | adapter.bot | botオブジェクトは[python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) Telegramオブジェクトです。詳細な使用方法についてはドキュメントを参照してください |
| Slack | slack | adapter.bot | botオブジェクトはlibs/slack_api/api.py内にあります。詳細な使用方法についてはそのコードとSlack SDKを参照してください |
+293
View File
@@ -0,0 +1,293 @@
# パイプラインイベントとAPI
:::info 目次
[[toc]]
:::
LangBotプラグインはパイプラインイベントを登録して処理できます。使用方法については、[コンポーネント: イベントリスナー](/en/plugin/dev/components/event-listener)を参照してください。
## イベント一覧
一部のイベントには`設定可能な属性`があり、プラグインコードで変更して、その後のLangBot処理で使用できます。
### *MessageReceived
グループチャットまたはプライベートチャットでメッセージを受信したときにトリガーされます。
```python
class PersonMessageReceived(BaseEventModel):
"""プライベートチャットメッセージを受信したとき"""
event_name: str = "PersonMessageReceived"
launcher_type: str
"""起動元オブジェクトタイプ(person)"""
launcher_id: typing.Union[int, str]
"""送信者ID"""
sender_id: typing.Union[int, str]
"""送信者ID"""
message_chain: platform_message.MessageChain = pydantic.Field(
serialization_alias="message_chain"
)
"""生のメッセージチェーン"""
class GroupMessageReceived(BaseEventModel):
"""グループチャットメッセージを受信したとき"""
event_name: str = "GroupMessageReceived"
launcher_type: str
"""起動元オブジェクトタイプ(group)"""
launcher_id: typing.Union[int, str]
"""グループID"""
sender_id: typing.Union[int, str]
"""送信者ID"""
message_chain: platform_message.MessageChain = pydantic.Field(
serialization_alias="message_chain"
)
"""生のメッセージチェーン"""
```
### *NormalMessageReceived
グループチャットまたはプライベートチャットメッセージを受信し、LLMで処理する必要があるメッセージ(コマンドでないメッセージ)であると判定されたときにトリガーされます。
```python
class PersonNormalMessageReceived(BaseEventModel):
"""処理すべきプライベートチャット通常メッセージが判定されたときにトリガーされる"""
event_name: str = "PersonNormalMessageReceived"
launcher_type: str
launcher_id: typing.Union[int, str]
sender_id: typing.Union[int, str]
text_message: str
"""メッセージテキスト"""
message_chain: platform_message.MessageChain = pydantic.Field(
serialization_alias="message_chain"
)
"""生のメッセージチェーン"""
# ========== 設定可能な属性 ==========
user_message_alter: typing.Optional[provider_message.ContentElement] = None
"""変更されたメッセージテキスト、langbot_plugin.api.entities.builtin.provider.message.ContentElement型"""
reply_message_chain: typing.Optional[platform_message.MessageChain] = None
"""返信メッセージコンポーネントリスト、デフォルト動作を防止した場合のみ有効"""
class GroupNormalMessageReceived(BaseEventModel):
"""処理すべきグループチャット通常メッセージが判定されたときにトリガーされる"""
event_name: str = "GroupNormalMessageReceived"
launcher_type: str
launcher_id: typing.Union[int, str]
sender_id: typing.Union[int, str]
text_message: str
"""メッセージテキスト"""
message_chain: platform_message.MessageChain = pydantic.Field(
serialization_alias="message_chain"
)
"""生のメッセージチェーン"""
# ========== 設定可能な属性 ==========
user_message_alter: typing.Optional[provider_message.ContentElement] = None
"""変更されたメッセージテキスト、langbot_plugin.api.entities.builtin.provider.message.ContentElement型"""
reply_message_chain: typing.Optional[platform_message.MessageChain] = None
"""返信メッセージコンポーネントリスト、デフォルト動作を防止した場合のみ有効"""
```
### *CommandSent
:::warning 注意
使用は推奨されなくなりました。代わりに[コンポーネント: Command](/en/plugin/dev/components/command)を使用してください。
:::
グループチャットまたはプライベートチャットでコマンドを受信したときにトリガーされます。
```python
class PersonCommandSent(BaseEventModel):
"""処理すべきプライベートチャットコマンドが判定されたときにトリガーされる"""
event_name: str = "PersonCommandSent"
launcher_type: str
launcher_id: typing.Union[int, str]
sender_id: typing.Union[int, str]
command: str
"""コマンドテキスト"""
params: list[str]
"""コマンドパラメータ"""
text_message: str
"""メッセージテキスト"""
is_admin: bool
"""管理者かどうか"""
class GroupCommandSent(BaseEventModel):
"""処理すべきグループチャットコマンドが判定されたときにトリガーされる"""
event_name: str = "GroupCommandSent"
launcher_type: str
launcher_id: typing.Union[int, str]
sender_id: typing.Union[int, str]
command: str
"""コマンドテキスト"""
params: list[str]
"""コマンドパラメータ"""
text_message: str
"""メッセージテキスト"""
is_admin: bool
"""管理者かどうか"""
```
### NormalMessageResponded
メッセージがLLMレスポンスを受信したときにトリガーされます。
```python
class NormalMessageResponded(BaseEventModel):
"""通常メッセージに返信するときにトリガーされる"""
event_name: str = "NormalMessageResponded"
launcher_type: str
launcher_id: typing.Union[int, str]
sender_id: typing.Union[int, str]
session: provider_session.Session
"""セッションオブジェクト"""
prefix: str
"""返信メッセージプレフィックス"""
response_text: str
"""返信メッセージテキスト"""
finish_reason: str
"""レスポンス終了理由"""
funcs_called: list[str]
"""呼び出された関数のリスト"""
# ========== 設定可能な属性 ==========
reply_message_chain: typing.Optional[platform_message.MessageChain] = None
"""返信メッセージコンポーネントリスト、デフォルト動作を防止した場合のみ有効"""
```
### PromptPreProcessing
LLMレスポンスコンテキスト(プロンプト)を構築するときにトリガーされます。
```python
class PromptPreProcessing(BaseEventModel):
"""セッション内のプロンプトを前処理するときにトリガーされる"""
event_name: str = "PromptPreProcessing"
session_name: str
# ========== 設定可能な属性 ==========
default_prompt: list[typing.Union[provider_message.Message, provider_message.MessageChunk]]
"""この会話のシナリオプリセット、変更可能、langbot_plugin.api.entities.builtin.provider.message.Messageまたはlangbot_plugin.api.entities.builtin.provider.message.MessageChunk型"""
prompt: list[typing.Union[provider_message.Message, provider_message.MessageChunk]]
"""この会話の既存メッセージレコード、変更可能、langbot_plugin.api.entities.builtin.provider.message.Messageまたはlangbot_plugin.api.entities.builtin.provider.message.MessageChunk型"""
```
## イベントコンテキストAPI
```python
...
@self.handler(events.PersonMessageReceived)
async def handler(event_context: context.EventContext):
...
```
イベント処理メソッドには`EventContext`オブジェクトが渡され、イベントコンテキスト情報が含まれます。このオブジェクトには[リクエストAPI](/en/plugin/dev/apis/common)とイベントコンテキスト固有のAPIの両方があります。以下は、イベントコンテキスト固有のAPIのリストです:
### 元のイベント属性の取得
`event_context.event`属性は元のイベントオブジェクトであり、元のイベントの属性を取得できます。型はリッスンされているイベントの型です。
例えば、リッスンされているイベントが`GroupMessageReceived`の場合:
```python
event = event_context.event
print(event.launcher_type) # 起動元オブジェクトタイプ(group)
print(event.launcher_id) # グループID
print(event.sender_id) # 送信者アカウントID
print(event.message_chain) # メッセージチェーン
```
### デフォルト動作を防止
```python
def prevent_default(self):
"""デフォルト動作を防止する"""
# 使用例
event_context.prevent_default()
```
このメソッドを呼び出すと、このイベントのデフォルトの後続動作が防止され、パイプラインは直接終了します。
:::info
次のイベントのみがデフォルト動作を防止できます:
- PersonMessageReceived
- GroupMessageReceived
- PersonNormalMessageReceived
- GroupNormalMessageReceived
- PersonCommandSent
- GroupCommandSent
- NormalMessageResponded
:::
### 後続実行を防止
```python
def prevent_postorder(self):
"""後続実行を防止する"""
# 使用例
event_context.prevent_postorder()
```
このメソッドを呼び出すと、後続のプラグインがこの時点で実行されなくなります。
+11
View File
@@ -0,0 +1,11 @@
# プラグイン技術詳細
## アーキテクチャ
<img width="600" src="/assets/image/zh/plugin/dev/plugin_system_arch.png" />
バージョン4.0では、高セキュリティで柔軟性の高い本番環境グレードのプラグインシステムを導入し、開発者に豊富なAPIと使いやすいサポートツールを提供しています。
Plugin Runtimeは、プラグインのライフサイクルを管理し、LangBotとプラグイン間の相互作用を調整するために使用されます。`stdio`と`websocket`の2つの動作モードがあります。LangBotがユーザーによって直接起動される場合(コンテナ内で実行されていない場合)、`stdio`モードを使用します。これは個人ユーザーや軽量環境で一般的です。LangBotがコンテナ内で実行される場合、`websocket`モードを使用します。これは本番環境専用に設計されています。
Plugin Runtimeは、インストールされた各プラグインを自動的に起動し、stdioを通じて相互作用します。プラグイン開発シナリオでは、開発者は`lbp`コマンドラインツールを使用してプラグインを起動し、WebSocketを介して実行中のRuntimeに接続してデバッグできます。
+244
View File
@@ -0,0 +1,244 @@
# プラグイン設定情報の完成
:::info 目次
[[toc]]
:::
## マニフェストファイルの修正
プラグインディレクトリ内の`manifest.yaml`ファイルは、プラグインの基本情報を宣言します。これはLangBot UIまたはプラグインマーケットプレイスのインターフェースに表示されます。
```yaml
apiVersion: v1 # 変更しないでください
kind: Plugin # 変更しないでください
metadata:
author: RockChinQ # 作成者、正規表現^[a-zA-Z0-9_-]+$に一致する必要があります
name: HelloPlugin # プラグイン名、プラグインを区別するために使用、正規表現^[a-zA-Z0-9-]+$に一致する必要があります
repository: 'https://github.com/langbot-app/HelloPlugin' # プラグインリポジトリURL
version: 0.1.0 # プラグインバージョン
description:
en_US: 'Hello LangBot Plugin' # プラグイン説明、多言語対応
zh_Hans: 'Hello LangBot Plugin'
label:
en_US: HelloPlugin # プラグインラベル、インターフェースに表示、多言語対応
zh_Hans: HelloPlugin
icon: assets/icon.svg # プラグインアイコン、デフォルトはassets/icon.svg、さまざまな画像形式に置き換え可能
spec:
config: [] # プラグイン設定項目フォーマット
components: {} # プラグインコンポーネントリスト、手動で変更する必要はありません
execution:
python:
path: main.py # 変更しないでください
attr: HelloPlugin # 変更しないでください
```
プラグインの多言語サポートは[RFC 4646](https://datatracker.ietf.org/doc/html/rfc4646)標準に従います。現在サポートされている言語は次のとおりです:
- `en_US` 英語
- `zh_Hans` 簡体字中国語
- `zh_Hant` 繁体字中国語
- `ja_JP` 日本語
## プラグイン設定項目フォーマット
`manifest.yaml`ファイルの`spec.config`で宣言されたフィールドは、LangBotによってユーザーが入力するための設定項目フォームとしてレンダリングされます。プラグインは、SDKが提供するAPIを通じて、ユーザーが入力した設定項目を取得できます(後のセクションを参照)。
例えば:
```yaml
spec:
config:
- name: github_token # 必須; 設定項目名、プラグイン内での取得に使用
type: string # 必須; 設定項目タイプ、string、integer、float、boolean、select、prompt-editor、llm-model-selector、bot-selectorなどをサポート
label: # 必須; 設定項目表示名、多言語サポート。言語コードはRFC 4646標準に従います。
en_US: Github Token
zh_Hans: Github Token
description: # 設定項目説明、多言語サポート。オプション。
en_US: Image downloading requires a Github token
zh_Hans: 如果不填的話、图片可能會下載失败
default: '' # 設定項目のデフォルト値、オプション。
required: false # 設定項目が必須かどうか、オプション。
- name: mode
type: select
...
```
設定項目でサポートされるタイプとフィールドは次のとおりです:
### type: string
文字列型。
```yaml
- name: api_key
type: string
...
```
### type: array[string]
文字列配列。
```yaml
- name: tags
type: array[string]
...
```
### type: integer
整数型。
```yaml
- name: progress
type: integer
...
```
### type: float
浮動小数点型。
```yaml
- name: temperature
type: float
...
```
### type: boolean
ブール型。
```yaml
- name: is_enabled
type: boolean
...
```
### type: select
ドロップダウンメニュー。`options`の設定が必要で、ドロップダウンメニューのオプションを表します。
```yaml
- name: mode
type: select
options: # ドロップダウンオプション、多言語サポート。
- name: mode1 # 値
label: # 表示名、多言語サポート。
en_US: Mode 1
zh_Hans: 模式 1
- name: mode2
label: # 表示名、多言語サポート。
en_US: Mode 2
zh_Hans: 模式 2
...
```
### type: prompt-editor
プロンプトエディター。パイプライン設定ページからプロンプトエディターを表示し、最終結果はOpenAIの`messages`形式で表されます。
```yaml
- name: prompt
type: prompt-editor
...
```
### type: text
大きなテキスト入力。フロントエンドでtextareaとしてレンダリングされ、ユーザーが入力し、文字列としてプラグインに渡されます。
```yaml
- name: prompt
type: text
...
```
### type: file
ファイルアップロード。最大10MBのファイルアップロードをサポートし、`{"file_key": "xxxxx.xxx", "mimetype": "xxxxx"}`形式でプラグインに渡されます。プラグインは`get_config_file` APIを使用してファイルの内容を取得できます。
```yaml
- name: config_file
type: file
accept: 'application/json' # オプション、受け入れるファイルMIMEタイプを指定
...
```
プラグインでファイルを取得する:
```python
# 設定からファイル情報を取得
file_config = self.get_config()['config_file']
file_key = file_config['file_key']
mimetype = file_config['mimetype']
# 出力例: {'file_input': {'file_key': 'plugin_config_d2234fd802054faf80babe0679a97fa9.json', 'mimetype': 'application/json'}}
print(file_config)
# ファイルの内容を取得
file_bytes = await self.get_config_file(file_key)
```
::: info
一般的なMIMEタイプとファイル拡張子のリファレンス: [MDNドキュメント](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)
:::
### type: array[file]
複数ファイルアップロード。fileタイプと似ていますが、複数のファイルのアップロードをサポートし、`[{"file_key": "xxxxx.xxx", "mimetype": "xxxxx"}]`形式でプラグインに渡されます。
```yaml
- name: resource_files
type: array[file]
accept: 'image/*' # オプション、受け入れるファイルMIMEタイプを指定
...
```
プラグインでファイルを取得する:
```python
# 設定からファイルリストを取得
files_config = self.get_config()['resource_files']
for file_config in files_config:
file_key = file_config['file_key']
mimetype = file_config['mimetype']
# ファイルの内容を取得
file_bytes = await self.get_config_file(file_key)
```
### type: llm-model-selector
LLMモデルセレクター。設定されたLLMモデルを選択できるLLMモデルセレクターを表示し、最終結果はLLMモデルUUIDとして表されます。
```yaml
- name: model
type: llm-model-selector
...
```
### type: bot-selector
Botセレクター。設定されたBotを選択できるBotセレクターを表示し、最終結果はBot UUIDとして表されます。
```yaml
- name: bot
type: bot-selector
...
```
プラグインでBot UUIDを使用する:
```python
# 設定からBot UUIDを取得
bot_uuid = self.get_config()['bot']
print(bot_uuid) # 出力: '550e8400-e29b-41d4-a716-446655440000'
```
## 次のステップ
このチュートリアルでは、プラグイン機能を段階的に完成させる方法を案内します。
- コンポーネントの追加: プラグインコンポーネントはプラグインのコア機能ユニットです。必要に応じて[コンポーネントを追加](/en/plugin/dev/components/add)できます。
+73
View File
@@ -0,0 +1,73 @@
# コンポーネントの追加
プラグインは、LangBotにさまざまな機能を提供する1つ以上のコンポーネントで構成されています。現在サポートされているコンポーネントタイプには次のものがあります:
- イベントリスナー(EventListener): パイプライン実行中のイベントをリッスンし、コンテキストやパイプラインを変更します。
- コマンド(Command): `!`(または他の設定されたプレフィックス)で始まるユーザーコマンドメッセージによってトリガーされます。
- ツール(Tool): LangBotの組み込みLocal Agentの実行中にLLMによって呼び出されます。
- ナレッジリトリーバー(KnowledgeRetriever): LangBotに外部ナレッジベース検索機能を提供し、さまざまなRAGシステムとの統合をサポートします。
## コンポーネントの追加
プラグインディレクトリでコマンドを実行します:
```bash
lbp comp <component_type>
```
例えば、イベントリスナーを追加する場合:
```bash
lbp comp EventListener
```
プロンプトに従って、コンポーネント設定(ある場合)を入力します。
```bash
➜ HelloPlugin > lbp comp EventListener
Generating component EventListener...
Component EventListener generated successfully.
組件 EventListener 生成成功。
➜ HelloPlugin >
```
:::info
CLIはプラグインディレクトリに`components`ディレクトリを生成し、その中に対応するコンポーネントディレクトリを作成します。
```
.
├── assets
│ └── icon.svg
├── components
│ ├── __init__.py
│ └── event_listener
│ ├── __init__.py
│ ├── default.py
│ └── default.yaml
├── main.py
├── manifest.yaml
├── README.md
└── requirements.txt
```
同時に、プラグインの`manifest.yaml`にコンポーネント検出設定が追加されます:
```yaml
...
components:
EventListener:
fromDirs:
- path: components/event_listener/
...
```
コンポーネントを削除するには、対応する情報を手動で削除できます。
:::
## コンポーネントタイプ
各コンポーネントの詳細な使用方法については、次を参照してください:
- [EventListener](./event-listener.md)
- [Command](./command.md)
- [Tool](./tool.md)
- [KnowledgeRetriever](./knowledge-retriever.md)
+212
View File
@@ -0,0 +1,212 @@
# コンポーネント: Command
Commandコンポーネントは、`!`(または他の設定されたプレフィックス)で始まるユーザーコマンドメッセージによってトリガーされます。`!help`コマンドをトリガーする例を次に示します:
<img width="600" src="/assets/image/zh/plugin/dev/components/command_use.png" />
## Commandコンポーネントの追加
1つのプラグインには任意の数のコマンドを含めることができます。プラグインディレクトリでコマンド`lbp comp Command`を実行し、プロンプトに従ってコマンド設定を入力します。
```bash
➜ HelloPlugin > lbp comp Command
Generating component Command...
Command name: info
Command description: Show information of the query
Component Command generated successfully.
組件 Command 生成成功。
```
これにより、`components/commands/`ディレクトリに`info.yaml`と`info.py`ファイルが生成されます。`.yaml`ファイルは`!info`コマンドの基本情報を定義し、`.py`ファイルはコマンドハンドラです:
```bash
➜ HelloPlugin > tree
...
├── components
│ ├── __init__.py
│ ├── commands
│ │ ├── __init__.py
│ │ ├── info.py
│ │ └── info.yaml
...
```
## マニフェストファイル: Commandコンポーネント
```yaml
apiVersion: v1 # 変更しないでください
kind: Command # 変更しないでください
metadata:
name: info # コマンド名、ユーザーは!infoでこのコマンドをトリガーします
label: # コマンド表示名、LangBot UIに表示、多言語対応
en_US: Info
zh_Hans: Info
description: # コマンド説明、LangBot UIに表示、多言語対応。オプション。
en_US: 'Show information of the query'
zh_Hans: '発送此次消息的詳細信息'
spec:
execution:
python:
path: info.py # コマンドハンドラ、変更しないでください
attr: Info # コマンドハンドラクラス名、info.pyのクラス名と一致
```
## プラグイン処理
以下のコードがデフォルトで生成されます(components/command/<command_name>.py)。`Info`クラスの`initialize`メソッドでサブコマンド処理ロジックを登録して実装する必要があります。
```python
# Auto generated by LangBot Plugin SDK.
# Please refer to https://docs.langbot.app/en/plugin/dev/tutor.html for more details.
from __future__ import annotations
from typing import Any, AsyncGenerator
from langbot_plugin.api.definition.components.command.command import Command, Subcommand
from langbot_plugin.api.entities.builtin.command.context import ExecuteContext, CommandReturn
class Info(Command):
async def initialize(self):
await super().initialize()
"Fill with your code here"
```
サブコマンドの追加:
```python
...
class Info(Command):
async def initialize(self):
await super().initialize()
@self.subcommand(
name="", # 空文字列はルートコマンドを表す
help="Show information of the query", # コマンドヘルプ情報
usage="info", # コマンド使用例、コマンドヘルプに表示
aliases=["i"], # コマンドエイリアス
)
async def send(self, context: ExecuteContext) -> AsyncGenerator[CommandReturn, None]:
print(context)
reply_text = f"Query ID: {context.query_id}\n"
reply_text += f"command: {context.command}\n"
reply_text += f"command_text: {context.command_text}\n"
reply_text += f"params: {context.params}\n"
reply_text += f"crt_params: {context.crt_params}\n"
reply_text += f"privilege: {context.privilege}\n"
reply_text += f"session: {context.session.launcher_type.value}_{context.session.launcher_id}\n"
yield CommandReturn(
text=reply_text,
)
@self.subcommand(
name="field",
help="Show information of the field",
usage="info field",
aliases=["f"],
)
async def field(self, context: ExecuteContext) -> AsyncGenerator[CommandReturn, None]:
print(context)
field_name = context.crt_params[0]
field_value = getattr(context, field_name)
yield CommandReturn(
text=f"{field_name}: {field_value}",
)
```
このコードでは、`@self.subcommand`デコレータを通じて`send`関数がサブコマンドとして登録され、コマンドコンテキスト(ExecuteContext)情報を出力し、それを返信メッセージに連結します。
### サブコマンド登録
`name`はサブコマンド名です。空のままにすると、メインコマンドを処理することを意味します。空でない場合、2番目のパラメータをコマンドとして照合します。例えば:
- `!info`は、name=""のサブコマンドに一致
- `!info field`は、name="field"のサブコマンドに一致
- `!info field value`は、name="field"のサブコマンドに一致し、`value`がサブコマンドパラメータ
- 特に、`name="*"`は、一致しないすべての第1レベルサブコマンドに一致し、`info`の後の各セクションをパラメータとして渡します。例えば`!info 123`、`!info abc`。ユーザーの入力に応じて、`context.crt_params`から`['123']`または`['abc']`を取得できます。
サブコマンド関数では、`context`変数を通じてコマンドパラメータを読み取ることができます。
上記のコマンドの効果は画像に示されています:
<img width="600" src="/assets/image/zh/plugin/dev/components/info_command_demo.png" />
### コマンドコンテキスト
```python
class ExecuteContext(pydantic.BaseModel):
"""単一コマンド実行コンテキスト"""
query_id: int
"""リクエストID"""
session: provider_session.Session
"""このメッセージのセッションオブジェクト"""
command_text: str
"""完全なコマンドテキスト"""
command: str
"""コマンド名"""
crt_command: str
"""現在のコマンド
マルチレベルコマンドでは、crt_commandは現在のコマンド、commandはルートコマンド。
例: !plugin on Webwlkr
pluginを処理する場合、commandはplugin、crt_commandはplugin
onを処理する場合、commandはplugin、crt_commandはon
"""
params: list[str]
"""コマンドパラメータ
コマンド全体をスペースで分割した後のパラメータリスト
"""
crt_params: list[str]
"""現在のコマンドパラメータ
マルチレベルコマンドでは、crt_paramsは現在のコマンドパラメータ、paramsはルートコマンドパラメータ。
例: !plugin on Webwlkr
pluginを処理する場合、paramsは['on', 'Webwlkr']、crt_paramsは['on', 'Webwlkr']
onを処理する場合、paramsは['on', 'Webwlkr']、crt_paramsは['Webwlkr']
"""
privilege: int
"""セッション権限レベル"""
...
```
### コマンド戻り値
コマンド戻り値(CommandReturn)は、現在テキスト、画像(image_url、画像リンク)、エラーの返却をサポートしています。
```python
yield CommandReturn(
text=reply_text,
)
yield CommandReturn(
image_url=image_url,
)
```
コマンド処理は複数のメッセージを返すことをサポートしているため、`yield`ステートメントを使用してメッセージを返してください。
具体的な戻り値については、`CommandReturn`の定義を参照してください: [langbot_plugin.api.entities.builtin.command.context.CommandReturn](https://github.com/langbot-app/langbot-plugin-sdk/tree/main/src/langbot_plugin/api/entities/builtin/command/context.py)
## 次のステップ
コマンド登録とコマンド実行の基本情報を学びました。次は:
- [プラグイン共通API](/en/plugin/dev/apis/common)を確認してください
@@ -0,0 +1,101 @@
# コンポーネント: イベントリスナー
LangBotのパイプラインは実行時にイベントを生成し、プラグインがフックして処理できるようにします。各プラグインは1つのイベントリスナー(components/event_listener/default.yaml)のみを持つことができますが、その中で任意の数のイベントを登録できます。
## イベントリスナーコンポーネントの追加
プラグインディレクトリでコマンド`lbp comp EventListener`を実行します。イベントリスナーコンポーネントの作成には設定は必要ありません。
```bash
➜ HelloPlugin > lbp comp EventListener
Generating component EventListener...
Component EventListener generated successfully.
組件 EventListener 生成成功。
```
これにより、`components/event_listener/`ディレクトリに`default.yaml`と`default.py`ファイルが生成されます。`.yaml`ファイルはイベントリスナーの基本情報を定義し、`.py`ファイルはイベントリスナーハンドラです:
```bash
➜ HelloPlugin > tree
...
├── components
│ ├── __init__.py
│ └── event_listener
│ ├── __init__.py
│ ├── default.py
│ └── default.yaml
...
```
## マニフェストファイル: イベントリスナー
各プラグインは1つのイベントリスナーのみを持つことができるため、マニフェストファイルでの変更は必要ありません。
## プラグイン処理
以下のコードがデフォルトで生成されます(components/event_listener/default.py)。`DefaultEventListener`クラスの`initialize`メソッドでイベント処理ロジックを登録して実装する必要があります。
```python
# Auto generated by LangBot Plugin SDK.
# Please refer to https://docs.langbot.app/en/plugin/dev/tutor.html for more details.
from __future__ import annotations
from langbot_plugin.api.definition.components.common.event_listener import EventListener
from langbot_plugin.api.entities import events, context
class DefaultEventListener(EventListener):
async def initialize(self):
await super().initialize()
"Fill with your code here"
```
特定のイベントのリスナーを追加:
```python
...
class DefaultEventListener(EventListener):
async def initialize(self):
await super().initialize()
@self.handler(events.PersonMessageReceived)
async def handler(event_context: context.EventContext):
print("Hello LangBot Plugin!")
print(event_context)
await event_context.reply(
platform_message.MessageChain([
platform_message.Plain(text=f"Hello from Nahida Plugin!"),
])
)
```
このコードは、`PersonMessageReceived`(プライベートチャットからのメッセージを受信)イベントのリスナーを登録し、イベントがトリガーされたときにイベントコンテキスト(EventContext)情報を出力し、イベントコンテキストAPIを呼び出してメッセージで返信します。
EventContextはこのイベントトリガーの共通コンテキスト情報を保存し、EventContext.eventはPersonMessageReceived(または他の対応するイベントタイプ)のオブジェクトで、イベントの詳細情報を保存します。
```python
# EventContext定義の概要
class EventContext(pydantic.BaseModel):
"""イベントコンテキスト、このイベント実行の情報を保存"""
...
event: pydantic.SerializeAsAny[BaseEventModel]
"""イベントオブジェクト、具体的な型はハンドラ登録時に指定された型、events.pyで見つけることができます"""
...
```
## イベント登録
イベント登録は`@self.handler`デコレータを通じて実装され、デコレータのパラメータはイベントタイプです。監視可能なすべてのイベントは`langbot_plugin.api.entities.builtin.events`で定義されています。
## 次のステップ
イベントリスナーの基本情報を学びました。次は:
- ドキュメント[パイプラインイベント](/en/plugin/dev/apis/pipeline-events)で`監視可能なイベントのリスト`と`イベントコンテキストAPI`を確認してください
- [プラグイン共通API](/en/plugin/dev/apis/common)を確認してください
@@ -0,0 +1,264 @@
# コンポーネント: ナレッジリトリーバー
ナレッジリトリーバーコンポーネントにより、プラグインはLangBotに外部ナレッジベース検索機能を提供できます。ユーザーがLangBotで外部ナレッジベースを作成する際、プラグインが提供するナレッジリトリーバーを選択してナレッジを検索できます。
<img width="600" src="/assets/image/zh/plugin/dev/components/knowledge_retriever_use.png" />
## ナレッジリトリーバーコンポーネントの追加
1つのプラグインには任意の数のナレッジリトリーバーを追加できます。プラグインディレクトリでコマンド`lbp comp KnowledgeRetriever`を実行し、プロンプトに従ってナレッジリトリーバーの設定を入力します。
```bash
➜ FastGPTRetriever > lbp comp KnowledgeRetriever
Generating component KnowledgeRetriever...
KnowledgeRetriever name: fastgpt
KnowledgeRetriever description: Retrieve knowledge from FastGPT knowledge bases
Component KnowledgeRetriever generated successfully.
```
これにより、`components/knowledge_retriever/`ディレクトリに`fastgpt.yaml`と`fastgpt.py`ファイルが生成されます。`.yaml`ファイルはナレッジリトリーバーの基本情報と設定パラメータを定義し、`.py`ファイルはこのリトリーバーのハンドラです:
```bash
➜ FastGPTRetriever > tree
...
├── components
│ ├── __init__.py
│ └── knowledge_retriever
│ ├── __init__.py
│ ├── fastgpt.py
│ └── fastgpt.yaml
...
```
## マニフェストファイル: ナレッジリトリーバー
```yaml
apiVersion: v1 # 変更しないでください
kind: KnowledgeRetriever # 変更しないでください
metadata:
name: fastgpt # ナレッジリトリーバー名、このリトリーバーを識別するために使用
label:
en_US: FastGPT Knowledge Base # リトリーバー表示名、LangBotのUIに表示、多言語対応
zh_Hans: FastGPT 知識庫
ja_JP: FastGPT ナレッジベース
description:
en_US: 'Retrieve knowledge from FastGPT knowledge bases' # リトリーバー説明、LangBotのUIに表示、多言語対応。オプション
zh_Hans: '従 FastGPT 知識庫中検索知識'
ja_JP: 'FastGPT ナレッジベースから知識を取得'
icon: assets/icon.svg # リトリーバーアイコン、外部ナレッジベース設定ページに表示
spec:
config: # リトリーバー設定パラメータ、ユーザーは外部ナレッジベース作成時にこれらのパラメータを入力する必要があります
- name: api_base_url # パラメータ名
type: string # パラメータタイプ: string、number、boolean、select
label:
en_US: API Base URL
zh_Hans: API 基礎地址
ja_JP: API ベース URL
description:
en_US: 'Base URL for FastGPT API'
zh_Hans: 'FastGPT API 基礎地址'
ja_JP: 'FastGPT API ベース URL'
default: 'http://localhost:3000' # デフォルトパラメータ値
required: true # 必須かどうか
- name: api_key
type: string
label:
en_US: FastGPT API Key
zh_Hans: FastGPT API Key
ja_JP: FastGPT API キー
description:
en_US: 'API key from your FastGPT instance'
zh_Hans: '従您的 FastGPT 実例獲取的 API Key'
ja_JP: 'FastGPT インスタンスから取得した API Key'
default: ''
required: true
- name: search_mode # select型パラメータの例
type: select
label:
en_US: Search Mode
zh_Hans: 搜索模式
ja_JP: 検索モード
description:
en_US: 'The search method to use'
zh_Hans: '使用的搜索方法'
ja_JP: '使用する検索方法'
default: 'embedding'
options: # select型パラメータはオプションリストを定義する必要があります
- name: 'embedding'
label:
en_US: 'Embedding Search'
zh_Hans: '向量搜索'
ja_JP: '埋め込み検索'
- name: 'fullTextRecall'
label:
en_US: 'Full-Text Recall'
zh_Hans: '全文検索'
ja_JP: '全文検索'
- name: using_rerank # boolean型パラメータの例
type: boolean
label:
en_US: Use Re-ranking
zh_Hans: 使用重排序
ja_JP: リランキングを使用
description:
en_US: 'Whether to use re-ranking'
zh_Hans: '是否使用重排序'
ja_JP: 'リランキングを使用するかどうか'
default: false
required: false
execution:
python:
path: fastgpt.py # リトリーバーハンドラ、変更しないでください
attr: FastGPT # リトリーバーハンドラのクラス名、fastgpt.pyのクラス名と一致
```
設定項目フォーマットのリファレンスについては、[プラグインマニフェスト設定フォーマット](/en/plugin/dev/basic-info)を参照してください。
## プラグインハンドラ
以下のコードがデフォルトで生成されます(components/knowledge_retriever/<retriever_name>.py)。`FastGPT`クラスの`retrieve`メソッドでナレッジ検索ロジックを実装する必要があります。完全なコードは[langbot-plugin-demo](https://github.com/langbot-app/langbot-plugin-demo)で見つけることができます。
```python
# Auto generated by LangBot Plugin SDK.
# Please refer to https://docs.langbot.app/en/plugin/dev/tutor.html for more details.
...
class FastGPT(KnowledgeRetriever):
async def retrieve(self, context: RetrievalContext) -> list[RetrievalResultEntry]:
"""FastGPTナレッジベースからナレッジを検索"""
# 1. 設定パラメータを取得
api_base_url = self.config.get('api_base_url', 'http://localhost:3000')
api_key = self.config.get('api_key')
dataset_id = self.config.get('dataset_id')
search_mode = self.config.get('search_mode', 'embedding')
using_rerank = self.config.get('using_rerank', False)
# 2. パラメータ検証
if not api_key or not dataset_id:
logger.error("Missing required configuration: api_key or dataset_id")
return []
# 3. APIリクエストを構築
url = f"{api_base_url.rstrip('/')}/api/core/dataset/searchTest"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"datasetId": dataset_id,
"text": context.query, # RetrievalContextからクエリテキストを取得
"searchMode": search_mode,
"usingReRank": using_rerank,
}
try:
# 4. 外部APIを呼び出す
async with httpx.AsyncClient() as client:
response = await client.post(url, json=payload, headers=headers, timeout=30.0)
response.raise_for_status()
result = response.json()
# 5. レスポンスを解析してRetrievalResultEntryに変換
results = []
for record in result.get('data', []):
# メインデータと補助データをコンテンツとして結合
content_text = '\n'.join([
record.get('q', ''),
record.get('a', '')
]).strip()
# 検索結果エントリを作成
entry = RetrievalResultEntry(
id=record.get('id', ''),
content=[ContentElement.from_text(content_text)],
metadata={
'dataset_id': record.get('datasetId', ''),
'source_name': record.get('sourceName', ''),
'score': record.get('score', 0.0),
},
# 類似度スコアを距離に変換(スコアが高いほど距離が小さい)
distance=1.0 - float(record.get('score', 0.0)),
)
results.append(entry)
logger.info(f"Retrieved {len(results)} chunks from FastGPT dataset {dataset_id}")
return results
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error from FastGPT API: {e.response.status_code} - {e.response.text}")
return []
except httpx.RequestError as e:
logger.error(f"Request error when calling FastGPT API: {str(e)}")
return []
except Exception as e:
traceback.print_exc()
logger.error(f"Unexpected error during retrieval: {str(e)}")
return []
```
### 検索コンテキスト
`RetrievalContext`にはこの検索のコンテキスト情報が含まれます:
```python
class RetrievalContext(pydantic.BaseModel):
"""ナレッジ検索コンテキスト"""
query: str
"""クエリテキスト、ユーザーの検索質問"""
```
### 検索結果
検索結果は`RetrievalResultEntry`オブジェクトのリストに変換する必要があり、各オブジェクトは検索されたナレッジチャンクを表します:
```python
class RetrievalResultEntry(pydantic.BaseModel):
"""単一検索結果エントリ"""
id: str
"""結果ID、このエントリを一意に識別"""
content: list[ContentElement]
"""結果コンテンツ、ContentElement.from_text()を使用してテキストコンテンツを作成"""
metadata: dict[str, Any]
"""結果メタデータ、ソース、スコアなど、任意のキーと値のペアを含めることができます"""
distance: float
"""距離スコア、クエリとの関連性を示します(小さいほど関連性が高い)
通常は1.0 - similarity_scoreとして計算されます"""
```
### 設定パラメータの取得
`self.config.get(パラメータ名, デフォルト値)`を使用して、ユーザーが設定したパラメータ値を取得します:
```python
# 文字列パラメータを取得
api_base_url = self.config.get('api_base_url', 'http://localhost:3000')
# 数値パラメータを取得
limit = self.config.get('limit', 5000)
similarity = self.config.get('similarity', 0.0)
# ブールパラメータを取得
using_rerank = self.config.get('using_rerank', False)
# selectパラメータを取得
search_mode = self.config.get('search_mode', 'embedding')
```
## リトリーバーのテスト
作成後、プラグインディレクトリでコマンド`lbp run`を実行してデバッグを開始します。その後、LangBotで:
1. 「ナレッジベース」ページに移動
2. 外部ナレッジベースを追加
3. プラグインが提供するナレッジリトリーバーを選択し、設定を入力
<img width="600" src="/assets/image/zh/plugin/dev/components/knowledge_retriever_config.png" />
保存後、LangBotパイプラインでこのナレッジベースを選択できます。
+174
View File
@@ -0,0 +1,174 @@
# コンポーネント: Tool
LangBotの組み込みLocal Agentは、実行中にツールを呼び出して外部世界と対話します。現在、プラグインとMCPの両方を通じてツールを追加することがサポートされています。
## Toolコンポーネントの追加
1つのプラグインには任意の数のツールを含めることができます。プラグインディレクトリでコマンド`lbp comp Tool`を実行し、プロンプトに従ってツール設定を入力します。
```bash
➜ HelloPlugin > lbp comp Tool
Generating component Tool...
Tool name: get_weather_alerts
Tool description: Get weather alerts for a US state.
Component Tool generated successfully.
組件 Tool 生成成功。
```
これにより、`components/tools/`ディレクトリに`get_weather_alerts.yaml`と`get_weather_alerts.py`ファイルが生成されます。`.yaml`ファイルはツールの基本情報を定義し、`.py`ファイルはツールハンドラです:
```bash
➜ HelloPlugin > tree
...
├── components
│ ├── __init__.py
│ └── tools
│ ├── __init__.py
│ ├── get_weather_alerts.py
│ └── get_weather_alerts.yaml
...
```
## マニフェストファイル: Tool
```yaml
apiVersion: v1 # 変更しないでください
kind: Tool # 変更しないでください
metadata:
name: get_weather_alerts # ツール名、LLM認識用
label:
en_US: GetWeatherAlerts # ツール表示名、LangBot UIに表示、多言語対応
zh_Hans: GetWeatherAlerts
description:
en_US: 'Get weather alerts for a US state.' # ツール説明、LangBot UIに表示、多言語対応。オプション
zh_Hans: '獲取美国某个州的天気預警'
spec:
parameters: [] # ツールパラメータ、会話コンテキストに基づいてLLMが生成する値
llm_prompt: 'Get weather alerts for a US state.' # ツールプロンプト、LLMがこのツールを呼び出すかどうかを判断するため
execution:
python:
path: get_weather_alerts.py # ツールハンドラ、変更しないでください
attr: GetWeatherAlerts # ツールハンドラクラス名、get_weather_alerts.pyのクラス名と一致
```
## プラグイン処理
以下のコードがデフォルトで生成されます(components/tools/<tool_name>.py)。`GetWeatherAlerts`クラスの`call`メソッドでこのツールの呼び出しと戻り値のロジックを実装する必要があります。
```python
# Auto generated by LangBot Plugin SDK.
# Please refer to https://docs.langbot.app/en/plugin/dev/tutor.html for more details.
from __future__ import annotations
from typing import Any
from langbot_plugin.api.definition.components.tool.tool import Tool
from langbot_plugin.api.entities.builtin.provider import session as provider_session
class GetWeatherAlerts(Tool):
async def call(self, params: dict[str, Any], session: provider_session.Session, query_id: int) -> str:
"""Fill your tool code here"""
return {}
```
`call`メソッドでこのツールを実装します:
:::info
天気検索ツールの例は、MCPの[サーバー作成例](https://modelcontextprotocol.io/quickstart/server)から来ています。
:::
```python
from __future__ import annotations
from typing import Any
from langbot_plugin.api.definition.components.tool.tool import Tool
from langbot_plugin.api.entities.builtin.provider import session as provider_session
import httpx
# 定数
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
async def make_nws_request(url: str) -> dict[str, Any] | None:
"""適切なエラー処理を使用してNWS APIにリクエストを行う。"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception:
return None
def format_alert(feature: dict) -> str:
"""アラート機能を読みやすい文字列にフォーマットする。"""
props = feature["properties"]
return f"""
Event: {props.get('event', 'Unknown')}
Area: {props.get('areaDesc', 'Unknown')}
Severity: {props.get('severity', 'Unknown')}
Description: {props.get('description', 'No description available')}
Instructions: {props.get('instruction', 'No specific instructions provided')}
"""
class GetWeatherAlerts(Tool):
async def call(self, params: dict[str, Any], session: provider_session.Session, query_id: int) -> str:
"""Fill your tool code here"""
state = params.get("state", "CA")
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data or "features" not in data:
return "Unable to fetch alerts or no alerts found."
if not data["features"]:
return "No active alerts for this state."
alerts = [format_alert(feature) for feature in data["features"]]
return "\n---\n".join(alerts)
```
このツールでは、`params`から`state`パラメータを取得し、NWS APIを呼び出してその州の天気アラートを取得する必要があるため、マニフェストファイルの`parameters`で`state`パラメータを定義する必要があります。
`parameters`フォーマットは[JSON Schema](https://json-schema.org/docs)に従い、[OpenAI Function Calling機能](https://platform.openai.com/docs/guides/function-calling#defining-functions)でサポートされており、そのルートタイプは`type: object`に固定されています。`properties`にパラメータを追加し、`required`に必須パラメータの説明を追加してください。
```yaml
...
spec:
parameters:
type: object # 変更しないでください
properties: # 変更しないでください、ここにパラメータを追加
state:
type: string
description: 'Two-letter US state code (e.g. CA, NY)'
required: # ここに必須パラメータの説明を追加
- state
...
```
このツールは`httpx`ライブラリも使用しているため、プラグインディレクトリの`requirements.txt`に`httpx`依存関係を追加する必要があります。
```txt
# HelloPlugin/requirements.txt
langbot-plugin # デフォルトで既に存在
httpx
```
次に、プラグインディレクトリでコマンド`lbp run`を実行してデバッグを開始します。LangBotでツール呼び出しをサポートするモデルを設定し、対応するパイプラインでそのモデルの使用を選択してこのツールを使用します。
<img width="600" src="/assets/image/zh/plugin/dev/components/tool_use_in_chat.png" />
## 次のステップ
ツールの基本的な使い方を学びました。次は:
- [プラグイン共通API](/en/plugin/dev/apis/common)を確認してください
+191
View File
@@ -0,0 +1,191 @@
# プラグインディレクトリ構造
:::info 目次
[[toc]]
:::
このドキュメントでは、LangBotプラグインの標準ディレクトリ構造とファイル組織仕様を紹介し、開発者が準拠したプラグインを作成できるように支援します。
## 基本ディレクトリ構造
標準的なLangBotプラグインは次のディレクトリ構造に従う必要があります:
```
MyPlugin/
├── manifest.yaml # プラグインマニフェストファイル(必須)
├── main.py # プラグインメインエントリファイル(必須)
├── README.md # 英語プラグインドキュメント(必須)
├── readme/ # 多言語READMEディレクトリ(オプション)
│ ├── README_zh_Hans.md # 簡体字中国語ドキュメント
│ ├── README_ja_JP.md # 日本語ドキュメント
│ └── README_zh_Hant.md # 繁体字中国語ドキュメント(オプション)
├── assets/ # リソースファイルディレクトリ
│ ├── icon.svg # プラグインアイコン(推奨)
│ └── ... # その他のリソースファイル
├── components/ # コンポーネントディレクトリ
│ ├── event_listener/ # イベントリスナーコンポーネント
│ ├── commands/ # コマンドコンポーネント
│ └── tools/ # ツールコンポーネント
├── requirements.txt # Python依存関係(オプション)
└── config/ # 設定ディレクトリ(オプション)
```
## 多言語README仕様
### ファイル配置仕様
LangBotプラグインは、異なる言語のユーザーにローカライズされたプラグイン説明を提供するために、多言語READMEドキュメントをサポートしています。
**重要な仕様:**
1. **ルート`README.md`(必須)**
- **英語**で記述する必要があります
- プラグインのデフォルトドキュメントとして機能します
- 要求された言語バージョンが存在しない場合のフォールバックとして使用されます
2. **`readme/`ディレクトリ(オプション)**
- **非英語**のREADMEドキュメントを保存するために使用
- ファイル命名形式: `README_{言語コード}.md`
### サポートされる言語コード
[RFC 4646](https://datatracker.ietf.org/doc/html/rfc4646)標準に従い、LangBotは現在次の言語コードをサポートしています:
| 言語 | 言語コード | ファイル名 | 配置場所 |
|----------|---------------|----------|----------|
| 英語 | `en`または`en_US` | `README.md` | **プラグインルートディレクトリ** |
| 簡体字中国語 | `zh_Hans` | `README_zh_Hans.md` | `readme/`ディレクトリ |
| 繁体字中国語 | `zh_Hant` | `README_zh_Hant.md` | `readme/`ディレクトリ |
| 日本語 | `ja_JP` | `README_ja_JP.md` | `readme/`ディレクトリ |
### ディレクトリ構造の例
```
MyPlugin/
├── README.md # ✅ 英語版(必須、ルートディレクトリ)
└── readme/ # ✅ 多言語ディレクトリ
├── README_zh_Hans.md # ✅ 簡体字中国語
├── README_ja_JP.md # ✅ 日本語
└── README_zh_Hant.md # ✅ 繁体字中国語
```
### 誤った例
❌ **誤り: readme/ディレクトリに英語READMEを配置**
```
MyPlugin/
├── readme/
│ ├── README_en.md # ❌ 誤り: 英語はreadme/に配置すべきではない
│ └── README_zh_Hans.md
```
❌ **誤り: ルートREADME.mdに非英語コンテンツが含まれる**
```markdown
# MyPlugin
This is a plugin...
これはプラグインです... # ❌ 誤り: ルートREADME.mdは英語のみを含むべき
```
### README言語フォールバックロジック
ユーザーが特定の言語でREADMEを要求した場合、LangBotは次の順序で検索します:
1. `readme/README_{言語コード}.md`を読み取ろうとします
2. 見つからない場合は、ルート`README.md`(英語版)にフォールバックします
**例:**
- ユーザーが簡体字中国語(`zh_Hans`)を要求
- → `readme/README_zh_Hans.md`を検索
- → 見つからない場合は、`README.md`(英語版)を返します
- ユーザーが日本語(`ja_JP`)を要求
- → `readme/README_ja_JP.md`を検索
- → 見つからない場合は、`README.md`(英語版)を返します
## リソースファイルディレクトリ
### assets/ディレクトリ
`assets/`ディレクトリはプラグインの静的リソースファイルを保存するために使用されます。
**推奨構造:**
```
assets/
├── icon.svg # プラグインアイコン(SVG形式推奨)
├── example.png # 例画像
├── screenshot1.png # スクリーンショット
└── logo.png # ロゴ画像
```
**アイコン仕様:**
- プラグインアイコンとして`icon.svg`を使用することを推奨
- サポートされる形式: `.svg`、`.png`、`.jpg`、`.jpeg`、`.gif`
- 推奨サイズ: 最低256x256ピクセル
- `manifest.yaml`での参照: `icon: assets/icon.svg`
### READMEでのリソース参照
READMEドキュメントで相対パスを使用してassets/ディレクトリの画像を参照できます:
```markdown
# MyPlugin
![例](./assets/example.png)
![スクリーンショット](./assets/screenshot1.png)
```
**注意:** プラグインをLangBot Spaceにアップロードすると、リソースファイルが自動的に処理およびホストされ、ユーザーがREADMEを表示したときに画像が正しく表示されます。
## コンポーネントディレクトリ
プラグイン機能はコンポーネントを通じて実装され、タイプ別に`components/`ディレクトリに整理する必要があります:
```
components/
├── event_listener/ # イベントリスナー
│ ├── on_message.py
│ └── on_message.yaml
├── commands/ # コマンド
│ ├── hello.py
│ └── hello.yaml
└── tools/ # ツール
├── search.py
└── search.yaml
```
コンポーネント開発の詳細な仕様については、[コンポーネントの追加](/en/plugin/dev/components/add)を参照してください。
## 設定ファイル
### manifest.yaml
プラグインマニフェストファイル`manifest.yaml`はコア設定ファイルであり、プラグインメタデータ、設定項目、コンポーネントリストなどの情報が含まれます。
詳細な手順については、[プラグイン設定情報の完成](/en/plugin/dev/basic-info)を参照してください。
### requirements.txt
プラグインが追加のPython依存関係を必要とする場合は、ルートディレクトリに`requirements.txt`ファイルを作成します:
```
requests>=2.28.0
beautifulsoup4>=4.11.0
pillow>=9.0.0
```
**注意:** LangBotは、プラグインのインストール時に`requirements.txt`にリストされている依存関係を自動的にインストールします。
## 関連ドキュメント
- [基本チュートリアル](/en/plugin/dev/tutor) - 最初のプラグインを作成する方法を学ぶ
- [プラグイン設定情報の完成](/en/plugin/dev/basic-info) - manifest.yamlの設定
- [コンポーネントの追加](/en/plugin/dev/components/add) - プラグインコンポーネントの開発
- [マーケットプレイスに公開](/en/plugin/dev/publish/market) - プラグインを配布
+27
View File
@@ -0,0 +1,27 @@
# 移行ガイド
このチュートリアルでは特定の考慮事項を強調しています。まず現在のバージョンのプラグインチュートリアルをお読みいただき、その後このドキュメントをプラグイン移行のリファレンスとしてご使用ください。
## 3.xサポートの非同期プラグインからの移行
:::info
プラグインの特徴:
- 主な期間: 2024.2 ~ 2025.8
- 登録方法: `main.py`のプラグインクラスで`@handler`デコレータを使用してイベントリスナーを登録し、`@llm_func`デコレータを使用してコンテンツ関数(ツール)を登録; すべてのハンドラ関数は非同期関数(async def)
:::
- プラグインとコンポーネント登録方法: 以前の単一プラグインクラスデコレータ登録方法から、マニフェストファイル登録方法に変更されました。[マニフェストファイル](/en/plugin/dev/basic-info)を参照してください; そして、異なるタイプのコンポーネントを独立して分離しました。詳細については、[コンポーネントの追加](/en/plugin/dev/components/add)を参照してください。
- メッセージチェーンエンティティ: リファクタリングされました。各メッセージチェーン要素の構築方法では、**名前付きパラメータ**の明示的な渡しが必要になりました。[メッセージプラットフォームエンティティ](/en/plugin/dev/apis/messages)を参照してください。
- イベントリスナー: 後方互換性を提供しますが、コンテキストで`query: Query`オブジェクトは提供されなくなりました。詳細については、[パイプラインイベント](/en/plugin/dev/apis/pipeline-events)を参照してください。
- コマンドコンポーネント: リファクタリングされました。[Commandコンポーネント](/en/plugin/dev/components/command)を参照してください。
## 2.xおよび3.xサポートの同期プラグインからの移行
:::info
プラグインの特徴:
- 主な期間: 2023.1 ~ 2024.2
- 登録方法: `main.py`のプラグインクラスで`@on`デコレータを使用してイベントリスナーを登録し、`@func`デコレータを使用してコンテンツ関数(ツール)を登録; すべてのハンドラ関数は同期関数(def)
:::
- 同期から非同期へ: プラグインランタイムは完全に非同期(asyncioベース)に変更されました。IO操作を含むすべてのプラグインコードを非同期記述に変更してください。
- 詳細な内容については、上記の3.x非同期プラグイン移行ガイドを参照してください。
+23
View File
@@ -0,0 +1,23 @@
# GitHub経由でプラグインを配布
プラグインをGitHubにアップロードし、リポジトリのReleaseを作成して`.lbpkg`ファイルをアップロードすることで、他のユーザーがLangBotでインストールできるようになります。
## プラグインのビルド
プラグインディレクトリで次のコマンドを実行します:
```bash
lbp build
```
これにより、`dist`ディレクトリに`.lbpkg`ファイルが生成されます。
## Releaseの作成
プラグインをGitHubにアップロードし、プラグインリポジトリのReleaseページに移動し、Releaseを作成をクリックして、先ほどビルドした`.lbpkg`ファイルをアップロードします。
<img width="600" src="/assets/image/zh/plugin/dev/dist/github_release.png" />
## プラグインのインストール
LangBotのプラグイン管理ページで、右上隅をクリックしてGitHubインストール方法を選択します。
+65
View File
@@ -0,0 +1,65 @@
# プラグインマーケットプレイスに公開
CLI経由で[LangBotプラグインマーケットプレイス](https://space.langbot.app/market)にプラグインを公開します。
## LangBot Spaceでアカウントを作成
LangBot SpaceはLangBotの集中サービスプラットフォームです。[LangBot Space](https://space.langbot.app)にアクセスし、右上隅をクリックしてGitHubでログインし、アカウントを作成してください。
<img width="600" src="/assets/image/zh/plugin/dev/login_space.png" />
GitHubの認証ページにリダイレクトされますので、プロンプトに従って認証を完了してください。
## CLIを使用してLangBot Spaceにログイン
任意のディレクトリでコマンド`lbp login`を実行します:
```bash
➜ HelloPlugin > lbp login
Starting LangBot CLI login process...
Generating device code...
==================================================
Please copy the user code and complete verification in your browser:
User Code: 6CD64D56
Verification URL: https://space.langbot.app/auth/device
Device code expires in: 120 seconds
==================================================
Waiting for verification...
```
`Verification URL`をクリックしてLangBot Spaceにリダイレクトし、`User Code`を入力してログインを完了してください。
<img width="600" src="/assets/image/zh/plugin/dev/space_device_flow.png" />
```bash
==================================================
✅ Login successful!
Access token saved to: ~/.langbot/cli/config.json
Token type: Bearer
Expires in: 21600 seconds
==================================================
```
ログインが成功したら、CLIを使用してプラグインをアップロードできます。
## プラグインのアップロード
プラグインディレクトリで`lbp publish`を実行してください:
```bash
➜ HelloPlugin > lbp publish
Building plugin to dist/tmp...
- Skipping ignored directory: dist
- Skipping ignored directory: __pycache__
...
Plugin built successfully: dist/tmp/RockChinQ-HelloPlugin-0.1.0.lbpkg
✅ Plugin published successfully. You can check it on https://https://space.langbot.app/market
```
[LangBotプラグインマーケットプレイス](https://space.langbot.app/market)でプラグイン提出タスクを確認できます。承認をお待ちください。承認後、マーケットプレイスでプラグインを表示できます。
<img width="600" src="/assets/image/zh/plugin/dev/plugin_submission.png" />
ご質問がある場合は、`[email protected]`にメールを送信するか、[コミュニティ](/en/insight/community)を通じてお問い合わせください。
+133
View File
@@ -0,0 +1,133 @@
# プラグイン開発チュートリアル
## アーキテクチャの基礎
バージョン4.0では、高セキュリティで柔軟性の高い本番環境グレードのプラグインシステムを導入し、開発者に豊富なAPIと使いやすいサポートツールを提供しています。
<img width="600" src="/assets/image/zh/plugin/dev/plugin_system_arch.png" />
Plugin Runtimeは、プラグインのライフサイクルを管理し、LangBotとプラグイン間の相互作用を調整するために使用されます。`stdio`と`websocket`の2つの動作モードがあります。LangBotがユーザーによって直接起動される場合(コンテナ内で実行されていない場合)、`stdio`モードを使用します。これは個人ユーザーや軽量環境で一般的です。LangBotがコンテナ内で実行される場合、`websocket`モードを使用します。これは本番環境専用に設計されています。
Plugin Runtimeは、インストールされた各プラグインを自動的に起動し、stdioを通じて相互作用します。プラグイン開発シナリオでは、開発者は`lbp`コマンドラインツールを使用してプラグインを起動し、WebSocketを介して実行中のRuntimeに接続してデバッグできます。
### プラグイン構造
プラグインのディレクトリ構造は次のようになります:
```bash
➜ HelloPlugin > tree
.
├── assets
│ └── icon.svg # プラグインアイコン、プラグインマーケットプレイスページに表示
├── components # プラグインコンポーネントディレクトリ、さまざまなコンポーネントコードとマニフェストファイルを保存
│ ├── __init__.py
│ ├── commands
│ │ ├── __init__.py
│ │ ├── info.py
│ │ └── info.yaml
│ ├── event_listener
│ │ ├── __init__.py
│ │ ├── default.py
│ │ └── default.yaml
│ └── tools
│ ├── __init__.py
│ ├── get_weather_alerts.py
│ └── get_weather_alerts.yaml
├── main.py # プラグインメインプログラム、プラグインライフサイクルをリッスン
├── manifest.yaml # プラグインマニフェストファイル、プラグインメタデータを記述
├── README.md # プラグインドキュメントファイル、プラグイン機能と使用方法を記述、プラグインマーケットプレイスページに表示
└── requirements.txt # プラグイン依存関係ファイル
```
main.pyのプラグインクラスは各プラグインの共通コードで、プラグイン起動時に初期化され、コンテキスト情報(設定など)が渡されます。ここでプラグインの初期化とシャットダウンロジックを実装できます。プラグインクラスは`langbot_plugin.api.definition.plugin.BasePlugin`を継承し、[LangBotグローバルAPI](/en/plugin/dev/apis/common)を提供します。
各コンポーネントはプラグインのコア機能モジュールであり、必要に応じて[追加および削除](/en/plugin/dev/components/add)できます。異なるコンポーネントは異なる状況で呼び出され、後でプラグイン機能を簡単に拡張できます。各コンポーネントは`langbot_plugin.api.definition.components`パッケージ下のさまざまなコンポーネント基底クラスから直接継承し、`plugin: BasePlugin`オブジェクトを含み、プラグインのAPIを直接呼び出すことができます。
::: info
- 詳細なAPIドキュメントについては、[APIリファレンス](/en/plugin/dev/apis/common)を参照してください。
このチュートリアルを続けて読んで、プラグイン開発プロセスを理解してください。
:::
## CLIのインストール
Python 3.10以上がインストールされており、[uvパッケージマネージャー](https://docs.astral.sh/uv/)がインストールされていることを確認してください。
任意の空のディレクトリで次のコマンドを実行して、LangBot CLIとSDKをインストールします:
```bash
pip install -U langbot_plugin
```
## プラグインディレクトリの初期化
プラグイン名が`HelloPlugin`であると仮定して、任意のディレクトリに`HelloPlugin`ディレクトリを作成し、そのディレクトリに入り、コマンドを実行してプラグインを初期化します:
```bash
lbp init
```
プロンプトに従って`Author`、`Description`などの情報を入力します。
:::info
`lbp init HelloPlugin`コマンドを使用して、サブディレクトリ`HelloPlugin`でプラグインを初期化することもできます。
<img width="600" src="/assets/image/zh/plugin/dev/create_plugin.png" />
:::
この操作により、プラグインの初期ファイルが生成されます。お気に入りのエディターで`HelloPlugin`ディレクトリを開き、プラグインコードの記述を開始できます。
:::info
`lbp`コマンドで「command not found」エラーが発生した場合、`PATH`環境変数が適切に設定されていない可能性があります。
`lbp`コマンドの代わりに`python -m langbot_plugin.cli.__init__`を使用できます。
例えば:
```bash
python -m langbot_plugin.cli.__init__ init HelloPlugin
cd HelloPlugin
```
:::
## デバッグモードの開始
まずLangBotをデプロイして起動し、Plugin Runtimeが実行されてポート`5401`をリッスンしていることを確認する必要があります。
::: info
Runtimeには2つの起動モードがあります:
- `Stdio`モード: 起動パラメータ`--standalone-runtime`なしでソースコードを使用してLangBotを起動すると、LangBotは自動的にPlugin Runtimeをサブプロセスとして起動し、`stdio`(標準入出力ストリーム)を通じてPlugin Runtimeと通信します。この場合、RuntimeはLangBotルートディレクトリの`data/plugins`ディレクトリからプラグインをロードし、LangBotホストのポート`5401`をデバッグポートとしてリッスンします。
- `WebSocket`モード:
- 本番環境: 公式の`docker-compose.yaml`を使用してLangBotを起動すると、Plugin Runtimeは別のコンテナで実行され、起動パラメータ`--standalone-runtime`のためにLangBotはWebSocketモードでPlugin Runtimeと通信します。Runtimeコンテナの5401ポートはデフォルトでホストの5401ポートにマッピングされます。
- 開発環境: 起動パラメータ`--standalone-runtime`を使用してソースコードでLangBotを起動すると、LangBotは`data/config.yaml`で設定された`plugin.runtime_ws_url`アドレス(ポートは通常5400)に従って既に起動されているPlugin Runtimeに接続します。スタンドアロンのPlugin Runtimeを自分で起動する必要があります。[Plugin Runtimeの開発](/en/develop/plugin-runtime)を参照してください。
`stdio`または`websocket`モードのいずれの場合でも、Plugin Runtimeはそのホストのポート`5401`をプラグインデバッグ接続のデバッグポートとしてリッスンします。
プラグインを開発する際は、[開発設定](/en/develop/dev-config)方法に従ってLangBotを起動することをお勧めします。これによりPlugin RuntimeがStdioモードで起動され、プラグイン開発が容易になります。
:::
プラグインディレクトリの`.env.example`ファイルを`.env`にコピーし、`DEBUG_RUNTIME_WS_URL`をPlugin RuntimeのWebSocketアドレスに確認または変更します。
```bash
cp .env.example .env
```
プラグインデバッグを開始すると、プラグインの出力が表示されます:
```bash
lbp run
```
<img width="600" src="/assets/image/zh/plugin/dev/launch_debug_plugin.png" />
そして、LangBotのWebUIでこのプラグインがロードされたことを確認できます。
<img width="600" src="/assets/image/zh/plugin/dev/debug_plugin_loaded.png" />
## 次のステップ
このチュートリアルでは、プラグイン機能を段階的に完成させる方法を案内します。
- プラグイン情報の変更: プラグインは基本的なプラグイン情報で作成されました。[プラグイン情報を完成させて](/en/plugin/dev/basic-info)ください。
- コンポーネントの追加: プラグインコンポーネントはプラグインのコア機能ユニットです。必要に応じて[コンポーネントを追加](/en/plugin/dev/components/add)できます。