--- dimensions: type: primary: implementation detail: high level: intermediate standard_title: Agent language: ja title: Agent description: このドキュメントでは、DifyのAgent戦略プラグインの開発プロセスについて詳しく説明します。ManifestファイルへのAgent戦略フィールドの追加、Agentプロバイダーの定義、Agent戦略を実装するためのコアステップが含まれます。パラメータの取得、モデルの呼び出し、ツールの呼び出し、ログの生成と管理に関する完全なサンプルコードも詳細に解説しています。 --- Agent戦略は、標準の入力内容と出力形式を定義する拡張可能なテンプレートです。具体的なAgent戦略インターフェースの機能コードを開発することで、CoT(思考の連鎖)/ ToT(思考の木)/ GoT(思考のグラフ)/ BoT(思考の骨格)など、さまざまなAgent戦略を実現し、[Sementic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/overview/) のような複雑な戦略を実装できます。 ### Manifest内へのフィールド追加 プラグインにAgent戦略を追加するには、`manifest.yaml`ファイル内に`plugins.agent_strategies`フィールドを新たに追加し、Agentプロバイダーも定義する必要があります。サンプルコードは以下の通りです。 ```yaml version: 0.0.2 type: plugin author: "langgenius" name: "agent" plugins: agent_strategies: - "provider/agent.yaml" ``` ここでは、`manifest`ファイル内の一部の無関係なフィールドは省略されています。Manifestの詳細な形式については、[マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest)ドキュメントを参照してください。 ### Agentプロバイダーの定義 次に、`agent.yaml`ファイルを新規作成し、基本的なAgentプロバイダー情報を入力する必要があります。 ```yaml identity: author: langgenius name: agent label: en_US: Agent zh_Hans: Agent pt_BR: Agent description: en_US: Agent zh_Hans: Agent pt_BR: Agent icon: icon.svg strategies: - strategies/function_calling.yaml ``` 主にいくつかの記述的な基本情報を含み、現在のプロバイダーがどの戦略を含むかを指定します。上記のサンプルコードでは、最も基本的な`function_calling.yaml`戦略ファイルのみが指定されています。 ### Agent戦略の定義と実装 #### 定義 次に、Agent戦略を実現できるコードを定義する必要があります。`function_calling.yaml`ファイルを新規作成します: ```yaml identity: name: function_calling author: Dify label: en_US: FunctionCalling zh_Hans: FunctionCalling pt_BR: FunctionCalling description: en_US: Function Calling is a basic strategy for agent, model will use the tools provided to perform the task. zh_Hans: Function Callingは基本的なAgent戦略であり、モデルは提供されたツールを使用してタスクを実行します。 pt_BR: Function Calling is a basic strategy for agent, model will use the tools provided to perform the task. parameters: - name: model type: model-selector scope: tool-call&llm required: true label: en_US: Model zh_Hans: モデル pt_BR: Model - name: tools type: array[tools] required: true label: en_US: Tools list zh_Hans: ツールリスト pt_BR: Tools list - name: query type: string required: true label: en_US: Query zh_Hans: ユーザーの質問 pt_BR: Query - name: max_iterations type: number required: false default: 5 label: en_US: Max Iterations zh_Hans: 最大反復回数 pt_BR: Max Iterations max: 50 min: 1 extra: python: source: strategies/function_calling.py ``` コード形式は[`Tool`標準形式](tool.md)に似ており、`model`、`tools`、`query`、`max_iterations`など合計4つのパラメータを定義し、最も基本的なAgent戦略の実装を容易にします。このコードの意味は、ユーザーがモデルと使用するツールを選択し、最大反復回数を設定し、最終的にqueryを渡してAgentの実行を開始できるようにすることです。 #### 機能実装コードの作成 **パラメータの取得** 上記で定義された4つのパラメータに基づき、`model`タイプのパラメータは`model-selector`であり、`tool`タイプのパラメータは特殊な`array[tools]`です。パラメータで取得された形式は、SDKに組み込まれている`AgentModelConfig`と`list[ToolEntity]`を使用して変換できます。 ```python from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity class FunctionCallingParams(BaseModel): query: str model: AgentModelConfig tools: list[ToolEntity] | None maximum_iterations: int = 3 class FunctionCallingAgentStrategy(AgentStrategy): def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: """ Run FunctionCall agent application """ fc_params = FunctionCallingParams(**parameters) ``` **モデルの呼び出し** 指定されたモデルの呼び出しは、Agentプラグインに不可欠な機能です。SDK内の`session.model.invoke()`関数を使用してモデルを呼び出します。`model`から必要な入力パラメータを取得できます。 `invoke model`のメソッドシグネチャのサンプルコード: ```python def invoke( self, model_config: LLMModelConfig, prompt_messages: list[PromptMessage], tools: list[PromptMessageTool] | None = None, stop: list[str] | None = None, stream: bool = True, ) -> Generator[LLMResultChunk, None, None] | LLMResult: ``` モデル情報`model_config`、プロンプト情報`prompt_messages`、およびツール情報`tools`を渡す必要があります。 そのうち`prompt_messages`パラメータは以下のサンプルコードを参照して呼び出すことができますが、`tool_messages`は一定の変換が必要です。 `invoke model`の使用方法のサンプルコードを参照してください: ```python from collections.abc import Generator from typing import Any from pydantic import BaseModel from dify_plugin.entities.agent import AgentInvokeMessage from dify_plugin.entities.model.llm import LLMModelConfig from dify_plugin.entities.model.message import ( PromptMessageTool, SystemPromptMessage, UserPromptMessage, ) from dify_plugin.entities.tool import ToolParameter from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity class FunctionCallingParams(BaseModel): query: str instruction: str | None model: AgentModelConfig tools: list[ToolEntity] | None maximum_iterations: int = 3 class FunctionCallingAgentStrategy(AgentStrategy): def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: """ Run FunctionCall agent application """ # init params fc_params = FunctionCallingParams(**parameters) query = fc_params.query model = fc_params.model stop = fc_params.model.completion_params.get("stop", []) if fc_params.model.completion_params else [] prompt_messages = [ SystemPromptMessage(content="あなたのシステムプロンプトメッセージ"), UserPromptMessage(content=query), ] tools = fc_params.tools prompt_messages_tools = self._init_prompt_tools(tools) # invoke llm chunks = self.session.model.llm.invoke( model_config=LLMModelConfig(**model.model_dump(mode="json")), prompt_messages=prompt_messages, stream=True, stop=stop, tools=prompt_messages_tools, ) def _init_prompt_tools(self, tools: list[ToolEntity] | None) -> list[PromptMessageTool]: """ Init tools """ prompt_messages_tools = [] for tool in tools or []: try: prompt_tool = self._convert_tool_to_prompt_message_tool(tool) except Exception: # APIツールは削除された可能性があります continue # save prompt tool prompt_messages_tools.append(prompt_tool) return prompt_messages_tools def _convert_tool_to_prompt_message_tool(self, tool: ToolEntity) -> PromptMessageTool: """ convert tool to prompt message tool """ message_tool = PromptMessageTool( name=tool.identity.name, description=tool.description.llm if tool.description else "", parameters={ "type": "object", "properties": {}, "required": [], }, ) parameters = tool.parameters for parameter in parameters: if parameter.form != ToolParameter.ToolParameterForm.LLM: continue parameter_type = parameter.type if parameter.type in { ToolParameter.ToolParameterType.FILE, ToolParameter.ToolParameterType.FILES, }: continue enum = [] if parameter.type == ToolParameter.ToolParameterType.SELECT: enum = [option.value for option in parameter.options] if parameter.options else [] message_tool.parameters["properties"][parameter.name] = { "type": parameter_type, "description": parameter.llm_description or "", } if len(enum) > 0: message_tool.parameters["properties"][parameter.name]["enum"] = enum if parameter.required: message_tool.parameters["required"].append(parameter.name) return message_tool ``` **ツールの呼び出し** ツールの呼び出しもAgentプラグインに不可欠な機能です。`self.session.tool.invoke()`を使用して呼び出すことができます。`invoke tool`のメソッドシグネチャのサンプルコード: ```python def invoke( self, provider_type: ToolProviderType, provider: str, tool_name: str, parameters: dict[str, Any], ) -> Generator[ToolInvokeMessage, None, None] ``` 必須パラメータは`provider_type`、`provider`、`tool_name`、`parameters`です。そのうち`tool_name`と`parameters`は、Function CallingではLLMによって生成されることがよくあります。`invoke tool`の使用例コード: ```python from dify_plugin.entities.tool import ToolProviderType class FunctionCallingAgentStrategy(AgentStrategy): def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: """ Run FunctionCall agent application """ fc_params = FunctionCallingParams(**parameters) # tool_call_name and tool_call_args parameter is obtained from the output of LLM tool_instances = {tool.identity.name: tool for tool in fc_params.tools} if fc_params.tools else {} tool_instance = tool_instances[tool_call_name] tool_invoke_responses = self.session.tool.invoke( provider_type=ToolProviderType.BUILT_IN, provider=tool_instance.identity.provider, tool_name=tool_instance.identity.name, # デフォルト値を追加 parameters={**tool_instance.runtime_parameters, **tool_call_args}, ) ``` `self.session.tool.invoke()`関数の出力はGeneratorであり、同様にストリーミング解析が必要であることを意味します。 解析方法については、以下の関数を参照してください: ```python import json from collections.abc import Generator from typing import cast from dify_plugin.entities.agent import AgentInvokeMessage from dify_plugin.entities.tool import ToolInvokeMessage def parse_invoke_response(tool_invoke_responses: Generator[AgentInvokeMessage]) -> str: result = "" for response in tool_invoke_responses: if response.type == ToolInvokeMessage.MessageType.TEXT: result += cast(ToolInvokeMessage.TextMessage, response.message).text elif response.type == ToolInvokeMessage.MessageType.LINK: result += ( f"結果リンク: {cast(ToolInvokeMessage.TextMessage, response.message).text}。" + " ユーザーに確認するよう伝えてください。" ) elif response.type in { ToolInvokeMessage.MessageType.IMAGE_LINK, ToolInvokeMessage.MessageType.IMAGE, }: result += ( "画像は既に作成されユーザーに送信済みです。" + "作成する必要はありません。ユーザーに今すぐ確認するよう伝えてください。" ) elif response.type == ToolInvokeMessage.MessageType.JSON: text = json.dumps(cast(ToolInvokeMessage.JsonMessage, response.message).json_object, ensure_ascii=False) result += f"ツール応答: {text}。" else: result += f"ツール応答: {response.message!r}。" return result ``` #### Log Agentの思考プロセスを確認したい場合、正常に返されたメッセージを確認する以外に、専用のインターフェースを使用してAgent全体の思考プロセスをツリー構造で表示することもできます。 **ログの作成** * このインターフェースは`AgentLogMessage`を作成して返します。このMessageはログ内のツリーのノードを表します。 * `parent`が渡された場合、そのノードは親ノードを持つことを示します。 * ステータスはデフォルトで"Success"(成功)です。ただし、タスクの実行プロセスをよりよく表示したい場合は、まずステータスを"start"に設定して「実行中」のログを表示し、タスク完了後にそのログのステータスを"Success"に更新することができます。これにより、ユーザーはタスクの開始から完了までの全プロセスを明確に確認できます。 * `label`は、最終的にユーザーにログのタイトルを表示するために使用されます。 ```python def create_log_message( self, label: str, data: Mapping[str, Any], status: AgentInvokeMessage.LogMessage.LogStatus = AgentInvokeMessage.LogMessage.LogStatus.SUCCESS, parent: AgentInvokeMessage | None = None, ) -> AgentInvokeMessage ``` **ログの完了** 前のステップで開始ステータスとして`start`状態を選択した場合、ログ完了インターフェースを使用してステータスを変更できます。 ```python def finish_log_message( self, log: AgentInvokeMessage, status: AgentInvokeMessage.LogMessage.LogStatus = AgentInvokeMessage.LogMessage.LogStatus.SUCCESS, error: Optional[str] = None, ) -> AgentInvokeMessage ``` **インスタンス** この例では、単純な2ステップの実行プロセスを示しています。まず「思考中」のステータスログを出力し、次に実際のタスク処理を完了します。 ```python class FunctionCallingAgentStrategy(AgentStrategy): def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: thinking_log = self.create_log_message( data={ "Query": parameters.get("query"), }, label="思考中", status=AgentInvokeMessage.LogMessage.LogStatus.START, ) yield thinking_log llm_response = self.session.model.llm.invoke( model_config=LLMModelConfig( provider="openai", model="gpt-4o-mini", mode="chat", completion_params={}, ), prompt_messages=[ SystemPromptMessage(content="あなたは役立つアシスタントです"), UserPromptMessage(content=parameters.get("query")), ], stream=False, tools=[], ) thinking_log = self.finish_log_message( log=thinking_log, ) yield thinking_log yield self.create_text_message(text=llm_response.message.content) ``` ## 関連リソース - [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - プラグイン開発の全体的なアーキテクチャを理解する - [Agent戦略プラグイン開発例](/plugin-dev-ja/9433-agent-strategy-plugin) - 実際のAgent戦略プラグイン開発例 - [マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest) - Manifestファイルの詳細な形式を理解する - [モデルの逆呼び出し](/plugin-dev-ja/9242-reverse-invocation-model) - プラットフォーム内のモデル機能を呼び出す方法を理解する - [ツールの逆呼び出し](/plugin-dev-ja/9242-reverse-invocation-tool) - 他のプラグインを呼び出す方法を理解する {/* Contributing Section DO NOT edit this section! It will be automatically generated by the script. */} --- [このページを編集する](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-ja/9232-agent.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml)