From f1f025b75d189981899cca41c62c09d2096aa79d Mon Sep 17 00:00:00 2001 From: Chenhe Gu Date: Thu, 4 Dec 2025 17:28:47 +0900 Subject: [PATCH] consolidate plugin dev docs into main structure (#581) * move files & renames * rename files and doc entries * sync develop plugin files * update group label translations * some cleanups * update configs * update links * add remote debug doc * delete redundant slashes and unnecessary notes * update ja and zh links --------- Co-authored-by: Riskey --- docs.json | 10049 ++++++++-------- .../cheatsheet.mdx | 22 +- .../creating-new-model-provider.mdx | 20 +- .../datasource-plugin.mdx | 12 +- .../develop-a-slack-bot-plugin.mdx | 46 +- .../develop-flomo-plugin.mdx | 2 +- .../develop-md-exporter.mdx | 2 +- .../dev-guides-and-walkthroughs/endpoint.mdx | 20 +- .../tool-oauth.mdx | 2 +- .../tool-plugin.mdx | 38 +- .../trigger-plugin.mdx | 4 +- .../advanced-development/bundle.mdx | 4 +- .../customizable-model.mdx | 2 +- .../reverse-invocation-app.mdx | 14 +- .../reverse-invocation-model.mdx | 16 +- .../reverse-invocation-node.mdx | 4 +- .../reverse-invocation-tool.mdx | 16 +- .../reverse-invocation.mdx | 18 +- .../plugin-types/general-specifications.mdx | 14 +- .../plugin-types/model-designing-rules.mdx | 12 +- .../plugin-types/model-schema.mdx | 12 +- .../plugin-types/multilingual-readme.mdx | 2 +- .../plugin-types/persistent-storage-kv.mdx | 2 +- .../plugin-types/plugin-info-by-manifest.mdx | 14 +- .../plugin-types/remote-debug-a-plugin.mdx | 2 +- .../features-and-specs/plugin-types/tool.mdx | 2 +- .../develop-plugin/getting-started/cli.mdx | 2 +- .../getting-started-dify-plugin.mdx | 26 +- .../develop-plugin/publishing/faq/faq.mdx | 2 +- .../plugin-auto-publish-pr.mdx | 2 +- .../marketplace-listing/release-by-file.mdx | 24 +- .../marketplace-listing/release-overview.mdx | 18 +- .../release-to-dify-marketplace.mdx | 24 +- .../release-to-individual-github-repo.mdx | 2 +- .../contributor-covenant-code-of-conduct.mdx | 18 +- .../privacy-protection-guidelines.mdx | 12 +- .../third-party-signature-verification.mdx | 2 +- .../build/predefined-error-handling-logic.mdx | 2 +- en/use-dify/build/shortcut-key.mdx | 2 +- en/use-dify/nodes/tools.mdx | 2 +- en/use-dify/nodes/trigger/plugin-trigger.mdx | 2 +- en/use-dify/nodes/variable-assigner.mdx | 2 +- .../cheatsheet.mdx | 164 + .../creating-new-model-provider.mdx | 462 + .../datasource-plugin.mdx | 458 + .../develop-a-slack-bot-plugin.mdx | 358 + .../develop-flomo-plugin.mdx | 349 + .../develop-md-exporter.mdx | 550 + .../dev-guides-and-walkthroughs/endpoint.mdx | 128 + .../tool-oauth.mdx | 382 + .../tool-plugin.mdx | 387 + .../trigger-plugin.mdx | 113 +- .../advanced-development/bundle.mdx | 106 + .../customizable-model.mdx | 360 + .../reverse-invocation-app.mdx | 142 + .../reverse-invocation-model.mdx | 69 +- .../reverse-invocation-node.mdx | 110 + .../reverse-invocation-tool.mdx | 104 + .../reverse-invocation.mdx | 47 + .../plugin-types/general-specifications.mdx | 279 + .../plugin-types/model-designing-rules.mdx | 573 + .../plugin-types/model-schema.mdx | 1263 ++ .../plugin-types/multilingual-readme.mdx | 52 + .../plugin-types/persistent-storage-kv.mdx | 162 + .../plugin-types/plugin-info-by-manifest.mdx | 253 + .../plugin-types/remote-debug-a-plugin.mdx | 33 + .../features-and-specs/plugin-types/tool.mdx | 393 + ja/develop-plugin/getting-started/cli.mdx | 156 + .../getting-started-dify-plugin.mdx | 108 + ja/develop-plugin/publishing/faq/faq.mdx | 49 + .../plugin-auto-publish-pr.mdx | 150 +- .../marketplace-listing/release-by-file.mdx | 75 + .../marketplace-listing/release-overview.mdx | 96 + .../release-to-dify-marketplace.mdx | 113 + .../release-to-individual-github-repo.mdx | 92 + .../contributor-covenant-code-of-conduct.mdx | 173 + .../privacy-protection-guidelines.mdx | 102 + .../third-party-signature-verification.mdx | 120 + ja/use-dify/nodes/trigger/plugin-trigger.mdx | 2 +- plugin-dev-en/9231-extension-plugin.mdx | 298 - plugin-dev-en/9433-agent-strategy-plugin.mdx | 1106 -- .../sync/check_mapping_consistency.py | 193 - plugin-dev-en/sync/plugin_mappings.json | 243 - .../sync/sync_all_mdx_files_to_json.py | 251 - plugin-dev-en/sync/view_file_mappings.py | 121 - .../0111-getting-started-dify-plugin.mdx | 72 - plugin-dev-ja/0131-cheatsheet.mdx | 158 - .../0211-getting-started-by-prompt.mdx | 1153 -- .../0211-getting-started-dify-tool.mdx | 520 - .../0211-getting-started-new-model.mdx | 125 - .../0221-initialize-development-tools.mdx | 77 - ...0222-creating-new-model-provider-extra.mdx | 285 - .../0222-creating-new-model-provider.mdx | 273 - plugin-dev-ja/0222-datasource-plugin.mdx | 452 - plugin-dev-ja/0222-debugging-logs.mdx | 58 - plugin-dev-ja/0222-tool-plugin.mdx | 386 - ...2-contributor-covenant-code-of-conduct.mdx | 73 - .../0312-privacy-protection-guidelines.mdx | 101 - ...312-third-party-signature-verification.mdx | 129 - plugin-dev-ja/0321-release-overview.mdx | 95 - plugin-dev-ja/0322-release-by-file.mdx | 74 - .../0322-release-to-dify-marketplace.mdx | 112 - ...0322-release-to-individual-github-repo.mdx | 117 - plugin-dev-ja/0331-faq.mdx | 46 - plugin-dev-ja/0411-doc-contribution-guide.mdx | 123 - plugin-dev-ja/0411-general-specifications.mdx | 131 - plugin-dev-ja/0411-model-designing-rules.mdx | 225 - .../0411-model-plugin-introduction.mdx | 93 - plugin-dev-ja/0411-multilingual-readme.mdx | 51 - plugin-dev-ja/0411-persistent-storage-kv.mdx | 73 - .../0411-plugin-info-by-manifest.mdx | 126 - plugin-dev-ja/0411-remote-debug-a-plugin.mdx | 43 - plugin-dev-ja/0411-tool.mdx | 132 - .../0412-doc-understanding-the-dimensions.mdx | 470 - .../0412-doc-writing-dimensions-guide.mdx | 261 - plugin-dev-ja/0412-model-schema.mdx | 695 -- .../0431-example-overview-and-index.mdx | 39 - .../0432-develop-a-slack-bot-plugin.mdx | 357 - plugin-dev-ja/0432-endpoint.mdx | 118 - plugin-dev-ja/9231-extension-plugin.mdx | 292 - plugin-dev-ja/9232-agent.mdx | 437 - plugin-dev-ja/9241-bundle.mdx | 107 - plugin-dev-ja/9241-reverse-invocation.mdx | 46 - plugin-dev-ja/9242-reverse-invocation-app.mdx | 134 - .../9242-reverse-invocation-tool.mdx | 102 - plugin-dev-ja/9243-customizable-model.mdx | 361 - .../9243-reverse-invocation-node.mdx | 107 - plugin-dev-ja/9433-agent-strategy-plugin.mdx | 1101 -- .../sync/check_mapping_consistency.py | 195 - plugin-dev-ja/sync/plugin_mappings.json | 244 - .../sync/sync_all_mdx_files_to_json.py | 251 - plugin-dev-ja/sync/view_file_mappings.py | 119 - .../0111-getting-started-dify-plugin.mdx | 73 - plugin-dev-zh/0131-cheatsheet.mdx | 160 - .../0211-getting-started-by-prompt.mdx | 1153 -- .../0211-getting-started-dify-tool.mdx | 520 - .../0211-getting-started-new-model.mdx | 125 - .../0221-initialize-development-tools.mdx | 105 - ...0222-creating-new-model-provider-extra.mdx | 285 - .../0222-creating-new-model-provider.mdx | 273 - plugin-dev-zh/0222-datasource-plugin.mdx | 451 - plugin-dev-zh/0222-debugging-logs.mdx | 58 - plugin-dev-zh/0222-tool-plugin.mdx | 386 - ...2-contributor-covenant-code-of-conduct.mdx | 117 - .../0312-privacy-protection-guidelines.mdx | 101 - ...312-third-party-signature-verification.mdx | 119 - plugin-dev-zh/0321-release-overview.mdx | 99 - plugin-dev-zh/0322-release-by-file.mdx | 74 - .../0322-release-to-dify-marketplace.mdx | 112 - ...0322-release-to-individual-github-repo.mdx | 119 - plugin-dev-zh/0331-faq.mdx | 47 - plugin-dev-zh/0411-doc-contribution-guide.mdx | 133 - plugin-dev-zh/0411-general-specifications.mdx | 131 - plugin-dev-zh/0411-model-designing-rules.mdx | 225 - .../0411-model-plugin-introduction.mdx | 104 - plugin-dev-zh/0411-multilingual-readme.mdx | 51 - plugin-dev-zh/0411-persistent-storage-kv.mdx | 73 - .../0411-plugin-info-by-manifest.mdx | 132 - plugin-dev-zh/0411-remote-debug-a-plugin.mdx | 42 - plugin-dev-zh/0411-tool.mdx | 132 - .../0412-doc-understanding-the-dimensions.mdx | 470 - .../0412-doc-writing-dimensions-guide.mdx | 261 - plugin-dev-zh/0412-model-schema.mdx | 701 -- .../0431-example-overview-and-index.mdx | 39 - .../0432-develop-a-slack-bot-plugin.mdx | 358 - plugin-dev-zh/0432-endpoint.mdx | 125 - plugin-dev-zh/9231-extension-plugin.mdx | 295 - plugin-dev-zh/9232-agent.mdx | 437 - plugin-dev-zh/9241-bundle.mdx | 105 - plugin-dev-zh/9241-reverse-invocation.mdx | 46 - plugin-dev-zh/9242-reverse-invocation-app.mdx | 138 - .../9242-reverse-invocation-tool.mdx | 104 - plugin-dev-zh/9243-customizable-model.mdx | 358 - .../9243-reverse-invocation-node.mdx | 107 - plugin-dev-zh/9433-agent-strategy-plugin.mdx | 1191 -- .../sync/check_mapping_consistency.py | 195 - plugin-dev-zh/sync/plugin_mappings.json | 250 - .../sync/sync_all_mdx_files_to_json.py | 191 - plugin-dev-zh/sync/view_file_mappings.py | 119 - scripts/contributing_in_page.py | 2 +- tools/translate/README.md | 3 +- tools/translate/config.json | 50 +- tools/translate/main.py | 16 - tools/translate/sync_and_translate.py | 4 +- .../cheatsheet.mdx | 164 + .../creating-new-model-provider.mdx | 462 + .../datasource-plugin.mdx | 458 + .../develop-a-slack-bot-plugin.mdx | 358 + .../develop-flomo-plugin.mdx | 349 + .../develop-md-exporter.mdx | 550 + .../dev-guides-and-walkthroughs/endpoint.mdx | 132 + .../tool-oauth.mdx | 176 +- .../tool-plugin.mdx | 387 + .../trigger-plugin.mdx | 115 +- .../advanced-development/bundle.mdx | 106 + .../customizable-model.mdx | 360 + .../reverse-invocation-app.mdx | 142 + .../reverse-invocation-model.mdx | 81 +- .../reverse-invocation-node.mdx | 110 + .../reverse-invocation-tool.mdx | 104 + .../reverse-invocation.mdx | 47 + .../plugin-types/general-specifications.mdx | 279 + .../plugin-types/model-designing-rules.mdx | 573 + .../plugin-types/model-schema.mdx | 1263 ++ .../plugin-types/multilingual-readme.mdx | 52 + .../plugin-types/persistent-storage-kv.mdx | 162 + .../plugin-types/plugin-info-by-manifest.mdx | 253 + .../plugin-types/remote-debug-a-plugin.mdx | 33 + .../features-and-specs/plugin-types/tool.mdx | 393 + zh/develop-plugin/getting-started/cli.mdx | 156 + .../getting-started-dify-plugin.mdx | 108 + zh/develop-plugin/publishing/faq/faq.mdx | 49 + .../plugin-auto-publish-pr.mdx | 137 +- .../marketplace-listing/release-by-file.mdx | 75 + .../marketplace-listing/release-overview.mdx | 96 + .../release-to-dify-marketplace.mdx | 113 + .../release-to-individual-github-repo.mdx | 92 + .../contributor-covenant-code-of-conduct.mdx | 173 + .../privacy-protection-guidelines.mdx | 102 + .../third-party-signature-verification.mdx | 120 + zh/use-dify/nodes/trigger/plugin-trigger.mdx | 2 +- 221 files changed, 21698 insertions(+), 29576 deletions(-) rename plugin-dev-en/0131-cheatsheet.mdx => en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx (74%) rename plugin-dev-en/0222-creating-new-model-provider.mdx => en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx (93%) rename plugin-dev-en/0222-datasource-plugin.mdx => en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx (96%) rename plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx => en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx (81%) rename plugin-dev-en/0432-develop-flomo-plugin.mdx => en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx (98%) rename plugin-dev-en/0432-develop-md-exporter.mdx => en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx (98%) rename plugin-dev-en/0432-endpoint.mdx => en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx (66%) rename plugin-dev-en/0222-tool-oauth.mdx => en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx (98%) rename plugin-dev-en/0222-tool-plugin.mdx => en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx (85%) rename plugin-dev-en/0222-trigger-plugin.mdx => en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx (99%) rename plugin-dev-en/9241-bundle.mdx => en/develop-plugin/features-and-specs/advanced-development/bundle.mdx (94%) rename plugin-dev-en/9243-customizable-model.mdx => en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx (98%) rename plugin-dev-en/9242-reverse-invocation-app.mdx => en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx (78%) rename plugin-dev-en/9242-reverse-invocation-model.mdx => en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx (85%) rename plugin-dev-en/9243-reverse-invocation-node.mdx => en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx (92%) rename plugin-dev-en/9242-reverse-invocation-tool.mdx => en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx (72%) rename plugin-dev-en/9241-reverse-invocation.mdx => en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx (52%) rename plugin-dev-en/0411-general-specifications.mdx => en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx (87%) rename plugin-dev-en/0411-model-designing-rules.mdx => en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx (94%) rename plugin-dev-en/0412-model-schema.mdx => en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx (97%) rename plugin-dev-en/0411-multilingual-readme.mdx => en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx (92%) rename plugin-dev-en/0411-persistent-storage-kv.mdx => en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx (96%) rename plugin-dev-en/0411-plugin-info-by-manifest.mdx => en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx (88%) rename plugin-dev-en/0411-remote-debug-a-plugin.mdx => en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx (91%) rename plugin-dev-en/0411-tool.mdx => en/develop-plugin/features-and-specs/plugin-types/tool.mdx (98%) rename plugin-dev-en/0111-cli.mdx => en/develop-plugin/getting-started/cli.mdx (97%) rename plugin-dev-en/0111-getting-started-dify-plugin.mdx => en/develop-plugin/getting-started/getting-started-dify-plugin.mdx (61%) rename plugin-dev-en/0331-faq.mdx => en/develop-plugin/publishing/faq/faq.mdx (93%) rename plugin-dev-en/0321-plugin-auto-publish-pr.mdx => en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx (98%) rename plugin-dev-en/0322-release-by-file.mdx => en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx (63%) rename plugin-dev-en/0321-release-overview.mdx => en/develop-plugin/publishing/marketplace-listing/release-overview.mdx (71%) rename plugin-dev-en/0322-release-to-dify-marketplace.mdx => en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx (70%) rename plugin-dev-en/0322-release-to-individual-github-repo.mdx => en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx (95%) rename plugin-dev-en/0312-contributor-covenant-code-of-conduct.mdx => en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx (87%) rename plugin-dev-en/0312-privacy-protection-guidelines.mdx => en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx (84%) rename plugin-dev-en/0312-third-party-signature-verification.mdx => en/develop-plugin/publishing/standards/third-party-signature-verification.mdx (96%) create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx create mode 100644 ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx rename plugin-dev-ja/0222-trigger-plugin.mdx => ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx (69%) create mode 100644 ja/develop-plugin/features-and-specs/advanced-development/bundle.mdx create mode 100644 ja/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx create mode 100644 ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx rename plugin-dev-ja/9242-reverse-invocation-model.mdx => ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx (50%) create mode 100644 ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx create mode 100644 ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx create mode 100644 ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/model-schema.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx create mode 100644 ja/develop-plugin/features-and-specs/plugin-types/tool.mdx create mode 100644 ja/develop-plugin/getting-started/cli.mdx create mode 100644 ja/develop-plugin/getting-started/getting-started-dify-plugin.mdx create mode 100644 ja/develop-plugin/publishing/faq/faq.mdx rename plugin-dev-ja/0321-plugin-auto-publish-pr.mdx => ja/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx (53%) create mode 100644 ja/develop-plugin/publishing/marketplace-listing/release-by-file.mdx create mode 100644 ja/develop-plugin/publishing/marketplace-listing/release-overview.mdx create mode 100644 ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx create mode 100644 ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx create mode 100644 ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx create mode 100644 ja/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx create mode 100644 ja/develop-plugin/publishing/standards/third-party-signature-verification.mdx delete mode 100644 plugin-dev-en/9231-extension-plugin.mdx delete mode 100644 plugin-dev-en/9433-agent-strategy-plugin.mdx delete mode 100644 plugin-dev-en/sync/check_mapping_consistency.py delete mode 100644 plugin-dev-en/sync/plugin_mappings.json delete mode 100644 plugin-dev-en/sync/sync_all_mdx_files_to_json.py delete mode 100644 plugin-dev-en/sync/view_file_mappings.py delete mode 100644 plugin-dev-ja/0111-getting-started-dify-plugin.mdx delete mode 100644 plugin-dev-ja/0131-cheatsheet.mdx delete mode 100644 plugin-dev-ja/0211-getting-started-by-prompt.mdx delete mode 100644 plugin-dev-ja/0211-getting-started-dify-tool.mdx delete mode 100644 plugin-dev-ja/0211-getting-started-new-model.mdx delete mode 100644 plugin-dev-ja/0221-initialize-development-tools.mdx delete mode 100644 plugin-dev-ja/0222-creating-new-model-provider-extra.mdx delete mode 100644 plugin-dev-ja/0222-creating-new-model-provider.mdx delete mode 100644 plugin-dev-ja/0222-datasource-plugin.mdx delete mode 100644 plugin-dev-ja/0222-debugging-logs.mdx delete mode 100644 plugin-dev-ja/0222-tool-plugin.mdx delete mode 100644 plugin-dev-ja/0312-contributor-covenant-code-of-conduct.mdx delete mode 100644 plugin-dev-ja/0312-privacy-protection-guidelines.mdx delete mode 100644 plugin-dev-ja/0312-third-party-signature-verification.mdx delete mode 100644 plugin-dev-ja/0321-release-overview.mdx delete mode 100644 plugin-dev-ja/0322-release-by-file.mdx delete mode 100644 plugin-dev-ja/0322-release-to-dify-marketplace.mdx delete mode 100644 plugin-dev-ja/0322-release-to-individual-github-repo.mdx delete mode 100644 plugin-dev-ja/0331-faq.mdx delete mode 100644 plugin-dev-ja/0411-doc-contribution-guide.mdx delete mode 100644 plugin-dev-ja/0411-general-specifications.mdx delete mode 100644 plugin-dev-ja/0411-model-designing-rules.mdx delete mode 100644 plugin-dev-ja/0411-model-plugin-introduction.mdx delete mode 100644 plugin-dev-ja/0411-multilingual-readme.mdx delete mode 100644 plugin-dev-ja/0411-persistent-storage-kv.mdx delete mode 100644 plugin-dev-ja/0411-plugin-info-by-manifest.mdx delete mode 100644 plugin-dev-ja/0411-remote-debug-a-plugin.mdx delete mode 100644 plugin-dev-ja/0411-tool.mdx delete mode 100644 plugin-dev-ja/0412-doc-understanding-the-dimensions.mdx delete mode 100644 plugin-dev-ja/0412-doc-writing-dimensions-guide.mdx delete mode 100644 plugin-dev-ja/0412-model-schema.mdx delete mode 100644 plugin-dev-ja/0431-example-overview-and-index.mdx delete mode 100644 plugin-dev-ja/0432-develop-a-slack-bot-plugin.mdx delete mode 100644 plugin-dev-ja/0432-endpoint.mdx delete mode 100644 plugin-dev-ja/9231-extension-plugin.mdx delete mode 100644 plugin-dev-ja/9232-agent.mdx delete mode 100644 plugin-dev-ja/9241-bundle.mdx delete mode 100644 plugin-dev-ja/9241-reverse-invocation.mdx delete mode 100644 plugin-dev-ja/9242-reverse-invocation-app.mdx delete mode 100644 plugin-dev-ja/9242-reverse-invocation-tool.mdx delete mode 100644 plugin-dev-ja/9243-customizable-model.mdx delete mode 100644 plugin-dev-ja/9243-reverse-invocation-node.mdx delete mode 100644 plugin-dev-ja/9433-agent-strategy-plugin.mdx delete mode 100644 plugin-dev-ja/sync/check_mapping_consistency.py delete mode 100644 plugin-dev-ja/sync/plugin_mappings.json delete mode 100644 plugin-dev-ja/sync/sync_all_mdx_files_to_json.py delete mode 100644 plugin-dev-ja/sync/view_file_mappings.py delete mode 100644 plugin-dev-zh/0111-getting-started-dify-plugin.mdx delete mode 100644 plugin-dev-zh/0131-cheatsheet.mdx delete mode 100644 plugin-dev-zh/0211-getting-started-by-prompt.mdx delete mode 100644 plugin-dev-zh/0211-getting-started-dify-tool.mdx delete mode 100644 plugin-dev-zh/0211-getting-started-new-model.mdx delete mode 100644 plugin-dev-zh/0221-initialize-development-tools.mdx delete mode 100644 plugin-dev-zh/0222-creating-new-model-provider-extra.mdx delete mode 100644 plugin-dev-zh/0222-creating-new-model-provider.mdx delete mode 100644 plugin-dev-zh/0222-datasource-plugin.mdx delete mode 100644 plugin-dev-zh/0222-debugging-logs.mdx delete mode 100644 plugin-dev-zh/0222-tool-plugin.mdx delete mode 100644 plugin-dev-zh/0312-contributor-covenant-code-of-conduct.mdx delete mode 100644 plugin-dev-zh/0312-privacy-protection-guidelines.mdx delete mode 100644 plugin-dev-zh/0312-third-party-signature-verification.mdx delete mode 100644 plugin-dev-zh/0321-release-overview.mdx delete mode 100644 plugin-dev-zh/0322-release-by-file.mdx delete mode 100644 plugin-dev-zh/0322-release-to-dify-marketplace.mdx delete mode 100644 plugin-dev-zh/0322-release-to-individual-github-repo.mdx delete mode 100644 plugin-dev-zh/0331-faq.mdx delete mode 100644 plugin-dev-zh/0411-doc-contribution-guide.mdx delete mode 100644 plugin-dev-zh/0411-general-specifications.mdx delete mode 100644 plugin-dev-zh/0411-model-designing-rules.mdx delete mode 100644 plugin-dev-zh/0411-model-plugin-introduction.mdx delete mode 100644 plugin-dev-zh/0411-multilingual-readme.mdx delete mode 100644 plugin-dev-zh/0411-persistent-storage-kv.mdx delete mode 100644 plugin-dev-zh/0411-plugin-info-by-manifest.mdx delete mode 100644 plugin-dev-zh/0411-remote-debug-a-plugin.mdx delete mode 100644 plugin-dev-zh/0411-tool.mdx delete mode 100644 plugin-dev-zh/0412-doc-understanding-the-dimensions.mdx delete mode 100644 plugin-dev-zh/0412-doc-writing-dimensions-guide.mdx delete mode 100644 plugin-dev-zh/0412-model-schema.mdx delete mode 100644 plugin-dev-zh/0431-example-overview-and-index.mdx delete mode 100644 plugin-dev-zh/0432-develop-a-slack-bot-plugin.mdx delete mode 100644 plugin-dev-zh/0432-endpoint.mdx delete mode 100644 plugin-dev-zh/9231-extension-plugin.mdx delete mode 100644 plugin-dev-zh/9232-agent.mdx delete mode 100644 plugin-dev-zh/9241-bundle.mdx delete mode 100644 plugin-dev-zh/9241-reverse-invocation.mdx delete mode 100644 plugin-dev-zh/9242-reverse-invocation-app.mdx delete mode 100644 plugin-dev-zh/9242-reverse-invocation-tool.mdx delete mode 100644 plugin-dev-zh/9243-customizable-model.mdx delete mode 100644 plugin-dev-zh/9243-reverse-invocation-node.mdx delete mode 100644 plugin-dev-zh/9433-agent-strategy-plugin.mdx delete mode 100644 plugin-dev-zh/sync/check_mapping_consistency.py delete mode 100644 plugin-dev-zh/sync/plugin_mappings.json delete mode 100644 plugin-dev-zh/sync/sync_all_mdx_files_to_json.py delete mode 100644 plugin-dev-zh/sync/view_file_mappings.py create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx rename plugin-dev-zh/0222-tool-oauth.mdx => zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx (55%) create mode 100644 zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx rename plugin-dev-zh/0222-trigger-plugin.mdx => zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx (76%) create mode 100644 zh/develop-plugin/features-and-specs/advanced-development/bundle.mdx create mode 100644 zh/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx create mode 100644 zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx rename plugin-dev-zh/9242-reverse-invocation-model.mdx => zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx (57%) create mode 100644 zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx create mode 100644 zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx create mode 100644 zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/model-schema.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx create mode 100644 zh/develop-plugin/features-and-specs/plugin-types/tool.mdx create mode 100644 zh/develop-plugin/getting-started/cli.mdx create mode 100644 zh/develop-plugin/getting-started/getting-started-dify-plugin.mdx create mode 100644 zh/develop-plugin/publishing/faq/faq.mdx rename plugin-dev-zh/0321-plugin-auto-publish-pr.mdx => zh/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx (62%) create mode 100644 zh/develop-plugin/publishing/marketplace-listing/release-by-file.mdx create mode 100644 zh/develop-plugin/publishing/marketplace-listing/release-overview.mdx create mode 100644 zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx create mode 100644 zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx create mode 100644 zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx create mode 100644 zh/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx create mode 100644 zh/develop-plugin/publishing/standards/third-party-signature-verification.mdx diff --git a/docs.json b/docs.json index 415ce74c..c545dcfa 100644 --- a/docs.json +++ b/docs.json @@ -1,5076 +1,4991 @@ { - "$schema": "https://mintlify.com/docs.json", - "theme": "maple", - "name": "Dify Docs", - "colors": { - "primary": "#0060FF", - "light": "#688FE8", - "dark": "#0034FF" + "$schema": "https://mintlify.com/docs.json", + "theme": "maple", + "name": "Dify Docs", + "colors": { + "primary": "#0060FF", + "light": "#688FE8", + "dark": "#0034FF" + }, + "description": "Dify is an open-source platform for building AI applications. It provides a comprehensive set of tools and features to help you build, deploy, and manage your AI applications.", + "favicon": "/logo/dify-logo.png", + "logo": { + "light": "https://assets-docs.dify.ai/2025/05/d05cfc6ebe48f725d171dc71c64a5d16.svg", + "dark": "https://assets-docs.dify.ai/2025/05/c51f1cda47c1d9a4a162d7736f6e4c53.svg" + }, + "navigation": { + "versions": [ + { + "version": "Latest", + "languages": [ + { + "language": "en", + "default": true, + "href": "en/use-dify/getting-started/introduction", + "dropdowns": [ + { + "dropdown": "Use Dify", + "icon": "book-open", + "pages": [ + { + "group": " ", + "pages": [ + { + "group": "Get Started", + "expanded": false, + "pages": [ + "en/use-dify/getting-started/introduction", + "en/use-dify/getting-started/quick-start", + "en/use-dify/getting-started/key-concepts" + ] + }, + { + "group": "Nodes", + "expanded": false, + "pages": [ + "en/use-dify/nodes/user-input", + { + "group": "Trigger", + "icon": "bolt-lightning", + "pages": [ + "en/use-dify/nodes/trigger/overview", + "en/use-dify/nodes/trigger/schedule-trigger", + "en/use-dify/nodes/trigger/plugin-trigger", + "en/use-dify/nodes/trigger/webhook-trigger" + ] + }, + "en/use-dify/nodes/llm", + "en/use-dify/nodes/knowledge-retrieval", + "en/use-dify/nodes/answer", + "en/use-dify/nodes/output", + "en/use-dify/nodes/agent", + "en/use-dify/nodes/tools", + "en/use-dify/nodes/question-classifier", + "en/use-dify/nodes/ifelse", + "en/use-dify/nodes/iteration", + "en/use-dify/nodes/loop", + "en/use-dify/nodes/code", + "en/use-dify/nodes/template", + "en/use-dify/nodes/variable-aggregator", + "en/use-dify/nodes/doc-extractor", + "en/use-dify/nodes/variable-assigner", + "en/use-dify/nodes/parameter-extractor", + "en/use-dify/nodes/http-request", + "en/use-dify/nodes/list-operator" + ] + }, + { + "group": "Build", + "expanded": false, + "pages": [ + "en/use-dify/build/shortcut-key", + "en/use-dify/build/goto-anything", + "en/use-dify/build/orchestrate-node", + "en/use-dify/build/predefined-error-handling-logic", + "en/use-dify/build/mcp", + "en/use-dify/build/version-control", + "en/use-dify/build/additional-features" + ] + }, + { + "group": "Debug", + "expanded": false, + "pages": [ + "en/use-dify/debug/step-run", + "en/use-dify/debug/variable-inspect", + "en/use-dify/debug/history-and-logs", + "en/use-dify/debug/error-type" + ] + }, + { + "group": "Publish", + "expanded": false, + "pages": [ + "en/use-dify/publish/README", + { + "group": "Web App", + "icon": "globe", + "pages": [ + "en/use-dify/publish/webapp/workflow-webapp", + "en/use-dify/publish/webapp/chatflow-webapp", + "en/use-dify/publish/webapp/web-app-settings", + "en/use-dify/publish/webapp/web-app-access", + "en/use-dify/publish/webapp/embedding-in-websites" + ] + }, + "en/use-dify/publish/publish-mcp", + "en/use-dify/publish/developing-with-apis" + ] + }, + { + "group": "Monitor", + "expanded": false, + "pages": [ + "en/use-dify/monitor/analysis", + "en/use-dify/monitor/logs", + "en/use-dify/monitor/annotation-reply", + { + "group": "Integrations", + "icon": "grid-2-plus", + "pages": [ + "en/use-dify/monitor/integrations/integrate-langsmith", + "en/use-dify/monitor/integrations/integrate-langfuse", + "en/use-dify/monitor/integrations/integrate-arize", + "en/use-dify/monitor/integrations/integrate-opik", + "en/use-dify/monitor/integrations/integrate-phoenix", + "en/use-dify/monitor/integrations/integrate-weave" + ] + } + ] + }, + { + "group": "Knowledge", + "expanded": false, + "pages": [ + "en/use-dify/knowledge/readme", + { + "group": "Create Knowledge", + "icon": "square-plus", + "pages": [ + "en/use-dify/knowledge/create-knowledge/introduction", + { + "group": "1. Import Text Data", + "pages": [ + "en/use-dify/knowledge/create-knowledge/import-text-data/readme", + "en/use-dify/knowledge/create-knowledge/import-text-data/sync-from-notion", + "en/use-dify/knowledge/create-knowledge/import-text-data/sync-from-website" + ] + }, + "en/use-dify/knowledge/create-knowledge/chunking-and-cleaning-text", + "en/use-dify/knowledge/create-knowledge/setting-indexing-methods" + ] + }, + { + "group": "Create from Knowledge Pipeline", + "icon": "pipe-section", + "pages": [ + "en/use-dify/knowledge/knowledge-pipeline/readme", + "en/use-dify/knowledge/knowledge-pipeline/create-knowledge-pipeline", + "en/use-dify/knowledge/knowledge-pipeline/knowledge-pipeline-orchestration", + "en/use-dify/knowledge/knowledge-pipeline/publish-knowledge-pipeline", + "en/use-dify/knowledge/knowledge-pipeline/upload-files", + "en/use-dify/knowledge/knowledge-pipeline/manage-knowledge-base", + "en/use-dify/knowledge/knowledge-pipeline/authorize-data-source" + ] + }, + { + "group": "Manage Knowledge", + "icon": "gear", + "pages": [ + "en/use-dify/knowledge/manage-knowledge/introduction", + "en/use-dify/knowledge/manage-knowledge/maintain-knowledge-documents", + "en/use-dify/knowledge/manage-knowledge/maintain-dataset-via-api" + ] + }, + "en/use-dify/knowledge/metadata", + "en/use-dify/knowledge/integrate-knowledge-within-application", + "en/use-dify/knowledge/retrieval-test-and-citation", + "en/use-dify/knowledge/knowledge-request-rate-limit", + "en/use-dify/knowledge/connect-external-knowledge-base", + "en/use-dify/knowledge/external-knowledge-api" + ] + }, + { + "group": "Workspace", + "expanded": false, + "pages": [ + "en/use-dify/workspace/readme", + "en/use-dify/workspace/model-providers", + "en/use-dify/workspace/plugins", + "en/use-dify/workspace/app-management", + "en/use-dify/workspace/team-members-management", + "en/use-dify/workspace/personal-account-management", + "en/use-dify/workspace/subscription-management" + ] + }, + { + "group": "Tutorials", + "expanded": false, + "pages": [ + "en/use-dify/tutorials/simple-chatbot", + "en/use-dify/tutorials/twitter-chatflow", + "en/use-dify/tutorials/customer-service-bot", + "en/use-dify/tutorials/build-ai-image-generation-app", + "en/use-dify/tutorials/article-reader" + ] + } + ] + } + ] + }, + { + "dropdown": "Self Host", + "icon": "server", + "pages": [ + { + "group": "Quick Start", + "pages": [ + "en/self-host/quick-start/docker-compose", + "en/self-host/quick-start/faqs" + ] + }, + { + "group": "Advanced Deployments", + "pages": [ + "en/self-host/advanced-deployments/local-source-code", + "en/self-host/advanced-deployments/start-the-frontend-docker-container" + ] + }, + { + "group": "Configuration", + "pages": [ + "en/self-host/configuration/environments" + ] + }, + { + "group": "Platform Guides", + "pages": [ + "en/self-host/platform-guides/bt-panel", + "en/self-host/platform-guides/dify-premium" + ] + }, + { + "group": "Troubleshooting", + "pages": [ + "en/self-host/troubleshooting/common-issues", + "en/self-host/troubleshooting/docker-issues", + "en/self-host/troubleshooting/integrations", + "en/self-host/troubleshooting/storage-and-migration", + "en/self-host/troubleshooting/weaviate-v4-migration" + ] + } + ] + }, + { + "dropdown": "API Reference", + "icon": "code", + "groups": [ + { + "group": "Chat and Agent", + "openapi": "en/api-reference/openapi_chat.json" + }, + { + "group": "Chatflow", + "openapi": "en/api-reference/openapi_chatflow.json" + }, + { + "group": "Workflow", + "openapi": "en/api-reference/openapi_workflow.json" + }, + { + "group": "Knowledge", + "openapi": "en/api-reference/openapi_knowledge.json" + }, + { + "group": "Text Completion", + "openapi": "en/api-reference/openapi_completion.json" + } + ] + }, + { + "dropdown": "Develop Plugin", + "icon": "code-pull-request", + "groups": [ + { + "group": "Getting Started", + "pages": [ + "en/develop-plugin/getting-started/getting-started-dify-plugin", + "en/develop-plugin/getting-started/cli" + ] + }, + { + "group": "Features & Specs", + "pages": [ + { + "group": "Plugin Types", + "pages": [ + "en/develop-plugin/features-and-specs/plugin-types/general-specifications", + "en/develop-plugin/features-and-specs/plugin-types/model-designing-rules", + "en/develop-plugin/features-and-specs/plugin-types/model-schema", + "en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv", + "en/develop-plugin/features-and-specs/plugin-types/tool", + "en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest", + "en/develop-plugin/features-and-specs/plugin-types/multilingual-readme", + "en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin" + ] + }, + { + "group": "Advanced Development", + "pages": [ + { + "group": "Reverse Calling", + "pages": [ + "en/develop-plugin/features-and-specs/advanced-development/bundle", + "en/develop-plugin/features-and-specs/advanced-development/reverse-invocation", + "en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app", + "en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model", + "en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool", + "en/develop-plugin/features-and-specs/advanced-development/customizable-model", + "en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node" + ] + } + ] + } + ] + }, + { + "group": "Development Guides & Walkthroughs", + "pages": [ + "en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet", + "en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin", + "en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth", + "en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin", + "en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin", + "en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider", + "en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin", + "en/develop-plugin/dev-guides-and-walkthroughs/endpoint", + "en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin", + "en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter" + ] + }, + { + "group": "Publishing", + "pages": [ + { + "group": "Standards", + "pages": [ + "en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct", + "en/develop-plugin/publishing/standards/privacy-protection-guidelines", + "en/develop-plugin/publishing/standards/third-party-signature-verification" + ] + }, + { + "group": "Marketplace Listing", + "pages": [ + "en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr", + "en/develop-plugin/publishing/marketplace-listing/release-overview", + "en/develop-plugin/publishing/marketplace-listing/release-by-file", + "en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace", + "en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo" + ] + }, + { + "group": "FAQ", + "pages": [ + "en/develop-plugin/publishing/faq/faq" + ] + } + ] + } + ] + } + ] + }, + { + "language": "zh", + "href": "zh/use-dify/getting-started/introduction", + "dropdowns": [ + { + "dropdown": "使用 Dify", + "icon": "book-open", + "pages": [ + { + "group": " ", + "pages": [ + { + "group": "入门", + "expanded": false, + "pages": [ + "zh/use-dify/getting-started/introduction", + "zh/use-dify/getting-started/quick-start", + "zh/use-dify/getting-started/key-concepts" + ] + }, + { + "group": "节点", + "expanded": false, + "pages": [ + "zh/use-dify/nodes/user-input", + { + "group": "触发器", + "icon": "bolt-lightning", + "pages": [ + "zh/use-dify/nodes/trigger/overview", + "zh/use-dify/nodes/trigger/schedule-trigger", + "zh/use-dify/nodes/trigger/plugin-trigger", + "zh/use-dify/nodes/trigger/webhook-trigger" + ] + }, + "zh/use-dify/nodes/llm", + "zh/use-dify/nodes/knowledge-retrieval", + "zh/use-dify/nodes/answer", + "zh/use-dify/nodes/output", + "zh/use-dify/nodes/agent", + "zh/use-dify/nodes/tools", + "zh/use-dify/nodes/question-classifier", + "zh/use-dify/nodes/ifelse", + "zh/use-dify/nodes/iteration", + "zh/use-dify/nodes/loop", + "zh/use-dify/nodes/code", + "zh/use-dify/nodes/template", + "zh/use-dify/nodes/variable-aggregator", + "zh/use-dify/nodes/doc-extractor", + "zh/use-dify/nodes/variable-assigner", + "zh/use-dify/nodes/parameter-extractor", + "zh/use-dify/nodes/http-request", + "zh/use-dify/nodes/list-operator" + ] + }, + { + "group": "构建", + "expanded": false, + "pages": [ + "zh/use-dify/build/shortcut-key", + "zh/use-dify/build/goto-anything", + "zh/use-dify/build/orchestrate-node", + "zh/use-dify/build/predefined-error-handling-logic", + "zh/use-dify/build/mcp", + "zh/use-dify/build/version-control", + "zh/use-dify/build/additional-features" + ] + }, + { + "group": "调试", + "expanded": false, + "pages": [ + "zh/use-dify/debug/step-run", + "zh/use-dify/debug/variable-inspect", + "zh/use-dify/debug/history-and-logs", + "zh/use-dify/debug/error-type" + ] + }, + { + "group": "发布", + "expanded": false, + "pages": [ + "zh/use-dify/publish/README", + { + "group": "Web App", + "icon": "globe", + "pages": [ + "zh/use-dify/publish/webapp/workflow-webapp", + "zh/use-dify/publish/webapp/chatflow-webapp", + "zh/use-dify/publish/webapp/web-app-settings", + "zh/use-dify/publish/webapp/web-app-access", + "zh/use-dify/publish/webapp/embedding-in-websites" + ] + }, + "zh/use-dify/publish/publish-mcp", + "zh/use-dify/publish/developing-with-apis" + ] + }, + { + "group": "监控", + "expanded": false, + "pages": [ + "zh/use-dify/monitor/analysis", + "zh/use-dify/monitor/logs", + "zh/use-dify/monitor/annotation-reply", + { + "group": "集成", + "icon": "grid-2-plus", + "pages": [ + "zh/use-dify/monitor/integrations/integrate-langsmith", + "zh/use-dify/monitor/integrations/integrate-langfuse", + "zh/use-dify/monitor/integrations/integrate-arize", + "zh/use-dify/monitor/integrations/integrate-opik", + "zh/use-dify/monitor/integrations/integrate-phoenix", + "zh/use-dify/monitor/integrations/integrate-weave" + ] + } + ] + }, + { + "group": "知识库", + "expanded": false, + "pages": [ + "zh/use-dify/knowledge/readme", + { + "group": "创建知识库", + "icon": "square-plus", + "pages": [ + "zh/use-dify/knowledge/create-knowledge/introduction", + { + "group": "导入文本数据", + "pages": [ + "zh/use-dify/knowledge/create-knowledge/import-text-data/readme", + "zh/use-dify/knowledge/create-knowledge/import-text-data/sync-from-notion", + "zh/use-dify/knowledge/create-knowledge/import-text-data/sync-from-website" + ] + }, + "zh/use-dify/knowledge/create-knowledge/chunking-and-cleaning-text", + "zh/use-dify/knowledge/create-knowledge/setting-indexing-methods" + ] + }, + { + "group": "从 Knowledge Pipeline 创建", + "icon": "pipe-section", + "pages": [ + "zh/use-dify/knowledge/knowledge-pipeline/readme", + "zh/use-dify/knowledge/knowledge-pipeline/create-knowledge-pipeline", + "zh/use-dify/knowledge/knowledge-pipeline/knowledge-pipeline-orchestration", + "zh/use-dify/knowledge/knowledge-pipeline/publish-knowledge-pipeline", + "zh/use-dify/knowledge/knowledge-pipeline/upload-files", + "zh/use-dify/knowledge/knowledge-pipeline/manage-knowledge-base", + "zh/use-dify/knowledge/knowledge-pipeline/authorize-data-source" + ] + }, + { + "group": "管理知识库", + "icon": "gear", + "pages": [ + "zh/use-dify/knowledge/manage-knowledge/introduction", + "zh/use-dify/knowledge/manage-knowledge/maintain-knowledge-documents", + "zh/use-dify/knowledge/manage-knowledge/maintain-dataset-via-api" + ] + }, + "zh/use-dify/knowledge/metadata", + "zh/use-dify/knowledge/integrate-knowledge-within-application", + "zh/use-dify/knowledge/retrieval-test-and-citation", + "zh/use-dify/knowledge/knowledge-request-rate-limit", + "zh/use-dify/knowledge/connect-external-knowledge-base", + "zh/use-dify/knowledge/external-knowledge-api" + ] + }, + { + "group": "工作区", + "expanded": false, + "pages": [ + "zh/use-dify/workspace/readme", + "zh/use-dify/workspace/model-providers", + "zh/use-dify/workspace/plugins", + "zh/use-dify/workspace/app-management", + "zh/use-dify/workspace/team-members-management", + "zh/use-dify/workspace/personal-account-management", + "zh/use-dify/workspace/subscription-management" + ] + }, + { + "group": "教程", + "expanded": false, + "pages": [ + "zh/use-dify/tutorials/simple-chatbot", + "zh/use-dify/tutorials/twitter-chatflow", + "zh/use-dify/tutorials/customer-service-bot", + "zh/use-dify/tutorials/build-ai-image-generation-app", + "zh/use-dify/tutorials/article-reader" + ] + } + ] + } + ] + }, + { + "dropdown": "自托管", + "icon": "server", + "pages": [ + { + "group": "快速开始", + "pages": [ + "zh/self-host/quick-start/docker-compose", + "zh/self-host/quick-start/faqs" + ] + }, + { + "group": "进阶部署", + "pages": [ + "zh/self-host/advanced-deployments/local-source-code", + "zh/self-host/advanced-deployments/start-the-frontend-docker-container" + ] + }, + { + "group": "配置", + "pages": [ + "zh/self-host/configuration/environments" + ] + }, + { + "group": "平台指南", + "pages": [ + "zh/self-host/platform-guides/bt-panel", + "zh/self-host/platform-guides/dify-premium" + ] + }, + { + "group": "故障排除", + "pages": [ + "zh/self-host/troubleshooting/common-issues", + "zh/self-host/troubleshooting/docker-issues", + "zh/self-host/troubleshooting/integrations", + "zh/self-host/troubleshooting/storage-and-migration", + "zh/self-host/troubleshooting/weaviate-v4-migration" + ] + } + ] + }, + { + "dropdown": "API 文档", + "icon": "code", + "groups": [ + { + "group": "Chatbot 和 Agent", + "openapi": "zh/api-reference/openapi_chat.json" + }, + { + "group": "Chatflow", + "openapi": "zh/api-reference/openapi_chatflow.json" + }, + { + "group": "工作流", + "openapi": "zh/api-reference/openapi_workflow.json" + }, + { + "group": "知识库", + "openapi": "zh/api-reference/openapi_knowledge.json" + }, + { + "group": "文本生成", + "openapi": "zh/api-reference/openapi_completion.json" + } + ] + }, + { + "dropdown": "开发插件", + "icon": "code-pull-request", + "groups": [ + { + "group": "快速开始", + "pages": [ + "zh/develop-plugin/getting-started/getting-started-dify-plugin", + "zh/develop-plugin/getting-started/cli" + ] + }, + { + "group": "特性与规范", + "pages": [ + { + "group": "插件类型", + "pages": [ + "zh/develop-plugin/features-and-specs/plugin-types/general-specifications", + "zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules", + "zh/develop-plugin/features-and-specs/plugin-types/model-schema", + "zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv", + "zh/develop-plugin/features-and-specs/plugin-types/tool", + "zh/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest", + "zh/develop-plugin/features-and-specs/plugin-types/multilingual-readme", + "zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin" + ] + }, + { + "group": "高级开发", + "pages": [ + { + "group": "反向调用", + "pages": [ + "zh/develop-plugin/features-and-specs/advanced-development/bundle", + "zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation", + "zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app", + "zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model", + "zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool", + "zh/develop-plugin/features-and-specs/advanced-development/customizable-model", + "zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node" + ] + } + ] + } + ] + }, + { + "group": "开发指南与示例", + "pages": [ + "zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet", + "zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin", + "zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth", + "zh/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin", + "zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin", + "zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider", + "zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin", + "zh/develop-plugin/dev-guides-and-walkthroughs/endpoint", + "zh/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin", + "zh/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter" + ] + }, + { + "group": "发布", + "pages": [ + { + "group": "标准", + "pages": [ + "zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct", + "zh/develop-plugin/publishing/standards/privacy-protection-guidelines", + "zh/develop-plugin/publishing/standards/third-party-signature-verification" + ] + }, + { + "group": "上架插件市场", + "pages": [ + "zh/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr", + "zh/develop-plugin/publishing/marketplace-listing/release-overview", + "zh/develop-plugin/publishing/marketplace-listing/release-by-file", + "zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace", + "zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo" + ] + }, + { + "group": "常见问题", + "pages": [ + "zh/develop-plugin/publishing/faq/faq" + ] + } + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "ja/use-dify/getting-started/introduction", + "dropdowns": [ + { + "dropdown": "Dify を使う", + "icon": "book-open", + "pages": [ + { + "group": " ", + "pages": [ + { + "group": "はじめに", + "expanded": false, + "pages": [ + "ja/use-dify/getting-started/introduction", + "ja/use-dify/getting-started/quick-start", + "ja/use-dify/getting-started/key-concepts" + ] + }, + { + "group": "ノード", + "expanded": false, + "pages": [ + "ja/use-dify/nodes/user-input", + { + "group": "トリガー", + "icon": "bolt-lightning", + "pages": [ + "ja/use-dify/nodes/trigger/overview", + "ja/use-dify/nodes/trigger/schedule-trigger", + "ja/use-dify/nodes/trigger/plugin-trigger", + "ja/use-dify/nodes/trigger/webhook-trigger" + ] + }, + "ja/use-dify/nodes/llm", + "ja/use-dify/nodes/knowledge-retrieval", + "ja/use-dify/nodes/answer", + "ja/use-dify/nodes/output", + "ja/use-dify/nodes/agent", + "ja/use-dify/nodes/tools", + "ja/use-dify/nodes/question-classifier", + "ja/use-dify/nodes/ifelse", + "ja/use-dify/nodes/iteration", + "ja/use-dify/nodes/loop", + "ja/use-dify/nodes/code", + "ja/use-dify/nodes/template", + "ja/use-dify/nodes/variable-aggregator", + "ja/use-dify/nodes/doc-extractor", + "ja/use-dify/nodes/variable-assigner", + "ja/use-dify/nodes/parameter-extractor", + "ja/use-dify/nodes/http-request", + "ja/use-dify/nodes/list-operator" + ] + }, + { + "group": "ビルド", + "expanded": false, + "pages": [ + "ja/use-dify/build/shortcut-key", + "ja/use-dify/build/goto-anything", + "ja/use-dify/build/orchestrate-node", + "ja/use-dify/build/predefined-error-handling-logic", + "ja/use-dify/build/mcp", + "ja/use-dify/build/version-control", + "ja/use-dify/build/additional-features" + ] + }, + { + "group": "デバッグ", + "expanded": false, + "pages": [ + "ja/use-dify/debug/step-run", + "ja/use-dify/debug/variable-inspect", + "ja/use-dify/debug/history-and-logs", + "ja/use-dify/debug/error-type" + ] + }, + { + "group": "公開", + "expanded": false, + "pages": [ + "ja/use-dify/publish/README", + { + "group": "Webアプリ", + "icon": "globe", + "pages": [ + "ja/use-dify/publish/webapp/workflow-webapp", + "ja/use-dify/publish/webapp/chatflow-webapp", + "ja/use-dify/publish/webapp/web-app-settings", + "ja/use-dify/publish/webapp/web-app-access", + "ja/use-dify/publish/webapp/embedding-in-websites" + ] + }, + "ja/use-dify/publish/publish-mcp", + "ja/use-dify/publish/developing-with-apis" + ] + }, + { + "group": "モニタリング", + "expanded": false, + "pages": [ + "ja/use-dify/monitor/analysis", + "ja/use-dify/monitor/logs", + "ja/use-dify/monitor/annotation-reply", + { + "group": "インテグレーション", + "icon": "grid-2-plus", + "pages": [ + "ja/use-dify/monitor/integrations/integrate-langsmith", + "ja/use-dify/monitor/integrations/integrate-langfuse", + "ja/use-dify/monitor/integrations/integrate-arize", + "ja/use-dify/monitor/integrations/integrate-opik", + "ja/use-dify/monitor/integrations/integrate-phoenix", + "ja/use-dify/monitor/integrations/integrate-weave" + ] + } + ] + }, + { + "group": "ナレッジベース", + "expanded": false, + "pages": [ + "ja/use-dify/knowledge/readme", + { + "group": "作成手順", + "icon": "square-plus", + "pages": [ + "ja/use-dify/knowledge/create-knowledge/introduction", + { + "group": "1. テキストデータのインポート", + "pages": [ + "ja/use-dify/knowledge/create-knowledge/import-text-data/readme", + "ja/use-dify/knowledge/create-knowledge/import-text-data/sync-from-notion", + "ja/use-dify/knowledge/create-knowledge/import-text-data/sync-from-website" + ] + }, + "ja/use-dify/knowledge/create-knowledge/chunking-and-cleaning-text", + "ja/use-dify/knowledge/create-knowledge/setting-indexing-methods" + ] + }, + { + "group": "ナレッジパイプライン", + "icon": "pipe-section", + "pages": [ + "ja/use-dify/knowledge/knowledge-pipeline/readme", + "ja/use-dify/knowledge/knowledge-pipeline/create-knowledge-pipeline", + "ja/use-dify/knowledge/knowledge-pipeline/knowledge-pipeline-orchestration", + "ja/use-dify/knowledge/knowledge-pipeline/publish-knowledge-pipeline", + "ja/use-dify/knowledge/knowledge-pipeline/upload-files", + "ja/use-dify/knowledge/knowledge-pipeline/manage-knowledge-base", + "ja/use-dify/knowledge/knowledge-pipeline/authorize-data-source" + ] + }, + { + "group": "ナレッジベースの管理", + "icon": "gear", + "pages": [ + "ja/use-dify/knowledge/manage-knowledge/introduction", + "ja/use-dify/knowledge/manage-knowledge/maintain-knowledge-documents", + "ja/use-dify/knowledge/manage-knowledge/maintain-dataset-via-api" + ] + }, + "ja/use-dify/knowledge/metadata", + "ja/use-dify/knowledge/integrate-knowledge-within-application", + "ja/use-dify/knowledge/retrieval-test-and-citation", + "ja/use-dify/knowledge/knowledge-request-rate-limit", + "ja/use-dify/knowledge/connect-external-knowledge-base", + "ja/use-dify/knowledge/external-knowledge-api" + ] + }, + { + "group": "ワークスペース", + "expanded": false, + "pages": [ + "ja/use-dify/workspace/readme", + "ja/use-dify/workspace/model-providers", + "ja/use-dify/workspace/plugins", + "ja/use-dify/workspace/app-management", + "ja/use-dify/workspace/team-members-management", + "ja/use-dify/workspace/personal-account-management", + "ja/use-dify/workspace/subscription-management" + ] + }, + { + "group": "チュートリアル", + "expanded": false, + "pages": [ + "ja/use-dify/tutorials/twitter-chatflow", + "ja/use-dify/tutorials/customer-service-bot", + "ja/use-dify/tutorials/build-ai-image-generation-app", + "ja/use-dify/tutorials/article-reader" + ] + } + ] + } + ] + }, + { + "dropdown": "セルフホスティング", + "icon": "server", + "pages": [ + { + "group": "クイックスタート", + "pages": [ + "ja/self-host/quick-start/docker-compose", + "ja/self-host/quick-start/faqs" + ] + }, + { + "group": "高度なデプロイ", + "pages": [ + "ja/self-host/advanced-deployments/local-source-code", + "ja/self-host/advanced-deployments/start-the-frontend-docker-container" + ] + }, + { + "group": "設定", + "pages": [ + "ja/self-host/configuration/environments" + ] + }, + { + "group": "プラットフォームガイド", + "pages": [ + "ja/self-host/platform-guides/bt-panel", + "ja/self-host/platform-guides/dify-premium" + ] + }, + { + "group": "トラブルシューティング", + "pages": [ + "ja/self-host/troubleshooting/common-issues", + "ja/self-host/troubleshooting/docker-issues", + "ja/self-host/troubleshooting/integrations", + "ja/self-host/troubleshooting/storage-and-migration", + "ja/self-host/troubleshooting/weaviate-v4-migration" + ] + } + ] + }, + { + "dropdown": "APIアクセス", + "icon": "code", + "groups": [ + { + "group": "ChatbotとAgent", + "openapi": "ja/api-reference/openapi_chat.json" + }, + { + "group": "チャットフロー", + "openapi": "ja/api-reference/openapi_chatflow.json" + }, + { + "group": "ワークフロー", + "openapi": "ja/api-reference/openapi_workflow.json" + }, + { + "group": "ナレッジ", + "openapi": "ja/api-reference/openapi_knowledge.json" + }, + { + "group": "テキスト ジェネレーター", + "openapi": "ja/api-reference/openapi_completion.json" + } + ] + }, + { + "dropdown": "プラグイン開発", + "icon": "code-pull-request", + "groups": [ + { + "group": "はじめに", + "pages": [ + "ja/develop-plugin/getting-started/getting-started-dify-plugin", + "ja/develop-plugin/getting-started/cli" + ] + }, + { + "group": "特性と仕様", + "pages": [ + { + "group": "プラグインタイプ", + "pages": [ + "ja/develop-plugin/features-and-specs/plugin-types/general-specifications", + "ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules", + "ja/develop-plugin/features-and-specs/plugin-types/model-schema", + "ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv", + "ja/develop-plugin/features-and-specs/plugin-types/tool", + "ja/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest", + "ja/develop-plugin/features-and-specs/plugin-types/multilingual-readme", + "ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin" + ] + }, + { + "group": "高度な開発", + "pages": [ + { + "group": "リバース呼び出し", + "pages": [ + "ja/develop-plugin/features-and-specs/advanced-development/bundle", + "ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation", + "ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app", + "ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model", + "ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool", + "ja/develop-plugin/features-and-specs/advanced-development/customizable-model", + "ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node" + ] + } + ] + } + ] + }, + { + "group": "開発ガイドとサンプル", + "pages": [ + "ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet", + "ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin", + "ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth", + "ja/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin", + "ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin", + "ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider", + "ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin", + "ja/develop-plugin/dev-guides-and-walkthroughs/endpoint", + "ja/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin", + "ja/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter" + ] + }, + { + "group": "公開", + "pages": [ + { + "group": "標準", + "pages": [ + "ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct", + "ja/develop-plugin/publishing/standards/privacy-protection-guidelines", + "ja/develop-plugin/publishing/standards/third-party-signature-verification" + ] + }, + { + "group": "マーケットプレイスリスト", + "pages": [ + "ja/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr", + "ja/develop-plugin/publishing/marketplace-listing/release-overview", + "ja/develop-plugin/publishing/marketplace-listing/release-by-file", + "ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace", + "ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo" + ] + }, + { + "group": "よくある質問", + "pages": [ + "ja/develop-plugin/publishing/faq/faq" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "version": "3.3.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "versions/3-3-x/zh/user-guide/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/3-3-x/zh/user-guide/introduction", + { + "group": "接入大模型", + "pages": [ + "versions/3-0-x/zh/user-guide/model-configuration/readme", + "versions/3-0-x/zh/user-guide/model-configuration/new-provider", + "versions/3-0-x/zh/user-guide/model-configuration/predefined-model", + "versions/3-0-x/zh/user-guide/model-configuration/customizable-model", + "versions/3-0-x/zh/user-guide/model-configuration/interfaces", + "versions/3-0-x/zh/user-guide/model-configuration/schema", + "versions/3-0-x/zh/user-guide/model-configuration/load-balancing" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/readme", + "versions/3-0-x/zh/user-guide/application-orchestrate/creating-an-application", + { + "group": "聊天助手", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/chatbot-application", + "versions/3-0-x/zh/user-guide/application-orchestrate/multiple-llms-debugging" + ] + }, + "versions/3-0-x/zh/user-guide/application-orchestrate/agent", + { + "group": "应用工具箱", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/readme", + "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/moderation-tool" + ] + } + ] + }, + { + "group": "工作流", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/readme", + "versions/3-0-x/zh/user-guide/workflow/key-concept", + "versions/3-0-x/zh/user-guide/workflow/variables", + { + "group": "节点说明", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/node/start", + "versions/3-0-x/zh/user-guide/workflow/node/llm", + "versions/3-0-x/zh/user-guide/workflow/node/knowledge-retrieval", + "versions/3-0-x/zh/user-guide/workflow/node/question-classifier", + "versions/3-0-x/zh/user-guide/workflow/node/ifelse", + "versions/3-0-x/zh/user-guide/workflow/node/code", + "versions/3-0-x/zh/user-guide/workflow/node/template", + "versions/3-0-x/zh/user-guide/workflow/node/doc-extractor", + "versions/3-0-x/zh/user-guide/workflow/node/list-operator", + "versions/3-0-x/zh/user-guide/workflow/node/variable-aggregator", + "versions/3-0-x/zh/user-guide/workflow/node/variable-assigner", + "versions/3-0-x/zh/user-guide/workflow/node/iteration", + "versions/3-0-x/zh/user-guide/workflow/node/parameter-extractor", + "versions/3-0-x/zh/user-guide/workflow/node/http-request", + "versions/3-0-x/zh/user-guide/workflow/node/agent", + "versions/3-0-x/zh/user-guide/workflow/node/tools", + "versions/3-0-x/zh/user-guide/workflow/node/end", + "versions/3-0-x/zh/user-guide/workflow/node/answer", + "versions/3-0-x/zh/user-guide/workflow/node/loop" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/shortcut-key", + "versions/3-0-x/zh/user-guide/workflow/orchestrate-node", + "versions/3-0-x/zh/user-guide/workflow/file-upload", + { + "group": "异常处理", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/error-handling/readme", + "versions/3-0-x/zh/user-guide/workflow/error-handling/predefined-nodes-failure-logic", + "versions/3-0-x/zh/user-guide/workflow/error-handling/error-type" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/additional-feature", + { + "group": "预览与调试", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/history", + "versions/3-2-x/zh/user-guide/workflow/debug-and-preview/variable-inspect" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/publish", + "versions/3-0-x/zh/user-guide/workflow/structured-outputs", + "versions/3-0-x/zh/user-guide/workflow/bulletin" + ] + }, + { + "group": "知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/readme", + { + "group": "创建知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-base-creation/introduction", + { + "group": "1. 导入文本数据", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" + ] + }, + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" + ] + }, + { + "group": "从 Knowledge Pipeline 创建", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/readme", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/create-knowledge-pipeline", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/publish-knowledge-pipeline", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/upload-files", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/manage-knowledge-base", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/authorize-data-source" + ] + }, + { + "group": "管理知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" + ] + }, + "versions/3-0-x/zh/user-guide/knowledge-base/metadata", + "versions/3-0-x/zh/user-guide/knowledge-base/integrate-knowledge-within-application", + "versions/3-0-x/zh/user-guide/knowledge-base/retrieval-test-and-citation", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-request-rate-limit", + "versions/3-0-x/zh/user-guide/knowledge-base/connect-external-knowledge-base", + "versions/3-0-x/zh/user-guide/knowledge-base/api-documentation/external-knowledge-api-documentation" + ] + }, + { + "group": "工具", + "pages": [ + "versions/3-0-x/zh/user-guide/tools/readme", + "versions/3-3-x/zh/user-guide/tools/mcp", + "versions/3-0-x/zh/user-guide/tools/quick-tool-integration", + "versions/3-0-x/zh/user-guide/tools/advanced-tool-integration", + { + "group": "工具配置详情", + "pages": [ + "versions/3-0-x/zh/user-guide/tools/tool-configuration/google", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/bing", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/searchapi", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/stable-diffusion", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/dall-e", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/perplexity", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/alphavantage", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/searxng", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/serper", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/siliconflow", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/comfyui" + ] + } + ] + }, + { + "group": "发布", + "pages": [ + "versions/2-8-x/zh/user-guide/application-publishing/permission-management", + "versions/3-3-x/zh/user-guide/application-publishing/publish-mcp", + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/readme", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/3-0-x/zh/user-guide/application-publishing/embedding-in-websites", + "versions/3-0-x/zh/user-guide/application-publishing/developing-with-apis", + "versions/3-0-x/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "标注", + "pages": [ + "versions/3-0-x/zh/user-guide/annotation/logs", + "versions/3-0-x/zh/user-guide/annotation/annotation-reply" + ] + }, + { + "group": "监测", + "pages": [ + "versions/3-0-x/zh/user-guide/monitoring/README", + { + "group": "集成外部与 Ops 工具", + "pages": [ + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/readme", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" + ] + }, + "versions/3-0-x/zh/user-guide/monitoring/analysis" + ] + }, + { + "group": "管理", + "pages": [ + "versions/3-0-x/zh/user-guide/management/app-management", + "versions/3-0-x/zh/user-guide/management/team-members-management", + "versions/3-0-x/zh/user-guide/management/personal-account-management", + "versions/3-0-x/zh/user-guide/management/subscription-management", + "versions/3-0-x/zh/user-guide/management/version-control" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "versions/3-3-x/en/user-guide/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/3-3-x/en/user-guide/introduction", + { + "group": "Model Configuration", + "pages": [ + "versions/3-0-x/en/user-guide/model-configuration/readme", + "versions/3-0-x/en/user-guide/model-configuration/new-provider", + "versions/3-0-x/en/user-guide/model-configuration/predefined-model", + "versions/3-0-x/en/user-guide/model-configuration/customizable-model", + "versions/3-0-x/en/user-guide/model-configuration/interfaces", + "versions/3-0-x/en/user-guide/model-configuration/schema" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/3-0-x/en/user-guide/application-orchestrate/readme", + "versions/3-0-x/en/user-guide/application-orchestrate/creating-an-application", + "versions/3-0-x/en/user-guide/application-orchestrate/chatbot-application", + "versions/3-0-x/en/user-guide/application-orchestrate/multiple-llms-debugging", + "versions/3-0-x/en/user-guide/application-orchestrate/text-generator", + "versions/3-0-x/en/user-guide/application-orchestrate/agent", + { + "group": "Application Toolkits", + "pages": [ + "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/readme", + "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/moderation-tool" + ] + } + ] + }, + { + "group": "Workflow", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/README", + "versions/3-0-x/en/user-guide/workflow/key-concepts", + "versions/3-0-x/en/user-guide/workflow/variables", + { + "group": "Node Description", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/node/start", + "versions/3-0-x/en/user-guide/workflow/node/end", + "versions/3-0-x/en/user-guide/workflow/node/answer", + "versions/3-0-x/en/user-guide/workflow/node/llm", + "versions/3-0-x/en/user-guide/workflow/node/knowledge-retrieval", + "versions/3-0-x/en/user-guide/workflow/node/question-classifier", + "versions/3-0-x/en/user-guide/workflow/node/ifelse", + "versions/3-0-x/en/user-guide/workflow/node/code", + "versions/3-0-x/en/user-guide/workflow/node/template", + "versions/3-0-x/en/user-guide/workflow/node/doc-extractor", + "versions/3-0-x/en/user-guide/workflow/node/list-operator", + "versions/3-0-x/en/user-guide/workflow/node/variable-aggregator", + "versions/3-0-x/en/user-guide/workflow/node/variable-assigner", + "versions/3-0-x/en/user-guide/workflow/node/iteration", + "versions/3-0-x/en/user-guide/workflow/node/parameter-extractor", + "versions/3-0-x/en/user-guide/workflow/node/http-request", + "versions/3-0-x/en/user-guide/workflow/node/agent", + "versions/3-0-x/en/user-guide/workflow/node/tools", + "versions/3-0-x/en/user-guide/workflow/node/loop" + ] + }, + "versions/3-0-x/en/user-guide/workflow/shortcut-key", + "versions/3-0-x/en/user-guide/workflow/orchestrate-node", + "versions/3-0-x/en/user-guide/workflow/file-upload", + { + "group": "Error Handling", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/error-handling/README", + "versions/3-0-x/en/user-guide/workflow/error-handling/predefined-error-handling-logic", + "versions/3-0-x/en/user-guide/workflow/error-handling/error-type" + ] + }, + "versions/3-0-x/en/user-guide/workflow/additional-features", + { + "group": "Debug and Preview", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/history", + "versions/3-2-x/en/user-guide/workflow/debug-and-preview/variable-inspect" + ] + }, + "versions/3-0-x/en/user-guide/workflow/publish", + "versions/3-0-x/en/user-guide/workflow/structured-outputs" + ] + }, + { + "group": "Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/readme", + { + "group": "Create Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-base-creation/introduction", + { + "group": "1. Import Text Data", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" + ] + }, + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" + ] + }, + { + "group": "Manage Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" + ] + }, + "versions/3-0-x/en/user-guide/knowledge-base/metadata", + "versions/3-0-x/en/user-guide/knowledge-base/integrate-knowledge-within-application", + "versions/3-0-x/en/user-guide/knowledge-base/retrieval-test-and-citation", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-request-rate-limit", + "versions/3-0-x/en/user-guide/knowledge-base/connect-external-knowledge-base", + "versions/3-0-x/en/user-guide/knowledge-base/external-knowledge-api" + ] + }, + { + "group": "Tools", + "pages": [ + "versions/3-3-x/en/user-guide/tools/mcp" + ] + }, + { + "group": "Publishing", + "pages": [ + "versions/2-8-x/en/user-guide/application-publishing/permission-management", + "versions/3-3-x/en/user-guide/application-publishing/publish-mcp", + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/README", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/3-0-x/en/user-guide/application-publishing/embedding-in-websites", + "versions/3-0-x/en/user-guide/application-publishing/developing-with-apis", + "versions/3-0-x/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Annotation", + "pages": [ + "versions/3-0-x/en/user-guide/annotation/logs", + "versions/3-0-x/en/user-guide/annotation/annotation-reply" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/3-0-x/en/user-guide/monitoring/README", + "versions/3-0-x/en/user-guide/monitoring/analysis", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/README", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" + ] + } + ] + }, + { + "group": "Extensions", + "pages": [ + { + "group": "API-Based Extension", + "pages": [ + "versions/3-0-x/en/user-guide/extension/api-based-extension/README", + "versions/3-0-x/en/user-guide/extension/api-based-extension/external-data-tool", + "versions/3-0-x/en/user-guide/extension/api-based-extension/cloudflare-workers", + "versions/3-0-x/en/user-guide/extension/api-based-extension/moderation" + ] + }, + { + "group": "Code-Based Extension", + "pages": [ + "versions/3-0-x/en/user-guide/extension/code-based-extension/README", + "versions/3-0-x/en/user-guide/extension/code-based-extension/external-data-tool", + "versions/3-0-x/en/user-guide/extension/code-based-extension/moderation" + ] + } + ] + }, + { + "group": "Management", + "pages": [ + "versions/3-0-x/en/user-guide/management/app-management", + "versions/3-0-x/en/user-guide/management/team-members-management", + "versions/3-0-x/en/user-guide/management/personal-account-management", + "versions/3-0-x/en/user-guide/management/version-control" + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "versions/3-3-x/ja/user-guide/introduction", + "groups": [ + { + "group": "ユーザーマニュアル", + "pages": [ + "versions/3-3-x/ja/user-guide/introduction", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/history", + "versions/3-2-x/ja/user-guide/workflow/debug-and-preview/variable-inspect" + ] + } + ] + }, + { + "group": "ツール", + "pages": [ + "versions/3-3-x/ja/user-guide/tools/mcp" + ] + }, + { + "group": "アプリのリリース", + "pages": [ + "versions/2-8-x/ja/user-guide/application-publishing/permission-management", + "versions/3-3-x/ja/user-guide/application-publishing/publish-mcp", + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + }, + { + "group": "監視", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/analysis", + "versions/legacy/ja/user-guide/monitoring/logs", + "versions/legacy/ja/user-guide/monitoring/annotation-reply", + { + "group": "外部Opsツールの統合", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "version": "3.2.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "versions/3-2-x/zh/user-guide/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/3-2-x/zh/user-guide/introduction", + { + "group": "接入大模型", + "pages": [ + "versions/3-0-x/zh/user-guide/model-configuration/readme", + "versions/3-0-x/zh/user-guide/model-configuration/new-provider", + "versions/3-0-x/zh/user-guide/model-configuration/predefined-model", + "versions/3-0-x/zh/user-guide/model-configuration/customizable-model", + "versions/3-0-x/zh/user-guide/model-configuration/interfaces", + "versions/3-0-x/zh/user-guide/model-configuration/schema", + "versions/3-0-x/zh/user-guide/model-configuration/load-balancing", + "versions/3-0-x/zh/user-guide/model-configuration/manage-model-credential" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/readme", + "versions/3-0-x/zh/user-guide/application-orchestrate/creating-an-application", + { + "group": "聊天助手", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/chatbot-application", + "versions/3-0-x/zh/user-guide/application-orchestrate/multiple-llms-debugging" + ] + }, + "versions/3-0-x/zh/user-guide/application-orchestrate/agent", + { + "group": "应用工具箱", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/readme", + "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/moderation-tool" + ] + } + ] + }, + { + "group": "工作流", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/readme", + "versions/3-0-x/zh/user-guide/workflow/key-concept", + "versions/3-0-x/zh/user-guide/workflow/variables", + { + "group": "节点说明", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/node/start", + "versions/3-0-x/zh/user-guide/workflow/node/llm", + "versions/3-0-x/zh/user-guide/workflow/node/knowledge-retrieval", + "versions/3-0-x/zh/user-guide/workflow/node/question-classifier", + "versions/3-0-x/zh/user-guide/workflow/node/ifelse", + "versions/3-0-x/zh/user-guide/workflow/node/code", + "versions/3-0-x/zh/user-guide/workflow/node/template", + "versions/3-0-x/zh/user-guide/workflow/node/doc-extractor", + "versions/3-0-x/zh/user-guide/workflow/node/list-operator", + "versions/3-0-x/zh/user-guide/workflow/node/variable-aggregator", + "versions/3-0-x/zh/user-guide/workflow/node/variable-assigner", + "versions/3-0-x/zh/user-guide/workflow/node/iteration", + "versions/3-0-x/zh/user-guide/workflow/node/parameter-extractor", + "versions/3-0-x/zh/user-guide/workflow/node/http-request", + "versions/3-0-x/zh/user-guide/workflow/node/agent", + "versions/3-0-x/zh/user-guide/workflow/node/tools", + "versions/3-0-x/zh/user-guide/workflow/node/end", + "versions/3-0-x/zh/user-guide/workflow/node/answer", + "versions/3-0-x/zh/user-guide/workflow/node/loop" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/shortcut-key", + "versions/3-0-x/zh/user-guide/workflow/orchestrate-node", + "versions/3-0-x/zh/user-guide/workflow/file-upload", + { + "group": "异常处理", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/error-handling/readme", + "versions/3-0-x/zh/user-guide/workflow/error-handling/predefined-nodes-failure-logic", + "versions/3-0-x/zh/user-guide/workflow/error-handling/error-type" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/additional-feature", + { + "group": "预览与调试", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/history", + "versions/3-2-x/zh/user-guide/workflow/debug-and-preview/variable-inspect" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/publish", + "versions/3-0-x/zh/user-guide/workflow/structured-outputs", + "versions/3-0-x/zh/user-guide/workflow/bulletin" + ] + }, + { + "group": "知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/readme", + { + "group": "创建知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-base-creation/introduction", + { + "group": "1. 导入文本数据", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" + ] + }, + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" + ] + }, + { + "group": "管理知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" + ] + }, + "versions/3-0-x/zh/user-guide/knowledge-base/metadata", + "versions/3-0-x/zh/user-guide/knowledge-base/integrate-knowledge-within-application", + "versions/3-0-x/zh/user-guide/knowledge-base/retrieval-test-and-citation", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-request-rate-limit", + "versions/3-0-x/zh/user-guide/knowledge-base/connect-external-knowledge-base", + "versions/3-0-x/zh/user-guide/knowledge-base/api-documentation/external-knowledge-api-documentation" + ] + }, + { + "group": "工具", + "pages": [ + "versions/3-0-x/zh/user-guide/tools/readme", + "versions/3-0-x/zh/user-guide/tools/quick-tool-integration", + "versions/3-0-x/zh/user-guide/tools/advanced-tool-integration", + { + "group": "工具配置详情", + "pages": [ + "versions/3-0-x/zh/user-guide/tools/tool-configuration/google", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/bing", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/searchapi", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/stable-diffusion", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/dall-e", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/perplexity", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/alphavantage", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/searxng", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/serper", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/siliconflow", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/comfyui" + ] + } + ] + }, + { + "group": "发布", + "pages": [ + "versions/2-8-x/zh/user-guide/application-publishing/permission-management", + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/readme", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/3-0-x/zh/user-guide/application-publishing/embedding-in-websites", + "versions/3-0-x/zh/user-guide/application-publishing/developing-with-apis", + "versions/3-0-x/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "标注", + "pages": [ + "versions/3-0-x/zh/user-guide/annotation/logs", + "versions/3-0-x/zh/user-guide/annotation/annotation-reply" + ] + }, + { + "group": "监测", + "pages": [ + "versions/3-0-x/zh/user-guide/monitoring/README", + { + "group": "集成外部与 Ops 工具", + "pages": [ + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/readme", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" + ] + }, + "versions/3-0-x/zh/user-guide/monitoring/analysis" + ] + }, + { + "group": "管理", + "pages": [ + "versions/3-0-x/zh/user-guide/management/app-management", + "versions/3-0-x/zh/user-guide/management/team-members-management", + "versions/3-0-x/zh/user-guide/management/personal-account-management", + "versions/3-0-x/zh/user-guide/management/subscription-management", + "versions/3-0-x/zh/user-guide/management/version-control" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "versions/3-2-x/en/user-guide/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/3-2-x/en/user-guide/introduction", + { + "group": "Model Configuration", + "pages": [ + "versions/3-0-x/en/user-guide/model-configuration/readme", + "versions/3-0-x/en/user-guide/model-configuration/new-provider", + "versions/3-0-x/en/user-guide/model-configuration/predefined-model", + "versions/3-0-x/en/user-guide/model-configuration/customizable-model", + "versions/3-0-x/en/user-guide/model-configuration/interfaces", + "versions/3-0-x/en/user-guide/model-configuration/schema", + "versions/3-0-x/en/user-guide/model-configuration/manage-model-credential" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/3-0-x/en/user-guide/application-orchestrate/readme", + "versions/3-0-x/en/user-guide/application-orchestrate/creating-an-application", + "versions/3-0-x/en/user-guide/application-orchestrate/chatbot-application", + "versions/3-0-x/en/user-guide/application-orchestrate/multiple-llms-debugging", + "versions/3-0-x/en/user-guide/application-orchestrate/text-generator", + "versions/3-0-x/en/user-guide/application-orchestrate/agent", + { + "group": "Application Toolkits", + "pages": [ + "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/readme", + "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/moderation-tool" + ] + } + ] + }, + { + "group": "Workflow", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/README", + "versions/3-0-x/en/user-guide/workflow/key-concepts", + "versions/3-0-x/en/user-guide/workflow/variables", + { + "group": "Node Description", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/node/start", + "versions/3-0-x/en/user-guide/workflow/node/end", + "versions/3-0-x/en/user-guide/workflow/node/answer", + "versions/3-0-x/en/user-guide/workflow/node/llm", + "versions/3-0-x/en/user-guide/workflow/node/knowledge-retrieval", + "versions/3-0-x/en/user-guide/workflow/node/question-classifier", + "versions/3-0-x/en/user-guide/workflow/node/ifelse", + "versions/3-0-x/en/user-guide/workflow/node/code", + "versions/3-0-x/en/user-guide/workflow/node/template", + "versions/3-0-x/en/user-guide/workflow/node/doc-extractor", + "versions/3-0-x/en/user-guide/workflow/node/list-operator", + "versions/3-0-x/en/user-guide/workflow/node/variable-aggregator", + "versions/3-0-x/en/user-guide/workflow/node/variable-assigner", + "versions/3-0-x/en/user-guide/workflow/node/iteration", + "versions/3-0-x/en/user-guide/workflow/node/parameter-extractor", + "versions/3-0-x/en/user-guide/workflow/node/http-request", + "versions/3-0-x/en/user-guide/workflow/node/agent", + "versions/3-0-x/en/user-guide/workflow/node/tools", + "versions/3-0-x/en/user-guide/workflow/node/loop" + ] + }, + "versions/3-0-x/en/user-guide/workflow/shortcut-key", + "versions/3-0-x/en/user-guide/workflow/orchestrate-node", + "versions/3-0-x/en/user-guide/workflow/file-upload", + { + "group": "Error Handling", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/error-handling/README", + "versions/3-0-x/en/user-guide/workflow/error-handling/predefined-error-handling-logic", + "versions/3-0-x/en/user-guide/workflow/error-handling/error-type" + ] + }, + "versions/3-0-x/en/user-guide/workflow/additional-features", + { + "group": "Debug and Preview", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/history", + "versions/3-2-x/en/user-guide/workflow/debug-and-preview/variable-inspect" + ] + }, + "versions/3-0-x/en/user-guide/workflow/publish", + "versions/3-0-x/en/user-guide/workflow/structured-outputs" + ] + }, + { + "group": "Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/readme", + { + "group": "Create Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-base-creation/introduction", + { + "group": "1. Import Text Data", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" + ] + }, + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" + ] + }, + { + "group": "Manage Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" + ] + }, + "versions/3-0-x/en/user-guide/knowledge-base/metadata", + "versions/3-0-x/en/user-guide/knowledge-base/integrate-knowledge-within-application", + "versions/3-0-x/en/user-guide/knowledge-base/retrieval-test-and-citation", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-request-rate-limit", + "versions/3-0-x/en/user-guide/knowledge-base/connect-external-knowledge-base", + "versions/3-0-x/en/user-guide/knowledge-base/external-knowledge-api" + ] + }, + { + "group": "Publishing", + "pages": [ + "versions/2-8-x/en/user-guide/application-publishing/permission-management", + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/README", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/3-0-x/en/user-guide/application-publishing/embedding-in-websites", + "versions/3-0-x/en/user-guide/application-publishing/developing-with-apis", + "versions/3-0-x/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Annotation", + "pages": [ + "versions/3-0-x/en/user-guide/annotation/logs", + "versions/3-0-x/en/user-guide/annotation/annotation-reply" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/3-0-x/en/user-guide/monitoring/README", + "versions/3-0-x/en/user-guide/monitoring/analysis", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/README", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" + ] + } + ] + }, + { + "group": "Extensions", + "pages": [ + { + "group": "API-Based Extension", + "pages": [ + "versions/3-0-x/en/user-guide/extension/api-based-extension/README", + "versions/3-0-x/en/user-guide/extension/api-based-extension/external-data-tool", + "versions/3-0-x/en/user-guide/extension/api-based-extension/cloudflare-workers", + "versions/3-0-x/en/user-guide/extension/api-based-extension/moderation" + ] + }, + { + "group": "Code-Based Extension", + "pages": [ + "versions/3-0-x/en/user-guide/extension/code-based-extension/README", + "versions/3-0-x/en/user-guide/extension/code-based-extension/external-data-tool", + "versions/3-0-x/en/user-guide/extension/code-based-extension/moderation" + ] + } + ] + }, + { + "group": "Management", + "pages": [ + "versions/3-0-x/en/user-guide/management/app-management", + "versions/3-0-x/en/user-guide/management/team-members-management", + "versions/3-0-x/en/user-guide/management/personal-account-management", + "versions/3-0-x/en/user-guide/management/version-control" + ] + } + ] + } + ] + }, + { + "language": "ja", + "default": true, + "href": "versions/3-2-x/ja/user-guide/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/3-2-x/ja/user-guide/introduction", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/history", + "versions/3-2-x/ja/user-guide/workflow/debug-and-preview/variable-inspect" + ] + } + ] + }, + { + "group": "アプリのリリース", + "pages": [ + "versions/2-8-x/ja/user-guide/application-publishing/permission-management", + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + }, + { + "group": "監視", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/analysis", + "versions/legacy/ja/user-guide/monitoring/logs", + "versions/legacy/ja/user-guide/monitoring/annotation-reply", + { + "group": "外部Opsツールの統合", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "version": "3.0.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "versions/3-0-x/zh/user-guide/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/3-0-x/zh/user-guide/introduction", + { + "group": "接入大模型", + "pages": [ + "versions/3-0-x/zh/user-guide/model-configuration/readme", + "versions/3-0-x/zh/user-guide/model-configuration/new-provider", + "versions/3-0-x/zh/user-guide/model-configuration/predefined-model", + "versions/3-0-x/zh/user-guide/model-configuration/customizable-model", + "versions/3-0-x/zh/user-guide/model-configuration/interfaces", + "versions/3-0-x/zh/user-guide/model-configuration/schema", + "versions/3-0-x/zh/user-guide/model-configuration/load-balancing" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/readme", + "versions/3-0-x/zh/user-guide/application-orchestrate/creating-an-application", + { + "group": "聊天助手", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/chatbot-application", + "versions/3-0-x/zh/user-guide/application-orchestrate/multiple-llms-debugging" + ] + }, + "versions/3-0-x/zh/user-guide/application-orchestrate/agent", + { + "group": "应用工具箱", + "pages": [ + "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/readme", + "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/moderation-tool" + ] + } + ] + }, + { + "group": "工作流", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/readme", + "versions/3-0-x/zh/user-guide/workflow/key-concept", + "versions/3-0-x/zh/user-guide/workflow/variables", + { + "group": "节点说明", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/node/start", + "versions/3-0-x/zh/user-guide/workflow/node/llm", + "versions/3-0-x/zh/user-guide/workflow/node/knowledge-retrieval", + "versions/3-0-x/zh/user-guide/workflow/node/question-classifier", + "versions/3-0-x/zh/user-guide/workflow/node/ifelse", + "versions/3-0-x/zh/user-guide/workflow/node/code", + "versions/3-0-x/zh/user-guide/workflow/node/template", + "versions/3-0-x/zh/user-guide/workflow/node/doc-extractor", + "versions/3-0-x/zh/user-guide/workflow/node/list-operator", + "versions/3-0-x/zh/user-guide/workflow/node/variable-aggregator", + "versions/3-0-x/zh/user-guide/workflow/node/variable-assigner", + "versions/3-0-x/zh/user-guide/workflow/node/iteration", + "versions/3-0-x/zh/user-guide/workflow/node/parameter-extractor", + "versions/3-0-x/zh/user-guide/workflow/node/http-request", + "versions/3-0-x/zh/user-guide/workflow/node/agent", + "versions/3-0-x/zh/user-guide/workflow/node/tools", + "versions/3-0-x/zh/user-guide/workflow/node/end", + "versions/3-0-x/zh/user-guide/workflow/node/answer", + "versions/3-0-x/zh/user-guide/workflow/node/loop" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/shortcut-key", + "versions/3-0-x/zh/user-guide/workflow/orchestrate-node", + "versions/3-0-x/zh/user-guide/workflow/file-upload", + { + "group": "异常处理", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/error-handling/readme", + "versions/3-0-x/zh/user-guide/workflow/error-handling/predefined-nodes-failure-logic", + "versions/3-0-x/zh/user-guide/workflow/error-handling/error-type" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/additional-feature", + { + "group": "预览与调试", + "pages": [ + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/step-run" + ] + }, + "versions/3-0-x/zh/user-guide/workflow/publish", + "versions/3-0-x/zh/user-guide/workflow/structured-outputs", + "versions/3-0-x/zh/user-guide/workflow/bulletin" + ] + }, + { + "group": "知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/readme", + { + "group": "创建知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-base-creation/introduction", + { + "group": "1. 导入文本数据", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" + ] + }, + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", + "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" + ] + }, + { + "group": "管理知识库", + "pages": [ + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" + ] + }, + "versions/3-0-x/zh/user-guide/knowledge-base/metadata", + "versions/3-0-x/zh/user-guide/knowledge-base/integrate-knowledge-within-application", + "versions/3-0-x/zh/user-guide/knowledge-base/retrieval-test-and-citation", + "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-request-rate-limit", + "versions/3-0-x/zh/user-guide/knowledge-base/connect-external-knowledge-base", + "versions/3-0-x/zh/user-guide/knowledge-base/api-documentation/external-knowledge-api-documentation" + ] + }, + { + "group": "工具", + "pages": [ + "versions/3-0-x/zh/user-guide/tools/readme", + "versions/3-0-x/zh/user-guide/tools/quick-tool-integration", + "versions/3-0-x/zh/user-guide/tools/advanced-tool-integration", + { + "group": "工具配置详情", + "pages": [ + "versions/3-0-x/zh/user-guide/tools/tool-configuration/google", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/bing", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/searchapi", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/stable-diffusion", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/dall-e", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/perplexity", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/alphavantage", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/searxng", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/serper", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/siliconflow", + "versions/3-0-x/zh/user-guide/tools/tool-configuration/comfyui" + ] + } + ] + }, + { + "group": "发布", + "pages": [ + "versions/2-8-x/zh/user-guide/application-publishing/permission-management", + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/readme", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/3-0-x/zh/user-guide/application-publishing/embedding-in-websites", + "versions/3-0-x/zh/user-guide/application-publishing/developing-with-apis", + "versions/3-0-x/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "标注", + "pages": [ + "versions/3-0-x/zh/user-guide/annotation/logs", + "versions/3-0-x/zh/user-guide/annotation/annotation-reply" + ] + }, + { + "group": "监测", + "pages": [ + "versions/3-0-x/zh/user-guide/monitoring/README", + { + "group": "集成外部与 Ops 工具", + "pages": [ + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/readme", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-weave", + "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-aliyun" + ] + }, + "versions/3-0-x/zh/user-guide/monitoring/analysis" + ] + }, + { + "group": "管理", + "pages": [ + "versions/3-0-x/zh/user-guide/management/app-management", + "versions/3-0-x/zh/user-guide/management/team-members-management", + "versions/3-0-x/zh/user-guide/management/personal-account-management", + "versions/3-0-x/zh/user-guide/management/subscription-management", + "versions/3-0-x/zh/user-guide/management/version-control" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "versions/3-0-x/en/user-guide/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/3-0-x/en/user-guide/introduction", + { + "group": "Model Configuration", + "pages": [ + "versions/3-0-x/en/user-guide/model-configuration/readme", + "versions/3-0-x/en/user-guide/model-configuration/new-provider", + "versions/3-0-x/en/user-guide/model-configuration/predefined-model", + "versions/3-0-x/en/user-guide/model-configuration/customizable-model", + "versions/3-0-x/en/user-guide/model-configuration/interfaces", + "versions/3-0-x/en/user-guide/model-configuration/schema" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/3-0-x/en/user-guide/application-orchestrate/readme", + "versions/3-0-x/en/user-guide/application-orchestrate/creating-an-application", + "versions/3-0-x/en/user-guide/application-orchestrate/chatbot-application", + "versions/3-0-x/en/user-guide/application-orchestrate/multiple-llms-debugging", + "versions/3-0-x/en/user-guide/application-orchestrate/text-generator", + "versions/3-0-x/en/user-guide/application-orchestrate/agent", + { + "group": "Application Toolkits", + "pages": [ + "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/readme", + "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/moderation-tool" + ] + } + ] + }, + { + "group": "Workflow", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/README", + "versions/3-0-x/en/user-guide/workflow/key-concepts", + "versions/3-0-x/en/user-guide/workflow/variables", + { + "group": "Node Description", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/node/start", + "versions/3-0-x/en/user-guide/workflow/node/end", + "versions/3-0-x/en/user-guide/workflow/node/answer", + "versions/3-0-x/en/user-guide/workflow/node/llm", + "versions/3-0-x/en/user-guide/workflow/node/knowledge-retrieval", + "versions/3-0-x/en/user-guide/workflow/node/question-classifier", + "versions/3-0-x/en/user-guide/workflow/node/ifelse", + "versions/3-0-x/en/user-guide/workflow/node/code", + "versions/3-0-x/en/user-guide/workflow/node/template", + "versions/3-0-x/en/user-guide/workflow/node/doc-extractor", + "versions/3-0-x/en/user-guide/workflow/node/list-operator", + "versions/3-0-x/en/user-guide/workflow/node/variable-aggregator", + "versions/3-0-x/en/user-guide/workflow/node/variable-assigner", + "versions/3-0-x/en/user-guide/workflow/node/iteration", + "versions/3-0-x/en/user-guide/workflow/node/parameter-extractor", + "versions/3-0-x/en/user-guide/workflow/node/http-request", + "versions/3-0-x/en/user-guide/workflow/node/agent", + "versions/3-0-x/en/user-guide/workflow/node/tools", + "versions/3-0-x/en/user-guide/workflow/node/loop" + ] + }, + "versions/3-0-x/en/user-guide/workflow/shortcut-key", + "versions/3-0-x/en/user-guide/workflow/orchestrate-node", + "versions/3-0-x/en/user-guide/workflow/file-upload", + { + "group": "Error Handling", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/error-handling/README", + "versions/3-0-x/en/user-guide/workflow/error-handling/predefined-error-handling-logic", + "versions/3-0-x/en/user-guide/workflow/error-handling/error-type" + ] + }, + "versions/3-0-x/en/user-guide/workflow/additional-features", + { + "group": "Debug and Preview", + "pages": [ + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/preview-and-run", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/step-run", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/log", + "versions/3-0-x/en/user-guide/workflow/debug-and-preview/history" + ] + }, + "versions/3-0-x/en/user-guide/workflow/publish", + "versions/3-0-x/en/user-guide/workflow/structured-outputs" + ] + }, + { + "group": "Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/readme", + { + "group": "Create Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-base-creation/introduction", + { + "group": "1. Import Text Data", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" + ] + }, + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", + "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" + ] + }, + { + "group": "Manage Knowledge", + "pages": [ + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" + ] + }, + "versions/3-0-x/en/user-guide/knowledge-base/metadata", + "versions/3-0-x/en/user-guide/knowledge-base/integrate-knowledge-within-application", + "versions/3-0-x/en/user-guide/knowledge-base/retrieval-test-and-citation", + "versions/3-0-x/en/user-guide/knowledge-base/knowledge-request-rate-limit", + "versions/3-0-x/en/user-guide/knowledge-base/connect-external-knowledge-base", + "versions/3-0-x/en/user-guide/knowledge-base/external-knowledge-api" + ] + }, + { + "group": "Publishing", + "pages": [ + "versions/2-8-x/en/user-guide/application-publishing/permission-management", + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/README", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/3-0-x/en/user-guide/application-publishing/embedding-in-websites", + "versions/3-0-x/en/user-guide/application-publishing/developing-with-apis", + "versions/3-0-x/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Annotation", + "pages": [ + "versions/3-0-x/en/user-guide/annotation/logs", + "versions/3-0-x/en/user-guide/annotation/annotation-reply" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/3-0-x/en/user-guide/monitoring/README", + "versions/3-0-x/en/user-guide/monitoring/analysis", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/README", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", + "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" + ] + } + ] + }, + { + "group": "Extensions", + "pages": [ + { + "group": "API-Based Extension", + "pages": [ + "versions/3-0-x/en/user-guide/extension/api-based-extension/README", + "versions/3-0-x/en/user-guide/extension/api-based-extension/external-data-tool", + "versions/3-0-x/en/user-guide/extension/api-based-extension/cloudflare-workers", + "versions/3-0-x/en/user-guide/extension/api-based-extension/moderation" + ] + }, + { + "group": "Code-Based Extension", + "pages": [ + "versions/3-0-x/en/user-guide/extension/code-based-extension/README", + "versions/3-0-x/en/user-guide/extension/code-based-extension/external-data-tool", + "versions/3-0-x/en/user-guide/extension/code-based-extension/moderation" + ] + } + ] + }, + { + "group": "Management", + "pages": [ + "versions/3-0-x/en/user-guide/management/app-management", + "versions/3-0-x/en/user-guide/management/team-members-management", + "versions/3-0-x/en/user-guide/management/personal-account-management", + "versions/3-0-x/en/user-guide/management/version-control" + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "versions/3-0-x/ja/user-guide/introduction", + "groups": [ + { + "group": "ユーザーマニュアル", + "pages": [ + "versions/3-0-x/ja/user-guide/introduction", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "アプリのリリース", + "pages": [ + "versions/2-8-x/ja/user-guide/application-publishing/permission-management", + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + }, + { + "group": "監視", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/analysis", + "versions/legacy/ja/user-guide/monitoring/logs", + "versions/legacy/ja/user-guide/monitoring/annotation-reply", + { + "group": "外部Opsツールの統合", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "version": "2.8.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "/zh/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/legacy/zh/user-guide/welcome", + { + "group": "接入模型", + "pages": [ + "versions/legacy/zh/user-guide/models/model-configuration", + "versions/legacy/zh/user-guide/models/new-provider", + "versions/legacy/zh/user-guide/models/predefined-model", + "versions/legacy/zh/user-guide/models/customizable-model", + "versions/legacy/zh/user-guide/models/interfaces", + "versions/legacy/zh/user-guide/models/schema", + "versions/legacy/zh/user-guide/models/load-balancing" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/legacy/zh/user-guide/build-app/chatbot", + "versions/legacy/zh/user-guide/build-app/text-generator", + "versions/legacy/zh/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/concepts", + "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/zh/user-guide/build-app/flow-app/variables", + { + "group": "节点说明", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", + "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "调试应用", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "发布应用", + "pages": [ + "versions/2-8-x/zh/user-guide/application-publishing/permission-management", + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", + "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/zh/user-guide/management/app-management", + "versions/legacy/zh/user-guide/management/team-members-management", + "versions/legacy/zh/user-guide/management/personal-account-management" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "/en/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/legacy/en/user-guide/welcome", + { + "group": "Model", + "pages": [ + "versions/legacy/en/user-guide/models/model-configuration", + "versions/legacy/en/user-guide/models/new-provider", + "versions/legacy/en/user-guide/models/predefined-model", + "versions/legacy/en/user-guide/models/customizable-model", + "versions/legacy/en/user-guide/models/interfaces", + "versions/legacy/en/user-guide/models/schema", + "versions/legacy/en/user-guide/models/load-balancing" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/legacy/en/user-guide/build-app/chatbot", + "versions/legacy/en/user-guide/build-app/text-generator", + "versions/legacy/en/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/concepts", + "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/en/user-guide/build-app/flow-app/variables", + { + "group": "Nodes", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", + "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/en/user-guide/build-app/flow-app/file-upload", + "versions/legacy/en/user-guide/build-app/flow-app/additional-features" + ] + } + ] + }, + { + "group": "Debug and Preview", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "Application Publishing", + "pages": [ + "versions/2-8-x/en/user-guide/application-publishing/permission-management", + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/en/user-guide/application-publishing/developing-with-apis", + "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Management", + "pages": [ + "versions/legacy/en/user-guide/management/app-management", + "versions/legacy/en/user-guide/management/team-members-management", + "versions/legacy/en/user-guide/management/personal-account-management" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/legacy/en/user-guide/monitoring/analysis", + "versions/legacy/en/user-guide/monitoring/logs", + "versions/legacy/en/user-guide/monitoring/annotation-reply", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "/ja/introduction", + "groups": [ + { + "group": "ユーザーマニュアル", + "pages": [ + "versions/legacy/ja/user-guide/welcome", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "アプリのリリース", + "pages": [ + "versions/2-8-x/ja/user-guide/application-publishing/permission-management", + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + }, + { + "group": "監視", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/analysis", + "versions/legacy/ja/user-guide/monitoring/logs", + "versions/legacy/ja/user-guide/monitoring/annotation-reply", + { + "group": "外部Opsツールの統合", + "pages": [ + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "version": "2.7.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "/zh/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/legacy/zh/user-guide/welcome", + { + "group": "接入模型", + "pages": [ + "versions/legacy/zh/user-guide/models/model-configuration", + "versions/legacy/zh/user-guide/models/new-provider", + "versions/legacy/zh/user-guide/models/predefined-model", + "versions/legacy/zh/user-guide/models/customizable-model", + "versions/legacy/zh/user-guide/models/interfaces", + "versions/legacy/zh/user-guide/models/schema", + "versions/legacy/zh/user-guide/models/load-balancing" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/legacy/zh/user-guide/build-app/chatbot", + "versions/legacy/zh/user-guide/build-app/text-generator", + "versions/legacy/zh/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/concepts", + "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/zh/user-guide/build-app/flow-app/variables", + { + "group": "节点说明", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", + "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "调试应用", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "发布应用", + "pages": [ + "versions/legacy/zh/user-guide/application-publishing/permission-management", + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", + "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/zh/user-guide/management/app-management", + "versions/legacy/zh/user-guide/management/team-members-management", + "versions/legacy/zh/user-guide/management/personal-account-management" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "/en/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/legacy/en/user-guide/welcome", + { + "group": "Model", + "pages": [ + "versions/legacy/en/user-guide/models/model-configuration", + "versions/legacy/en/user-guide/models/new-provider", + "versions/legacy/en/user-guide/models/predefined-model", + "versions/legacy/en/user-guide/models/customizable-model", + "versions/legacy/en/user-guide/models/interfaces", + "versions/legacy/en/user-guide/models/schema", + "versions/legacy/en/user-guide/models/load-balancing" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/legacy/en/user-guide/build-app/chatbot", + "versions/legacy/en/user-guide/build-app/text-generator", + "versions/legacy/en/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/concepts", + "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/en/user-guide/build-app/flow-app/variables", + { + "group": "Nodes", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", + "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/en/user-guide/build-app/flow-app/file-upload", + "versions/legacy/en/user-guide/build-app/flow-app/additional-features" + ] + } + ] + }, + { + "group": "Debug and Preview", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "Application Publishing", + "pages": [ + "versions/legacy/en/user-guide/application-publishing/permission-management", + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/en/user-guide/application-publishing/developing-with-apis", + "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Management", + "pages": [ + "versions/legacy/en/user-guide/management/app-management", + "versions/legacy/en/user-guide/management/team-members-management", + "versions/legacy/en/user-guide/management/personal-account-management" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/legacy/en/user-guide/monitoring/analysis", + "versions/legacy/en/user-guide/monitoring/logs", + "versions/legacy/en/user-guide/monitoring/annotation-reply", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "/ja/introduction", + "groups": [ + { + "group": "ユーザーマニュアル", + "pages": [ + "versions/legacy/ja/user-guide/welcome", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "アプリのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/permission-management", + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + } + ] + } + ] + } + ] + }, + { + "version": "2.6.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "/zh/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/legacy/zh/user-guide/welcome", + { + "group": "接入模型", + "pages": [ + "versions/legacy/zh/user-guide/models/model-configuration", + "versions/legacy/zh/user-guide/models/new-provider", + "versions/legacy/zh/user-guide/models/predefined-model", + "versions/legacy/zh/user-guide/models/customizable-model", + "versions/legacy/zh/user-guide/models/interfaces", + "versions/legacy/zh/user-guide/models/schema", + "versions/legacy/zh/user-guide/models/load-balancing" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/legacy/zh/user-guide/build-app/chatbot", + "versions/legacy/zh/user-guide/build-app/text-generator", + "versions/legacy/zh/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/concepts", + "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/zh/user-guide/build-app/flow-app/variables", + { + "group": "节点说明", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", + "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "调试应用", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "发布应用", + "pages": [ + "versions/legacy/zh/user-guide/application-publishing/permission-management", + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", + "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/zh/user-guide/management/app-management", + "versions/legacy/zh/user-guide/management/team-members-management", + "versions/legacy/zh/user-guide/management/personal-account-management" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "/en/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/legacy/en/user-guide/welcome", + { + "group": "Model", + "pages": [ + "versions/legacy/en/user-guide/models/model-configuration", + "versions/legacy/en/user-guide/models/new-provider", + "versions/legacy/en/user-guide/models/predefined-model", + "versions/legacy/en/user-guide/models/customizable-model", + "versions/legacy/en/user-guide/models/interfaces", + "versions/legacy/en/user-guide/models/schema", + "versions/legacy/en/user-guide/models/load-balancing" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/legacy/en/user-guide/build-app/chatbot", + "versions/legacy/en/user-guide/build-app/text-generator", + "versions/legacy/en/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/concepts", + "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/en/user-guide/build-app/flow-app/variables", + { + "group": "Nodes", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", + "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/en/user-guide/build-app/flow-app/file-upload", + "versions/legacy/en/user-guide/build-app/flow-app/additional-features" + ] + } + ] + }, + { + "group": "Debug and Preview", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "Application Publishing", + "pages": [ + "versions/legacy/en/user-guide/application-publishing/permission-management", + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/en/user-guide/application-publishing/developing-with-apis", + "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Management", + "pages": [ + "versions/legacy/en/user-guide/management/app-management", + "versions/legacy/en/user-guide/management/team-members-management", + "versions/legacy/en/user-guide/management/personal-account-management" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/legacy/en/user-guide/monitoring/analysis", + "versions/legacy/en/user-guide/monitoring/logs", + "versions/legacy/en/user-guide/monitoring/annotation-reply", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "/ja/introduction", + "groups": [ + { + "group": "ユーザーマニュアル", + "pages": [ + "versions/legacy/ja/user-guide/welcome", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "アプリのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/permission-management", + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + } + ] + } + ] + } + ] + }, + { + "version": "2.5.x (Enterprise)", + "languages": [ + { + "language": "zh", + "href": "/zh/introduction", + "groups": [ + { + "group": "用户手册", + "pages": [ + "versions/legacy/zh/user-guide/welcome", + { + "group": "接入模型", + "pages": [ + "versions/legacy/zh/user-guide/models/model-configuration", + "versions/legacy/zh/user-guide/models/new-provider", + "versions/legacy/zh/user-guide/models/predefined-model", + "versions/legacy/zh/user-guide/models/customizable-model", + "versions/legacy/zh/user-guide/models/interfaces", + "versions/legacy/zh/user-guide/models/schema", + "versions/legacy/zh/user-guide/models/load-balancing" + ] + }, + { + "group": "构建应用", + "pages": [ + "versions/legacy/zh/user-guide/build-app/chatbot", + "versions/legacy/zh/user-guide/build-app/text-generator", + "versions/legacy/zh/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/concepts", + "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/zh/user-guide/build-app/flow-app/variables", + { + "group": "节点说明", + "pages": [ + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", + "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "调试应用", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "发布应用", + "pages": [ + { + "group": "发布为公开 Web 站点", + "pages": [ + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", + "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/zh/user-guide/management/app-management", + "versions/legacy/zh/user-guide/management/team-members-management", + "versions/legacy/zh/user-guide/management/personal-account-management" + ] + } + ] + } + ] + }, + { + "language": "en", + "default": true, + "href": "/en/introduction", + "groups": [ + { + "group": "User Guide", + "pages": [ + "versions/legacy/en/user-guide/welcome", + { + "group": "Model", + "pages": [ + "versions/legacy/en/user-guide/models/model-configuration", + "versions/legacy/en/user-guide/models/new-provider", + "versions/legacy/en/user-guide/models/predefined-model", + "versions/legacy/en/user-guide/models/customizable-model", + "versions/legacy/en/user-guide/models/interfaces", + "versions/legacy/en/user-guide/models/schema", + "versions/legacy/en/user-guide/models/load-balancing" + ] + }, + { + "group": "Application Orchestration", + "pages": [ + "versions/legacy/en/user-guide/build-app/chatbot", + "versions/legacy/en/user-guide/build-app/text-generator", + "versions/legacy/en/user-guide/build-app/agent", + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/concepts", + "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/en/user-guide/build-app/flow-app/variables", + { + "group": "Nodes", + "pages": [ + "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", + "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/en/user-guide/build-app/flow-app/file-upload", + "versions/legacy/en/user-guide/build-app/flow-app/additional-features" + ] + } + ] + }, + { + "group": "Debug and Preview", + "pages": [ + { + "group": "Chatflow & Workflow", + "pages": [ + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "Application Publishing", + "pages": [ + { + "group": "Publish as a Single-page Web App", + "pages": [ + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/en/user-guide/application-publishing/developing-with-apis", + "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "Management", + "pages": [ + "versions/legacy/en/user-guide/management/app-management", + "versions/legacy/en/user-guide/management/team-members-management", + "versions/legacy/en/user-guide/management/personal-account-management" + ] + }, + { + "group": "Monitoring", + "pages": [ + "versions/legacy/en/user-guide/monitoring/analysis", + "versions/legacy/en/user-guide/monitoring/logs", + "versions/legacy/en/user-guide/monitoring/annotation-reply", + { + "group": "Integrate External Ops Tools", + "pages": [ + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", + "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" + ] + } + ] + } + ] + } + ] + }, + { + "language": "ja", + "href": "/ja/introduction", + "groups": [ + { + "group": "ユーザーマニュアル", + "pages": [ + "versions/legacy/ja/user-guide/welcome", + { + "group": "モデルの接続", + "pages": [ + "versions/legacy/ja/user-guide/models/model-configuration", + "versions/legacy/ja/user-guide/models/new-provider", + "versions/legacy/ja/user-guide/models/predefined-model", + "versions/legacy/ja/user-guide/models/customizable-model", + "versions/legacy/ja/user-guide/models/interfaces", + "versions/legacy/ja/user-guide/models/schema", + "versions/legacy/ja/user-guide/models/load-balancing" + ] + }, + { + "group": "アプリの構築", + "pages": [ + "versions/legacy/ja/user-guide/build-app/chatbot", + "versions/legacy/ja/user-guide/build-app/text-generator", + "versions/legacy/ja/user-guide/build-app/agent", + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/concepts", + "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", + "versions/legacy/ja/user-guide/build-app/flow-app/variables", + { + "group": "ノードの説明", + "pages": [ + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", + "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" + ] + }, + "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", + "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", + "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" + ] + } + ] + }, + { + "group": "アプリのデバッグ", + "pages": [ + { + "group": "チャットフロー & ワークフロー", + "pages": [ + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", + "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" + ] + } + ] + }, + { + "group": "アプリのリリース", + "pages": [ + { + "group": "公開Webアプリとしてのリリース", + "pages": [ + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", + "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" + ] + }, + "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", + "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", + "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" + ] + }, + { + "group": "管理", + "pages": [ + "versions/legacy/ja/user-guide/management/app-management", + "versions/legacy/ja/user-guide/management/team-members-management", + "versions/legacy/ja/user-guide/management/personal-account-management" + ] + } + ] + } + ] + } + ] + } + ] + }, + "contextual": { + "options": [ + "copy" + ] + }, + "redirects": [ + { + "source": "/en/guides/workflow/node/start", + "destination": "/en/use-dify/getting-started/key-concepts#workflow" }, - "description": "Dify is an open-source platform for building AI applications. It provides a comprehensive set of tools and features to help you build, deploy, and manage your AI applications.", - "favicon": "/logo/dify-logo.png", - "logo": { - "light": "https://assets-docs.dify.ai/2025/05/d05cfc6ebe48f725d171dc71c64a5d16.svg", - "dark": "https://assets-docs.dify.ai/2025/05/c51f1cda47c1d9a4a162d7736f6e4c53.svg" + { + "source": "/en/guides/workflow/node/user-input", + "destination": "/en/use-dify/nodes/user-input" }, - "navigation": { - "versions": [ - { - "version": "Latest", - "languages": [ - { - "language": "en", - "default": true, - "href": "en/use-dify/getting-started/introduction", - "dropdowns": [ - { - "dropdown": "Use Dify", - "icon": "book-open", - "pages": [ - { - "group": " ", - "pages": [ - { - "group": "Get Started", - "expanded": false, - "pages": [ - "en/use-dify/getting-started/introduction", - "en/use-dify/getting-started/quick-start", - "en/use-dify/getting-started/key-concepts" - ] - }, - { - "group": "Nodes", - "expanded": false, - "pages": [ - "en/use-dify/nodes/user-input", - { - "group": "Trigger", - "icon": "bolt-lightning", - "pages": [ - "en/use-dify/nodes/trigger/overview", - "en/use-dify/nodes/trigger/schedule-trigger", - "en/use-dify/nodes/trigger/plugin-trigger", - "en/use-dify/nodes/trigger/webhook-trigger" - ] - }, - "en/use-dify/nodes/llm", - "en/use-dify/nodes/knowledge-retrieval", - "en/use-dify/nodes/answer", - "en/use-dify/nodes/output", - "en/use-dify/nodes/agent", - "en/use-dify/nodes/tools", - "en/use-dify/nodes/question-classifier", - "en/use-dify/nodes/ifelse", - "en/use-dify/nodes/iteration", - "en/use-dify/nodes/loop", - "en/use-dify/nodes/code", - "en/use-dify/nodes/template", - "en/use-dify/nodes/variable-aggregator", - "en/use-dify/nodes/doc-extractor", - "en/use-dify/nodes/variable-assigner", - "en/use-dify/nodes/parameter-extractor", - "en/use-dify/nodes/http-request", - "en/use-dify/nodes/list-operator" - ] - }, - { - "group": "Build", - "expanded": false, - "pages": [ - "en/use-dify/build/shortcut-key", - "en/use-dify/build/goto-anything", - "en/use-dify/build/orchestrate-node", - "en/use-dify/build/predefined-error-handling-logic", - "en/use-dify/build/mcp", - "en/use-dify/build/version-control", - "en/use-dify/build/additional-features" - ] - }, - { - "group": "Debug", - "expanded": false, - "pages": [ - "en/use-dify/debug/step-run", - "en/use-dify/debug/variable-inspect", - "en/use-dify/debug/history-and-logs", - "en/use-dify/debug/error-type" - ] - }, - { - "group": "Publish", - "expanded": false, - "pages": [ - "en/use-dify/publish/README", - { - "group": "Web App", - "icon": "globe", - "pages": [ - "en/use-dify/publish/webapp/workflow-webapp", - "en/use-dify/publish/webapp/chatflow-webapp", - "en/use-dify/publish/webapp/web-app-settings", - "en/use-dify/publish/webapp/web-app-access", - "en/use-dify/publish/webapp/embedding-in-websites" - ] - }, - "en/use-dify/publish/publish-mcp", - "en/use-dify/publish/developing-with-apis" - ] - }, - { - "group": "Monitor", - "expanded": false, - "pages": [ - "en/use-dify/monitor/analysis", - "en/use-dify/monitor/logs", - "en/use-dify/monitor/annotation-reply", - { - "group": "Integrations", - "icon": "grid-2-plus", - "pages": [ - "en/use-dify/monitor/integrations/integrate-langsmith", - "en/use-dify/monitor/integrations/integrate-langfuse", - "en/use-dify/monitor/integrations/integrate-arize", - "en/use-dify/monitor/integrations/integrate-opik", - "en/use-dify/monitor/integrations/integrate-phoenix", - "en/use-dify/monitor/integrations/integrate-weave" - ] - } - ] - }, - { - "group": "Knowledge", - "expanded": false, - "pages": [ - "en/use-dify/knowledge/readme", - { - "group": "Create Knowledge", - "icon": "square-plus", - "pages": [ - "en/use-dify/knowledge/create-knowledge/introduction", - { - "group": "1. Import Text Data", - "pages": [ - "en/use-dify/knowledge/create-knowledge/import-text-data/readme", - "en/use-dify/knowledge/create-knowledge/import-text-data/sync-from-notion", - "en/use-dify/knowledge/create-knowledge/import-text-data/sync-from-website" - ] - }, - "en/use-dify/knowledge/create-knowledge/chunking-and-cleaning-text", - "en/use-dify/knowledge/create-knowledge/setting-indexing-methods" - ] - }, - { - "group": "Create from Knowledge Pipeline", - "icon": "pipe-section", - "pages": [ - "en/use-dify/knowledge/knowledge-pipeline/readme", - "en/use-dify/knowledge/knowledge-pipeline/create-knowledge-pipeline", - "en/use-dify/knowledge/knowledge-pipeline/knowledge-pipeline-orchestration", - "en/use-dify/knowledge/knowledge-pipeline/publish-knowledge-pipeline", - "en/use-dify/knowledge/knowledge-pipeline/upload-files", - "en/use-dify/knowledge/knowledge-pipeline/manage-knowledge-base", - "en/use-dify/knowledge/knowledge-pipeline/authorize-data-source" - ] - }, - { - "group": "Manage Knowledge", - "icon": "gear", - "pages": [ - "en/use-dify/knowledge/manage-knowledge/introduction", - "en/use-dify/knowledge/manage-knowledge/maintain-knowledge-documents", - "en/use-dify/knowledge/manage-knowledge/maintain-dataset-via-api" - ] - }, - "en/use-dify/knowledge/metadata", - "en/use-dify/knowledge/integrate-knowledge-within-application", - "en/use-dify/knowledge/retrieval-test-and-citation", - "en/use-dify/knowledge/knowledge-request-rate-limit", - "en/use-dify/knowledge/connect-external-knowledge-base", - "en/use-dify/knowledge/external-knowledge-api" - ] - }, - { - "group": "Workspace", - "expanded": false, - "pages": [ - "en/use-dify/workspace/readme", - "en/use-dify/workspace/model-providers", - "en/use-dify/workspace/plugins", - "en/use-dify/workspace/app-management", - "en/use-dify/workspace/team-members-management", - "en/use-dify/workspace/personal-account-management", - "en/use-dify/workspace/subscription-management" - ] - }, - { - "group": "Tutorials", - "expanded": false, - "pages": [ - "en/use-dify/tutorials/simple-chatbot", - "en/use-dify/tutorials/twitter-chatflow", - "en/use-dify/tutorials/customer-service-bot", - "en/use-dify/tutorials/build-ai-image-generation-app", - "en/use-dify/tutorials/article-reader" - ] - } - ] - } - ] - }, - { - "dropdown": "Self Host", - "icon": "server", - "pages": [ - { - "group": "Quick Start", - "pages": [ - "en/self-host/quick-start/docker-compose", - "en/self-host/quick-start/faqs" - ] - }, - { - "group": "Advanced Deployments", - "pages": [ - "en/self-host/advanced-deployments/local-source-code", - "en/self-host/advanced-deployments/start-the-frontend-docker-container" - ] - }, - { - "group": "Configuration", - "pages": [ - "en/self-host/configuration/environments" - ] - }, - { - "group": "Platform Guides", - "pages": [ - "en/self-host/platform-guides/bt-panel", - "en/self-host/platform-guides/dify-premium" - ] - }, - { - "group": "Troubleshooting", - "pages": [ - "en/self-host/troubleshooting/common-issues", - "en/self-host/troubleshooting/docker-issues", - "en/self-host/troubleshooting/integrations", - "en/self-host/troubleshooting/storage-and-migration", - "en/self-host/troubleshooting/weaviate-v4-migration" - ] - } - ] - }, - { - "dropdown": "API Reference", - "icon": "code", - "groups": [ - { - "group": "Chat and Agent", - "openapi": "en/api-reference/openapi_chat.json" - }, - { - "group": "Chatflow", - "openapi": "en/api-reference/openapi_chatflow.json" - }, - { - "group": "Workflow", - "openapi": "en/api-reference/openapi_workflow.json" - }, - { - "group": "Knowledge", - "openapi": "en/api-reference/openapi_knowledge.json" - }, - { - "group": "Text Completion", - "openapi": "en/api-reference/openapi_completion.json" - } - ] - }, - { - "dropdown": "Develop Plugin", - "icon": "code-pull-request", - "groups": [ - { - "group": "Getting Started", - "pages": [ - "plugin-dev-en/0111-getting-started-dify-plugin", - "plugin-dev-en/0111-cli" - ] - }, - { - "group": "Features & Specs", - "pages": [ - { - "group": "Plugin Types", - "pages": [ - "plugin-dev-en/0411-general-specifications", - "plugin-dev-en/0411-model-designing-rules", - "plugin-dev-en/0412-model-schema", - "plugin-dev-en/0411-persistent-storage-kv", - "plugin-dev-en/0411-tool", - "plugin-dev-en/0411-plugin-info-by-manifest", - "plugin-dev-en/0411-multilingual-readme" - ] - }, - { - "group": "Advanced Development", - "pages": [ - { - "group": "Reverse Calling", - "pages": [ - "plugin-dev-en/9241-bundle", - "plugin-dev-en/9241-reverse-invocation", - "plugin-dev-en/9242-reverse-invocation-app", - "plugin-dev-en/9242-reverse-invocation-model", - "plugin-dev-en/9242-reverse-invocation-tool", - "plugin-dev-en/9243-customizable-model", - "plugin-dev-en/9243-reverse-invocation-node" - ] - } - ] - } - ] - }, - { - "group": "Development Guides & Walkthroughs", - "pages": [ - "plugin-dev-en/0131-cheatsheet", - "plugin-dev-en/0222-tool-plugin", - "plugin-dev-en/0222-tool-oauth", - "plugin-dev-en/0222-datasource-plugin", - "plugin-dev-en/0222-trigger-plugin", - "plugin-dev-en/0222-creating-new-model-provider", - "plugin-dev-en/0432-develop-a-slack-bot-plugin", - "plugin-dev-en/0432-endpoint", - "plugin-dev-en/0432-develop-flomo-plugin", - "plugin-dev-en/0432-develop-md-exporter" - ] - }, - { - "group": "Contribution & Publishing", - "pages": [ - { - "group": "Code of Conduct & Standards", - "pages": [ - "plugin-dev-en/0312-contributor-covenant-code-of-conduct", - "plugin-dev-en/0312-privacy-protection-guidelines", - "plugin-dev-en/0312-third-party-signature-verification" - ] - }, - { - "group": "Publishing & Listing", - "pages": [ - "plugin-dev-en/0321-plugin-auto-publish-pr", - "plugin-dev-en/0321-release-overview", - "plugin-dev-en/0322-release-by-file", - "plugin-dev-en/0322-release-to-dify-marketplace", - "plugin-dev-en/0322-release-to-individual-github-repo" - ] - }, - { - "group": "FAQ", - "pages": [ - "plugin-dev-en/0331-faq" - ] - } - ] - } - ] - } - ] - }, - { - "language": "zh", - "href": "zh/use-dify/getting-started/introduction", - "dropdowns": [ - { - "dropdown": "使用 Dify", - "icon": "book-open", - "pages": [ - { - "group": " ", - "pages": [ - { - "group": "入门", - "expanded": false, - "pages": [ - "zh/use-dify/getting-started/introduction", - "zh/use-dify/getting-started/quick-start", - "zh/use-dify/getting-started/key-concepts" - ] - }, - { - "group": "节点", - "expanded": false, - "pages": [ - "zh/use-dify/nodes/user-input", - { - "group": "触发器", - "icon": "bolt-lightning", - "pages": [ - "zh/use-dify/nodes/trigger/overview", - "zh/use-dify/nodes/trigger/schedule-trigger", - "zh/use-dify/nodes/trigger/plugin-trigger", - "zh/use-dify/nodes/trigger/webhook-trigger" - ] - }, - "zh/use-dify/nodes/llm", - "zh/use-dify/nodes/knowledge-retrieval", - "zh/use-dify/nodes/answer", - "zh/use-dify/nodes/output", - "zh/use-dify/nodes/agent", - "zh/use-dify/nodes/tools", - "zh/use-dify/nodes/question-classifier", - "zh/use-dify/nodes/ifelse", - "zh/use-dify/nodes/iteration", - "zh/use-dify/nodes/loop", - "zh/use-dify/nodes/code", - "zh/use-dify/nodes/template", - "zh/use-dify/nodes/variable-aggregator", - "zh/use-dify/nodes/doc-extractor", - "zh/use-dify/nodes/variable-assigner", - "zh/use-dify/nodes/parameter-extractor", - "zh/use-dify/nodes/http-request", - "zh/use-dify/nodes/list-operator" - ] - }, - { - "group": "构建", - "expanded": false, - "pages": [ - "zh/use-dify/build/shortcut-key", - "zh/use-dify/build/goto-anything", - "zh/use-dify/build/orchestrate-node", - "zh/use-dify/build/predefined-error-handling-logic", - "zh/use-dify/build/mcp", - "zh/use-dify/build/version-control", - "zh/use-dify/build/additional-features" - ] - }, - { - "group": "调试", - "expanded": false, - "pages": [ - "zh/use-dify/debug/step-run", - "zh/use-dify/debug/variable-inspect", - "zh/use-dify/debug/history-and-logs", - "zh/use-dify/debug/error-type" - ] - }, - { - "group": "发布", - "expanded": false, - "pages": [ - "zh/use-dify/publish/README", - { - "group": "Web App", - "icon": "globe", - "pages": [ - "zh/use-dify/publish/webapp/workflow-webapp", - "zh/use-dify/publish/webapp/chatflow-webapp", - "zh/use-dify/publish/webapp/web-app-settings", - "zh/use-dify/publish/webapp/web-app-access", - "zh/use-dify/publish/webapp/embedding-in-websites" - ] - }, - "zh/use-dify/publish/publish-mcp", - "zh/use-dify/publish/developing-with-apis" - ] - }, - { - "group": "监控", - "expanded": false, - "pages": [ - "zh/use-dify/monitor/analysis", - "zh/use-dify/monitor/logs", - "zh/use-dify/monitor/annotation-reply", - { - "group": "集成", - "icon": "grid-2-plus", - "pages": [ - "zh/use-dify/monitor/integrations/integrate-langsmith", - "zh/use-dify/monitor/integrations/integrate-langfuse", - "zh/use-dify/monitor/integrations/integrate-arize", - "zh/use-dify/monitor/integrations/integrate-opik", - "zh/use-dify/monitor/integrations/integrate-phoenix", - "zh/use-dify/monitor/integrations/integrate-weave" - ] - } - ] - }, - { - "group": "知识库", - "expanded": false, - "pages": [ - "zh/use-dify/knowledge/readme", - { - "group": "创建知识库", - "icon": "square-plus", - "pages": [ - "zh/use-dify/knowledge/create-knowledge/introduction", - { - "group": "导入文本数据", - "pages": [ - "zh/use-dify/knowledge/create-knowledge/import-text-data/readme", - "zh/use-dify/knowledge/create-knowledge/import-text-data/sync-from-notion", - "zh/use-dify/knowledge/create-knowledge/import-text-data/sync-from-website" - ] - }, - "zh/use-dify/knowledge/create-knowledge/chunking-and-cleaning-text", - "zh/use-dify/knowledge/create-knowledge/setting-indexing-methods" - ] - }, - { - "group": "从 Knowledge Pipeline 创建", - "icon": "pipe-section", - "pages": [ - "zh/use-dify/knowledge/knowledge-pipeline/readme", - "zh/use-dify/knowledge/knowledge-pipeline/create-knowledge-pipeline", - "zh/use-dify/knowledge/knowledge-pipeline/knowledge-pipeline-orchestration", - "zh/use-dify/knowledge/knowledge-pipeline/publish-knowledge-pipeline", - "zh/use-dify/knowledge/knowledge-pipeline/upload-files", - "zh/use-dify/knowledge/knowledge-pipeline/manage-knowledge-base", - "zh/use-dify/knowledge/knowledge-pipeline/authorize-data-source" - ] - }, - { - "group": "管理知识库", - "icon": "gear", - "pages": [ - "zh/use-dify/knowledge/manage-knowledge/introduction", - "zh/use-dify/knowledge/manage-knowledge/maintain-knowledge-documents", - "zh/use-dify/knowledge/manage-knowledge/maintain-dataset-via-api" - ] - }, - "zh/use-dify/knowledge/metadata", - "zh/use-dify/knowledge/integrate-knowledge-within-application", - "zh/use-dify/knowledge/retrieval-test-and-citation", - "zh/use-dify/knowledge/knowledge-request-rate-limit", - "zh/use-dify/knowledge/connect-external-knowledge-base", - "zh/use-dify/knowledge/external-knowledge-api" - ] - }, - { - "group": "工作区", - "expanded": false, - "pages": [ - "zh/use-dify/workspace/readme", - "zh/use-dify/workspace/model-providers", - "zh/use-dify/workspace/plugins", - "zh/use-dify/workspace/app-management", - "zh/use-dify/workspace/team-members-management", - "zh/use-dify/workspace/personal-account-management", - "zh/use-dify/workspace/subscription-management" - ] - }, - { - "group": "教程", - "expanded": false, - "pages": [ - "zh/use-dify/tutorials/simple-chatbot", - "zh/use-dify/tutorials/twitter-chatflow", - "zh/use-dify/tutorials/customer-service-bot", - "zh/use-dify/tutorials/build-ai-image-generation-app", - "zh/use-dify/tutorials/article-reader" - ] - } - ] - } - ] - }, - { - "dropdown": "自托管", - "icon": "server", - "pages": [ - { - "group": "快速开始", - "pages": [ - "zh/self-host/quick-start/docker-compose", - "zh/self-host/quick-start/faqs" - ] - }, - { - "group": "进阶部署", - "pages": [ - "zh/self-host/advanced-deployments/local-source-code", - "zh/self-host/advanced-deployments/start-the-frontend-docker-container" - ] - }, - { - "group": "配置", - "pages": [ - "zh/self-host/configuration/environments" - ] - }, - { - "group": "平台指南", - "pages": [ - "zh/self-host/platform-guides/bt-panel", - "zh/self-host/platform-guides/dify-premium" - ] - }, - { - "group": "故障排除", - "pages": [ - "zh/self-host/troubleshooting/common-issues", - "zh/self-host/troubleshooting/docker-issues", - "zh/self-host/troubleshooting/integrations", - "zh/self-host/troubleshooting/storage-and-migration", - "zh/self-host/troubleshooting/weaviate-v4-migration" - ] - } - ] - }, - { - "dropdown": "API 文档", - "icon": "code", - "groups": [ - { - "group": "Chatbot 和 Agent", - "openapi": "zh/api-reference/openapi_chat.json" - }, - { - "group": "Chatflow", - "openapi": "zh/api-reference/openapi_chatflow.json" - }, - { - "group": "工作流", - "openapi": "zh/api-reference/openapi_workflow.json" - }, - { - "group": "知识库", - "openapi": "zh/api-reference/openapi_knowledge.json" - }, - { - "group": "文本生成", - "openapi": "zh/api-reference/openapi_completion.json" - } - ] - }, - { - "dropdown": "开发插件", - "icon": "code-pull-request", - "groups": [ - { - "group": "概念与入门", - "pages": [ - { - "group": "概览", - "pages": [ - "plugin-dev-zh/0111-getting-started-dify-plugin" - ] - }, - "plugin-dev-zh/0131-cheatsheet" - ] - }, - { - "group": "开发实践", - "pages": [ - { - "group": "快速开始", - "pages": [ - "plugin-dev-zh/0211-getting-started-by-prompt", - "plugin-dev-zh/0211-getting-started-dify-tool", - "plugin-dev-zh/0211-getting-started-new-model" - ] - }, - { - "group": "开发 Dify 插件", - "pages": [ - "plugin-dev-zh/0221-initialize-development-tools", - "plugin-dev-zh/0222-creating-new-model-provider-extra", - "plugin-dev-zh/0222-creating-new-model-provider", - "plugin-dev-zh/0222-debugging-logs", - "plugin-dev-zh/0222-tool-plugin" - ] - } - ] - }, - { - "group": "贡献与发布", - "pages": [ - { - "group": "行为准则与规范", - "pages": [ - "plugin-dev-zh/0312-contributor-covenant-code-of-conduct", - "plugin-dev-zh/0312-privacy-protection-guidelines", - "plugin-dev-zh/0312-third-party-signature-verification" - ] - }, - { - "group": "发布与上架", - "pages": [ - "plugin-dev-zh/0321-plugin-auto-publish-pr", - "plugin-dev-zh/0321-release-overview", - "plugin-dev-zh/0322-release-by-file", - "plugin-dev-zh/0322-release-to-dify-marketplace", - "plugin-dev-zh/0322-release-to-individual-github-repo" - ] - }, - { - "group": "常见问题解答", - "pages": [ - "plugin-dev-zh/0331-faq" - ] - } - ] - }, - { - "group": "实践案例与示例", - "pages": [ - { - "group": "开发示例", - "pages": [ - "plugin-dev-zh/0431-example-overview-and-index", - "plugin-dev-zh/0432-develop-a-slack-bot-plugin", - "plugin-dev-zh/0432-endpoint" - ] - } - ] - }, - { - "group": "高级开发", - "pages": [ - { - "group": "Extension 与 Agent", - "pages": [ - "plugin-dev-zh/9231-extension-plugin", - "plugin-dev-zh/9232-agent", - "plugin-dev-zh/9433-agent-strategy-plugin" - ] - }, - { - "group": "反向调用", - "pages": [ - "plugin-dev-zh/9241-bundle", - "plugin-dev-zh/9241-reverse-invocation", - "plugin-dev-zh/9242-reverse-invocation-app", - "plugin-dev-zh/9242-reverse-invocation-model", - "plugin-dev-zh/9242-reverse-invocation-tool", - "plugin-dev-zh/9243-customizable-model", - "plugin-dev-zh/9243-reverse-invocation-node" - ] - } - ] - }, - { - "group": "Reference & Specifications", - "pages": [ - { - "group": "核心规范与功能", - "pages": [ - "plugin-dev-zh/0411-general-specifications", - "plugin-dev-zh/0411-model-designing-rules", - "plugin-dev-zh/0411-model-plugin-introduction", - "plugin-dev-zh/0411-persistent-storage-kv", - "plugin-dev-zh/0411-plugin-info-by-manifest", - "plugin-dev-zh/0411-remote-debug-a-plugin", - "plugin-dev-zh/0411-tool", - "plugin-dev-zh/0412-model-schema", - "plugin-dev-zh/0411-multilingual-readme" - ] - } - ] - }, - { - "group": "关于本文档", - "pages": [ - "plugin-dev-zh/0411-doc-contribution-guide", - "plugin-dev-zh/0412-doc-writing-dimensions-guide", - "plugin-dev-zh/0412-doc-understanding-the-dimensions" - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "ja/use-dify/getting-started/introduction", - "dropdowns": [ - { - "dropdown": "Dify を使う", - "icon": "book-open", - "pages": [ - { - "group": " ", - "pages": [ - { - "group": "はじめに", - "expanded": false, - "pages": [ - "ja/use-dify/getting-started/introduction", - "ja/use-dify/getting-started/quick-start", - "ja/use-dify/getting-started/key-concepts" - ] - }, - { - "group": "ノード", - "expanded": false, - "pages": [ - "ja/use-dify/nodes/user-input", - { - "group": "トリガー", - "icon": "bolt-lightning", - "pages": [ - "ja/use-dify/nodes/trigger/overview", - "ja/use-dify/nodes/trigger/schedule-trigger", - "ja/use-dify/nodes/trigger/plugin-trigger", - "ja/use-dify/nodes/trigger/webhook-trigger" - ] - }, - "ja/use-dify/nodes/llm", - "ja/use-dify/nodes/knowledge-retrieval", - "ja/use-dify/nodes/answer", - "ja/use-dify/nodes/output", - "ja/use-dify/nodes/agent", - "ja/use-dify/nodes/tools", - "ja/use-dify/nodes/question-classifier", - "ja/use-dify/nodes/ifelse", - "ja/use-dify/nodes/iteration", - "ja/use-dify/nodes/loop", - "ja/use-dify/nodes/code", - "ja/use-dify/nodes/template", - "ja/use-dify/nodes/variable-aggregator", - "ja/use-dify/nodes/doc-extractor", - "ja/use-dify/nodes/variable-assigner", - "ja/use-dify/nodes/parameter-extractor", - "ja/use-dify/nodes/http-request", - "ja/use-dify/nodes/list-operator" - ] - }, - { - "group": "ビルド", - "expanded": false, - "pages": [ - "ja/use-dify/build/shortcut-key", - "ja/use-dify/build/goto-anything", - "ja/use-dify/build/orchestrate-node", - "ja/use-dify/build/predefined-error-handling-logic", - "ja/use-dify/build/mcp", - "ja/use-dify/build/version-control", - "ja/use-dify/build/additional-features" - ] - }, - { - "group": "デバッグ", - "expanded": false, - "pages": [ - "ja/use-dify/debug/step-run", - "ja/use-dify/debug/variable-inspect", - "ja/use-dify/debug/history-and-logs", - "ja/use-dify/debug/error-type" - ] - }, - { - "group": "公開", - "expanded": false, - "pages": [ - "ja/use-dify/publish/README", - { - "group": "Webアプリ", - "icon": "globe", - "pages": [ - "ja/use-dify/publish/webapp/workflow-webapp", - "ja/use-dify/publish/webapp/chatflow-webapp", - "ja/use-dify/publish/webapp/web-app-settings", - "ja/use-dify/publish/webapp/web-app-access", - "ja/use-dify/publish/webapp/embedding-in-websites" - ] - }, - "ja/use-dify/publish/publish-mcp", - "ja/use-dify/publish/developing-with-apis" - ] - }, - { - "group": "モニタリング", - "expanded": false, - "pages": [ - "ja/use-dify/monitor/analysis", - "ja/use-dify/monitor/logs", - "ja/use-dify/monitor/annotation-reply", - { - "group": "インテグレーション", - "icon": "grid-2-plus", - "pages": [ - "ja/use-dify/monitor/integrations/integrate-langsmith", - "ja/use-dify/monitor/integrations/integrate-langfuse", - "ja/use-dify/monitor/integrations/integrate-arize", - "ja/use-dify/monitor/integrations/integrate-opik", - "ja/use-dify/monitor/integrations/integrate-phoenix", - "ja/use-dify/monitor/integrations/integrate-weave" - ] - } - ] - }, - { - "group": "ナレッジベース", - "expanded": false, - "pages": [ - "ja/use-dify/knowledge/readme", - { - "group": "作成手順", - "icon": "square-plus", - "pages": [ - "ja/use-dify/knowledge/create-knowledge/introduction", - { - "group": "1. テキストデータのインポート", - "pages": [ - "ja/use-dify/knowledge/create-knowledge/import-text-data/readme", - "ja/use-dify/knowledge/create-knowledge/import-text-data/sync-from-notion", - "ja/use-dify/knowledge/create-knowledge/import-text-data/sync-from-website" - ] - }, - "ja/use-dify/knowledge/create-knowledge/chunking-and-cleaning-text", - "ja/use-dify/knowledge/create-knowledge/setting-indexing-methods" - ] - }, - { - "group": "ナレッジパイプライン", - "icon": "pipe-section", - "pages": [ - "ja/use-dify/knowledge/knowledge-pipeline/readme", - "ja/use-dify/knowledge/knowledge-pipeline/create-knowledge-pipeline", - "ja/use-dify/knowledge/knowledge-pipeline/knowledge-pipeline-orchestration", - "ja/use-dify/knowledge/knowledge-pipeline/publish-knowledge-pipeline", - "ja/use-dify/knowledge/knowledge-pipeline/upload-files", - "ja/use-dify/knowledge/knowledge-pipeline/manage-knowledge-base", - "ja/use-dify/knowledge/knowledge-pipeline/authorize-data-source" - ] - }, - { - "group": "ナレッジベースの管理", - "icon": "gear", - "pages": [ - "ja/use-dify/knowledge/manage-knowledge/introduction", - "ja/use-dify/knowledge/manage-knowledge/maintain-knowledge-documents", - "ja/use-dify/knowledge/manage-knowledge/maintain-dataset-via-api" - ] - }, - "ja/use-dify/knowledge/metadata", - "ja/use-dify/knowledge/integrate-knowledge-within-application", - "ja/use-dify/knowledge/retrieval-test-and-citation", - "ja/use-dify/knowledge/knowledge-request-rate-limit", - "ja/use-dify/knowledge/connect-external-knowledge-base", - "ja/use-dify/knowledge/external-knowledge-api" - ] - }, - { - "group": "ワークスペース", - "expanded": false, - "pages": [ - "ja/use-dify/workspace/readme", - "ja/use-dify/workspace/model-providers", - "ja/use-dify/workspace/plugins", - "ja/use-dify/workspace/app-management", - "ja/use-dify/workspace/team-members-management", - "ja/use-dify/workspace/personal-account-management", - "ja/use-dify/workspace/subscription-management" - ] - }, - { - "group": "チュートリアル", - "expanded": false, - "pages": [ - "ja/use-dify/tutorials/twitter-chatflow", - "ja/use-dify/tutorials/customer-service-bot", - "ja/use-dify/tutorials/build-ai-image-generation-app", - "ja/use-dify/tutorials/article-reader" - ] - } - ] - } - ] - }, - { - "dropdown": "セルフホスティング", - "icon": "server", - "pages": [ - { - "group": "クイックスタート", - "pages": [ - "ja/self-host/quick-start/docker-compose", - "ja/self-host/quick-start/faqs" - ] - }, - { - "group": "高度なデプロイ", - "pages": [ - "ja/self-host/advanced-deployments/local-source-code", - "ja/self-host/advanced-deployments/start-the-frontend-docker-container" - ] - }, - { - "group": "設定", - "pages": [ - "ja/self-host/configuration/environments" - ] - }, - { - "group": "プラットフォームガイド", - "pages": [ - "ja/self-host/platform-guides/bt-panel", - "ja/self-host/platform-guides/dify-premium" - ] - }, - { - "group": "トラブルシューティング", - "pages": [ - "ja/self-host/troubleshooting/common-issues", - "ja/self-host/troubleshooting/docker-issues", - "ja/self-host/troubleshooting/integrations", - "ja/self-host/troubleshooting/storage-and-migration", - "ja/self-host/troubleshooting/weaviate-v4-migration" - ] - } - ] - }, - { - "dropdown": "プラグイン開発", - "icon": "code-pull-request", - "groups": [ - { - "group": "概念と概要", - "pages": [ - { - "group": "概要", - "pages": [ - "plugin-dev-ja/0111-getting-started-dify-plugin" - ] - }, - "plugin-dev-ja/0131-cheatsheet" - ] - }, - { - "group": "開発実践", - "pages": [ - { - "group": "クイックスタート", - "pages": [ - "plugin-dev-ja/0211-getting-started-by-prompt", - "plugin-dev-ja/0211-getting-started-dify-tool", - "plugin-dev-ja/0211-getting-started-new-model" - ] - }, - { - "group": "Difyプラグインの開発", - "pages": [ - "plugin-dev-ja/0221-initialize-development-tools", - "plugin-dev-ja/0222-creating-new-model-provider-extra", - "plugin-dev-ja/0222-creating-new-model-provider", - "plugin-dev-ja/0222-debugging-logs", - "plugin-dev-ja/0222-tool-plugin" - ] - } - ] - }, - { - "group": "貢献と公開", - "pages": [ - { - "group": "行動規範と基準", - "pages": [ - "plugin-dev-ja/0312-contributor-covenant-code-of-conduct", - "plugin-dev-ja/0312-privacy-protection-guidelines", - "plugin-dev-ja/0312-third-party-signature-verification" - ] - }, - { - "group": "公開と掲載", - "pages": [ - "plugin-dev-ja/0321-plugin-auto-publish-pr", - "plugin-dev-ja/0321-release-overview", - "plugin-dev-ja/0322-release-by-file", - "plugin-dev-ja/0322-release-to-dify-marketplace", - "plugin-dev-ja/0322-release-to-individual-github-repo" - ] - }, - { - "group": "よくある質問 (FAQ)", - "pages": [ - "plugin-dev-ja/0331-faq" - ] - } - ] - }, - { - "group": "実践例とユースケース", - "pages": [ - { - "group": "開発例", - "pages": [ - "plugin-dev-ja/0431-example-overview-and-index", - "plugin-dev-ja/0432-develop-a-slack-bot-plugin", - "plugin-dev-ja/0432-endpoint" - ] - } - ] - }, - { - "group": "高度な開発", - "pages": [ - { - "group": "Extension と Agent", - "pages": [ - "plugin-dev-ja/9231-extension-plugin", - "plugin-dev-ja/9232-agent", - "plugin-dev-ja/9433-agent-strategy-plugin" - ] - }, - { - "group": "リバースコール", - "pages": [ - "plugin-dev-ja/9241-bundle", - "plugin-dev-ja/9241-reverse-invocation", - "plugin-dev-ja/9242-reverse-invocation-app", - "plugin-dev-ja/9242-reverse-invocation-model", - "plugin-dev-ja/9242-reverse-invocation-tool", - "plugin-dev-ja/9243-customizable-model", - "plugin-dev-ja/9243-reverse-invocation-node" - ] - } - ] - }, - { - "group": "リファレンスと仕様", - "pages": [ - { - "group": "コア仕様と機能", - "pages": [ - "plugin-dev-ja/0411-general-specifications", - "plugin-dev-ja/0411-model-designing-rules", - "plugin-dev-ja/0411-model-plugin-introduction", - "plugin-dev-ja/0411-persistent-storage-kv", - "plugin-dev-ja/0411-plugin-info-by-manifest", - "plugin-dev-ja/0411-remote-debug-a-plugin", - "plugin-dev-ja/0411-tool", - "plugin-dev-ja/0412-model-schema", - "plugin-dev-ja/0411-multilingual-readme" - ] - } - ] - }, - { - "group": "ドキュメントについて", - "pages": [ - "plugin-dev-ja/0411-doc-contribution-guide", - "plugin-dev-ja/0412-doc-writing-dimensions-guide", - "plugin-dev-ja/0412-doc-understanding-the-dimensions" - ] - } - ] - }, - { - "dropdown": "APIアクセス", - "icon": "code", - "groups": [ - { - "group": "ChatbotとAgent", - "openapi": "ja/api-reference/openapi_chat.json" - }, - { - "group": "チャットフロー", - "openapi": "ja/api-reference/openapi_chatflow.json" - }, - { - "group": "ワークフロー", - "openapi": "ja/api-reference/openapi_workflow.json" - }, - { - "group": "ナレッジ", - "openapi": "ja/api-reference/openapi_knowledge.json" - }, - { - "group": "テキスト ジェネレーター", - "openapi": "ja/api-reference/openapi_completion.json" - } - ] - } - ] - } - ] - }, - { - "version": "3.3.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "versions/3-3-x/zh/user-guide/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/3-3-x/zh/user-guide/introduction", - { - "group": "接入大模型", - "pages": [ - "versions/3-0-x/zh/user-guide/model-configuration/readme", - "versions/3-0-x/zh/user-guide/model-configuration/new-provider", - "versions/3-0-x/zh/user-guide/model-configuration/predefined-model", - "versions/3-0-x/zh/user-guide/model-configuration/customizable-model", - "versions/3-0-x/zh/user-guide/model-configuration/interfaces", - "versions/3-0-x/zh/user-guide/model-configuration/schema", - "versions/3-0-x/zh/user-guide/model-configuration/load-balancing" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/readme", - "versions/3-0-x/zh/user-guide/application-orchestrate/creating-an-application", - { - "group": "聊天助手", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/chatbot-application", - "versions/3-0-x/zh/user-guide/application-orchestrate/multiple-llms-debugging" - ] - }, - "versions/3-0-x/zh/user-guide/application-orchestrate/agent", - { - "group": "应用工具箱", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/readme", - "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/moderation-tool" - ] - } - ] - }, - { - "group": "工作流", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/readme", - "versions/3-0-x/zh/user-guide/workflow/key-concept", - "versions/3-0-x/zh/user-guide/workflow/variables", - { - "group": "节点说明", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/node/start", - "versions/3-0-x/zh/user-guide/workflow/node/llm", - "versions/3-0-x/zh/user-guide/workflow/node/knowledge-retrieval", - "versions/3-0-x/zh/user-guide/workflow/node/question-classifier", - "versions/3-0-x/zh/user-guide/workflow/node/ifelse", - "versions/3-0-x/zh/user-guide/workflow/node/code", - "versions/3-0-x/zh/user-guide/workflow/node/template", - "versions/3-0-x/zh/user-guide/workflow/node/doc-extractor", - "versions/3-0-x/zh/user-guide/workflow/node/list-operator", - "versions/3-0-x/zh/user-guide/workflow/node/variable-aggregator", - "versions/3-0-x/zh/user-guide/workflow/node/variable-assigner", - "versions/3-0-x/zh/user-guide/workflow/node/iteration", - "versions/3-0-x/zh/user-guide/workflow/node/parameter-extractor", - "versions/3-0-x/zh/user-guide/workflow/node/http-request", - "versions/3-0-x/zh/user-guide/workflow/node/agent", - "versions/3-0-x/zh/user-guide/workflow/node/tools", - "versions/3-0-x/zh/user-guide/workflow/node/end", - "versions/3-0-x/zh/user-guide/workflow/node/answer", - "versions/3-0-x/zh/user-guide/workflow/node/loop" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/shortcut-key", - "versions/3-0-x/zh/user-guide/workflow/orchestrate-node", - "versions/3-0-x/zh/user-guide/workflow/file-upload", - { - "group": "异常处理", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/error-handling/readme", - "versions/3-0-x/zh/user-guide/workflow/error-handling/predefined-nodes-failure-logic", - "versions/3-0-x/zh/user-guide/workflow/error-handling/error-type" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/additional-feature", - { - "group": "预览与调试", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/history", - "versions/3-2-x/zh/user-guide/workflow/debug-and-preview/variable-inspect" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/publish", - "versions/3-0-x/zh/user-guide/workflow/structured-outputs", - "versions/3-0-x/zh/user-guide/workflow/bulletin" - ] - }, - { - "group": "知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/readme", - { - "group": "创建知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-base-creation/introduction", - { - "group": "1. 导入文本数据", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" - ] - }, - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" - ] - }, - { - "group": "从 Knowledge Pipeline 创建", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/readme", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/create-knowledge-pipeline", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/publish-knowledge-pipeline", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/upload-files", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/manage-knowledge-base", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-pipeline/authorize-data-source" - ] - }, - { - "group": "管理知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" - ] - }, - "versions/3-0-x/zh/user-guide/knowledge-base/metadata", - "versions/3-0-x/zh/user-guide/knowledge-base/integrate-knowledge-within-application", - "versions/3-0-x/zh/user-guide/knowledge-base/retrieval-test-and-citation", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-request-rate-limit", - "versions/3-0-x/zh/user-guide/knowledge-base/connect-external-knowledge-base", - "versions/3-0-x/zh/user-guide/knowledge-base/api-documentation/external-knowledge-api-documentation" - ] - }, - { - "group": "工具", - "pages": [ - "versions/3-0-x/zh/user-guide/tools/readme", - "versions/3-3-x/zh/user-guide/tools/mcp", - "versions/3-0-x/zh/user-guide/tools/quick-tool-integration", - "versions/3-0-x/zh/user-guide/tools/advanced-tool-integration", - { - "group": "工具配置详情", - "pages": [ - "versions/3-0-x/zh/user-guide/tools/tool-configuration/google", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/bing", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/searchapi", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/stable-diffusion", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/dall-e", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/perplexity", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/alphavantage", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/searxng", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/serper", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/siliconflow", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/comfyui" - ] - } - ] - }, - { - "group": "发布", - "pages": [ - "versions/2-8-x/zh/user-guide/application-publishing/permission-management", - "versions/3-3-x/zh/user-guide/application-publishing/publish-mcp", - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/readme", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/3-0-x/zh/user-guide/application-publishing/embedding-in-websites", - "versions/3-0-x/zh/user-guide/application-publishing/developing-with-apis", - "versions/3-0-x/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "标注", - "pages": [ - "versions/3-0-x/zh/user-guide/annotation/logs", - "versions/3-0-x/zh/user-guide/annotation/annotation-reply" - ] - }, - { - "group": "监测", - "pages": [ - "versions/3-0-x/zh/user-guide/monitoring/README", - { - "group": "集成外部与 Ops 工具", - "pages": [ - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/readme", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" - ] - }, - "versions/3-0-x/zh/user-guide/monitoring/analysis" - ] - }, - { - "group": "管理", - "pages": [ - "versions/3-0-x/zh/user-guide/management/app-management", - "versions/3-0-x/zh/user-guide/management/team-members-management", - "versions/3-0-x/zh/user-guide/management/personal-account-management", - "versions/3-0-x/zh/user-guide/management/subscription-management", - "versions/3-0-x/zh/user-guide/management/version-control" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "versions/3-3-x/en/user-guide/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/3-3-x/en/user-guide/introduction", - { - "group": "Model Configuration", - "pages": [ - "versions/3-0-x/en/user-guide/model-configuration/readme", - "versions/3-0-x/en/user-guide/model-configuration/new-provider", - "versions/3-0-x/en/user-guide/model-configuration/predefined-model", - "versions/3-0-x/en/user-guide/model-configuration/customizable-model", - "versions/3-0-x/en/user-guide/model-configuration/interfaces", - "versions/3-0-x/en/user-guide/model-configuration/schema" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/3-0-x/en/user-guide/application-orchestrate/readme", - "versions/3-0-x/en/user-guide/application-orchestrate/creating-an-application", - "versions/3-0-x/en/user-guide/application-orchestrate/chatbot-application", - "versions/3-0-x/en/user-guide/application-orchestrate/multiple-llms-debugging", - "versions/3-0-x/en/user-guide/application-orchestrate/text-generator", - "versions/3-0-x/en/user-guide/application-orchestrate/agent", - { - "group": "Application Toolkits", - "pages": [ - "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/readme", - "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/moderation-tool" - ] - } - ] - }, - { - "group": "Workflow", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/README", - "versions/3-0-x/en/user-guide/workflow/key-concepts", - "versions/3-0-x/en/user-guide/workflow/variables", - { - "group": "Node Description", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/node/start", - "versions/3-0-x/en/user-guide/workflow/node/end", - "versions/3-0-x/en/user-guide/workflow/node/answer", - "versions/3-0-x/en/user-guide/workflow/node/llm", - "versions/3-0-x/en/user-guide/workflow/node/knowledge-retrieval", - "versions/3-0-x/en/user-guide/workflow/node/question-classifier", - "versions/3-0-x/en/user-guide/workflow/node/ifelse", - "versions/3-0-x/en/user-guide/workflow/node/code", - "versions/3-0-x/en/user-guide/workflow/node/template", - "versions/3-0-x/en/user-guide/workflow/node/doc-extractor", - "versions/3-0-x/en/user-guide/workflow/node/list-operator", - "versions/3-0-x/en/user-guide/workflow/node/variable-aggregator", - "versions/3-0-x/en/user-guide/workflow/node/variable-assigner", - "versions/3-0-x/en/user-guide/workflow/node/iteration", - "versions/3-0-x/en/user-guide/workflow/node/parameter-extractor", - "versions/3-0-x/en/user-guide/workflow/node/http-request", - "versions/3-0-x/en/user-guide/workflow/node/agent", - "versions/3-0-x/en/user-guide/workflow/node/tools", - "versions/3-0-x/en/user-guide/workflow/node/loop" - ] - }, - "versions/3-0-x/en/user-guide/workflow/shortcut-key", - "versions/3-0-x/en/user-guide/workflow/orchestrate-node", - "versions/3-0-x/en/user-guide/workflow/file-upload", - { - "group": "Error Handling", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/error-handling/README", - "versions/3-0-x/en/user-guide/workflow/error-handling/predefined-error-handling-logic", - "versions/3-0-x/en/user-guide/workflow/error-handling/error-type" - ] - }, - "versions/3-0-x/en/user-guide/workflow/additional-features", - { - "group": "Debug and Preview", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/history", - "versions/3-2-x/en/user-guide/workflow/debug-and-preview/variable-inspect" - ] - }, - "versions/3-0-x/en/user-guide/workflow/publish", - "versions/3-0-x/en/user-guide/workflow/structured-outputs" - ] - }, - { - "group": "Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/readme", - { - "group": "Create Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-base-creation/introduction", - { - "group": "1. Import Text Data", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" - ] - }, - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" - ] - }, - { - "group": "Manage Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" - ] - }, - "versions/3-0-x/en/user-guide/knowledge-base/metadata", - "versions/3-0-x/en/user-guide/knowledge-base/integrate-knowledge-within-application", - "versions/3-0-x/en/user-guide/knowledge-base/retrieval-test-and-citation", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-request-rate-limit", - "versions/3-0-x/en/user-guide/knowledge-base/connect-external-knowledge-base", - "versions/3-0-x/en/user-guide/knowledge-base/external-knowledge-api" - ] - }, - { - "group": "Tools", - "pages": [ - "versions/3-3-x/en/user-guide/tools/mcp" - ] - }, - { - "group": "Publishing", - "pages": [ - "versions/2-8-x/en/user-guide/application-publishing/permission-management", - "versions/3-3-x/en/user-guide/application-publishing/publish-mcp", - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/README", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/3-0-x/en/user-guide/application-publishing/embedding-in-websites", - "versions/3-0-x/en/user-guide/application-publishing/developing-with-apis", - "versions/3-0-x/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Annotation", - "pages": [ - "versions/3-0-x/en/user-guide/annotation/logs", - "versions/3-0-x/en/user-guide/annotation/annotation-reply" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/3-0-x/en/user-guide/monitoring/README", - "versions/3-0-x/en/user-guide/monitoring/analysis", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/README", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" - ] - } - ] - }, - { - "group": "Extensions", - "pages": [ - { - "group": "API-Based Extension", - "pages": [ - "versions/3-0-x/en/user-guide/extension/api-based-extension/README", - "versions/3-0-x/en/user-guide/extension/api-based-extension/external-data-tool", - "versions/3-0-x/en/user-guide/extension/api-based-extension/cloudflare-workers", - "versions/3-0-x/en/user-guide/extension/api-based-extension/moderation" - ] - }, - { - "group": "Code-Based Extension", - "pages": [ - "versions/3-0-x/en/user-guide/extension/code-based-extension/README", - "versions/3-0-x/en/user-guide/extension/code-based-extension/external-data-tool", - "versions/3-0-x/en/user-guide/extension/code-based-extension/moderation" - ] - } - ] - }, - { - "group": "Management", - "pages": [ - "versions/3-0-x/en/user-guide/management/app-management", - "versions/3-0-x/en/user-guide/management/team-members-management", - "versions/3-0-x/en/user-guide/management/personal-account-management", - "versions/3-0-x/en/user-guide/management/version-control" - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "versions/3-3-x/ja/user-guide/introduction", - "groups": [ - { - "group": "ユーザーマニュアル", - "pages": [ - "versions/3-3-x/ja/user-guide/introduction", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/history", - "versions/3-2-x/ja/user-guide/workflow/debug-and-preview/variable-inspect" - ] - } - ] - }, - { - "group": "ツール", - "pages": [ - "versions/3-3-x/ja/user-guide/tools/mcp" - ] - }, - { - "group": "アプリのリリース", - "pages": [ - "versions/2-8-x/ja/user-guide/application-publishing/permission-management", - "versions/3-3-x/ja/user-guide/application-publishing/publish-mcp", - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - }, - { - "group": "監視", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/analysis", - "versions/legacy/ja/user-guide/monitoring/logs", - "versions/legacy/ja/user-guide/monitoring/annotation-reply", - { - "group": "外部Opsツールの統合", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "version": "3.2.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "versions/3-2-x/zh/user-guide/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/3-2-x/zh/user-guide/introduction", - { - "group": "接入大模型", - "pages": [ - "versions/3-0-x/zh/user-guide/model-configuration/readme", - "versions/3-0-x/zh/user-guide/model-configuration/new-provider", - "versions/3-0-x/zh/user-guide/model-configuration/predefined-model", - "versions/3-0-x/zh/user-guide/model-configuration/customizable-model", - "versions/3-0-x/zh/user-guide/model-configuration/interfaces", - "versions/3-0-x/zh/user-guide/model-configuration/schema", - "versions/3-0-x/zh/user-guide/model-configuration/load-balancing", - "versions/3-0-x/zh/user-guide/model-configuration/manage-model-credential" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/readme", - "versions/3-0-x/zh/user-guide/application-orchestrate/creating-an-application", - { - "group": "聊天助手", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/chatbot-application", - "versions/3-0-x/zh/user-guide/application-orchestrate/multiple-llms-debugging" - ] - }, - "versions/3-0-x/zh/user-guide/application-orchestrate/agent", - { - "group": "应用工具箱", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/readme", - "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/moderation-tool" - ] - } - ] - }, - { - "group": "工作流", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/readme", - "versions/3-0-x/zh/user-guide/workflow/key-concept", - "versions/3-0-x/zh/user-guide/workflow/variables", - { - "group": "节点说明", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/node/start", - "versions/3-0-x/zh/user-guide/workflow/node/llm", - "versions/3-0-x/zh/user-guide/workflow/node/knowledge-retrieval", - "versions/3-0-x/zh/user-guide/workflow/node/question-classifier", - "versions/3-0-x/zh/user-guide/workflow/node/ifelse", - "versions/3-0-x/zh/user-guide/workflow/node/code", - "versions/3-0-x/zh/user-guide/workflow/node/template", - "versions/3-0-x/zh/user-guide/workflow/node/doc-extractor", - "versions/3-0-x/zh/user-guide/workflow/node/list-operator", - "versions/3-0-x/zh/user-guide/workflow/node/variable-aggregator", - "versions/3-0-x/zh/user-guide/workflow/node/variable-assigner", - "versions/3-0-x/zh/user-guide/workflow/node/iteration", - "versions/3-0-x/zh/user-guide/workflow/node/parameter-extractor", - "versions/3-0-x/zh/user-guide/workflow/node/http-request", - "versions/3-0-x/zh/user-guide/workflow/node/agent", - "versions/3-0-x/zh/user-guide/workflow/node/tools", - "versions/3-0-x/zh/user-guide/workflow/node/end", - "versions/3-0-x/zh/user-guide/workflow/node/answer", - "versions/3-0-x/zh/user-guide/workflow/node/loop" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/shortcut-key", - "versions/3-0-x/zh/user-guide/workflow/orchestrate-node", - "versions/3-0-x/zh/user-guide/workflow/file-upload", - { - "group": "异常处理", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/error-handling/readme", - "versions/3-0-x/zh/user-guide/workflow/error-handling/predefined-nodes-failure-logic", - "versions/3-0-x/zh/user-guide/workflow/error-handling/error-type" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/additional-feature", - { - "group": "预览与调试", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/history", - "versions/3-2-x/zh/user-guide/workflow/debug-and-preview/variable-inspect" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/publish", - "versions/3-0-x/zh/user-guide/workflow/structured-outputs", - "versions/3-0-x/zh/user-guide/workflow/bulletin" - ] - }, - { - "group": "知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/readme", - { - "group": "创建知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-base-creation/introduction", - { - "group": "1. 导入文本数据", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" - ] - }, - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" - ] - }, - { - "group": "管理知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" - ] - }, - "versions/3-0-x/zh/user-guide/knowledge-base/metadata", - "versions/3-0-x/zh/user-guide/knowledge-base/integrate-knowledge-within-application", - "versions/3-0-x/zh/user-guide/knowledge-base/retrieval-test-and-citation", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-request-rate-limit", - "versions/3-0-x/zh/user-guide/knowledge-base/connect-external-knowledge-base", - "versions/3-0-x/zh/user-guide/knowledge-base/api-documentation/external-knowledge-api-documentation" - ] - }, - { - "group": "工具", - "pages": [ - "versions/3-0-x/zh/user-guide/tools/readme", - "versions/3-0-x/zh/user-guide/tools/quick-tool-integration", - "versions/3-0-x/zh/user-guide/tools/advanced-tool-integration", - { - "group": "工具配置详情", - "pages": [ - "versions/3-0-x/zh/user-guide/tools/tool-configuration/google", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/bing", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/searchapi", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/stable-diffusion", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/dall-e", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/perplexity", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/alphavantage", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/searxng", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/serper", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/siliconflow", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/comfyui" - ] - } - ] - }, - { - "group": "发布", - "pages": [ - "versions/2-8-x/zh/user-guide/application-publishing/permission-management", - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/readme", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/3-0-x/zh/user-guide/application-publishing/embedding-in-websites", - "versions/3-0-x/zh/user-guide/application-publishing/developing-with-apis", - "versions/3-0-x/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "标注", - "pages": [ - "versions/3-0-x/zh/user-guide/annotation/logs", - "versions/3-0-x/zh/user-guide/annotation/annotation-reply" - ] - }, - { - "group": "监测", - "pages": [ - "versions/3-0-x/zh/user-guide/monitoring/README", - { - "group": "集成外部与 Ops 工具", - "pages": [ - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/readme", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" - ] - }, - "versions/3-0-x/zh/user-guide/monitoring/analysis" - ] - }, - { - "group": "管理", - "pages": [ - "versions/3-0-x/zh/user-guide/management/app-management", - "versions/3-0-x/zh/user-guide/management/team-members-management", - "versions/3-0-x/zh/user-guide/management/personal-account-management", - "versions/3-0-x/zh/user-guide/management/subscription-management", - "versions/3-0-x/zh/user-guide/management/version-control" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "versions/3-2-x/en/user-guide/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/3-2-x/en/user-guide/introduction", - { - "group": "Model Configuration", - "pages": [ - "versions/3-0-x/en/user-guide/model-configuration/readme", - "versions/3-0-x/en/user-guide/model-configuration/new-provider", - "versions/3-0-x/en/user-guide/model-configuration/predefined-model", - "versions/3-0-x/en/user-guide/model-configuration/customizable-model", - "versions/3-0-x/en/user-guide/model-configuration/interfaces", - "versions/3-0-x/en/user-guide/model-configuration/schema", - "versions/3-0-x/en/user-guide/model-configuration/manage-model-credential" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/3-0-x/en/user-guide/application-orchestrate/readme", - "versions/3-0-x/en/user-guide/application-orchestrate/creating-an-application", - "versions/3-0-x/en/user-guide/application-orchestrate/chatbot-application", - "versions/3-0-x/en/user-guide/application-orchestrate/multiple-llms-debugging", - "versions/3-0-x/en/user-guide/application-orchestrate/text-generator", - "versions/3-0-x/en/user-guide/application-orchestrate/agent", - { - "group": "Application Toolkits", - "pages": [ - "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/readme", - "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/moderation-tool" - ] - } - ] - }, - { - "group": "Workflow", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/README", - "versions/3-0-x/en/user-guide/workflow/key-concepts", - "versions/3-0-x/en/user-guide/workflow/variables", - { - "group": "Node Description", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/node/start", - "versions/3-0-x/en/user-guide/workflow/node/end", - "versions/3-0-x/en/user-guide/workflow/node/answer", - "versions/3-0-x/en/user-guide/workflow/node/llm", - "versions/3-0-x/en/user-guide/workflow/node/knowledge-retrieval", - "versions/3-0-x/en/user-guide/workflow/node/question-classifier", - "versions/3-0-x/en/user-guide/workflow/node/ifelse", - "versions/3-0-x/en/user-guide/workflow/node/code", - "versions/3-0-x/en/user-guide/workflow/node/template", - "versions/3-0-x/en/user-guide/workflow/node/doc-extractor", - "versions/3-0-x/en/user-guide/workflow/node/list-operator", - "versions/3-0-x/en/user-guide/workflow/node/variable-aggregator", - "versions/3-0-x/en/user-guide/workflow/node/variable-assigner", - "versions/3-0-x/en/user-guide/workflow/node/iteration", - "versions/3-0-x/en/user-guide/workflow/node/parameter-extractor", - "versions/3-0-x/en/user-guide/workflow/node/http-request", - "versions/3-0-x/en/user-guide/workflow/node/agent", - "versions/3-0-x/en/user-guide/workflow/node/tools", - "versions/3-0-x/en/user-guide/workflow/node/loop" - ] - }, - "versions/3-0-x/en/user-guide/workflow/shortcut-key", - "versions/3-0-x/en/user-guide/workflow/orchestrate-node", - "versions/3-0-x/en/user-guide/workflow/file-upload", - { - "group": "Error Handling", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/error-handling/README", - "versions/3-0-x/en/user-guide/workflow/error-handling/predefined-error-handling-logic", - "versions/3-0-x/en/user-guide/workflow/error-handling/error-type" - ] - }, - "versions/3-0-x/en/user-guide/workflow/additional-features", - { - "group": "Debug and Preview", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/history", - "versions/3-2-x/en/user-guide/workflow/debug-and-preview/variable-inspect" - ] - }, - "versions/3-0-x/en/user-guide/workflow/publish", - "versions/3-0-x/en/user-guide/workflow/structured-outputs" - ] - }, - { - "group": "Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/readme", - { - "group": "Create Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-base-creation/introduction", - { - "group": "1. Import Text Data", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" - ] - }, - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" - ] - }, - { - "group": "Manage Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" - ] - }, - "versions/3-0-x/en/user-guide/knowledge-base/metadata", - "versions/3-0-x/en/user-guide/knowledge-base/integrate-knowledge-within-application", - "versions/3-0-x/en/user-guide/knowledge-base/retrieval-test-and-citation", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-request-rate-limit", - "versions/3-0-x/en/user-guide/knowledge-base/connect-external-knowledge-base", - "versions/3-0-x/en/user-guide/knowledge-base/external-knowledge-api" - ] - }, - { - "group": "Publishing", - "pages": [ - "versions/2-8-x/en/user-guide/application-publishing/permission-management", - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/README", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/3-0-x/en/user-guide/application-publishing/embedding-in-websites", - "versions/3-0-x/en/user-guide/application-publishing/developing-with-apis", - "versions/3-0-x/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Annotation", - "pages": [ - "versions/3-0-x/en/user-guide/annotation/logs", - "versions/3-0-x/en/user-guide/annotation/annotation-reply" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/3-0-x/en/user-guide/monitoring/README", - "versions/3-0-x/en/user-guide/monitoring/analysis", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/README", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" - ] - } - ] - }, - { - "group": "Extensions", - "pages": [ - { - "group": "API-Based Extension", - "pages": [ - "versions/3-0-x/en/user-guide/extension/api-based-extension/README", - "versions/3-0-x/en/user-guide/extension/api-based-extension/external-data-tool", - "versions/3-0-x/en/user-guide/extension/api-based-extension/cloudflare-workers", - "versions/3-0-x/en/user-guide/extension/api-based-extension/moderation" - ] - }, - { - "group": "Code-Based Extension", - "pages": [ - "versions/3-0-x/en/user-guide/extension/code-based-extension/README", - "versions/3-0-x/en/user-guide/extension/code-based-extension/external-data-tool", - "versions/3-0-x/en/user-guide/extension/code-based-extension/moderation" - ] - } - ] - }, - { - "group": "Management", - "pages": [ - "versions/3-0-x/en/user-guide/management/app-management", - "versions/3-0-x/en/user-guide/management/team-members-management", - "versions/3-0-x/en/user-guide/management/personal-account-management", - "versions/3-0-x/en/user-guide/management/version-control" - ] - } - ] - } - ] - }, - { - "language": "ja", - "default": true, - "href": "versions/3-2-x/ja/user-guide/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/3-2-x/ja/user-guide/introduction", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/ja/user-guide/workflow/debug-and-preview/history", - "versions/3-2-x/ja/user-guide/workflow/debug-and-preview/variable-inspect" - ] - } - ] - }, - { - "group": "アプリのリリース", - "pages": [ - "versions/2-8-x/ja/user-guide/application-publishing/permission-management", - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - }, - { - "group": "監視", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/analysis", - "versions/legacy/ja/user-guide/monitoring/logs", - "versions/legacy/ja/user-guide/monitoring/annotation-reply", - { - "group": "外部Opsツールの統合", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "version": "3.0.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "versions/3-0-x/zh/user-guide/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/3-0-x/zh/user-guide/introduction", - { - "group": "接入大模型", - "pages": [ - "versions/3-0-x/zh/user-guide/model-configuration/readme", - "versions/3-0-x/zh/user-guide/model-configuration/new-provider", - "versions/3-0-x/zh/user-guide/model-configuration/predefined-model", - "versions/3-0-x/zh/user-guide/model-configuration/customizable-model", - "versions/3-0-x/zh/user-guide/model-configuration/interfaces", - "versions/3-0-x/zh/user-guide/model-configuration/schema", - "versions/3-0-x/zh/user-guide/model-configuration/load-balancing" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/readme", - "versions/3-0-x/zh/user-guide/application-orchestrate/creating-an-application", - { - "group": "聊天助手", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/chatbot-application", - "versions/3-0-x/zh/user-guide/application-orchestrate/multiple-llms-debugging" - ] - }, - "versions/3-0-x/zh/user-guide/application-orchestrate/agent", - { - "group": "应用工具箱", - "pages": [ - "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/readme", - "versions/3-0-x/zh/user-guide/application-orchestrate/app-toolkits/moderation-tool" - ] - } - ] - }, - { - "group": "工作流", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/readme", - "versions/3-0-x/zh/user-guide/workflow/key-concept", - "versions/3-0-x/zh/user-guide/workflow/variables", - { - "group": "节点说明", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/node/start", - "versions/3-0-x/zh/user-guide/workflow/node/llm", - "versions/3-0-x/zh/user-guide/workflow/node/knowledge-retrieval", - "versions/3-0-x/zh/user-guide/workflow/node/question-classifier", - "versions/3-0-x/zh/user-guide/workflow/node/ifelse", - "versions/3-0-x/zh/user-guide/workflow/node/code", - "versions/3-0-x/zh/user-guide/workflow/node/template", - "versions/3-0-x/zh/user-guide/workflow/node/doc-extractor", - "versions/3-0-x/zh/user-guide/workflow/node/list-operator", - "versions/3-0-x/zh/user-guide/workflow/node/variable-aggregator", - "versions/3-0-x/zh/user-guide/workflow/node/variable-assigner", - "versions/3-0-x/zh/user-guide/workflow/node/iteration", - "versions/3-0-x/zh/user-guide/workflow/node/parameter-extractor", - "versions/3-0-x/zh/user-guide/workflow/node/http-request", - "versions/3-0-x/zh/user-guide/workflow/node/agent", - "versions/3-0-x/zh/user-guide/workflow/node/tools", - "versions/3-0-x/zh/user-guide/workflow/node/end", - "versions/3-0-x/zh/user-guide/workflow/node/answer", - "versions/3-0-x/zh/user-guide/workflow/node/loop" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/shortcut-key", - "versions/3-0-x/zh/user-guide/workflow/orchestrate-node", - "versions/3-0-x/zh/user-guide/workflow/file-upload", - { - "group": "异常处理", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/error-handling/readme", - "versions/3-0-x/zh/user-guide/workflow/error-handling/predefined-nodes-failure-logic", - "versions/3-0-x/zh/user-guide/workflow/error-handling/error-type" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/additional-feature", - { - "group": "预览与调试", - "pages": [ - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/zh/user-guide/workflow/debug-and-preview/step-run" - ] - }, - "versions/3-0-x/zh/user-guide/workflow/publish", - "versions/3-0-x/zh/user-guide/workflow/structured-outputs", - "versions/3-0-x/zh/user-guide/workflow/bulletin" - ] - }, - { - "group": "知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/readme", - { - "group": "创建知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-base-creation/introduction", - { - "group": "1. 导入文本数据", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" - ] - }, - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", - "versions/3-0-x/zh/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" - ] - }, - { - "group": "管理知识库", - "pages": [ - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" - ] - }, - "versions/3-0-x/zh/user-guide/knowledge-base/metadata", - "versions/3-0-x/zh/user-guide/knowledge-base/integrate-knowledge-within-application", - "versions/3-0-x/zh/user-guide/knowledge-base/retrieval-test-and-citation", - "versions/3-0-x/zh/user-guide/knowledge-base/knowledge-request-rate-limit", - "versions/3-0-x/zh/user-guide/knowledge-base/connect-external-knowledge-base", - "versions/3-0-x/zh/user-guide/knowledge-base/api-documentation/external-knowledge-api-documentation" - ] - }, - { - "group": "工具", - "pages": [ - "versions/3-0-x/zh/user-guide/tools/readme", - "versions/3-0-x/zh/user-guide/tools/quick-tool-integration", - "versions/3-0-x/zh/user-guide/tools/advanced-tool-integration", - { - "group": "工具配置详情", - "pages": [ - "versions/3-0-x/zh/user-guide/tools/tool-configuration/google", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/bing", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/searchapi", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/stable-diffusion", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/dall-e", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/perplexity", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/alphavantage", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/searxng", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/serper", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/siliconflow", - "versions/3-0-x/zh/user-guide/tools/tool-configuration/comfyui" - ] - } - ] - }, - { - "group": "发布", - "pages": [ - "versions/2-8-x/zh/user-guide/application-publishing/permission-management", - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/readme", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/3-0-x/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/3-0-x/zh/user-guide/application-publishing/embedding-in-websites", - "versions/3-0-x/zh/user-guide/application-publishing/developing-with-apis", - "versions/3-0-x/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "标注", - "pages": [ - "versions/3-0-x/zh/user-guide/annotation/logs", - "versions/3-0-x/zh/user-guide/annotation/annotation-reply" - ] - }, - { - "group": "监测", - "pages": [ - "versions/3-0-x/zh/user-guide/monitoring/README", - { - "group": "集成外部与 Ops 工具", - "pages": [ - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/readme", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-weave", - "versions/3-0-x/zh/user-guide/monitoring/integrate-external-ops-tools/integrate-aliyun" - ] - }, - "versions/3-0-x/zh/user-guide/monitoring/analysis" - ] - }, - { - "group": "管理", - "pages": [ - "versions/3-0-x/zh/user-guide/management/app-management", - "versions/3-0-x/zh/user-guide/management/team-members-management", - "versions/3-0-x/zh/user-guide/management/personal-account-management", - "versions/3-0-x/zh/user-guide/management/subscription-management", - "versions/3-0-x/zh/user-guide/management/version-control" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "versions/3-0-x/en/user-guide/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/3-0-x/en/user-guide/introduction", - { - "group": "Model Configuration", - "pages": [ - "versions/3-0-x/en/user-guide/model-configuration/readme", - "versions/3-0-x/en/user-guide/model-configuration/new-provider", - "versions/3-0-x/en/user-guide/model-configuration/predefined-model", - "versions/3-0-x/en/user-guide/model-configuration/customizable-model", - "versions/3-0-x/en/user-guide/model-configuration/interfaces", - "versions/3-0-x/en/user-guide/model-configuration/schema" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/3-0-x/en/user-guide/application-orchestrate/readme", - "versions/3-0-x/en/user-guide/application-orchestrate/creating-an-application", - "versions/3-0-x/en/user-guide/application-orchestrate/chatbot-application", - "versions/3-0-x/en/user-guide/application-orchestrate/multiple-llms-debugging", - "versions/3-0-x/en/user-guide/application-orchestrate/text-generator", - "versions/3-0-x/en/user-guide/application-orchestrate/agent", - { - "group": "Application Toolkits", - "pages": [ - "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/readme", - "versions/3-0-x/en/user-guide/application-orchestrate/app-toolkits/moderation-tool" - ] - } - ] - }, - { - "group": "Workflow", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/README", - "versions/3-0-x/en/user-guide/workflow/key-concepts", - "versions/3-0-x/en/user-guide/workflow/variables", - { - "group": "Node Description", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/node/start", - "versions/3-0-x/en/user-guide/workflow/node/end", - "versions/3-0-x/en/user-guide/workflow/node/answer", - "versions/3-0-x/en/user-guide/workflow/node/llm", - "versions/3-0-x/en/user-guide/workflow/node/knowledge-retrieval", - "versions/3-0-x/en/user-guide/workflow/node/question-classifier", - "versions/3-0-x/en/user-guide/workflow/node/ifelse", - "versions/3-0-x/en/user-guide/workflow/node/code", - "versions/3-0-x/en/user-guide/workflow/node/template", - "versions/3-0-x/en/user-guide/workflow/node/doc-extractor", - "versions/3-0-x/en/user-guide/workflow/node/list-operator", - "versions/3-0-x/en/user-guide/workflow/node/variable-aggregator", - "versions/3-0-x/en/user-guide/workflow/node/variable-assigner", - "versions/3-0-x/en/user-guide/workflow/node/iteration", - "versions/3-0-x/en/user-guide/workflow/node/parameter-extractor", - "versions/3-0-x/en/user-guide/workflow/node/http-request", - "versions/3-0-x/en/user-guide/workflow/node/agent", - "versions/3-0-x/en/user-guide/workflow/node/tools", - "versions/3-0-x/en/user-guide/workflow/node/loop" - ] - }, - "versions/3-0-x/en/user-guide/workflow/shortcut-key", - "versions/3-0-x/en/user-guide/workflow/orchestrate-node", - "versions/3-0-x/en/user-guide/workflow/file-upload", - { - "group": "Error Handling", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/error-handling/README", - "versions/3-0-x/en/user-guide/workflow/error-handling/predefined-error-handling-logic", - "versions/3-0-x/en/user-guide/workflow/error-handling/error-type" - ] - }, - "versions/3-0-x/en/user-guide/workflow/additional-features", - { - "group": "Debug and Preview", - "pages": [ - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/preview-and-run", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/step-run", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/log", - "versions/3-0-x/en/user-guide/workflow/debug-and-preview/history" - ] - }, - "versions/3-0-x/en/user-guide/workflow/publish", - "versions/3-0-x/en/user-guide/workflow/structured-outputs" - ] - }, - { - "group": "Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/readme", - { - "group": "Create Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-base-creation/introduction", - { - "group": "1. Import Text Data", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/readme", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-notion", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website" - ] - }, - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/chunking-and-cleaning-text", - "versions/3-0-x/en/user-guide/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods" - ] - }, - { - "group": "Manage Knowledge", - "pages": [ - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/introduction", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-knowledge-documents", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-and-documents-maintenance/maintain-dataset-via-api" - ] - }, - "versions/3-0-x/en/user-guide/knowledge-base/metadata", - "versions/3-0-x/en/user-guide/knowledge-base/integrate-knowledge-within-application", - "versions/3-0-x/en/user-guide/knowledge-base/retrieval-test-and-citation", - "versions/3-0-x/en/user-guide/knowledge-base/knowledge-request-rate-limit", - "versions/3-0-x/en/user-guide/knowledge-base/connect-external-knowledge-base", - "versions/3-0-x/en/user-guide/knowledge-base/external-knowledge-api" - ] - }, - { - "group": "Publishing", - "pages": [ - "versions/2-8-x/en/user-guide/application-publishing/permission-management", - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/README", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/3-0-x/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/3-0-x/en/user-guide/application-publishing/embedding-in-websites", - "versions/3-0-x/en/user-guide/application-publishing/developing-with-apis", - "versions/3-0-x/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Annotation", - "pages": [ - "versions/3-0-x/en/user-guide/annotation/logs", - "versions/3-0-x/en/user-guide/annotation/annotation-reply" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/3-0-x/en/user-guide/monitoring/README", - "versions/3-0-x/en/user-guide/monitoring/analysis", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/README", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-opik", - "versions/3-0-x/en/user-guide/monitoring/integrate-external-ops-tools/integrate-weave" - ] - } - ] - }, - { - "group": "Extensions", - "pages": [ - { - "group": "API-Based Extension", - "pages": [ - "versions/3-0-x/en/user-guide/extension/api-based-extension/README", - "versions/3-0-x/en/user-guide/extension/api-based-extension/external-data-tool", - "versions/3-0-x/en/user-guide/extension/api-based-extension/cloudflare-workers", - "versions/3-0-x/en/user-guide/extension/api-based-extension/moderation" - ] - }, - { - "group": "Code-Based Extension", - "pages": [ - "versions/3-0-x/en/user-guide/extension/code-based-extension/README", - "versions/3-0-x/en/user-guide/extension/code-based-extension/external-data-tool", - "versions/3-0-x/en/user-guide/extension/code-based-extension/moderation" - ] - } - ] - }, - { - "group": "Management", - "pages": [ - "versions/3-0-x/en/user-guide/management/app-management", - "versions/3-0-x/en/user-guide/management/team-members-management", - "versions/3-0-x/en/user-guide/management/personal-account-management", - "versions/3-0-x/en/user-guide/management/version-control" - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "versions/3-0-x/ja/user-guide/introduction", - "groups": [ - { - "group": "ユーザーマニュアル", - "pages": [ - "versions/3-0-x/ja/user-guide/introduction", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "アプリのリリース", - "pages": [ - "versions/2-8-x/ja/user-guide/application-publishing/permission-management", - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - }, - { - "group": "監視", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/analysis", - "versions/legacy/ja/user-guide/monitoring/logs", - "versions/legacy/ja/user-guide/monitoring/annotation-reply", - { - "group": "外部Opsツールの統合", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "version": "2.8.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "/zh/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/legacy/zh/user-guide/welcome", - { - "group": "接入模型", - "pages": [ - "versions/legacy/zh/user-guide/models/model-configuration", - "versions/legacy/zh/user-guide/models/new-provider", - "versions/legacy/zh/user-guide/models/predefined-model", - "versions/legacy/zh/user-guide/models/customizable-model", - "versions/legacy/zh/user-guide/models/interfaces", - "versions/legacy/zh/user-guide/models/schema", - "versions/legacy/zh/user-guide/models/load-balancing" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/legacy/zh/user-guide/build-app/chatbot", - "versions/legacy/zh/user-guide/build-app/text-generator", - "versions/legacy/zh/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/concepts", - "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/zh/user-guide/build-app/flow-app/variables", - { - "group": "节点说明", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", - "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "调试应用", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "发布应用", - "pages": [ - "versions/2-8-x/zh/user-guide/application-publishing/permission-management", - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", - "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/zh/user-guide/management/app-management", - "versions/legacy/zh/user-guide/management/team-members-management", - "versions/legacy/zh/user-guide/management/personal-account-management" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "/en/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/legacy/en/user-guide/welcome", - { - "group": "Model", - "pages": [ - "versions/legacy/en/user-guide/models/model-configuration", - "versions/legacy/en/user-guide/models/new-provider", - "versions/legacy/en/user-guide/models/predefined-model", - "versions/legacy/en/user-guide/models/customizable-model", - "versions/legacy/en/user-guide/models/interfaces", - "versions/legacy/en/user-guide/models/schema", - "versions/legacy/en/user-guide/models/load-balancing" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/legacy/en/user-guide/build-app/chatbot", - "versions/legacy/en/user-guide/build-app/text-generator", - "versions/legacy/en/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/concepts", - "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/en/user-guide/build-app/flow-app/variables", - { - "group": "Nodes", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", - "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/en/user-guide/build-app/flow-app/file-upload", - "versions/legacy/en/user-guide/build-app/flow-app/additional-features" - ] - } - ] - }, - { - "group": "Debug and Preview", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "Application Publishing", - "pages": [ - "versions/2-8-x/en/user-guide/application-publishing/permission-management", - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/en/user-guide/application-publishing/developing-with-apis", - "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Management", - "pages": [ - "versions/legacy/en/user-guide/management/app-management", - "versions/legacy/en/user-guide/management/team-members-management", - "versions/legacy/en/user-guide/management/personal-account-management" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/legacy/en/user-guide/monitoring/analysis", - "versions/legacy/en/user-guide/monitoring/logs", - "versions/legacy/en/user-guide/monitoring/annotation-reply", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "/ja/introduction", - "groups": [ - { - "group": "ユーザーマニュアル", - "pages": [ - "versions/legacy/ja/user-guide/welcome", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "アプリのリリース", - "pages": [ - "versions/2-8-x/ja/user-guide/application-publishing/permission-management", - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - }, - { - "group": "監視", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/analysis", - "versions/legacy/ja/user-guide/monitoring/logs", - "versions/legacy/ja/user-guide/monitoring/annotation-reply", - { - "group": "外部Opsツールの統合", - "pages": [ - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/ja/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - } - ] - }, - { - "version": "2.7.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "/zh/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/legacy/zh/user-guide/welcome", - { - "group": "接入模型", - "pages": [ - "versions/legacy/zh/user-guide/models/model-configuration", - "versions/legacy/zh/user-guide/models/new-provider", - "versions/legacy/zh/user-guide/models/predefined-model", - "versions/legacy/zh/user-guide/models/customizable-model", - "versions/legacy/zh/user-guide/models/interfaces", - "versions/legacy/zh/user-guide/models/schema", - "versions/legacy/zh/user-guide/models/load-balancing" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/legacy/zh/user-guide/build-app/chatbot", - "versions/legacy/zh/user-guide/build-app/text-generator", - "versions/legacy/zh/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/concepts", - "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/zh/user-guide/build-app/flow-app/variables", - { - "group": "节点说明", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", - "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "调试应用", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "发布应用", - "pages": [ - "versions/legacy/zh/user-guide/application-publishing/permission-management", - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", - "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/zh/user-guide/management/app-management", - "versions/legacy/zh/user-guide/management/team-members-management", - "versions/legacy/zh/user-guide/management/personal-account-management" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "/en/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/legacy/en/user-guide/welcome", - { - "group": "Model", - "pages": [ - "versions/legacy/en/user-guide/models/model-configuration", - "versions/legacy/en/user-guide/models/new-provider", - "versions/legacy/en/user-guide/models/predefined-model", - "versions/legacy/en/user-guide/models/customizable-model", - "versions/legacy/en/user-guide/models/interfaces", - "versions/legacy/en/user-guide/models/schema", - "versions/legacy/en/user-guide/models/load-balancing" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/legacy/en/user-guide/build-app/chatbot", - "versions/legacy/en/user-guide/build-app/text-generator", - "versions/legacy/en/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/concepts", - "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/en/user-guide/build-app/flow-app/variables", - { - "group": "Nodes", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", - "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/en/user-guide/build-app/flow-app/file-upload", - "versions/legacy/en/user-guide/build-app/flow-app/additional-features" - ] - } - ] - }, - { - "group": "Debug and Preview", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "Application Publishing", - "pages": [ - "versions/legacy/en/user-guide/application-publishing/permission-management", - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/en/user-guide/application-publishing/developing-with-apis", - "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Management", - "pages": [ - "versions/legacy/en/user-guide/management/app-management", - "versions/legacy/en/user-guide/management/team-members-management", - "versions/legacy/en/user-guide/management/personal-account-management" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/legacy/en/user-guide/monitoring/analysis", - "versions/legacy/en/user-guide/monitoring/logs", - "versions/legacy/en/user-guide/monitoring/annotation-reply", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "/ja/introduction", - "groups": [ - { - "group": "ユーザーマニュアル", - "pages": [ - "versions/legacy/ja/user-guide/welcome", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "アプリのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/permission-management", - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - } - ] - } - ] - } - ] - }, - { - "version": "2.6.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "/zh/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/legacy/zh/user-guide/welcome", - { - "group": "接入模型", - "pages": [ - "versions/legacy/zh/user-guide/models/model-configuration", - "versions/legacy/zh/user-guide/models/new-provider", - "versions/legacy/zh/user-guide/models/predefined-model", - "versions/legacy/zh/user-guide/models/customizable-model", - "versions/legacy/zh/user-guide/models/interfaces", - "versions/legacy/zh/user-guide/models/schema", - "versions/legacy/zh/user-guide/models/load-balancing" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/legacy/zh/user-guide/build-app/chatbot", - "versions/legacy/zh/user-guide/build-app/text-generator", - "versions/legacy/zh/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/concepts", - "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/zh/user-guide/build-app/flow-app/variables", - { - "group": "节点说明", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", - "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "调试应用", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "发布应用", - "pages": [ - "versions/legacy/zh/user-guide/application-publishing/permission-management", - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", - "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/zh/user-guide/management/app-management", - "versions/legacy/zh/user-guide/management/team-members-management", - "versions/legacy/zh/user-guide/management/personal-account-management" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "/en/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/legacy/en/user-guide/welcome", - { - "group": "Model", - "pages": [ - "versions/legacy/en/user-guide/models/model-configuration", - "versions/legacy/en/user-guide/models/new-provider", - "versions/legacy/en/user-guide/models/predefined-model", - "versions/legacy/en/user-guide/models/customizable-model", - "versions/legacy/en/user-guide/models/interfaces", - "versions/legacy/en/user-guide/models/schema", - "versions/legacy/en/user-guide/models/load-balancing" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/legacy/en/user-guide/build-app/chatbot", - "versions/legacy/en/user-guide/build-app/text-generator", - "versions/legacy/en/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/concepts", - "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/en/user-guide/build-app/flow-app/variables", - { - "group": "Nodes", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", - "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/en/user-guide/build-app/flow-app/file-upload", - "versions/legacy/en/user-guide/build-app/flow-app/additional-features" - ] - } - ] - }, - { - "group": "Debug and Preview", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "Application Publishing", - "pages": [ - "versions/legacy/en/user-guide/application-publishing/permission-management", - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/en/user-guide/application-publishing/developing-with-apis", - "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Management", - "pages": [ - "versions/legacy/en/user-guide/management/app-management", - "versions/legacy/en/user-guide/management/team-members-management", - "versions/legacy/en/user-guide/management/personal-account-management" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/legacy/en/user-guide/monitoring/analysis", - "versions/legacy/en/user-guide/monitoring/logs", - "versions/legacy/en/user-guide/monitoring/annotation-reply", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "/ja/introduction", - "groups": [ - { - "group": "ユーザーマニュアル", - "pages": [ - "versions/legacy/ja/user-guide/welcome", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "アプリのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/permission-management", - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - } - ] - } - ] - } - ] - }, - { - "version": "2.5.x (Enterprise)", - "languages": [ - { - "language": "zh", - "href": "/zh/introduction", - "groups": [ - { - "group": "用户手册", - "pages": [ - "versions/legacy/zh/user-guide/welcome", - { - "group": "接入模型", - "pages": [ - "versions/legacy/zh/user-guide/models/model-configuration", - "versions/legacy/zh/user-guide/models/new-provider", - "versions/legacy/zh/user-guide/models/predefined-model", - "versions/legacy/zh/user-guide/models/customizable-model", - "versions/legacy/zh/user-guide/models/interfaces", - "versions/legacy/zh/user-guide/models/schema", - "versions/legacy/zh/user-guide/models/load-balancing" - ] - }, - { - "group": "构建应用", - "pages": [ - "versions/legacy/zh/user-guide/build-app/chatbot", - "versions/legacy/zh/user-guide/build-app/text-generator", - "versions/legacy/zh/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/concepts", - "versions/legacy/zh/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/zh/user-guide/build-app/flow-app/variables", - { - "group": "节点说明", - "pages": [ - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/zh/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/zh/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/zh/user-guide/build-app/flow-app/file-upload", - "versions/legacy/zh/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "调试应用", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/zh/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "发布应用", - "pages": [ - { - "group": "发布为公开 Web 站点", - "pages": [ - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/zh/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/zh/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/zh/user-guide/application-publishing/developing-with-apis", - "versions/legacy/zh/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/zh/user-guide/management/app-management", - "versions/legacy/zh/user-guide/management/team-members-management", - "versions/legacy/zh/user-guide/management/personal-account-management" - ] - } - ] - } - ] - }, - { - "language": "en", - "default": true, - "href": "/en/introduction", - "groups": [ - { - "group": "User Guide", - "pages": [ - "versions/legacy/en/user-guide/welcome", - { - "group": "Model", - "pages": [ - "versions/legacy/en/user-guide/models/model-configuration", - "versions/legacy/en/user-guide/models/new-provider", - "versions/legacy/en/user-guide/models/predefined-model", - "versions/legacy/en/user-guide/models/customizable-model", - "versions/legacy/en/user-guide/models/interfaces", - "versions/legacy/en/user-guide/models/schema", - "versions/legacy/en/user-guide/models/load-balancing" - ] - }, - { - "group": "Application Orchestration", - "pages": [ - "versions/legacy/en/user-guide/build-app/chatbot", - "versions/legacy/en/user-guide/build-app/text-generator", - "versions/legacy/en/user-guide/build-app/agent", - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/concepts", - "versions/legacy/en/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/en/user-guide/build-app/flow-app/variables", - { - "group": "Nodes", - "pages": [ - "versions/legacy/en/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/en/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/en/user-guide/build-app/flow-app/shotcut-key", - "versions/legacy/en/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/en/user-guide/build-app/flow-app/file-upload", - "versions/legacy/en/user-guide/build-app/flow-app/additional-features" - ] - } - ] - }, - { - "group": "Debug and Preview", - "pages": [ - { - "group": "Chatflow & Workflow", - "pages": [ - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/en/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "Application Publishing", - "pages": [ - { - "group": "Publish as a Single-page Web App", - "pages": [ - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/en/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/en/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/en/user-guide/application-publishing/developing-with-apis", - "versions/legacy/en/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "Management", - "pages": [ - "versions/legacy/en/user-guide/management/app-management", - "versions/legacy/en/user-guide/management/team-members-management", - "versions/legacy/en/user-guide/management/personal-account-management" - ] - }, - { - "group": "Monitoring", - "pages": [ - "versions/legacy/en/user-guide/monitoring/analysis", - "versions/legacy/en/user-guide/monitoring/logs", - "versions/legacy/en/user-guide/monitoring/annotation-reply", - { - "group": "Integrate External Ops Tools", - "pages": [ - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langfuse", - "versions/legacy/en/user-guide/monitoring/integrate-external-ops-tools/integrate-langsmith" - ] - } - ] - } - ] - } - ] - }, - { - "language": "ja", - "href": "/ja/introduction", - "groups": [ - { - "group": "ユーザーマニュアル", - "pages": [ - "versions/legacy/ja/user-guide/welcome", - { - "group": "モデルの接続", - "pages": [ - "versions/legacy/ja/user-guide/models/model-configuration", - "versions/legacy/ja/user-guide/models/new-provider", - "versions/legacy/ja/user-guide/models/predefined-model", - "versions/legacy/ja/user-guide/models/customizable-model", - "versions/legacy/ja/user-guide/models/interfaces", - "versions/legacy/ja/user-guide/models/schema", - "versions/legacy/ja/user-guide/models/load-balancing" - ] - }, - { - "group": "アプリの構築", - "pages": [ - "versions/legacy/ja/user-guide/build-app/chatbot", - "versions/legacy/ja/user-guide/build-app/text-generator", - "versions/legacy/ja/user-guide/build-app/agent", - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/concepts", - "versions/legacy/ja/user-guide/build-app/flow-app/create-flow-app", - "versions/legacy/ja/user-guide/build-app/flow-app/variables", - { - "group": "ノードの説明", - "pages": [ - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/start", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/end", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/answer", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/llm", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/knowledge-retrieval", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/question-classifier", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/ifelse", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/code", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/template", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/doc-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/list-operator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-aggregator", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/variable-assigner", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/iteration", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/parameter-extractor", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/http-request", - "versions/legacy/ja/user-guide/build-app/flow-app/nodes/tools" - ] - }, - "versions/legacy/ja/user-guide/build-app/flow-app/orchestrate-node", - "versions/legacy/ja/user-guide/build-app/flow-app/file-upload", - "versions/legacy/ja/user-guide/build-app/flow-app/additional-feature" - ] - } - ] - }, - { - "group": "アプリのデバッグ", - "pages": [ - { - "group": "チャットフロー & ワークフロー", - "pages": [ - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/preview-and-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/step-run", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/log", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/checklist", - "versions/legacy/ja/user-guide/debug-app/chatflow-and-workflow/history" - ] - } - ] - }, - { - "group": "アプリのリリース", - "pages": [ - { - "group": "公開Webアプリとしてのリリース", - "pages": [ - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/web-app-settings", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/text-generator", - "versions/legacy/ja/user-guide/application-publishing/launch-your-webapp-quickly/conversation-application" - ] - }, - "versions/legacy/ja/user-guide/application-publishing/embedding-in-websites", - "versions/legacy/ja/user-guide/application-publishing/developing-with-apis", - "versions/legacy/ja/user-guide/application-publishing/based-on-frontend-templates" - ] - }, - { - "group": "管理", - "pages": [ - "versions/legacy/ja/user-guide/management/app-management", - "versions/legacy/ja/user-guide/management/team-members-management", - "versions/legacy/ja/user-guide/management/personal-account-management" - ] - } - ] - } - ] - } - ] - } - ] + { + "source": "/en/guides/workflow/node/trigger", + "destination": "/en/use-dify/nodes/trigger/overview" }, - "contextual": { - "options": [ - "copy" - ] + { + "source": "/en/guides/workflow/node/schedule-trigger", + "destination": "/en/use-dify/nodes/trigger/schedule-trigger" }, - "redirects": [ - { - "source": "/en/guides/workflow/node/start", - "destination": "/en/use-dify/getting-started/key-concepts#workflow" - }, - { - "source": "/en/guides/workflow/node/user-input", - "destination": "/en/use-dify/nodes/user-input" - }, - { - "source": "/en/guides/workflow/node/trigger", - "destination": "/en/use-dify/nodes/trigger/overview" - }, - { - "source": "/en/guides/workflow/node/schedule-trigger", - "destination": "/en/use-dify/nodes/trigger/schedule-trigger" - }, - { - "source": "/en/guides/workflow/node/webhook-trigger", - "destination": "/en/use-dify/nodes/trigger/webhook-trigger" - }, - { - "source": "/en/guides/workflow/node/plugin-trigger", - "destination": "/en/use-dify/nodes/trigger/plugin-trigger" - }, - { - "source": "/en/guides/workflow/node/knowledge-retrieval", - "destination": "/en/use-dify/nodes/knowledge-retrieval" - }, - { - "source": "/en/guides/workflow/node/agent", - "destination": "/en/use-dify/nodes/agent" - }, - { - "source": "/en/guides/workflow/node/question-classifier", - "destination": "/en/use-dify/nodes/question-classifier" - }, - { - "source": "/en/guides/workflow/node/ifelse", - "destination": "/en/use-dify/nodes/ifelse" - }, - { - "source": "/en/guides/workflow/node/iteration", - "destination": "/en/use-dify/nodes/iteration" - }, - { - "source": "/en/guides/workflow/node/loop", - "destination": "/en/use-dify/nodes/loop" - }, - { - "source": "/en/guides/workflow/node/code", - "destination": "/en/use-dify/nodes/code" - }, - { - "source": "/en/guides/workflow/node/template", - "destination": "/en/use-dify/nodes/template" - }, - { - "source": "/en/guides/workflow/node/variable-aggregator", - "destination": "/en/use-dify/nodes/variable-aggregator" - }, - { - "source": "/en/guides/workflow/node/doc-extractor", - "destination": "/en/use-dify/nodes/doc-extractor" - }, - { - "source": "/en/guides/workflow/node/variable-assigner", - "destination": "/en/use-dify/nodes/variable-assigner" - }, - { - "source": "/en/guides/workflow/node/parameter-extractor", - "destination": "/en/use-dify/nodes/parameter-extractor" - }, - { - "source": "/en/guides/workflow/node/http-request", - "destination": "/en/use-dify/nodes/http-request" - }, - { - "source": "/en/guides/workflow/node/list-operator", - "destination": "/en/use-dify/nodes/list-operator" - }, - { - "source": "/en/guides/workflow/node/tools", - "destination": "/en/use-dify/nodes/tools" - }, - { - "source": "/en/guides/workflow/node/end", - "destination": "/en/use-dify/nodes/output" - }, - { - "source": "/en/guides/workflow/node/llm", - "destination": "/en/use-dify/nodes/llm" - }, - { - "source": "/zh-hans/guides/workflow/node/start", - "destination": "/zh/use-dify/getting-started/key-concepts#工作流" - }, - { - "source": "/zh-hans/guides/workflow/node/user-input", - "destination": "/zh/use-dify/nodes/user-input" - }, - { - "source": "/zh-hans/guides/workflow/node/trigger", - "destination": "/zh/use-dify/nodes/trigger/overview" - }, - { - "source": "/zh-hans/guides/workflow/node/schedule-trigger", - "destination": "/zh/use-dify/nodes/trigger/schedule-trigger" - }, - { - "source": "/zh-hans/guides/workflow/node/webhook-trigger", - "destination": "/zh/use-dify/nodes/trigger/webhook-trigger" - }, - { - "source": "/zh-hans/guides/workflow/node/plugin-trigger", - "destination": "/zh/use-dify/nodes/trigger/plugin-trigger" - }, - { - "source": "/zh-hans/guides/workflow/node/knowledge-retrieval", - "destination": "/zh/use-dify/nodes/knowledge-retrieval" - }, - { - "source": "/zh-hans/guides/workflow/node/agent", - "destination": "/zh/use-dify/nodes/agent" - }, - { - "source": "/zh-hans/guides/workflow/node/question-classifier", - "destination": "/zh/use-dify/nodes/question-classifier" - }, - { - "source": "/zh-hans/guides/workflow/node/ifelse", - "destination": "/zh/use-dify/nodes/ifelse" - }, - { - "source": "/zh-hans/guides/workflow/node/iteration", - "destination": "/zh/use-dify/nodes/iteration" - }, - { - "source": "/zh-hans/guides/workflow/node/loop", - "destination": "/zh/use-dify/nodes/loop" - }, - { - "source": "/zh-hans/guides/workflow/node/code", - "destination": "/zh/use-dify/nodes/code" - }, - { - "source": "/zh-hans/guides/workflow/node/template", - "destination": "/zh/use-dify/nodes/template" - }, - { - "source": "/zh-hans/guides/workflow/node/variable-aggregator", - "destination": "/zh/use-dify/nodes/variable-aggregator" - }, - { - "source": "/zh-hans/guides/workflow/node/doc-extractor", - "destination": "/zh/use-dify/nodes/doc-extractor" - }, - { - "source": "/zh-hans/guides/workflow/node/variable-assigner", - "destination": "/zh/use-dify/nodes/variable-assigner" - }, - { - "source": "/zh-hans/guides/workflow/node/parameter-extractor", - "destination": "/zh/use-dify/nodes/parameter-extractor" - }, - { - "source": "/zh-hans/guides/workflow/node/http-request", - "destination": "/zh/use-dify/nodes/http-request" - }, - { - "source": "/zh-hans/guides/workflow/node/list-operator", - "destination": "/zh/use-dify/nodes/list-operator" - }, - { - "source": "/zh-hans/guides/workflow/node/tools", - "destination": "/zh/use-dify/nodes/tools" - }, - { - "source": "/zh-hans/guides/workflow/node/end", - "destination": "/zh/use-dify/nodes/output" - }, - { - "source": "/zh-hans/guides/workflow/node/llm", - "destination": "/zh/use-dify/nodes/llm" - }, - { - "source": "/ja-jp/guides/workflow/node/start", - "destination": "/ja/use-dify/getting-started/key-concepts#ワークフロー" - }, - { - "source": "/ja-jp/guides/workflow/node/user-input", - "destination": "/ja/use-dify/nodes/user-input" - }, - { - "source": "/ja-jp/guides/workflow/node/trigger", - "destination": "/ja/use-dify/nodes/trigger/overview" - }, - { - "source": "/ja-jp/guides/workflow/node/schedule-trigger", - "destination": "/ja/use-dify/nodes/trigger/schedule-trigger" - }, - { - "source": "/ja-jp/guides/workflow/node/webhook-trigger", - "destination": "/ja/use-dify/nodes/trigger/webhook-trigger" - }, - { - "source": "/ja-jp/guides/workflow/node/plugin-trigger", - "destination": "/ja/use-dify/nodes/trigger/plugin-trigger" - }, - { - "source": "/ja-jp/guides/workflow/node/knowledge-retrieval", - "destination": "/ja/use-dify/nodes/knowledge-retrieval" - }, - { - "source": "/ja-jp/guides/workflow/node/agent", - "destination": "/ja/use-dify/nodes/agent" - }, - { - "source": "/ja-jp/guides/workflow/node/question-classifier", - "destination": "/ja/use-dify/nodes/question-classifier" - }, - { - "source": "/ja-jp/guides/workflow/node/ifelse", - "destination": "/ja/use-dify/nodes/ifelse" - }, - { - "source": "/ja-jp/guides/workflow/node/iteration", - "destination": "/ja/use-dify/nodes/iteration" - }, - { - "source": "/ja-jp/guides/workflow/node/loop", - "destination": "/ja/use-dify/nodes/loop" - }, - { - "source": "/ja-jp/guides/workflow/node/code", - "destination": "/ja/use-dify/nodes/code" - }, - { - "source": "/ja-jp/guides/workflow/node/template", - "destination": "/ja/use-dify/nodes/template" - }, - { - "source": "/ja-jp/guides/workflow/node/variable-aggregator", - "destination": "/ja/use-dify/nodes/variable-aggregator" - }, - { - "source": "/ja-jp/guides/workflow/node/doc-extractor", - "destination": "/ja/use-dify/nodes/doc-extractor" - }, - { - "source": "/ja-jp/guides/workflow/node/variable-assigner", - "destination": "/ja/use-dify/nodes/variable-assigner" - }, - { - "source": "/ja-jp/guides/workflow/node/parameter-extractor", - "destination": "/ja/use-dify/nodes/parameter-extractor" - }, - { - "source": "/ja-jp/guides/workflow/node/http-request", - "destination": "/ja/use-dify/nodes/http-request" - }, - { - "source": "/ja-jp/guides/workflow/node/list-operator", - "destination": "/ja/use-dify/nodes/list-operator" - }, - { - "source": "/ja-jp/guides/workflow/node/tools", - "destination": "/ja/use-dify/nodes/tools" - }, - { - "source": "/ja-jp/guides/workflow/node/end", - "destination": "/ja/use-dify/nodes/output" - }, - { - "source": "/ja-jp/guides/workflow/node/llm", - "destination": "/ja/use-dify/nodes/llm" - }, - { - "source": "/en/getting-started/dify-for-education", - "destination": "/en/use-dify/workspace/subscription-management#dify-for-education" - }, - { - "source": "/zh-hans/getting-started/dify-for-education", - "destination": "/zh/use-dify/workspace/subscription-management#dify-for-education" - }, - { - "source": "/ja-jp/getting-started/dify-for-education", - "destination": "/ja/use-dify/workspace/subscription-management#dify-for-education" - }, - { - "source": "/plugins/schema-definition/model", - "destination": "/versions/legacy/en/plugins/schema-definition/model/model-designing-rules" - }, - { - "source": "/plugins/schema-definition", - "destination": "/versions/legacy/en/plugins/schema-definition/manifest" - }, - { - "source": "/zh-hans", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/introduction", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/en/introduction", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/introduction", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/introduction", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/getting-started/readme/features-and-specifications", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/getting-started/readme/model-providers", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/getting-started/install-self-hosted", - "destination": "/en/self-host/quick-start/docker-compose" - }, - { - "source": "/getting-started/install-self-hosted/docker-compose", - "destination": "/en/self-host/quick-start/docker-compose" - }, - { - "source": "/getting-started/install-self-hosted/local-source-code", - "destination": "/en/self-host/advanced-deployments/local-source-code" - }, - { - "source": "/getting-started/install-self-hosted/bt-panel", - "destination": "/en/self-host/platform-guides/bt-panel" - }, - { - "source": "/getting-started/install-self-hosted/start-the-frontend-docker-container", - "destination": "/en/self-host/advanced-deployments/start-the-frontend-docker-container" - }, - { - "source": "/getting-started/install-self-hosted/environments", - "destination": "/en/self-host/configuration/environments" - }, - { - "source": "/getting-started/install-self-hosted/faqs", - "destination": "/en/self-host/quick-start/faqs" - }, - { - "source": "/getting-started/cloud", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/getting-started/dify-premium", - "destination": "/en/self-host/platform-guides/dify-premium" - }, - { - "source": "/zh-hans/guides/application-publishing/launch-your-webapp-quickly/readme", - "destination": "/zh/use-dify/publish/README" - }, - { - "source": "/ja-jp/guides/application-publishing/launch-your-webapp-quickly/readme", - "destination": "/ja/use-dify/publish/README" - }, - { - "source": "/en/guides/application-publishing/launch-your-webapp-quickly/readme", - "destination": "/en/use-dify/publish/README" - }, - { - "source": "/plugins/:slug*", - "destination": "/plugin-dev-en/0111-getting-started-dify-plugin" - }, - { - "source": "/plugins/quick-start", - "destination": "/plugin-dev-en/0111-getting-started-dify-plugin" - }, - { - "source": "/plugins/quick-start/install-plugins", - "destination": "/plugin-dev-en/0111-getting-started-dify-plugin" - }, - { - "source": "/plugins/quick-start/develop-plugins", - "destination": "/plugin-dev-en/0131-cheatsheet" - }, - { - "source": "/plugins/quick-start/develop-plugins/initialize-development-tools", - "destination": "/plugin-dev-en/0221-initialize-development-tools" - }, - { - "source": "/plugins/quick-start/develop-plugins/tool-plugin", - "destination": "/plugin-dev-en/0222-tool-plugin" - }, - { - "source": "/plugins/quick-start/develop-plugins/model-plugin", - "destination": "/plugin-dev-en/0411-model-plugin-introduction" - }, - { - "source": "/plugins/quick-start/develop-plugins/model-plugin/create-model-providers", - "destination": "/plugin-dev-en/0222-creating-new-model-provider" - }, - { - "source": "/en/guides/workflow/node/:slug*", - "destination": "/en/use-dify/nodes/:slug*" - }, - { - "source": "/en/guides/workflow/debug-and-preview/:slug*", - "destination": "/en/use-dify/debug/:slug*" - }, - { - "source": "/en/guides/application-publishing/launch-your-webapp-quickly/:slug*", - "destination": "/en/use-dify/publish/webapp/:slug*" - }, - { - "source": "/en/guides/application-publishing/:slug*", - "destination": "/en/use-dify/publish/:slug*" - }, - { - "source": "/en/guides/annotation/:slug*", - "destination": "/en/use-dify/monitor/:slug*" - }, - { - "source": "/en/guides/monitoring/integrate-external-ops-tools/:slug*", - "destination": "/en/use-dify/monitor/integrations/:slug*" - }, - { - "source": "/en/guides/monitoring/:slug*", - "destination": "/en/use-dify/monitor/:slug*" - }, - { - "source": "/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/:slug*", - "destination": "/en/use-dify/knowledge/create-knowledge/import-text-data/:slug*" - }, - { - "source": "/en/guides/knowledge-base/create-knowledge-and-upload-documents/:slug*", - "destination": "/en/use-dify/knowledge/create-knowledge/:slug*" - }, - { - "source": "/en/guides/knowledge-base/knowledge-and-documents-maintenance/:slug*", - "destination": "/en/use-dify/knowledge/manage-knowledge/:slug*" - }, - { - "source": "/en/guides/knowledge-base/:slug*", - "destination": "/en/use-dify/knowledge/:slug*" - }, - { - "source": "/en/guides/management/:slug*", - "destination": "/en/use-dify/workspace/:slug*" - }, - { - "source": "/en/guides/model-configuration/:slug*", - "destination": "/en/use-dify/workspace/model-providers" - }, - { - "source": "/en/workshop/basic/:slug*", - "destination": "/en/use-dify/tutorials/:slug*" - }, - { - "source": "/en/workshop/intermediate/:slug*", - "destination": "/en/use-dify/tutorials/:slug*" - }, - { - "source": "/en/workshop/:slug*", - "destination": "/en/use-dify/tutorials/:slug*" - }, - { - "source": "/en/getting-started/install-self-hosted/:slug*", - "destination": "/en/self-host/dify-community/:slug*" - }, - { - "source": "/en/guides/workflow/:slug*", - "destination": "/en/use-dify/build/:slug*" - }, - { - "source": "/en/guides/application-orchestrate/app-toolkits/:slug*", - "destination": "/en/use-dify/nodes/tools" - }, - { - "source": "/en/guides/application-orchestrate/:slug*", - "destination": "/en/use-dify/getting-started/quick-start" - }, - { - "source": "/en/plugins/:slug*", - "destination": "/plugin-dev-en/0111-getting-started-dify-plugin" - }, - { - "source": "/en/development/backend/:slug*", - "destination": "/api-reference/:slug*" - }, - { - "source": "/en/development/:slug*", - "destination": "/plugin-dev-en/0111-getting-started-dify-plugin" - }, - { - "source": "/en/learn-more/extended-reading/retrieval-augment/:slug*", - "destination": "/en/use-dify/knowledge/:slug*" - }, - { - "source": "/en/learn-more/extended-reading/dify-docs-mcp", - "destination": "/en/use-dify/build/mcp" - }, - { - "source": "/en/learn-more/:slug*", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/en/guides/:slug*", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/en/getting-started/:slug*", - "destination": "/en/use-dify/getting-started/:slug*" - }, - { - "source": "/en/community/:slug*", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/en/resources/:slug*", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/en/policies/:slug*", - "destination": "/en/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/guides/workflow/node/:slug*", - "destination": "/ja/use-dify/nodes/:slug*" - }, - { - "source": "/ja-jp/guides/workflow/debug-and-preview/:slug*", - "destination": "/ja/use-dify/debug/:slug*" - }, - { - "source": "/ja-jp/guides/application-publishing/launch-your-webapp-quickly/:slug*", - "destination": "/ja/use-dify/publish/webapp/:slug*" - }, - { - "source": "/ja-jp/guides/application-publishing/:slug*", - "destination": "/ja/use-dify/publish/:slug*" - }, - { - "source": "/ja-jp/guides/annotation/:slug*", - "destination": "/ja/use-dify/monitor/:slug*" - }, - { - "source": "/ja-jp/guides/monitoring/integrate-external-ops-tools/:slug*", - "destination": "/ja/use-dify/monitor/integrations/:slug*" - }, - { - "source": "/ja-jp/guides/monitoring/:slug*", - "destination": "/ja/use-dify/monitor/:slug*" - }, - { - "source": "/ja-jp/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/:slug*", - "destination": "/ja/use-dify/knowledge/create-knowledge/import-text-data/:slug*" - }, - { - "source": "/ja-jp/guides/knowledge-base/create-knowledge-and-upload-documents/:slug*", - "destination": "/ja/use-dify/knowledge/create-knowledge/:slug*" - }, - { - "source": "/ja-jp/guides/knowledge-base/knowledge-and-documents-maintenance/:slug*", - "destination": "/ja/use-dify/knowledge/manage-knowledge/:slug*" - }, - { - "source": "/ja-jp/guides/knowledge-base/:slug*", - "destination": "/ja/use-dify/knowledge/:slug*" - }, - { - "source": "/ja-jp/guides/management/:slug*", - "destination": "/ja/use-dify/workspace/:slug*" - }, - { - "source": "/ja-jp/guides/model-configuration/:slug*", - "destination": "/ja/use-dify/workspace/model-providers" - }, - { - "source": "/ja-jp/workshop/basic/:slug*", - "destination": "/ja/use-dify/tutorials/:slug*" - }, - { - "source": "/ja-jp/workshop/intermediate/:slug*", - "destination": "/ja/use-dify/tutorials/:slug*" - }, - { - "source": "/ja-jp/workshop/:slug*", - "destination": "/ja/use-dify/tutorials/:slug*" - }, - { - "source": "/ja-jp/getting-started/install-self-hosted/:slug*", - "destination": "/ja/self-host/dify-community/:slug*" - }, - { - "source": "/ja-jp/guides/workflow/:slug*", - "destination": "/ja/use-dify/build/:slug*" - }, - { - "source": "/ja-jp/guides/application-orchestrate/app-toolkits/:slug*", - "destination": "/ja/use-dify/nodes/tools" - }, - { - "source": "/ja-jp/guides/application-orchestrate/:slug*", - "destination": "/ja/use-dify/getting-started/quick-start" - }, - { - "source": "/ja-jp/plugins/:slug*", - "destination": "/ja/use-dify/workspace/plugins" - }, - { - "source": "/ja-jp/development/backend/:slug*", - "destination": "/api-reference/:slug*" - }, - { - "source": "/ja-jp/development/models-integration/:slug*", - "destination": "/ja/use-dify/workspace/model-providers" - }, - { - "source": "/ja-jp/development/:slug*", - "destination": "/api-reference/:slug*" - }, - { - "source": "/ja-jp/learn-more/extended-reading/retrieval-augment/:slug*", - "destination": "/ja/use-dify/knowledge/:slug*" - }, - { - "source": "/ja-jp/learn-more/extended-reading/dify-docs-mcp", - "destination": "/ja/use-dify/build/mcp" - }, - { - "source": "/ja-jp/learn-more/faq/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/learn-more/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/guides/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/getting-started/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/community/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/resources/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/ja-jp/policies/:slug*", - "destination": "/ja/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/guides/workflow/node/:slug*", - "destination": "/zh/use-dify/nodes/:slug*" - }, - { - "source": "/zh-hans/guides/workflow/debug-and-preview/:slug*", - "destination": "/zh/use-dify/debug/:slug*" - }, - { - "source": "/zh-hans/guides/application-publishing/launch-your-webapp-quickly/:slug*", - "destination": "/zh/use-dify/publish/webapp/:slug*" - }, - { - "source": "/zh-hans/guides/application-publishing/:slug*", - "destination": "/zh/use-dify/publish/:slug*" - }, - { - "source": "/zh-hans/guides/annotation/:slug*", - "destination": "/zh/use-dify/monitor/:slug*" - }, - { - "source": "/zh-hans/guides/monitoring/integrate-external-ops-tools/:slug*", - "destination": "/zh/use-dify/monitor/integrations/:slug*" - }, - { - "source": "/zh-hans/guides/monitoring/:slug*", - "destination": "/zh/use-dify/monitor/:slug*" - }, - { - "source": "/zh-hans/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/:slug*", - "destination": "/zh/use-dify/knowledge/create-knowledge/import-text-data/:slug*" - }, - { - "source": "/zh-hans/guides/knowledge-base/create-knowledge-and-upload-documents/:slug*", - "destination": "/zh/use-dify/knowledge/create-knowledge/:slug*" - }, - { - "source": "/zh-hans/guides/knowledge-base/knowledge-and-documents-maintenance/:slug*", - "destination": "/zh/use-dify/knowledge/manage-knowledge/:slug*" - }, - { - "source": "/zh-hans/guides/knowledge-base/:slug*", - "destination": "/zh/use-dify/knowledge/:slug*" - }, - { - "source": "/zh-hans/guides/management/:slug*", - "destination": "/zh/use-dify/workspace/:slug*" - }, - { - "source": "/zh-hans/guides/model-configuration/:slug*", - "destination": "/zh/use-dify/workspace/model-providers" - }, - { - "source": "/zh-hans/workshop/basic/:slug*", - "destination": "/zh/use-dify/tutorials/:slug*" - }, - { - "source": "/zh-hans/workshop/intermediate/:slug*", - "destination": "/zh/use-dify/tutorials/:slug*" - }, - { - "source": "/zh-hans/workshop/:slug*", - "destination": "/zh/use-dify/tutorials/:slug*" - }, - { - "source": "/zh-hans/getting-started/install-self-hosted/:slug*", - "destination": "/zh/self-host/dify-community/:slug*" - }, - { - "source": "/zh-hans/guides/workflow/:slug*", - "destination": "/zh/use-dify/build/:slug*" - }, - { - "source": "/zh-hans/guides/application-orchestrate/app-toolkits/:slug*", - "destination": "/zh/use-dify/nodes/tools" - }, - { - "source": "/zh-hans/guides/application-orchestrate/:slug*", - "destination": "/zh/use-dify/getting-started/quick-start" - }, - { - "source": "/zh-hans/plugins/:slug*", - "destination": "/zh/use-dify/workspace/plugins" - }, - { - "source": "/zh-hans/development/backend/:slug*", - "destination": "/api-reference/:slug*" - }, - { - "source": "/zh-hans/development/models-integration/:slug*", - "destination": "/zh/use-dify/workspace/model-providers" - }, - { - "source": "/zh-hans/development/:slug*", - "destination": "/api-reference/:slug*" - }, - { - "source": "/zh-hans/learn-more/extended-reading/retrieval-augment/:slug*", - "destination": "/zh/use-dify/knowledge/:slug*" - }, - { - "source": "/zh-hans/learn-more/extended-reading/dify-docs-mcp", - "destination": "/zh/use-dify/build/mcp" - }, - { - "source": "/zh-hans/learn-more/faq/:slug*", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/learn-more/:slug*", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/guides/:slug*", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/getting-started/cloud", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/getting-started/dify-premium", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/community/:slug*", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/resources/:slug*", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/zh-hans/policies/:slug*", - "destination": "/zh/use-dify/getting-started/introduction" - }, - { - "source": "/use-dify/:slug*", - "destination": "/en/use-dify/:slug*" - }, - { - "source": "/self-host/:slug*", - "destination": "/en/self-host/:slug*" - }, - { - "source": "/en/guides/model-configuration/load-balancing", - "destination": "/en/use-dify/workspace/model-providers#configure-model-load-balancing" - }, - { - "source": "/guides/model-configuration/load-balancing", - "destination": "/en/use-dify/workspace/model-providers#configure-model-load-balancing" - }, - { - "source": "/zh-hans/guides/model-configuration/load-balancing", - "destination": "/zh/use-dify/workspace/model-providers#配置模型负载均衡" - }, - { - "source": "/ja-jp/guides/model-configuration/load-balancing", - "destination": "/ja/use-dify/workspace/model-providers#負荷分散の構成" + { + "source": "/en/guides/workflow/node/webhook-trigger", + "destination": "/en/use-dify/nodes/trigger/webhook-trigger" + }, + { + "source": "/en/guides/workflow/node/plugin-trigger", + "destination": "/en/use-dify/nodes/trigger/plugin-trigger" + }, + { + "source": "/en/guides/workflow/node/knowledge-retrieval", + "destination": "/en/use-dify/nodes/knowledge-retrieval" + }, + { + "source": "/en/guides/workflow/node/agent", + "destination": "/en/use-dify/nodes/agent" + }, + { + "source": "/en/guides/workflow/node/question-classifier", + "destination": "/en/use-dify/nodes/question-classifier" + }, + { + "source": "/en/guides/workflow/node/ifelse", + "destination": "/en/use-dify/nodes/ifelse" + }, + { + "source": "/en/guides/workflow/node/iteration", + "destination": "/en/use-dify/nodes/iteration" + }, + { + "source": "/en/guides/workflow/node/loop", + "destination": "/en/use-dify/nodes/loop" + }, + { + "source": "/en/guides/workflow/node/code", + "destination": "/en/use-dify/nodes/code" + }, + { + "source": "/en/guides/workflow/node/template", + "destination": "/en/use-dify/nodes/template" + }, + { + "source": "/en/guides/workflow/node/variable-aggregator", + "destination": "/en/use-dify/nodes/variable-aggregator" + }, + { + "source": "/en/guides/workflow/node/doc-extractor", + "destination": "/en/use-dify/nodes/doc-extractor" + }, + { + "source": "/en/guides/workflow/node/variable-assigner", + "destination": "/en/use-dify/nodes/variable-assigner" + }, + { + "source": "/en/guides/workflow/node/parameter-extractor", + "destination": "/en/use-dify/nodes/parameter-extractor" + }, + { + "source": "/en/guides/workflow/node/http-request", + "destination": "/en/use-dify/nodes/http-request" + }, + { + "source": "/en/guides/workflow/node/list-operator", + "destination": "/en/use-dify/nodes/list-operator" + }, + { + "source": "/en/guides/workflow/node/tools", + "destination": "/en/use-dify/nodes/tools" + }, + { + "source": "/en/guides/workflow/node/end", + "destination": "/en/use-dify/nodes/output" + }, + { + "source": "/en/guides/workflow/node/llm", + "destination": "/en/use-dify/nodes/llm" + }, + { + "source": "/zh-hans/guides/workflow/node/start", + "destination": "/zh/use-dify/getting-started/key-concepts#工作流" + }, + { + "source": "/zh-hans/guides/workflow/node/user-input", + "destination": "/zh/use-dify/nodes/user-input" + }, + { + "source": "/zh-hans/guides/workflow/node/trigger", + "destination": "/zh/use-dify/nodes/trigger/overview" + }, + { + "source": "/zh-hans/guides/workflow/node/schedule-trigger", + "destination": "/zh/use-dify/nodes/trigger/schedule-trigger" + }, + { + "source": "/zh-hans/guides/workflow/node/webhook-trigger", + "destination": "/zh/use-dify/nodes/trigger/webhook-trigger" + }, + { + "source": "/zh-hans/guides/workflow/node/plugin-trigger", + "destination": "/zh/use-dify/nodes/trigger/plugin-trigger" + }, + { + "source": "/zh-hans/guides/workflow/node/knowledge-retrieval", + "destination": "/zh/use-dify/nodes/knowledge-retrieval" + }, + { + "source": "/zh-hans/guides/workflow/node/agent", + "destination": "/zh/use-dify/nodes/agent" + }, + { + "source": "/zh-hans/guides/workflow/node/question-classifier", + "destination": "/zh/use-dify/nodes/question-classifier" + }, + { + "source": "/zh-hans/guides/workflow/node/ifelse", + "destination": "/zh/use-dify/nodes/ifelse" + }, + { + "source": "/zh-hans/guides/workflow/node/iteration", + "destination": "/zh/use-dify/nodes/iteration" + }, + { + "source": "/zh-hans/guides/workflow/node/loop", + "destination": "/zh/use-dify/nodes/loop" + }, + { + "source": "/zh-hans/guides/workflow/node/code", + "destination": "/zh/use-dify/nodes/code" + }, + { + "source": "/zh-hans/guides/workflow/node/template", + "destination": "/zh/use-dify/nodes/template" + }, + { + "source": "/zh-hans/guides/workflow/node/variable-aggregator", + "destination": "/zh/use-dify/nodes/variable-aggregator" + }, + { + "source": "/zh-hans/guides/workflow/node/doc-extractor", + "destination": "/zh/use-dify/nodes/doc-extractor" + }, + { + "source": "/zh-hans/guides/workflow/node/variable-assigner", + "destination": "/zh/use-dify/nodes/variable-assigner" + }, + { + "source": "/zh-hans/guides/workflow/node/parameter-extractor", + "destination": "/zh/use-dify/nodes/parameter-extractor" + }, + { + "source": "/zh-hans/guides/workflow/node/http-request", + "destination": "/zh/use-dify/nodes/http-request" + }, + { + "source": "/zh-hans/guides/workflow/node/list-operator", + "destination": "/zh/use-dify/nodes/list-operator" + }, + { + "source": "/zh-hans/guides/workflow/node/tools", + "destination": "/zh/use-dify/nodes/tools" + }, + { + "source": "/zh-hans/guides/workflow/node/end", + "destination": "/zh/use-dify/nodes/output" + }, + { + "source": "/zh-hans/guides/workflow/node/llm", + "destination": "/zh/use-dify/nodes/llm" + }, + { + "source": "/ja-jp/guides/workflow/node/start", + "destination": "/ja/use-dify/getting-started/key-concepts#ワークフロー" + }, + { + "source": "/ja-jp/guides/workflow/node/user-input", + "destination": "/ja/use-dify/nodes/user-input" + }, + { + "source": "/ja-jp/guides/workflow/node/trigger", + "destination": "/ja/use-dify/nodes/trigger/overview" + }, + { + "source": "/ja-jp/guides/workflow/node/schedule-trigger", + "destination": "/ja/use-dify/nodes/trigger/schedule-trigger" + }, + { + "source": "/ja-jp/guides/workflow/node/webhook-trigger", + "destination": "/ja/use-dify/nodes/trigger/webhook-trigger" + }, + { + "source": "/ja-jp/guides/workflow/node/plugin-trigger", + "destination": "/ja/use-dify/nodes/trigger/plugin-trigger" + }, + { + "source": "/ja-jp/guides/workflow/node/knowledge-retrieval", + "destination": "/ja/use-dify/nodes/knowledge-retrieval" + }, + { + "source": "/ja-jp/guides/workflow/node/agent", + "destination": "/ja/use-dify/nodes/agent" + }, + { + "source": "/ja-jp/guides/workflow/node/question-classifier", + "destination": "/ja/use-dify/nodes/question-classifier" + }, + { + "source": "/ja-jp/guides/workflow/node/ifelse", + "destination": "/ja/use-dify/nodes/ifelse" + }, + { + "source": "/ja-jp/guides/workflow/node/iteration", + "destination": "/ja/use-dify/nodes/iteration" + }, + { + "source": "/ja-jp/guides/workflow/node/loop", + "destination": "/ja/use-dify/nodes/loop" + }, + { + "source": "/ja-jp/guides/workflow/node/code", + "destination": "/ja/use-dify/nodes/code" + }, + { + "source": "/ja-jp/guides/workflow/node/template", + "destination": "/ja/use-dify/nodes/template" + }, + { + "source": "/ja-jp/guides/workflow/node/variable-aggregator", + "destination": "/ja/use-dify/nodes/variable-aggregator" + }, + { + "source": "/ja-jp/guides/workflow/node/doc-extractor", + "destination": "/ja/use-dify/nodes/doc-extractor" + }, + { + "source": "/ja-jp/guides/workflow/node/variable-assigner", + "destination": "/ja/use-dify/nodes/variable-assigner" + }, + { + "source": "/ja-jp/guides/workflow/node/parameter-extractor", + "destination": "/ja/use-dify/nodes/parameter-extractor" + }, + { + "source": "/ja-jp/guides/workflow/node/http-request", + "destination": "/ja/use-dify/nodes/http-request" + }, + { + "source": "/ja-jp/guides/workflow/node/list-operator", + "destination": "/ja/use-dify/nodes/list-operator" + }, + { + "source": "/ja-jp/guides/workflow/node/tools", + "destination": "/ja/use-dify/nodes/tools" + }, + { + "source": "/ja-jp/guides/workflow/node/end", + "destination": "/ja/use-dify/nodes/output" + }, + { + "source": "/ja-jp/guides/workflow/node/llm", + "destination": "/ja/use-dify/nodes/llm" + }, + { + "source": "/en/getting-started/dify-for-education", + "destination": "/en/use-dify/workspace/subscription-management#dify-for-education" + }, + { + "source": "/zh-hans/getting-started/dify-for-education", + "destination": "/zh/use-dify/workspace/subscription-management#dify-for-education" + }, + { + "source": "/ja-jp/getting-started/dify-for-education", + "destination": "/ja/use-dify/workspace/subscription-management#dify-for-education" + }, + { + "source": "/plugins/schema-definition/model", + "destination": "/versions/legacy/en/plugins/schema-definition/model/model-designing-rules" + }, + { + "source": "/plugins/schema-definition", + "destination": "/versions/legacy/en/plugins/schema-definition/manifest" + }, + { + "source": "/zh-hans", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/introduction", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/en/introduction", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/introduction", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/introduction", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/getting-started/readme/features-and-specifications", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/getting-started/readme/model-providers", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/getting-started/install-self-hosted", + "destination": "/en/self-host/quick-start/docker-compose" + }, + { + "source": "/getting-started/install-self-hosted/docker-compose", + "destination": "/en/self-host/quick-start/docker-compose" + }, + { + "source": "/getting-started/install-self-hosted/local-source-code", + "destination": "/en/self-host/advanced-deployments/local-source-code" + }, + { + "source": "/getting-started/install-self-hosted/bt-panel", + "destination": "/en/self-host/platform-guides/bt-panel" + }, + { + "source": "/getting-started/install-self-hosted/start-the-frontend-docker-container", + "destination": "/en/self-host/advanced-deployments/start-the-frontend-docker-container" + }, + { + "source": "/getting-started/install-self-hosted/environments", + "destination": "/en/self-host/configuration/environments" + }, + { + "source": "/getting-started/install-self-hosted/faqs", + "destination": "/en/self-host/quick-start/faqs" + }, + { + "source": "/getting-started/cloud", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/getting-started/dify-premium", + "destination": "/en/self-host/platform-guides/dify-premium" + }, + { + "source": "/zh-hans/guides/application-publishing/launch-your-webapp-quickly/readme", + "destination": "/zh/use-dify/publish/README" + }, + { + "source": "/ja-jp/guides/application-publishing/launch-your-webapp-quickly/readme", + "destination": "/ja/use-dify/publish/README" + }, + { + "source": "/en/guides/application-publishing/launch-your-webapp-quickly/readme", + "destination": "/en/use-dify/publish/README" + }, + { + "source": "/plugins/:slug*", + "destination": "/en/develop-plugin/getting-started/getting-started-dify-plugin" + }, + { + "source": "/plugins/quick-start", + "destination": "/en/develop-plugin/getting-started/getting-started-dify-plugin" + }, + { + "source": "/plugins/quick-start/install-plugins", + "destination": "/en/develop-plugin/getting-started/getting-started-dify-plugin" + }, + { + "source": "/plugins/quick-start/develop-plugins", + "destination": "/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet" + }, + { + "source": "/plugins/quick-start/develop-plugins/initialize-development-tools", + "destination": "/en/develop-plugin/getting-started/cli" + }, + { + "source": "/plugins/quick-start/develop-plugins/tool-plugin", + "destination": "/en/develop-plugin/features-and-specs/plugin-types/tool" + }, + { + "source": "/plugins/quick-start/develop-plugins/model-plugin", + "destination": "/en/develop-plugin/features-and-specs/plugin-types/model-schema" + }, + { + "source": "/plugins/quick-start/develop-plugins/model-plugin/create-model-providers", + "destination": "/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider" + }, + { + "source": "/en/guides/workflow/node/:slug*", + "destination": "/en/use-dify/nodes/:slug*" + }, + { + "source": "/en/guides/workflow/debug-and-preview/:slug*", + "destination": "/en/use-dify/debug/:slug*" + }, + { + "source": "/en/guides/application-publishing/launch-your-webapp-quickly/:slug*", + "destination": "/en/use-dify/publish/webapp/:slug*" + }, + { + "source": "/en/guides/application-publishing/:slug*", + "destination": "/en/use-dify/publish/:slug*" + }, + { + "source": "/en/guides/annotation/:slug*", + "destination": "/en/use-dify/monitor/:slug*" + }, + { + "source": "/en/guides/monitoring/integrate-external-ops-tools/:slug*", + "destination": "/en/use-dify/monitor/integrations/:slug*" + }, + { + "source": "/en/guides/monitoring/:slug*", + "destination": "/en/use-dify/monitor/:slug*" + }, + { + "source": "/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/:slug*", + "destination": "/en/use-dify/knowledge/create-knowledge/import-text-data/:slug*" + }, + { + "source": "/en/guides/knowledge-base/create-knowledge-and-upload-documents/:slug*", + "destination": "/en/use-dify/knowledge/create-knowledge/:slug*" + }, + { + "source": "/en/guides/knowledge-base/knowledge-and-documents-maintenance/:slug*", + "destination": "/en/use-dify/knowledge/manage-knowledge/:slug*" + }, + { + "source": "/en/guides/knowledge-base/:slug*", + "destination": "/en/use-dify/knowledge/:slug*" + }, + { + "source": "/en/guides/management/:slug*", + "destination": "/en/use-dify/workspace/:slug*" + }, + { + "source": "/en/guides/model-configuration/:slug*", + "destination": "/en/use-dify/workspace/model-providers" + }, + { + "source": "/en/workshop/basic/:slug*", + "destination": "/en/use-dify/tutorials/:slug*" + }, + { + "source": "/en/workshop/intermediate/:slug*", + "destination": "/en/use-dify/tutorials/:slug*" + }, + { + "source": "/en/workshop/:slug*", + "destination": "/en/use-dify/tutorials/:slug*" + }, + { + "source": "/en/getting-started/install-self-hosted/:slug*", + "destination": "/en/self-host/dify-community/:slug*" + }, + { + "source": "/en/guides/workflow/:slug*", + "destination": "/en/use-dify/build/:slug*" + }, + { + "source": "/en/guides/application-orchestrate/app-toolkits/:slug*", + "destination": "/en/use-dify/nodes/tools" + }, + { + "source": "/en/guides/application-orchestrate/:slug*", + "destination": "/en/use-dify/getting-started/quick-start" + }, + { + "source": "/en/plugins/:slug*", + "destination": "/en/develop-plugin/0111-getting-started-dify-plugin" + }, + { + "source": "/en/development/backend/:slug*", + "destination": "/api-reference/:slug*" + }, + { + "source": "/en/development/:slug*", + "destination": "/en/develop-plugin/0111-getting-started-dify-plugin" + }, + { + "source": "/en/learn-more/extended-reading/retrieval-augment/:slug*", + "destination": "/en/use-dify/knowledge/:slug*" + }, + { + "source": "/en/learn-more/extended-reading/dify-docs-mcp", + "destination": "/en/use-dify/build/mcp" + }, + { + "source": "/en/learn-more/:slug*", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/en/guides/:slug*", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/en/getting-started/:slug*", + "destination": "/en/use-dify/getting-started/:slug*" + }, + { + "source": "/en/community/:slug*", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/en/resources/:slug*", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/en/policies/:slug*", + "destination": "/en/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/guides/workflow/node/:slug*", + "destination": "/ja/use-dify/nodes/:slug*" + }, + { + "source": "/ja-jp/guides/workflow/debug-and-preview/:slug*", + "destination": "/ja/use-dify/debug/:slug*" + }, + { + "source": "/ja-jp/guides/application-publishing/launch-your-webapp-quickly/:slug*", + "destination": "/ja/use-dify/publish/webapp/:slug*" + }, + { + "source": "/ja-jp/guides/application-publishing/:slug*", + "destination": "/ja/use-dify/publish/:slug*" + }, + { + "source": "/ja-jp/guides/annotation/:slug*", + "destination": "/ja/use-dify/monitor/:slug*" + }, + { + "source": "/ja-jp/guides/monitoring/integrate-external-ops-tools/:slug*", + "destination": "/ja/use-dify/monitor/integrations/:slug*" + }, + { + "source": "/ja-jp/guides/monitoring/:slug*", + "destination": "/ja/use-dify/monitor/:slug*" + }, + { + "source": "/ja-jp/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/:slug*", + "destination": "/ja/use-dify/knowledge/create-knowledge/import-text-data/:slug*" + }, + { + "source": "/ja-jp/guides/knowledge-base/create-knowledge-and-upload-documents/:slug*", + "destination": "/ja/use-dify/knowledge/create-knowledge/:slug*" + }, + { + "source": "/ja-jp/guides/knowledge-base/knowledge-and-documents-maintenance/:slug*", + "destination": "/ja/use-dify/knowledge/manage-knowledge/:slug*" + }, + { + "source": "/ja-jp/guides/knowledge-base/:slug*", + "destination": "/ja/use-dify/knowledge/:slug*" + }, + { + "source": "/ja-jp/guides/management/:slug*", + "destination": "/ja/use-dify/workspace/:slug*" + }, + { + "source": "/ja-jp/guides/model-configuration/:slug*", + "destination": "/ja/use-dify/workspace/model-providers" + }, + { + "source": "/ja-jp/workshop/basic/:slug*", + "destination": "/ja/use-dify/tutorials/:slug*" + }, + { + "source": "/ja-jp/workshop/intermediate/:slug*", + "destination": "/ja/use-dify/tutorials/:slug*" + }, + { + "source": "/ja-jp/workshop/:slug*", + "destination": "/ja/use-dify/tutorials/:slug*" + }, + { + "source": "/ja-jp/getting-started/install-self-hosted/:slug*", + "destination": "/ja/self-host/dify-community/:slug*" + }, + { + "source": "/ja-jp/guides/workflow/:slug*", + "destination": "/ja/use-dify/build/:slug*" + }, + { + "source": "/ja-jp/guides/application-orchestrate/app-toolkits/:slug*", + "destination": "/ja/use-dify/nodes/tools" + }, + { + "source": "/ja-jp/guides/application-orchestrate/:slug*", + "destination": "/ja/use-dify/getting-started/quick-start" + }, + { + "source": "/ja-jp/plugins/:slug*", + "destination": "/ja/use-dify/workspace/plugins" + }, + { + "source": "/ja-jp/development/backend/:slug*", + "destination": "/api-reference/:slug*" + }, + { + "source": "/ja-jp/development/models-integration/:slug*", + "destination": "/ja/use-dify/workspace/model-providers" + }, + { + "source": "/ja-jp/development/:slug*", + "destination": "/api-reference/:slug*" + }, + { + "source": "/ja-jp/learn-more/extended-reading/retrieval-augment/:slug*", + "destination": "/ja/use-dify/knowledge/:slug*" + }, + { + "source": "/ja-jp/learn-more/extended-reading/dify-docs-mcp", + "destination": "/ja/use-dify/build/mcp" + }, + { + "source": "/ja-jp/learn-more/faq/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/learn-more/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/guides/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/getting-started/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/community/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/resources/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/ja-jp/policies/:slug*", + "destination": "/ja/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/guides/workflow/node/:slug*", + "destination": "/zh/use-dify/nodes/:slug*" + }, + { + "source": "/zh-hans/guides/workflow/debug-and-preview/:slug*", + "destination": "/zh/use-dify/debug/:slug*" + }, + { + "source": "/zh-hans/guides/application-publishing/launch-your-webapp-quickly/:slug*", + "destination": "/zh/use-dify/publish/webapp/:slug*" + }, + { + "source": "/zh-hans/guides/application-publishing/:slug*", + "destination": "/zh/use-dify/publish/:slug*" + }, + { + "source": "/zh-hans/guides/annotation/:slug*", + "destination": "/zh/use-dify/monitor/:slug*" + }, + { + "source": "/zh-hans/guides/monitoring/integrate-external-ops-tools/:slug*", + "destination": "/zh/use-dify/monitor/integrations/:slug*" + }, + { + "source": "/zh-hans/guides/monitoring/:slug*", + "destination": "/zh/use-dify/monitor/:slug*" + }, + { + "source": "/zh-hans/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/:slug*", + "destination": "/zh/use-dify/knowledge/create-knowledge/import-text-data/:slug*" + }, + { + "source": "/zh-hans/guides/knowledge-base/create-knowledge-and-upload-documents/:slug*", + "destination": "/zh/use-dify/knowledge/create-knowledge/:slug*" + }, + { + "source": "/zh-hans/guides/knowledge-base/knowledge-and-documents-maintenance/:slug*", + "destination": "/zh/use-dify/knowledge/manage-knowledge/:slug*" + }, + { + "source": "/zh-hans/guides/knowledge-base/:slug*", + "destination": "/zh/use-dify/knowledge/:slug*" + }, + { + "source": "/zh-hans/guides/management/:slug*", + "destination": "/zh/use-dify/workspace/:slug*" + }, + { + "source": "/zh-hans/guides/model-configuration/:slug*", + "destination": "/zh/use-dify/workspace/model-providers" + }, + { + "source": "/zh-hans/workshop/basic/:slug*", + "destination": "/zh/use-dify/tutorials/:slug*" + }, + { + "source": "/zh-hans/workshop/intermediate/:slug*", + "destination": "/zh/use-dify/tutorials/:slug*" + }, + { + "source": "/zh-hans/workshop/:slug*", + "destination": "/zh/use-dify/tutorials/:slug*" + }, + { + "source": "/zh-hans/getting-started/install-self-hosted/:slug*", + "destination": "/zh/self-host/dify-community/:slug*" + }, + { + "source": "/zh-hans/guides/workflow/:slug*", + "destination": "/zh/use-dify/build/:slug*" + }, + { + "source": "/zh-hans/guides/application-orchestrate/app-toolkits/:slug*", + "destination": "/zh/use-dify/nodes/tools" + }, + { + "source": "/zh-hans/guides/application-orchestrate/:slug*", + "destination": "/zh/use-dify/getting-started/quick-start" + }, + { + "source": "/zh-hans/plugins/:slug*", + "destination": "/zh/use-dify/workspace/plugins" + }, + { + "source": "/zh-hans/development/backend/:slug*", + "destination": "/api-reference/:slug*" + }, + { + "source": "/zh-hans/development/models-integration/:slug*", + "destination": "/zh/use-dify/workspace/model-providers" + }, + { + "source": "/zh-hans/development/:slug*", + "destination": "/api-reference/:slug*" + }, + { + "source": "/zh-hans/learn-more/extended-reading/retrieval-augment/:slug*", + "destination": "/zh/use-dify/knowledge/:slug*" + }, + { + "source": "/zh-hans/learn-more/extended-reading/dify-docs-mcp", + "destination": "/zh/use-dify/build/mcp" + }, + { + "source": "/zh-hans/learn-more/faq/:slug*", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/learn-more/:slug*", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/guides/:slug*", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/getting-started/cloud", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/getting-started/dify-premium", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/community/:slug*", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/resources/:slug*", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/zh-hans/policies/:slug*", + "destination": "/zh/use-dify/getting-started/introduction" + }, + { + "source": "/use-dify/:slug*", + "destination": "/en/use-dify/:slug*" + }, + { + "source": "/self-host/:slug*", + "destination": "/en/self-host/:slug*" + }, + { + "source": "/en/guides/model-configuration/load-balancing", + "destination": "/en/use-dify/workspace/model-providers#configure-model-load-balancing" + }, + { + "source": "/guides/model-configuration/load-balancing", + "destination": "/en/use-dify/workspace/model-providers#configure-model-load-balancing" + }, + { + "source": "/zh-hans/guides/model-configuration/load-balancing", + "destination": "/zh/use-dify/workspace/model-providers#配置模型负载均衡" + }, + { + "source": "/ja-jp/guides/model-configuration/load-balancing", + "destination": "/ja/use-dify/workspace/model-providers#負荷分散の構成" + } + ], + "navbar": { + "links": [ + { + "label": "Changelog", + "href": "https://github.com/langgenius/dify/releases" } ], - "navbar": { - "links": [ - { - "label": "Changelog", - "href": "https://github.com/langgenius/dify/releases" - } - ], - "primary": { - "type": "button", - "label": "Studio", - "href": "https://cloud.dify.ai" - } - }, - "integrations": { - "ga4": { - "measurementId": "G-HHGQ6GKNCE" - } - }, - "footer": { - "socials": { - "x": "https://x.com/dify_ai", - "github": "https://github.com/langgenius/dify-docs", - "linkedin": "https://www.linkedin.com/company/langgenius" - } + "primary": { + "type": "button", + "label": "Studio", + "href": "https://cloud.dify.ai" + } + }, + "integrations": { + "ga4": { + "measurementId": "G-HHGQ6GKNCE" + } + }, + "footer": { + "socials": { + "x": "https://x.com/dify_ai", + "github": "https://github.com/langgenius/dify-docs", + "linkedin": "https://www.linkedin.com/company/langgenius" } } +} \ No newline at end of file diff --git a/plugin-dev-en/0131-cheatsheet.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx similarity index 74% rename from plugin-dev-en/0131-cheatsheet.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx index 487746e5..2647dbb2 100644 --- a/plugin-dev-en/0131-cheatsheet.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx @@ -18,7 +18,7 @@ description: A comprehensive reference guide for Dify plugin development, includ - Python version ≥ 3.12 - Dify plugin scaffold tool (dify-plugin-daemon) -> Learn more: [Initializing Development Tools](/plugin-dev-en/0221-initialize-development-tools) +> Learn more: [Initializing Development Tools](/en/develop-plugin/getting-started/cli) ### Obtaining the Dify Plugin Development Package @@ -83,7 +83,7 @@ Here we use `dify` as an example. If you are using a local installation method, Follow the prompts to complete the basic plugin information configuration -> Learn more: [Dify Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool) +> Learn more: [Dify Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) #### 2. Run in Development Mode @@ -93,7 +93,7 @@ Configure the `.env` file, then run the following command in the plugin director python -m main ``` -> Learn more: [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) +> Learn more: [Remote Debugging Plugins](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) #### 4. Packaging and Deployment @@ -104,7 +104,7 @@ cd .. dify plugin package ./yourapp ``` -> Learn more: [Publishing Overview](/plugin-dev-en/0321-release-overview) +> Learn more: [Publishing Overview](/en/develop-plugin/publishing/marketplace-listing/release-overview) ### Plugin Categories @@ -137,22 +137,22 @@ class ToolLabelEnum(Enum): Dify supports the development of various types of plugins: - **Tool plugin**: Integrate third-party APIs and services - > Learn more: [Dify Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool) + > Learn more: [Dify Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - **Model plugin**: Integrate AI models - > Learn more: [Model Plugin](/plugin-dev-en/0411-model-plugin-introduction), [Quick Integration of a New Model](/plugin-dev-en/0211-getting-started-new-model) + > Learn more: [Model Plugin](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules), [Quick Integration of a New Model](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - **Agent strategy plugin**: Customize Agent thinking and decision-making strategies - > Learn more: [Agent Strategy Plugin](/plugin-dev-en/9433-agent-strategy-plugin) + > Learn more: [Agent Strategy Plugin](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - **Extension plugin**: Extend Dify platform functionality, such as Endpoints and WebAPP - > Learn more: [Extension Plugin](/plugin-dev-en/9231-extension-plugin) + > Learn more: [Extension Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - **Data source plugin**: Serve as the document data source and starting point for knowledge pipelines - > Learn more: [Data Source Plugin](/plugin-dev-en/0222-datasource-plugin) + > Learn more: [Data Source Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin) - **Trigger plugin**: Automatically trigger Workflow execution upon third-party events - > Learn more: [Trigger Plugin](/plugin-dev-en/0222-trigger-plugin) + > Learn more: [Trigger Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin) {/* Contributing Section @@ -162,5 +162,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0131-cheatsheet.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0222-creating-new-model-provider.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx similarity index 93% rename from plugin-dev-en/0222-creating-new-model-provider.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx index e6936b15..46367620 100644 --- a/plugin-dev-en/0222-creating-new-model-provider.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx @@ -14,7 +14,7 @@ description: This comprehensive guide provides detailed instructions on creating ### Prerequisites -* [Dify CLI](/plugin-dev-en/0111-cli.mdx) +* [Dify CLI](/en/develop-plugin/getting-started/cli) * Basic Python programming skills and understanding of object-oriented programming * Familiarity with the API documentation of the model provider you want to integrate @@ -194,7 +194,7 @@ model_credential_schema: # Additional fields as needed... ``` -For complete model provider YAML specifications, please refer to the [Model Schema](/plugin-dev-en/0412-model-schema) documentation. +For complete model provider YAML specifications, please refer to the [Model Schema](/en/develop-plugin/features-and-specs/plugin-types/model-schema) documentation. ### 3.2 Write Model Provider Code @@ -269,8 +269,8 @@ After setting up your provider, you need to implement the model-specific code th For detailed instructions on these steps, please refer to: -* [Model Design Rules](/plugin-dev-en/0411-model-designing-rules) - Standards for integrating predefined models -* [Model Schema](/plugin-dev-en/0412-model-schema) - Standards for model configuration files +* [Model Design Rules](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - Standards for integrating predefined models +* [Model Schema](/en/develop-plugin/features-and-specs/plugin-types/model-schema) - Standards for model configuration files ### 4.1 Define Model Configuration (YAML) @@ -441,14 +441,14 @@ When your plugin is ready: 3. Submit a pull request to the [Dify official plugins repository](https://github.com/langgenius/dify-official-plugins) -For more details on the publishing process, see the [Publishing Overview](/plugin-dev-en/0321-release-overview). +For more details on the publishing process, see the [Publishing Overview](/en/develop-plugin/publishing/marketplace-listing/release-overview). ## Reference Resources -- [Quick Integration of a New Model](/plugin-dev-en/0211-getting-started-new-model) - How to add new models to existing providers -- [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) - Return to the plugin development getting started guide -- [Model Schema](/plugin-dev-en/0412-model-schema) - Learn detailed model configuration specifications -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Learn about plugin manifest file configuration +- [Quick Integration of a New Model](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - How to add new models to existing providers +- [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) - Return to the plugin development getting started guide +- [Model Schema](/en/develop-plugin/features-and-specs/plugin-types/model-schema) - Learn detailed model configuration specifications +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Learn about plugin manifest file configuration - [Dify Plugin SDK Reference](https://github.com/langgenius/dify-plugin-sdks) - Look up base classes, data structures, and error types {/* @@ -459,5 +459,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0222-creating-new-model-provider.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0222-datasource-plugin.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx similarity index 96% rename from plugin-dev-en/0222-datasource-plugin.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx index 7cd68dda..4f54186e 100644 --- a/plugin-dev-en/0222-datasource-plugin.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx @@ -11,14 +11,14 @@ This article describes how to develop a data source plugin, covering plugin arch Before reading on, ensure you have a basic understanding of the knowledge pipeline and some knowledge of plugin development. You can find relevant information here: - [Step 2: Knowledge Pipeline Orchestration](/en/guides/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration) -- [Dify Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool) +- [Dify Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) ## **Data Source Plugin Types** Dify supports three types of data source plugins: web crawler, online document, and online drive. When implementing the plugin code, the class that provides the plugin's functionality must inherit from a specific data source class. Each of the three plugin types corresponds to a different parent class. - To learn how to inherit from a parent class to implement plugin functionality, see [Dify Plugin Development: Hello World Guide - 4.4 Implementing Tool Logic](/plugin-dev-en/0211-getting-started-dify-tool#4-4-implementing-tool-logic). + To learn how to inherit from a parent class to implement plugin functionality, see [Dify Plugin Development: Hello World Guide - 4.4 Implementing Tool Logic](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin#4-4-implementing-tool-logic). Each data source plugin type supports multiple data sources. For example: @@ -106,13 +106,13 @@ datasources: ``` - For more about creating a provider YAML file, see [Dify Plugin Development: Hello World Guide-4.3 Configuring Provider Credentials](/plugin-dev-en/0211-getting-started-dify-tool#4-3-configuring-provider-credentials). + For more about creating a provider YAML file, see [Dify Plugin Development: Hello World Guide-4.3 Configuring Provider Credentials](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin#4-3-configuring-provider-credentials). Data source plugins support authentication via OAuth 2.0 or API Key. - To configure OAuth, see [Add OAuth Support to Your Tool Plugin](/plugin-dev-en/0222-tool-oauth). + To configure OAuth, see [Add OAuth Support to Your Tool Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth). #### Create the Provider Code File @@ -442,7 +442,7 @@ Next, you can: - Publish the plugin to Dify Marketplace by submitting a pull request. - For the plugin publishing process, see [Publishing Plugins](/plugin-dev-en/0321-release-overview). + For the plugin publishing process, see [Publishing Plugins](/en/develop-plugin/publishing/marketplace-listing/release-overview). {/* @@ -453,5 +453,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0222-datasource-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx similarity index 81% rename from plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx index 0a37a097..143fb6dc 100644 --- a/plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx @@ -15,7 +15,7 @@ description: This guide provides a complete walkthrough for developing a Slack B **What You’ll Learn:** -Gain a solid understanding of how to build a Slack Bot that’s powered by AI—one that can respond to user questions right inside Slack. If you haven't developed a plugin before, we recommend reading the [Plugin Development Quick Start Guide](/plugin-dev-en/0211-getting-started-dify-tool) first. +Gain a solid understanding of how to build a Slack Bot that’s powered by AI—one that can respond to user questions right inside Slack. If you haven't developed a plugin before, we recommend reading the [Plugin Development Quick Start Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) first. ### Project Background @@ -46,7 +46,7 @@ Slack is an open, real-time communication platform with a robust API. Among its ### Prerequisites -- **Dify plugin developing tool**: For more information, see [Initializing the Development Tool](/plugin-dev-en/0221-initialize-development-tools). +- **Dify plugin developing tool**: For more information, see [Initializing the Development Tool](/en/develop-plugin/getting-started/cli). - **Python environment (version ≥ 3.12)**: Refer to this [Python Installation Tutorial](https://pythontest.com/python/installing-python-3-11/) or ask an LLM for a complete setup guide. - Create a Slack App and Get an OAuth Token @@ -68,7 +68,7 @@ Go to the [Slack API platform](https://api.slack.com/apps), create a Slack app f ### 1. Developing the Plugin -Now we’ll dive into the actual coding. Before starting, make sure you’ve read [Quick Start: Developing an Extension Plugin](/plugin-dev-en/9231-extension-plugin) or have already built a Dify plugin before. +Now we’ll dive into the actual coding. Before starting, make sure you’ve read [Quick Start: Developing an Extension Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) or have already built a Dify plugin before. #### 1.1 Initialize the Project @@ -80,7 +80,7 @@ dify plugin init Follow the prompts to provide basic project info. Select the `extension` template, and grant both `Apps` and `Endpoints` permissions. -For additional details on reverse-invoking Dify services within a plugin, see [Reverse Invocation: App](/plugin-dev-en/9242-reverse-invocation-app). +For additional details on reverse-invoking Dify services within a plugin, see [Reverse Invocation: App](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app). ![Plugins permission](https://assets-docs.dify.ai/2024/12/d89a6282c5584fc43a9cadeddf09c0de.png) @@ -301,7 +301,7 @@ In your code, `self.session.app.chat.invoke` is used to call the Dify applicatio ### 4. Package the Plugin (Optional) -Once you confirm that the plugin works correctly, you can package and name it via the following command. After it runs, you’ll find a `slack_bot.difypkg` file in the current directory—your final plugin package. For detailed packaging steps, refer to [Package as a Local File and Share](/plugin-dev-en/0322-release-by-file). +Once you confirm that the plugin works correctly, you can package and name it via the following command. After it runs, you’ll find a `slack_bot.difypkg` file in the current directory—your final plugin package. For detailed packaging steps, refer to [Package as a Local File and Share](/en/develop-plugin/publishing/marketplace-listing/release-by-file). ```bash # Replace ./slack_bot with your actual plugin project path. @@ -315,20 +315,20 @@ Congratulations! You’ve successfully developed, tested, and packaged a plugin! ### 5. Publish the Plugin (Optional) -You can now upload it to the [Dify Marketplace repository](https://github.com/langgenius/dify-plugins) for public release. Before publishing, ensure your plugin meets the [Publishing to Dify Marketplace Guidelines](/plugin-dev-en/0322-release-to-dify-marketplace). Once approved, your code is merged into the main branch, and the plugin goes live on the [Dify Marketplace](https://marketplace.dify.ai/). +You can now upload it to the [Dify Marketplace repository](https://github.com/langgenius/dify-plugins) for public release. Before publishing, ensure your plugin meets the [Publishing to Dify Marketplace Guidelines](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace). Once approved, your code is merged into the main branch, and the plugin goes live on the [Dify Marketplace](https://marketplace.dify.ai/). --- ## Related Resources -- [Plugin Development Basics](/plugin-dev-en/0111-getting-started-dify-plugin) - Comprehensive overview of Dify plugin development -- [Plugin Development Quick Start Guide](/plugin-dev-en/0211-getting-started-dify-tool) - Start developing plugins from scratch -- [Develop an Extension Plugin](/plugin-dev-en/9231-extension-plugin) - Learn about extension plugin development -- [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation) - Understand how to call Dify platform capabilities -- [Reverse Invocation: App](/plugin-dev-en/9242-reverse-invocation-app) - Learn how to call apps within the platform -- [Publishing Plugins](/plugin-dev-en/0321-release-overview) - Learn the publishing process -- [Publishing to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace) - Marketplace publishing guide -- [Endpoint Detailed Definition](/plugin-dev-en/0432-endpoint) - Detailed Endpoint definition +- [Plugin Development Basics](/en/develop-plugin/getting-started/getting-started-dify-plugin) - Comprehensive overview of Dify plugin development +- [Plugin Development Quick Start Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Start developing plugins from scratch +- [Develop an Extension Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - Learn about extension plugin development +- [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Understand how to call Dify platform capabilities +- [Reverse Invocation: App](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - Learn how to call apps within the platform +- [Publishing Plugins](/en/develop-plugin/publishing/marketplace-listing/release-overview) - Learn the publishing process +- [Publishing to Dify Marketplace](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - Marketplace publishing guide +- [Endpoint Detailed Definition](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - Detailed Endpoint definition ### Further Reading @@ -337,16 +337,16 @@ For a complete Dify plugin project example, visit the [GitHub repository](https: If you want to explore more about plugin development, check the following: **Quick Starts:** -- [Develop an Extension Plugin](/plugin-dev-en/9231-extension-plugin) -- [Develop a Model Plugin](/plugin-dev-en/0211-getting-started-new-model) -- [Bundle Plugins: Packaging Multiple Plugins](/plugin-dev-en/9241-bundle) +- [Develop an Extension Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) +- [Develop a Model Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) +- [Bundle Plugins: Packaging Multiple Plugins](/en/develop-plugin/features-and-specs/advanced-development/bundle) **Plugin Interface Docs:** -- [Defining Plugin Information via Manifest File](/plugin-dev-en/0411-plugin-info-by-manifest) - Manifest structure -- [Endpoint](/plugin-dev-en/0432-endpoint) - Endpoint detailed definition -- [Reverse Invocation](/plugin-dev-en/9241-reverse-invocation) - Reverse-calling Dify capabilities -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Tool specifications -- [Model Schema](/plugin-dev-en/0412-model-schema) - Model +- [Defining Plugin Information via Manifest File](/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest) - Manifest structure +- [Endpoint](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - Endpoint detailed definition +- [Reverse Invocation](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Reverse-calling Dify capabilities +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Tool specifications +- [Model Schema](/en/develop-plugin/features-and-specs/plugin-types/model-schema) - Model {/* Contributing Section @@ -356,5 +356,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0432-develop-flomo-plugin.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx similarity index 98% rename from plugin-dev-en/0432-develop-flomo-plugin.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx index b533f79d..c6e4ec9c 100644 --- a/plugin-dev-en/0432-develop-flomo-plugin.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx @@ -344,5 +344,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0432-develop-flomo-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0432-develop-md-exporter.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx similarity index 98% rename from plugin-dev-en/0432-develop-md-exporter.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx index ce27ab1e..52e4443c 100644 --- a/plugin-dev-en/0432-develop-md-exporter.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx @@ -545,4 +545,4 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0432-develop-md-exporter.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0432-endpoint.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx similarity index 66% rename from plugin-dev-en/0432-endpoint.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx index e1cf4863..30179b21 100644 --- a/plugin-dev-en/0432-endpoint.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx @@ -16,7 +16,7 @@ description: Authors Yeuoly, Allen. This document details the structure and impl # Endpoint -This document uses the [Neko Cat](/plugin-dev-en/9231-extension-plugin) project as an example to explain the structure of Endpoints within a plugin. Endpoints are HTTP interfaces exposed by the plugin, which can be used for integration with external systems. For the complete plugin code, please refer to the [GitHub repository](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko). +This document uses the [Neko Cat](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) project as an example to explain the structure of Endpoints within a plugin. Endpoints are HTTP interfaces exposed by the plugin, which can be used for integration with external systems. For the complete plugin code, please refer to the [GitHub repository](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko). ### Group Definition @@ -30,7 +30,7 @@ Besides the `Endpoint Name`, you can add new form items by writing the group's c #### **Structure** -* `settings` (map[string] [ProviderConfig](/plugin-dev-en/0411-general-specifications#providerconfig)): Endpoint configuration definition. +* `settings` (map[string] [ProviderConfig](/en/develop-plugin/features-and-specs/plugin-types/general-specifications#providerconfig)): Endpoint configuration definition. * `endpoints` (list[string], required): Points to the specific `endpoint` interface definitions. ```yaml @@ -108,16 +108,16 @@ class Duck(Endpoint): * Pay attention to security when developing Endpoints and avoid executing dangerous operations. * Endpoints can be used to handle Webhook callbacks or provide interfaces for other systems to connect. -If you are learning plugin development, it is recommended to first read the [Getting Started with Plugin Development](/plugin-dev-en/0211-getting-started-dify-tool) and the [Developer Cheatsheet](/plugin-dev-en/0131-cheatsheet). +If you are learning plugin development, it is recommended to first read the [Getting Started with Plugin Development](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) and the [Developer Cheatsheet](/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet). ## Related Resources -* [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) - Understand the overall architecture of plugin development. -* [Neko Cat Example](/plugin-dev-en/9231-extension-plugin) - An example of extension plugin development. -* [General Specifications Definition](/plugin-dev-en/0411-general-specifications) - Understand common structures like ProviderConfig. -* [Develop a Slack Bot Plugin Example](/plugin-dev-en/0432-develop-a-slack-bot-plugin) - Another plugin development example. -* [Getting Started with Plugin Development](/plugin-dev-en/0211-getting-started-dify-tool) - Develop a plugin from scratch. -* [Reverse Invocation of Dify Services](/plugin-dev-en/9242-reverse-invocation-app) - Learn how to use the reverse invocation feature. +* [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) - Understand the overall architecture of plugin development. +* [Neko Cat Example](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - An example of extension plugin development. +* [General Specifications Definition](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Understand common structures like ProviderConfig. +* [Develop a Slack Bot Plugin Example](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - Another plugin development example. +* [Getting Started with Plugin Development](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Develop a plugin from scratch. +* [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - Learn how to use the reverse invocation feature. {/* Contributing Section @@ -127,5 +127,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0432-endpoint.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0222-tool-oauth.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx similarity index 98% rename from plugin-dev-en/0222-tool-oauth.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx index 82494c1f..ca2b4e10 100644 --- a/plugin-dev-en/0222-tool-oauth.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx @@ -377,5 +377,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0222-tool-oauth.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0222-tool-plugin.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx similarity index 85% rename from plugin-dev-en/0222-tool-plugin.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx index faf70d42..0b172328 100644 --- a/plugin-dev-en/0222-tool-plugin.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx @@ -35,7 +35,7 @@ This article will use `Google Search` as an example to demonstrate how to quickl - Dify plugin scaffolding tool - Python environment, version ≥ 3.12 -For detailed instructions on how to prepare the plugin development scaffolding tool, please refer to [Initializing Development Tools](/plugin-dev-en/0221-initialize-development-tools). If you are developing a plugin for the first time, it is recommended to read [Dify Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool) first. +For detailed instructions on how to prepare the plugin development scaffolding tool, please refer to [Initializing Development Tools](/en/develop-plugin/getting-started/cli). If you are developing a plugin for the first time, it is recommended to read [Dify Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) first. ### Creating a New Project @@ -57,7 +57,7 @@ dify plugin init All templates in the scaffolding tool provide complete code projects. In this example, select the `Tool` plugin. -> If you are already familiar with plugin development and do not need to rely on templates, you can refer to the [General Specifications](/plugin-dev-en/0411-general-specifications) guide to complete the development of different types of plugins. +> If you are already familiar with plugin development and do not need to rely on templates, you can refer to the [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) guide to complete the development of different types of plugins. ![Plugin Type: Tool](https://assets-docs.dify.ai/2024/12/dd3c0f9a66454e15868eabced7b74fd6.png) @@ -176,7 +176,7 @@ extra: source: google.py ``` -- The sub-level structure of `credentials_for_provider` needs to meet the requirements of [General Specifications](/plugin-dev-en/0411-general-specifications). +- The sub-level structure of `credentials_for_provider` needs to meet the requirements of [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications). - You need to specify which tools the provider includes. This example only includes one `tools/google_search.yaml` file. - As a provider, in addition to defining its basic information, you also need to implement some of its code logic, so you need to specify its implementation logic. In this example, we put the code file for the functionality in `google.py`, but we won't implement it yet, but instead write the code for `google_search` first. @@ -289,7 +289,7 @@ class GoogleSearchTool(Tool): yield self.create_json_message(valuable_res) ``` -This example means requesting `serpapi` and using `self.create_json_message` to return a formatted `json` data string. If you want to learn more about return data types, you can refer to the [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) and [Persistent Storage KV](/plugin-dev-en/0411-persistent-storage-kv) documents. +This example means requesting `serpapi` and using `self.create_json_message` to return a formatted `json` data string. If you want to learn more about return data types, you can refer to the [Remote Debugging Plugins](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) and [Persistent Storage KV](/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) documents. #### 4. Completing the Tool Provider Code @@ -351,32 +351,32 @@ Congratulations, you have completed the entire process of developing, debugging, ### Publishing the Plugin (Optional) -If you want to publish the plugin to the Dify Marketplace, please ensure that your plugin follows the specifications in [Publish to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace). After passing the review, the code will be merged into the main branch and automatically launched to the [Dify Marketplace](https://marketplace.dify.ai/). +If you want to publish the plugin to the Dify Marketplace, please ensure that your plugin follows the specifications in [Publish to Dify Marketplace](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace). After passing the review, the code will be merged into the main branch and automatically launched to the [Dify Marketplace](https://marketplace.dify.ai/). -[Publishing Overview](/plugin-dev-en/0321-release-overview) +[Publishing Overview](/en/develop-plugin/publishing/marketplace-listing/release-overview) ### Explore More #### **Quick Start:** -- [Developing Extension Plugins](/plugin-dev-en/9231-extension-plugin) -- [Developing Model Plugins](/plugin-dev-en/0211-getting-started-new-model) -- [Bundle Plugins: Packaging Multiple Plugins](/plugin-dev-en/9241-bundle) +- [Developing Extension Plugins](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) +- [Developing Model Plugins](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) +- [Bundle Plugins: Packaging Multiple Plugins](/en/develop-plugin/features-and-specs/advanced-development/bundle) #### **Plugin Interface Documentation:** -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Manifest Structure and Tool Specifications -- [Endpoint](/plugin-dev-en/0432-endpoint) - Detailed Endpoint Definition -- [Reverse Invocation](/plugin-dev-en/9241-reverse-invocation) - Reverse Invocation of Dify Capabilities -- [Model Schema](/plugin-dev-en/0412-model-schema) - Models -- [Agent Plugins](/plugin-dev-en/9232-agent) - Extending Agent Strategies +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Manifest Structure and Tool Specifications +- [Endpoint](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - Detailed Endpoint Definition +- [Reverse Invocation](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Reverse Invocation of Dify Capabilities +- [Model Schema](/en/develop-plugin/features-and-specs/plugin-types/model-schema) - Models +- [Agent Plugins](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Extending Agent Strategies ## Next Learning Steps -- [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) - Learn more advanced debugging techniques -- [Persistent Storage](/plugin-dev-en/0411-persistent-storage-kv) - Learn how to use data storage in plugins -- [Slack Bot Plugin Development Example](/plugin-dev-en/0432-develop-a-slack-bot-plugin) - View a more complex plugin development case -- [Tool Plugin](/plugin-dev-en/0411-tool) - Explore advanced features of tool plugins +- [Remote Debugging Plugins](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - Learn more advanced debugging techniques +- [Persistent Storage](/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) - Learn how to use data storage in plugins +- [Slack Bot Plugin Development Example](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - View a more complex plugin development case +- [Tool Plugin](/en/develop-plugin/features-and-specs/plugin-types/tool) - Explore advanced features of tool plugins {/* Contributing Section @@ -386,5 +386,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0222-tool-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0222-trigger-plugin.mdx b/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx similarity index 99% rename from plugin-dev-en/0222-trigger-plugin.mdx rename to en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx index d5717bd5..7662af6d 100644 --- a/plugin-dev-en/0222-trigger-plugin.mdx +++ b/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx @@ -302,7 +302,7 @@ To enable automatic subscription creation via OAuth or API key, you need to modi - `credentials_schema` (optional): Declares the required credentials for creating a subscription with an API key or access token, such as `access_tokens` for GitHub. - - `oauth_schema` (optional): Required for implementing subscription creation via OAuth. For details on how to define it, see [Add OAuth Support to Your Tool Plugin](/plugin-dev-en/0222-tool-oauth). + - `oauth_schema` (optional): Required for implementing subscription creation via OAuth. For details on how to define it, see [Add OAuth Support to Your Tool Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth). In `github.py`, create a `Constructor` class to implement the automatic subscription logic. @@ -660,5 +660,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0222-trigger-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9241-bundle.mdx b/en/develop-plugin/features-and-specs/advanced-development/bundle.mdx similarity index 94% rename from plugin-dev-en/9241-bundle.mdx rename to en/develop-plugin/features-and-specs/advanced-development/bundle.mdx index 8e9cace1..ebf87e79 100644 --- a/plugin-dev-en/9241-bundle.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/bundle.mdx @@ -27,7 +27,7 @@ You can use the Dify CLI tool to package multiple plugins into a Bundle. Bundle * Dify plugin scaffolding tool * Python environment, version ≥ 3.10 -For detailed instructions on how to prepare the plugin development scaffolding tool, please refer to [Initialize Development Tools](/plugin-dev-en/0221-initialize-development-tools). +For detailed instructions on how to prepare the plugin development scaffolding tool, please refer to [Initialize Development Tools](/en/develop-plugin/getting-started/cli). ### Create a Bundle Project @@ -105,5 +105,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9241-bundle.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/bundle.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9243-customizable-model.mdx b/en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx similarity index 98% rename from plugin-dev-en/9243-customizable-model.mdx rename to en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx index 3e033ae3..c35033b1 100644 --- a/plugin-dev-en/9243-customizable-model.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx @@ -360,5 +360,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9243-customizable-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9242-reverse-invocation-app.mdx b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx similarity index 78% rename from plugin-dev-en/9242-reverse-invocation-app.mdx rename to en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx index 23fa622c..079d6ed6 100644 --- a/plugin-dev-en/9242-reverse-invocation-app.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx @@ -13,7 +13,7 @@ description: This document details how plugins can reverse invoke App services w invocation specifications, and practical code examples for each. --- -Reverse invoking an App means that a plugin can access data from an App within Dify. This module supports both streaming and non-streaming App calls. If you are unfamiliar with the basic concepts of reverse invocation, please first read [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation.mdx). +Reverse invoking an App means that a plugin can access data from an App within Dify. This module supports both streaming and non-streaming App calls. If you are unfamiliar with the basic concepts of reverse invocation, please first read [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation). **Interface Types:** @@ -126,11 +126,11 @@ class Duck(Endpoint): ## Related Resources -- [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation.mdx) - Understand the fundamental concepts of reverse invocation -- [Reverse Invocation Model](/plugin-dev-en/9242-reverse-invocation-model.mdx) - Learn how to call model capabilities within the platform -- [Reverse Invocation Tool](/plugin-dev-en/9242-reverse-invocation-tool.mdx) - Learn how to call other plugins -- [Develop a Slack Bot Plugin](/plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx) - A practical application case using reverse invocation -- [Develop Extension Plugins](/plugin-dev-en/9231-extension-plugin.mdx) - Learn how to develop extension plugins +- [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Understand the fundamental concepts of reverse invocation +- [Reverse Invocation Model](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) - Learn how to call model capabilities within the platform +- [Reverse Invocation Tool](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) - Learn how to call other plugins +- [Develop a Slack Bot Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - A practical application case using reverse invocation +- [Develop Extension Plugins](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - Learn how to develop extension plugins {/* Contributing Section @@ -140,5 +140,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9242-reverse-invocation-app.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9242-reverse-invocation-model.mdx b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx similarity index 85% rename from plugin-dev-en/9242-reverse-invocation-model.mdx rename to en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx index a8ac3723..ece1d56e 100644 --- a/plugin-dev-en/9242-reverse-invocation-model.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx @@ -14,9 +14,9 @@ description: This document details how plugins can reverse invoke model services examples, and best practice recommendations for invoking models. --- -Reverse invoking a Model refers to the ability of a plugin to call Dify's internal LLM capabilities, including all model types and functions within the platform, such as TTS, Rerank, etc. If you are not familiar with the basic concepts of reverse invocation, please read [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation) first. +Reverse invoking a Model refers to the ability of a plugin to call Dify's internal LLM capabilities, including all model types and functions within the platform, such as TTS, Rerank, etc. If you are not familiar with the basic concepts of reverse invocation, please read [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) first. -However, please note that invoking a model requires passing a `ModelConfig` type parameter. Its structure can be referenced in the [General Specifications Definition](/plugin-dev-en/0411-general-specifications), and this structure will have slight differences for different types of models. +However, please note that invoking a model requires passing a `ModelConfig` type parameter. Its structure can be referenced in the [General Specifications Definition](/en/develop-plugin/features-and-specs/plugin-types/general-specifications), and this structure will have slight differences for different types of models. For example, for `LLM` type models, it also needs to include `completion_params` and `mode` parameters. You can manually construct this structure or use `model-selector` type parameters or configurations. @@ -280,11 +280,11 @@ If this endpoint returns `true`, it indicates that the `text` contains sensitive ## Related Resources -- [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation) - Understand the fundamental concepts of reverse invocation -- [Reverse Invocation of App](/plugin-dev-en/9242-reverse-invocation-app) - Learn how to invoke Apps within the platform -- [Reverse Invocation of Tool](/plugin-dev-en/9242-reverse-invocation-tool) - Learn how to invoke other plugins -- [Model Plugin Development Guide](/plugin-dev-en/0211-getting-started-new-model) - Learn how to develop custom model plugins -- [Model Designing Rules](/plugin-dev-en/0411-model-designing-rules) - Understand the design principles of model plugins +- [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Understand the fundamental concepts of reverse invocation +- [Reverse Invocation of App](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - Learn how to invoke Apps within the platform +- [Reverse Invocation of Tool](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) - Learn how to invoke other plugins +- [Model Plugin Development Guide](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - Learn how to develop custom model plugins +- [Model Designing Rules](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - Understand the design principles of model plugins {/* Contributing Section @@ -294,5 +294,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9242-reverse-invocation-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9243-reverse-invocation-node.mdx b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx similarity index 92% rename from plugin-dev-en/9243-reverse-invocation-node.mdx rename to en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx index 4993619e..8cadd8ba 100644 --- a/plugin-dev-en/9243-reverse-invocation-node.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx @@ -39,7 +39,7 @@ The `ParameterExtractor` and `QuestionClassifier` nodes in `Workflow` encapsulat pass ``` -Here, `parameters` is a list of parameters to be extracted, `model` conforms to the `LLMModelConfig` specification, `query` is the source text for parameter extraction, and `instruction` provides any additional instructions that might be needed for the LLM. For the structure of `NodeResponse`, please refer to this [document](/plugin-dev-en/0411-general-specifications.mdx#noderesponse). +Here, `parameters` is a list of parameters to be extracted, `model` conforms to the `LLMModelConfig` specification, `query` is the source text for parameter extraction, and `instruction` provides any additional instructions that might be needed for the LLM. For the structure of `NodeResponse`, please refer to this [document](/en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx#noderesponse). #### **Use Case** @@ -109,5 +109,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9243-reverse-invocation-node.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9242-reverse-invocation-tool.mdx b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx similarity index 72% rename from plugin-dev-en/9242-reverse-invocation-tool.mdx rename to en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx index 71c8a6f8..9e961b2d 100644 --- a/plugin-dev-en/9242-reverse-invocation-tool.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx @@ -13,7 +13,7 @@ description: This document details how plugins can reverse invoke Tool services Tool). Each method includes corresponding entry points and interface parameter descriptions. --- -Reverse invoking a Tool means that a plugin can call other tool-type plugins within the Dify platform. If you are unfamiliar with the basic concepts of reverse invocation, please first read [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation.mdx). +Reverse invoking a Tool means that a plugin can call other tool-type plugins within the Dify platform. If you are unfamiliar with the basic concepts of reverse invocation, please first read [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation). Consider the following scenarios: @@ -48,7 +48,7 @@ Here, `provider` is the plugin ID plus the tool provider name, formatted like `l ### Calling Workflow as Tool -For more information on Workflow as Tool, please refer to the [Tool Plugin documentation](/plugin-dev-en/0222-tool-plugin.mdx). (Note: Original link `/plugin-dev-zh/9223-tool` does not exist in English list, linked to closest match). +For more information on Workflow as Tool, please refer to the [Tool Plugin documentation](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin). **Entry Point** @@ -88,11 +88,11 @@ Here, `provider` is the ID of this tool, and `tool_name` is the `operation_id` f ## Related Resources -- [Reverse Invocation of Dify Services](/plugin-dev-en/9241-reverse-invocation.mdx) - Understand the fundamental concepts of reverse invocation -- [Reverse Invocation App](/plugin-dev-en/9242-reverse-invocation-app.mdx) - Learn how to call Apps within the platform -- [Reverse Invocation Model](/plugin-dev-en/9242-reverse-invocation-model.mdx) - Learn how to call model capabilities within the platform -- [Tool Plugin Development Guide](/plugin-dev-en/0211-getting-started-dify-tool.mdx) - Learn how to develop tool plugins -- [Advanced Tool Plugins](/plugin-dev-en/0222-tool-plugin.mdx) - Learn about advanced features like Workflow as Tool (Note: Original link `/plugin-dev-zh/9223-tool` does not exist in English list, linked to closest match) +- [Reverse Invocation of Dify Services](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Understand the fundamental concepts of reverse invocation +- [Reverse Invocation App](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - Learn how to call Apps within the platform +- [Reverse Invocation Model](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) - Learn how to call model capabilities within the platform +- [Tool Plugin Development Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Learn how to develop tool plugins +- [Advanced Tool Plugins](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Learn about advanced features like Workflow as Tool {/* Contributing Section @@ -102,5 +102,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9242-reverse-invocation-tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/9241-reverse-invocation.mdx b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx similarity index 52% rename from plugin-dev-en/9241-reverse-invocation.mdx rename to en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx index 77afe7f1..19889a9e 100644 --- a/plugin-dev-en/9241-reverse-invocation.mdx +++ b/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx @@ -18,25 +18,25 @@ Plugins can freely call some services within the main Dify platform to enhance t ### Callable Dify Modules -* [App](/plugin-dev-en/9242-reverse-invocation-app.mdx) +* [App](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) Plugins can access data from Apps within the Dify platform. -* [Model](/plugin-dev-en/9242-reverse-invocation-model.mdx) +* [Model](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) Plugins can reverse invoke LLM capabilities within the Dify platform, including all model types and functions within the platform, such as TTS, Rerank, etc. -* [Tool](/plugin-dev-en/9242-reverse-invocation-tool.mdx) +* [Tool](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) Plugins can call other tool-type plugins within the Dify platform. -* [Node](/plugin-dev-en/9243-reverse-invocation-node.mdx) +* [Node](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node) Plugins can call nodes within a specific Chatflow/Workflow application in the Dify platform. ## Related Resources -- [Develop Extension Plugins](/plugin-dev-en/9231-extension-plugin.mdx) - Learn how to develop plugins that integrate with external systems -- [Develop a Slack Bot Plugin](/plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx) - An example of using reverse invocation to integrate with the Slack platform -- [Bundle Type Plugins](/plugin-dev-en/9241-bundle.mdx) - Learn how to package multiple plugins that use reverse invocation -- [Using Persistent Storage](/plugin-dev-en/0411-persistent-storage-kv.mdx) - Enhance plugin capabilities through KV storage +- [Develop Extension Plugins](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint) - Learn how to develop plugins that integrate with external systems +- [Develop a Slack Bot Plugin](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - An example of using reverse invocation to integrate with the Slack platform +- [Bundle Type Plugins](/en/develop-plugin/features-and-specs/advanced-development/bundle) - Learn how to package multiple plugins that use reverse invocation +- [Using Persistent Storage](/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) - Enhance plugin capabilities through KV storage {/* Contributing Section @@ -46,5 +46,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9241-reverse-invocation.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-general-specifications.mdx b/en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx similarity index 87% rename from plugin-dev-en/0411-general-specifications.mdx rename to en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx index 687fec0d..c31fe5d6 100644 --- a/plugin-dev-en/0411-general-specifications.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx @@ -7,7 +7,7 @@ dimensions: standard_title: General Specs language: en title: General Specs -description: This article will briefly introduce common structures in plugin development. During development, it is strongly recommended to read this alongside [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) and the [Developer Cheatsheet](/plugin-dev-en/0111-cli) for a better understanding of the overall architecture. +description: This article will briefly introduce common structures in plugin development. During development, it is strongly recommended to read this alongside [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) and the [Developer Cheatsheet](/en/develop-plugin/getting-started/cli) for a better understanding of the overall architecture. --- ### Path Specifications @@ -196,7 +196,7 @@ When `type` is `tool-selector`: - Enumeration of model types, refer to the [Model Design Rules](/plugin-dev-en/0411-model-designing-rules#modeltype) document + Enumeration of model types, refer to the [Model Design Rules](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules#modeltype) document #### NodeResponse @@ -261,10 +261,10 @@ When `type` is `tool-selector`: ## Related Resources -- [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) - Comprehensive understanding of Dify plugin development -- [Developer Cheatsheet](/plugin-dev-en/0131-cheatsheet) - Quick reference for common commands and concepts in plugin development -- [Tool Plugin Development Details](/plugin-dev-en/0222-tool-plugin) - Understanding how to define plugin information and the tool plugin development process -- [Model Design Rules](/plugin-dev-en/0411-model-designing-rules) - Understanding the standards for model configuration +- [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) - Comprehensive understanding of Dify plugin development +- [Developer Cheatsheet](/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet) - Quick reference for common commands and concepts in plugin development +- [Tool Plugin Development Details](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Understanding how to define plugin information and the tool plugin development process +- [Model Design Rules](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - Understanding the standards for model configuration {/* Contributing Section @@ -274,5 +274,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-general-specifications.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-model-designing-rules.mdx b/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx similarity index 94% rename from plugin-dev-en/0411-model-designing-rules.mdx rename to en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx index 65daef03..0160f127 100644 --- a/plugin-dev-en/0411-model-designing-rules.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx @@ -312,7 +312,7 @@ description: This document defines in detail the core concepts and structures fo Use template -> For details on using templates, you can refer to the examples in [Creating a New Model Provider](/plugin-dev-en/0222-creating-new-model-provider). +> For details on using templates, you can refer to the examples in [Creating a New Model Provider](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider). There are 5 pre-configured variable content templates by default: @@ -560,10 +560,10 @@ You can directly set the template variable name in `use_template`, which will us ## Related Resources -- [Model Architecture Details](/plugin-dev-en/0412-model-schema) - Deep dive into the architecture specifications of model plugins -- [Quickly Integrate a New Model](/plugin-dev-en/0211-getting-started-new-model) - Learn how to apply these rules to add new models -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Understand the configuration of plugin manifest files -- [Create a New Model Provider](/plugin-dev-en/0222-creating-new-model-provider) - Develop brand new model provider plugins +- [Model Architecture Details](/en/develop-plugin/features-and-specs/plugin-types/model-schema) - Deep dive into the architecture specifications of model plugins +- [Quickly Integrate a New Model](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - Learn how to apply these rules to add new models +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Understand the configuration of plugin manifest files +- [Create a New Model Provider](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - Develop brand new model provider plugins {/* Contributing Section @@ -573,5 +573,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-model-designing-rules.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0412-model-schema.mdx b/en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx similarity index 97% rename from plugin-dev-en/0412-model-schema.mdx rename to en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx index a8aa980e..33b29dcf 100644 --- a/plugin-dev-en/0412-model-schema.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx @@ -15,7 +15,7 @@ description: Comprehensive guide to the Dify model plugin API including implemen This document details the interfaces and data structures required to implement Dify model plugins. It serves as a technical reference for developers integrating AI models with the Dify platform. -Before diving into this API reference, we recommend first reading the [Model Design Rules](/plugin-dev-en/0411-model-designing-rules) and [Model Plugin Introduction](/plugin-dev-en/0131-model-plugin-introduction) for conceptual understanding. +Before diving into this API reference, we recommend first reading the [Model Design Rules](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) and [Model Plugin Introduction](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) for conceptual understanding. @@ -1245,10 +1245,10 @@ class RerankDocument(BaseModel): ## Related Resources -- [Model Design Rules](/plugin-dev-en/0411-model-designing-rules) - Understand the standards for model configuration -- [Model Plugin Introduction](/plugin-dev-en/0411-model-plugin-introduction) - Quickly understand the basic concepts of model plugins -- [Quickly Integrate a New Model](/plugin-dev-en/0211-getting-started-new-model) - Learn how to add new models to existing providers -- [Create a New Model Provider](/plugin-dev-en/0222-creating-new-model-provider) - Learn how to develop brand new model providers +- [Model Design Rules](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - Understand the standards for model configuration +- [Model Plugin Introduction](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - Quickly understand the basic concepts of model plugins +- [Quickly Integrate a New Model](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - Learn how to add new models to existing providers +- [Create a New Model Provider](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - Learn how to develop brand new model providers {/* Contributing Section @@ -1258,5 +1258,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0412-model-schema.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-multilingual-readme.mdx b/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx similarity index 92% rename from plugin-dev-en/0411-multilingual-readme.mdx rename to en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx index 9272c14b..d29fad84 100644 --- a/plugin-dev-en/0411-multilingual-readme.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx @@ -47,5 +47,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-multilingual-readme.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-persistent-storage-kv.mdx b/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx similarity index 96% rename from plugin-dev-en/0411-persistent-storage-kv.mdx rename to en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx index 8a79d7e0..cf825adb 100644 --- a/plugin-dev-en/0411-persistent-storage-kv.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx @@ -157,5 +157,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-persistent-storage-kv.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-plugin-info-by-manifest.mdx b/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx similarity index 88% rename from plugin-dev-en/0411-plugin-info-by-manifest.mdx rename to en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx index 8f422676..69f9e36f 100644 --- a/plugin-dev-en/0411-plugin-info-by-manifest.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx @@ -9,7 +9,7 @@ language: en title: Manifest --- -The Manifest is a YAML-compliant file that defines the most basic information of a **plugin**, including but not limited to the plugin name, author, included tools, models, etc. For the overall architecture of the plugin, please refer to [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) and [Developer Cheatsheet](/plugin-dev-en/0131-cheatsheet). +The Manifest is a YAML-compliant file that defines the most basic information of a **plugin**, including but not limited to the plugin name, author, included tools, models, etc. For the overall architecture of the plugin, please refer to [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) and [Developer Cheatsheet](/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet). If the format of this file is incorrect, the parsing and packaging process of the plugin will fail. @@ -192,19 +192,19 @@ privacy: "./privacy.md" - Plugin extension for [Tool](/plugin-dev-en/0222-tool-plugin) providers. + Plugin extension for [Tool](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) providers. - Plugin extension for [Model](/plugin-dev-en/0411-model-plugin-introduction) providers. + Plugin extension for [Model](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules) providers. - Plugin extension for [Endpoints](/plugin-dev-en/0432-develop-a-slack-bot-plugin) providers. + Plugin extension for [Endpoints](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) providers. - Plugin extension for [Agent Strategy](/plugin-dev-en/9433-agent-strategy-plugin) providers. + Plugin extension for [Agent Strategy](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation) providers. @@ -237,7 +237,7 @@ privacy: "./privacy.md" - Specifies the relative path or URL of the plugin's privacy policy file, e.g., `"./privacy.md"` or `"https://your-web/privacy"`. If you plan to list the plugin on the Dify Marketplace, **this field is required** to provide clear user data usage and privacy statements. For detailed filling guidelines, please refer to [Plugin Privacy Data Protection Guidelines](/plugin-dev-en/0312-privacy-protection-guidelines). + Specifies the relative path or URL of the plugin's privacy policy file, e.g., `"./privacy.md"` or `"https://your-web/privacy"`. If you plan to list the plugin on the Dify Marketplace, **this field is required** to provide clear user data usage and privacy statements. For detailed filling guidelines, please refer to [Plugin Privacy Data Protection Guidelines](/en/develop-plugin/publishing/standards/privacy-protection-guidelines). {/* @@ -248,5 +248,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-plugin-info-by-manifest.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-remote-debug-a-plugin.mdx b/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx similarity index 91% rename from plugin-dev-en/0411-remote-debug-a-plugin.mdx rename to en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx index 25fcd08f..0dfe644c 100644 --- a/plugin-dev-en/0411-remote-debug-a-plugin.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx @@ -42,5 +42,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-remote-debug-a-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0411-tool.mdx b/en/develop-plugin/features-and-specs/plugin-types/tool.mdx similarity index 98% rename from plugin-dev-en/0411-tool.mdx rename to en/develop-plugin/features-and-specs/plugin-types/tool.mdx index 27e54c69..40e66464 100644 --- a/plugin-dev-en/0411-tool.mdx +++ b/en/develop-plugin/features-and-specs/plugin-types/tool.mdx @@ -391,5 +391,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0411-tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0111-cli.mdx b/en/develop-plugin/getting-started/cli.mdx similarity index 97% rename from plugin-dev-en/0111-cli.mdx rename to en/develop-plugin/getting-started/cli.mdx index ad56a369..a3625611 100644 --- a/plugin-dev-en/0111-cli.mdx +++ b/en/develop-plugin/getting-started/cli.mdx @@ -151,5 +151,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0111-cli.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/cli.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0111-getting-started-dify-plugin.mdx b/en/develop-plugin/getting-started/getting-started-dify-plugin.mdx similarity index 61% rename from plugin-dev-en/0111-getting-started-dify-plugin.mdx rename to en/develop-plugin/getting-started/getting-started-dify-plugin.mdx index 93759483..96ac0067 100644 --- a/plugin-dev-en/0111-getting-started-dify-plugin.mdx +++ b/en/develop-plugin/getting-started/getting-started-dify-plugin.mdx @@ -27,38 +27,38 @@ Through plugins, your AI applications can: Package and manage AI models as plugins - Learn more + Learn more Build specialized capabilities for Agents and workflows - Learn more + Learn more Create custom reasoning strategies for autonomous Agents - Learn more + Learn more Implement integration with external services through HTTP Webhooks - Learn more + Learn more @@ -68,28 +68,28 @@ Through plugins, your AI applications can: Tools and techniques for efficient plugin development Package and share your plugins with the Dify community Technical specifications and documentation Communicate with other developers and contribute to the ecosystem @@ -103,5 +103,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0111-getting-started-dify-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/getting-started-dify-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0331-faq.mdx b/en/develop-plugin/publishing/faq/faq.mdx similarity index 93% rename from plugin-dev-en/0331-faq.mdx rename to en/develop-plugin/publishing/faq/faq.mdx index cb27128c..fa2bef66 100644 --- a/plugin-dev-en/0331-faq.mdx +++ b/en/develop-plugin/publishing/faq/faq.mdx @@ -47,5 +47,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0331-faq.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/faq/faq.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0321-plugin-auto-publish-pr.mdx b/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx similarity index 98% rename from plugin-dev-en/0321-plugin-auto-publish-pr.mdx rename to en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx index 294d67cf..c2461022 100644 --- a/plugin-dev-en/0321-plugin-auto-publish-pr.mdx +++ b/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx @@ -312,5 +312,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0321-plugin-auto-publish-pr.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0322-release-by-file.mdx b/en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx similarity index 63% rename from plugin-dev-en/0322-release-by-file.mdx rename to en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx index 2f6c09c7..0bf58c56 100644 --- a/plugin-dev-en/0322-release-by-file.mdx +++ b/en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx @@ -14,7 +14,7 @@ description: This document provides detailed steps on how to package a Dify plug with other users. --- -After completing plugin development, you can package the plugin project as a local file and share it with others. After obtaining the plugin file, it can be installed into a Dify Workspace. If you haven't developed a plugin yet, you can refer to the [Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool). +After completing plugin development, you can package the plugin project as a local file and share it with others. After obtaining the plugin file, it can be installed into a Dify Workspace. If you haven't developed a plugin yet, you can refer to the [Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin). * **Features**: * Not dependent on online platforms, **quick and flexible** way to share plugins. @@ -27,15 +27,15 @@ This article will introduce how to package a plugin project as a local file and ### Prerequisites -* **Dify Plugin Development Tool**, for detailed instructions, please refer to [Initializing Development Tools](/plugin-dev-en/0221-initialize-development-tools). +* **Dify Plugin Development Tool**, for detailed instructions, please refer to [Initializing Development Tools](/en/develop-plugin/getting-started/cli). After configuration, enter the `dify version` command in the terminal to check if it outputs version information to confirm that the necessary development tools have been installed. ### Packaging the Plugin -> Before packaging the plugin, please ensure that the `author` field in the plugin's `manifest.yaml` file and the `.yaml` file under the `/provider` path is consistent with your GitHub ID. For detailed information about the manifest file, please refer to [General Specifications](/plugin-dev-en/0411-general-specifications). +> Before packaging the plugin, please ensure that the `author` field in the plugin's `manifest.yaml` file and the `.yaml` file under the `/provider` path is consistent with your GitHub ID. For detailed information about the manifest file, please refer to [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications). -After completing the plugin project development, make sure you have completed the [remote debugging test](/plugin-dev-en/0411-remote-debug-a-plugin). Navigate to the directory above your plugin project and run the following plugin packaging command: +After completing the plugin project development, make sure you have completed the [remote debugging test](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin). Navigate to the directory above your plugin project and run the following plugin packaging command: ```bash dify plugin package ./your_plugin_project @@ -55,16 +55,16 @@ Visit the Dify plugin management page, click **Install Plugin** in the upper rig You can share the plugin file with others or upload it to the internet for others to download. If you want to share your plugin more widely, you can consider: -1. [Publish to Individual GitHub Repository](/plugin-dev-en/0322-release-to-individual-github-repo) - Share the plugin through GitHub -2. [Publish to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace) - Publish the plugin on the official marketplace +1. [Publish to Individual GitHub Repository](/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo) - Share the plugin through GitHub +2. [Publish to Dify Marketplace](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - Publish the plugin on the official marketplace ## Related Resources -- [Publishing Plugins](/plugin-dev-en/0321-release-overview) - Learn about various publishing methods -- [Initializing Development Tools](/plugin-dev-en/0221-initialize-development-tools) - Configure plugin development environment -- [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) - Learn plugin debugging methods -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Define plugin metadata -- [Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool) - Develop a plugin from scratch +- [Publishing Plugins](/en/develop-plugin/publishing/marketplace-listing/release-overview) - Learn about various publishing methods +- [Initializing Development Tools](/en/develop-plugin/getting-started/cli) - Configure plugin development environment +- [Remote Debugging Plugins](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - Learn plugin debugging methods +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Define plugin metadata +- [Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Develop a plugin from scratch {/* Contributing Section @@ -74,5 +74,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0322-release-by-file.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0321-release-overview.mdx b/en/develop-plugin/publishing/marketplace-listing/release-overview.mdx similarity index 71% rename from plugin-dev-en/0321-release-overview.mdx rename to en/develop-plugin/publishing/marketplace-listing/release-overview.mdx index e1448d54..b335c719 100644 --- a/plugin-dev-en/0321-release-overview.mdx +++ b/en/develop-plugin/publishing/marketplace-listing/release-overview.mdx @@ -16,7 +16,7 @@ description: This document introduces three ways to publish Dify plugins - offic ### Publishing Methods -To meet the publishing needs of different developers, Dify provides the following three plugin publishing methods. Before publishing, please ensure that you have completed the development and testing of your plugin, and have read [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) and [Plugin Developer Guidelines](/plugin-dev-en/0312-contributor-covenant-code-of-conduct). +To meet the publishing needs of different developers, Dify provides the following three plugin publishing methods. Before publishing, please ensure that you have completed the development and testing of your plugin, and have read [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) and [Plugin Developer Guidelines](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct). #### **1. Marketplace** @@ -34,7 +34,7 @@ To meet the publishing needs of different developers, Dify provides the followin For detailed instructions, please refer to: -[Publish to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace) +[Publish to Dify Marketplace](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) #### 2. **GitHub Repository** @@ -52,7 +52,7 @@ For detailed instructions, please refer to: For detailed instructions, please refer to: -[Publish to Individual GitHub Repository](/plugin-dev-en/0322-release-to-individual-github-repo) +[Publish to Individual GitHub Repository](/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo) #### 3. Plugin File Package (Local Installation) @@ -72,7 +72,7 @@ You can package your plugin project as a local file and share it with others. Af For detailed instructions, please refer to: -[Package as Local File and Share](/plugin-dev-en/0322-release-by-file) +[Package as Local File and Share](/en/develop-plugin/publishing/marketplace-listing/release-by-file) ### **Publishing Recommendations** @@ -82,10 +82,10 @@ For detailed instructions, please refer to: ## Related Resources -- [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) - Comprehensive understanding of Dify plugin development -- [Plugin Developer Guidelines](/plugin-dev-en/0312-contributor-covenant-code-of-conduct) - Understand the standards for plugin submission -- [Plugin Privacy Data Protection Guide](/plugin-dev-en/0312-privacy-protection-guidelines) - Understand the requirements for writing privacy policies -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Understand the configuration of plugin manifest files +- [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) - Comprehensive understanding of Dify plugin development +- [Plugin Developer Guidelines](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - Understand the standards for plugin submission +- [Plugin Privacy Data Protection Guide](/en/develop-plugin/publishing/standards/privacy-protection-guidelines) - Understand the requirements for writing privacy policies +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Understand the configuration of plugin manifest files {/* Contributing Section @@ -95,5 +95,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0321-release-overview.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-overview.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0322-release-to-dify-marketplace.mdx b/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx similarity index 70% rename from plugin-dev-en/0322-release-to-dify-marketplace.mdx rename to en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx index 37bfe26d..1bae4c5b 100644 --- a/plugin-dev-en/0322-release-to-dify-marketplace.mdx +++ b/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx @@ -12,7 +12,7 @@ description: This guide provides detailed instructions on the complete process o process, post-release maintenance, and other key steps and considerations. --- -Dify Marketplace welcomes plugin submissions from partners and community developers. Your contributions will further enrich the possibilities of Dify plugins. This guide provides a clear publishing process and best practice recommendations to help your plugin get published smoothly and bring value to the community. If you haven't developed a plugin yet, you can refer to the [Plugin Development: Hello World Guide](/plugin-dev-en/0211-getting-started-dify-tool). +Dify Marketplace welcomes plugin submissions from partners and community developers. Your contributions will further enrich the possibilities of Dify plugins. This guide provides a clear publishing process and best practice recommendations to help your plugin get published smoothly and bring value to the community. If you haven't developed a plugin yet, you can refer to the [Plugin Development: Hello World Guide](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin). Please follow these steps to submit your plugin Pull Request (PR) to the [GitHub repository](https://github.com/langgenius/dify-plugins) for review. After approval, your plugin will be officially launched on the Dify Marketplace. @@ -20,8 +20,8 @@ Please follow these steps to submit your plugin Pull Request (PR) to the [GitHub Publishing a plugin to the Dify Marketplace involves the following steps: -1. Complete plugin development and testing according to the [Plugin Developer Guidelines](/plugin-dev-en/0312-contributor-covenant-code-of-conduct); -2. Write a privacy policy for the plugin according to the [Plugin Privacy Data Protection Guide](/plugin-dev-en/0312-privacy-protection-guidelines), and include the file path or URL of the privacy policy in the plugin [General Specifications](/plugin-dev-en/0411-general-specifications); +1. Complete plugin development and testing according to the [Plugin Developer Guidelines](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct); +2. Write a privacy policy for the plugin according to the [Plugin Privacy Data Protection Guide](/en/develop-plugin/publishing/standards/privacy-protection-guidelines), and include the file path or URL of the privacy policy in the plugin [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications); 3. Complete plugin packaging; 4. Fork the [Dify Plugins](https://github.com/langgenius/dify-plugins) code repository; 5. Create your personal or organization folder in the repository and upload the packaged `.difypkg` file to your folder; @@ -32,7 +32,7 @@ Plugin submission, review, and publication flow chart: ![The process of uploading plugins](https://assets-docs.dify.ai/2025/01/05df333acfaf662e99316432db23ba9f.png) -> **Note**: The Contributor Agreement in the above diagram refers to the [Plugin Developer Guidelines](/plugin-dev-en/0312-contributor-covenant-code-of-conduct). +> **Note**: The Contributor Agreement in the above diagram refers to the [Plugin Developer Guidelines](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct). *** @@ -69,11 +69,11 @@ Actively respond to reviewer questions and feedback: **2. Review Focus** * Check if the plugin name, description, and setup instructions are clear and instructive. -* Check if the plugin's [General Specifications](/plugin-dev-en/0411-general-specifications) meets format standards and includes valid author contact information. +* Check if the plugin's [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) meets format standards and includes valid author contact information. **3. Plugin Functionality and Relevance** -* Test plugins according to the [Plugin Development Guide](/plugin-dev-en/0111-getting-started-dify-plugin). +* Test plugins according to the [Plugin Development Guide](/en/develop-plugin/getting-started/getting-started-dify-plugin). * Ensure the plugin has a reasonable purpose in the Dify ecosystem. [Dify.AI](https://dify.ai/) reserves the right to accept or reject plugin submissions. @@ -96,11 +96,11 @@ Yes, but breaking changes should be avoided. ## Related Resources -- [Publishing Plugins](/plugin-dev-en/0321-release-overview) - Learn about various publishing methods -- [Plugin Developer Guidelines](/plugin-dev-en/0312-contributor-covenant-code-of-conduct) - Plugin submission standards -- [Plugin Privacy Data Protection Guide](/plugin-dev-en/0312-privacy-protection-guidelines) - Privacy policy writing requirements -- [Package as Local File and Share](/plugin-dev-en/0322-release-by-file) - Plugin packaging methods -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Define plugin metadata +- [Publishing Plugins](/en/develop-plugin/publishing/marketplace-listing/release-overview) - Learn about various publishing methods +- [Plugin Developer Guidelines](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - Plugin submission standards +- [Plugin Privacy Data Protection Guide](/en/develop-plugin/publishing/standards/privacy-protection-guidelines) - Privacy policy writing requirements +- [Package as Local File and Share](/en/develop-plugin/publishing/marketplace-listing/release-by-file) - Plugin packaging methods +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Define plugin metadata {/* Contributing Section @@ -110,5 +110,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0322-release-to-dify-marketplace.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0322-release-to-individual-github-repo.mdx b/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx similarity index 95% rename from plugin-dev-en/0322-release-to-individual-github-repo.mdx rename to en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx index 5dada2ce..82f80580 100644 --- a/plugin-dev-en/0322-release-to-individual-github-repo.mdx +++ b/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx @@ -91,5 +91,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0322-release-to-individual-github-repo.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0312-contributor-covenant-code-of-conduct.mdx b/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx similarity index 87% rename from plugin-dev-en/0312-contributor-covenant-code-of-conduct.mdx rename to en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx index 17b7939d..4a47ea55 100644 --- a/plugin-dev-en/0312-contributor-covenant-code-of-conduct.mdx +++ b/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx @@ -35,7 +35,7 @@ description: To ensure the quality of all plugins in the Dify Marketplace and pr - **Brand Alignment**: Plugin name must match the plugin's branding. -- **Functionality Verification**: Test the plugin thoroughly before submission and confirm it works as intended. For details, refer to [Remote Debug a Plugin](/plugin-dev-en/0411-remote-debug-a-plugin). The plugin must be production-ready. +- **Functionality Verification**: Test the plugin thoroughly before submission and confirm it works as intended. For details, refer to [Remote Debug a Plugin](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin). The plugin must be production-ready. - **README Requirements**: - Setup instructions and usage guidance. @@ -54,7 +54,7 @@ description: To ensure the quality of all plugins in the Dify Marketplace and pr - **Authentication Settings**: If authentication is needed, include the full configuration steps—do not omit them. -- **Privacy Policy**: Prepare a privacy policy document or online URL in accordance with the [Privacy Guidelines](/plugin-dev-en/0312-privacy-protection-guidelines). +- **Privacy Policy**: Prepare a privacy policy document or online URL in accordance with the [Privacy Guidelines](/en/develop-plugin/publishing/standards/privacy-protection-guidelines). - **Performance**: Plugins must operate efficiently and must not degrade the performance of Dify or user systems. @@ -133,7 +133,7 @@ description: To ensure the quality of all plugins in the Dify Marketplace and pr ## 9. Privacy and Data Compliance -- **Disclosure Required**: You **must declare** whether your plugin collects any user personal data. See the [Privacy Guidelines](/plugin-dev-en/0312-privacy-protection-guidelines). +- **Disclosure Required**: You **must declare** whether your plugin collects any user personal data. See the [Privacy Guidelines](/en/develop-plugin/publishing/standards/privacy-protection-guidelines). - **Simple Data Listing**: If collecting data, briefly list types (e.g., username, email, device ID, location). No need for exhaustive detail. @@ -159,11 +159,11 @@ description: To ensure the quality of all plugins in the Dify Marketplace and pr ## Related Resources -- [Basic Concepts of Plugin Development](/plugin-dev-en/0111-getting-started-dify-plugin) - Learn the basics of plugin development -- [Publishing Plugins](/plugin-dev-en/0321-release-overview) - Overview of the plugin publishing process -- [Plugin Privacy Data Protection Guide](/plugin-dev-en/0312-privacy-protection-guidelines) - Guide for writing privacy policies -- [Publish to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace) - Publish plugins on the official marketplace -- [Remote Debugging Plugins](/plugin-dev-en/0411-remote-debug-a-plugin) - Plugin debugging guide +- [Basic Concepts of Plugin Development](/en/develop-plugin/getting-started/getting-started-dify-plugin) - Learn the basics of plugin development +- [Publishing Plugins](/en/develop-plugin/publishing/marketplace-listing/release-overview) - Overview of the plugin publishing process +- [Plugin Privacy Data Protection Guide](/en/develop-plugin/publishing/standards/privacy-protection-guidelines) - Guide for writing privacy policies +- [Publish to Dify Marketplace](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - Publish plugins on the official marketplace +- [Remote Debugging Plugins](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - Plugin debugging guide {/* Contributing Section @@ -173,5 +173,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0312-contributor-covenant-code-of-conduct.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0312-privacy-protection-guidelines.mdx b/en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx similarity index 84% rename from plugin-dev-en/0312-privacy-protection-guidelines.mdx rename to en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx index 7757caff..896e6fad 100644 --- a/plugin-dev-en/0312-privacy-protection-guidelines.mdx +++ b/en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx @@ -69,7 +69,7 @@ For example, if the plugin you are developing involves Slack services, make sure #### 3. Introducing a privacy policy statement within the plugin Manifest file -For detailed instructions on filling out specific fields, please refer to the [General Specifications](/plugin-dev-en/0411-general-specifications) documentation. +For detailed instructions on filling out specific fields, please refer to the [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) documentation. **FAQ** @@ -89,10 +89,10 @@ For detailed instructions on filling out specific fields, please refer to the [G ## Related Resources -- [Publishing Overview](/plugin-dev-en/0321-release-overview) - Understand the plugin publishing process -- [Publish to Dify Marketplace](/plugin-dev-en/0322-release-to-dify-marketplace) - Learn how to submit plugins to the official marketplace -- [Plugin Developer Guidelines](/plugin-dev-en/0312-contributor-covenant-code-of-conduct) - Understand plugin submission guidelines -- [General Specifications](/plugin-dev-en/0411-general-specifications) - Plugin metadata configuration +- [Publishing Overview](/en/develop-plugin/publishing/marketplace-listing/release-overview) - Understand the plugin publishing process +- [Publish to Dify Marketplace](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - Learn how to submit plugins to the official marketplace +- [Plugin Developer Guidelines](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - Understand plugin submission guidelines +- [General Specifications](/en/develop-plugin/features-and-specs/plugin-types/general-specifications) - Plugin metadata configuration {/* Contributing Section @@ -102,5 +102,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0312-privacy-protection-guidelines.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/plugin-dev-en/0312-third-party-signature-verification.mdx b/en/develop-plugin/publishing/standards/third-party-signature-verification.mdx similarity index 96% rename from plugin-dev-en/0312-third-party-signature-verification.mdx rename to en/develop-plugin/publishing/standards/third-party-signature-verification.mdx index 7b6dcec6..9aebc73a 100644 --- a/plugin-dev-en/0312-third-party-signature-verification.mdx +++ b/en/develop-plugin/publishing/standards/third-party-signature-verification.mdx @@ -115,5 +115,5 @@ It will be automatically generated by the script. --- -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/0312-third-party-signature-verification.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/third-party-signature-verification.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) diff --git a/en/use-dify/build/predefined-error-handling-logic.mdx b/en/use-dify/build/predefined-error-handling-logic.mdx index f38a1f20..347309ca 100644 --- a/en/use-dify/build/predefined-error-handling-logic.mdx +++ b/en/use-dify/build/predefined-error-handling-logic.mdx @@ -67,7 +67,7 @@ When you set an iteration to `continue-on-error`, failed items return `null` in When using default value or fail branch, you get two special variables: -- `error_type` - What kind of error happened (see [Error Types](en/use-dify/debug/error-types)) +- `error_type` - What kind of error happened (see [Error Types](/en/use-dify/debug/error-types)) - `error_message` - The actual error details Use these to: diff --git a/en/use-dify/build/shortcut-key.mdx b/en/use-dify/build/shortcut-key.mdx index 8574083d..7c5d0148 100644 --- a/en/use-dify/build/shortcut-key.mdx +++ b/en/use-dify/build/shortcut-key.mdx @@ -6,7 +6,7 @@ icon: "keyboard" Speed up your workflow building with keyboard shortcuts. -**[Go to Anything](en/use-dify/build/goto-anything)**: Press `Cmd+K` (macOS) or `Ctrl+K` (Windows) anywhere in Dify to search and jump to everything—apps, plugins, knowledge bases, even workflow nodes. Use slash commands like `/theme` to change appearance, `/language` to switch languages, or `/help` to access documentation. +**[Go to Anything](/en/use-dify/build/goto-anything)**: Press `Cmd+K` (macOS) or `Ctrl+K` (Windows) anywhere in Dify to search and jump to everything—apps, plugins, knowledge bases, even workflow nodes. Use slash commands like `/theme` to change appearance, `/language` to switch languages, or `/help` to access documentation. ![Command+K search interface](/images/command-k.gif) diff --git a/en/use-dify/nodes/tools.mdx b/en/use-dify/nodes/tools.mdx index 94a8f55d..3b948007 100644 --- a/en/use-dify/nodes/tools.mdx +++ b/en/use-dify/nodes/tools.mdx @@ -86,4 +86,4 @@ Configure robust error handling for tools that depend on external services: Access tool configuration through **Tools** in your workspace navigation. Here you can manage authentication credentials, import custom tools, configure MCP servers, and publish workflows as tools. -For detailed guidance on tool creation, management, and publishing workflows as tools, see the [Tool Configuration Guide](/plugin-dev-en/getting-started-dify-plugin). +For detailed guidance on tool creation, management, and publishing workflows as tools, see the [Tool Configuration Guide](/en/develop-plugin/getting-started/getting-started-dify-plugin). diff --git a/en/use-dify/nodes/trigger/plugin-trigger.mdx b/en/use-dify/nodes/trigger/plugin-trigger.mdx index 731a5ead..dbe3a39a 100644 --- a/en/use-dify/nodes/trigger/plugin-trigger.mdx +++ b/en/use-dify/nodes/trigger/plugin-trigger.mdx @@ -17,7 +17,7 @@ For example, suppose you have installed a GitHub trigger plugin. It provides a l 1. On the workflow canvas, right-click and select **Add Node** > **Start**, then choose from the available plugin triggers or search for more in [Dify Marketplace](https://marketplace.dify.ai/?language=en-US&category=trigger). - - If there's no suitable trigger plugin for your target external system, you can [request one from the community](https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml), [develop one yourself](/plugin-dev-en/0222-trigger-plugin), or use a [webhook trigger](/en/use-dify/nodes/trigger/webhook-trigger) instead. + - If there's no suitable trigger plugin for your target external system, you can [request one from the community](https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml), [develop one yourself](/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin), or use a [webhook trigger](/en/use-dify/nodes/trigger/webhook-trigger) instead. - A workflow can have multiple plugin triggers running in parallel. When the parallel branches contain identical consecutive nodes, you can add a [Variable Aggregator](/en/use-dify/nodes/variable-aggregator) node to merge the branches before the common section, without duplicating the same nodes across each branch. diff --git a/en/use-dify/nodes/variable-assigner.mdx b/en/use-dify/nodes/variable-assigner.mdx index c91efd80..1b29c6fb 100644 --- a/en/use-dify/nodes/variable-assigner.mdx +++ b/en/use-dify/nodes/variable-assigner.mdx @@ -4,7 +4,7 @@ description: "Manage persistent conversation variables in chatflow applications" icon: "pen-to-square" --- -The Variable Assigner node manages persistent data in chatflow applications by writing to conversation variables (Understand the different types of variables [here](en/use-dify/getting-started/key-concepts#variables)). Unlike regular workflow variables that reset with each execution, conversation variables persist throughout an entire chat session. +The Variable Assigner node manages persistent data in chatflow applications by writing to conversation variables (Understand the different types of variables [here](/en/use-dify/getting-started/key-concepts#variables)). Unlike regular workflow variables that reset with each execution, conversation variables persist throughout an entire chat session. Variable Assigner interface diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx new file mode 100644 index 00000000..99487baa --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx @@ -0,0 +1,164 @@ +--- +dimensions: + type: + primary: conceptual + detail: architecture + level: beginner +standard_title: Cheatsheet +language: en +title: Dify プラグイン開発チートシート +description: 環境要件、インストール方法、開発プロセス、プラグインのカテゴリとタイプ、一般的なコードスニペット、よくある問題の解決策を含む、Dify プラグイン開発の包括的なリファレンスガイドです。開発者が素早く参照できるように設計されています。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet)を参照してください。 + +### 環境要件 + +- Python バージョン ≥ 3.12 +- Dify プラグインスキャフォールドツール (dify-plugin-daemon) + +> 詳細: [開発ツールの初期化](/ja/develop-plugin/getting-started/cli) + +### Dify プラグイン開発パッケージの取得 + +[Dify Plugin CLI](https://github.com/langgenius/dify-plugin-daemon/releases) + +#### 各プラットフォームのインストール方法 + +**macOS [Brew](https://github.com/langgenius/homebrew-dify) (グローバルインストール):** + +```bash +brew tap langgenius/dify +brew install dify +``` + +インストール後、新しいターミナルウィンドウを開き、`dify version` コマンドを入力してください。バージョン情報が出力されれば、インストールは成功です。 + +**macOS ARM (M シリーズチップ):** + +```bash +# Download dify-plugin-darwin-arm64 +chmod +x dify-plugin-darwin-arm64 +./dify-plugin-darwin-arm64 version +``` + +**macOS Intel:** + +```bash +# Download dify-plugin-darwin-amd64 +chmod +x dify-plugin-darwin-amd64 +./dify-plugin-darwin-amd64 version +``` + +**Linux:** + +```bash +# Download dify-plugin-linux-amd64 +chmod +x dify-plugin-linux-amd64 +./dify-plugin-linux-amd64 version +``` + +**グローバルインストール (推奨):** + +```bash +# Rename and move to system path +# Example (macOS ARM) +mv dify-plugin-darwin-arm64 dify +sudo mv dify /usr/local/bin/ +dify version +``` + +### 開発パッケージの実行 + +ここでは `dify` を例として使用します。ローカルインストール方法を使用している場合は、コマンドを適宜置き換えてください。例: `./dify-plugin-darwin-arm64 plugin init` + +### プラグイン開発プロセス + +#### 1. 新しいプラグインの作成 + +```bash +./dify plugin init +``` + +プロンプトに従って、基本的なプラグイン情報の設定を完了してください + +> 詳細: [Dify プラグイン開発: Hello World ガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) + +#### 2. 開発モードで実行 + +`.env` ファイルを設定し、プラグインディレクトリで以下のコマンドを実行します: + +```bash +python -m main +``` + +> 詳細: [プラグインのリモートデバッグ](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) + +#### 4. パッケージングとデプロイ + +プラグインをパッケージ化: + +```bash +cd .. +dify plugin package ./yourapp +``` + +> 詳細: [公開の概要](/ja/develop-plugin/publishing/marketplace-listing/release-overview) + +### プラグインカテゴリ + +#### ツールラベル + +カテゴリ `tag` [class ToolLabelEnum(Enum)](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/dify_plugin/entities/tool.py) + +```python +class ToolLabelEnum(Enum): + SEARCH = "search" + IMAGE = "image" + VIDEOS = "videos" + WEATHER = "weather" + FINANCE = "finance" + DESIGN = "design" + TRAVEL = "travel" + SOCIAL = "social" + NEWS = "news" + MEDICAL = "medical" + PRODUCTIVITY = "productivity" + EDUCATION = "education" + BUSINESS = "business" + ENTERTAINMENT = "entertainment" + UTILITIES = "utilities" + OTHER = "other" +``` + +### プラグインタイプリファレンス + +Dify は様々なタイプのプラグイン開発をサポートしています: + +- **ツールプラグイン**: サードパーティの API とサービスを統合 + > 詳細: [Dify プラグイン開発: Hello World ガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) + +- **モデルプラグイン**: AI モデルを統合 + > 詳細: [モデルプラグイン](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules)、[新しいモデルのクイック統合](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) + +- **エージェント戦略プラグイン**: エージェントの思考と意思決定戦略をカスタマイズ + > 詳細: [エージェント戦略プラグイン](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) + +- **拡張プラグイン**: Endpoints や WebAPP など、Dify プラットフォームの機能を拡張 + > 詳細: [拡張プラグイン](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) + +- **データソースプラグイン**: ナレッジベースパイプラインのドキュメントデータソースおよび開始点として機能 + > 詳細: [データソースプラグイン](/ja/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin) + +- **トリガープラグイン**: サードパーティのイベントに基づいてワークフローの実行を自動的にトリガー + > 詳細: [トリガープラグイン](/ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin) + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx new file mode 100644 index 00000000..0ee1b03d --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx @@ -0,0 +1,462 @@ +--- +dimensions: + type: + primary: implementation + detail: standard + level: intermediate +standard_title: Model Provider Plugin +language: en +title: モデルプロバイダープラグイン +description: この包括的なガイドでは、モデルプロバイダープラグインの作成について詳細な手順を提供し、プロジェクトの初期化、ディレクトリ構造の編成、モデル構成方法、プロバイダーコードの記述、およびコア API 実装の詳細な例を含むモデル統合の実装について説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider)を参照してください。 + +### 前提条件 + +* [Dify CLI](/ja/develop-plugin/getting-started/cli) +* 基本的な Python プログラミングスキルとオブジェクト指向プログラミングの理解 +* 統合したいモデルプロバイダーの API ドキュメントへの精通 + +## ステップ 1: 新しいプラグインプロジェクトの作成と設定 + +### プロジェクトの初期化 + +```bash +dify plugin init +``` + +### モデルプラグインテンプレートの選択 + +利用可能なオプションから `LLM` タイプのプラグインテンプレートを選択します。このテンプレートは、モデル統合のための完全なコード構造を提供します。 + +![Plugin type: llm](https://assets-docs.dify.ai/2024/12/8efe646e9174164b9edbf658b5934b86.png) + +### プラグイン権限の設定 + +モデルプロバイダープラグインには、以下の必須権限を設定します: + +* **Models** - モデル操作の基本権限 +* **LLM** - 大規模言語モデル機能の権限 +* **Storage** - ファイル操作の権限(必要な場合) + +![Model Plugin Permission](https://assets-docs.dify.ai/2024/12/10f3b3ee6c03a1215309f13d712455d4.png) + +### ディレクトリ構造の概要 + +初期化後、プラグインプロジェクトは以下のようなディレクトリ構造になります(LLM と Embedding をサポートする `my_provider` という名前のプロバイダーを想定): + +```bash +models/my_provider/ +├── models # モデル実装と設定ディレクトリ +│ ├── llm # LLM タイプ +│ │ ├── _position.yaml (オプション、ソート順を制御) +│ │ ├── model1.yaml # 特定モデルの設定 +│ │ └── llm.py # LLM 実装ロジック +│ └── text_embedding # Embedding タイプ +│ ├── _position.yaml +│ ├── embedding-model.yaml +│ └── text_embedding.py +├── provider # プロバイダーレベルのコードディレクトリ +│ └── my_provider.py # プロバイダー認証情報の検証 +└── manifest.yaml # プラグインマニフェストファイル +``` + +## ステップ 2: モデル設定方法の理解 + +Dify は、ユーザーがプロバイダーのモデルとどのようにやり取りするかを決定する 2 つのモデル設定方法をサポートしています: + +### 事前定義モデル(`predefined-model`) + +これらは、統一されたプロバイダー認証情報のみで使用できるモデルです。ユーザーがプロバイダーの API キーやその他の認証詳細を設定すると、すべての事前定義モデルにすぐにアクセスできます。 + +**例:** `OpenAI` プロバイダーは、`gpt-3.5-turbo-0125` や `gpt-4o-2024-05-13` などの事前定義モデルを提供しています。ユーザーは OpenAI API キーを一度設定するだけで、これらすべてのモデルにアクセスできます。 + +### カスタムモデル(`customizable-model`) + +これらは、各特定のモデルインスタンスに追加の設定が必要です。このアプローチは、モデルがプロバイダーレベルの認証情報以外の個別パラメータを必要とする場合に便利です。 + +**例:** `Xinference` は LLM と Text Embedding の両方をサポートしていますが、各モデルには固有の **model_uid** があります。ユーザーは使用したい各モデルごとにこの model_uid を個別に設定する必要があります。 + +これらの設定方法は、単一のプロバイダー内で**共存できます**。たとえば、プロバイダーがいくつかの事前定義モデルを提供しながら、ユーザーが特定の設定でカスタムモデルを追加できるようにすることができます。 + +## ステップ 3: モデルプロバイダーファイルの作成 + +新しいモデルプロバイダーの作成には、2 つの主要なコンポーネントが含まれます: + +1. **プロバイダー設定 YAML ファイル** - プロバイダーの基本情報、サポートされるモデルタイプ、認証情報要件を定義 +2. **プロバイダークラスの実装** - 認証検証やその他のプロバイダーレベルの機能を実装 + +*** + +### 3.1 モデルプロバイダー設定ファイルの作成 + +プロバイダー設定は、プロバイダーの基本情報、サポートされるモデルタイプ、設定方法、認証情報ルールを宣言する YAML ファイルで定義されます。このファイルは、プラグインプロジェクトのルートディレクトリに配置されます。 + +以下は、`anthropic.yaml` 設定ファイルの注釈付き例です: + +```yaml +# 基本プロバイダー識別 +provider: anthropic # プロバイダー ID(一意である必要があります) +label: + en_US: Anthropic # UI での表示名 +description: + en_US: Anthropic's powerful models, such as Claude 3. + zh_Hans: Anthropic 的强大模型,例如 Claude 3。 +icon_small: + en_US: icon_s_en.svg # プロバイダーの小さいアイコン(選択 UI に表示) +icon_large: + en_US: icon_l_en.svg # 大きいアイコン(詳細ビューに表示) +background: "#F0F0EB" # UI でのプロバイダーの背景色 + +# ユーザー向けヘルプ情報 +help: + title: + en_US: Get your API Key from Anthropic + zh_Hans: 从 Anthropic 获取 API Key + url: + en_US: https://console.anthropic.com/account/keys + +# サポートされるモデルタイプと設定アプローチ +supported_model_types: + - llm # このプロバイダーは LLM モデルを提供 +configurate_methods: + - predefined-model # 事前定義モデルアプローチを使用 + +# プロバイダーレベルの認証情報フォーム定義 +provider_credential_schema: + credential_form_schemas: + - variable: anthropic_api_key # API キーの変数名 + label: + en_US: API Key + type: secret-input # 機密データ用のセキュア入力 + required: true + placeholder: + zh_Hans: 在此输入你的 API Key + en_US: Enter your API Key + - variable: anthropic_api_url + label: + en_US: API URL + type: text-input # 通常のテキスト入力 + required: false + placeholder: + zh_Hans: 在此输入你的 API URL + en_US: Enter your API URL + +# モデル設定 +models: + llm: # LLM タイプモデルの設定 + predefined: + - "models/llm/*.yaml" # モデル設定ファイルを見つけるパターン + position: "models/llm/_position.yaml" # 表示順序を定義するファイル + +# 実装ファイルの場所 +extra: + python: + provider_source: provider/anthropic.py # プロバイダークラスの実装 + model_sources: + - "models/llm/llm.py" # モデル実装ファイル +``` + +### カスタムモデル設定 + +プロバイダーがカスタムモデルをサポートする場合、各個別モデルに対してユーザーが設定する必要がある追加フィールドを定義する `model_credential_schema` セクションを追加する必要があります。これは、ファインチューニングされたモデルをサポートするプロバイダーや、モデル固有のパラメータが必要な場合に一般的です。 + +以下は OpenAI プロバイダーの例です: + +```yaml +model_credential_schema: + model: # ファインチューニングされたモデル名フィールド + label: + en_US: Model Name + zh_Hans: 模型名称 + placeholder: + en_US: Enter your model name + zh_Hans: 输入模型名称 + credential_form_schemas: + - variable: openai_api_key + label: + en_US: API Key + type: secret-input + required: true + placeholder: + zh_Hans: 在此输入你的 API Key + en_US: Enter your API Key + - variable: openai_organization + label: + zh_Hans: 组织 ID + en_US: Organization + type: text-input + required: false + placeholder: + zh_Hans: 在此输入你的组织 ID + en_US: Enter your Organization ID + # 必要に応じて追加フィールド... +``` + +完全なモデルプロバイダー YAML 仕様については、[モデルスキーマ](/ja/develop-plugin/features-and-specs/plugin-types/model-schema)ドキュメントを参照してください。 + +### 3.2 モデルプロバイダーコードの記述 + +次に、プロバイダークラス実装用の Python ファイルを作成します。このファイルは、プロバイダー名に一致する名前で `/provider` ディレクトリに配置する必要があります(例:`anthropic.py`)。 + +プロバイダークラスは `ModelProvider` を継承し、少なくとも `validate_provider_credentials` メソッドを実装する必要があります: + +```python +import logging +from dify_plugin.entities.model import ModelType +from dify_plugin.errors.model import CredentialsValidateFailedError +from dify_plugin import ModelProvider + +logger = logging.getLogger(__name__) + + +class AnthropicProvider(ModelProvider): + def validate_provider_credentials(self, credentials: dict) -> None: + """ + API に対して認証情報をテストして検証します。 + + このメソッドは、認証情報が有効であることを確認するために + 簡単な API 呼び出しを試みる必要があります。 + + :param credentials: YAML スキーマで定義されたプロバイダー認証情報 + :raises CredentialsValidateFailedError: 検証が失敗した場合 + """ + try: + # LLM モデルタイプのインスタンスを取得し、認証情報を検証 + model_instance = self.get_model_instance(ModelType.LLM) + model_instance.validate_credentials( + model="claude-3-opus-20240229", + credentials=credentials + ) + except CredentialsValidateFailedError as ex: + # 認証情報検証エラーをそのまま渡す + raise ex + except Exception as ex: + # その他の例外をログに記録して再スロー + logger.exception(f"{self.get_provider_schema().provider} credentials validate failed") + raise ex +``` + +`validate_provider_credentials` メソッドは、ユーザーが Dify でプロバイダー認証情報を保存しようとするたびに呼び出されるため、非常に重要です。このメソッドは: + +1. 簡単な API 呼び出しを行って認証情報を検証しようとする +2. 検証が成功した場合は静かに戻る +3. 検証が失敗した場合は、役立つメッセージとともに `CredentialsValidateFailedError` をスロー + +#### カスタムモデルプロバイダーの場合 + +カスタムモデルのみを使用するプロバイダー(各モデルに独自の設定が必要な場合)には、より単純なプロバイダークラスを実装できます。たとえば、`Xinference` の場合: + +```python +from dify_plugin import ModelProvider + +class XinferenceProvider(ModelProvider): + def validate_provider_credentials(self, credentials: dict) -> None: + """ + カスタムモデルのみのプロバイダーの場合、検証はモデルレベルで行われます。 + このメソッドは、抽象基底クラスの要件を満たすために存在します。 + """ + pass +``` + +## ステップ 4: モデル固有のコードの実装 + +プロバイダーの設定後、サポートする各モデルタイプの API 呼び出しを処理するモデル固有のコードを実装する必要があります。これには以下が含まれます: + +1. 各特定モデルのモデル設定 YAML ファイルの作成 +2. API 通信を処理するモデルタイプクラスの実装 + +これらのステップの詳細な手順については、以下を参照してください: + +* [モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - 事前定義モデルを統合するための標準 +* [モデルスキーマ](/ja/develop-plugin/features-and-specs/plugin-types/model-schema) - モデル設定ファイルの標準 + +### 4.1 モデル設定の定義(YAML) + +各特定モデルについて、適切なモデルタイプディレクトリ(例:`models/llm/`)に YAML ファイルを作成し、そのプロパティ、パラメータ、機能を定義します。 + +**例(`claude-3-5-sonnet-20240620.yaml`):** + +```yaml +model: claude-3-5-sonnet-20240620 # モデルの API 識別子 +label: + en_US: claude-3-5-sonnet-20240620 # UI での表示名 +model_type: llm # ディレクトリタイプと一致する必要があります +features: # 特別な機能 + - agent-thought + - vision + - tool-call + - stream-tool-call + - document +model_properties: # モデル固有のプロパティ + mode: chat # "chat" または "completion" + context_size: 200000 # 最大コンテキストウィンドウ +parameter_rules: # ユーザー調整可能なパラメータ + - name: temperature + use_template: temperature # 事前定義テンプレートを参照 + - name: top_p + use_template: top_p + - name: max_tokens + use_template: max_tokens + required: true + default: 8192 + min: 1 + max: 8192 +pricing: # オプションの価格情報 + input: '3.00' + output: '15.00' + unit: '0.000001' # 100万トークンあたり + currency: USD +``` + +### 4.2 モデル呼び出しコードの実装(Python) + +サポートする各モデルタイプ用の Python ファイルを作成します(例:`models/llm/` ディレクトリ内の `llm.py`)。このクラスは、API 通信、パラメータ変換、結果のフォーマットを処理します。 + +以下は LLM の実装構造の例です: + +```python +import logging +from typing import Union, Generator, Optional, List +from dify_plugin.provider_kits.llm import LargeLanguageModel # 基底クラス +from dify_plugin.provider_kits.llm import LLMResult, LLMResultChunk, LLMUsage # 結果クラス +from dify_plugin.provider_kits.llm import PromptMessage, PromptMessageTool # メッセージクラス +from dify_plugin.errors.provider_error import InvokeError, InvokeAuthorizationError # エラークラス + +logger = logging.getLogger(__name__) + +class MyProviderLargeLanguageModel(LargeLanguageModel): + def _invoke(self, model: str, credentials: dict, prompt_messages: List[PromptMessage], + model_parameters: dict, tools: Optional[List[PromptMessageTool]] = None, + stop: Optional[List[str]] = None, stream: bool = True, + user: Optional[str] = None) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]: + """ + モデル API を呼び出すためのコアメソッド。 + + パラメータ: + model: 呼び出すモデル識別子 + credentials: 認証情報 + prompt_messages: 送信するメッセージのリスト + model_parameters: temperature、max_tokens などのパラメータ + tools: 関数呼び出し用のオプションのツール定義 + stop: オプションの停止シーケンスのリスト + stream: レスポンスをストリーミングするか(True)、完全なレスポンスを返すか(False) + user: API トラッキング用のオプションのユーザー識別子 + + 戻り値: + stream=True の場合: LLMResultChunk オブジェクトを生成するジェネレータ + stream=False の場合: 完全な LLMResult オブジェクト + """ + # API リクエストパラメータの準備 + api_params = self._prepare_api_params( + credentials, model_parameters, prompt_messages, tools, stop + ) + + try: + # ストリーミング設定に基づいて適切なヘルパーメソッドを呼び出す + if stream: + return self._invoke_stream(model, api_params, user) + else: + return self._invoke_sync(model, api_params, user) + except Exception as e: + # エラーを処理してマッピング + self._handle_api_error(e) + + def _invoke_stream(self, model: str, api_params: dict, user: Optional[str]) -> Generator[LLMResultChunk, None, None]: + """ストリーミング API 呼び出し用のヘルパーメソッド""" + # ストリーミング呼び出しの実装詳細 + pass + + def _invoke_sync(self, model: str, api_params: dict, user: Optional[str]) -> LLMResult: + """同期 API 呼び出し用のヘルパーメソッド""" + # 同期呼び出しの実装詳細 + pass + + def validate_credentials(self, model: str, credentials: dict) -> None: + """ + この特定のモデルに対して認証情報が機能するかを検証します。 + ユーザーが認証情報を追加または変更しようとするときに呼び出されます。 + """ + # 認証情報検証の実装 + pass + + def get_num_tokens(self, model: str, credentials: dict, + prompt_messages: List[PromptMessage], + tools: Optional[List[PromptMessageTool]] = None) -> int: + """ + 指定された入力のトークン数を推定します。 + オプションですが、正確なコスト見積もりのために推奨されます。 + """ + # トークンカウントの実装 + pass + + @property + def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + ベンダー固有の例外から Dify 標準の例外へのマッピングを定義します。 + これにより、異なるプロバイダー間でエラー処理を標準化できます。 + """ + return { + InvokeAuthorizationError: [ + # ベンダー固有の認証エラーをここにリスト + ], + # その他のエラーマッピング + } +``` + +実装する最も重要なメソッドは `_invoke` で、コア API 通信を処理します。このメソッドは: + +1. Dify の標準化された入力をプロバイダーの API が必要とする形式に変換 +2. 適切なエラー処理で API 呼び出しを実行 +3. API レスポンスを Dify の標準化された出力形式に変換 +4. ストリーミングモードと非ストリーミングモードの両方を処理 + +## ステップ 5: プラグインのデバッグとテスト + +Dify は、開発中にプラグインをテストできるリモートデバッグ機能を提供しています: + +1. Dify インスタンスで「プラグイン管理」に移動し、「プラグインをデバッグ」をクリックしてデバッグキーとサーバーアドレスを取得 +2. `.env` ファイルでこれらの値をローカル環境に設定: + +```dotenv +INSTALL_METHOD=remote +REMOTE_INSTALL_HOST= +REMOTE_INSTALL_PORT=5003 +REMOTE_INSTALL_KEY=****-****-****-****-**** +``` + +3. `python -m main` でプラグインをローカルで実行し、Dify でテスト + +## ステップ 6: パッケージ化と公開 + +プラグインの準備ができたら: + +1. スキャフォールディングツールを使用してパッケージ化: + ```bash + dify plugin package models/ + ``` + +2. 提出前にパッケージ化されたプラグインをローカルでテスト + +3. [Dify 公式プラグインリポジトリ](https://github.com/langgenius/dify-official-plugins)にプルリクエストを提出 + +公開プロセスの詳細については、[公開の概要](/ja/develop-plugin/publishing/marketplace-listing/release-overview)を参照してください。 + +## 参考リソース + +- [新しいモデルのクイック統合](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 既存のプロバイダーに新しいモデルを追加する方法 +- [プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin) - プラグイン開発入門ガイドに戻る +- [モデルスキーマ](/ja/develop-plugin/features-and-specs/plugin-types/model-schema) - 詳細なモデル設定仕様を学ぶ +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - プラグインマニフェストファイルの設定を学ぶ +- [Dify プラグイン SDK リファレンス](https://github.com/langgenius/dify-plugin-sdks) - 基底クラス、データ構造、エラータイプを参照 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx new file mode 100644 index 00000000..d2a43550 --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx @@ -0,0 +1,458 @@ +--- +title: "データソースプラグイン" +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin)を参照してください。 + +データソースプラグインは、Dify 1.9.0で導入された新しいタイプのプラグインです。ナレッジパイプラインにおいて、ドキュメントデータソースとして機能し、パイプライン全体の起点となります。 + +この記事では、データソースプラグインの開発方法について、プラグインアーキテクチャ、コード例、デバッグ方法を網羅し、データソースプラグインの迅速な開発とリリースを支援します。 + +## 前提条件 + +読み進める前に、ナレッジパイプラインの基本的な理解とプラグイン開発に関する知識があることを確認してください。関連情報はこちらで確認できます: + +- [ステップ2:ナレッジパイプラインオーケストレーション](/ja/guides/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration) +- [Difyプラグイン開発:Hello Worldガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) + +## **データソースプラグインの種類** + +Difyは3種類のデータソースプラグインをサポートしています:Webクローラー、オンラインドキュメント、オンラインドライブ。プラグインコードを実装する際、プラグインの機能を提供するクラスは特定のデータソースクラスを継承する必要があります。3種類のプラグインタイプはそれぞれ異なる親クラスに対応しています。 + + + 親クラスを継承してプラグイン機能を実装する方法については、[Difyプラグイン開発:Hello Worldガイド - 4.4 ツールロジックの実装](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin#4-4-implementing-tool-logic)を参照してください。 + + +各データソースプラグインタイプは複数のデータソースをサポートしています。例えば: + +- **Webクローラー**:Jina Reader、FireCrawl +- **オンラインドキュメント**:Notion、Confluence、GitHub +- **オンラインドライブ**:OneDrive、Google Drive、Box、AWS S3、Tencent COS + +データソースタイプとデータソースプラグインタイプの関係を以下に示します。 + +![](/images/data_source_type.png) + +## データソースプラグインの開発 + +### データソースプラグインの作成 + +スキャフォールディングコマンドラインツールを使用して、`datasource`タイプを選択することでデータソースプラグインを作成できます。セットアップが完了すると、コマンドラインツールが自動的にプラグインプロジェクトコードを生成します。 + +```powershell +dify plugin init +``` + +![](/images/datasource_plugin_init.png) + + + 通常、データソースプラグインはDifyプラットフォームの他の機能を使用する必要がないため、追加の権限は必要ありません。 + + +#### データソースプラグインの構造 + +データソースプラグインは3つの主要コンポーネントで構成されています: + +- `manifest.yaml`ファイル:プラグインの基本情報を記述します。 +- `provider`ディレクトリ:プラグインプロバイダーの説明と認証実装コードを含みます。 +- `datasources`ディレクトリ:データソースからデータを取得するための説明とコアロジックを含みます。 + +``` +├── _assets +│ └── icon.svg +├── datasources +│ ├── your_datasource.py +│ └── your_datasource.yaml +├── main.py +├── manifest.yaml +├── PRIVACY.md +├── provider +│ ├── your_datasource.py +│ └── your_datasource.yaml +├── README.md +└── requirements.txt +``` + +#### 正しいバージョンとタグの設定 + +- `manifest.yaml`ファイルで、最小サポートDifyバージョンを以下のように設定します: + + ```yaml + minimum_dify_version: 1.9.0 + ``` +- `manifest.yaml`ファイルで、Dify Marketplaceのデータソースカテゴリにプラグインを表示するために以下のタグを追加します: + + ```yaml + tags: + - rag + ``` +- `requirements.txt`ファイルで、データソースプラグイン開発に使用するプラグインSDKバージョンを以下のように設定します: + + ```yaml + dify-plugin>=0.5.0,<0.6.0 + ``` + +### データソースプロバイダーの追加 + +#### プロバイダーYAMLファイルの作成 + +プロバイダーYAMLファイルの内容は基本的にツールプラグインと同じですが、以下の2点のみ異なります: + +```yaml +# データソースプラグインのプロバイダータイプを指定:online_drive、online_document、またはwebsite_crawl +provider_type: online_drive # online_document, website_crawl + +# データソースを指定 +datasources: + - datasources/PluginName.yaml +``` + + + プロバイダーYAMLファイルの作成について詳しくは、[Difyプラグイン開発:Hello Worldガイド-4.3 プロバイダー認証情報の設定](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin#4-3-configuring-provider-credentials)を参照してください。 + + + + データソースプラグインはOAuth 2.0またはAPIキーによる認証をサポートしています。 + + OAuthの設定については、[ツールプラグインにOAuthサポートを追加する](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth)を参照してください。 + + +#### プロバイダーコードファイルの作成 + +- APIキー認証モードを使用する場合、データソースプラグインのプロバイダーコードファイルはツールプラグインと同一です。プロバイダークラスが継承する親クラスを`DatasourceProvider`に変更するだけです。 + + ```python + class YourDatasourceProvider(DatasourceProvider): + + def _validate_credentials(self, credentials: Mapping[str, Any]) -> None: + try: + """ + IMPLEMENT YOUR VALIDATION HERE + """ + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) + ``` +- OAuth認証モードを使用する場合、データソースプラグインはツールプラグインとわずかに異なります。OAuthでアクセス権限を取得する際、データソースプラグインはフロントエンドに表示するユーザー名とアバターを同時に返すことができます。そのため、`_oauth_get_credentials`と`_oauth_refresh_credentials`は`name`、`avatar_url`、`expires_at`、`credentials`を含む`DatasourceOAuthCredentials`型を返す必要があります。 + + `DatasourceOAuthCredentials`クラスは以下のように定義されており、返す際に対応する型を設定する必要があります: + + ```python + class DatasourceOAuthCredentials(BaseModel): + name: str | None = Field(None, description="The name of the OAuth credential") + avatar_url: str | None = Field(None, description="The avatar url of the OAuth") + credentials: Mapping[str, Any] = Field(..., description="The credentials of the OAuth") + expires_at: int | None = Field( + default=-1, + description="""The expiration timestamp (in seconds since Unix epoch, UTC) of the credentials. + Set to -1 or None if the credentials do not expire.""", + ) + ``` + +`_oauth_get_authorization_url`、`_oauth_get_credentials`、`_oauth_refresh_credentials`の関数シグネチャは以下の通りです: + + + + ```python + def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: + """ + Generate the authorization URL for {{ .PluginName }} OAuth. + """ + try: + """ + IMPLEMENT YOUR AUTHORIZATION URL GENERATION HERE + """ + except Exception as e: + raise DatasourceOAuthError(str(e)) + return "" + ``` + + + ```python + def _oauth_get_credentials( + self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request + ) -> DatasourceOAuthCredentials: + """ + Exchange code for access_token. + """ + try: + """ + IMPLEMENT YOUR CREDENTIALS EXCHANGE HERE + """ + except Exception as e: + raise DatasourceOAuthError(str(e)) + return DatasourceOAuthCredentials( + name="", + avatar_url="", + expires_at=-1, + credentials={}, + ) + ``` + + + ```python + def _oauth_refresh_credentials( + self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] + ) -> DatasourceOAuthCredentials: + """ + Refresh the credentials + """ + return DatasourceOAuthCredentials( + name="", + avatar_url="", + expires_at=-1, + credentials={}, + ) + ``` + + + +### データソースの追加 + +YAMLファイル形式とデータソースコード形式は、3種類のデータソースによって異なります。 + +#### Webクローラー + +WebクローラーデータソースプラグインのプロバイダーYAMLファイルでは、`output_schema`は常に4つのパラメータを返す必要があります:`source_url`、`content`、`title`、`description`。 + +```yaml +output_schema: + type: object + properties: + source_url: + type: string + description: the source url of the website + content: + type: string + description: the content from the website + title: + type: string + description: the title of the website + "description": + type: string + description: the description of the website +``` + +Webクローラープラグインのメインロジックコードでは、クラスは`WebsiteCrawlDatasource`を継承し、`_get_website_crawl`メソッドを実装する必要があります。次に、`create_crawl_message`メソッドを使用してWebクロールメッセージを返します。 + +複数のWebページをクロールしてバッチで返すには、`WebSiteInfo.status`を`processing`に設定し、`create_crawl_message`メソッドを使用して各バッチのクロールされたページを返します。すべてのページがクロールされた後、`WebSiteInfo.status`を`completed`に設定します。 + +```python +class YourDataSource(WebsiteCrawlDatasource): + + def _get_website_crawl( + self, datasource_parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + + crawl_res = WebSiteInfo(web_info_list=[], status="", total=0, completed=0) + crawl_res.status = "processing" + yield self.create_crawl_message(crawl_res) + + ### your crawl logic + ... + crawl_res.status = "completed" + crawl_res.web_info_list = [ + WebSiteInfoDetail( + title="", + source_url="", + description="", + content="", + ) + ] + crawl_res.total = 1 + crawl_res.completed = 1 + + yield self.create_crawl_message(crawl_res) +``` + +#### オンラインドキュメント + +オンラインドキュメントデータソースプラグインの戻り値には、ドキュメントの内容を表す`content`フィールドを少なくとも含める必要があります。例えば: + +```yaml +output_schema: + type: object + properties: + workspace_id: + type: string + description: workspace id + page_id: + type: string + description: page id + content: + type: string + description: page content +``` + +オンラインドキュメントプラグインのメインロジックコードでは、クラスは`OnlineDocumentDatasource`を継承し、2つのメソッドを実装する必要があります:`_get_pages`と`_get_content`。 + +ユーザーがプラグインを実行すると、まず`_get_pages`メソッドを呼び出してドキュメントのリストを取得します。ユーザーがリストからドキュメントを選択した後、`_get_content`メソッドを呼び出してドキュメントのコンテンツを取得します。 + + + + ```python + def _get_pages(self, datasource_parameters: dict[str, Any]) -> DatasourceGetPagesResponse: + # your get pages logic + response = requests.get(url, headers=headers, params=params, timeout=30) + pages = [] + for item in response.json().get("results", []): + page = OnlineDocumentPage( + page_name=item.get("title", ""), + page_id=item.get("id", ""), + type="page", + last_edited_time=item.get("version", {}).get("createdAt", ""), + parent_id=item.get("parentId", ""), + page_icon=None, + ) + pages.append(page) + online_document_info = OnlineDocumentInfo( + workspace_name=workspace_name, + workspace_icon=workspace_icon, + workspace_id=workspace_id, + pages=[page], + total=pages.length(), + ) + return DatasourceGetPagesResponse(result=[online_document_info]) + ``` + + + ```python + def _get_content(self, page: GetOnlineDocumentPageContentRequest) -> Generator[DatasourceMessage, None, None]: + # your fetch content logic, example + response = requests.get(url, headers=headers, params=params, timeout=30) + ... + yield self.create_variable_message("content", "") + yield self.create_variable_message("page_id", "") + yield self.create_variable_message("workspace_id", "") + ``` + + + +#### オンラインドライブ + +オンラインドライブデータソースプラグインはファイルを返すため、以下の仕様に準拠する必要があります: + +```yaml +output_schema: + type: object + properties: + file: + $ref: "https://dify.ai/schemas/v1/file.json" +``` + +オンラインドライブプラグインのメインロジックコードでは、クラスは`OnlineDriveDatasource`を継承し、2つのメソッドを実装する必要があります:`_browse_files`と`_download_file`。 + +ユーザーがプラグインを実行すると、まず`_browse_files`を呼び出してファイルリストを取得します。この時点で、`prefix`は空であり、ルートディレクトリのファイルリストを要求していることを示します。ファイルリストにはフォルダとファイルタイプの変数が含まれています。ユーザーがフォルダを開くと、`_browse_files`メソッドが再度呼び出されます。この時点で、`OnlineDriveBrowseFilesRequest`の`prefix`はそのフォルダ内のファイルリストを取得するために使用されるフォルダIDになります。 + +ユーザーがファイルを選択した後、プラグインは`_download_file`メソッドとファイルIDを使用してファイルのコンテンツを取得します。`_get_mime_type_from_filename`メソッドを使用してファイルのMIMEタイプを取得でき、パイプラインが異なるファイルタイプを適切に処理できるようになります。 + +ファイルリストに複数のファイルが含まれている場合、`OnlineDriveFileBucket.is_truncated`を`True`に設定し、`OnlineDriveFileBucket.next_page_parameters`をファイルリストの次のページを取得するために必要なパラメータ(サービスプロバイダーに応じて次のページのリクエストIDやURLなど)に設定できます。 + + + + ```python + def _browse_files( + self, request: OnlineDriveBrowseFilesRequest + ) -> OnlineDriveBrowseFilesResponse: + + credentials = self.runtime.credentials + bucket_name = request.bucket + prefix = request.prefix or "" # Allow empty prefix for root folder; When you browse the folder, the prefix is the folder id + max_keys = request.max_keys or 10 + next_page_parameters = request.next_page_parameters or {} + + files = [] + files.append(OnlineDriveFile( + id="", + name="", + size=0, + type="folder" # or "file" + )) + + return OnlineDriveBrowseFilesResponse(result=[ + OnlineDriveFileBucket( + bucket="", + files=files, + is_truncated=False, + next_page_parameters={} + ) + ]) + ``` + + + ```python + def _download_file(self, request: OnlineDriveDownloadFileRequest) -> Generator[DatasourceMessage, None, None]: + credentials = self.runtime.credentials + file_id = request.id + + file_content = bytes() + file_name = "" + + mime_type = self._get_mime_type_from_filename(file_name) + + yield self.create_blob_message(file_content, meta={ + "file_name": file_name, + "mime_type": mime_type + }) + + def _get_mime_type_from_filename(self, filename: str) -> str: + """Determine MIME type from file extension.""" + import mimetypes + mime_type, _ = mimetypes.guess_type(filename) + return mime_type or "application/octet-stream" + ``` + + + +AWS S3のようなストレージサービスでは、`prefix`、`bucket`、`id`変数には特別な用途があり、開発中に必要に応じて柔軟に適用できます: + +- `prefix`:ファイルパスのプレフィックスを表します。例えば、`prefix=container1/folder1/`は`container1`バケット内の`folder1`フォルダからファイルまたはファイルリストを取得します。 +- `bucket`:ファイルバケットを表します。例えば、`bucket=container1`は`container1`バケット内のファイルまたはファイルリストを取得します。このフィールドは、非標準S3プロトコルドライブでは空白のままにできます。 +- `id`:`_download_file`メソッドは`prefix`変数を使用しないため、完全なファイルパスを`id`に含める必要があります。例えば、`id=container1/folder1/file1.txt`は`container1`バケット内の`folder1`フォルダから`file1.txt`ファイルを取得することを示します。 + + + [公式Google Driveプラグイン](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/google_cloud_storage/datasources/google_cloud_storage.py)と[公式AWS S3プラグイン](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/aws_s3_storage/datasources/aws_s3_storage.py)の具体的な実装を参照できます。 + + +## プラグインのデバッグ + +データソースプラグインは、リモートデバッグまたはローカルプラグインとしてインストールしてデバッグする2つのデバッグ方法をサポートしています。以下の点に注意してください: + +- プラグインがOAuth認証を使用している場合、リモートデバッグの`redirect_uri`はローカルプラグインのものとは異なります。サービスプロバイダーのOAuth Appの関連設定を適宜更新してください。 +- データソースプラグインはシングルステップデバッグをサポートしていますが、完全な機能を確保するために、完全なナレッジパイプラインでテストすることをお勧めします。 + +## 最終チェック + +パッケージ化と公開の前に、以下のすべてを完了していることを確認してください: + +- 最小サポートDifyバージョンを`1.9.0`に設定。 +- SDKバージョンを`dify-plugin>=0.5.0,<0.6.0`に設定。 +- `README.md`と`PRIVACY.md`ファイルを作成。 +- コードファイルには英語のコンテンツのみを含める。 +- デフォルトアイコンをデータソースプロバイダーのロゴに置き換える。 + +## パッケージ化と公開 + +プラグインディレクトリで以下のコマンドを実行して`.difypkg`プラグインパッケージを生成します: + +``` +dify plugin package . -o your_datasource.difypkg +``` + +次に、以下のことができます: + +- Dify環境にプラグインをインポートして使用する。 +- プルリクエストを送信してDify Marketplaceにプラグインを公開する。 + + + プラグイン公開プロセスについては、[プラグインの公開](/ja/develop-plugin/publishing/marketplace-listing/release-overview)を参照してください。 + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx new file mode 100644 index 00000000..9ff4578c --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx @@ -0,0 +1,358 @@ +--- +dimensions: + type: + primary: reference + detail: examples + level: intermediate +standard_title: Develop A Slack Bot Plugin +language: en +title: Slack Botプラグインの開発 +description: このガイドでは、Slack Botプラグインの開発について、プロジェクトの初期化、設定フォームの編集、機能の実装、デバッグ、エンドポイントのセットアップ、検証、パッケージングまで完全なウォークスルーを提供します。Slack上でAIを活用したチャットボットを構築するために、Difyプラグインスキャフォールディングツールと事前に作成したSlack Appが必要です。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin)を参照してください。 + +**学習内容:** + +AIを活用したSlack Botの構築方法をしっかりと理解できます。このBotはSlack内でユーザーの質問に直接回答できます。プラグインを初めて開発する場合は、まず[プラグイン開発クイックスタートガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)を読むことをお勧めします。 + +### プロジェクトの背景 + +Difyプラグインエコシステムは、統合をよりシンプルでアクセスしやすくすることに焦点を当てています。このガイドでは、Slackを例として、Slack Botプラグインの開発プロセスを順を追って説明します。これにより、チームはSlack内でLLMと直接チャットでき、AIの活用効率が大幅に向上します。 + +Slackは、堅牢なAPIを備えたオープンなリアルタイムコミュニケーションプラットフォームです。その機能の中には、webhookベースのイベントシステムがあり、開発が非常に簡単です。このシステムを活用してSlack Botプラグインを作成します。以下の図に示されています: + +![Slack Bot diagram ](https://assets-docs.dify.ai/2025/01/a0865d18f1ca4051601ca53fa6f92db2.png) + +> 混乱を避けるため、以下の概念を説明します: +> +> * **Slack Bot** Slackプラットフォーム上のチャットボットで、リアルタイムでやり取りできる仮想ユーザーとして機能します。 +> * **Slack Botプラグイン** DifyアプリケーションとSlackを接続するDify Marketplace内のプラグインです。このガイドでは、そのプラグインの開発方法に焦点を当てています。 + +**動作の仕組み(簡単な概要):** + +1. **Slack Botにメッセージを送信する** + + Slack内のユーザーがBotにメッセージを送信すると、Slack Botは即座にDifyプラットフォームにwebhookリクエストを発行します。 + +2. **メッセージをSlack Botプラグインに転送する** + + Difyプラットフォームは、Slack Botプラグインをトリガーし、詳細をDifyアプリケーションに中継します。これは、メールシステムで受信者のアドレスを入力するのと似ています。SlackのAPIを通じてSlack webhookアドレスを設定し、Slack Botプラグインに入力することで、この接続が確立されます。プラグインはSlackリクエストを処理し、Difyアプリケーションに送信します。そこでLLMがユーザーの入力を分析し、応答を生成します。 + +3. **Slackに応答を返す** + + Slack BotプラグインがDifyアプリケーションから応答を受け取ると、同じルートを通じてLLMの回答をSlack Botに送り返します。Slack内のユーザーは、チャットしている場所で、よりインテリジェントでインタラクティブな体験を得られます。 + +### 前提条件 + +- **Difyプラグイン開発ツール**:詳細については、[開発ツールの初期化](/ja/develop-plugin/getting-started/cli)を参照してください。 +- **Python環境(バージョン ≥ 3.12)**:この[Pythonインストールチュートリアル](https://pythontest.com/python/installing-python-3-11/)を参照するか、LLMに完全なセットアップガイドを尋ねてください。 +- Slack Appを作成してOAuthトークンを取得する + +[Slack APIプラットフォーム](https://api.slack.com/apps)にアクセスし、Slack appをゼロから作成し、デプロイするワークスペースを選択します。 + +![](https://assets-docs.dify.ai/2025/01/c1fd0ac1467faf5a3ebf3818bb234aa8.png) + +1. **Webhooksを有効にする:** + +![](https://assets-docs.dify.ai/2025/01/7112e0710300f1db16827e17f3deac00.png) + +2. **Slackワークスペースにアプリをインストールする:** + +![](https://assets-docs.dify.ai/2025/01/88c360ff4f7b04fea52174ce330522fa.png) + +3. 将来のプラグイン開発のために**OAuthトークンを取得する**: + +![](https://assets-docs.dify.ai/2025/01/dcd8ec947253f2ef9ae121ed77ec9f26.png) + +### 1. プラグインの開発 + +ここから実際のコーディングに入ります。開始する前に、[クイックスタート:拡張プラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint)を読んでいるか、すでにDifyプラグインを構築した経験があることを確認してください。 + +#### 1.1 プロジェクトの初期化 + +以下のコマンドを実行して、プラグイン開発環境をセットアップします: + +```bash +dify plugin init +``` + +プロンプトに従って基本的なプロジェクト情報を入力します。`extension`テンプレートを選択し、`Apps`と`Endpoints`の両方の権限を付与します。 + +プラグイン内でDifyサービスを逆呼び出しする方法の詳細については、[逆呼び出し:App](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app)を参照してください。 + +![Plugins permission](https://assets-docs.dify.ai/2024/12/d89a6282c5584fc43a9cadeddf09c0de.png) + +#### 1.2 設定フォームの編集 + +このプラグインは、どのDifyアプリが応答を処理するか、およびBotの応答を認証するためのSlack Appトークンを知る必要があります。そのため、プラグインのフォームにこれら2つのフィールドを追加します。 + +groupディレクトリ内のYAMLファイルを修正します。例えば、`group/slack.yaml`です。フォームのファイル名は、プラグイン作成時に入力した情報によって決まるので、適宜調整してください。 + +**サンプルコード:** + +`slack.yaml` + +```yaml +settings: + - name: bot_token + type: secret-input + required: true + label: + en_US: Bot Token + zh_Hans: Bot Token + pt_BR: Token do Bot + ja_JP: Bot Token + placeholder: + en_US: Please input your Bot Token + zh_Hans: 请输入你的 Bot Token + pt_BR: Por favor, insira seu Token do Bot + ja_JP: ボットトークンを入力してください + - name: allow_retry + type: boolean + required: false + label: + en_US: Allow Retry + zh_Hans: 允许重试 + pt_BR: Permitir Retentativas + ja_JP: 再試行を許可 + default: false + - name: app + type: app-selector + required: true + label: + en_US: App + zh_Hans: 应用 + pt_BR: App + ja_JP: アプリ + placeholder: + en_US: the app you want to use to answer Slack messages + zh_Hans: 你想要用来回答 Slack 消息的应用 + pt_BR: o app que você deseja usar para responder mensagens do Slack + ja_JP: あなたが Slack メッセージに回答するために使用するアプリ +endpoints: + - endpoints/slack.yaml +``` + +設定フィールドの説明: + +``` + - name: app + type: app-selector + scope: chat +``` + +* **type**: app-selectorに設定すると、ユーザーはこのプラグインを使用する際にメッセージを特定のDifyアプリに転送できます。 + +* **scope**: chatに設定すると、プラグインはエージェント、チャットボット、またはchatflowなどのアプリタイプとのみやり取りできます。 + +最後に、`endpoints/slack.yaml`ファイルで、受信するSlackメッセージを適切に処理するためにリクエストメソッドをPOSTに変更します。 + +**サンプルコード:** + +`endpoints/slack.yaml` + +```yaml +path: "/" +method: "POST" +extra: + python: + source: "endpoints/slack.py" +``` + +#### 2. 関数コードの編集 + +`endpoints/slack.py`ファイルを修正し、以下のコードを追加します: + +```python +import json +import traceback +from typing import Mapping +from werkzeug import Request, Response +from dify_plugin import Endpoint +from slack_sdk import WebClient +from slack_sdk.errors import SlackApiError + + +class SlackEndpoint(Endpoint): + def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: + """ + Invokes the endpoint with the given request. + """ + retry_num = r.headers.get("X-Slack-Retry-Num") + if (not settings.get("allow_retry") and (r.headers.get("X-Slack-Retry-Reason") == "http_timeout" or ((retry_num is not None and int(retry_num) > 0)))): + return Response(status=200, response="ok") + data = r.get_json() + + # Handle Slack URL verification challenge + if data.get("type") == "url_verification": + return Response( + response=json.dumps({"challenge": data.get("challenge")}), + status=200, + content_type="application/json" + ) + + if (data.get("type") == "event_callback"): + event = data.get("event") + if (event.get("type") == "app_mention"): + message = event.get("text", "") + if message.startswith("<@"): + message = message.split("> ", 1)[1] if "> " in message else message + channel = event.get("channel", "") + blocks = event.get("blocks", []) + blocks[0]["elements"][0]["elements"] = blocks[0].get("elements")[0].get("elements")[1:] + token = settings.get("bot_token") + client = WebClient(token=token) + try: + response = self.session.app.chat.invoke( + app_id=settings["app"]["app_id"], + query=message, + inputs={}, + response_mode="blocking", + ) + try: + blocks[0]["elements"][0]["elements"][0]["text"] = response.get("answer") + result = client.chat_postMessage( + channel=channel, + text=response.get("answer"), + blocks=blocks + ) + return Response( + status=200, + response=json.dumps(result), + content_type="application/json" + ) + except SlackApiError as e: + raise e + except Exception as e: + err = traceback.format_exc() + return Response( + status=200, + response="Sorry, I'm having trouble processing your request. Please try again later." + str(err), + content_type="text/plain", + ) + else: + return Response(status=200, response="ok") + else: + return Response(status=200, response="ok") + else: + return Response(status=200, response="ok") +``` + +### 2. プラグインのデバッグ + +Difyプラットフォームに移動し、プラグインのリモートデバッグアドレスとキーを取得します。 + +![](https://assets-docs.dify.ai/2025/01/8d24006f0cabf5bf61640a9023c45db8.png) + +プラグインプロジェクトに戻り、`.env.example`ファイルをコピーして`.env`にリネームします。 + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_URL=debug.dify.ai:5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +`python -m main`を実行してプラグインを起動します。Difyのプラグイン管理ページで、ワークスペースにプラグインがインストールされているのが確認できるはずです。他のチームメンバーもアクセスできるようになります。 + +```bash +python -m main +``` + +#### プラグインエンドポイントの設定 + +Difyのプラグイン管理ページから、新しくインストールされたテストプラグインを見つけ、新しいエンドポイントを作成します。名前、Botトークンを入力し、接続するアプリを選択します。 + + + +保存後、**POST**リクエストURLが生成されます: + + + +次に、Slack Appのセットアップを完了します: + +1. **Event Subscriptionsを有効にする** + ![](https://assets-docs.dify.ai/2025/01/1d33bb9cde78a1b5656ad6a0b8350195.png) + + 上記で生成したPOSTリクエストURLを貼り付けます。 + ![](https://assets-docs.dify.ai/2025/01/65aa41f37c3800af49e944f9ff28e121.png) + +2. **必要な権限を付与する** + ![](https://assets-docs.dify.ai/2025/01/25c38a2cf10ec6c55ae54970d790f37e.png) + +--- + +### 3. プラグインの検証 + +コード内で、`self.session.app.chat.invoke`がDifyアプリケーションを呼び出すために使用され、`app_id`や`query`などのパラメータを渡します。応答はSlack Botに返されます。`python -m main`を再度実行してプラグインをデバッグ用に再起動し、SlackがDify Appの応答を正しく表示するかどうかを確認します: + +![](https://assets-docs.dify.ai/2025/01/6fc872d1343ce8503d63c5222f7f26f9.png) + +--- + +### 4. プラグインのパッケージ化(オプション) + +プラグインが正しく動作することを確認したら、以下のコマンドでパッケージ化して名前を付けることができます。実行後、現在のディレクトリに`slack_bot.difypkg`ファイルが作成されます。これが最終的なプラグインパッケージです。詳細なパッケージ化手順については、[ローカルファイルとしてパッケージ化して共有](/ja/develop-plugin/publishing/marketplace-listing/release-by-file)を参照してください。 + +```bash +# ./slack_botを実際のプラグインプロジェクトパスに置き換えてください。 + +dify plugin package ./slack_bot +``` + +おめでとうございます!プラグインの開発、テスト、パッケージ化が正常に完了しました! + +--- + +### 5. プラグインの公開(オプション) + +[Dify Marketplaceリポジトリ](https://github.com/langgenius/dify-plugins)にアップロードして公開できます。公開前に、プラグインが[Dify Marketplace公開ガイドライン](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace)に準拠していることを確認してください。承認されると、コードはメインブランチにマージされ、プラグインは[Dify Marketplace](https://marketplace.dify.ai/)で公開されます。 + +--- + +## 関連リソース + +- [プラグイン開発の基礎](/ja/develop-plugin/getting-started/getting-started-dify-plugin) - Difyプラグイン開発の包括的な概要 +- [プラグイン開発クイックスタートガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - ゼロからプラグイン開発を始める +- [拡張プラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 拡張プラグイン開発について学ぶ +- [Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Difyプラットフォームの機能を呼び出す方法を理解する +- [逆呼び出し:App](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - プラットフォーム内でアプリを呼び出す方法を学ぶ +- [プラグインの公開](/ja/develop-plugin/publishing/marketplace-listing/release-overview) - 公開プロセスを学ぶ +- [Dify Marketplaceへの公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - Marketplace公開ガイド +- [エンドポイントの詳細定義](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 詳細なエンドポイント定義 + +### さらに読む + +完全なDifyプラグインプロジェクトの例については、[GitHubリポジトリ](https://github.com/langgenius/dify-plugins)をご覧ください。完全なソースコードと実装の詳細を含む追加のプラグインも見つかります。 + +プラグイン開発についてさらに探求したい場合は、以下を確認してください: + +**クイックスタート:** +- [拡張プラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) +- [モデルプラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) +- [バンドルプラグイン:複数のプラグインのパッケージング](/ja/develop-plugin/features-and-specs/advanced-development/bundle) + +**プラグインインターフェースドキュメント:** +- [Manifestファイルによるプラグイン情報の定義](/ja/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest) - Manifest構造 +- [エンドポイント](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - エンドポイントの詳細定義 +- [逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Dify機能の逆呼び出し +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - ツール仕様 +- [モデルスキーマ](/ja/develop-plugin/features-and-specs/plugin-types/model-schema) - モデル + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx new file mode 100644 index 00000000..e428242a --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx @@ -0,0 +1,349 @@ +--- +title: '10分でDifyプラグインを構築するガイド' +description: 'わずか10分でFlomoメモサービスと連携する機能的なDifyプラグインの構築方法を学びます' +language: en +standard_title: 10-Minute Guide to Building Dify Plugins +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin)を参照してください。 + +## 構築するもの + +このガイドを終えると、以下の機能を持つDifyプラグインが完成します: + +- Flomoメモ取りAPIへの接続 +- AIとの会話から直接Flomoにメモを保存する機能 +- 認証とエラー状態の適切な処理 +- Dify Marketplaceでの配布準備完了 + + + + 10分 + + + 基本的なPythonの知識とFlomoアカウント + + + +## ステップ1:Dify CLIのインストールとプロジェクト作成 + + + + + + ```bash + brew tap langgenius/dify + brew install dify + ``` + + + [Dify GitHubリリースページ](https://github.com/langgenius/dify-plugin-daemon/releases)から最新のDify CLIを取得してください + + ```bash + # Download appropriate version + chmod +x dify-plugin-linux-amd64 + mv dify-plugin-linux-amd64 dify + sudo mv dify /usr/local/bin/ + ``` + + + + インストールを確認: + ```bash + dify version + ``` + + + + 以下のコマンドで新しいプラグインプロジェクトを作成します: + + ```bash + dify plugin init + ``` + + プロンプトに従ってプラグインをセットアップします: + - 名前を「flomo」にする + - プラグインタイプとして「tool」を選択 + - その他の必須フィールドを入力 + + + + ```bash + cd flomo + ``` + + これにより、必要なすべてのファイルを含むプラグインの基本構造が作成されます。 + + + +## ステップ2:プラグインマニフェストの定義 + + +manifest.yamlファイルはプラグインのメタデータ、権限、機能を定義します。 + + +`manifest.yaml`ファイルを作成します: + +```yaml +version: 0.0.4 +type: plugin +author: yourname +label: + en_US: Flomo + zh_Hans: Flomo 浮墨笔记 +created_at: "2023-10-01T00:00:00Z" +icon: icon.png + +resource: + memory: 67108864 # 64MB + permission: + storage: + enabled: false + +plugins: + tools: + - flomo.yaml + +meta: + version: 0.0.1 + arch: + - amd64 + - arm64 + runner: + language: python + version: 3.12 + entrypoint: main +``` + +## ステップ3:ツール定義の作成 + +ツールインターフェースを定義する`flomo.yaml`ファイルを作成します: + +```yaml +identity: + author: yourname + name: flomo + label: + en_US: Flomo Note + zh_Hans: Flomo 浮墨笔记 +description: + human: + en_US: Add notes to your Flomo account directly from Dify. + zh_Hans: 直接从Dify添加笔记到您的Flomo账户。 + llm: > + A tool that allows users to save notes to Flomo. Use this tool when users want to save important information from the conversation. The tool accepts a 'content' parameter that contains the text to be saved as a note. +credential_schema: + api_url: + type: string + required: true + label: + en_US: API URL + zh_Hans: API URL + human_description: + en_US: Flomo API URL from your Flomo account settings. + zh_Hans: 从您的Flomo账户设置中获取的API URL。 +tool_schema: + content: + type: string + required: true + label: + en_US: Note Content + zh_Hans: 笔记内容 + human_description: + en_US: Content to save as a note in Flomo. + zh_Hans: 要保存为Flomo笔记的内容。 +``` + +## ステップ4:コアユーティリティ関数の実装 + +API連携用のユーティリティモジュールを`utils/flomo_utils.py`に作成します: + + +```python utils/flomo_utils.py +import requests + +def send_flomo_note(api_url: str, content: str) -> None: + """ + Send a note to Flomo via the API URL. Raises requests.RequestException on network errors, + and ValueError on invalid status codes or input. + """ + api_url = api_url.strip() + if not api_url: + raise ValueError("API URL is required and cannot be empty.") + if not api_url.startswith('https://flomoapp.com/iwh/'): + raise ValueError( + "API URL should be in the format: https://flomoapp.com/iwh/{token}/{secret}/" + ) + if not content: + raise ValueError("Content cannot be empty.") + + headers = {'Content-Type': 'application/json'} + response = requests.post(api_url, json={"content": content}, headers=headers, timeout=10) + + if response.status_code != 200: + raise ValueError(f"API URL is not valid. Received status code: {response.status_code}") +``` + + +## ステップ5:ツールプロバイダーの実装 + +ツールプロバイダーは認証情報の検証を処理します。`provider/flomo.py`を作成します: + + +```python provider/flomo.py +from typing import Any +from dify_plugin import ToolProvider +from dify_plugin.errors.tool import ToolProviderCredentialValidationError +import requests +from utils.flomo_utils import send_flomo_note + +class FlomoProvider(ToolProvider): + def _validate_credentials(self, credentials: dict[str, Any]) -> None: + try: + api_url = credentials.get('api_url', '').strip() + # Use utility for validation and sending test note + send_flomo_note(api_url, "Hello, #flomo https://flomoapp.com") + except ValueError as e: + raise ToolProviderCredentialValidationError(str(e)) + except requests.RequestException as e: + raise ToolProviderCredentialValidationError(f"Connection error: {str(e)}") +``` + + +## ステップ6:ツールの実装 + +Toolクラスはユーザーがプラグインを呼び出したときに実際のAPI呼び出しを処理します。`tools/flomo.py`を作成します: + + +```python tools/flomo.py +from collections.abc import Generator +from typing import Any +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage +import requests +from utils.flomo_utils import send_flomo_note + +class FlomoTool(Tool): + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + content = tool_parameters.get("content", "") + api_url = self.runtime.credentials.get("api_url", "") + + try: + send_flomo_note(api_url, content) + except ValueError as e: + yield self.create_text_message(str(e)) + return + except requests.RequestException as e: + yield self.create_text_message(f"Connection error: {str(e)}") + return + + # Return success message and structured data + yield self.create_text_message( + "Note created successfully! Your content has been sent to Flomo." + ) + yield self.create_json_message({ + "status": "success", + "content": content, + }) +``` + + + +常に例外を適切に処理し、ユーザーフレンドリーなエラーメッセージを返すようにしてください。あなたのプラグインはDifyエコシステムにおけるブランドを代表するものであることを忘れないでください。 + + +## ステップ7:プラグインのテスト + + + + サンプル環境ファイルをコピーします: + ```bash + cp .env.example .env + ``` + + `.env`ファイルをDify環境の詳細で編集します: + ``` + INSTALL_METHOD=remote + REMOTE_INSTALL_HOST=debug-plugin.dify.dev + REMOTE_INSTALL_PORT=5003 + REMOTE_INSTALL_KEY=your_debug_key + ``` + + デバッグキーとホストはDifyダッシュボードで確認できます:右上の「プラグイン」アイコンをクリックし、デバッグアイコンをクリックします。ポップアップウィンドウで「APIキー」と「ホストアドレス」をコピーしてください。 + + + + ```bash + pip install -r requirements.txt + python -m main + ``` + + プラグインがデバッグモードでDifyインスタンスに接続されます。 + + + + Difyインスタンスでプラグインに移動し、デバッグ中のプラグイン(「debugging」とマークされています)を見つけます。 + Flomo APIの認証情報を追加し、メモの送信をテストします。 + + + +## ステップ9:パッケージ化と配布 + +プラグインを共有する準備ができたら: + +```bash +dify plugin package ./ +``` + +これにより、Dify Marketplaceにアップロードできる`plugin.difypkg`ファイルが作成されます。 + +## FAQとトラブルシューティング + + + + `.env`ファイルが正しく設定されていること、正しいデバッグキーを使用していることを確認してください。 + + + + Flomo API URLの形式を再確認してください。形式は次のようになっている必要があります:`https://flomoapp.com/iwh/{token}/{secret}/` + + + + 必要なすべてのファイルが存在し、manifest.yamlの構造が有効であることを確認してください。 + + + +## まとめ + +外部APIサービスと連携する機能的なDifyプラグインを構築しました!この同じパターンは、データベースや検索エンジンから生産性ツールやカスタムAPIまで、何千ものサービスとの統合に使用できます。 + + + + 機能、セットアップ、使用例を説明するREADME.mdを英語(en_US)で作成してください + + + 他の言語用に`readme/README_zh_Hans.md`のような追加のREADMEファイルを作成してください + + + + + + プラグインを公開する場合はプライバシーポリシー(PRIVACY.md)を追加してください + + + ドキュメントに包括的な例を含めてください + + + さまざまなドキュメントサイズとフォーマットで徹底的にテストしてください + + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx new file mode 100644 index 00000000..2e52454c --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx @@ -0,0 +1,550 @@ +--- +title: 'Markdownエクスポータープラグインの構築' +description: '会話をさまざまなドキュメント形式にエクスポートするプラグインの作成方法を学ぶ' +language: en +standard_title: Building a Markdown Exporter Plugin +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter)を参照してください。 + +## 構築するもの + +このガイドでは、会話を一般的なドキュメント形式にエクスポートする実用的なDifyプラグインの構築方法を学びます。最終的に、プラグインは以下の機能を持ちます: + +- MarkdownテキストをWord文書(.docx)に変換 +- 会話をPDFファイルとしてエクスポート +- 適切なフォーマットでファイル作成を処理 +- ドキュメントエクスポートのためのクリーンなユーザー体験を提供 + + + + 15分 + + + 基本的なPython知識とドキュメント操作ライブラリへの習熟 + + + +## ステップ1:環境のセットアップ + + + + + + ```bash + brew tap langgenius/dify + brew install dify + ``` + + + [Dify GitHubリリースページ](https://github.com/langgenius/dify-plugin-daemon/releases)から最新のDify CLIを取得します + + ```bash + # Download appropriate version + chmod +x dify-plugin-linux-amd64 + mv dify-plugin-linux-amd64 dify + sudo mv dify /usr/local/bin/ + ``` + + + + インストールの確認: + ```bash + dify version + ``` + + + + 新しいプラグインプロジェクトを初期化します: + + ```bash + dify plugin init + ``` + + プロンプトに従って入力してください: + - Name: "md_exporter" + - Type: "tool" + - その他の詳細は指示に従って完了してください + + + +## ステップ2:プラグインマニフェストの定義 + +`manifest.yaml`ファイルを作成してプラグインのメタデータを定義します: + +```yaml +version: 0.0.4 +type: plugin +author: your_username +label: + en_US: Markdown Exporter + zh_Hans: Markdown导出工具 +created_at: "2025-09-30T00:00:00Z" +icon: icon.png + +resource: + memory: 134217728 # 128MB + permission: + storage: + enabled: true # We need storage for temp files + +plugins: + tools: + - word_export.yaml + - pdf_export.yaml + +meta: + version: 0.0.1 + arch: + - amd64 + - arm64 + runner: + language: python + version: 3.11 + entrypoint: main +``` + +## ステップ3:Wordエクスポートツールの定義 + +`word_export.yaml`ファイルを作成してWord文書エクスポートツールを定義します: + +```yaml +identity: + author: your_username + name: word_export + label: + en_US: Export to Word + zh_Hans: 导出为Word文档 +description: + human: + en_US: Export conversation content to a Word document (.docx) + zh_Hans: 将对话内容导出为Word文档(.docx) + llm: > + A tool that converts markdown text to a Word document (.docx) format. + Use this tool when the user wants to save or export the conversation + content as a Word document. The input text should be in markdown format. +credential_schema: {} # No credentials needed +tool_schema: + markdown_content: + type: string + required: true + label: + en_US: Markdown Content + zh_Hans: Markdown内容 + human_description: + en_US: The markdown content to convert to Word format + zh_Hans: 要转换为Word格式的Markdown内容 + document_name: + type: string + required: false + label: + en_US: Document Name + zh_Hans: 文档名称 + human_description: + en_US: Name for the exported document (without extension) + zh_Hans: 导出文档的名称(无需扩展名) +``` + +## ステップ4:PDFエクスポートツールの定義 + +PDFエクスポート用の`pdf_export.yaml`ファイルを作成します: + +```yaml +identity: + author: your_username + name: pdf_export + label: + en_US: Export to PDF + zh_Hans: 导出为PDF文档 +description: + human: + en_US: Export conversation content to a PDF document + zh_Hans: 将对话内容导出为PDF文档 + llm: > + A tool that converts markdown text to a PDF document. + Use this tool when the user wants to save or export the conversation + content as a PDF file. The input text should be in markdown format. +credential_schema: {} # No credentials needed +tool_schema: + markdown_content: + type: string + required: true + label: + en_US: Markdown Content + zh_Hans: Markdown内容 + human_description: + en_US: The markdown content to convert to PDF format + zh_Hans: 要转换为PDF格式的Markdown内容 + document_name: + type: string + required: false + label: + en_US: Document Name + zh_Hans: 文档名称 + human_description: + en_US: Name for the exported document (without extension) + zh_Hans: 导出文档的名称(无需扩展名) +``` + +## ステップ5:必要な依存関係のインストール + +必要なライブラリを含む`requirements.txt`を作成または更新します: + +```text +python-docx>=0.8.11 +markdown>=3.4.1 +weasyprint>=59.0 +beautifulsoup4>=4.12.2 +``` + +## ステップ6:Wordエクスポート機能の実装 + +`utils/docx_utils.py`にユーティリティモジュールを作成します: + + +```python utils/docx_utils.py +import os +import tempfile +import uuid +from docx import Document +from docx.shared import Pt +from docx.enum.text import WD_PARAGRAPH_ALIGNMENT +import markdown +from bs4 import BeautifulSoup + +def convert_markdown_to_docx(markdown_text, document_name=None): + """ + Convert markdown text to a Word document and return the file path + """ + if not document_name: + document_name = f"exported_document_{uuid.uuid4().hex[:8]}" + + # Convert markdown to HTML + html = markdown.markdown(markdown_text) + soup = BeautifulSoup(html, 'html.parser') + + # Create a new Word document + doc = Document() + + # Process HTML elements and add to document + for element in soup.find_all(['h1', 'h2', 'h3', 'h4', 'p', 'ul', 'ol']): + if element.name == 'h1': + heading = doc.add_heading(element.text.strip(), level=1) + heading.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER + elif element.name == 'h2': + doc.add_heading(element.text.strip(), level=2) + elif element.name == 'h3': + doc.add_heading(element.text.strip(), level=3) + elif element.name == 'h4': + doc.add_heading(element.text.strip(), level=4) + elif element.name == 'p': + paragraph = doc.add_paragraph(element.text.strip()) + elif element.name in ('ul', 'ol'): + for li in element.find_all('li'): + doc.add_paragraph(li.text.strip(), style='ListBullet') + + # Create temp directory if it doesn't exist + temp_dir = tempfile.gettempdir() + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Save the document + file_path = os.path.join(temp_dir, f"{document_name}.docx") + doc.save(file_path) + + return file_path +``` + + +## ステップ7:PDFエクスポート機能の実装 + +`utils/pdf_utils.py`にユーティリティモジュールを作成します: + + +```python utils/pdf_utils.py +import os +import tempfile +import uuid +import markdown +from weasyprint import HTML, CSS +from weasyprint.text.fonts import FontConfiguration + +def convert_markdown_to_pdf(markdown_text, document_name=None): + """ + Convert markdown text to a PDF document and return the file path + """ + if not document_name: + document_name = f"exported_document_{uuid.uuid4().hex[:8]}" + + # Convert markdown to HTML + html_content = markdown.markdown(markdown_text) + + # Add basic styling + styled_html = f""" + + + + + {document_name} + + + + {html_content} + + + """ + + # Create temp directory if it doesn't exist + temp_dir = tempfile.gettempdir() + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Output file path + file_path = os.path.join(temp_dir, f"{document_name}.pdf") + + # Configure fonts + font_config = FontConfiguration() + + # Render PDF + HTML(string=styled_html).write_pdf( + file_path, + stylesheets=[], + font_config=font_config + ) + + return file_path +``` + + +## ステップ8:ツール実装の作成 + +まず、`tools/word_export.py`にWordエクスポートツールを作成します: + + +```python tools/word_export.py +import os +import base64 +from collections.abc import Generator +from typing import Any +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage +from utils.docx_utils import convert_markdown_to_docx + +class WordExportTool(Tool): + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + # Extract parameters + markdown_content = tool_parameters.get("markdown_content", "") + document_name = tool_parameters.get("document_name", "exported_document") + + if not markdown_content: + yield self.create_text_message("Error: No content provided for export.") + return + + try: + # Convert markdown to Word + file_path = convert_markdown_to_docx(markdown_content, document_name) + + # Read the file as binary + with open(file_path, 'rb') as file: + file_content = file.read() + + # Encode as base64 + file_base64 = base64.b64encode(file_content).decode('utf-8') + + # Return success message and file + yield self.create_text_message( + f"Document exported successfully as Word (.docx) format." + ) + + yield self.create_file_message( + file_name=f"{document_name}.docx", + file_content=file_base64, + mime_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ) + + except Exception as e: + yield self.create_text_message(f"Error exporting to Word: {str(e)}") + return +``` + + +次に、`tools/pdf_export.py`にPDFエクスポートツールを作成します: + + +```python tools/pdf_export.py +import os +import base64 +from collections.abc import Generator +from typing import Any +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage +from utils.pdf_utils import convert_markdown_to_pdf + +class PDFExportTool(Tool): + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + # Extract parameters + markdown_content = tool_parameters.get("markdown_content", "") + document_name = tool_parameters.get("document_name", "exported_document") + + if not markdown_content: + yield self.create_text_message("Error: No content provided for export.") + return + + try: + # Convert markdown to PDF + file_path = convert_markdown_to_pdf(markdown_content, document_name) + + # Read the file as binary + with open(file_path, 'rb') as file: + file_content = file.read() + + # Encode as base64 + file_base64 = base64.b64encode(file_content).decode('utf-8') + + # Return success message and file + yield self.create_text_message( + f"Document exported successfully as PDF format." + ) + + yield self.create_file_message( + file_name=f"{document_name}.pdf", + file_content=file_base64, + mime_type="application/pdf" + ) + + except Exception as e: + yield self.create_text_message(f"Error exporting to PDF: {str(e)}") + return +``` + + +## ステップ9:エントリーポイントの作成 + +プロジェクトのルートに`main.py`ファイルを作成します: + + +```python main.py +from dify_plugin import PluginRunner +from tools.word_export import WordExportTool +from tools.pdf_export import PDFExportTool + +plugin = PluginRunner( + tools=[ + WordExportTool(), + PDFExportTool(), + ], + providers=[] # No credential providers needed +) +``` + + +## ステップ10:プラグインのテスト + + + + まず、テンプレートから`.env`ファイルを作成します: + ```bash + cp .env.example .env + ``` + + Dify環境の詳細を設定します: + ``` + INSTALL_METHOD=remote + REMOTE_INSTALL_HOST=debug-plugin.dify.dev + REMOTE_INSTALL_PORT=5003 + REMOTE_INSTALL_KEY=your_debug_key + ``` + + + + ```bash + pip install -r requirements.txt + ``` + + + + ```bash + python -m main + ``` + + + +## ステップ11:配布用にパッケージ化 + +プラグインを共有する準備ができたら: + +```bash +dify plugin package ./ +``` + +これにより、配布用の`plugin.difypkg`ファイルが作成されます。 + +## クリエイティブな活用例 + + + + このプラグインを使用して、分析サマリーをクライアント向けのプロフェッショナルなレポートに変換 + + + コーチングやコンサルティングセッションのノートをフォーマットされたドキュメントとしてエクスポート + + + +## 基本を超えて + +このプラグインを拡張するための興味深い方法をいくつか紹介します: + +- **カスタムテンプレート**:企業ブランディングやパーソナライズされたスタイルを追加 +- **マルチフォーマットサポート**:HTML、Markdown、その他のフォーマットへのエクスポートを拡張 +- **画像処理**:会話からの画像を処理して含める +- **テーブルサポート**:データテーブルの適切なフォーマットを実装 +- **コラボレーティブ編集**:Google Docsや類似のプラットフォームとの統合を追加 + + +ドキュメント変換の核心的な課題は、フォーマットと構造を維持することです。このプラグインで使用されているアプローチは、まずMarkdownをHTML(中間形式)に変換し、その後そのHTMLをターゲット形式に処理します。 + +この2段階のプロセスは柔軟性を提供します—HTML表現で動作する新しい出力モジュールを追加するだけで、追加のフォーマットをサポートするように拡張できます。 + +PDF生成には、CSSサポート付きの高品質なPDFレンダリングを提供するWeasyPrintが選択されました。Word文書には、python-docxがドキュメント構造に対する詳細な制御を提供します。 + + +## まとめ + +会話をプロフェッショナルなドキュメント形式でエクスポートできるようにすることで、Difyプラットフォームに実際の価値を追加する実用的なプラグインを構築しました。この機能は、AI会話と従来のドキュメントワークフローの間のギャップを埋めます。 + + + + 機能、セットアップ、使用例を説明するREADME.mdを英語(en_US)で作成してください + + + 他の言語用に`readme/README_zh_Hans.md`などの追加READMEファイルを作成してください + + + + + + プラグインを公開する場合はプライバシーポリシー(PRIVACY.md)を追加してください + + + ドキュメントに包括的な例を含めてください + + + さまざまなドキュメントサイズとフォーマットで徹底的にテストしてください + + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx new file mode 100644 index 00000000..60645596 --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx @@ -0,0 +1,128 @@ +--- +dimensions: + type: + primary: reference + detail: examples + level: intermediate +standard_title: Endpoint +language: ja +title: Neko Cat Endpoint +description: 著者 Yeuoly、Allen。このドキュメントでは、Neko Cat プロジェクトを例として、Dify プラグインにおける Endpoint の構造と実装について詳しく説明します。Endpoint グループの定義、インターフェースの設定、_invoke メソッドの実装、リクエストとレスポンスの処理について説明します。また、各種 YAML 設定フィールドの意味と使用方法についても解説します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint)を参照してください。 + +# Endpoint + +このドキュメントでは、[Neko Cat](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) プロジェクトを例として、プラグイン内の Endpoint の構造について説明します。Endpoint はプラグインが公開する HTTP インターフェースで、外部システムとの統合に使用できます。完全なプラグインコードについては、[GitHub リポジトリ](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko)を参照してください。 + +### グループ定義 + +`Endpoint` グループは、複数の `Endpoint` の集合です。Dify プラグイン内で新しい `Endpoint` を作成する際、以下の設定を入力する必要がある場合があります。 + +![](https://assets-docs.dify.ai/2024/11/763dbf86e4319591415dc5a1b6948ccb.png) + +`Endpoint Name` の他に、グループの設定情報を記述することで新しいフォーム項目を追加できます。保存をクリックすると、含まれる複数のインターフェースが表示され、それらは同じ設定情報を使用します。 + +![](https://assets-docs.dify.ai/2024/11/b778b7093b7df0dc80a476c65ddcbe58.png) + +#### **構造** + +* `settings` (map[string] [ProviderConfig](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications#providerconfig)): Endpoint 設定の定義。 +* `endpoints` (list[string], 必須): 具体的な `endpoint` インターフェース定義を指します。 + +```yaml +settings: + api_key: + type: secret-input + required: true + label: + en_US: API key + zh_Hans: API key + ja_Jp: API key + pt_BR: API key + placeholder: + en_US: Please input your API key + zh_Hans: 请输入你的 API key + ja_Jp: あなたの API key を入れてください + pt_BR: Por favor, insira sua chave API +endpoints: + - endpoints/duck.yaml + - endpoints/neko.yaml +``` + +### インターフェース定義 + +* `path` (string): Werkzeug インターフェース標準に従います。 +* `method` (string): インターフェースメソッド、`HEAD`、`GET`、`POST`、`PUT`、`DELETE`、`OPTIONS` のみサポートします。 +* `extra` (object): 基本情報以外の設定情報。 + * `python` (object) + * `source` (string): このインターフェースを実装するソースコード。 + +```yaml +path: "/duck/" +method: "GET" +extra: + python: + source: "endpoints/duck.py" +``` + +### インターフェース実装 + +`dify_plugin.Endpoint` を継承するサブクラスを実装し、`_invoke` メソッドを実装する必要があります。 + +* **入力パラメータ** + * `r` (Request): `werkzeug` の `Request` オブジェクト。 + * `values` (Mapping): パスから解析されたパスパラメータ。 + * `settings` (Mapping): この `Endpoint` の設定情報。 +* **戻り値** + * `werkzeug` の `Response` オブジェクト、ストリーミングレスポンスをサポートします。 + * 文字列を直接返すことはサポートされていません。 + +サンプルコード: + +```python +import json +from typing import Mapping +from werkzeug import Request, Response +from dify_plugin import Endpoint + +class Duck(Endpoint): + def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: + """ + Invokes the endpoint with the given request. + """ + app_id = values["app_id"] + + def generator(): + yield f"{app_id}
" + + return Response(generator(), status=200, content_type="text/html") +``` + +## 注意事項 + +* Endpoint はプラグインが呼び出されたときにのみインスタンス化されます。常時稼働するサービスではありません。 +* Endpoint を開発する際はセキュリティに注意し、危険な操作の実行を避けてください。 +* Endpoint は Webhook コールバックの処理や、他のシステムが接続するためのインターフェースの提供に使用できます。 + +プラグイン開発を学習中の場合は、まず[プラグイン開発入門](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)と[開発者チートシート](/ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet)を読むことをお勧めします。 + +## 関連リソース + +* [プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin) - プラグイン開発の全体的なアーキテクチャを理解する。 +* [Neko Cat サンプル](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 拡張プラグイン開発のサンプル。 +* [汎用仕様定義](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - ProviderConfig などの共通構造を理解する。 +* [Slack Bot プラグイン開発サンプル](/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 別のプラグイン開発サンプル。 +* [プラグイン開発入門](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - ゼロからプラグインを開発する。 +* [Dify サービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - 逆呼び出し機能の使用方法を学ぶ。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx new file mode 100644 index 00000000..7ed903f5 --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx @@ -0,0 +1,382 @@ +--- +title: "ツールプラグインにOAuthサポートを追加する" +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth)を参照してください。 + +![b0e673ba3e339b31ac36dc3cd004df04787bcaa64bb6d2cac6feb7152b7b515f.png](/images/b0e673ba3e339b31ac36dc3cd004df04787bcaa64bb6d2cac6feb7152b7b515f.png) + +このガイドでは、ツールプラグインに[OAuth](https://oauth.net/2/)サポートを組み込む方法を説明します。 + +OAuthは、GmailやGitHubなどのサードパーティサービスからユーザーデータにアクセスする必要があるツールプラグインを認可するためのより優れた方法です。ユーザーがAPIキーを手動で入力する必要がなく、OAuthを使用することでツールはユーザーの明示的な同意のもとでユーザーに代わって動作できます。 + +## 背景 + +DifyにおけるOAuthには、開発者が理解し設計すべき**2つの別々のフロー**があります。 + +### フロー1: OAuthクライアントセットアップ(管理者/開発者フロー) + + + Dify Cloudでは、Difyチームが人気のあるツールプラグイン用のOAuthアプリを作成し、OAuthクライアントをセットアップするため、ユーザーは自分で設定する手間が省けます。 + + セルフホストDifyインスタンスの管理者は、このセットアップフローを実行する必要があります。 + + +Difyインスタンスの管理者または開発者は、まずサードパーティサービスに信頼できるアプリケーションとしてOAuthアプリを登録する必要があります。これにより、DifyツールプロバイダーをOAuthクライアントとして設定するために必要な資格情報を取得できます。 + +例として、DifyのGmailツールプロバイダー用のOAuthクライアントをセットアップする手順を示します: + + + + 1. [Google Cloud Console](https://console.cloud.google.com)にアクセスし、新しいプロジェクトを作成するか、既存のプロジェクトを選択します + 2. 必要なAPI(例:Gmail API)を有効にします + + + 1. **APIs & Services** \> **OAuth consent screen**に移動します + 2. 公開プラグインの場合は**External**ユーザータイプを選択します + 3. アプリケーション名、ユーザーサポートメール、開発者連絡先を入力します + 4. 必要に応じて承認済みドメインを追加します + 5. テストの場合:**Test users**セクションでテストユーザーを追加します + + + 1. **APIs & Services** \> **Credentials**に移動します + 2. **Create Credentials** \> **OAuth 2.0 Client IDs**をクリックします + 3. **Web application**タイプを選択します + 4. `client_id`と`client_secret`が生成されます。これらを資格情報として保存します。 + + + OAuthクライアント設定ポップアップにclient_idとclient_secretを入力して、ツールプロバイダーをクライアントとしてセットアップします。 + + acd5f5057235c3a0c554abaedcf276fb48f80567f0231eae9158a795f8e1c45d.png + + + Difyが生成したリダイレクトURIをGoogle OAuthクライアントのページに登録します: + + dfe60a714a275c5bf65f814673bd2f0a0db4fda27573a2f0b28a1c39e4c61da2.png + + + Difyは`redirect_uri`をOAuthクライアント設定ポップアップに表示します。通常、次の形式に従います: + + ```bash + https://{your-dify-domain}/console/api/oauth/plugin/{plugin-id}/{provider-name}/{tool-name}/callback + ``` + + セルフホストDifyの場合、`your-dify-domain`は`CONSOLE_WEB_URL`と一致する必要があります。 + + + + + + 各サービスには固有の要件があるため、統合するサービスの特定のOAuthドキュメントを必ず参照してください。 + + +### フロー2: ユーザー認可(Difyユーザーフロー) + +OAuthクライアントを設定した後、個々のDifyユーザーは、プラグインが自分の個人アカウントにアクセスすることを認可できるようになります。 + +833c205f5441910763b27d3e3ff0c4449a730a690da91abc3ce032c70da04223.png + +## 実装 + +### 1. プロバイダーマニフェストでOAuthスキーマを定義する + +プロバイダーマニフェストの`oauth_schema`セクションは、プラグインのOAuthに必要な資格情報と、OAuthフローが生成するものをDifyに伝えます。OAuthをセットアップするには、2つのスキーマが必要です: + +#### client_schema + +OAuthクライアントセットアップの入力を定義します: + +```yaml gmail.yaml +oauth_schema: + client_schema: + - name: "client_id" + type: "secret-input" + required: true + url: "https://developers.google.com/identity/protocols/oauth2" + - name: "client_secret" + type: "secret-input" + required: true +``` + + + `url`フィールドはサードパーティサービスのヘルプドキュメントに直接リンクします。これは困っている管理者/開発者の助けになります。 + + +#### credentials_schema + +ユーザー認可フローが生成するものを指定します(Difyがこれらを自動的に管理します): + +```yaml +# also under oauth_schema + credentials_schema: + - name: "access_token" + type: "secret-input" + - name: "refresh_token" + type: "secret-input" + - name: "expires_at" + type: "secret-input" +``` + + + OAuth \+ APIキー認証オプションを提供するには、`oauth_schema`と`credentials_for_provider`の両方を含めてください。 + + +### 2. ツールプロバイダーで必要なOAuthメソッドを完成させる + +`ToolProvider`を実装している場所に、以下のインポートを追加します: + +```python +from dify_plugin.entities.oauth import ToolOAuthCredentials +from dify_plugin.errors.tool import ToolProviderCredentialValidationError, ToolProviderOAuthError +``` + +`ToolProvider`クラスは、これら3つのOAuthメソッドを実装する必要があります(例として`GmailProvider`を使用): + + + いかなる場合でも、`ToolOAuthCredentials`の資格情報に`client_secret`を返してはなりません。これはセキュリティ上の問題につながる可能性があります。 + + + + +```python _oauth_get_authorization_url expandable +def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: + """ + Generate the authorization URL using credentials from OAuth Client Setup Flow. + This URL is where users grant permissions. + """ + # Generate random state for CSRF protection (recommended for all OAuth flows) + state = secrets.token_urlsafe(16) + + # Define Gmail-specific scopes - request minimal necessary permissions + scope = "read:user read:data" # Replace with your required scopes + + # Assemble Gmail-specific payload + params = { + "client_id": system_credentials["client_id"], # From OAuth Client Setup + "redirect_uri": redirect_uri, # Dify generates this - DON'T modify + "scope": scope, + "response_type": "code", # Standard OAuth authorization code flow + "access_type": "offline", # Critical: gets refresh token (if supported) + "prompt": "consent", # Forces reauth when scopes change (if supported) + "state": state, # CSRF protection + } + + return f"{self._AUTH_URL}?{urllib.parse.urlencode(params)}" +``` + + +```python _oauth_get_credentials expandable +def _oauth_get_credentials( + self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request +) -> ToolOAuthCredentials: + """ + Exchange authorization code for access token and refresh token. This is called + to creates ONE credential set for one account connection + """ + # Extract authorization code from OAuth callback + code = request.args.get("code") + if not code: + raise ToolProviderOAuthError("Authorization code not provided") + + # Check for authorization errors from OAuth provider + error = request.args.get("error") + if error: + error_description = request.args.get("error_description", "") + raise ToolProviderOAuthError(f"OAuth authorization failed: {error} - {error_description}") + + # Exchange authorization code for tokens using OAuth Client Setup credentials + + # Assemble Gmail-specific payload + data = { + "client_id": system_credentials["client_id"], # From OAuth Client Setup + "client_secret": system_credentials["client_secret"], # From OAuth Client Setup + "code": code, # From user's authorization + "grant_type": "authorization_code", # Standard OAuth flow type + "redirect_uri": redirect_uri, # Must exactly match authorization URL + } + + headers = {"Content-Type": "application/x-www-form-urlencoded"} + + try: + response = requests.post( + self._TOKEN_URL, + data=data, + headers=headers, + timeout=10 + ) + response.raise_for_status() + + token_data = response.json() + + # Handle OAuth provider errors in response + if "error" in token_data: + error_desc = token_data.get('error_description', token_data['error']) + raise ToolProviderOAuthError(f"Token exchange failed: {error_desc}") + + access_token = token_data.get("access_token") + if not access_token: + raise ToolProviderOAuthError("No access token received from provider") + + # Build credentials dict matching your credentials_schema + credentials = { + "access_token": access_token, + "token_type": token_data.get("token_type", "Bearer"), + } + + # Include refresh token if provided (critical for long-term access) + refresh_token = token_data.get("refresh_token") + if refresh_token: + credentials["refresh_token"] = refresh_token + + # Handle token expiration - some providers don't provide expires_in + expires_in = token_data.get("expires_in", 3600) # Default to 1 hour + expires_at = int(time.time()) + expires_in + + return ToolOAuthCredentials(credentials=credentials, expires_at=expires_at) + + except requests.RequestException as e: + raise ToolProviderOAuthError(f"Network error during token exchange: {str(e)}") + except Exception as e: + raise ToolProviderOAuthError(f"Failed to exchange authorization code: {str(e)}") +``` + + +```python _oauth_refresh_credentials +def _oauth_refresh_credentials( + self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] +) -> ToolOAuthCredentials: + """ + Refresh the credentials using refresh token. + Dify calls this automatically when tokens expire + """ + refresh_token = credentials.get("refresh_token") + if not refresh_token: + raise ToolProviderOAuthError("No refresh token available") + + # Standard OAuth refresh token flow + data = { + "client_id": system_credentials["client_id"], # From OAuth Client Setup + "client_secret": system_credentials["client_secret"], # From OAuth Client Setup + "refresh_token": refresh_token, # From previous authorization + "grant_type": "refresh_token", # OAuth refresh flow + } + + headers = {"Content-Type": "application/x-www-form-urlencoded"} + + try: + response = requests.post( + self._TOKEN_URL, + data=data, + headers=headers, + timeout=10 + ) + response.raise_for_status() + + token_data = response.json() + + # Handle refresh errors + if "error" in token_data: + error_desc = token_data.get('error_description', token_data['error']) + raise ToolProviderOAuthError(f"Token refresh failed: {error_desc}") + + access_token = token_data.get("access_token") + if not access_token: + raise ToolProviderOAuthError("No access token received from provider") + + # Build new credentials, preserving existing refresh token + new_credentials = { + "access_token": access_token, + "token_type": token_data.get("token_type", "Bearer"), + "refresh_token": refresh_token, # Keep existing refresh token + } + + # Handle token expiration + expires_in = token_data.get("expires_in", 3600) + + # update refresh token if new one provided + new_refresh_token = token_data.get("refresh_token") + if new_refresh_token: + new_credentials["refresh_token"] = new_refresh_token + + # Calculate new expiration timestamp for Dify's token management + expires_at = int(time.time()) + expires_in + + return ToolOAuthCredentials(credentials=new_credentials, expires_at=expires_at) + + except requests.RequestException as e: + raise ToolProviderOAuthError(f"Network error during token refresh: {str(e)}") + except Exception as e: + raise ToolProviderOAuthError(f"Failed to refresh credentials: {str(e)}") +``` + + + +### 3. ツールでトークンにアクセスする + +`Tool`実装でOAuth資格情報を使用して認証済みAPI呼び出しを行うことができます: + +```python +class YourTool(BuiltinTool): + def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage: + if self.runtime.credential_type == CredentialType.OAUTH: + access_token = self.runtime.credentials["access_token"] + + response = requests.get("https://api.service.com/data", + headers={"Authorization": f"Bearer {access_token}"}) + return self.create_text_message(response.text) +``` + +`self.runtime.credentials`は現在のユーザーのトークンを自動的に提供します。Difyはリフレッシュを自動的に処理します。 + +OAuthとAPI_KEY認証の両方をサポートするプラグインの場合、`self.runtime.credential_type`を使用して2つの認証タイプを区別できます。 + +### 4. 正しいバージョンを指定する + +以前のバージョンのプラグインSDKとDifyはOAuth認証をサポートしていません。そのため、プラグインSDKのバージョンを以下に設定する必要があります: + +``` +dify_plugin>=0.4.2,<0.5.0. +``` + +`manifest.yaml`に、最小Difyバージョンを追加します: + +```yaml +meta: + version: 0.0.1 + arch: + - amd64 + - arm64 + runner: + language: python + version: "3.12" + entrypoint: main + minimum_dify_version: 1.7.1 +``` + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx new file mode 100644 index 00000000..620ffe13 --- /dev/null +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx @@ -0,0 +1,387 @@ +--- +dimensions: + type: + primary: implementation + detail: standard + level: intermediate +standard_title: Tool Plugin +language: en +title: ツールプラグイン +description: このドキュメントでは、Dify用のツールプラグインの開発方法について詳細な手順を提供します。Google Searchを例として、完全なツールプラグイン開発プロセスを示します。内容には、プラグインの初期化、テンプレートの選択、ツールプロバイダー設定ファイルの定義、サードパーティサービス認証情報の追加、ツール機能コードの実装、デバッグ、およびリリース用のパッケージングが含まれます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)を参照してください。 + +ツールとは、Chatflow / ワークフロー / エージェントタイプのアプリケーションから呼び出すことができるサードパーティサービスを指し、Difyアプリケーションを強化するための完全なAPI実装機能を提供します。例えば、オンライン検索、画像生成などの追加機能を追加できます。 + +![Tool Plugin Example](https://assets-docs.dify.ai/2024/12/7e7bcf1f9e3acf72c6917ea9de4e4613.png) + +この記事では、**「ツールプラグイン」**とは、ツールプロバイダーファイル、機能コード、およびその他の構造を含む完全なプロジェクトを指します。ツールプロバイダーには複数のツール(単一のツール内で提供される追加機能として理解できます)を含めることができ、構造は以下の通りです: + +``` +- Tool Provider + - Tool A + - Tool B +``` + +![Tool Plugin Structure](https://assets-docs.dify.ai/2025/02/60c4c86a317d865133aa460592eac079.png) + +この記事では、`Google Search`を例として、ツールプラグインを素早く開発する方法を説明します。 + +### 前提条件 + +- Difyプラグインスキャフォールディングツール +- Python環境、バージョン ≥ 3.12 + +プラグイン開発スキャフォールディングツールの準備方法の詳細については、[開発ツールの初期化](/ja/develop-plugin/getting-started/cli)を参照してください。初めてプラグインを開発する場合は、まず[Difyプラグイン開発:Hello Worldガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)を読むことをお勧めします。 + +### 新しいプロジェクトの作成 + +スキャフォールディングコマンドラインツールを実行して、新しいDifyプラグインプロジェクトを作成します。 + +```bash +./dify-plugin-darwin-arm64 plugin init +``` + +バイナリファイルを`dify`に名前変更し、`/usr/local/bin`パスにコピーした場合は、以下のコマンドを実行して新しいプラグインプロジェクトを作成できます: + +```bash +dify plugin init +``` + +> 以下のテキストでは、`dify`をコマンドライン例として使用します。問題が発生した場合は、`dify`コマンドをコマンドラインツールのパスに置き換えてください。 + +### プラグインタイプとテンプレートの選択 + +スキャフォールディングツールのすべてのテンプレートは完全なコードプロジェクトを提供します。この例では、`Tool`プラグインを選択します。 + +> すでにプラグイン開発に精通しており、テンプレートに依存する必要がない場合は、[一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)ガイドを参照して、さまざまなタイプのプラグインの開発を完了できます。 + +![Plugin Type: Tool](https://assets-docs.dify.ai/2024/12/dd3c0f9a66454e15868eabced7b74fd6.png) + +#### プラグイン権限の設定 + +プラグインは、Difyプラットフォームから読み取る権限も必要です。このサンプルプラグインに以下の権限を付与します: + +- Tools +- Apps +- 永続ストレージStorageを有効にし、デフォルトサイズのストレージを割り当てる +- Endpointsの登録を許可 + +> ターミナルの矢印キーを使用して権限を選択し、「Tab」ボタンを使用して権限を付与します。 + +すべての権限項目をチェックした後、Enterを押してプラグインの作成を完了します。システムは自動的にプラグインプロジェクトコードを生成します。 + +![Plugin Permissions](https://assets-docs.dify.ai/2024/12/9cf92c2e74dce55e6e9e331d031e5a9f.png) + +### ツールプラグインの開発 + +#### 1. ツールプロバイダーファイルの作成 + +ツールプロバイダーファイルはyaml形式のファイルで、ツールプラグインの基本設定エントリとして理解でき、ツールに必要な認証情報を提供するために使用されます。 + +プラグインテンプレートプロジェクトの`/provider`パスに移動し、yamlファイルを`google.yaml`に名前変更します。この`yaml`ファイルには、プロバイダーの名前、アイコン、作者などのツールプロバイダーに関する情報が含まれます。この情報は、プラグインのインストール時に表示されます。 + +**サンプルコード** + +```yaml +identity: # Basic information of the tool provider + author: Your-name # Author + name: google # Name, unique, cannot have the same name as other providers + label: # Label, for frontend display + en_US: Google # English label + zh_Hans: Google # Chinese label + description: # Description, for frontend display + en_US: Google # English description + zh_Hans: Google # Chinese description + icon: icon.svg # Tool icon, needs to be placed in the _assets folder + tags: # Tags, for frontend display + - search +``` + +ファイルパスが`/tools`ディレクトリにあることを確認してください。完全なパスは以下の通りです: + +```yaml +plugins: + tools: + - 'google.yaml' +``` + +`google.yaml`は、プラグインプロジェクト内の絶対パスを使用する必要があります。この例では、プロジェクトのルートディレクトリに配置されています。YAMLファイルのidentityフィールドは以下のように説明されます:`identity`には、作者、名前、ラベル、説明、アイコンなど、ツールプロバイダーに関する基本情報が含まれています。 + +- アイコンは添付リソースである必要があり、プロジェクトのルートディレクトリの`_assets`フォルダに配置する必要があります。 +- タグは、ユーザーがカテゴリを通じてプラグインを素早く見つけるのに役立ちます。以下は現在サポートされているすべてのタグです。 + +```python +class ToolLabelEnum(Enum): + SEARCH = 'search' + IMAGE = 'image' + VIDEOS = 'videos' + WEATHER = 'weather' + FINANCE = 'finance' + DESIGN = 'design' + TRAVEL = 'travel' + SOCIAL = 'social' + NEWS = 'news' + MEDICAL = 'medical' + PRODUCTIVITY = 'productivity' + EDUCATION = 'education' + BUSINESS = 'business' + ENTERTAINMENT = 'entertainment' + UTILITIES = 'utilities' + OTHER = 'other' +``` + +#### **2. サードパーティサービス認証情報の完成** + +開発の便宜のため、サードパーティサービス`SerpApi`が提供するGoogle Search APIを使用することを選択します。`SerpApi`は使用にAPI Keyが必要なため、`yaml`ファイルに`credentials_for_provider`フィールドを追加する必要があります。 + +完全なコードは以下の通りです: + +```yaml +identity: + author: Dify + name: google + label: + en_US: Google + zh_Hans: Google + pt_BR: Google + description: + en_US: Google + zh_Hans: GoogleSearch + pt_BR: Google + icon: icon.svg + tags: + - search +credentials_for_provider: #Add credentials_for_provider field + serpapi_api_key: + type: secret-input + required: true + label: + en_US: SerpApi API key + zh_Hans: SerpApi API key + placeholder: + en_US: Please input your SerpApi API key + zh_Hans: Please enter your SerpApi API key + help: + en_US: Get your SerpApi API key from SerpApi + zh_Hans: Get your SerpApi API key from SerpApi + url: https://serpapi.com/manage-api-key +tools: + - tools/google_search.yaml +extra: + python: + source: google.py +``` + +- `credentials_for_provider`のサブレベル構造は、[一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)の要件を満たす必要があります。 +- プロバイダーに含まれるツールを指定する必要があります。この例では、`tools/google_search.yaml`ファイルのみが含まれています。 +- プロバイダーとして、基本情報を定義するだけでなく、そのコードロジックの一部を実装する必要があるため、その実装ロジックを指定する必要があります。この例では、機能のコードファイルを`google.py`に配置しますが、まだ実装せず、最初に`google_search`のコードを書きます。 + +#### 3. ツールYAMLファイルの記入 + +ツールプラグインには複数のツール機能を持たせることができ、各ツール機能には、ツール機能の基本情報、パラメータ、出力などを記述する`yaml`ファイルが必要です。 + +引き続き`GoogleSearch`ツールを例として、`/tools`フォルダに新しい`google_search.yaml`ファイルを作成します。 + +```yaml +identity: + name: google_search + author: Dify + label: + en_US: GoogleSearch + zh_Hans: Google Search + pt_BR: GoogleSearch +description: + human: + en_US: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. + zh_Hans: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. + pt_BR: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. + llm: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. +parameters: + - name: query + type: string + required: true + label: + en_US: Query string + zh_Hans: Query string + pt_BR: Query string + human_description: + en_US: used for searching + zh_Hans: used for searching web content + pt_BR: used for searching + llm_description: key words for searching + form: llm +extra: + python: + source: tools/google_search.py +``` + +- `identity`には、名前、作者、ラベル、説明などのツールの基本情報が含まれています。 +- `parameters`パラメータリスト + - `name`(必須)パラメータ名、一意で、他のパラメータと同じ名前を持つことはできません。 + - `type`(必須)パラメータタイプ、現在`string`、`number`、`boolean`、`select`、`secret-input`の5つのタイプをサポートしており、それぞれ文字列、数値、ブール値、ドロップダウン、暗号化入力ボックスに対応しています。機密情報には`secret-input`タイプを使用してください。 + - `label`(必須)パラメータラベル、フロントエンド表示用。 + - `form`(必須)フォームタイプ、現在`llm`、`form`の2つのタイプをサポートしています。 + - エージェントアプリケーションでは、`llm`はパラメータがLLM自体によって推論されることを意味し、`form`はこのツールを使用するために事前にパラメータを設定できることを意味します。 + - ワークフローアプリケーションでは、`llm`と`form`の両方をフロントエンドで入力する必要がありますが、`llm`パラメータはツールノードの入力変数として使用されます。 + - `required`必須かどうか + - `llm`モードでは、パラメータが必須の場合、エージェントはこのパラメータを推論する必要があります。 + - `form`モードでは、パラメータが必須の場合、ユーザーは会話開始前にフロントエンドでこのパラメータを入力する必要があります。 + - `options`パラメータオプション + - `llm`モードでは、Difyはすべてのオプションをモデルに渡し、モデルはこれらのオプションに基づいて推論できます。 + - `form`モードでは、`type`が`select`の場合、フロントエンドはこれらのオプションを表示します。 + - `default`デフォルト値。 + - `min`最小値、パラメータタイプが`number`の場合に設定できます。 + - `max`最大値、パラメータタイプが`number`の場合に設定できます。 + - `human_description`フロントエンド表示用の説明、複数言語をサポート。 + - `placeholder`入力フィールドのプロンプトテキスト、フォームタイプが`form`でパラメータタイプが`string`、`number`、`secret-input`の場合に設定でき、複数言語をサポート。 + - `llm_description`モデルに渡される説明。モデルがこのパラメータをより良く理解できるように、このパラメータに関するできるだけ詳細な情報をここに記述して、モデルがパラメータを理解できるようにしてください。 + +#### 4. ツールコードの準備 + +ツールの設定情報を入力した後、ツールの機能のコードを書き始め、ツールの論理的な目的を実装できます。`/tools`ディレクトリに`google_search.py`を作成し、以下の内容を記述します: + +```python +from collections.abc import Generator +from typing import Any + +import requests + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +SERP_API_URL = "https://serpapi.com/search" + +class GoogleSearchTool(Tool): + def _parse_response(self, response: dict) -> dict: + result = {} + if "knowledge_graph" in response: + result["title"] = response["knowledge_graph"].get("title", "") + result["description"] = response["knowledge_graph"].get("description", "") + if "organic_results" in response: + result["organic_results"] = [ + { + "title": item.get("title", ""), + "link": item.get("link", ""), + "snippet": item.get("snippet", ""), + } + for item in response["organic_results"] + ] + return result + + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + params = { + "api_key": self.runtime.credentials["serpapi_api_key"], + "q": tool_parameters["query"], + "engine": "google", + "google_domain": "google.com", + "gl": "us", + "hl": "en", + } + + response = requests.get(url=SERP_API_URL, params=params, timeout=5) + response.raise_for_status() + valuable_res = self._parse_response(response.json()) + + yield self.create_json_message(valuable_res) +``` + +この例は、`serpapi`にリクエストを送信し、`self.create_json_message`を使用してフォーマットされた`json`データ文字列を返すことを意味します。返却データタイプの詳細については、[プラグインのリモートデバッグ](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)と[永続ストレージKV](/ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv)ドキュメントを参照してください。 + +#### 4. ツールプロバイダーコードの完成 + +最後に、認証情報の検証ロジックを実装するプロバイダーの実装コードを作成する必要があります。認証情報の検証が失敗した場合、`ToolProviderCredentialValidationError`例外がスローされます。検証が成功すると、`google_search`ツールサービスが正しくリクエストされます。 + +`/provider`ディレクトリに`google.py`ファイルを作成し、以下の内容を記述します: + +```python +from typing import Any + +from dify_plugin import ToolProvider +from dify_plugin.errors.tool import ToolProviderCredentialValidationError +from tools.google_search import GoogleSearchTool + +class GoogleProvider(ToolProvider): + def _validate_credentials(self, credentials: dict[str, Any]) -> None: + try: + for _ in GoogleSearchTool.from_credentials(credentials).invoke( + tool_parameters={"query": "test", "result_type": "link"}, + ): + pass + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) +``` + +### プラグインのデバッグ + +プラグインの開発が完了したら、プラグインが正常に機能するかどうかをテストする必要があります。Difyは、テスト環境でプラグインの機能を素早く検証するのに役立つ便利なリモートデバッグ方法を提供しています。 + +[「プラグイン管理」](https://cloud.dify.ai/plugins)ページに移動して、リモートサーバーアドレスとデバッグキーを取得します。 + +![Remote Debug Key](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) + +プラグインプロジェクトに戻り、`.env.example`ファイルをコピーして`.env`に名前変更し、取得したリモートサーバーアドレスとデバッグキー情報を入力します。 + +`.env`ファイル: + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_URL=debug.dify.ai:5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +`python -m main`コマンドを実行してプラグインを起動します。プラグインページで、プラグインがワークスペースにインストールされていることを確認でき、チームの他のメンバーもプラグインにアクセスできます。 + +![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) + +### プラグインのパッケージング(オプション) + +プラグインが正常に実行できることを確認した後、以下のコマンドラインツールを使用してプラグインをパッケージ化して名前を付けることができます。実行後、現在のフォルダに`google.difypkg`ファイルが作成されます。これが最終的なプラグインパッケージです。 + +```bash +# Replace ./google with the actual path of the plugin project + +dify plugin package ./google +``` + +おめでとうございます!ツールタイプのプラグインの開発、デバッグ、パッケージングの全プロセスを完了しました! + +### プラグインの公開(オプション) + +プラグインをDify Marketplaceに公開したい場合は、プラグインが[Dify Marketplaceへの公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace)の仕様に従っていることを確認してください。レビューに合格すると、コードはメインブランチにマージされ、自動的に[Dify Marketplace](https://marketplace.dify.ai/)で公開されます。 + +[公開の概要](/ja/develop-plugin/publishing/marketplace-listing/release-overview) + +### さらに探索 + +#### **クイックスタート:** + +- [拡張プラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) +- [モデルプラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) +- [バンドルプラグイン:複数のプラグインのパッケージング](/ja/develop-plugin/features-and-specs/advanced-development/bundle) + +#### **プラグインインターフェースドキュメント:** + +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - マニフェスト構造とツール仕様 +- [Endpoint](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 詳細なEndpointの定義 +- [リバース呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - Dify機能のリバース呼び出し +- [モデルスキーマ](/ja/develop-plugin/features-and-specs/plugin-types/model-schema) - モデル +- [エージェントプラグイン](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - エージェント戦略の拡張 + +## 次の学習ステップ + +- [プラグインのリモートデバッグ](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - より高度なデバッグテクニックを学ぶ +- [永続ストレージ](/ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) - プラグインでのデータストレージの使用方法を学ぶ +- [Slack Botプラグイン開発例](/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - より複雑なプラグイン開発ケースを見る +- [ツールプラグイン](/ja/develop-plugin/features-and-specs/plugin-types/tool) - ツールプラグインの高度な機能を探索 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-ja/0222-trigger-plugin.mdx b/ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx similarity index 69% rename from plugin-dev-ja/0222-trigger-plugin.mdx rename to ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx index 45302628..1ac7e791 100644 --- a/plugin-dev-ja/0222-trigger-plugin.mdx +++ b/ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx @@ -2,87 +2,88 @@ title: "トリガープラグイン" --- + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin)を参照してください。 + ## トリガープラグインとは? -トリガー(Trigger) は、Dify v1.10.0で導入された新しいタイプの開始ノードです。Code、Tool、Knowledge Retrievalなどの機能的なノードとは異なり、トリガーの目的は、**サードパーティのイベントをDifyが認識・処理できる入力形式に変換する**ことです。 +トリガーは Dify v1.10.0 で新しいタイプの開始ノードとして導入されました。コード、ツール、ナレッジベース検索などの機能ノードとは異なり、トリガーの目的は**サードパーティのイベントを Dify が認識して処理できる入力形式に変換すること**です。 -![トリガープラグインの紹介](/images/trigger_plugin_intro.PNG) +![Trigger Plugin Intro](/images/trigger_plugin_intro.PNG) -例えば、Gmailの`new email`イベントの受信先としてDifyを設定すると、新しいメールを受信するたびに、Gmailはワークフローを起動するためのイベントをDifyに自動的に送信します。しかし、これには課題があります。 +例えば、Gmail で Dify を `new email` イベントの受信者として設定すると、新しいメールを受信するたびに、Gmail はワークフローをトリガーするために使用できるイベントを Dify に自動的に送信します。しかし: -- Gmailの元のイベント形式は、Difyの入力形式と互換性がありません。 +- Gmail の元のイベント形式は Dify の入力形式と互換性がありません。 -- 世界中には何千ものプラットフォームが存在し、それぞれが独自のイベント形式を持っています。 +- 世界中には数千のプラットフォームがあり、それぞれ独自のイベント形式を持っています。 -そのため、さまざまなプラットフォームや形式から送られてくるこれらのイベントを定義・解析し、Difyが受け入れられる統一された入力形式に変換するために、トリガープラグインが必要となります。 +そのため、異なるプラットフォームや様々な形式からのこれらのイベントを定義・解析し、Dify が受け入れられる入力形式に統一するトリガープラグインが必要です。 ## 技術概要 -Difyのトリガーは、Webで広く採用されているメカニズムである**Webhook**に基づいて実装されています。多くの主流SaaSプラットフォーム(GitHub、Slack、Linearなど)は、包括的な開発者向けドキュメントと共にWebhookをサポートしています。 +Dify のトリガーは、Web 全体で広く採用されているメカニズムである webhook に基づいて実装されています。多くの主要な SaaS プラットフォーム(GitHub、Slack、Linear など)は、包括的な開発者ドキュメントと共に webhook をサポートしています。 -Webhookは、HTTPベースのイベントディスパッチャと理解することができます。**イベント受信アドレスを設定すると、これらのSaaSプラットフォームは、登録したイベントが発生するたびに、ターゲットサーバーにイベントデータを自動的にプッシュします。** +webhook は HTTP ベースのイベントディスパッチャーとして理解できます。**イベント受信アドレスが設定されると、これらの SaaS プラットフォームは、購読したイベントが発生するたびに、イベントデータをターゲットサーバーに自動的にプッシュします。** -異なるプラットフォームからのWebhookイベントを統一的に処理するために、Difyは**サブスクリプション (Subscription)** と **イベント (Event)** という2つのコアコンセプトを定義しています。 +異なるプラットフォームからの webhook イベントを統一的に処理するために、Dify は 2 つのコアコンセプトを定義しています:**Subscription** と **Event**。 -- **サブスクリプション**: Webhookベースのイベントディスパッチでは、**サードパーティプラットフォームの開発者コンソールでDifyのネットワークアドレスをターゲットサーバーとして登録する必要があります。Difyでは、この設定プロセスをサブスクリプションと呼びます。** +- **Subscription**:Webhook ベースのイベントディスパッチには、**サードパーティプラットフォームの開発者コンソールで Dify のネットワークアドレスをターゲットサーバーとして登録する必要があります。Dify では、この設定プロセスを *Subscription* と呼びます。** -- **イベント**: プラットフォームは、*メール受信*、*メール削除*、*メール既読*など、複数のタイプのイベントを送信することがあり、これらはすべて登録されたアドレスにプッシュされます。トリガープラグインは複数のイベントタイプを処理でき、各イベントがDifyワークフロー内のプラグイントリガーノードに対応します。 +- **Event**:プラットフォームは複数のタイプのイベント(*メール受信*、*メール削除*、*メールを既読にマーク*など)を送信する可能性があり、これらはすべて登録されたアドレスにプッシュされます。トリガープラグインは複数のイベントタイプを処理でき、各イベントは Dify ワークフロー内のプラグイントリガーノードに対応します。 ## プラグイン開発 -トリガープラグインの開発プロセスは、他のプラグインタイプ(Tool、Data Source、Modelなど)と一貫しています。 +トリガープラグインの開発プロセスは、他のプラグインタイプ(ツール、データソース、モデルなど)と一貫しています。 -`dify plugin init`コマンドを使用して開発テンプレートを作成できます。生成されるファイル構造は、標準のプラグイン形式仕様に準拠しています。 +`dify plugin init` コマンドを使用して開発テンプレートを作成できます。生成されるファイル構造は標準のプラグイン形式仕様に従います。 ``` ├── _assets -│   └── icon.svg +│ └── icon.svg ├── events -│   └── star -│   ├── star_created.py -│   └── star_created.yaml +│ └── star +│ ├── star_created.py +│ └── star_created.yaml ├── main.py ├── manifest.yaml ├── provider -│   ├── github.py -│   └── github.yaml +│ ├── github.py +│ └── github.yaml ├── README.md ├── PRIVACY.md └── requirements.txt ``` -- `manifest.yaml`: プラグインの基本的なメタデータを記述します。 +- `manifest.yaml`:プラグインの基本的なメタデータを記述します。 -- `provider` ディレクトリ: プロバイダーのメタデータ、購読を作成するためのコード、Webhookリクエスト受信後にイベントを分類するためのコードが含まれます。 +- `provider` ディレクトリ:プロバイダーのメタデータ、サブスクリプション作成のコード、webhook リクエスト受信後のイベント分類のコードを含みます。 -- **`events` ディレクトリ: イベント処理とフィルタリングのコードが含まれ、ノードレベルでのローカルイベントフィルタリングをサポートします。関連するイベントをグループ化するためにサブディレクトリを作成できます。** +- **`events` ディレクトリ:イベント処理とフィルタリングのコードを含み、ノードレベルでのローカルイベントフィルタリングをサポートします。関連するイベントをグループ化するためにサブディレクトリを作成できます。** - トリガープラグインの場合、要求されるDifyの最小バージョンは`1.10.0`、SDKバージョンは`>= 0.6.0`に設定する必要があります。 + トリガープラグインの場合、最小必要 Dify バージョンは `1.10.0` に設定し、SDK バージョンは `>= 0.6.0` である必要があります。 -次に、GitHubを例として、トリガープラグインの開発プロセスを説明します。 +次に、GitHub を例として、トリガープラグインの開発プロセスを説明します。 -### Subscription(購読)の作成 +### サブスクリプションの作成 -Webhookの設定方法は、主流のSaaSプラットフォーム間で大きく異なります。 +Webhook の設定方法は、主要な SaaS プラットフォーム間で大きく異なります: -- 一部のプラットフォーム(GitHubなど)は、APIベースのWebhook設定をサポートしています。これらのプラットフォームでは、OAuth認証が完了すると、Difyが自動的にWebhookをセットアップできます。 +- 一部のプラットフォーム(GitHub など)は API ベースの webhook 設定をサポートしています。これらのプラットフォームでは、OAuth 認証が完了すると、Dify は自動的に webhook をセットアップできます。 -- 他のプラットフォーム(Notionなど)は、Webhook設定APIを提供しておらず、ユーザーによる手動認証が必要な場合があります。 +- 他のプラットフォーム(Notion など)は webhook 設定 API を提供しておらず、ユーザーが手動で認証を行う必要がある場合があります。 -これらの違いに対応するため、サブスクリプションのプロセスを**サブスクリプションコンストラクタ (Subscription Constructor)** と **サブスクリプション (Subscription)** 自体の2つの部分に分けます。 +これらの違いに対応するため、サブスクリプションプロセスを 2 つの部分に分けています:**Subscription Constructor** と **Subscription** 自体。 -Notionのようなプラットフォームでは、サブスクリプションを作成するために、ユーザーがDifyから提供されたコールバックURLを手動でコピーし、Notionワークスペースに貼り付けてWebhook設定を完了させる必要があります。このプロセスは、Difyインターフェースの**URLを貼り付けて新しいサブスクリプションを作成**オプションに対応します。 +Notion のようなプラットフォームでは、サブスクリプションを作成するには、ユーザーが Dify から提供されたコールバック URL を手動でコピーし、Notion ワークスペースに貼り付けて webhook 設定を完了する必要があります。このプロセスは、Dify インターフェースの **Paste URL to create a new subscription** オプションに対応します。 -URLを貼り付けて新しいサブスクリプションを作成 +URL を貼り付けて新しいサブスクリプションを作成 -手動でのURL貼り付けによるサブスクリプション作成を実装するには、`github.yaml`と`github.py`の2つのファイルを変更する必要があります。 +手動 URL 貼り付けによるサブスクリプション作成を実装するには、`github.yaml` と `github.py` の 2 つのファイルを変更する必要があります。 - - GitHubのWebhookは暗号化メカニズムを使用しているため、受信リクエストを復号化して検証するにはシークレットキーが必要です。そのため、`github.yaml`で`webhook_secret`を宣言する必要があります。 + GitHub の webhook は暗号化メカニズムを使用しているため、受信リクエストを復号化して検証するためにシークレットキーが必要です。そのため、`github.yaml` で `webhook_secret` を宣言する必要があります。 ```YAML subscription_schema: @@ -101,16 +102,16 @@ Notionのようなプラットフォームでは、サブスクリプション - まず、`dispatch_event`インターフェースを実装する必要があります。コールバックURLに送信されるすべてのリクエストはこのインターフェースによって処理され、処理されたイベントはデバッグと検証のために**リクエストログ**セクションに表示されます。 + まず、`dispatch_event` インターフェースを実装する必要があります。コールバック URL に送信されるすべてのリクエストはこのインターフェースによって処理され、処理されたイベントはデバッグと検証のために **Request Logs** セクションに表示されます。 - 手動セットアップ + 手動設定 - コード内では、`github.yaml`で宣言された`webhook_secret`を`subscription.properties`経由で取得できます。 + コードでは、`subscription.properties` を通じて `github.yaml` で宣言された `webhook_secret` を取得できます。 - `dispatch_event`メソッドは、リクエストの内容に基づいてイベントタイプを決定する必要があります。以下の例では、このイベント抽出は`_dispatch_trigger_event`メソッドによって処理されます。 + `dispatch_event` メソッドは、リクエストの内容に基づいてイベントタイプを判断する必要があります。以下の例では、このイベント抽出は `_dispatch_trigger_event` メソッドによって処理されます。 - 完全なコードサンプルについては、[DifyのGitHubトリガープラグイン](https://github.com/langgenius/dify-plugin-sdks/tree/feat/trigger/python/examples/github_trigger)を参照してください。 + 完全なコードサンプルについては、[Dify の GitHub トリガープラグイン](https://github.com/langgenius/dify-plugin-sdks/tree/feat/trigger/python/examples/github_trigger)を参照してください。 ```Python @@ -136,9 +137,9 @@ Notionのようなプラットフォームでは、サブスクリプション ### イベント処理 -イベントが抽出されると、対応する実装は元のHTTPリクエストをフィルタリングし、Difyワークフローが受け入れ可能な入力形式に変換する必要があります。 +イベントが抽出されると、対応する実装は元の HTTP リクエストをフィルタリングし、Dify ワークフローが受け入れられる入力形式に変換する必要があります。 -Issueイベントを例にとると、`events/issues/issues.yaml`と`events/issues/issues.py`を通じてイベントとその実装を定義できます。イベントの出力は`issues.yaml`の`output_schema`セクションで定義でき、これはツールプラグインと同じくJSON Schema仕様に従います。 +Issue イベントを例にとると、`events/issues/issues.yaml` と `events/issues/issues.py` を通じてイベントとその実装を定義できます。イベントの出力は `issues.yaml` の `output_schema` セクションで定義でき、ツールプラグインと同じ JSON Schema 仕様に従います。 @@ -202,7 +203,7 @@ Issueイベントを例にとると、`events/issues/issues.yaml`と`events/issu ### イベントフィルタリング -特定のイベント(例えば、特定のラベルを持つIssueイベントのみ)をフィルタリングするには、`issues.yaml`のイベント定義に`parameters`を追加します。その後、`_on_event`メソッド内で`EventIgnoreError`例外をスローすることで、設定された基準を満たさないイベントを除外できます。 +特定のイベントをフィルタリングするには(例えば、特定のラベルを持つ Issue イベントのみに焦点を当てる場合)、`issues.yaml` のイベント定義に `parameters` を追加できます。その後、`_on_event` メソッドで、設定された条件を満たさないイベントをフィルタリングするために `EventIgnoreError` 例外をスローできます。 @@ -249,13 +250,13 @@ Issueイベントを例にとると、`events/issues/issues.yaml`と`events/issu -### OAuthまたはAPIキーによるサブスクリプションの作成 +### OAuth または API キーによるサブスクリプション作成 -OAuthまたはAPIキーを介した自動的なサブスクリプション作成を有効にするには、`github.yaml`と`github.py`ファイルを変更する必要があります。 +OAuth または API キーによる自動サブスクリプション作成を有効にするには、`github.yaml` と `github.py` ファイルを変更する必要があります。 - `github.yaml`に以下のフィールドを追加します。 + `github.yaml` に以下のフィールドを追加します。 ```YAML subscription_constructor: @@ -297,16 +298,16 @@ OAuthまたはAPIキーを介した自動的なサブスクリプション作成 source: provider/github.py ``` - `subscription_constructor`は、サブスクリプションがどのように構築されるかを定義するためにDifyによって抽象化された概念です。以下のフィールドが含まれます。 + `subscription_constructor` は、サブスクリプションの構築方法を定義するために Dify が抽象化した概念です。以下のフィールドが含まれます: - - `parameters` (任意): 購読するイベントタイプやターゲットのGitHubリポジトリなど、サブスクリプション作成に必要なパラメータを定義します。 + - `parameters`(オプション):購読するイベントタイプやターゲット GitHub リポジトリなど、サブスクリプション作成に必要なパラメータを定義します - - `credentials_schema` (任意): APIキーでサブスクリプションを作成する際に必要な認証情報(例: GitHubの`access_tokens`)を宣言します。 + - `credentials_schema`(オプション):API キーまたはアクセストークンを使用してサブスクリプションを作成するために必要な認証情報を宣言します(GitHub の `access_tokens` など)。 - - `oauth_schema` (任意): OAuth経由でのサブスクリプション作成を実装する場合に必要です。定義方法の詳細は、[ツールプラグインにOAuthサポートを追加する](/plugin-dev-en/0222-tool-oauth)を参照してください。 + - `oauth_schema`(オプション):OAuth によるサブスクリプション作成を実装するために必要です。定義方法の詳細については、[ツールプラグインに OAuth サポートを追加する](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-oauth)を参照してください。 - `github.py`に`Constructor`クラスを作成し、自動サブスクリプションロジックを実装します。 + `github.py` で、自動サブスクリプションロジックを実装する `Constructor` クラスを作成します。 ```Python class GithubSubscriptionConstructor(TriggerSubscriptionConstructor): @@ -383,16 +384,15 @@ OAuthまたはAPIキーを介した自動的なサブスクリプション作成 --- +これら 2 つのファイルを変更すると、Dify インターフェースに **Create with API Key** オプションが表示されます。 -これら2つのファイルを変更すると、Difyインターフェースに**APIキーで作成**オプションが表示されます。 +OAuth による自動サブスクリプション作成も同じ `Constructor` クラスで実装できます:`subscription_constructor` の下に `oauth_schema` フィールドを追加することで、OAuth 認証を有効にできます。 -OAuth経由の自動サブスクリプション作成も同じ`Constructor`クラスで実装できます。`subscription_constructor`の下に`oauth_schema`フィールドを追加することで、OAuth認証を有効にできます。 - -OAuthとAPIキーのオプション +OAuth と API キーオプション ## さらに詳しく -トリガープラグイン開発における核心クラスのインターフェース定義と実装方法は以下の通りです。 +トリガープラグイン開発におけるコアクラスのインターフェース定義と実装方法は以下の通りです。 ### Trigger @@ -662,5 +662,4 @@ It will be automatically generated by the script. --- -[このページを編集する](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-ja/0222-trigger-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/advanced-development/bundle.mdx b/ja/develop-plugin/features-and-specs/advanced-development/bundle.mdx new file mode 100644 index 00000000..f21f08a9 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/advanced-development/bundle.mdx @@ -0,0 +1,106 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: beginner +standard_title: Bundle +language: en +title: Bundleプラグインパッケージ +description: このドキュメントでは、Bundleプラグインパッケージの概念と開発方法を紹介します。Bundleプラグインパッケージは複数のプラグインを集約でき、3つのタイプ(Marketplace、GitHub、Package)をサポートしています。ドキュメントでは、Bundleプロジェクトの作成、異なるタイプの依存関係の追加、Bundleプロジェクトのパッケージ化までの全プロセスを詳しく説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/bundle)を参照してください。 + +Bundleプラグインパッケージは、複数のプラグインの集合体です。単一のプラグイン内に複数のプラグインをパッケージ化することで、一括インストールを可能にし、より強力なサービスを提供します。 + +Dify CLIツールを使用して、複数のプラグインをBundleにパッケージ化できます。Bundleプラグインパッケージには3つのタイプがあります: + +* `Marketplace`タイプ。プラグインのIDとバージョン情報を保存します。インポート時に、特定のプラグインパッケージがDify Marketplaceからダウンロードされます。 +* `GitHub`タイプ。GitHubリポジトリアドレス、リリースバージョン番号、アセットファイル名を保存します。インポート時に、Difyは対応するGitHubリポジトリにアクセスしてプラグインパッケージをダウンロードします。 +* `Package`タイプ。プラグインパッケージはBundle内に直接保存されます。参照元を保存しませんが、Bundleパッケージのサイズが大きくなる可能性があります。 + +### 前提条件 + +* Difyプラグインスキャフォールディングツール +* Python環境、バージョン ≥ 3.10 + +プラグイン開発スキャフォールディングツールの準備方法の詳細については、[開発ツールの初期化](/ja/develop-plugin/getting-started/cli)を参照してください。 + +### Bundleプロジェクトの作成 + +現在のディレクトリで、スキャフォールディングコマンドラインツールを実行して新しいプラグインパッケージプロジェクトを作成します。 + +```bash +./dify-plugin-darwin-arm64 bundle init +``` + +バイナリファイルを`dify`にリネームして`/usr/local/bin`パスにコピーしている場合は、次のコマンドを実行して新しいプラグインプロジェクトを作成できます: + +```bash +dify bundle init +``` + +#### 1. プラグイン情報の入力 + +プロンプトに従って、プラグイン名、作成者情報、プラグインの説明を設定します。チームで共同作業している場合は、作成者として組織名を入力することもできます。 + +> 名前は1〜128文字で、文字、数字、ハイフン、アンダースコアのみを含めることができます。 + +![Bundle基本情報](https://assets-docs.dify.ai/2024/12/03a1c4cdc72213f09523eb1b40832279.png) + +情報を入力してEnterを押すと、Bundleプラグインプロジェクトディレクトリが自動的に作成されます。 + +![](https://assets-docs.dify.ai/2024/12/356d1a8201fac3759bf01ee64e79a52b.png) + +#### 2. 依存関係の追加 + +* **Marketplace** + +次のコマンドを実行します: + +```bash +dify-plugin bundle append marketplace . --marketplace_pattern=langgenius/openai:0.0.1 +``` + +`marketplace_pattern`はマーケットプレイス内のプラグインへの参照で、形式は`organization_name/plugin_name:version_number`です。 + +* **GitHub** + +次のコマンドを実行します: + +```bash +dify-plugin bundle append github . --repo_pattern=langgenius/openai:0.0.1/openai.difypkg +``` + +`repo_pattern`はGitHub上のプラグインへの参照で、形式は`organization_name/repository_name:release/asset_name`です。 + +* **Package** + +次のコマンドを実行します: + +```bash +dify-plugin bundle append package . --package_path=./openai.difypkg +``` + +`package_path`はプラグインパッケージのディレクトリです。 + +### Bundleプロジェクトのパッケージ化 + +次のコマンドを実行してBundleプラグインをパッケージ化します: + +```bash +dify-plugin bundle package ./bundle +``` + +コマンドを実行すると、現在のディレクトリに`bundle.difybndl`ファイルが自動的に作成されます。このファイルが最終的なパッケージ化結果です。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/bundle.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx b/ja/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx new file mode 100644 index 00000000..fe4bb4ab --- /dev/null +++ b/ja/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx @@ -0,0 +1,360 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: advanced +standard_title: Customizable Model +language: ja +title: カスタムモデルの統合 +description: このドキュメントでは、Xinferenceモデルを例として、カスタムモデルをDifyに統合する方法を詳しく説明します。モデルプロバイダーファイルの作成、モデルタイプに基づくコードの記述、モデル呼び出しロジックの実装、例外処理、デバッグ、公開までの完全なプロセスをカバーしています。特に、LLM呼び出し、トークン計算、認証情報の検証、パラメータ生成などのコアメソッドの実装を詳しく説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/customizable-model)を参照してください。 + +**カスタムモデル**とは、自分でデプロイまたは設定するLLMを指します。このドキュメントでは、[Xinferenceモデル](https://inference.readthedocs.io/en/latest/)を例として、カスタムモデルを**モデルプラグイン**に統合する方法を説明します。 + +デフォルトでは、カスタムモデルは自動的に2つのパラメータ(**モデルタイプ**と**モデル名**)を含み、プロバイダーYAMLファイルで追加の定義は必要ありません。 + +プロバイダー設定ファイルに`validate_provider_credential`を実装する必要はありません。ランタイム中、ユーザーが選択したモデルタイプまたはモデル名に基づいて、Difyは自動的に対応するモデルレイヤーの`validate_credentials`メソッドを呼び出して認証情報を検証します。 + +## カスタムモデルプラグインの統合 + +以下はカスタムモデルを統合する手順です: + +1. **モデルプロバイダーファイルの作成**\ + カスタムモデルに含まれるモデルタイプを特定します。 +2. **モデルタイプごとのコードファイルの作成**\ + モデルのタイプ(例:`llm`や`text_embedding`)に応じて、別々のコードファイルを作成します。各モデルタイプが個別の論理レイヤーに整理されていることを確認し、保守と将来の拡張を容易にします。 +3. **モデル呼び出しロジックの開発**\ + 各モデルタイプモジュール内で、そのモデルタイプの名前を付けたPythonファイル(例:`llm.py`)を作成します。ファイル内でシステムのモデルインターフェース仕様に準拠した特定のモデルロジックを実装するクラスを定義します。 +4. **プラグインのデバッグ**\ + 新しいプロバイダー機能のユニットテストと統合テストを作成し、すべてのコンポーネントが意図どおりに動作することを確認します。 + +*** + +### 1. **モデルプロバイダーファイルの作成** + +プラグインの`/provider`ディレクトリに、`xinference.yaml`ファイルを作成します。 + +`Xinference`ファミリーのモデルは**LLM**、**Text Embedding**、**Rerank**モデルタイプをサポートしているため、`xinference.yaml`にはこれら3つすべてを含める必要があります。 + +**例:** + +```yaml +provider: xinference # Identifies the provider +label: # Display name; can set both en_US (English) and zh_Hans (Chinese). If zh_Hans is not set, en_US is used by default. + en_US: Xorbits Inference +icon_small: # Small icon; store in the _assets folder of this provider's directory. The same multi-language logic applies as with label. + en_US: icon_s_en.svg +icon_large: # Large icon + en_US: icon_l_en.svg +help: # Help information + title: + en_US: How to deploy Xinference + zh_Hans: 如何部署 Xinference + url: + en_US: https://github.com/xorbitsai/inference + +supported_model_types: # Model types Xinference supports: LLM/Text Embedding/Rerank +- llm +- text-embedding +- rerank + +configurate_methods: # Xinference is locally deployed and does not offer predefined models. Refer to its documentation to learn which model to use. Thus, we choose a customizable-model approach. +- customizable-model + +provider_credential_schema: + credential_form_schemas: +``` + +次に、`provider_credential_schema`を定義します。`Xinference`はテキスト生成、エンベディング、リランキングモデルをサポートしているため、以下のように設定できます: + +```yaml +provider_credential_schema: + credential_form_schemas: + - variable: model_type + type: select + label: + en_US: Model type + zh_Hans: 模型类型 + required: true + options: + - value: text-generation + label: + en_US: Language Model + zh_Hans: 语言模型 + - value: embeddings + label: + en_US: Text Embedding + - value: reranking + label: + en_US: Rerank +``` + +Xinferenceのすべてのモデルには`model_name`が必要です: + +```yaml + - variable: model_name + type: text-input + label: + en_US: Model name + zh_Hans: 模型名称 + required: true + placeholder: + zh_Hans: 填写模型名称 + en_US: Input model name +``` + +Xinferenceはローカルでデプロイする必要があるため、ユーザーはサーバーアドレス(server\_url)とモデルUIDを提供する必要があります。例えば: + +```yaml + - variable: server_url + label: + zh_Hans: 服务器 URL + en_US: Server url + type: text-input + required: true + placeholder: + zh_Hans: 在此输入 Xinference 的服务器地址,如 https://example.com/xxx + en_US: Enter the url of your Xinference, for example https://example.com/xxx + + - variable: model_uid + label: + zh_Hans: 模型 UID + en_US: Model uid + type: text-input + required: true + placeholder: + zh_Hans: 在此输入你的 Model UID + en_US: Enter the model uid +``` + +これらのパラメータを定義したら、カスタムモデルプロバイダーのYAML設定は完了です。次に、この設定で定義された各モデルの機能コードファイルを作成します。 + +### 2. モデルコードの開発 + +Xinferenceはllm、rerank、speech2text、ttsをサポートしているため、/models下に対応するディレクトリを作成し、それぞれに機能コードを含める必要があります。 + +以下はllmタイプのモデルの例です。llm.pyという名前のファイルを作成し、\_\_base.large\_language\_model.LargeLanguageModelを拡張するXinferenceAILargeLanguageModelなどのクラスを定義します。このクラスには以下を含める必要があります: + +* **LLM呼び出し** + +LLMを呼び出すためのコアメソッドで、ストリーミングと同期応答の両方をサポートします: + +```python +def _invoke( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + model_parameters: dict, + tools: Optional[list[PromptMessageTool]] = None, + stop: Optional[list[str]] = None, + stream: bool = True, + user: Optional[str] = None +) -> Union[LLMResult, Generator]: + """ + Invoke the large language model. + + :param model: model name + :param credentials: model credentials + :param prompt_messages: prompt messages + :param model_parameters: model parameters + :param tools: tools for tool calling + :param stop: stop words + :param stream: determines if response is streamed + :param user: unique user id + :return: full response or a chunk generator + """ +``` + +ストリーミングと同期応答を処理するために2つの別々の関数が必要です。Pythonは`yield`を含む関数を`Generator`型を返すジェネレータとして扱うため、これらを分離することをお勧めします: + +```yaml +def _invoke(self, stream: bool, **kwargs) -> Union[LLMResult, Generator]: + if stream: + return self._handle_stream_response(**kwargs) + return self._handle_sync_response(**kwargs) + +def _handle_stream_response(self, **kwargs) -> Generator: + for chunk in response: + yield chunk + +def _handle_sync_response(self, **kwargs) -> LLMResult: + return LLMResult(**response) +``` + +* **入力トークンの事前計算** + +モデルがトークンカウントインターフェースを提供していない場合は、単に0を返します: + +```python +def get_num_tokens( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + tools: Optional[list[PromptMessageTool]] = None +) -> int: + """ + Get the number of tokens for the given prompt messages. + """ + return 0 +``` + +または、`AIModel`基底クラスから`self._get_num_tokens_by_gpt2(text: str)`を呼び出すことができます。これはGPT-2トークナイザーを使用します。これは近似値であり、モデルと正確に一致しない場合があることに注意してください。 + +* **モデル認証情報の検証** + +プロバイダーレベルの認証情報チェックと似ていますが、単一のモデルにスコープされます: + +```python +def validate_credentials(self, model: str, credentials: dict) -> None: + """ + Validate model credentials. + """ +``` + +* **動的モデルパラメータスキーマ** + +[事前定義モデル](/ja/plugins/quick-start/develop-plugins/model-plugin/predefined-model)とは異なり、モデルがサポートするパラメータを定義するYAMLはありません。パラメータスキーマを動的に生成する必要があります。 + +例えば、Xinferenceは`max_tokens`、`temperature`、`top_p`をサポートしています。他のプロバイダー(例:`OpenLLM`)は、特定のモデルでのみ`top_k`などのパラメータをサポートする場合があります。つまり、各モデルの機能に合わせてスキーマを適応させる必要があります: + +```python +def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity | None: + """ + used to define customizable model schema + """ + rules = [ + ParameterRule( + name='temperature', type=ParameterType.FLOAT, + use_template='temperature', + label=I18nObject( + zh_Hans='温度', en_US='Temperature' + ) + ), + ParameterRule( + name='top_p', type=ParameterType.FLOAT, + use_template='top_p', + label=I18nObject( + zh_Hans='Top P', en_US='Top P' + ) + ), + ParameterRule( + name='max_tokens', type=ParameterType.INT, + use_template='max_tokens', + min=1, + default=512, + label=I18nObject( + zh_Hans='最大生成长度', en_US='Max Tokens' + ) + ) + ] + + # if model is A, add top_k to rules + if model == 'A': + rules.append( + ParameterRule( + name='top_k', type=ParameterType.INT, + use_template='top_k', + min=1, + default=50, + label=I18nObject( + zh_Hans='Top K', en_US='Top K' + ) + ) + ) + + """ + some NOT IMPORTANT code here + """ + + entity = AIModelEntity( + model=model, + label=I18nObject( + en_US=model + ), + fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, + model_type=model_type, + model_properties={ + ModelPropertyKey.MODE: ModelType.LLM, + }, + parameter_rules=rules + ) + + return entity +``` + +* **エラーマッピング** + +モデル呼び出し中にエラーが発生した場合、ランタイムが認識する適切なInvokeErrorタイプにマッピングします。これにより、Difyは異なるエラーを標準化された方法で処理できます: + +ランタイムエラー: + +``` +• `InvokeConnectionError` +• `InvokeServerUnavailableError` +• `InvokeRateLimitError` +• `InvokeAuthorizationError` +• `InvokeBadRequestError` +``` + +```python +@property +def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + Map model invocation errors to unified error types. + The key is the error type thrown to the caller. + The value is the error type thrown by the model, which needs to be mapped to a + unified Dify error for consistent handling. + """ + # return { + # InvokeConnectionError: [requests.exceptions.ConnectionError], + # ... + # } +``` + +インターフェースメソッドの詳細については、[モデルドキュメント](https://docs.dify.ai/zh-hans/plugins/schema-definition/model)を参照してください。 + +このガイドで説明した完全なコードファイルを表示するには、[GitHubリポジトリ](https://github.com/langgenius/dify-official-plugins/tree/main/models/xinference)にアクセスしてください。 + +### 3. プラグインのデバッグ + +開発が完了したら、プラグインをテストして正しく動作することを確認します。詳細については、以下を参照してください: + + + + +### 4. プラグインの公開 + +このプラグインをDify Marketplaceに掲載したい場合は、以下を参照してください: + +Dify Marketplaceに公開 + +## さらに探索 + +**クイックスタート:** + +* [拡張プラグインの開発](/ja/plugins/quick-start/develop-plugins/extension-plugin) +* [ツールプラグインの開発](/ja/plugins/quick-start/develop-plugins/tool-plugin) +* [バンドルプラグイン:複数のプラグインをパッケージ化](/ja/plugins/quick-start/develop-plugins/bundle) + +**プラグインエンドポイントドキュメント:** + +* [マニフェスト](/ja/plugins/schema-definition/manifest)構造 +* [エンドポイント](/ja/plugins/schema-definition/endpoint)定義 +* [Difyサービスの逆呼び出し](/ja/plugins/schema-definition/reverse-invocation-of-the-dify-service) +* [ツール](/ja/plugins/schema-definition/tool) +* [モデル](/ja/plugins/schema-definition/model) + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx new file mode 100644 index 00000000..706e02fa --- /dev/null +++ b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx @@ -0,0 +1,142 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: intermediate +standard_title: Reverse Invocation App +language: ja +title: App +description: このドキュメントでは、プラグインがDifyプラットフォーム内でAppサービスを逆呼び出しする方法について詳しく説明します。Chatインターフェース(Chatbot/Agent/Chatflowアプリケーション用)、Workflowインターフェース、Completionインターフェースの3種類のインターフェースについて、エントリーポイント、呼び出し仕様、および各インターフェースの実用的なコード例を提供します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app)を参照してください。 + +Appの逆呼び出しとは、プラグインがDify内のAppからデータにアクセスできることを意味します。このモジュールは、ストリーミングと非ストリーミングの両方のApp呼び出しをサポートしています。逆呼び出しの基本概念に不慣れな場合は、まず[Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation)をお読みください。 + +**インターフェースの種類:** + +* `Chatbot/Agent/Chatflow`タイプのアプリケーションは、すべてチャットベースのアプリケーションであり、同じ入出力パラメータタイプを共有しています。したがって、これらは**Chatインターフェース**として統一的に扱うことができます。 +* ワークフローアプリケーションは、別個の**Workflowインターフェース**を占有します。 +* Completion(テキスト生成アプリケーション)アプリケーションは、別個の**Completionインターフェース**を占有します。 + +プラグインは、プラグインが存在するワークスペース内のAppにのみアクセスできることに注意してください。 + +### Chatインターフェースの呼び出し + +#### **エントリーポイント** + +```python + self.session.app.chat +``` + +#### **インターフェース仕様** + +```python + def invoke( + self, + app_id: str, + inputs: dict, + response_mode: Literal["streaming", "blocking"], + conversation_id: str, + files: list, + ) -> Generator[dict, None, None] | dict: + pass +``` + +`response_mode`が`streaming`の場合、このインターフェースは直接`Generator[dict]`を返します。それ以外の場合は`dict`を返します。具体的なインターフェースフィールドについては、`ServiceApi`の戻り結果を参照してください。 + +#### **ユースケース** + +`Endpoint`内でChatタイプのAppを呼び出し、結果を直接返すことができます。 + +```python +import json +from typing import Mapping +from werkzeug import Request, Response +from dify_plugin import Endpoint + +class Duck(Endpoint): + def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: + """ + Invokes the endpoint with the given request. + """ + app_id = values["app_id"] + + def generator(): + # Note: The original example incorrectly called self.session.app.workflow.invoke + # It should call self.session.app.chat.invoke for a chat app. + # Assuming a chat app is intended here based on the section title. + response = self.session.app.chat.invoke( + app_id=app_id, + inputs={}, # Provide actual inputs as needed + response_mode="streaming", + conversation_id="some-conversation-id", # Provide a conversation ID if needed + files=[] + ) + + for data in response: + yield f"{json.dumps(data)}
" + + return Response(generator(), status=200, content_type="text/html") +``` + +### Workflowインターフェースの呼び出し + +#### **エントリーポイント** + +```python + self.session.app.workflow +``` + +#### **インターフェース仕様** + +```python + def invoke( + self, + app_id: str, + inputs: dict, + response_mode: Literal["streaming", "blocking"], + files: list, + ) -> Generator[dict, None, None] | dict: + pass +``` + +### Completionインターフェースの呼び出し + +#### **エントリーポイント** + +```python + self.session.app.completion +``` + +**インターフェース仕様** + +```python + def invoke( + self, + app_id: str, + inputs: dict, + response_mode: Literal["streaming", "blocking"], + files: list, + ) -> Generator[dict, None, None] | dict: + pass +``` + +## 関連リソース + +- [Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 逆呼び出しの基本概念を理解する +- [モデルの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) - プラットフォーム内でモデル機能を呼び出す方法を学ぶ +- [ツールの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) - 他のプラグインを呼び出す方法を学ぶ +- [Slack Botプラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 逆呼び出しを使用した実践的なアプリケーションケース +- [拡張プラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 拡張プラグインの開発方法を学ぶ + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-ja/9242-reverse-invocation-model.mdx b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx similarity index 50% rename from plugin-dev-ja/9242-reverse-invocation-model.mdx rename to ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx index b9a0d7fa..f8efee1c 100644 --- a/plugin-dev-ja/9242-reverse-invocation-model.mdx +++ b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx @@ -6,19 +6,21 @@ dimensions: level: intermediate standard_title: Reverse Invocation Model language: ja -title: モデル -description: このドキュメントでは、プラグインがDifyプラットフォーム内のモデルサービスをリバースコールする方法について詳しく説明します。内容は、LLM、Summary、TextEmbedding、Rerank、TTS、Speech2Text、Moderationなどのモデルをリバースコールする具体的な方法を含み、各モデルの呼び出しには、対応するエントリポイント、インターフェースパラメータの説明、および実際の使用例コードが付随しており、モデル呼び出しのベストプラクティスも提供しています。 +title: モデルの逆呼び出し +description: このドキュメントでは、プラグインがDifyプラットフォーム内でモデルサービスを逆呼び出しする方法について詳しく説明します。LLM、Summary、TextEmbedding、Rerank、TTS、Speech2Text、Moderationモデルの逆呼び出しの具体的な方法を網羅しています。各モデルの呼び出しには、エントリーポイント、インターフェースパラメータの説明、実用的なコード例、モデル呼び出しのベストプラクティス推奨事項が含まれています。 --- -リバースコールモデルとは、プラグインがDify内のLLM(TTS、Rerankなど、プラットフォーム内のすべてのモデルタイプと機能を含む)をリバースコールする能力を指します。リバースコールの基本概念にまだ慣れていない場合は、まず[Difyサービスのリバースコール](/plugin-dev-ja/9241-reverse-invocation)をお読みください。 + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model)を参照してください。 -ただし、モデルの呼び出しには `ModelConfig` 型のパラメータを渡す必要があり、その構造は[一般的な仕様定義](/plugin-dev-ja/0411-general-specifications)を参照できます。また、モデルの種類によって、この構造にはわずかな違いがあることに注意してください。 +モデルの逆呼び出しとは、プラグインがDifyの内部LLM機能を呼び出す能力を指し、TTS、Rerankなど、プラットフォーム内のすべてのモデルタイプと機能を含みます。逆呼び出しの基本概念に慣れていない場合は、まず[Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation)をお読みください。 -例えば、`LLM` タイプのモデルの場合、`completion_params` と `mode` パラメータも含まれている必要があり、この構造を手動で構築するか、`model-selector` タイプのパラメータまたは設定を使用できます。 +ただし、モデルを呼び出すには`ModelConfig`型のパラメータを渡す必要があることに注意してください。その構造は[一般仕様定義](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)で参照でき、この構造はモデルの種類によってわずかに異なります。 + +例えば、`LLM`型のモデルでは、`completion_params`と`mode`パラメータも含める必要があります。この構造を手動で構築するか、`model-selector`型のパラメータまたは設定を使用できます。 ### LLMの呼び出し -#### **エントリポイント** +#### **エントリーポイント** ```python self.session.model.llm @@ -38,11 +40,11 @@ description: このドキュメントでは、プラグインがDifyプラット pass ``` -呼び出すモデルに `tool_call` の機能がない場合、ここで渡される `tools` は有効にならないことに注意してください。 +呼び出すモデルに`tool_call`機能がない場合、ここで渡される`tools`は有効にならないことに注意してください。 #### **使用例** -`Tool` 内で `OpenAI` の `gpt-4o-mini` モデルを呼び出したい場合は、以下のサンプルコードを参照してください。 +`Tool`内でOpenAIの`gpt-4o-mini`モデルを呼び出したい場合は、以下のサンプルコードを参照してください: ```python from collections.abc import Generator @@ -79,11 +81,11 @@ class LLMTool(Tool): yield self.create_text_message(text=chunk.delta.message.content) ``` -コード内で `tool_parameters` の `query` パラメータが渡されていることに注意してください。 +コード内で`tool_parameters`から`query`パラメータが渡されていることに注意してください。 ### **ベストプラクティス** -`LLMModelConfig` を手動で構築することは推奨されません。代わりに、ユーザーがUI上で使用したいモデルを選択できるようにすることを推奨します。この場合、ツールのパラメータリストを次のように変更し、`model` パラメータを追加できます。 +`LLMModelConfig`を手動で構築することは推奨されません。代わりに、ユーザーがUI上で使用したいモデルを選択できるようにしてください。この場合、以下のように`model`パラメータを追加してツールのパラメータリストを変更できます: ```yaml identity: @@ -93,13 +95,11 @@ identity: en_US: LLM zh_Hans: LLM pt_BR: LLM - ja: LLM description: human: en_US: A tool for invoking a large language model zh_Hans: 用于调用大型语言模型的工具 pt_BR: A tool for invoking a large language model - ja: 大規模言語モデルを呼び出すためのツール llm: A tool for invoking a large language model parameters: - name: prompt @@ -109,12 +109,10 @@ parameters: en_US: Prompt string zh_Hans: 提示字符串 pt_BR: Prompt string - ja: プロンプト文字列 human_description: en_US: used for searching zh_Hans: 用于搜索网页内容 pt_BR: used for searching - ja: ウェブコンテンツの検索に使用 llm_description: key words for searching form: llm - name: model @@ -125,12 +123,10 @@ parameters: en_US: Model zh_Hans: 使用的模型 pt_BR: Model - ja: 使用するモデル human_description: en_US: Model zh_Hans: 使用的模型 pt_BR: Model - ja: 使用するモデル llm_description: which Model to invoke form: form extra: @@ -138,7 +134,7 @@ extra: source: tools/llm.py ``` -この例では `model` の `scope` が `llm` に指定されていることに注意してください。この場合、ユーザーは `llm` タイプのパラメータしか選択できず、上記の使用例のコードを次のように変更できます。 +この例では、`model`の`scope`が`llm`として指定されていることに注意してください。これにより、ユーザーは`llm`型のパラメータのみを選択できます。したがって、前の使用例のコードは以下のように変更できます: ```python from collections.abc import Generator @@ -158,7 +154,7 @@ class LLMTool(Tool): content='you are a helpful assistant' ), UserPromptMessage( - content=tool_parameters.get('query') + content=tool_parameters.get('query') # Assuming 'query' is still needed, otherwise use 'prompt' from parameters ) ], stream=True @@ -172,9 +168,9 @@ class LLMTool(Tool): ### Summaryの呼び出し -このエンドポイントにリクエストしてテキストを要約することができます。現在のワークスペース内のシステムモデルを使用してテキストを要約します。 +このエンドポイントにリクエストして、テキストを要約できます。現在のワークスペース内のシステムモデルを使用してテキストを要約します。 -**エントリポイント** +**エントリーポイント** ```python self.session.model.summary @@ -182,8 +178,8 @@ class LLMTool(Tool): **エンドポイント** -* `text` は要約されるテキストです。 -* `instruction` は追加したい指示であり、これによりテキストを特定のスタイルで要約できます。 +* `text`は要約するテキストです。 +* `instruction`は追加したい追加の指示で、テキストをスタイル的に要約できます。 ```python def invoke( @@ -193,7 +189,7 @@ class LLMTool(Tool): ### TextEmbeddingの呼び出し -**エントリポイント** +**エントリーポイント** ```python self.session.model.text_embedding @@ -210,7 +206,7 @@ class LLMTool(Tool): ### Rerankの呼び出し -**エントリポイント** +**エントリーポイント** ```python self.session.model.rerank @@ -227,7 +223,7 @@ class LLMTool(Tool): ### TTSの呼び出し -**エントリポイント** +**エントリーポイント** ```python self.session.model.tts @@ -242,11 +238,11 @@ class LLMTool(Tool): pass ``` -`tts` エンドポイントが返す `bytes` ストリームは `mp3` オーディオバイトストリームであり、各イテレーションで返されるのは完全なオーディオであることに注意してください。より高度な処理タスクを実行したい場合は、適切なライブラリを選択してください。 +`tts`エンドポイントが返す`bytes`ストリームは`mp3`オーディオバイトストリームであることに注意してください。各イテレーションは完全なオーディオセグメントを返します。より詳細な処理タスクを実行したい場合は、適切なライブラリを選択してください。 ### Speech2Textの呼び出し -**エントリポイント** +**エントリーポイント** ```python self.session.model.speech2text @@ -261,11 +257,11 @@ class LLMTool(Tool): pass ``` -ここで `file` は `mp3` 形式でエンコードされたオーディオファイルです。 +ここで`file`は`mp3`形式でエンコードされたオーディオファイルです。 ### Moderationの呼び出し -**エントリポイント** +**エントリーポイント** ```python self.session.model.moderation @@ -278,15 +274,15 @@ class LLMTool(Tool): pass ``` -このエンドポイントが `true` を返した場合、`text` に機密コンテンツが含まれていることを示します。 +このエンドポイントが`true`を返す場合、`text`に機密コンテンツが含まれていることを示します。 ## 関連リソース -- [Difyサービスのリバースコール](/plugin-dev-ja/9241-reverse-invocation) - リバースコールの基本概念を理解する -- [Appのリバースコール](/plugin-dev-ja/9242-reverse-invocation-app) - プラットフォーム内のAppを呼び出す方法を理解する -- [Toolのリバースコール](/plugin-dev-ja/9242-reverse-invocation-tool) - 他のプラグインを呼び出す方法を理解する -- [モデルプラグイン開発ガイド](/plugin-dev-ja/0211-getting-started-new-model) - カスタムモデルプラグインの開発方法を学ぶ -- [モデル設計規則](/plugin-dev-ja/0411-model-designing-rules) - モデルプラグインの設計原則を理解する +- [Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 逆呼び出しの基本概念を理解する +- [アプリの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - プラットフォーム内でアプリを呼び出す方法を学ぶ +- [ツールの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) - 他のプラグインを呼び出す方法を学ぶ +- [モデルプラグイン開発ガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - カスタムモデルプラグインの開発方法を学ぶ +- [モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - モデルプラグインの設計原則を理解する {/* Contributing Section @@ -296,5 +292,4 @@ It will be automatically generated by the script. --- -[このページを編集する](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-ja/9242-reverse-invocation-model.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx new file mode 100644 index 00000000..5dd5cea3 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx @@ -0,0 +1,110 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: advanced +standard_title: Reverse Invocation Node +language: ja +title: ノード +description: このドキュメントでは、プラグインがDifyプラットフォーム内のChatflow/ワークフローアプリケーションノードの機能を逆呼び出しする方法について説明します。主に、ParameterExtractorとQuestionClassifierという2つの特定のノードの呼び出し方法について説明します。このドキュメントでは、これら2つのノードを呼び出すためのエントリーポイント、インターフェースパラメータ、およびサンプルコードについて詳しく説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node)を参照してください。 + +ノードの逆呼び出しとは、プラグインがDify Chatflow/ワークフローアプリケーション内の特定のノードの機能にアクセスできることを意味します。 + +`ワークフロー`内の`ParameterExtractor`および`QuestionClassifier`ノードは、複雑なプロンプトとコードロジックをカプセル化しており、LLMを通じてハードコーディングでは解決が難しいタスクを実現できます。プラグインはこれら2つのノードを呼び出すことができます。 + +### パラメータ抽出ノードの呼び出し + +#### **エントリーポイント** + +```python + self.session.workflow_node.parameter_extractor +``` + +#### **インターフェース** + +```python + def invoke( + self, + parameters: list[ParameterConfig], + model: ModelConfig, + query: str, + instruction: str = "", + ) -> NodeResponse + pass +``` + +ここで、`parameters`は抽出するパラメータのリスト、`model`は`LLMModelConfig`仕様に準拠、`query`はパラメータ抽出のソーステキスト、`instruction`はLLMに必要な追加の指示を提供します。`NodeResponse`の構造については、この[ドキュメント](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx#noderesponse)を参照してください。 + +#### **ユースケース** + +会話から人の名前を抽出するには、以下のコードを参照できます: + +```python +from collections.abc import Generator +from dify_plugin.entities.tool import ToolInvokeMessage +from dify_plugin import Tool +from dify_plugin.entities.workflow_node import ModelConfig, ParameterConfig, NodeResponse # Assuming NodeResponse is importable + +class ParameterExtractorTool(Tool): + def _invoke( + self, tool_parameters: dict + ) -> Generator[ToolInvokeMessage, None, None]: + response: NodeResponse = self.session.workflow_node.parameter_extractor.invoke( + parameters=[ + ParameterConfig( + name="name", + description="name of the person", + required=True, + type="string", + ) + ], + model=ModelConfig( + provider="langgenius/openai/openai", + name="gpt-4o-mini", + completion_params={}, + ), + query="My name is John Doe", + instruction="Extract the name of the person", + ) + + # Assuming NodeResponse has an 'outputs' attribute which is a dictionary + extracted_name = response.outputs.get("name", "Name not found") + yield self.create_text_message(extracted_name) +``` + +### 質問分類ノードの呼び出し + +#### **エントリーポイント** + +```python + self.session.workflow_node.question_classifier +``` + +#### **インターフェース** + +```python + def invoke( + self, + classes: list[ClassConfig], # Assuming ClassConfig is defined/imported + model: ModelConfig, + query: str, + instruction: str = "", + ) -> NodeResponse: + pass +``` + +インターフェースのパラメータは`ParameterExtractor`と一致しています。最終結果は`NodeResponse.outputs['class_name']`に格納されます。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx new file mode 100644 index 00000000..27b62207 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx @@ -0,0 +1,104 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: intermediate +standard_title: Reverse Invocation Tool +language: en +title: ツール +description: このドキュメントでは、プラグインがDifyプラットフォーム内でツールサービスを逆呼び出しする方法について詳しく説明します。インストール済みツールの呼び出し(Built-in Tool)、Workflowをツールとして呼び出し、カスタムツールの呼び出し(Custom Tool)の3種類のツール呼び出し方法について説明します。各方法には、対応するエントリーポイントとインターフェースパラメータの説明が含まれています。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool)を参照してください。 + +ツールの逆呼び出しとは、プラグインがDifyプラットフォーム内の他のツールタイププラグインを呼び出すことを意味します。逆呼び出しの基本概念に馴染みがない場合は、まず[Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation)をお読みください。 + +以下のシナリオを考えてみてください: + +* ツールタイププラグインが機能を実装したが、結果が期待通りではなく、データの後処理が必要な場合。 +* タスクにウェブスクレイパーが必要で、スクレイピングサービスを柔軟に選択したい場合。 +* 複数のツールの結果を集約する必要があるが、ワークフローアプリケーションでの処理が難しい場合。 + +これらの場合、プラグイン内で他の既存のツールを呼び出す必要があります。これらのツールは、マーケットプレイスから、自作のWorkflow as Tool、またはカスタムツールである可能性があります。 + +これらの要件は、プラグインの`self.session.tool`フィールドを呼び出すことで満たすことができます。 + +### インストール済みツールの呼び出し + +プラグインが現在のワークスペースにインストールされているさまざまなツール(他のツールタイププラグインを含む)を呼び出すことができます。 + +**エントリーポイント** + +```python + self.session.tool +``` + +**インターフェース** + +```python + def invoke_builtin_tool( + self, provider: str, tool_name: str, parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + pass +``` + +ここで、`provider`はプラグインIDとツールプロバイダー名を組み合わせたもので、`langgenius/google/google`のような形式です。`tool_name`は具体的なツール名で、`parameters`はツールに渡す引数です。 + +### Workflow as Toolの呼び出し + +Workflow as Toolの詳細については、[ツールプラグインドキュメント](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)を参照してください。 + +**エントリーポイント** + +```python + self.session.tool +``` + +**インターフェース** + +```python + def invoke_workflow_tool( + self, provider: str, tool_name: str, parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + pass +``` + +この場合、`provider`はこのツールのIDで、`tool_name`はツールの作成時に指定されます。 + +### カスタムツールの呼び出し + +**エントリーポイント** + +```python + self.session.tool +``` + +**インターフェース** + +```python + def invoke_api_tool( + self, provider: str, tool_name: str, parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + pass +``` + +ここで、`provider`はこのツールのIDで、`tool_name`はOpenAPI仕様の`operation_id`です。存在しない場合は、Difyによって自動生成された`tool_name`であり、ツール管理ページで確認できます。 + +## 関連リソース + +- [Difyサービスの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 逆呼び出しの基本概念を理解する +- [アプリの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - プラットフォーム内でアプリを呼び出す方法を学ぶ +- [モデルの逆呼び出し](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) - プラットフォーム内でモデル機能を呼び出す方法を学ぶ +- [ツールプラグイン開発ガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - ツールプラグインの開発方法を学ぶ +- [高度なツールプラグイン](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - Workflow as Toolなどの高度な機能について学ぶ + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx new file mode 100644 index 00000000..5f6b0b00 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx @@ -0,0 +1,47 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: beginner +standard_title: Reverse Invocation +language: ja +title: Difyサービスの逆呼び出し +description: このドキュメントでは、Difyプラグインの逆呼び出し機能について簡単に紹介します。これは、プラグインがDifyメインプラットフォーム内の指定されたサービスを呼び出せることを意味します。呼び出し可能な4種類のモジュールを紹介します:App(アプリデータへのアクセス)、Model(プラットフォーム内のモデル機能の呼び出し)、Tool(プラットフォーム内の他のツールプラグインの呼び出し)、Node(Chatflow/ワークフローアプリケーション内のノードの呼び出し)。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation)を参照してください。 + +プラグインは、機能を強化するためにDifyメインプラットフォーム内のいくつかのサービスを自由に呼び出すことができます。 + +### 呼び出し可能なDifyモジュール + +* [App](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) + + プラグインはDifyプラットフォーム内のアプリからデータにアクセスできます。 +* [Model](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) + + プラグインはDifyプラットフォーム内のLLM機能を逆呼び出しできます。これには、TTS、Rerankなど、プラットフォーム内のすべてのモデルタイプと機能が含まれます。 +* [Tool](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) + + プラグインはDifyプラットフォーム内の他のツールタイププラグインを呼び出すことができます。 +* [Node](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node) + + プラグインはDifyプラットフォーム内の特定のChatflow/ワークフローアプリケーション内のノードを呼び出すことができます。 + +## 関連リソース + +- [拡張プラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 外部システムと統合するプラグインの開発方法を学ぶ +- [Slack Botプラグインの開発](/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 逆呼び出しを使用してSlackプラットフォームと統合する例 +- [バンドルタイププラグイン](/ja/develop-plugin/features-and-specs/advanced-development/bundle) - 逆呼び出しを使用する複数のプラグインをパッケージ化する方法を学ぶ +- [永続ストレージの使用](/ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) - KVストレージを通じてプラグイン機能を強化する + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx b/ja/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx new file mode 100644 index 00000000..30d0e58c --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx @@ -0,0 +1,279 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: General Specs +language: ja +title: 一般仕様 +description: この記事では、プラグイン開発における一般的な構造について簡単に紹介します。開発中は、全体的なアーキテクチャをより深く理解するために、[プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin)と[開発者チートシート](/ja/develop-plugin/getting-started/cli)を併せて読むことを強くお勧めします。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/general-specifications)を参照してください。 + +### パス仕様 + +Manifestまたは任意のyamlファイルでファイルパスを記入する際は、ファイルの種類に応じて以下の2つの仕様に従ってください: + +* 対象ファイルが画像や動画などのマルチメディアファイルの場合、例えばプラグインの`icon`を記入する際は、これらのファイルをプラグインのルートディレクトリ下の`_assets`フォルダに配置する必要があります。 +* 対象ファイルが`.py`や`.yaml`コードファイルなどの通常のテキストファイルの場合、プラグインプロジェクト内でのファイルの絶対パスを記入する必要があります。 + +### 共通構造 + +プラグインを定義する際、ツール、モデル、Endpoints間で共有できるデータ構造がいくつかあります。これらの共有構造をここで定義します。 + +#### I18nObject + +`I18nObject`は[IETF BCP 47](https://tools.ietf.org/html/bcp47)標準に準拠した国際化構造です。現在、4つの言語がサポートされています: + + + 英語(米国) + + + + 簡体字中国語 + + + + 日本語 + + + + ポルトガル語(ブラジル) + + +#### ProviderConfig + +`ProviderConfig`は共通のプロバイダーフォーム構造で、`Tool`と`Endpoint`の両方に適用されます + + + フォーム項目名 + + + + [IETF BCP 47](https://tools.ietf.org/html/bcp47)標準に準拠した表示ラベル + + + + フォームフィールドタイプ - UIでフィールドがどのようにレンダリングされるかを決定します + + + + オプションの範囲指定、`type`の値に基づいて異なります + + + + フィールドが空であってはならないかどうか + + + + デフォルト値、基本型のみサポート:`float`、`int`、`string` + + + + 利用可能なオプション、typeが`select`の場合のみ使用 + + + + ヘルプドキュメントリンクラベル、[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 + + + + ヘルプドキュメントリンク + + + + 複数言語でのプレースホルダーテキスト、[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 + + +#### ProviderConfigOption(object) + + + オプションの値 + + + + オプションの表示ラベル、[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 + + +#### ProviderConfigType(string) + + + 暗号化される設定情報 + + + + プレーンテキスト入力フィールド + + + + ドロップダウン選択フィールド + + + + スイッチ/トグルコントロール + + + + モデル設定セレクター、プロバイダー名、モデル名、モデルパラメータなどを含む + + + + アプリケーションIDセレクター + + + + ツール設定セレクター、ツールプロバイダー、名前、パラメータなどを含む + + + + データセットセレクター(TBD) + + +#### ProviderConfigScope(string) + +`type`が`model-selector`の場合: + + すべてのモデルタイプ + + + 大規模言語モデルのみ + + + テキスト埋め込みモデルのみ + + + リランキングモデルのみ + + + テキスト読み上げモデルのみ + + + 音声テキスト変換モデルのみ + + + コンテンツモデレーションモデルのみ + + + ビジョンモデルのみ + + +`type`が`app-selector`の場合: + + すべてのアプリケーションタイプ + + + チャットアプリケーションのみ + + + ワークフローアプリケーションのみ + + + 補完アプリケーションのみ + + +`type`が`tool-selector`の場合: + + すべてのツールタイプ + + + プラグインツールのみ + + + APIツールのみ + + + ワークフローツールのみ + + +#### ModelConfig + + + plugin_idを含むモデルプロバイダー名、`langgenius/openai/openai`の形式 + + + + 特定のモデル名 + + + + モデルタイプの列挙、[モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules#modeltype)ドキュメントを参照 + + +#### NodeResponse + + + 最終的にノードに入力される変数 + + + + ノードの出力結果 + + + + ノード実行中に生成されるデータ + + +#### ToolSelector + + + ツールプロバイダー名 + + + + ツール名 + + + + ツールの説明 + + + + ツール設定情報 + + + + LLM推論が必要なパラメータ + + + パラメータ名 + + + + パラメータタイプ + + + + パラメータが必須かどうか + + + + パラメータの説明 + + + + デフォルト値 + + + + パラメータで利用可能なオプション + + + +## 関連リソース + +- [プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin) - Difyプラグイン開発の包括的な理解 +- [開発者チートシート](/ja/develop-plugin/getting-started/cli) - プラグイン開発における一般的なコマンドと概念のクイックリファレンス +- [ツールプラグイン開発の詳細](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - プラグイン情報の定義方法とツールプラグイン開発プロセスの理解 +- [モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - モデル設定の標準の理解 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/ja/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx b/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx new file mode 100644 index 00000000..46de4d90 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx @@ -0,0 +1,573 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Model Specs +language: ja +title: モデル仕様 +description: このドキュメントでは、Difyモデルプラグイン開発のコア概念と構造について詳細に定義しています。モデルプロバイダー(Provider)、AIモデルエンティティ(AIModelEntity)、モデルタイプ(ModelType)、設定方法(ConfigurateMethod)、モデル機能(ModelFeature)、パラメータルール(ParameterRule)、価格設定(PriceConfig)、および各種認証情報モードの詳細なデータ構造仕様が含まれます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules)を参照してください。 + +* モデルプロバイダールールは [Provider](#provider) エンティティに基づいています。 +* モデルルールは [AIModelEntity](#aimodelentity) エンティティに基づいています。 + +> 以下のすべてのエンティティは `Pydantic BaseModel` に基づいており、`entities` モジュールで確認できます。 + +### Provider + + + プロバイダー識別子、例:`openai` + + + + プロバイダー表示名、i18n、`en_US`(英語)と `zh_Hans`(中国語)の両方の言語を設定可能 + + + 中国語ラベル、設定されていない場合はデフォルトで `en_US` を使用 + + + + 英語ラベル + + + + + プロバイダーの説明、i18n + + + 中国語の説明 + + + + 英語の説明 + + + + + プロバイダーの小アイコン、対応するプロバイダー実装ディレクトリ下の `_assets` ディレクトリに保存 + + + 中国語アイコン + + + + 英語アイコン + + + + + プロバイダーの大アイコン、対応するプロバイダー実装ディレクトリ下の `_assets` ディレクトリに保存 + + + 中国語アイコン + + + + 英語アイコン + + + + + 背景色の値、例:#FFFFFF、空の場合はフロントエンドのデフォルト色値が表示されます + + + + ヘルプ情報 + + + ヘルプタイトル、i18n + + + 中国語タイトル + + + + 英語タイトル + + + + + ヘルプリンク、i18n + + + 中国語リンク + + + + 英語リンク + + + + + + サポートされるモデルタイプ + + + + 設定方法 + + + + プロバイダー認証情報仕様 + + + + モデル認証情報仕様 + + +### AIModelEntity + + + モデル識別子、例:`gpt-3.5-turbo` + + + + モデル表示名、i18n、`en_US`(英語)と `zh_Hans`(中国語)の両方の言語を設定可能 + + + 中国語ラベル + + + + 英語ラベル + + + + + モデルタイプ + + + + サポートされる機能のリスト + + + + モデルプロパティ + + + モード(モデルタイプ `llm` で利用可能) + + + + コンテキストサイズ(モデルタイプ `llm` および `text-embedding` で利用可能) + + + + 最大チャンク数(モデルタイプ `text-embedding` および `moderation` で利用可能) + + + + 最大ファイルアップロード制限、単位:MB(モデルタイプ `speech2text` で利用可能) + + + + サポートされるファイル拡張子形式、例:mp3,mp4(モデルタイプ `speech2text` で利用可能) + + + + デフォルト音声、必須:alloy,echo,fable,onyx,nova,shimmer(モデルタイプ `tts` で利用可能) + + + + 利用可能な音声のリスト(モデルタイプ `tts` で利用可能) + + + 音声モデル + + + + 音声モデルの表示名 + + + + 音声モデルでサポートされる言語 + + + + + 単一変換の単語制限、デフォルトは段落分割(モデルタイプ `tts` で利用可能) + + + + サポートされるオーディオファイル拡張子形式、例:mp3,wav(モデルタイプ `tts` で利用可能) + + + + テキストからオーディオへの変換でサポートされる同時タスク数(モデルタイプ `tts` で利用可能) + + + + チャンクあたりの最大文字数(モデルタイプ `moderation` で利用可能) + + + + + モデル呼び出しパラメータルール + + + + 価格情報 + + + + 非推奨かどうか。非推奨の場合、モデルリストには表示されなくなりますが、すでに設定されているものは引き続き使用できます。デフォルトはFalseです。 + + +### ModelType + + + テキスト生成モデル + + + + テキスト埋め込みモデル + + + + リランクモデル + + + + 音声からテキスト + + + + テキストから音声 + + + + コンテンツモデレーション + + +### ConfigurateMethod + + + 事前定義モデル - ユーザーは統一されたプロバイダー認証情報を設定するだけで、プロバイダー下の事前定義モデルを使用できることを示します。 + + + + カスタマイズ可能モデル - ユーザーは各モデルの認証情報設定を追加する必要があります。 + + + + リモートから取得 - `predefined-model` 設定方法と同様に、統一されたプロバイダー認証情報のみが必要ですが、モデルは認証情報を使用してプロバイダーから取得されます。 + + +### ModelFeature + + + エージェント推論、一般的に70B以上のモデルには思考連鎖機能があります。 + + + + ビジョン、すなわち:画像理解。 + + + + ツール呼び出し + + + + 複数ツール呼び出し + + + + ストリーミングツール呼び出し + + +### FetchFrom + + + 事前定義モデル + + + + リモートモデル + + +### LLMMode + + + テキスト補完 + + + + チャット + + +### ParameterRule + + + モデル呼び出しの実際のパラメータ名 + + + + テンプレートを使用 + + +> テンプレートの使用方法の詳細については、[新しいモデルプロバイダーの作成](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider)の例を参照してください。 + +デフォルトで5つの事前設定された変数コンテンツテンプレートがあります: + +* `temperature` +* `top_p` +* `frequency_penalty` +* `presence_penalty` +* `max_tokens` + +`use_template` にテンプレート変数名を直接設定でき、entities.defaults.PARAMETER\_RULE\_TEMPLATE のデフォルト設定を使用します。`name` と `use_template` 以外のパラメータを設定する必要はありません。追加の設定パラメータが設定されている場合、デフォルト設定を上書きします。例については `openai/llm/gpt-3.5-turbo.yaml` を参照できます。 + + + ラベル、i18n + + + 中国語ラベル + + + + 英語ラベル + + + + + パラメータタイプ + + + 整数 + + + + 浮動小数点 + + + + 文字列 + + + + ブール値 + + + + + ヘルプ情報 + + + 中国語ヘルプ情報 + + + + 英語ヘルプ情報 + + + + + 必須かどうか、デフォルトはFalse + + + + デフォルト値 + + + + 最小値、数値タイプのみに適用 + + + + 最大値、数値タイプのみに適用 + + + + 精度、保持する小数桁数、数値タイプのみに適用 + + + + ドロップダウンオプション値、`type` が `string` の場合のみ適用、設定されていないか null の場合、オプション値は制限されません + + +### PriceConfig + + + 入力単価、すなわちプロンプト単価 + + + + 出力単価、すなわち返されるコンテンツの単価 + + + + 価格単位、例えば1Mトークンあたりの価格の場合、単価に対応する単位トークン数は `0.000001` です + + + + 通貨単位 + + +### ProviderCredentialSchema + + + 認証情報フォーム仕様 + + +### ModelCredentialSchema + + + モデル識別子、デフォルト変数名は `model` + + + モデルフォーム項目の表示名 + + + 英語 + + + + 中国語 + + + + + モデルプロンプトコンテンツ + + + 英語 + + + + 中国語 + + + + + + 認証情報フォーム仕様 + + +### CredentialFormSchema + + + フォーム項目変数名 + + + + フォーム項目ラベル + + + 英語 + + + + 中国語 + + + + + フォーム項目タイプ + + + + 必須かどうか + + + + デフォルト値 + + + + `select` または `radio` に固有のフォーム項目属性、ドロップダウンコンテンツを定義 + + + + `text-input` に固有のフォーム項目属性、フォーム項目プレースホルダー + + + 英語 + + + + 中国語 + + + + + `text-input` に固有のフォーム項目属性、最大入力長を定義、0は制限なしを意味 + + + + 他のフォーム項目の値が条件を満たすときに表示、空の場合は常に表示 + + +#### FormType + + + テキスト入力コンポーネント + + + + パスワード入力コンポーネント + + + + 単一選択ドロップダウン + + + + ラジオコンポーネント + + + + スイッチコンポーネント、`true` と `false` のみサポート + + +#### FormOption + + + ラベル + + + 英語 + + + + 中国語 + + + + + ドロップダウンオプション値 + + + + 他のフォーム項目の値が条件を満たすときに表示、空の場合は常に表示 + + +#### FormShowOnObject + + + 他のフォーム項目変数名 + + + + 他のフォーム項目変数値 + + +## 関連リソース + +- [モデルアーキテクチャの詳細](/ja/develop-plugin/features-and-specs/plugin-types/model-schema) - モデルプラグインのアーキテクチャ仕様の詳細 +- [新しいモデルをすばやく統合する](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - これらのルールを適用して新しいモデルを追加する方法を学ぶ +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - プラグインマニフェストファイルの設定を理解する +- [新しいモデルプロバイダーを作成する](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - まったく新しいモデルプロバイダープラグインを開発する + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/model-schema.mdx b/ja/develop-plugin/features-and-specs/plugin-types/model-schema.mdx new file mode 100644 index 00000000..4a41f6d1 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/model-schema.mdx @@ -0,0 +1,1263 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: intermediate +standard_title: Model Schema +language: ja +title: モデルAPIインターフェース +description: LLM、TextEmbedding、Rerank、Speech2text、Text2speechモデルの実装要件を含むDifyモデルプラグインAPIの包括的なガイド。すべての関連データ構造の詳細な仕様を含みます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/model-schema)を参照してください。 + +## はじめに + +このドキュメントでは、Difyモデルプラグインを実装するために必要なインターフェースとデータ構造について詳しく説明します。AIモデルをDifyプラットフォームと統合する開発者向けの技術リファレンスとして機能します。 + + +このAPIリファレンスに入る前に、概念的な理解のために[モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules)と[モデルプラグイン入門](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules)を先に読むことをお勧めします。 + + + + + 異なるAIサービスプロバイダー向けのモデルプロバイダークラスの実装方法を学ぶ + + + 5つのサポートされているモデルタイプの実装詳細:LLM、Embedding、Rerank、Speech2Text、Text2Speech + + + モデルAPIで使用されるすべてのデータ構造の包括的なリファレンス + + + 適切なエラーマッピングと例外処理のガイドライン + + + +## モデルプロバイダー + +すべてのモデルプロバイダーは`__base.model_provider.ModelProvider`基底クラスを継承し、認証情報検証インターフェースを実装する必要があります。 + +### プロバイダー認証情報検証 + + +```python Core Implementation +def validate_provider_credentials(self, credentials: dict) -> None: + """ + Validate provider credentials by making a test API call + + Parameters: + credentials: Provider credentials as defined in `provider_credential_schema` + + Raises: + CredentialsValidateFailedError: If validation fails + """ + try: + # Example implementation - validate using an LLM model instance + model_instance = self.get_model_instance(ModelType.LLM) + model_instance.validate_credentials( + model="example-model", + credentials=credentials + ) + except Exception as ex: + logger.exception(f"Credential validation failed") + raise CredentialsValidateFailedError(f"Invalid credentials: {str(ex)}") +``` + +```python Custom Model Provider +class XinferenceProvider(Provider): + def validate_provider_credentials(self, credentials: dict) -> None: + """ + For custom-only model providers, a simple implementation is sufficient + as validation happens at the model level + """ + pass +``` + + + + プロバイダーのYAML設定の`provider_credential_schema`で定義された認証情報。 + 通常、`api_key`、`organization_id`などのフィールドを含みます。 + + + +検証が失敗した場合、実装は`CredentialsValidateFailedError`例外をスローする必要があります。これにより、Dify UIで適切なエラーハンドリングが保証されます。 + + + +事前定義されたモデルプロバイダーの場合、認証情報がAPIで機能することを検証する徹底的な検証メソッドを実装する必要があります。カスタムモデルプロバイダー(各モデルが独自の認証情報を持つ場合)では、簡略化された実装で十分です。 + + +## モデル + +Difyは5つの異なるモデルタイプをサポートしており、それぞれ特定のインターフェースの実装が必要です。ただし、すべてのモデルタイプにはいくつかの共通要件があります。 + +### 共通インターフェース + +タイプに関係なく、すべてのモデル実装はこれら2つの基本メソッドを実装する必要があります: + +#### 1. モデル認証情報検証 + + +```python Implementation +def validate_credentials(self, model: str, credentials: dict) -> None: + """ + Validate that the provided credentials work with the specified model + + Parameters: + model: The specific model identifier (e.g., "gpt-4") + credentials: Authentication details for the model + + Raises: + CredentialsValidateFailedError: If validation fails + """ + try: + # Make a lightweight API call to verify credentials + # Example: List available models or check account status + response = self._api_client.validate_api_key(credentials["api_key"]) + + # Verify the specific model is available if applicable + if model not in response.get("available_models", []): + raise CredentialsValidateFailedError(f"Model {model} is not available") + + except ApiException as e: + raise CredentialsValidateFailedError(str(e)) +``` + + + + 検証する特定のモデル識別子(例:「gpt-4」、「claude-3-opus」) + + + + プロバイダーの設定で定義された認証情報 + + +#### 2. エラーマッピング + + +```python Implementation +@property +def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + Map provider-specific exceptions to standardized Dify error types + + Returns: + Dictionary mapping Dify error types to lists of provider exception types + """ + return { + InvokeConnectionError: [ + requests.exceptions.ConnectionError, + requests.exceptions.Timeout, + ConnectionRefusedError + ], + InvokeServerUnavailableError: [ + ServiceUnavailableError, + HTTPStatusError + ], + InvokeRateLimitError: [ + RateLimitExceededError, + QuotaExceededError + ], + InvokeAuthorizationError: [ + AuthenticationError, + InvalidAPIKeyError, + PermissionDeniedError + ], + InvokeBadRequestError: [ + InvalidRequestError, + ValidationError + ] + } +``` + + + + + ネットワーク接続の失敗、タイムアウト + + + サービスプロバイダーがダウンまたは利用不可 + + + レート制限またはクォータ制限に到達 + + + 認証または権限の問題 + + + 無効なパラメータまたはリクエスト + + + + +エラーマッピングに依存する代わりに、コード内でこれらの標準化されたエラータイプを直接スローすることもできます。このアプローチにより、エラーメッセージをより細かく制御できます。 + + +### LLM実装 + +大規模言語モデルプロバイダーを実装するには、`__base.large_language_model.LargeLanguageModel`基底クラスを継承し、これらのメソッドを実装します: + +#### 1. モデル呼び出し + +このコアメソッドは、言語モデルへのストリーミングおよび非ストリーミングAPI呼び出しの両方を処理します。 + + +```python Core Implementation +def _invoke( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + model_parameters: dict, + tools: Optional[list[PromptMessageTool]] = None, + stop: Optional[list[str]] = None, + stream: bool = True, + user: Optional[str] = None +) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]: + """ + Invoke the language model + """ + # Prepare API parameters + api_params = self._prepare_api_parameters( + model, + credentials, + prompt_messages, + model_parameters, + tools, + stop + ) + + try: + # Choose between streaming and non-streaming implementation + if stream: + return self._invoke_stream(model, api_params, user) + else: + return self._invoke_sync(model, api_params, user) + + except Exception as e: + # Map errors using the error mapping property + self._handle_api_error(e) + +# Helper methods for streaming and non-streaming calls +def _invoke_stream(self, model, api_params, user): + # Implement streaming call and yield chunks + pass + +def _invoke_sync(self, model, api_params, user): + # Implement synchronous call and return complete result + pass +``` + + + + + モデル識別子(例:「gpt-4」、「claude-3」) + + + + API用の認証情報 + + + + Difyの標準化されたフォーマットのメッセージリスト: + - `completion`モデルの場合:単一の`UserPromptMessage`を含める + - `chat`モデルの場合:必要に応じて`SystemPromptMessage`、`UserPromptMessage`、`AssistantPromptMessage`、`ToolPromptMessage`を含める + + + + モデルのYAML設定で定義されたモデル固有のパラメータ(temperature、top_pなど) + + + + 関数呼び出し機能のためのツール定義 + + + + 遭遇時にモデル生成を停止するストップシーケンス + + + + ストリーミングレスポンスを返すかどうか + + + + API監視用のユーザー識別子 + + + + + + 利用可能になったレスポンスのチャンクをyieldするジェネレータ + + + + 完全な生成テキストを含む完全なレスポンスオブジェクト + + + + +コードを整理して保守しやすくするために、ストリーミングと非ストリーミング呼び出し用に別々のヘルパーメソッドを実装することをお勧めします。 + + +#### 2. トークンカウント + + +```python Implementation +def get_num_tokens( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + tools: Optional[list[PromptMessageTool]] = None +) -> int: + """ + Calculate the number of tokens in the prompt + """ + # Convert prompt_messages to the format expected by the tokenizer + text = self._convert_messages_to_text(prompt_messages) + + try: + # Use the appropriate tokenizer for this model + tokenizer = self._get_tokenizer(model) + return len(tokenizer.encode(text)) + except Exception: + # Fall back to a generic tokenizer + return self._get_num_tokens_by_gpt2(text) +``` + + + +モデルがトークナイザーを提供していない場合、基底クラスの`_get_num_tokens_by_gpt2(text)`メソッドを使用して妥当な近似値を得ることができます。 + + +#### 3. カスタムモデルスキーマ(オプション) + + +```python Implementation +def get_customizable_model_schema( + self, + model: str, + credentials: dict +) -> Optional[AIModelEntity]: + """ + Get parameter schema for custom models + """ + # For fine-tuned models, you might return the base model's schema + if model.startswith("ft:"): + base_model = self._extract_base_model(model) + return self._get_predefined_model_schema(base_model) + + # For standard models, return None to use the predefined schema + return None +``` + + + +このメソッドは、カスタムモデルをサポートするプロバイダーにのみ必要です。カスタムモデルが基本モデルからパラメータルールを継承できるようにします。 + + +### TextEmbedding実装 + + +テキスト埋め込みモデルは、テキストを意味的な意味を捉える高次元ベクトルに変換し、検索、類似性検索、分類に役立ちます。 + + +Text Embeddingプロバイダーを実装するには、`__base.text_embedding_model.TextEmbeddingModel`基底クラスを継承します: + +#### 1. コア埋め込みメソッド + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + texts: list[str], + user: Optional[str] = None +) -> TextEmbeddingResult: + """ + Generate embedding vectors for multiple texts + """ + # Set up API client with credentials + client = self._get_client(credentials) + + # Handle batching if needed + batch_size = self._get_batch_size(model) + all_embeddings = [] + total_tokens = 0 + start_time = time.time() + + # Process in batches to avoid API limits + for i in range(0, len(texts), batch_size): + batch = texts[i:i+batch_size] + + # Make API call to the embeddings endpoint + response = client.embeddings.create( + model=model, + input=batch, + user=user + ) + + # Extract embeddings from response + batch_embeddings = [item.embedding for item in response.data] + all_embeddings.extend(batch_embeddings) + + # Track token usage + total_tokens += response.usage.total_tokens + + # Calculate usage metrics + elapsed_time = time.time() - start_time + usage = self._create_embedding_usage( + model=model, + tokens=total_tokens, + latency=elapsed_time + ) + + return TextEmbeddingResult( + model=model, + embeddings=all_embeddings, + usage=usage + ) +``` + + + + + 埋め込みモデル識別子 + + + + 埋め込みサービス用の認証情報 + + + + 埋め込むテキスト入力のリスト + + + + API監視用のユーザー識別子 + + + + + + 以下を含む構造化されたレスポンス: + - model:埋め込みに使用されたモデル + - embeddings:入力テキストに対応する埋め込みベクトルのリスト + - usage:トークン使用量とコストに関するメタデータ + + + +#### 2. トークンカウントメソッド + + +```python Implementation +def get_num_tokens( + self, + model: str, + credentials: dict, + texts: list[str] +) -> int: + """ + Calculate the number of tokens in the texts to be embedded + """ + # Join all texts to estimate token count + combined_text = " ".join(texts) + + try: + # Use the appropriate tokenizer for this model + tokenizer = self._get_tokenizer(model) + return len(tokenizer.encode(combined_text)) + except Exception: + # Fall back to a generic tokenizer + return self._get_num_tokens_by_gpt2(combined_text) +``` + + + +埋め込みモデルでは、正確なトークンカウントはコスト見積もりに重要ですが、機能性には重要ではありません。`_get_num_tokens_by_gpt2`メソッドはほとんどのモデルに対して妥当な近似値を提供します。 + + +### Rerank実装 + + +リランキングモデルは、通常初期検索フェーズの後、クエリとの関連性に基づいて候補ドキュメントのセットを再順序付けすることで検索品質を向上させます。 + + +Rerankingプロバイダーを実装するには、`__base.rerank_model.RerankModel`基底クラスを継承します: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + query: str, + docs: list[str], + score_threshold: Optional[float] = None, + top_n: Optional[int] = None, + user: Optional[str] = None +) -> RerankResult: + """ + Rerank documents based on relevance to the query + """ + # Set up API client with credentials + client = self._get_client(credentials) + + # Prepare request data + request_data = { + "query": query, + "documents": docs, + } + + # Call reranking API endpoint + response = client.rerank( + model=model, + **request_data, + user=user + ) + + # Process results + ranked_results = [] + for i, result in enumerate(response.results): + # Create RerankDocument for each result + doc = RerankDocument( + index=result.document_index, # Original index in docs list + text=docs[result.document_index], # Original text + score=result.relevance_score # Relevance score + ) + ranked_results.append(doc) + + # Sort by score in descending order + ranked_results.sort(key=lambda x: x.score, reverse=True) + + # Apply score threshold filtering if specified + if score_threshold is not None: + ranked_results = [doc for doc in ranked_results if doc.score >= score_threshold] + + # Apply top_n limit if specified + if top_n is not None and top_n > 0: + ranked_results = ranked_results[:top_n] + + return RerankResult( + model=model, + docs=ranked_results + ) +``` + + + + + リランキングモデル識別子 + + + + API用の認証情報 + + + + 検索クエリテキスト + + + + リランキングされるドキュメントテキストのリスト + + + + 結果をフィルタリングするためのオプションの最小スコア閾値 + + + + 返す結果数のオプションの制限 + + + + API監視用のユーザー識別子 + + + + + + 以下を含む構造化されたレスポンス: + - model:リランキングに使用されたモデル + - docs:index、text、scoreを持つRerankDocumentオブジェクトのリスト + + + + +リランキングは計算コストが高くなる可能性があり、特に大きなドキュメントセットでは顕著です。タイムアウトや過度のリソース消費を避けるために、大きなドキュメントコレクションにはバッチ処理を実装してください。 + + +### Speech2Text実装 + + +音声テキスト変換モデルは、音声ファイルから話された言語を書かれたテキストに変換し、文字起こしサービス、音声コマンド、アクセシビリティ機能などのアプリケーションを可能にします。 + + +Speech-to-Textプロバイダーを実装するには、`__base.speech2text_model.Speech2TextModel`基底クラスを継承します: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + file: IO[bytes], + user: Optional[str] = None +) -> str: + """ + Convert speech audio to text + """ + # Set up API client with credentials + client = self._get_client(credentials) + + try: + # Determine the file format + file_format = self._detect_audio_format(file) + + # Prepare the file for API submission + # Most APIs require either a file path or binary data + audio_data = file.read() + + # Call the speech-to-text API + response = client.audio.transcriptions.create( + model=model, + file=("audio.mp3", audio_data), # Adjust filename based on actual format + user=user + ) + + # Extract and return the transcribed text + return response.text + + except Exception as e: + # Map to appropriate error type + self._handle_api_error(e) + + finally: + # Reset file pointer for potential reuse + file.seek(0) +``` + +```python Helper Methods +def _detect_audio_format(self, file: IO[bytes]) -> str: + """ + Detect the audio format based on file header + """ + # Read the first few bytes to check the file signature + header = file.read(12) + file.seek(0) # Reset file pointer + + # Check for common audio format signatures + if header.startswith(b'RIFF') and header[8:12] == b'WAVE': + return 'wav' + elif header.startswith(b'ID3') or header.startswith(b'\xFF\xFB'): + return 'mp3' + elif header.startswith(b'OggS'): + return 'ogg' + elif header.startswith(b'fLaC'): + return 'flac' + else: + # Default or additional format checks + return 'mp3' # Default assumption +``` + + + + + 音声テキスト変換モデル識別子 + + + + API用の認証情報 + + + + 文字起こしする音声を含むバイナリファイルオブジェクト + + + + API監視用のユーザー識別子 + + + + + + 音声ファイルから文字起こしされたテキスト + + + + +異なるファイルタイプを適切に処理するためには、音声フォーマットの検出が重要です。例に示すように、ファイルヘッダーからフォーマットを検出するヘルパーメソッドの実装を検討してください。 + + + +一部の音声テキスト変換APIにはファイルサイズの制限があります。必要に応じて、大きな音声ファイル用にチャンク処理を実装することを検討してください。 + + +### Text2Speech実装 + + +テキスト音声変換モデルは、書かれたテキストを自然な音声に変換し、音声アシスタント、スクリーンリーダー、音声コンテンツ生成などのアプリケーションを可能にします。 + + +Text-to-Speechプロバイダーを実装するには、`__base.text2speech_model.Text2SpeechModel`基底クラスを継承します: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + content_text: str, + streaming: bool, + user: Optional[str] = None +) -> Union[bytes, Generator[bytes, None, None]]: + """ + Convert text to speech audio + """ + # Set up API client with credentials + client = self._get_client(credentials) + + # Get voice settings based on model + voice = self._get_voice_for_model(model) + + try: + # Choose implementation based on streaming preference + if streaming: + return self._stream_audio( + client=client, + model=model, + text=content_text, + voice=voice, + user=user + ) + else: + return self._generate_complete_audio( + client=client, + model=model, + text=content_text, + voice=voice, + user=user + ) + except Exception as e: + self._handle_api_error(e) +``` + +```python Helper Methods +def _stream_audio(self, client, model, text, voice, user=None): + """ + Implementation for streaming audio output + """ + # Make API request with stream=True + response = client.audio.speech.create( + model=model, + voice=voice, + input=text, + stream=True, + user=user + ) + + # Yield chunks as they arrive + for chunk in response: + if chunk: + yield chunk + +def _generate_complete_audio(self, client, model, text, voice, user=None): + """ + Implementation for complete audio file generation + """ + # Make API request for complete audio + response = client.audio.speech.create( + model=model, + voice=voice, + input=text, + user=user + ) + + # Get audio data as bytes + audio_data = response.content + return audio_data +``` + + + + + テキスト音声変換モデル識別子 + + + + API用の認証情報 + + + + 音声に変換するテキストコンテンツ + + + + ストリーミング音声を返すか完全なファイルを返すか + + + + API監視用のユーザー識別子 + + + + + + 利用可能になった音声チャンクをyieldするジェネレータ + + + + バイトとしての完全な音声データ + + + + +ほとんどのテキスト音声変換APIでは、モデルと一緒に音声を指定する必要があります。Difyのモデル識別子とプロバイダーの音声オプション間のマッピングを実装することを検討してください。 + + + +長いテキスト入力は、より良い音声合成品質のためにチャンク処理が必要な場合があります。句読点、数字、特殊文字を適切に処理するためのテキスト前処理の実装を検討してください。 + + + +### Moderation実装 + + +モデレーションモデルは、潜在的に有害、不適切、または安全でないコンテンツについてコンテンツを分析し、プラットフォームの安全性とコンテンツポリシーの維持を支援します。 + + +Moderationプロバイダーを実装するには、`__base.moderation_model.ModerationModel`基底クラスを継承します: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + text: str, + user: Optional[str] = None +) -> bool: + """ + Analyze text for harmful content + + Returns: + bool: False if the text is safe, True if it contains harmful content + """ + # Set up API client with credentials + client = self._get_client(credentials) + + try: + # Call moderation API + response = client.moderations.create( + model=model, + input=text, + user=user + ) + + # Check if any categories were flagged + result = response.results[0] + + # Return True if flagged in any category, False if safe + return result.flagged + + except Exception as e: + # Log the error but default to safe if there's an API issue + # This is a conservative approach - production systems might want + # different fallback behavior + logger.error(f"Moderation API error: {str(e)}") + return False +``` + +```python Detailed Implementation +def _invoke( + self, + model: str, + credentials: dict, + text: str, + user: Optional[str] = None +) -> bool: + """ + Analyze text for harmful content with detailed category checking + """ + # Set up API client with credentials + client = self._get_client(credentials) + + try: + # Call moderation API + response = client.moderations.create( + model=model, + input=text, + user=user + ) + + # Get detailed category results + result = response.results[0] + categories = result.categories + + # Check specific categories based on your application's needs + # For example, you might want to flag certain categories but not others + critical_violations = [ + categories.harassment, + categories.hate, + categories.self_harm, + categories.sexual, + categories.violence + ] + + # Flag content if any critical category is violated + return any(critical_violations) + + except Exception as e: + self._handle_api_error(e) + # Default to safe in case of error + return False +``` + + + + + モデレーションモデル識別子 + + + + API用の認証情報 + + + + 分析するテキストコンテンツ + + + + API監視用のユーザー識別子 + + + + + + コンテンツの安全性を示すブール値: + - False:コンテンツは安全 + - True:コンテンツに有害な素材が含まれている + + + + +モデレーションは安全機構として使用されることが多いです。ソリューションを実装する際は、偽陰性(有害なコンテンツを通過させる)と偽陽性(安全なコンテンツをブロックする)の影響を考慮してください。 + + + +多くのモデレーションAPIは、単なるバイナリ結果ではなく、詳細なカテゴリスコアを提供します。アプリケーションで必要な場合は、有害なコンテンツの特定のカテゴリに関するより詳細な情報を返すようにこの実装を拡張することを検討してください。 + + +### エンティティ + +#### PromptMessageRole + +メッセージロール + +```python +class PromptMessageRole(Enum): + """ + Enum class for prompt message. + """ + SYSTEM = "system" + USER = "user" + ASSISTANT = "assistant" + TOOL = "tool" +``` + +#### PromptMessageContentType + +メッセージコンテンツタイプ、プレーンテキストと画像に分かれます。 + +```python +class PromptMessageContentType(Enum): + """ + Enum class for prompt message content type. + """ + TEXT = 'text' + IMAGE = 'image' +``` + +#### PromptMessageContent + +メッセージコンテンツ基底クラス、パラメータ宣言のみに使用され、初期化できません。 + +```python +class PromptMessageContent(BaseModel): + """ + Model class for prompt message content. + """ + type: PromptMessageContentType + data: str # Content data +``` + +現在、テキストと画像の2種類をサポートしており、テキストと複数の画像を同時にサポートできます。 +`TextPromptMessageContent`と`ImagePromptMessageContent`を別々に初期化する必要があります。 + +#### TextPromptMessageContent + +```python +class TextPromptMessageContent(PromptMessageContent): + """ + Model class for text prompt message content. + """ + type: PromptMessageContentType = PromptMessageContentType.TEXT +``` + +テキストと画像を渡す場合、テキストは`content`リストの一部としてこのエンティティとして構築する必要があります。 + +#### ImagePromptMessageContent + +```python +class ImagePromptMessageContent(PromptMessageContent): + """ + Model class for image prompt message content. + """ + class DETAIL(Enum): + LOW = 'low' + HIGH = 'high' + + type: PromptMessageContentType = PromptMessageContentType.IMAGE + detail: DETAIL = DETAIL.LOW # Resolution +``` + +テキストと画像を渡す場合、画像は`content`リストの一部としてこのエンティティとして構築する必要があります。 +`data`は`url`または画像の`base64`エンコードされた文字列にすることができます。 + +#### PromptMessage + +すべてのロールメッセージボディの基底クラス、パラメータ宣言のみに使用され、初期化できません。 + +```python +class PromptMessage(ABC, BaseModel): + """ + Model class for prompt message. + """ + role: PromptMessageRole # Message role + content: Optional[str | list[PromptMessageContent]] = None # Supports two types: string and content list. The content list is for multimodal needs, see PromptMessageContent for details. + name: Optional[str] = None # Name, optional. +``` + +#### UserPromptMessage + +UserMessageメッセージボディ、ユーザーメッセージを表します。 + +```python +class UserPromptMessage(PromptMessage): + """ + Model class for user prompt message. + """ + role: PromptMessageRole = PromptMessageRole.USER +``` + +#### AssistantPromptMessage + +モデル応答メッセージを表し、通常`few-shots`またはチャット履歴入力に使用されます。 + +```python +class AssistantPromptMessage(PromptMessage): + """ + Model class for assistant prompt message. + """ + class ToolCall(BaseModel): + """ + Model class for assistant prompt message tool call. + """ + class ToolCallFunction(BaseModel): + """ + Model class for assistant prompt message tool call function. + """ + name: str # Tool name + arguments: str # Tool parameters + + id: str # Tool ID, only effective for OpenAI tool call, a unique ID for tool invocation, the same tool can be called multiple times + type: str # Default is function + function: ToolCallFunction # Tool call information + + role: PromptMessageRole = PromptMessageRole.ASSISTANT + tool_calls: list[ToolCall] = [] # Model's tool call results (only returned when tools are passed in and the model decides to call them) +``` + +ここで`tool_calls`は、モデルに`tools`を渡した後にモデルが返す`tool call`のリストです。 + +#### SystemPromptMessage + +システムメッセージを表し、通常モデルのシステム指示を設定するために使用されます。 + +```python +class SystemPromptMessage(PromptMessage): + """ + Model class for system prompt message. + """ + role: PromptMessageRole = PromptMessageRole.SYSTEM +``` + +#### ToolPromptMessage + +ツールメッセージを表し、ツールが実行された後に次のステップの計画のために結果をモデルに渡すために使用されます。 + +```python +class ToolPromptMessage(PromptMessage): + """ + Model class for tool prompt message. + """ + role: PromptMessageRole = PromptMessageRole.TOOL + tool_call_id: str # Tool call ID, if OpenAI tool call is not supported, you can also pass in the tool name +``` + +基底クラスの`content`にツール実行結果を渡します。 + +#### PromptMessageTool + +```python +class PromptMessageTool(BaseModel): + """ + Model class for prompt message tool. + """ + name: str # Tool name + description: str # Tool description + parameters: dict # Tool parameters dict + +``` + +*** + +#### LLMResult + +```python +class LLMResult(BaseModel): + """ + Model class for llm result. + """ + model: str # Actually used model + prompt_messages: list[PromptMessage] # Prompt message list + message: AssistantPromptMessage # Reply message + usage: LLMUsage # Tokens used and cost information + system_fingerprint: Optional[str] = None # Request fingerprint, refer to OpenAI parameter definition +``` + +#### LLMResultChunkDelta + +ストリーミングレスポンスの各イテレーション内のDeltaエンティティ + +```python +class LLMResultChunkDelta(BaseModel): + """ + Model class for llm result chunk delta. + """ + index: int # Sequence number + message: AssistantPromptMessage # Reply message + usage: Optional[LLMUsage] = None # Tokens used and cost information, only returned in the last message + finish_reason: Optional[str] = None # Completion reason, only returned in the last message +``` + +#### LLMResultChunk + +ストリーミングレスポンスのイテレーションエンティティ + +```python +class LLMResultChunk(BaseModel): + """ + Model class for llm result chunk. + """ + model: str # Actually used model + prompt_messages: list[PromptMessage] # Prompt message list + system_fingerprint: Optional[str] = None # Request fingerprint, refer to OpenAI parameter definition + delta: LLMResultChunkDelta # Changes in content for each iteration +``` + +#### LLMUsage + +```python +class LLMUsage(ModelUsage): + """ + Model class for llm usage. + """ + prompt_tokens: int # Tokens used by prompt + prompt_unit_price: Decimal # Prompt unit price + prompt_price_unit: Decimal # Prompt price unit, i.e., unit price based on how many tokens + prompt_price: Decimal # Prompt cost + completion_tokens: int # Tokens used by completion + completion_unit_price: Decimal # Completion unit price + completion_price_unit: Decimal # Completion price unit, i.e., unit price based on how many tokens + completion_price: Decimal # Completion cost + total_tokens: int # Total tokens used + total_price: Decimal # Total cost + currency: str # Currency unit + latency: float # Request time (s) +``` + +*** + +#### TextEmbeddingResult + +```python +class TextEmbeddingResult(BaseModel): + """ + Model class for text embedding result. + """ + model: str # Actually used model + embeddings: list[list[float]] # Embedding vector list, corresponding to the input texts list + usage: EmbeddingUsage # Usage information +``` + +#### EmbeddingUsage + +```python +class EmbeddingUsage(ModelUsage): + """ + Model class for embedding usage. + """ + tokens: int # Tokens used + total_tokens: int # Total tokens used + unit_price: Decimal # Unit price + price_unit: Decimal # Price unit, i.e., unit price based on how many tokens + total_price: Decimal # Total cost + currency: str # Currency unit + latency: float # Request time (s) +``` + +*** + +#### RerankResult + +```python +class RerankResult(BaseModel): + """ + Model class for rerank result. + """ + model: str # Actually used model + docs: list[RerankDocument] # List of reranked segments +``` + +#### RerankDocument + +```python +class RerankDocument(BaseModel): + """ + Model class for rerank document. + """ + index: int # Original sequence number + text: str # Segment text content + score: float # Score +``` + +## 関連リソース + +- [モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - モデル設定の標準を理解する +- [モデルプラグイン入門](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - モデルプラグインの基本概念を素早く理解する +- [新しいモデルを素早く統合する](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 既存のプロバイダーに新しいモデルを追加する方法を学ぶ +- [新しいモデルプロバイダーを作成する](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 全く新しいモデルプロバイダーを開発する方法を学ぶ + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx b/ja/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx new file mode 100644 index 00000000..a5001679 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx @@ -0,0 +1,52 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Multilingual README +language: en +title: 多言語README +description: この記事では、Difyプラグインの多言語READMEのファイル仕様と、Dify Marketplaceでの表示ルールについて紹介します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme)を参照してください。 + +プラグイン用の多言語READMEを作成できます。これは[Dify Marketplace](https://marketplace.dify.ai)やその他の場所で、ユーザーの優先言語に基づいて表示されます。 + +### README **ファイル仕様** + +| **言語** | 必須 | ファイル名 | パス | **説明** | +| :------------------ | :------- | :-------------------------- | :----------------------------------------------------- | :--------------------------------------------------------------- | +| **英語** | はい | `README.md` | プラグインルートディレクトリ | / | +| **その他の言語** | いいえ | `README_.md` | プラグインルートディレクトリ下の`readme`フォルダ内 | 現在、日本語、ポルトガル語、簡体字中国語をサポートしています。 | + +以下はディレクトリ構造の例です: + +```bash +... +├── main.py +├── manifest.yaml +├── readme +│ ├── README_ja_JP.md +│ ├── README_pt_BR.md +│ └── README_zh_Hans.md +├── README.md +... +``` + +### 多言語READMEの**Marketplaceでの表示方法** + +プラグインにユーザーの優先言語のREADMEがある場合、Dify Marketplaceのプラグイン詳細ページにはその言語バージョンのREADMEが表示されます。 + +![](/images/plugin_details_page_en.jpeg) + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集する](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx b/ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx new file mode 100644 index 00000000..02b7328c --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx @@ -0,0 +1,162 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Persistent Storage KV +language: ja +title: 永続ストレージ +description: 組み込みのキーバリューデータベースを使用して、Difyプラグインで永続ストレージを実装し、インタラクション間で状態を維持する方法を学びます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv)を参照してください。 + +## 概要 + +ほとんどのプラグインツールとエンドポイントは、ステートレスな単一ラウンドのインタラクションモデルで動作します: +1. リクエストを受信 +2. データを処理 +3. レスポンスを返却 +4. インタラクションを終了 + +しかし、多くの実際のアプリケーションでは、複数のインタラクション間で状態を維持する必要があります。ここで**永続ストレージ**が不可欠になります。 + + +永続ストレージメカニズムにより、プラグインは同じワークスペース内でデータを永続的に保存でき、ステートフルなアプリケーションやメモリ機能を実現できます。 + + +Difyは現在、プラグイン用のキーバリュー(KV)ストレージシステムを提供しており、開発者のニーズに基づいて、将来的にはより柔軟で強力なストレージインターフェースを導入する予定です。 + +## ストレージへのアクセス + +すべてのストレージ操作は、プラグインのセッションで利用可能な`storage`オブジェクトを通じて実行されます: + +```python +# Access the storage interface +storage = self.session.storage +``` + +## ストレージ操作 + +### データの保存 + +`set`メソッドでデータを保存します: + +```python +def set(self, key: str, val: bytes) -> None: + """ + Store data in persistent storage + + Parameters: + key: Unique identifier for your data + val: Binary data to store (bytes) + """ + pass +``` + + +値は`bytes`形式である必要があります。これにより、ファイルを含むさまざまな種類のデータを柔軟に保存できます。 + + +#### 例:さまざまなデータ型の保存 + +```python +# String data (must convert to bytes) +storage.set("user_name", "John Doe".encode('utf-8')) + +# JSON data +import json +user_data = {"name": "John", "age": 30, "preferences": ["AI", "NLP"]} +storage.set("user_data", json.dumps(user_data).encode('utf-8')) + +# File data +with open("image.jpg", "rb") as f: + image_data = f.read() + storage.set("profile_image", image_data) +``` + +### データの取得 + +`get`メソッドで保存されたデータを取得します: + +```python +def get(self, key: str) -> bytes: + """ + Retrieve data from persistent storage + + Parameters: + key: Unique identifier for your data + + Returns: + The stored data as bytes, or None if key doesn't exist + """ + pass +``` + +#### 例:データの取得と変換 + +```python +# Retrieving string data +name_bytes = storage.get("user_name") +if name_bytes: + name = name_bytes.decode('utf-8') + print(f"Retrieved name: {name}") + +# Retrieving JSON data +import json +user_data_bytes = storage.get("user_data") +if user_data_bytes: + user_data = json.loads(user_data_bytes.decode('utf-8')) + print(f"User preferences: {user_data['preferences']}") +``` + +### データの削除 + +`delete`メソッドで保存されたデータを削除します: + +```python +def delete(self, key: str) -> None: + """ + Delete data from persistent storage + + Parameters: + key: Unique identifier for the data to delete + """ + pass +``` + +## ベストプラクティス + + + + 競合を避け、コードをより保守しやすくするために、キーに一貫した命名規則を作成してください。 + + + キーが見つからない可能性があるため、処理前にデータが存在するかどうかを常に確認してください。 + + + 保存前に複雑なオブジェクトをJSONまたは他のシリアライズ形式に変換してください。 + + + 潜在的なエラーを適切に処理するために、ストレージ操作をtry/exceptブロックでラップしてください。 + + + +## 一般的なユースケース + +- **ユーザー設定**:セッション間でユーザーの設定やプリファレンスを保存 +- **会話履歴**:以前の会話からのコンテキストを維持 +- **APIトークン**:認証トークンを安全に保存 +- **キャッシュデータ**:API呼び出しを減らすために頻繁にアクセスされるデータを保存 +- **ファイルストレージ**:ユーザーがアップロードしたファイルや生成されたコンテンツを保存 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集する](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx b/ja/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx new file mode 100644 index 00000000..65b597d3 --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx @@ -0,0 +1,253 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Plugin info by Manifest +language: ja +title: Manifest +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest)を参照してください。 + +Manifestは、**プラグイン**の最も基本的な情報を定義するYAML準拠のファイルです。プラグイン名、作成者、含まれるツール、モデルなどが含まれますが、これらに限定されません。プラグインの全体的なアーキテクチャについては、[プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin)と[開発者チートシート](/ja/develop-plugin/dev-guides-and-walkthroughs/cheatsheet)を参照してください。 + +このファイルのフォーマットが正しくない場合、プラグインの解析とパッケージングプロセスは失敗します。 + +### コード例 + +以下はManifestファイルの簡単な例です。各データ項目の意味と機能については後で説明します。 + +他のプラグインの参照コードについては、[GitHubコードリポジトリ](https://github.com/langgenius/dify-official-plugins/blob/main/tools/google/manifest.yaml)を参照してください。 + +```yaml +version: 0.0.1 +type: "plugin" +author: "Yeuoly" +name: "neko" +label: + en_US: "Neko" +created_at: "2024-07-12T08:03:44.658609186Z" +icon: "icon.svg" +resource: + memory: 1048576 + permission: + tool: + enabled: true + model: + enabled: true + llm: true + endpoint: + enabled: true + app: + enabled: true + storage: + enabled: true + size: 1048576 +plugins: + endpoints: + - "provider/neko.yaml" +meta: + version: 0.0.1 + arch: + - "amd64" + - "arm64" + runner: + language: "python" + version: "3.10" + entrypoint: "main" +privacy: "./privacy.md" +``` + +### 構造 + + + プラグインのバージョン。 + + + + プラグインタイプ。現在は`plugin`のみサポートされており、将来的に`bundle`がサポートされる予定です。 + + + + 作成者。Marketplaceでは組織名として定義されます。 + + + + 多言語名。 + + + + 作成時刻。Marketplaceでは現在時刻より後であってはなりません。 + + + + アイコンパス。 + + + + 申請するリソース。 + + + 最大メモリ使用量。主にSaaS上のAWS Lambdaリソース申請に関連します。単位はバイトです。 + + + + 権限申請。 + + + ツールの逆呼び出し権限。 + + + ツール権限を有効にするかどうか。 + + + + + モデルの逆呼び出し権限。 + + + モデル権限を有効にするかどうか。 + + + + 大規模言語モデル権限を有効にするかどうか。 + + + + テキスト埋め込みモデル権限を有効にするかどうか。 + + + + rerankモデル権限を有効にするかどうか。 + + + + テキスト読み上げモデル権限を有効にするかどうか。 + + + + 音声テキスト変換モデル権限を有効にするかどうか。 + + + + コンテンツモデレーションモデル権限を有効にするかどうか。 + + + + + ノードの逆呼び出し権限。 + + + ノード権限を有効にするかどうか。 + + + + + `endpoint`を登録する権限。 + + + endpoint権限を有効にするかどうか。 + + + + + `app`の逆呼び出し権限。 + + + app権限を有効にするかどうか。 + + + + + 永続ストレージを申請する権限。 + + + ストレージ権限を有効にするかどうか。 + + + + 許可される最大永続メモリサイズ。単位はバイトです。 + + + + + + + プラグインによって拡張される特定の機能の`yaml`ファイルのリスト。プラグインパッケージ内の絶対パスです。例えば、モデルを拡張する必要がある場合、`openai.yaml`のようなファイルを定義し、ここにファイルパスを記入する必要があります。このパスにファイルが実際に存在しない場合、パッケージングは失敗します。 + + + ツールとモデルを同時に拡張することは許可されていません。 + + + + 拡張がないことは許可されていません。 + + + + モデルとEndpointsを同時に拡張することは許可されていません。 + + + + 現在、各タイプの拡張では1つのプロバイダーのみがサポートされています。 + + + + [ツール](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)プロバイダーのプラグイン拡張。 + + + + [モデル](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules)プロバイダーのプラグイン拡張。 + + + + [Endpoints](/ja/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin)プロバイダーのプラグイン拡張。 + + + + [エージェント戦略](/ja/develop-plugin/features-and-specs/advanced-development/reverse-invocation)プロバイダーのプラグイン拡張。 + + + + + プラグインのメタデータ。 + + + `manifest`フォーマットバージョン。初期バージョンは`0.0.1`です。 + + + + サポートされるアーキテクチャ。現在は`amd64`と`arm64`のみサポートされています。 + + + + ランタイム設定。 + + + プログラミング言語。現在はPythonのみサポートされています。 + + + + 言語バージョン。現在は`3.12`のみサポートされています。 + + + + プログラムエントリポイント。Pythonでは`main`である必要があります。 + + + + + + プラグインのプライバシーポリシーファイルの相対パスまたはURLを指定します。例:`"./privacy.md"`または`"https://your-web/privacy"`。プラグインをDify Marketplaceに掲載する予定がある場合、明確なユーザーデータの使用とプライバシーに関する声明を提供するために**このフィールドは必須**です。詳細な記入ガイドラインについては、[プラグインプライバシーデータ保護ガイドライン](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines)を参照してください。 + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx b/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx new file mode 100644 index 00000000..a3e0658b --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx @@ -0,0 +1,33 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Remote Debug a Plugin +language: en +title: プラグインのデバッグ +description: このドキュメントでは、Difyのリモートデバッグ機能を使用してプラグインをテストする方法を紹介します。デバッグ情報の取得、環境変数ファイルの設定、プラグインのリモートデバッグの開始、プラグインのインストール状態の確認について詳細な手順を提供します。この方法により、開発者はローカルで開発しながら、Dify環境でリアルタイムにプラグインをテストできます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)を参照してください。 + +プラグイン開発が完了したら、次のステップはプラグインが正常に機能するかどうかをテストすることです。Difyは、テスト環境でプラグインの機能を素早く検証するための便利なリモートデバッグ方法を提供しています。 + +[「プラグイン管理」](https://cloud.dify.ai/plugins)ページに移動して、リモートサーバーアドレスとデバッグKeyを取得します。 + +![リモートデバッグプラグイン](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) + +プラグインプロジェクトに戻り、`.env.example`ファイルをコピーして`.env`にリネームし、取得したリモートサーバーアドレスとデバッグKey情報を入力します。 + +`.env`ファイル: + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_URL=debug.dify.ai:5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +`python -m main`コマンドを実行してプラグインを起動します。プラグインページで、プラグインがワークスペースにインストールされていることが確認でき、チームの他のメンバーもプラグインにアクセスできます。 + +![ワークスペースにインストールされたプラグイン](https://assets-docs.dify.ai/2024/12/ec26e5afc57bbfeb807719638f603807.png) \ No newline at end of file diff --git a/ja/develop-plugin/features-and-specs/plugin-types/tool.mdx b/ja/develop-plugin/features-and-specs/plugin-types/tool.mdx new file mode 100644 index 00000000..c644508e --- /dev/null +++ b/ja/develop-plugin/features-and-specs/plugin-types/tool.mdx @@ -0,0 +1,393 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Tool +language: ja +title: ツールの戻り値 +description: このドキュメントでは、Difyプラグインにおけるツールのデータ構造と使用方法について詳しく紹介します。さまざまな種類のメッセージ(画像URL、リンク、テキスト、ファイル、JSON)の返し方、変数およびストリーミング変数メッセージの作成方法、ワークフローで参照するためのツール出力変数スキーマの定義方法について説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/tool)を参照してください。 + +## 概要 + + +詳細なインターフェースドキュメントに入る前に、Difyプラグインのツール統合プロセスについて全般的な理解があることを確認してください。 + + + + + テキスト、リンク、画像、JSONなど、さまざまな種類のメッセージを返す + + + ワークフロー統合のための変数を作成および操作する + + + ワークフロー参照用のカスタム出力変数を定義する + + + +## データ構造 + +### メッセージの戻り値 + + +Difyは `text`、`links`、`images`、`file BLOBs`、`JSON` など、さまざまなメッセージタイプをサポートしています。これらのメッセージは専用のインターフェースを通じて返すことができます。 + + +デフォルトでは、ワークフロー内のツールの出力には `files`、`text`、`json` の3つの固定変数が含まれます。以下のメソッドを使用して、これらの変数に適切なコンテンツを設定できます。 + + +`create_image_message` などのメソッドを使用して画像を返すことができますが、ツールはカスタム出力変数もサポートしており、ワークフロー内で特定のデータを参照するのに便利です。 + + +### メッセージタイプ + + +```python Image URL +def create_image_message(self, image: str) -> ToolInvokeMessage: + """ + Return an image URL message + + Dify will automatically download the image from the provided URL + and display it to the user. + + Args: + image: URL to an image file + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python Link +def create_link_message(self, link: str) -> ToolInvokeMessage: + """ + Return a clickable link message + + Args: + link: URL to be displayed as a clickable link + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python Text +def create_text_message(self, text: str) -> ToolInvokeMessage: + """ + Return a text message + + Args: + text: Text content to be displayed + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python File +def create_blob_message(self, blob: bytes, meta: dict = None) -> ToolInvokeMessage: + """ + Return a file blob message + + For returning raw file data such as images, audio, video, + or documents (PPT, Word, Excel, etc.) + + Args: + blob: Raw file data in bytes + meta: File metadata dictionary. Include 'mime_type' to specify + the file type, otherwise 'octet/stream' will be used + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python JSON +def create_json_message(self, json: dict) -> ToolInvokeMessage: + """ + Return a formatted JSON message + + Useful for data transmission between workflow nodes. + In agent mode, most LLMs can read and understand JSON data. + + Args: + json: Python dictionary to be serialized as JSON + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + + + + + ダウンロードして表示される画像のURL + + + + クリック可能なリンクとして表示されるURL + + + + 表示されるテキストコンテンツ + + + + バイト形式の生ファイルデータ + + + + 以下を含むファイルメタデータ: + - `mime_type`:ファイルのMIMEタイプ(例:"image/png") + - ファイルに関連するその他のメタデータ + + + + JSONとしてシリアライズされるPython辞書 + + + + +ファイルBLOBを扱う際は、ファイルが正しく処理されるように、`meta` 辞書に常に `mime_type` を指定してください。例:`{"mime_type": "image/png"}`。 + + +### 変数 + + +```python Standard Variable +from typing import Any + +def create_variable_message(self, variable_name: str, variable_value: Any) -> ToolInvokeMessage: + """ + Create a named variable for workflow integration + + For non-streaming output variables. If multiple instances with the + same name are created, the latest one overrides previous values. + + Args: + variable_name: Name of the variable to create + variable_value: Value of the variable (any Python data type) + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python Streaming Variable +def create_stream_variable_message( + self, variable_name: str, variable_value: str +) -> ToolInvokeMessage: + """ + Create a streaming variable with typewriter effect + + When referenced in an answer node in a chatflow application, + the text will be output with a typewriter effect. + + Args: + variable_name: Name of the variable to create + variable_value: String value to stream (only strings supported) + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + + + + + 作成または更新される変数の名前 + + + + 変数に割り当てる値: + - 標準変数の場合:任意のPythonデータ型 + - ストリーミング変数の場合:文字列データのみ + + + + +ストリーミング変数メソッド(`create_stream_variable_message`)は現在、文字列データのみをサポートしています。複雑なデータ型はタイプライター効果でストリーミングできません。 + + +## カスタム出力変数 + + +ワークフローアプリケーションでツールの出力変数を参照するには、どの変数が出力される可能性があるかを定義する必要があります。これはツールのマニフェストで [JSON Schema](https://json-schema.org/) 形式を使用して行います。 + + +### 出力スキーマの定義 + + +```yaml Tool Manifest with Output Schema +identity: + author: example_author + name: example_tool + label: + en_US: Example Tool + zh_Hans: 示例工具 + ja_JP: ツール例 + pt_BR: Ferramenta de exemplo +description: + human: + en_US: A simple tool that returns a name + zh_Hans: 返回名称的简单工具 + ja_JP: 名前を返す簡単なツール + pt_BR: Uma ferramenta simples que retorna um nome + llm: A simple tool that returns a name variable +output_schema: + type: object + properties: + name: + type: string + description: "The name returned by the tool" + age: + type: integer + description: "The age returned by the tool" + profile: + type: object + properties: + interests: + type: array + items: + type: string + location: + type: string +``` + + + + + ツールの出力スキーマを定義するルートオブジェクト + + + + ツール出力スキーマでは "object" である必要があります + + + + すべての可能な出力変数の辞書 + + + + 各出力変数の定義(型と説明を含む) + + + + +出力スキーマを定義しても、実装コードで `create_variable_message()` を使用して実際に変数を返す必要があります。そうしないと、ワークフローはその変数に対して `None` を受け取ります。 + + +### 実装例 + + +```python Basic Variable Example +def run(self, inputs): + # Process inputs and generate a name + generated_name = "Alice" + + # Return the name as a variable that matches the output_schema + return self.create_variable_message("name", generated_name) +``` + +```python Complex Structure Example +def run(self, inputs): + # Generate complex structured data + user_data = { + "name": "Bob", + "age": 30, + "profile": { + "interests": ["coding", "reading", "hiking"], + "location": "San Francisco" + } + } + + # Return individual variables + self.create_variable_message("name", user_data["name"]) + self.create_variable_message("age", user_data["age"]) + self.create_variable_message("profile", user_data["profile"]) + + # Also return a text message for display + return self.create_text_message(f"User {user_data['name']} processed successfully") +``` + + + +複雑なワークフローの場合、複数の出力変数を定義してすべてを返すことができます。これにより、ワークフロー設計者がツールを使用する際の柔軟性が向上します。 + + +## 例 + +### 完全なツール実装 + + +```python Weather Forecast Tool +import requests +from typing import Any + +class WeatherForecastTool: + def run(self, inputs: dict) -> Any: + # Get location from inputs + location = inputs.get("location", "London") + + try: + # Call weather API (example only) + weather_data = self._get_weather_data(location) + + # Create variables for workflow use + self.create_variable_message("temperature", weather_data["temperature"]) + self.create_variable_message("conditions", weather_data["conditions"]) + self.create_variable_message("forecast", weather_data["forecast"]) + + # Create a JSON message for data transmission + self.create_json_message(weather_data) + + # Create an image message for the weather map + self.create_image_message(weather_data["map_url"]) + + # Return a formatted text response + return self.create_text_message( + f"Weather in {location}: {weather_data['temperature']}°C, {weather_data['conditions']}. " + f"Forecast: {weather_data['forecast']}" + ) + + except Exception as e: + # Handle errors gracefully + return self.create_text_message(f"Error retrieving weather data: {str(e)}") + + def _get_weather_data(self, location: str) -> dict: + # Mock implementation - in a real tool, this would call a weather API + return { + "location": location, + "temperature": 22, + "conditions": "Partly Cloudy", + "forecast": "Sunny with occasional showers tomorrow", + "map_url": "https://example.com/weather-map.png" + } +``` + + + +ツールを設計する際は、直接出力(ユーザーが見るもの)と変数出力(他のワークフローノードが使用できるもの)の両方を考慮してください。この分離により、ツールの使用方法に柔軟性が生まれます。 + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/getting-started/cli.mdx b/ja/develop-plugin/getting-started/cli.mdx new file mode 100644 index 00000000..78795890 --- /dev/null +++ b/ja/develop-plugin/getting-started/cli.mdx @@ -0,0 +1,156 @@ +--- +dimensions: + type: + primary: conceptual + detail: architecture + level: beginner +standard_title: CLI +language: en +title: CLI +description: Difyプラグイン開発用コマンドラインインターフェース +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/getting-started/cli)を参照してください。 + +コマンドラインインターフェース(CLI)を使用してDifyプラグインのセットアップとパッケージ化を行います。CLIは、初期化からパッケージ化まで、プラグイン開発ワークフローを効率的に管理する方法を提供します。 + +このガイドでは、Difyプラグイン開発におけるCLIの使用方法について説明します。 + +## 前提条件 +始める前に、以下がインストールされていることを確認してください: +- Pythonバージョン ≥ 3.12 +- Dify CLI +- Homebrew(Macユーザーの場合) + +## Difyプラグインプロジェクトの作成 + + + + ```bash + brew tap langgenius/dify + brew install dify + ``` + + + [Dify GitHubリリースページ](https://github.com/langgenius/dify-plugin-daemon/releases)から最新のDify CLIを取得してください + + ```bash + # Download dify-plugin-darwin-arm64 + chmod +x dify-plugin-darwin-arm64 + mv dify-plugin-darwin-arm64 dify + sudo mv dify /usr/local/bin/ + ``` + + + +これでDify CLIのインストールが完了しました。以下のコマンドを実行してインストールを確認できます: + + +```bash +dify version +``` + + +以下のコマンドを使用して新しいDifyプラグインプロジェクトを作成できます: + +```bash +dify plugin init +``` + +プロンプトが表示されたら、必要なフィールドを入力してください: + +```bash +Edit profile of the plugin +Plugin name (press Enter to next step): hello-world +Author (press Enter to next step): langgenius +Description (press Enter to next step): hello world example +Repository URL (Optional) (press Enter to next step): Repository URL (Optional) + Enable multilingual README: [✔] English is required by default + +Languages to generate: + English: [✔] (required) + → 简体中文 (Simplified Chinese): [✔] + 日本語 (Japanese): [✘] + Português (Portuguese - Brazil): [✘] + +Controls: + ↑/↓ Navigate • Space/Tab Toggle selection • Enter Next step +``` + +`python`を選択してEnterキーを押し、Pythonプラグインテンプレートで続行します。 + +```bash +Select the type of plugin you want to create, and press `Enter` to continue +Before starting, here's some basic knowledge about Plugin types in Dify: + +- Tool: Tool Providers like Google Search, Stable Diffusion, etc. Used to perform specific tasks. +- Model: Model Providers like OpenAI, Anthropic, etc. Use their models to enhance AI capabilities. +- Endpoint: Similar to Service API in Dify and Ingress in Kubernetes. Extend HTTP services as endpoints with custom logi +- Agent Strategy: Implement your own agent strategies like Function Calling, ReAct, ToT, CoT, etc. + +Based on the ability you want to extend, Plugins are divided into four types: Tool, Model, Extension, and Agent Strategy + +- Tool: A tool provider that can also implement endpoints. For example, building a Discord Bot requires both Sending and +- Model: Strictly for model providers, no other extensions allowed. +- Extension: For simple HTTP services that extend functionality. +- Agent Strategy: Implement custom agent logic with a focused approach. + +We've provided templates to help you get started. Choose one of the options below: +-> tool + agent-strategy + llm + text-embedding + rerank + tts + speech2text + moderation + extension +``` + +デフォルトのdifyバージョンを入力します。空白のままにすると最新バージョンが使用されます: + +```bash +Edit minimal Dify version requirement, leave it blank by default +Minimal Dify version (press Enter to next step): +``` + +準備完了です!CLIは指定したプラグイン名で新しいディレクトリを作成し、プラグインの基本構造をセットアップします。 + +```bash +cd hello-world +``` + +## プラグインの実行 + +hello-worldディレクトリにいることを確認してください + +```bash +cp .env.example .env +``` + +`.env`ファイルを編集して、APIキーやその他の設定などのプラグインの環境変数を設定します。これらの変数はDifyダッシュボードで確認できます。Dify環境にログインし、右上の「プラグイン」アイコンをクリックしてから、デバッグアイコン(または虫のようなもの)をクリックします。ポップアップウィンドウで「APIキー」と「ホストアドレス」をコピーします。(キーとホストアドレスの取得インターフェースを示すローカルの対応するスクリーンショットを参照してください) + + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_HOST=debug-plugin.dify.dev +REMOTE_INSTALL_PORT=5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +以下のコマンドを使用して、プラグインをローカルで実行できます: + +```bash +pip install -r requirements.txt +python -m main +``` + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集する](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/cli.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/getting-started/getting-started-dify-plugin.mdx b/ja/develop-plugin/getting-started/getting-started-dify-plugin.mdx new file mode 100644 index 00000000..e702d6a3 --- /dev/null +++ b/ja/develop-plugin/getting-started/getting-started-dify-plugin.mdx @@ -0,0 +1,108 @@ +--- +dimensions: + type: + primary: conceptual + detail: introduction + level: beginner +standard_title: Getting Started with Dify Plugin Development +language: en +title: Dify プラグイン +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/getting-started/getting-started-dify-plugin)を参照してください。 + +Dify プラグインは、AI アプリケーションに追加機能を提供するモジュラーコンポーネントです。外部サービス、カスタム機能、特殊なツールを Dify で構築した AI アプリケーションに統合することができます。 + + + + + +プラグインを通じて、AI アプリケーションは以下のことが可能になります: +- 外部 API への接続 +- 様々なタイプのデータ処理 +- 特殊な計算の実行 +- 実世界でのアクションの実行 + +## プラグインの種類 + + + + AI モデルをプラグインとしてパッケージ化して管理 + + 詳細を見る + + + エージェントとワークフロー向けの特殊な機能を構築 + + 詳細を見る + + + 自律型エージェント向けのカスタム推論戦略を作成 + + 詳細を見る + + + HTTP Webhook を通じた外部サービスとの統合を実装 + + 詳細を見る + + + +## その他のリソース + + + + 効率的なプラグイン開発のためのツールとテクニック + + + プラグインをパッケージ化して Dify コミュニティと共有 + + + 技術仕様とドキュメント + + + 他の開発者とコミュニケーションを取り、エコシステムに貢献 + + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/getting-started-dify-plugin.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/faq/faq.mdx b/ja/develop-plugin/publishing/faq/faq.mdx new file mode 100644 index 00000000..2d73d5ca --- /dev/null +++ b/ja/develop-plugin/publishing/faq/faq.mdx @@ -0,0 +1,49 @@ +--- +dimensions: + type: + primary: operational + detail: maintenance + level: beginner +todo: Developers (Contributors) should thoroughly test before releasing; debugging + should not be the user's (Dify User / Consumer) responsibility. +standard_title: Faq +language: en +title: よくある質問 +description: このドキュメントでは、Difyプラグインの開発とインストールに関するよくある質問に回答します。プラグインのアップロード失敗の解決方法(authorフィールドの修正)やプラグインインストール時の検証例外の処理方法(FORCE_VERIFYING_SIGNATURE環境変数の設定)などを含みます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/faq/faq)を参照してください。 + +## インストール時にプラグインのアップロードが失敗した場合はどうすればよいですか? + +**エラー詳細**: `PluginDaemonBadRequestError: plugin_unique_identifier is not valid` というエラーメッセージが表示されます。 + +**解決策**: プラグインプロジェクト内の `manifest.yaml` ファイルと `/provider` パス下の `.yaml` ファイルにある `author` フィールドを、ご自身のGitHub IDに変更してください。 + +プラグインパッケージコマンドを再実行し、新しいプラグインパッケージをインストールしてください。 + +## プラグインのインストール中に例外が発生した場合はどのように対処すればよいですか? + +**問題の説明**: プラグインのインストール中に `plugin verification has been enabled, and the plugin you want to install has a bad signature` という例外メッセージが表示されました。どのように対処すればよいですか? + +**解決策**: `/docker/.env` 設定ファイルの末尾に `FORCE_VERIFYING_SIGNATURE=false` フィールドを追加します。その後、以下のコマンドを実行してDifyサービスを再起動してください: + +```bash +cd docker +docker compose down +docker compose up -d +``` + +このフィールドを追加すると、DifyプラットフォームはDify Marketplaceにリスト(審査)されていないすべてのプラグインのインストールを許可するようになりますが、これはセキュリティリスクをもたらす可能性があります。 + +まずテスト/サンドボックス環境でプラグインをインストールし、安全性を確認してから本番環境にインストールすることをお勧めします。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/faq/faq.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-ja/0321-plugin-auto-publish-pr.mdx b/ja/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx similarity index 53% rename from plugin-dev-ja/0321-plugin-auto-publish-pr.mdx rename to ja/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx index 0bd749b2..03fb7995 100644 --- a/plugin-dev-ja/0321-plugin-auto-publish-pr.mdx +++ b/ja/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx @@ -6,48 +6,51 @@ dimensions: level: beginner standard_title: Plugin Auto Publish PR language: ja -title: PRを通じてプラグインを自動的に公開する -description: このドキュメントでは、GitHub Actionsを使用してDifyプラグインのリリースプロセスを自動化する方法について説明します。設定手順、パラメータの説明、使用方法などが含まれており、プラグイン開発者が手動介入なしにリリースプロセスを合理化するのに役立ちます。 +title: PRによるプラグインの自動公開 +description: このドキュメントでは、GitHub Actionsを使用してDifyプラグインのリリースプロセスを自動化する方法について説明します。設定手順、パラメータの説明、使用方法を含み、プラグイン開発者が手動操作なしでリリースプロセスを効率化できるようサポートします。 --- + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr)を参照してください。 + ### 背景 -プラグイン貢献者が**他のユーザーにすでに使用されているDifyプラグイン**を更新する必要がある場合、そのプロセスは非常に煩雑です:貢献者はまずプラグインのソースコードを修正してバージョン番号を更新し、変更をプラグインソースリポジトリにプッシュし、フォークしたdify-pluginリポジトリに新しいブランチを作成する必要があります。その後、プラグインを手動でパッケージ化し、パッケージファイルをアップロードし、元のdify-pluginリポジトリにマージするためのPRを作成する必要があります。このプロセスはプラグインコードが変更されるたびに繰り返す必要があり、時間がかかり非効率的です。 +他のユーザーが積極的に使用しているプラグインを更新するのは面倒な作業です。従来は、コードの修正、バージョンの更新、変更のプッシュ、ブランチの作成、ファイルのパッケージング、PRの手動送信が必要でした。この繰り返しのプロセスは開発を遅らせます。 -このワークフローを簡素化するために、**Plugin Auto-PR**と呼ばれるGitHub Actionsベースの自動化ワークフローを構築しました。このツールを使用すると、プラグイン貢献者はプラグインのパッケージ化、ブランチのプッシュ、PRの作成を一度の操作で完了できます。 +そこで、**Plugin Auto-PR**を作成しました。これはプロセス全体を自動化するGitHub Actionsワークフローです。これにより、パッケージング、プッシュ、PRの作成を1つのアクションで行え、優れたプラグインの構築に集中できます。 -### 概念紹介 +### コンセプト #### GitHub Actions -GitHub Actionsは、GitHubが提供する組み込みのCI/CDサービスで、様々なビルド、テスト、デプロイタスクを自動化します。 +GitHub Actionsは、GitHub上の開発タスクを自動化します。 -**動作原理**:トリガー条件(コードのプッシュなど)が満たされると、GitHubは自動的に仮想マシンを割り当ててワークフローを実行します。すべての操作はGitHubクラウドで完了します。 +**仕組み**: トリガー(例:コードのプッシュ)が発生すると、クラウドベースの仮想マシンでワークフローが実行され、ビルドからデプロイまですべてが自動的に処理されます。 -![ワークフロー](https://assets-docs.dify.ai/2025/04/60534de8e220f860947b32a8329a8349.png) +![Workflow](https://assets-docs.dify.ai/2025/04/60534de8e220f860947b32a8329a8349.png) -**無料枠の制限**: +**制限**: -* 公開リポジトリ:無制限 -* プライベートリポジトリ:月2000分 +* パブリックリポジトリ: 無制限 +* プライベートリポジトリ: 月2000分 #### Plugin Auto-PR -**動作原理**: +**仕組み**: -1. プラグインソースリポジトリのmainブランチにコードをプッシュすると、ワークフローがトリガーされます -2. ワークフローは`manifest.yaml`ファイルからプラグイン情報を読み取ります -3. プラグインを自動的に`.difypkg`ファイルとしてパッケージ化します -4. パッケージファイルをフォークした`dify-plugins`リポジトリにプッシュします -5. 新しいブランチを作成して変更をコミットします -6. 上流リポジトリへのマージを自動的にPRで要求します +1. プラグインソースリポジトリのメインブランチにコードをプッシュするとワークフローがトリガーされます +2. ワークフローが`manifest.yaml`ファイルからプラグイン情報を読み取ります +3. プラグインを`.difypkg`ファイルとして自動的にパッケージングします +4. パッケージングされたファイルをフォークした`dify-plugins`リポジトリにプッシュします +5. 新しいブランチを作成し、変更をコミットします +6. 上流リポジトリにマージするためのPRを自動的に作成します -### 環境準備 +### 前提条件 -#### リポジトリ要件 +#### リポジトリ -* すでに独自のプラグインソースコードリポジトリがある(例:`your-name/plugin-source`) -* すでに独自のフォークしたプラグインリポジトリがある(例:`your-name/dify-plugins`) +* 自分のプラグインソースコードリポジトリがすでにあること(例:`your-name/plugin-source`) +* 自分のフォークしたプラグインリポジトリがすでにあること(例:`your-name/dify-plugins`) +* フォークしたリポジトリにすでにプラグインディレクトリ構造があること: ``` dify-plugins/ @@ -55,58 +58,58 @@ dify-plugins/ └── plugin-name ``` -#### 権限要件 +#### 権限 -このワークフローが正常に機能するには、適切な権限が必要です: +このワークフローが機能するには適切な権限が必要です: -* 十分な権限を持つGitHub Personal Access Token(PAT)を作成する必要があります -* そのPATはフォークしたリポジトリにコードをプッシュする権限が必要です -* そのPATは上流リポジトリにPRを作成する権限が必要です +* 十分な権限を持つGitHub Personal Access Token (PAT)を作成する必要があります +* PATはフォークしたリポジトリにコードをプッシュする権限が必要です +* PATは上流リポジトリにPRを作成する権限が必要です -### パラメータと設定の詳細 +### パラメータと設定 -#### 必須パラメータ +#### セットアップ要件 -プラグイン自動公開ワークフローでは、以下の重要な要素を正しく設定する必要があります: +自動公開を開始するには、2つの主要なコンポーネントが必要です: -**manifest.yamlファイル**:これは自動化プロセス全体の中核となる設定ソースです。以下のフィールドが正しいことを確認する必要があります: +**manifest.yamlファイル**: このファイルが自動化プロセスを駆動します: -* `name`:プラグイン名(パッケージ名とブランチ名の生成に使用) -* `version`:バージョン番号(更新のたびに増分する必要あり) -* `author`:GitHubユーザー名(ターゲットリポジトリパスの決定に使用) +* `name`: プラグイン名(パッケージ名とブランチ名に影響します) +* `version`: セマンティックバージョン番号(リリースごとに増加) +* `author`: GitHubユーザー名(リポジトリパスを決定します) -**PLUGIN\_ACTION Secret**:プラグインソースリポジトリにこのシークレットを正しく設定する必要があります。 +**PLUGIN\_ACTION Secret**: このシークレットをプラグインソースリポジトリに追加する必要があります: -* 値の要件:十分な権限を持つPersonal Access Token(PAT)である必要があります -* 権限要件:フォークしたリポジトリにブランチをプッシュし、上流リポジトリにPRを作成する能力 +* 値: 十分な権限を持つPersonal Access Token (PAT)である必要があります +* 権限: フォークしたリポジトリにブランチをプッシュし、上流リポジトリにPRを作成する能力 #### 自動生成されるパラメータ -ワークフローは**以下を自動的に処理**し、手動介入は不要です: +セットアップが完了すると、ワークフローは以下のパラメータを自動的に処理します: -* GitHubユーザー名:`manifest.yaml`の`author`フィールドから読み取り -* 作者フォルダ名:`author`フィールドと一致 -* プラグイン名:`manifest.yaml`の`name`フィールドから読み取り -* ブランチ名:`bump-{plugin-name}-plugin-{version}` -* パッケージファイル名:`{plugin-name}-{version}.difypkg` -* PRのタイトルと内容:プラグイン名とバージョンに基づいて自動生成 +* GitHubユーザー名: `manifest.yaml`の`author`フィールドから読み取り +* 作者フォルダ名: `author`フィールドと一致 +* プラグイン名: `manifest.yaml`の`name`フィールドから読み取り +* ブランチ名: `bump-{plugin-name}-plugin-{version}` +* パッケージファイル名: `{plugin-name}-{version}.difypkg` +* PRタイトルと内容: プラグイン名とバージョンに基づいて自動生成 -### インストールと設定手順 +### ステップバイステップガイド - 公式の`dify-plugins`リポジトリをフォークし、独自のプラグインソースリポジトリがあることを確認します。 + 公式の`dify-plugins`リポジトリをフォークし、自分のプラグインソースリポジトリがあることを確認してください。 - - プラグインソースリポジトリに移動し、**Settings > Secrets and variables > Actions > New repository secret**をクリックして、GitHubシークレットを作成します: + + プラグインソースリポジトリに移動し、**Settings > Secrets and variables > Actions > New repository secret**をクリックして、GitHub Secretを作成します: - * 名前:`PLUGIN_ACTION` - * 値:ターゲットリポジトリ(`your-name/dify-plugins`)への書き込み権限を持つGitHub Personal Access Token(PAT) + * 名前: `PLUGIN_ACTION` + * 値: ターゲットリポジトリ(`your-name/dify-plugins`)への書き込み権限を持つGitHub Personal Access Token (PAT) - シークレットの作成 + Create Secrets - リポジトリに`.github/workflows/`ディレクトリを作成し、このディレクトリに`plugin-publish.yml`という名前のファイルを作成し、以下の内容をファイルにコピーします: + リポジトリに`.github/workflows/`ディレクトリを作成し、このディレクトリに`plugin-publish.yml`という名前のファイルを作成して、以下の内容をファイルにコピーしてください: ```yaml # .github/workflows/auto-pr.yml @@ -255,53 +258,53 @@ dify-plugins/ ``` - `manifest.yaml`ファイルが以下のフィールドを正しく設定していることを確認します: + 以下のフィールドが正しく設定されていることを確認してください: ```yaml - version: 0.0.x # バージョン番号 - author: your-github-username # GitHubユーザー名/作者名 - name: your-plugin-name # プラグイン名 + version: 0.0.x # Version number + author: your-github-username # GitHub username/Author name + name: your-plugin-name # Plugin name ``` ### 使用ガイド -#### 初回セットアッププロセス +#### 初回セットアップ -自動公開ワークフローを初めて設定する場合は、次の手順を完了します: +自動公開ワークフローを初めてセットアップする際は、以下の手順を完了してください: 1. 公式の`dify-plugins`リポジトリをフォークしていることを確認します 2. プラグインソースリポジトリの構造が正しいことを確認します -3. プラグインソースリポジトリに`PLUGIN_ACTION Secret`を設定します +3. プラグインソースリポジトリに`PLUGIN_ACTION Secret`をセットアップします 4. ワークフローファイル`.github/workflows/plugin-publish.yml`を作成します 5. `manifest.yaml`ファイルの`name`と`author`フィールドが正しく設定されていることを確認します -#### 以降の更新プロセス +#### その後の更新 -セットアップが完了したら、新しいバージョンを公開する必要がある場合は、以下を行うだけです: +セットアップ後に新しいバージョンを公開するには: -1. プラグインコードを修正します +1. コードを修正します 2. `manifest.yaml`の`version`フィールドを更新します -![リリース](https://assets-docs.dify.ai/2025/04/9eed2b9110e91e18008b399e58198f03.png) +![Release](https://assets-docs.dify.ai/2025/04/9eed2b9110e91e18008b399e58198f03.png) -3. すべての変更をmainブランチにプッシュします -4. GitHub Actionsがパッケージング、ブランチ作成、PR提出を自動的に完了するのを待ちます +3. すべての変更をメインブランチにプッシュします +4. GitHub Actionsがパッケージング、ブランチ作成、PR送信を完了するのを待ちます -### 実行結果 +### 結果 -プラグインソースリポジトリのmainブランチにコードをプッシュすると、GitHub Actionsは自動的に公開プロセスを実行します: +プラグインソースリポジトリのメインブランチにコードをプッシュすると、GitHub Actionsが自動的に公開プロセスを実行します: -* プラグインを`{plugin-name}-{version}.difypkg`形式で自動的にパッケージ化します -* パッケージファイルをターゲットリポジトリに自動的にプッシュします -* フォークリポジトリへのマージを自動的にPRで作成します +* プラグインを`{plugin-name}-{version}.difypkg`形式でパッケージング +* パッケージングされたファイルをターゲットリポジトリにプッシュ +* フォークリポジトリにマージするためのPRを作成 -![結果](https://assets-docs.dify.ai/2025/04/60d5de910c6ce2482c67ddec3320311f.png) +![Outcome](https://assets-docs.dify.ai/2025/04/60d5de910c6ce2482c67ddec3320311f.png) ### サンプルリポジトリ -完全な設定の詳細とベストプラクティスを理解するために、[サンプルリポジトリ](https://github.com/Yevanchen/exa-in-dify)を参照してください。\` +設定とベストプラクティスを理解するには、[サンプルリポジトリ](https://github.com/Yevanchen/exa-in-dify)を参照してください。 {/* Contributing Section @@ -311,5 +314,4 @@ It will be automatically generated by the script. --- -[このページを編集する](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-ja/0321-plugin-auto-publish-pr.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[このページを編集](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx) | [問題を報告](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/marketplace-listing/release-by-file.mdx b/ja/develop-plugin/publishing/marketplace-listing/release-by-file.mdx new file mode 100644 index 00000000..62b8f589 --- /dev/null +++ b/ja/develop-plugin/publishing/marketplace-listing/release-by-file.mdx @@ -0,0 +1,75 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: intermediate +standard_title: Release by File +language: en +title: ローカルファイルとしてパッケージ化して共有 +description: このドキュメントでは、Difyプラグインプロジェクトをローカルファイルとしてパッケージ化し、他のユーザーと共有する方法について詳細な手順を提供します。プラグインのパッケージ化前の準備作業、Difyプラグイン開発ツールを使用したパッケージ化コマンドの実行方法、生成された.difypkgファイルのインストール方法、および他のユーザーとプラグインファイルを共有する方法について説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/marketplace-listing/release-by-file)を参照してください。 + +プラグイン開発が完了したら、プラグインプロジェクトをローカルファイルとしてパッケージ化し、他のユーザーと共有できます。プラグインファイルを入手した後、Dify Workspaceにインストールできます。まだプラグインを開発していない場合は、[プラグイン開発:Hello Worldガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)を参照してください。 + +* **特徴**: + * オンラインプラットフォームに依存せず、**迅速で柔軟**なプラグイン共有方法。 + * **プライベートプラグイン**や**内部テスト**に適しています。 +* **公開プロセス**: + * プラグインプロジェクトをローカルファイルとしてパッケージ化。 + * Difyプラグインページでファイルをアップロードしてプラグインをインストール。 + +この記事では、プラグインプロジェクトをローカルファイルとしてパッケージ化する方法と、ローカルファイルを使用してプラグインをインストールする方法を紹介します。 + +### 前提条件 + +* **Difyプラグイン開発ツール**、詳細な手順については[開発ツールの初期化](/ja/develop-plugin/getting-started/cli)を参照してください。 + +設定後、ターミナルで`dify version`コマンドを入力し、バージョン情報が出力されることを確認して、必要な開発ツールがインストールされていることを確認してください。 + +### プラグインのパッケージ化 + +> プラグインをパッケージ化する前に、プラグインの`manifest.yaml`ファイルと`/provider`パス下の`.yaml`ファイルの`author`フィールドがGitHub IDと一致していることを確認してください。マニフェストファイルの詳細については、[一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)を参照してください。 + +プラグインプロジェクトの開発が完了したら、[リモートデバッグテスト](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)が完了していることを確認してください。プラグインプロジェクトの上位ディレクトリに移動し、以下のプラグインパッケージ化コマンドを実行します: + +```bash +dify plugin package ./your_plugin_project +``` + +コマンドを実行すると、現在のパスに`.difypkg`拡張子のファイルが生成されます。 + +![プラグインファイルの生成](https://assets-docs.dify.ai/2024/12/98e09c04273eace8fe6e5ac976443cca.png) + +### プラグインのインストール + +Difyプラグイン管理ページにアクセスし、右上の**プラグインをインストール** → **ローカルファイルから**をクリックしてインストールするか、プラグインファイルをページの空白部分にドラッグ&ドロップしてプラグインをインストールします。 + +![プラグインファイルのインストール](https://assets-docs.dify.ai/2024/12/8c31c4025a070f23455799f942b91a57.png) + +### プラグインの公開 + +プラグインファイルを他のユーザーと共有したり、インターネットにアップロードして他のユーザーがダウンロードできるようにできます。プラグインをより広く共有したい場合は、以下を検討してください: + +1. [個人GitHubリポジトリに公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo) - GitHubを通じてプラグインを共有 +2. [Dify Marketplaceに公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - 公式マーケットプレイスにプラグインを公開 + +## 関連リソース + +- [プラグインの公開](/ja/develop-plugin/publishing/marketplace-listing/release-overview) - さまざまな公開方法について学ぶ +- [開発ツールの初期化](/ja/develop-plugin/getting-started/cli) - プラグイン開発環境の設定 +- [プラグインのリモートデバッグ](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - プラグインのデバッグ方法を学ぶ +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - プラグインメタデータの定義 +- [プラグイン開発:Hello Worldガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - ゼロからプラグインを開発 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/marketplace-listing/release-overview.mdx b/ja/develop-plugin/publishing/marketplace-listing/release-overview.mdx new file mode 100644 index 00000000..bdac9307 --- /dev/null +++ b/ja/develop-plugin/publishing/marketplace-listing/release-overview.mdx @@ -0,0 +1,96 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: beginner +standard_title: Release Overview +language: en +title: プラグインの公開 +description: このドキュメントでは、Difyプラグインを公開する3つの方法(公式マーケットプレイス、オープンソースGitHubリポジトリ、ローカルプラグインファイルパッケージ)を紹介します。各方法の特徴、公開プロセス、適用シナリオを詳しく説明し、さまざまな開発者のニーズに対応するための具体的な公開推奨事項を提供します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/marketplace-listing/release-overview)を参照してください。 + +### 公開方法 + +さまざまな開発者の公開ニーズに対応するため、Difyは以下の3つのプラグイン公開方法を提供しています。公開する前に、プラグインの開発とテストが完了していること、および[プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin)と[プラグイン開発者ガイドライン](/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)を読んでいることを確認してください。 + +#### **1. マーケットプレイス** + +**概要**: Difyが提供する公式プラグインマーケットプレイスで、ユーザーはさまざまなプラグインを閲覧、検索し、ワンクリックでインストールできます。 + +**特徴**: + +* プラグインは公開前に審査され、**安全で信頼性が高い**ことが保証されます。 +* 個人またはチームの**ワークスペース**に直接インストールできます。 + +**公開プロセス**: + +* プラグインプロジェクトを**Difyマーケットプレイス**の[コードリポジトリ](https://github.com/langgenius/dify-plugins)に提出します。 +* 公式審査後、プラグインはマーケットプレイスで公開され、他のユーザーがインストールして使用できるようになります。 + +詳細な手順については、以下を参照してください: + +[Difyマーケットプレイスへの公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) + +#### 2. **GitHubリポジトリ** + +**概要**: **GitHub**でプラグインをオープンソース化またはホストし、他のユーザーが閲覧、ダウンロード、インストールできるようにします。 + +**特徴**: + +* **バージョン管理**と**オープンソース共有**に便利です。 +* ユーザーはプラグインリンクから直接インストールでき、プラットフォームの審査は不要です。 + +**公開プロセス**: + +* プラグインコードをGitHubリポジトリにプッシュします。 +* リポジトリリンクを共有し、ユーザーはリンクを通じてプラグインを**Difyワークスペース**に統合できます。 + +詳細な手順については、以下を参照してください: + +[個人のGitHubリポジトリへの公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo) + +#### 3. プラグインファイルパッケージ(ローカルインストール) + +**概要**: プラグインをローカルファイル(`.difypkg`形式など)としてパッケージ化し、他のユーザーがインストールできるように共有します。 + +**特徴**: + +* オンラインプラットフォームに依存せず、**迅速で柔軟な**プラグイン共有方法です。 +* **プライベートプラグイン**や**内部テスト**に適しています。 + +**公開プロセス**: + +* プラグインプロジェクトをローカルファイルとしてパッケージ化します。 +* Difyプラグインページで**プラグインをアップロード**をクリックし、ローカルファイルを選択してプラグインをインストールします。 + +プラグインプロジェクトをローカルファイルとしてパッケージ化し、他のユーザーと共有できます。プラグインページでファイルをアップロードすると、Difyワークスペースにプラグインをインストールできます。 + +詳細な手順については、以下を参照してください: + +[ローカルファイルとしてパッケージ化して共有](/ja/develop-plugin/publishing/marketplace-listing/release-by-file) + +### **公開の推奨事項** + +* **プラグインを宣伝したい場合** → **マーケットプレイスの使用を推奨**、公式審査によりプラグインの品質を確保し、露出を増やします。 +* **オープンソース共有プロジェクト** → **GitHubの使用を推奨**、バージョン管理とコミュニティコラボレーションに便利です。 +* **迅速な配布または内部テスト** → **プラグインファイルの使用を推奨**、シンプルで効率的なインストールと共有方法です。 + +## 関連リソース + +- [プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin) - Difyプラグイン開発を包括的に理解する +- [プラグイン開発者ガイドライン](/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - プラグイン提出の基準を理解する +- [プラグインプライバシーデータ保護ガイド](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines) - プライバシーポリシー作成の要件を理解する +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - プラグインマニフェストファイルの設定を理解する + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-overview.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx b/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx new file mode 100644 index 00000000..2e80bfdd --- /dev/null +++ b/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx @@ -0,0 +1,113 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: intermediate +standard_title: Release to Dify Marketplace +language: en +title: Dify Marketplaceへの公開 +description: このガイドでは、Dify Marketplaceへのプラグイン公開の完全なプロセスについて、PRの提出、レビュープロセス、リリース後のメンテナンス、その他の重要なステップと考慮事項を含めて詳細に説明します。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace)を参照してください。 + +Dify Marketplaceは、パートナーやコミュニティ開発者からのプラグイン提出を歓迎します。皆様の貢献は、Difyプラグインの可能性をさらに豊かにします。このガイドでは、明確な公開プロセスとベストプラクティスの推奨事項を提供し、プラグインがスムーズに公開され、コミュニティに価値をもたらすことを支援します。まだプラグインを開発していない場合は、[プラグイン開発:Hello Worldガイド](/ja/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)を参照してください。 + +以下の手順に従って、プラグインのPull Request(PR)を[GitHubリポジトリ](https://github.com/langgenius/dify-plugins)に提出し、レビューを受けてください。承認後、プラグインはDify Marketplaceに正式に公開されます。 + +### プラグイン公開プロセス + +Dify Marketplaceへのプラグイン公開には、以下のステップが含まれます: + +1. [プラグイン開発者ガイドライン](/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)に従って、プラグインの開発とテストを完了する; +2. [プラグインプライバシーデータ保護ガイド](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines)に従ってプラグインのプライバシーポリシーを作成し、プライバシーポリシーのファイルパスまたはURLをプラグインの[一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)に含める; +3. プラグインのパッケージングを完了する; +4. [Dify Plugins](https://github.com/langgenius/dify-plugins)コードリポジトリをフォークする; +5. リポジトリに個人または組織のフォルダを作成し、パッケージ化された`.difypkg`ファイルをフォルダにアップロードする; +6. GitHubのPRテンプレート形式に従ってPull Request(PR)を提出し、レビューを待つ; +7. レビューが承認されると、プラグインコードがMainブランチにマージされ、プラグインは自動的に[Dify Marketplace](https://marketplace.dify.ai/)に公開されます。 + +プラグインの提出、レビュー、公開のフローチャート: + +![プラグインアップロードのプロセス](https://assets-docs.dify.ai/2025/01/05df333acfaf662e99316432db23ba9f.png) + +> **注意**:上記の図のContributor Agreement(貢献者同意書)は、[プラグイン開発者ガイドライン](/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)を指します。 + +*** + +### Pull Request(PR)レビュー中 + +レビュアーの質問やフィードバックに積極的に対応してください: + +* **14日以内**に解決されないPRコメントは、stale(古い)としてマークされます(再開可能)。 +* **30日以内**に解決されないPRコメントは、クローズされます(再開不可、新しいPRを作成する必要があります)。 + +*** + +### **Pull Request(PR)承認後** + +**1. 継続的なメンテナンス** + +* ユーザーから報告された問題や機能リクエストに対応する。 +* 重大なAPI変更が発生した場合はプラグインを移行する: + * Difyは事前に変更通知と移行手順を公開します。 + * Difyエンジニアが移行サポートを提供できます。 + +**2. Marketplaceパブリックベータテスト段階での制限** + +* 既存のプラグインに破壊的変更を導入しないでください。 + +*** + +### レビュープロセス + +**1. レビュー順序** + +* PRは**先着順**で処理されます。レビューは1週間以内に開始されます。遅延がある場合、レビュアーはコメントを通じてPR作成者に通知します。 + +**2. レビューの焦点** + +* プラグイン名、説明、セットアップ手順が明確で説明的かどうかを確認する。 +* プラグインの[一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)が形式基準を満たし、有効な作成者連絡先情報が含まれているかを確認する。 + +**3. プラグインの機能と関連性** + +* [プラグイン開発ガイド](/ja/develop-plugin/getting-started/getting-started-dify-plugin)に従ってプラグインをテストする。 +* プラグインがDifyエコシステムで合理的な目的を持っていることを確認する。 + +[Dify.AI](https://dify.ai/)は、プラグイン提出を承認または拒否する権利を留保します。 + +*** + +### よくある質問 + +1. **プラグインがユニークかどうかをどのように判断しますか?** + +例:多言語バージョンのみを追加するGoogle検索プラグインは、既存プラグインの最適化と見なすべきです。ただし、プラグインが重要な機能改善(最適化されたバッチ処理やエラーハンドリングなど)を実装している場合は、新しいプラグインとして提出できます。 + +2. **PRがstaleまたはクローズとしてマークされた場合はどうすればよいですか?** + +staleとマークされたPRは、フィードバックに対応した後に再開できます。クローズされたPR(30日以上)は、新しいPRを作成する必要があります。 + +3. **ベータテスト段階中にプラグインを更新できますか?** + +はい、ただし破壊的変更は避けるべきです。 + +## 関連リソース + +- [プラグインの公開](/ja/develop-plugin/publishing/marketplace-listing/release-overview) - さまざまな公開方法について学ぶ +- [プラグイン開発者ガイドライン](/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - プラグイン提出基準 +- [プラグインプライバシーデータ保護ガイド](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines) - プライバシーポリシー作成要件 +- [ローカルファイルとしてパッケージ化して共有](/ja/develop-plugin/publishing/marketplace-listing/release-by-file) - プラグインのパッケージング方法 +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - プラグインメタデータの定義 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx b/ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx new file mode 100644 index 00000000..6c755747 --- /dev/null +++ b/ja/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx @@ -0,0 +1,92 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: intermediate +standard_title: Release to Individual GitHub Repo +language: en +title: 個人GitHubリポジトリへの公開 +description: このドキュメントでは、Difyプラグインを個人のGitHubリポジトリに公開する方法について、準備作業、ローカルプラグインリポジトリの初期化、リモートリポジトリへの接続、プラグインファイルのアップロード、プラグインコードのパッケージング、およびGitHub経由でのプラグインインストールの完全なプロセスを含む詳細な手順を提供します。この方法により、開発者は自分のプラグインコードと更新を完全に管理できます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo)を参照してください。 + +### 公開方法 + +開発者のさまざまな公開ニーズに対応するため、Difyは3つのプラグイン公開方法を提供しています: + +#### **1. マーケットプレイス** + +**概要**: Dify公式プラグインマーケットプレイスでは、ユーザーがさまざまなプラグインを閲覧、検索し、ワンクリックでインストールできます。 + +**特徴**: + +* プラグインは審査を通過した後に利用可能になり、**信頼性**と**高品質**が保証されます。 +* 個人またはチームの**ワークスペース**に直接インストールできます。 + +**公開プロセス**: + +* プラグインプロジェクトを**Dify Marketplace**の[コードリポジトリ](https://github.com/langgenius/dify-plugins)に提出します。 +* 公式審査の後、プラグインはマーケットプレイスで公開され、他のユーザーがインストールして使用できるようになります。 + +詳細な手順については、以下を参照してください: + + + + +#### 2. **GitHubリポジトリ** + +**概要**: プラグインを**GitHub**でオープンソース化またはホストすることで、他のユーザーが簡単に閲覧、ダウンロード、インストールできます。 + +**特徴**: + +* **バージョン管理**と**オープンソース共有**に便利です。 +* ユーザーはプラットフォームの審査を経ずに、リンクから直接プラグインをインストールできます。 + +**公開プロセス**: + +* プラグインコードをGitHubリポジトリにプッシュします。 +* リポジトリリンクを共有し、ユーザーはリンクを通じてプラグインを**Difyワークスペース**に統合できます。 + +詳細な手順については、以下を参照してください: + + + + +#### プラグインファイル(ローカルインストール) + +**概要**: プラグインをローカルファイル(例:`.difypkg`形式)としてパッケージ化し、他のユーザーがインストールできるように共有します。 + +**特徴**: + +* オンラインプラットフォームに依存せず、**迅速かつ柔軟**にプラグインを共有できます。 +* **プライベートプラグイン**や**内部テスト**に適しています。 + +**公開プロセス**: + +* プラグインプロジェクトをローカルファイルとしてパッケージ化します。 +* Difyプラグインページで**プラグインをアップロード**をクリックし、ローカルファイルを選択してプラグインをインストールします。 + +プラグインプロジェクトをローカルファイルとしてパッケージ化し、他のユーザーと共有できます。プラグインページでファイルをアップロードすると、プラグインをDifyワークスペースにインストールできます。 + +詳細な手順については、以下を参照してください: + + + + +### **公開に関する推奨事項** + +* **プラグインを宣伝したい場合** → **マーケットプレイスの使用を推奨**、公式審査によりプラグインの品質を確保し、露出を増やせます。 +* **オープンソース共有プロジェクト** → **GitHubの使用を推奨**、バージョン管理とコミュニティコラボレーションに便利です。 +* **迅速な配布または内部テスト** → **プラグインファイルの使用を推奨**、シンプルで効率的なインストールと共有が可能です。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx b/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx new file mode 100644 index 00000000..469372da --- /dev/null +++ b/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx @@ -0,0 +1,173 @@ +--- +dimensions: + type: + primary: operational + detail: setup + level: intermediate +standard_title: Contributor Covenant Code of Conduct +language: en +title: プラグイン開発ガイドライン +description: Dify Marketplaceのすべてのプラグインの品質を確保し、Dify Marketplaceユーザーに一貫した高品質な体験を提供するため、プラグインを審査に提出する際には、これらのプラグイン開発ガイドラインに記載されているすべての要件を遵守する必要があります。プラグインを提出することにより、**以下のすべての条項を読み、理解し、遵守することに同意したものとみなされます**。これらのガイドラインに従うことで、プラグインの審査がより迅速に行われます。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)を参照してください。 + +## 1. プラグインの価値と独自性 + +- **生成AIに焦点を当てる**: プラグインのコア機能が生成AI領域に焦点を当て、Difyユーザーに明確で重要な価値を提供することを確認してください。これには以下が含まれます: + - 新しいモデル、ツール、またはサービスの統合。 + - AIアプリケーションを強化するための独自のデータソースまたは処理機能の提供。 + - Difyプラットフォームでのワークフローの簡素化または自動化。 + - AIアプリケーション開発のための革新的なサポート機能の提供。 + +- **機能の重複を避ける**: 提出されるプラグインは、Marketplace内の既存のプラグインと重複または類似しては**なりません**。公開される各プラグインは、ユーザーに最高の体験を提供するために、独自で独立したものでなければなりません。 + +- **意味のある更新**: プラグインの更新では、現在のバージョンにはない**新しい機能やサービス**が導入されていることを確認してください。 + +- **PRの提出に関するアドバイス**: プルリクエストには、新しいプラグインが必要な理由を明確にする簡単な説明を含めることを**推奨**します。 + +## 2. プラグイン機能チェックリスト + +- **ユニークな名前**: 事前にプラグインディレクトリを検索して、プラグイン名がユニークであることを確認してください。 + +- **ブランドの整合性**: プラグイン名はプラグインのブランディングと一致する必要があります。 + +- **機能の検証**: 提出前にプラグインを徹底的にテストし、意図したとおりに動作することを確認してください。詳細については、[プラグインのリモートデバッグ](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)を参照してください。プラグインは本番環境に対応している必要があります。 + +- **README要件**: + - セットアップ手順と使用ガイダンス。 + - プラグインに接続するために必要なコード、API、認証情報、または情報。 + - 無関係なコンテンツやリンクを含めては**なりません**。 + - 誇大な宣伝文句や検証不可能な主張を使用しては**なりません**。 + - いかなる種類の広告も含めては**なりません**(自己宣伝やディスプレイ広告を含む)。 + - 誤解を招く、攻撃的な、または名誉毀損的なコンテンツを含めては**なりません**。 + - スクリーンショットに実際のユーザー名やデータを公開しては**なりません**。 + - 404ページやエラーを返すページへのリンクを含めては**なりません**。 + - 過度なスペルミスや句読点の誤りを避けてください。 + +- **ユーザーデータの使用**: 収集したデータは、サービスへの接続とプラグイン機能の改善のためにのみ使用してください。 + +- **エラーの明確さ**: 必須フィールドをマークし、ユーザーが問題を理解するのに役立つ明確なエラーメッセージを提供してください。 + +- **認証設定**: 認証が必要な場合は、完全な設定手順を含めてください—省略しないでください。 + +- **プライバシーポリシー**: [プライバシーガイドライン](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines)に従って、プライバシーポリシードキュメントまたはオンラインURLを準備してください。 + +- **パフォーマンス**: プラグインは効率的に動作する必要があり、Difyやユーザーシステムのパフォーマンスを低下させてはなりません。 + +- **認証情報のセキュリティ**: APIキーやその他の認証情報は、安全に保存および送信する必要があります。ハードコーディングしたり、権限のない第三者に公開したりしないでください。 + + +## 3. 言語要件 + +- **英語を主要言語とする**: Dify Marketplaceはグローバルなユーザーにサービスを提供しているため、すべてのユーザー向けテキスト(プラグイン名、説明、フィールド名、ラベル、ヘルプテキスト、エラーメッセージ)の**主要言語は英語**でなければなりません。 + +- **多言語サポートを推奨**: 複数言語のサポートを推奨します。 + + +## 4. 禁止および制限されるプラグイン + +- **禁止: 誤解を招くまたは悪意のある行為** + プラグインはユーザーを誤解させてはなりません。スパム、フィッシング、または迷惑メッセージの送信を目的としたプラグインを作成しないでください。審査プロセスを欺こうとしたり、ユーザーデータを盗んだり、ユーザーになりすましたりする試みは、削除および将来の提出禁止につながる可能性があります。 + +- **禁止: 攻撃的なコンテンツ** + プラグインには、暴力的なコンテンツ、ヘイトスピーチ、差別、またはグローバルな文化、宗教、ユーザーに対する不敬を含めてはなりません。 + +- **禁止: 金融取引** + プラグインは、金融取引、資産移転、または決済処理を促進してはなりません。これには、ブロックチェーン/暗号アプリケーションにおけるトークンまたは資産の所有権移転が含まれます。 + +- **制限: 頻繁な欠陥を持つプラグイン** + 重大なバグを避けるために、プラグインを徹底的にテストしてください。欠陥のある提出を繰り返すと、遅延やペナルティにつながる可能性があります。 + +- **制限: 不必要なプラグイン分割** + 各プラグインが明確にスタンドアロンの製品またはサービスでない限り、同じAPIと認証を共有する機能のために複数のプラグインを作成しないでください。機能を1つの高レベルプラグインに統合することを推奨します。 + +- **制限: 重複提出** + 本質的に同一のプラグインを繰り返し提出することは避けてください。そうすると、審査が遅れたり、拒否されたりする可能性があります。 + +## 5. プラグインの収益化 + +- **Dify Marketplaceは現在、**無料**のプラグインのみをサポートしています。 + +- **将来のポリシー**: 収益化と価格モデルに関するポリシーは、将来発表される予定です。 + +## 6. 商標と知的財産 + +- **許可が必要**: 提出するロゴや商標を使用する権利があることを確認してください。 + +- **検証権**: サードパーティのロゴが使用されている場合—特に明らかに有名なブランドに属している場合—許可があることを証明するよう求める場合があります。 + +- **違反の結果**: 無許可の使用が発見された場合、Difyは変更を求めるか、プラグインを削除する権利を留保します。権利者からの苦情も削除につながる可能性があります。 + +- **Difyロゴの使用禁止**: Dify自体のロゴを使用することはできません。 + +- **画像の基準**: 低品質、歪んだ、またはトリミングが不適切な画像を提出しないでください。審査チームは交換を求める場合があります。 + +- **アイコンの制限**: アイコンには、誤解を招く、攻撃的な、または悪意のあるビジュアルを含めてはなりません。 + + + +## 7. プラグインの更新とバージョン管理 + +- **責任ある更新**: 説明または外部チャネル(例:GitHub Release Notes)を通じて、破壊的な変更を明確に伝えてください。 + +- **メンテナンスの推奨**: バグの修正、Difyプラットフォームの変更への対応、またはサードパーティサービスからの更新への対応—特にセキュリティに関して—のために定期的に更新してください。 + +- **廃止通知**: プラグインを廃止する場合は、事前にユーザーに通知し(例:プラグインの説明にタイムラインと計画を記載)、利用可能な場合は代替案を提案してください。 + + +## 8. プラグインのメンテナンスとサポート + +- **オーナーの責任**: プラグインオーナーは、技術サポートとメンテナンスに責任を負います。 + +- **サポートチャネルが必要**: オーナーは、審査および公開中のフィードバックのために、**少なくとも1つ**のサポートチャネル(GitHubリポジトリまたはメール)を提供する必要があります。 + +- **メンテナンスされていないプラグインの処理**: プラグインにメンテナンスがなく、オーナーが合理的な通知後も応答しない場合、Difyは以下を行う可能性があります: + - 「メンテナンス不足」または「潜在的リスク」タグを追加する。 + - 新規インストールを制限する。 + - 最終的にプラグインを非公開にする。 + + +## 9. プライバシーとデータコンプライアンス + +- **開示が必要**: プラグインがユーザーの個人データを収集するかどうかを**宣言する必要があります**。[プライバシーガイドライン](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines)を参照してください。 + +- **シンプルなデータリスト**: データを収集する場合は、種類を簡潔にリストしてください(例:ユーザー名、メール、デバイスID、位置情報)。網羅的な詳細は必要ありません。 + +- **プライバシーポリシー**: 以下を記載したプライバシーポリシーリンクを**提供する必要があります**: + - どのような情報が収集されるか。 + - どのように使用されるか。 + - 第三者と何が共有されるか(該当する場合は、そのプライバシーリンクも含む)。 + +- **審査の焦点**: + - **形式チェック**: 収集するデータを宣言していることを確認します。 + - **機密データスキャン**: 機密データ(例:健康、金融、子供の情報)を収集するプラグインには追加の精査が必要です。 + - **悪意のある行為のスキャン**: プラグインは、同意なしにユーザーデータを収集またはアップロードしてはなりません。 + +--- + +## 10. 審査と裁量 + +- **拒否/削除の権利**: 要件、プライバシー基準、または関連ポリシーが満たされていない場合、Difyはプラグインを拒否または削除する可能性があります。これには、審査プロセスの悪用やデータの誤用が含まれます。 + +- **適時な審査**: Dify審査チームは、ボリュームと複雑さに応じて、妥当な時間内にプラグインを審査することを目指します。 + +- **コミュニケーション**: 提供されたサポートチャネルを通じて連絡する場合があります—アクティブであることを確認してください。 + +## 関連リソース + +- [プラグイン開発の基本概念](/ja/develop-plugin/getting-started/getting-started-dify-plugin) - プラグイン開発の基本を学ぶ +- [プラグインの公開](/ja/develop-plugin/publishing/marketplace-listing/release-overview) - プラグイン公開プロセスの概要 +- [プラグインプライバシーデータ保護ガイド](/ja/develop-plugin/publishing/standards/privacy-protection-guidelines) - プライバシーポリシー作成ガイド +- [Dify Marketplaceへの公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - 公式マーケットプレイスでプラグインを公開 +- [プラグインのリモートデバッグ](/ja/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - プラグインデバッグガイド + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx b/ja/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx new file mode 100644 index 00000000..d11d90da --- /dev/null +++ b/ja/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx @@ -0,0 +1,102 @@ +--- +dimensions: + type: + primary: operational + detail: setup + level: intermediate +standard_title: Privacy Protection Guidelines +language: en +title: プラグインプライバシーポリシーガイドライン +description: このドキュメントは、開発者がDify Marketplaceにプラグインを提出する際のプライバシーポリシーの書き方に関するガイドラインを説明します。収集する個人データの種類(直接識別情報、間接識別情報、組み合わせ情報)の特定とリストアップ方法、プラグインプライバシーポリシーの記入方法、Manifestファイルへのプライバシーポリシー声明の含め方、および関連するよくある質問への回答が含まれています。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/standards/privacy-protection-guidelines)を参照してください。 + +プラグインをDify Marketplaceに提出する際は、ユーザーデータの取り扱い方法について透明性を持つ必要があります。以下のガイドラインは、プラグインのプライバシー関連の質問とユーザーデータ処理への対応方法に焦点を当てています。 + +プライバシーポリシーは以下のポイントを中心に作成してください: + +**プラグインはユーザーの個人データを収集・使用しますか?** 収集する場合は、収集するデータの種類をリストアップしてください。 + +> 「個人データ」とは、特定の個人を識別できる情報を指します。単独で、または他のデータと組み合わせることで、特定の個人を特定、連絡、またはターゲットにするために使用される情報です。 + +#### 1. 収集するデータの種類をリストアップする + +**タイプA:** **直接識別子** + +* 氏名(例:フルネーム、名、姓) +* メールアドレス +* 電話番号 +* 自宅住所またはその他の物理的住所 +* 政府発行の識別番号(例:社会保障番号、パスポート番号、運転免許証番号) + +**タイプB**: **間接識別子** + +* デバイス識別子(例:IMEI、MACアドレス、デバイスID) +* IPアドレス +* 位置データ(例:GPS座標、市区町村、地域) +* オンライン識別子(例:クッキー、広告ID) +* ユーザー名 +* プロフィール写真 +* 生体データ(例:指紋、顔認識データ) +* ウェブ閲覧履歴 +* 購入履歴 +* 健康情報 +* 財務情報 + +**タイプC: 他のデータと組み合わせて個人を識別できるデータ:** + +* 年齢 +* 性別 +* 職業 +* 興味・関心 + +プラグインが個人情報を収集しない場合でも、プラグイン内でのサードパーティサービスの使用がデータ収集や処理を伴う可能性があることを確認する必要があります。プラグイン開発者として、サードパーティサービスによって実行されるものを含め、プラグインに関連するすべてのデータ収集活動を開示する責任があります。したがって、サードパーティサービスのプライバシーポリシーを十分に読み、プラグインによって収集されるデータが提出時に申告されていることを確認してください。 + +例えば、開発中のプラグインがSlackサービスを使用する場合は、プラグインのプライバシーポリシー声明で[Slackのプライバシーポリシー](https://slack.com/trust/privacy/privacy-policy)を参照し、データ収集の慣行を明確に開示してください。 + +#### **2. プラグインの最新のプライバシーポリシーを提出する** + +**プライバシーポリシー**には以下を含める必要があります: + +* 収集するデータの種類 +* 収集したデータの使用方法 +* データがサードパーティと共有されるかどうか、共有される場合はそのサードパーティを特定し、そのプライバシーポリシーへのリンクを提供する +* プライバシーポリシーの書き方がわからない場合は、Difyチームが発行したプラグインのプライバシーポリシーを参考にすることもできます。 + +#### 3. プラグインManifestファイル内にプライバシーポリシー声明を導入する + +特定のフィールドの記入に関する詳細な手順については、[一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications)ドキュメントを参照してください。 + +**よくある質問** + +1. **ユーザーの個人データに関する「収集と使用」とはどういう意味ですか?プラグインで個人データが収集・使用される一般的な例はありますか?** + +ユーザーデータの「収集と使用」とは、一般的にユーザーデータの収集、送信、使用、または共有を指します。製品が個人データまたは機密ユーザーデータを処理する一般的な例には以下が含まれます: + +* 個人を特定できる情報を収集するフォームの使用 +* サードパーティ認証サービスを使用する場合でも、ログイン機能の実装 +* 個人を特定できる情報を含む可能性のある入力やリソースに関する情報の収集 +* ユーザーの行動、インタラクション、使用パターンを追跡するアナリティクスの実装 +* メッセージ、チャットログ、メールアドレスなどの通信データの保存 +* 接続されたソーシャルメディアアカウントからのユーザープロフィールやデータへのアクセス +* 活動レベル、心拍数、医療情報などの健康・フィットネスデータの収集 +* 検索クエリの保存やブラウジング行動の追跡 +* 銀行口座情報、信用スコア、取引履歴などの財務情報の処理 + +## 関連リソース + +- [公開の概要](/ja/develop-plugin/publishing/marketplace-listing/release-overview) - プラグイン公開プロセスを理解する +- [Dify Marketplaceへの公開](/ja/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - 公式マーケットプレイスへのプラグイン提出方法を学ぶ +- [プラグイン開発者ガイドライン](/ja/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - プラグイン提出ガイドラインを理解する +- [一般仕様](/ja/develop-plugin/features-and-specs/plugin-types/general-specifications) - プラグインメタデータ設定 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/develop-plugin/publishing/standards/third-party-signature-verification.mdx b/ja/develop-plugin/publishing/standards/third-party-signature-verification.mdx new file mode 100644 index 00000000..29c8b85d --- /dev/null +++ b/ja/develop-plugin/publishing/standards/third-party-signature-verification.mdx @@ -0,0 +1,120 @@ +--- +dimensions: + type: + primary: operational + detail: setup + level: intermediate +standard_title: Third-Party Signature Verification +language: ja +title: サードパーティ署名検証用のプラグイン署名 +description: このドキュメントでは、Dify Community Editionでサードパーティ署名検証機能を有効化して使用する方法について説明します。キーペアの生成、プラグインの署名と検証、環境設定の手順を含み、管理者がDify Marketplaceで入手できないプラグインを安全にインストールできるようにします。 +--- + + ⚠️ このドキュメントはAIによって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/publishing/standards/third-party-signature-verification)を参照してください。 + +--- +title: +--- + +この機能はDify Community Editionでのみ利用可能です。サードパーティ署名検証は現在Dify Cloud Editionではサポートされていません。 + +サードパーティ署名検証により、Dify管理者は署名検証を完全に無効化することなく、Dify Marketplaceに掲載されていないプラグインのインストールを安全に承認できます。これは例えば以下のシナリオをサポートします: + +* Dify管理者は、開発者から送信されたプラグインを承認後、署名を追加できます。 +* プラグイン開発者は、自分のプラグインに署名を追加し、署名検証を無効化できないDify管理者向けに公開鍵と一緒に公開できます。 + +Dify管理者とプラグイン開発者の両方が、事前に生成されたキーペアを使用してプラグインに署名を追加できます。さらに、管理者はプラグインのインストール時に特定の公開鍵を使用した署名検証を強制するようにDifyを設定できます。 + +## 署名と検証用のキーペア生成 + +プラグインの署名を追加および検証するための新しいキーペアを以下のコマンドで生成します: + +```bash +dify signature generate -f your_key_pair +``` + +このコマンドを実行すると、現在のディレクトリに2つのファイルが生成されます: + +* **秘密鍵**: `your_key_pair.private.pem` +* **公開鍵**: `your_key_pair.public.pem` + +秘密鍵はプラグインの署名に使用し、公開鍵はプラグインの署名検証に使用します。 + +秘密鍵は安全に保管してください。漏洩した場合、攻撃者が任意のプラグインに有効な署名を追加でき、Difyのセキュリティが侵害される可能性があります。 + +## プラグインへの署名追加と検証 + +以下のコマンドを実行してプラグインに署名を追加します。**署名するプラグインファイル**と**秘密鍵**を指定する必要があることに注意してください: + +```bash +dify signature sign your_plugin_project.difypkg -p your_key_pair.private.pem +``` + +コマンドを実行すると、同じディレクトリに元のファイル名に`signed`が追加された新しいプラグインファイルが生成されます:`your_plugin_project.signed.difypkg` + +このコマンドを使用して、プラグインが正しく署名されていることを検証できます。ここでは、**署名済みプラグインファイル**と**公開鍵**を指定する必要があります: + +```bash +dify signature verify your_plugin_project.signed.difypkg -p your_key_pair.public.pem +``` + +公開鍵引数を省略した場合、検証にはDify Marketplace公開鍵が使用されます。その場合、Dify Marketplaceからダウンロードされていないプラグインファイルでは署名検証が失敗します。 + +## サードパーティ署名検証の有効化 + +Dify管理者は、プラグインをインストールする前に、事前承認された公開鍵を使用した署名検証を強制できます。 + +### 公開鍵の配置 + +署名に使用した秘密鍵に対応する**公開鍵**を、プラグインデーモンがアクセスできる場所に配置します。 + +例えば、`docker/volumes/plugin_daemon`の下に`public_keys`ディレクトリを作成し、公開鍵ファイルをそこにコピーします: + +```bash +mkdir docker/volumes/plugin_daemon/public_keys +cp your_key_pair.public.pem docker/volumes/plugin_daemon/public_keys +``` + +### 環境変数の設定 + +`plugin_daemon`コンテナで、以下の環境変数を設定します: + +* `THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED` + * サードパーティ署名検証を有効にします。 + * 機能を有効にするには`true`に設定します。 +* `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` + * 署名検証に使用する公開鍵ファイルのパスを指定します。 + * カンマで区切って複数の公開鍵ファイルをリストできます。 + +以下は、これらの変数を設定するDocker Composeオーバーライドファイル(`docker-compose.override.yaml`)の例です: + +```yaml +services: + plugin_daemon: + environment: + FORCE_VERIFYING_SIGNATURE: true + THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED: true + THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS: /app/storage/public_keys/your_key_pair.public.pem +``` + +`docker/volumes/plugin_daemon`は`plugin_daemon`コンテナ内の`/app/storage`にマウントされることに注意してください。`THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS`で指定するパスがコンテナ内のパスに対応していることを確認してください。 + +これらの変更を適用するには、Difyサービスを再起動します: + +```bash +cd docker +docker compose down +docker compose up -d +``` + +サービスを再起動すると、現在のCommunity Edition環境でサードパーティ署名検証機能が有効になります。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/third-party-signature-verification.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/ja/use-dify/nodes/trigger/plugin-trigger.mdx b/ja/use-dify/nodes/trigger/plugin-trigger.mdx index 255e0032..3026c746 100644 --- a/ja/use-dify/nodes/trigger/plugin-trigger.mdx +++ b/ja/use-dify/nodes/trigger/plugin-trigger.mdx @@ -17,7 +17,7 @@ title: プラグイントリガー workflow キャンバスで右クリックし、**ブロックを追加** > **始める** を選択してから、利用可能なプラグイントリガーの中から選択するか、[Dify Marketplace](https://marketplace.dify.ai/?language=jp-ja&category=trigger) でさらに検索します。 - - 対象の外部システムに適切なトリガープラグインがない場合は、[コミュニティにリクエスト](https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml)したり、[自分で開発](/plugin-dev-ja/0222-trigger-plugin)したり、代わりに [Webhook トリガー](/ja/use-dify/nodes/trigger/webhook-trigger)を使用したりできます。 + - 対象の外部システムに適切なトリガープラグインがない場合は、[コミュニティにリクエスト](https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml)したり、[自分で開発](/ja/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin)したり、代わりに [Webhook トリガー](/ja/use-dify/nodes/trigger/webhook-trigger)を使用したりできます。 - 1 つの workflow は、並行して実行される複数のプラグイントリガーで開始できます。並行分岐に同一の連続したノードが含まれている場合、共通セクションの前に[変数集約](/ja/use-dify/nodes/variable-aggregator)ノードを追加して分岐をマージできます。これにより、各分岐で同じノードを個別に重複して追加することを回避できます。 diff --git a/plugin-dev-en/9231-extension-plugin.mdx b/plugin-dev-en/9231-extension-plugin.mdx deleted file mode 100644 index ae264c29..00000000 --- a/plugin-dev-en/9231-extension-plugin.mdx +++ /dev/null @@ -1,298 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: high - level: beginner -standard_title: Extension Plugin -language: en -title: Extension Plugin -description: This document provides a complete tutorial for developing Extension type - plugins, detailing the entire process including environment preparation, project - creation, defining plugin request entry points, writing functional code, debugging, - packaging, and publishing. The example project is a Nyan Cat plugin that demonstrates - how to handle HTTP requests and provide web services through an Extension plugin. ---- - -This article will guide you through quickly developing an Extension type plugin to help you understand the basic plugin development process. - -### Prerequisites - -* Dify plugin scaffolding tool -* Python environment, version ≥ 3.12 - -For detailed instructions on preparing the plugin development scaffolding tool, please refer to [Initializing Development Tools](/plugin-dev-en/0221-initialize-development-tools). - -### Creating a New Project - -In the current path, run the scaffolding command line tool to create a new Dify plugin project. - -``` -./dify-plugin-darwin-arm64 plugin init -``` - -If you have renamed the binary file to `dify` and copied it to the `/usr/local/bin` path, you can run the following command to create a new plugin project: - -```bash -dify plugin init -``` - -#### 1. Filling in Plugin Information - -Follow the prompts to configure the plugin name, author information, and plugin description. If you are working collaboratively as a team, you can also enter an organization name as the author. - -> The plugin name must be 1-128 characters long and can only contain letters, numbers, hyphens, and underscores. - -![Plugins details](https://assets-docs.dify.ai/2024/12/75cfccb11fe31c56c16429b3998f2eb0.png) - -Once completed, select Python as the plugin development language. - -![Plugins development: Python](https://assets-docs.dify.ai/2024/11/1129101623ac4c091a3f6f75f4103848.png) - -#### 2. Select Plugin Type and Initialize Project Template - -All templates in the scaffolding tool provide complete code projects. For demonstration purposes, this article will use the `Extension` type plugin template as an example. For developers already familiar with plugin development, templates are not necessary, and you can refer to the [interface documentation](/plugin-dev-en/0411-general-specifications) to guide the development of different types of plugins. - -![Extension](https://assets-docs.dify.ai/2024/11/ff08f77b928494e10197b456fc4e2d5b.png) - -#### 3. Configure Plugin Permissions - -The plugin also needs permissions to read from the Dify main platform to connect properly. Grant the following permissions to this example plugin: - -* Tools -* LLMs -* Apps -* Enable persistent storage Storage, allocate default size storage -* Allow registering Endpoints - -> Use the arrow keys in the terminal to select permissions, and use the "Tab" button to grant permissions. - -After checking all permission items, press Enter to complete the plugin creation. The system will automatically generate the plugin project code. - -![Plugins permissions](https://assets-docs.dify.ai/2024/11/5518ca1e425a7135f18f499e55d16bdd.png) - -The basic file structure of the plugin includes the following: - -``` -. -├── GUIDE.md -├── README.md -├── _assets -│ └── icon.svg -├── endpoints -│ ├── your-project.py -│ └── your-project.yaml -├── group -│ └── your-project.yaml -├── main.py -├── manifest.yaml -└── requirements.txt -``` - -* `GUIDE.md` A short tutorial guiding you through the plugin writing process. -* `README.md` Brief introduction about the current plugin, where you need to fill in the introduction and usage instructions for the plugin. -* `_assets` Stores all multimedia files related to the current plugin. -* `endpoints` An `Extension` type plugin template created according to the CLI guidance, this directory stores all Endpoint implementation code. -* `group` Specifies the key type, multilingual settings, and the file path of the API definition. -* `main.py` The entry file for the entire project. -* `manifest.yaml` The basic configuration file for the entire plugin, containing configuration information such as what permissions the plugin needs and what type of extension it is. -* `requirements.txt` Stores Python environment dependencies. - -### Developing the Plugin - -#### 1. Define the Plugin's Request Entry Point (Endpoint) - -Edit `endpoints/test_plugin.yaml`, referring to the following code for modification: - -```yaml -path: "/neko" -method: "GET" -extra: - python: - source: "endpoints/test_plugin.py" -``` - -The intent of this code is to define the entry path for the plugin as `/neko`, with the request method as GET type. The plugin's functional implementation code is in the `endpoints/test_plugin.py` file. - -#### 2. Write Plugin Functionality - -Plugin functionality: Request service, output a Nyan Cat. - -Write the plugin's functional implementation code in the `endpoints/test_plugin.py` file, referring to the following example code: - -```python -from typing import Mapping -from werkzeug import Request, Response -from flask import Flask, render_template_string -from dify_plugin import Endpoint - -app = Flask(__name__) - -class NekoEndpoint(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - ascii_art = ''' -⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛⬛️⬜️⬜️⬜️⬜️⬜⬜️⬜️️ -🟥🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️🟥🟥🟥🟥🟥🟥🟥🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧⬛️⬜️⬜️⬜️⬜️⬜⬜️️ -🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥⬛️🥧🥧🥧💟💟💟💟💟💟💟💟💟💟💟💟💟🥧🥧🥧⬛️⬜️⬜️⬜️⬜⬜️️ -🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥⬛️🥧🥧💟💟💟💟💟💟🍓💟💟🍓💟💟💟💟💟🥧🥧⬛️⬜️⬜️⬜️⬜️⬜️️ -🟧🟧🟥🟥🟥🟥🟥🟥🟥🟥🟧🟧🟧🟧🟧🟧🟧🟧🟥🟥🟥🟥🟥🟥🟥⬛🥧💟💟🍓💟💟💟💟💟💟💟💟💟💟💟💟💟💟🥧⬛️⬜️⬜️⬜️⬜⬜️️ -🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬛️🥧💟💟💟💟💟💟💟💟💟💟⬛️⬛️💟💟🍓💟💟🥧⬛️⬜️⬛️️⬛️️⬜⬜️️ -🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬛️🥧💟💟💟💟💟💟💟💟💟⬛️🌫🌫⬛💟💟💟💟🥧⬛️⬛️🌫🌫⬛⬜️️ -🟨🟨🟧🟧🟧🟧🟧🟧🟧🟧🟨🟨🟨🟨🟨🟨🟨🟨🟧⬛️⬛️⬛️⬛️🟧🟧⬛️🥧💟💟💟💟💟💟🍓💟💟⬛️🌫🌫🌫⬛💟💟💟🥧⬛️🌫🌫🌫⬛⬜️️ -🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨⬛️🌫🌫⬛️⬛️🟧⬛️🥧💟💟💟💟💟💟💟💟💟⬛️🌫🌫🌫🌫⬛️⬛️⬛️⬛️🌫🌫🌫🌫⬛⬜️️ -🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨⬛️⬛️🌫🌫⬛️⬛️⬛️🥧💟💟💟🍓💟💟💟💟💟⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛⬜️️ -🟩🟩🟨🟨🟨🟨🟨🟨🟨🟨🟩🟩🟩🟩🟩🟩🟩🟩🟨🟨⬛⬛️🌫🌫⬛️⬛️🥧💟💟💟💟💟💟💟🍓⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛️ -🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬛️⬛️🌫🌫⬛️🥧💟🍓💟💟💟💟💟💟⬛️🌫🌫🌫⬜️⬛️🌫🌫🌫🌫🌫⬜️⬛️🌫🌫⬛️ -️🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬛️⬛️⬛️⬛️🥧💟💟💟💟💟💟💟💟⬛️🌫🌫🌫⬛️⬛️🌫🌫🌫⬛️🌫⬛️⬛️🌫🌫⬛️ -🟦🟦🟩🟩🟩🟩🟩🟩🟩🟩🟦🟦🟦🟦🟦🟦🟦🟦🟩🟩🟩🟩🟩🟩⬛️⬛️🥧💟💟💟💟💟🍓💟💟⬛🌫🟥🟥🌫🌫🌫🌫🌫🌫🌫🌫🌫🟥🟥⬛️ -🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛️🥧🥧💟🍓💟💟💟💟💟⬛️🌫🟥🟥🌫⬛️🌫🌫⬛️🌫🌫⬛️🌫🟥🟥⬛️ -🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛️🥧🥧🥧💟💟💟💟💟💟💟⬛️🌫🌫🌫⬛️⬛️⬛️⬛️⬛️⬛️⬛️🌫🌫⬛️⬜️ -🟪🟪🟦🟦🟦🟦🟦🟦🟦🟦🟪🟪🟪🟪🟪🟪🟪🟪🟦🟦🟦🟦🟦🟦⬛️⬛️⬛️🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛️⬜️⬜️ -🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪⬛️🌫🌫🌫⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬜️⬜️⬜️ -🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪⬛️🌫🌫⬛️⬛️⬜️⬛️🌫🌫⬛️⬜️⬜️⬜️⬜️⬜️⬛️🌫🌫⬛️⬜️⬛️🌫🌫⬛️⬜️⬜️⬜️⬜️ -⬜️⬜️🟪🟪🟪🟪🟪🟪🟪🟪⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️🟪🟪🟪🟪🟪⬛️⬛️⬛️⬛⬜️⬜️⬛️⬛️⬛️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️⬜️⬜️⬛️⬛️⬜️⬜️⬜️⬜️⬜️️ - ''' - ascii_art_lines = ascii_art.strip().split('\n') - with app.app_context(): - return Response(render_template_string(''' - - - - - - -
- - - - ''', ascii_art_lines=ascii_art_lines), status=200, content_type="text/html") -``` - -To run this code, you need to first install the following Python dependency packages: - -```python -pip install werkzeug -pip install flask -pip install dify-plugin -``` - -### Debugging the Plugin - -Next, you need to test whether the plugin can function properly. Dify provides a remote debugging method. Go to the "Plugin Management" page to obtain the debugging Key and remote server address. - -![](https://assets-docs.dify.ai/2024/11/1cf15bc59ea10eb67513c8bdca557111.png) - -Return to the plugin project, copy the `.env.example` file and rename it to `.env`, then fill in the remote server address and debugging Key information you obtained. - -`.env` file - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -Run the `python -m main` command to start the plugin. On the plugins page, you can see that the plugin has been installed in the Workspace. Other team members can also access the plugin. - -![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) - -Add a new Endpoint in the plugin, fill in the name and `api_key` information as desired. Visit the automatically generated URL to see the web service provided by the plugin. - -![](https://assets-docs.dify.ai/2024/11/c76375b8df2449d0d8c31a7c2a337579.png) - -### Packaging the Plugin - -After confirming that the plugin can run normally, you can package and name the plugin using the following command line tool. After running, you will discover a `neko.difypkg` file in the current folder, which is the final plugin package. - -```bash -# Replace ./neko with the actual path of the plugin project - -dify plugin package ./neko -``` - -Congratulations, you have completed the entire process of developing, testing, and packaging a plugin! - -### Publishing the Plugin - -Now you can upload it to the [Dify Plugins code repository](https://github.com/langgenius/dify-plugins) to publish your plugin! Before uploading, please ensure that your plugin follows the [plugin publishing specifications](/plugin-dev-en/0322-release-to-dify-marketplace). After the review is approved, the code will be merged into the main branch and automatically launched to the [Dify Marketplace](https://marketplace.dify.ai/). - -### Explore More - -**Quick Start:** - -* [Tool Plugin: Google Search](/plugin-dev-en/0222-tool-plugin) -* [Model Plugin](/plugin-dev-en/0211-getting-started-new-model) -* [Bundle Plugin: Packaging Multiple Plugins](/plugin-dev-en/9241-bundle) - -**Plugin Interface Documentation:** - -* [Manifest](/plugin-dev-en/0411-general-specifications) Structure -* [Endpoint](/plugin-dev-en/0411-general-specifications) Detailed Definition -* [Reverse Invocation of Dify Capabilities](/plugin-dev-en/9241-reverse-invocation) -* [Tools](/plugin-dev-en/0411-tool) -* [Models](/plugin-dev-en/0412-model-schema) -* [Extending Agent Strategies](/plugin-dev-en/9232-agent) - -**Best Practices:** - -[Developing a Slack Bot Plugin](/plugin-dev-en/0432-develop-a-slack-bot-plugin) - -{/* -Contributing Section -DO NOT edit this section! -It will be automatically generated by the script. -*/} - ---- - -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9231-extension-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-en/9433-agent-strategy-plugin.mdx b/plugin-dev-en/9433-agent-strategy-plugin.mdx deleted file mode 100644 index c120fdf4..00000000 --- a/plugin-dev-en/9433-agent-strategy-plugin.mdx +++ /dev/null @@ -1,1106 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: advanced -standard_title: Agent Strategy Plugin -language: en -title: Agent Strategy Plugin -description: This document details how to develop an Agent strategy plugin, covering - the entire process from initializing the plugin template to invoking models, invoking - tools, outputting logs, and packaging for release. It provides detailed code examples, - including how to implement automated tool invocation features that help LLMs perform - reasoning or decision-making logic. ---- - -An **Agent Strategy Plugin** helps an LLM carry out tasks like reasoning or decision-making, including choosing and calling tools, as well as handling results. This allows the system to address problems more autonomously. - -Below, you’ll see how to develop a plugin that supports **Function Calling** to automatically fetch the current time. - -### Prerequisites - -- Dify plugin scaffolding tool -- Python environment (version ≥ 3.12) - -For details on preparing the plugin development tool, see [Initializing the Development Tool](/plugin-dev-en/0221-initialize-development-tools). - - -**Tip**: Run `dify version` in your terminal to confirm that the scaffolding tool is installed. - - ---- - -### 1. Initializing the Plugin Template - -Run the following command to create a development template for your Agent plugin: - -``` -dify plugin init -``` - -Follow the on-screen prompts and refer to the sample comments for guidance. - -```bash -➜ Dify Plugins Developing dify plugin init -Edit profile of the plugin -Plugin name (press Enter to next step): # Enter the plugin name -Author (press Enter to next step): Author name # Enter the plugin author -Description (press Enter to next step): Description # Enter the plugin description ---- -Select the language you want to use for plugin development, and press Enter to con -BTW, you need Python 3.12+ to develop the Plugin if you choose Python. --> python # Select Python environment - go (not supported yet) ---- -Based on the ability you want to extend, we have divided the Plugin into four type - -- Tool: It's a tool provider, but not only limited to tools, you can implement an -- Model: Just a model provider, extending others is not allowed. -- Extension: Other times, you may only need a simple http service to extend the fu -- Agent Strategy: Implement your own logics here, just by focusing on Agent itself - -What's more, we have provided the template for you, you can choose one of them b - tool --> agent-strategy # Select Agent strategy template - llm - text-embedding ---- -Configure the permissions of the plugin, use up and down to navigate, tab to sel -Backwards Invocation: -Tools: - Enabled: [✔] You can invoke tools inside Dify if it's enabled # Enabled by default -Models: - Enabled: [✔] You can invoke models inside Dify if it's enabled # Enabled by default - LLM: [✔] You can invoke LLM models inside Dify if it's enabled # Enabled by default - Text Embedding: [✘] You can invoke text embedding models inside Dify if it' - Rerank: [✘] You can invoke rerank models inside Dify if it's enabled -... -``` - -After initialization, you’ll get a folder containing all the resources needed for plugin development. Familiarizing yourself with the overall structure of an Agent Strategy Plugin will streamline the development process: - -```text -├── GUIDE.md # User guide and documentation -├── PRIVACY.md # Privacy policy and data handling guidelines -├── README.md # Project overview and setup instructions -├── _assets/ # Static assets directory -│ └── icon.svg # Agent strategy provider icon/logo -├── main.py # Main application entry point -├── manifest.yaml # Basic plugin configuration -├── provider/ # Provider configurations directory -│ └── basic_agent.yaml # Your agent provider settings -├── requirements.txt # Python dependencies list -└── strategies/ # Strategy implementation directory - ├── basic_agent.py # Basic agent strategy implementation - └── basic_agent.yaml # Basic agent strategy configuration -``` - -All key functionality for this plugin is in the `strategies/` directory. - ---- - -### 2. Developing the Plugin - -Agent Strategy Plugin development revolves around two files: - -- **Plugin Declaration**: `strategies/basic_agent.yaml` -- **Plugin Implementation**: `strategies/basic_agent.py` - -#### 2.1 Defining Parameters - -To build an Agent plugin, start by specifying the necessary parameters in `strategies/basic_agent.yaml`. These parameters define the plugin’s core features, such as calling an LLM or using tools. - -We recommend including the following four parameters first: - -1. **model**: The large language model to call (e.g., GPT-4, GPT-4o-mini). -2. **tools**: A list of tools that enhance your plugin’s functionality. -3. **query**: The user input or prompt content sent to the model. -4. **maximum_iterations**: The maximum iteration count to prevent excessive computation. - -Example Code: - -```yaml -identity: - name: basic_agent # the name of the agent_strategy - author: novice # the author of the agent_strategy - label: - en_US: BasicAgent # the engilish label of the agent_strategy -description: - en_US: BasicAgent # the english description of the agent_strategy -parameters: - - name: model # the name of the model parameter - type: model-selector # model-type - scope: tool-call&llm # the scope of the parameter - required: true - label: - en_US: Model - zh_Hans: 模型 - pt_BR: Model - - name: tools # the name of the tools parameter - type: array[tools] # the type of tool parameter - required: true - label: - en_US: Tools list - zh_Hans: 工具列表 - pt_BR: Tools list - - name: query # the name of the query parameter - type: string # the type of query parameter - required: true - label: - en_US: Query - zh_Hans: 查询 - pt_BR: Query - - name: maximum_iterations - type: number - required: false - default: 5 - label: - en_US: Maxium Iterations - zh_Hans: 最大迭代次数 - pt_BR: Maxium Iterations - max: 50 # if you set the max and min value, the display of the parameter will be a slider - min: 1 -extra: - python: - source: strategies/basic_agent.py -``` - -Once you’ve configured these parameters, the plugin will automatically generate a user-friendly interface so you can easily manage them: - -![Agent Strategy Plugin UI](https://assets-docs.dify.ai/2025/01/d011e2eba4c37f07a9564067ba787df8.png) - -#### 2.2 Retrieving Parameters and Execution - -After users fill out these basic fields, your plugin needs to process the submitted parameters. In `strategies/basic_agent.py`, define a parameter class for the Agent, then retrieve and apply these parameters in your logic. - -Verify incoming parameters: - -```python -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str -``` - -After getting the parameters, the specific business logic is executed: - -```python -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) -``` - -### 3. Invoking the Model - -In an Agent Strategy Plugin, **invoking the model** is central to the workflow. You can invoke an LLM efficiently using `session.model.llm.invoke()` from the SDK, handling text generation, dialogue, and so forth. - -If you want the LLM **handle tools**, ensure it outputs structured parameters to match a tool’s interface. In other words, the LLM must produce input arguments that the tool can accept based on the user’s instructions. - -Construct the following parameters: - -* model -* prompt\_messages -* tools -* stop -* stream - -Example code for method definition: - -```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:... -``` - -To view the complete functionality implementation, please refer to the Example Code for model invocation. - -This code achieves the following functionality: after a user inputs a command, the Agent strategy plugin automatically calls the LLM, constructs the necessary parameters for tool invocation based on the generated results, and enables the model to flexibly dispatch integrated tools to efficiently complete complex tasks. - -![Request parameters for generating tools](https://assets-docs.dify.ai/2025/01/01e32c2d77150213c7c929b3cceb4dae.png) - -### 4. Handle a Tool - -After specifying the tool parameters, the Agent Strategy Plugin must actually call these tools. Use `session.tool.invoke()` to make those requests. - -Construct the following parameters: - -- provider -- tool\_name -- parameters - -Example code for method definition: - -```python - def invoke( - self, - provider_type: ToolProviderType, - provider: str, - tool_name: str, - parameters: dict[str, Any], - ) -> Generator[ToolInvokeMessage, None, None]:... -``` - -If you’d like the LLM itself to generate the parameters needed for tool calls, you can do so by combining the model’s output with your tool-calling code. - -```python -tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} -) -for tool_call_id, tool_call_name, tool_call_args in tool_calls: - tool_instance = tool_instances[tool_call_name] - 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}, - ) -``` - -With this in place, your Agent Strategy Plugin can automatically perform **Function Calling**—for instance, retrieving the current time. - -![Tool Invocation](https://assets-docs.dify.ai/2025/01/80e5de8acc2b0ed00524e490fd611ff5.png) - -### 5. Creating Logs - -Often, multiple steps are necessary to complete a complex task in an **Agent Strategy Plugin**. It’s crucial for developers to track each step’s results, analyze the decision process, and optimize strategy. Using `create_log_message` and `finish_log_message` from the SDK, you can log real-time states before and after calls, aiding in quick problem diagnosis. - -For example: - -- Log a “starting model call” message before calling the model, clarifying the task’s execution progress. -- Log a “call succeeded” message once the model responds, ensuring the model’s output can be traced end to end. - -```python -model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - ) -yield model_log -self.session.model.llm.invoke(...) -yield self.finish_log_message( - log=model_log, - data={ - "output": response, - "tool_name": tool_call_names, - "tool_input": tool_call_inputs, - }, - metadata={ - "started_at": model_started_at, - "finished_at": time.perf_counter(), - "elapsed_time": time.perf_counter() - model_started_at, - "provider": params.model.provider, - }, -) -``` - -When the setup is complete, the workflow log will output the execution results: - -![Agent Output execution results](https://assets-docs.dify.ai/2025/01/96516388a4fb1da9cea85fc1804ff377.png) - -If multiple rounds of logs occur, you can structure them hierarchically by setting a `parent` parameter in your log calls, making them easier to follow. - -Reference method: - -```python -function_call_round_log = self.create_log_message( - label="Function Call Round1 ", - data={}, - metadata={}, -) -yield function_call_round_log - -model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - # add parent log - parent=function_call_round_log, -) -yield model_log -``` - -#### Sample code for agent-plugin functions - - - - #### Invoke Model - -The following code demonstrates how to give the Agent strategy plugin the ability to invoke the model: - -```python -import json -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - #### Handle Tools - -The following code shows how to implement model calls for the Agent strategy plugin and send canonicalized requests to the tool. - -```python -import json -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - #### Example of a complete function code - -A complete sample plugin code that includes a **invoking model, handling tool** and a **function to output multiple rounds of logs**: - -```python -import json -import time -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - function_call_round_log = self.create_log_message( - label="Function Call Round1 ", - data={}, - metadata={}, - ) - yield function_call_round_log - model_started_at = time.perf_counter() - model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - parent=function_call_round_log, - ) - yield model_log - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - tool_call_names = "" - tool_call_inputs = "" - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.finish_log_message( - log=model_log, - data={ - "output": response, - "tool_name": tool_call_names, - "tool_input": tool_call_inputs, - }, - metadata={ - "started_at": model_started_at, - "finished_at": time.perf_counter(), - "elapsed_time": time.perf_counter() - model_started_at, - "provider": params.model.provider, - }, - ) - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - -### 3. Debugging the Plugin - -After finalizing the plugin’s declaration file and implementation code, run `python -m main` in the plugin directory to restart it. Next, confirm the plugin runs correctly. Dify offers remote debugging—go to [“Plugin Management”](https://console-plugin.dify.dev/plugins) to obtain your debug key and remote server address. - -![](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) - -Back in your plugin project, copy `.env.example` to `.env` and insert the relevant remote server and debug key info. - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -Then run: - -```bash -python -m main -``` - -You’ll see the plugin installed in your Workspace, and team members can also access it. - -![Browser Plugins](https://assets-docs.dify.ai/2025/01/c82ec0202e5bf914b36e06c796398dd6.png) - -### Packaging the Plugin (Optional) - -Once everything works, you can package your plugin by running: - -```bash -# Replace ./basic_agent/ with your actual plugin project path. - -dify plugin package ./basic_agent/ -``` - -A file named `google.difypkg` (for example) appears in your current folder—this is your final plugin package. - -**Congratulations!** You’ve fully developed, tested, and packaged your Agent Strategy Plugin. - -### Publishing the Plugin (Optional) - -You can now upload it to the [Dify Plugins repository](https://github.com/langgenius/dify-plugins). Before doing so, ensure it meets the [Plugin Publishing Guidelines](https://docs.dify.ai/plugins/publish-plugins/publish-to-dify-marketplace). Once approved, your code merges into the main branch, and the plugin automatically goes live on the [Dify Marketplace](https://marketplace.dify.ai/). - ---- - -### Further Exploration - -Complex tasks often need multiple rounds of thinking and tool calls, typically repeating **model invoke → tool use** until the task ends or a maximum iteration limit is reached. Managing prompts effectively is crucial in this process. Check out the [complete Function Calling implementation](https://github.com/langgenius/dify-official-plugins/blob/main/agent-strategies/cot_agent/strategies/function_calling.py) for a standardized approach to letting models call external tools and handle their outputs. - -{/* -Contributing Section -DO NOT edit this section! -It will be automatically generated by the script. -*/} - ---- - -[Edit this page](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-en/9433-agent-strategy-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-en/sync/check_mapping_consistency.py b/plugin-dev-en/sync/check_mapping_consistency.py deleted file mode 100644 index 3edff4b3..00000000 --- a/plugin-dev-en/sync/check_mapping_consistency.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python3 -""" -文件映射一致性检查工具 -对比 JSON 映射记录与实际文件情况,确保映射准确无误 -""" - -import json -import os -from pathlib import Path -from typing import Set, Dict - -# ANSI 颜色代码 -GREEN = '\033[92m' -YELLOW = '\033[93m' -RED = '\033[91m' -BLUE = '\033[94m' -CYAN = '\033[96m' -RESET = '\033[0m' - -class MappingValidator: - def __init__(self, json_file: str = "plugin_mappings.json"): - script_file_path = Path(os.path.abspath(__file__)).resolve() - - - self.base_dir = script_file_path.parent.parent.parent - - self.json_file = script_file_path.parent / json_file - - # plugin_dir 是 /en/plugins - self.plugin_dir = self.base_dir / "en" / "plugins" - - # dev_dir 是 /plugin-dev-en - self.dev_dir = self.base_dir / "plugin-dev-en" - - self.mappings = [] - self.load_mappings() - - def load_mappings(self): - """加载映射文件""" - try: - with open(self.json_file, 'r', encoding='utf-8') as f: - data = json.load(f) - self.mappings = data.get('mappings', []) - except FileNotFoundError: - print(f"{RED}错误: 找不到文件 {self.json_file}{RESET}") - self.mappings = [] - except json.JSONDecodeError: - print(f"{RED}错误: JSON 文件格式错误{RESET}") - self.mappings = [] - - def count_mdx_files(self, directory: Path) -> int: - """递归统计目录中的 .mdx 文件数量""" - count = 0 - for file in directory.rglob('*.mdx'): - count += 1 - return count - - def get_actual_file_paths(self, directory: Path) -> Set[str]: - """获取目录中所有 .mdx 文件的相对路径""" - files = set() - for file in directory.rglob('*.mdx'): - relative_path = str(file.relative_to(self.base_dir)) - files.add(relative_path) - return files - - def calculate_mapping_stats(self) -> Dict: - """计算映射统计""" - total = len(self.mappings) - plugin_only = sum(1 for m in self.mappings if m.get('plugin_path') and not m.get('dev_path')) - dev_only = sum(1 for m in self.mappings if m.get('dev_path') and not m.get('plugin_path')) - complete = sum(1 for m in self.mappings if m.get('plugin_path') and m.get('dev_path')) - - # 计算预期的文件数 - expected_plugin_files = total - dev_only # 总数 - 仅开发 = 插件文件数 - expected_dev_files = total - plugin_only # 总数 - 仅插件 = 开发文件数 - - return { - 'total_mappings': total, - 'plugin_only': plugin_only, - 'dev_only': dev_only, - 'complete_mappings': complete, - 'expected_plugin_files': expected_plugin_files, - 'expected_dev_files': expected_dev_files - } - - def validate(self): - """执行验证""" - print(f"\n{CYAN}=== 插件文档映射一致性检查工具 ==={RESET}") - print(f"{CYAN}功能:对比 JSON 映射记录与实际文件,确保映射准确无遗漏{RESET}\n") - - # 统计实际文件数 - actual_plugin_count = self.count_mdx_files(self.plugin_dir) - actual_dev_count = self.count_mdx_files(self.dev_dir) - - # 获取映射统计 - stats = self.calculate_mapping_stats() - - # 显示映射统计 - print(f"{BLUE}【JSON 映射统计情况】{RESET}") - print(f" 总映射记录数: {stats['total_mappings']} 条") - print(f" 完整映射(两边都有): {stats['complete_mappings']} 条") - print(f" 仅插件文档: {stats['plugin_only']} 条") - print(f" 仅开发文档: {stats['dev_only']} 条\n") - - # 显示预期vs实际 - print(f"{BLUE}【运行时文件计数情况】{RESET}") - print(" 📁 插件文件夹 (en/plugins):") - print(f" JSON 映射预期: {stats['expected_plugin_files']} 个文件") - print(f" 实际扫描结果: {actual_plugin_count} 个 .mdx 文件") - if actual_plugin_count == stats['expected_plugin_files']: - print(f" 状态: {GREEN}✓ 完全一致{RESET}") - else: - diff = actual_plugin_count - stats['expected_plugin_files'] - print(f" 状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}") - - print("\n 📁 开发文件夹 (plugin-dev-en):") - print(f" JSON 映射预期: {stats['expected_dev_files']} 个文件") - print(f" 实际扫描结果: {actual_dev_count} 个 .mdx 文件") - if actual_dev_count == stats['expected_dev_files']: - print(f" 状态: {GREEN}✓ 完全一致{RESET}") - else: - diff = actual_dev_count - stats['expected_dev_files'] - print(f" 状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}") - - # 显示计算公式说明 - print(f"\n{BLUE}【预期文件数计算说明】{RESET}") - print(f" 插件预期数 = 总映射数({stats['total_mappings']}) - 仅开发数({stats['dev_only']}) = {stats['expected_plugin_files']}") - print(f" 开发预期数 = 总映射数({stats['total_mappings']}) - 仅插件数({stats['plugin_only']}) = {stats['expected_dev_files']}") - - # 如果有差异,找出具体文件 - if actual_plugin_count != stats['expected_plugin_files'] or actual_dev_count != stats['expected_dev_files']: - self.find_discrepancies() - else: - print(f"\n{GREEN}✅ 检查完成:所有文件映射完全一致!{RESET}") - - def find_discrepancies(self): - """找出映射和实际文件的差异""" - print(f"\n{YELLOW}【差异详细分析】{RESET}\n") - - # 获取实际文件路径 - actual_plugin_files = self.get_actual_file_paths(self.plugin_dir) - actual_dev_files = self.get_actual_file_paths(self.dev_dir) - - # 获取映射中的文件路径 - mapped_plugin_files = set(m['plugin_path'] for m in self.mappings if m.get('plugin_path')) - mapped_dev_files = set(m['dev_path'] for m in self.mappings if m.get('dev_path')) - - # 找出未映射的文件 - unmapped_plugin_files = actual_plugin_files - mapped_plugin_files - unmapped_dev_files = actual_dev_files - mapped_dev_files - - # 找出映射中但不存在的文件 - nonexistent_plugin_files = mapped_plugin_files - actual_plugin_files - nonexistent_dev_files = mapped_dev_files - actual_dev_files - - has_issues = False - - if unmapped_plugin_files: - has_issues = True - print(f"{RED}❗ 实际存在但 JSON 中未记录的插件文件:{RESET}") - for file in sorted(unmapped_plugin_files): - print(f" - {file}") - - if unmapped_dev_files: - has_issues = True - print(f"\n{RED}❗ 实际存在但 JSON 中未记录的开发文件:{RESET}") - for file in sorted(unmapped_dev_files): - print(f" - {file}") - - if nonexistent_plugin_files: - has_issues = True - print(f"\n{RED}❗ JSON 中记录但实际不存在的插件文件:{RESET}") - for file in sorted(nonexistent_plugin_files): - print(f" - {file}") - - if nonexistent_dev_files: - has_issues = True - print(f"\n{RED}❗ JSON 中记录但实际不存在的开发文件:{RESET}") - for file in sorted(nonexistent_dev_files): - print(f" - {file}") - - if has_issues: - print(f"\n{YELLOW}💡 建议:运行 sync_mdx_to_json.py 同步文件到映射{RESET}") - else: - print(f"{GREEN}未发现具体文件差异,检查完成{RESET}") - -def main(): - """主函数""" - validator = MappingValidator() - validator.validate() - -if __name__ == "__main__": - main() diff --git a/plugin-dev-en/sync/plugin_mappings.json b/plugin-dev-en/sync/plugin_mappings.json deleted file mode 100644 index ce9d70ee..00000000 --- a/plugin-dev-en/sync/plugin_mappings.json +++ /dev/null @@ -1,243 +0,0 @@ -{ - "mappings": [ - { - "plugin_path": "en/plugins/introduction.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "en/plugins/manage-plugins.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/README.mdx", - "dev_path": "plugin-dev-en/0111-getting-started-dify-plugin.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-en/0211-getting-started-new-model.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/faq.mdx", - "dev_path": "plugin-dev-en/0331-faq.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/tool-plugin.mdx", - "dev_path": "plugin-dev-en/0222-tool-plugin.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/model-plugin/README.mdx", - "dev_path": "plugin-dev-en/0411-model-plugin-introduction.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/initialize-development-tools.mdx", - "dev_path": "plugin-dev-en/0221-initialize-development-tools.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/model-plugin/create-model-providers.mdx", - "dev_path": "plugin-dev-en/0222-creating-new-model-provider.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/README.mdx", - "dev_path": "plugin-dev-en/0321-release-overview.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/package-plugin-file-and-publish.mdx", - "dev_path": "plugin-dev-en/0322-release-by-file.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/publish-to-dify-marketplace/README.mdx", - "dev_path": "plugin-dev-en/0322-release-to-dify-marketplace.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/publish-plugin-on-personal-github-repo.mdx", - "dev_path": "plugin-dev-en/0322-release-to-individual-github-repo.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/publish-to-dify-marketplace/plugin-developer-guidelines.mdx", - "dev_path": "plugin-dev-en/0312-contributor-covenant-code-of-conduct.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/publish-to-dify-marketplace/plugin-privacy-protection-guidelines.mdx", - "dev_path": "plugin-dev-en/0312-privacy-protection-guidelines.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/general-specifications.mdx", - "dev_path": "plugin-dev-en/0411-general-specifications.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/model/model-designing-rules.mdx", - "dev_path": "plugin-dev-en/0411-model-designing-rules.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/persistent-storage.mdx", - "dev_path": "plugin-dev-en/0411-persistent-storage-kv.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/manifest.mdx", - "dev_path": "plugin-dev-en/0411-plugin-info-by-manifest.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/debug-plugin.mdx", - "dev_path": "plugin-dev-en/0411-remote-debug-a-plugin.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/tool.mdx", - "dev_path": "plugin-dev-en/0411-tool.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/model/model-schema.mdx", - "dev_path": "plugin-dev-en/0412-model-schema.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/best-practice/develop-a-slack-bot-plugin.mdx", - "dev_path": "plugin-dev-en/0432-develop-a-slack-bot-plugin.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/endpoint.mdx", - "dev_path": "plugin-dev-en/0432-endpoint.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/extension-plugin.mdx", - "dev_path": "plugin-dev-en/9231-extension-plugin.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/agent.mdx", - "dev_path": "plugin-dev-en/9232-agent.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/bundle.mdx", - "dev_path": "plugin-dev-en/9241-bundle.mdx", - "verified": true, - "sync": "内容高度相同,已确认同步。" - }, - { - "plugin_path": "en/plugins/schema-definition/reverse-invocation-of-the-dify-service/README.mdx", - "dev_path": "plugin-dev-en/9241-reverse-invocation.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/reverse-invocation-of-the-dify-service/app.mdx", - "dev_path": "plugin-dev-en/9242-reverse-invocation-app.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/reverse-invocation-of-the-dify-service/model.mdx", - "dev_path": "plugin-dev-en/9242-reverse-invocation-model.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/reverse-invocation-of-the-dify-service/tool.mdx", - "dev_path": "plugin-dev-en/9242-reverse-invocation-tool.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/model-plugin/customizable-model.mdx", - "dev_path": "plugin-dev-en/9243-customizable-model.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/reverse-invocation-of-the-dify-service/node.mdx", - "dev_path": "plugin-dev-en/9243-reverse-invocation-node.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/agent-strategy-plugin.mdx", - "dev_path": "plugin-dev-en/9433-agent-strategy-plugin.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/install-plugins.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "en/plugins/best-practice/how-to-print-strings-to-logs-for-debugging.mdx", - "dev_path": "plugin-dev-en/0222-debugging-logs.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/best-practice/how-to-use-mcp-zapier.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/develop-plugins/model-plugin/predefined-model.mdx", - "dev_path": "plugin-dev-en/0222-creating-new-model-provider-extra.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/plugin-auto-publish-pr.mdx", - "dev_path": "plugin-dev-en/0321-plugin-auto-publish-pr.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/publish-plugins/signing-plugins-for-third-party-signature-verification.mdx", - "dev_path": "plugin-dev-en/0312-third-party-signature-verification.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/quick-start/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 需要进行适配" - }, - { - "plugin_path": "en/plugins/best-practice/README.mdx", - "dev_path": "plugin-dev-en/0431-example-overview-and-index.mdx", - "verified": true - }, - { - "plugin_path": "en/plugins/schema-definition/model/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - }, - { - "plugin_path": "en/plugins/schema-definition/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-en/0131-cheatsheet.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-en/0211-getting-started-dify-tool.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-en/0211-getting-started-by-prompt.mdx", - "verified": true - } - ] -} diff --git a/plugin-dev-en/sync/sync_all_mdx_files_to_json.py b/plugin-dev-en/sync/sync_all_mdx_files_to_json.py deleted file mode 100644 index 8f43f91e..00000000 --- a/plugin-dev-en/sync/sync_all_mdx_files_to_json.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python3 -""" -同步 MDX 文件到映射 -确保所有 mdx 文件都在 JSON 映射中,并去除 metadata -""" - -import json -import os -from pathlib import Path -from typing import Set, Dict - - -class MdxSyncManager: - def __init__(self, json_file: str = "plugin_mappings.json"): - self.base_dir = Path(os.path.dirname( - # 指向项目根目录 - os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - self.json_file = self.base_dir / "plugin-dev-en" / \ - "sync" / json_file # 修正 JSON 文件路径 - self.plugin_dir = self.base_dir / "en" / "plugins" # 指向英文插件目录 - self.dev_dir = self.base_dir / "plugin-dev-en" # 指向英文开发目录 - self.mappings = [] - self.load_mappings() - - def load_mappings(self): - """加载现有映射""" - try: - with open(self.json_file, 'r', encoding='utf-8') as f: - data = json.load(f) - # 只加载 mappings,忽略 metadata - self.mappings = data.get('mappings', []) - except FileNotFoundError: - print(f"创建新的映射文件: {self.json_file}") - self.mappings = [] - except json.JSONDecodeError: - print("JSON 文件格式错误,创建新文件") - self.mappings = [] - - def save_mappings(self): - """保存映射(不包含 metadata)""" - # 只保存 mappings,不保存 metadata - data = { - 'mappings': self.mappings - } - with open(self.json_file, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - - def get_mdx_files(self, directory: Path) -> Set[str]: - """获取目录中所有 mdx 文件的相对路径""" - mdx_files = set() - for file in directory.rglob('*.mdx'): - relative_path = str(file.relative_to(self.base_dir)) - mdx_files.add(relative_path) - return mdx_files - - def get_existing_paths(self) -> Dict[str, Dict]: - """获取现有映射中的所有路径""" - existing = {} - for mapping in self.mappings: - if mapping['plugin_path']: - existing[mapping['plugin_path']] = mapping - if mapping['dev_path']: - existing[mapping['dev_path']] = mapping - return existing - - def get_base_filename(self, filepath: str) -> str: - """从文件路径中提取基本名称,移除扩展名和常见的语言代码。""" - name = os.path.basename(filepath) - # 顺序很重要:先匹配更具体的(如 .mdx),再匹配通用的(如 .mdx) - if name.endswith('.mdx'): - return name[:-7] - elif name.endswith('.mdx'): # 保留以处理多语言情况 - return name[:-7] - elif name.endswith('.ja.mdx'): # 保留以处理多语言情况 - return name[:-7] - elif name.endswith('.mdx'): # 通用 .mdx - return name[:-4] - return os.path.splitext(name)[0] # 备选方案:返回不含最后一个扩展名的名称 - - def _find_match_in_set(self, source_file_path: str, target_file_set: Set[str]) -> str | None: - """通过比较基本名称,在目标集合中查找源文件的匹配项。""" - source_base = self.get_base_filename(source_file_path) - for target_file in target_file_set: - if self.get_base_filename(target_file) == source_base: - return target_file - return None - - def find_matching_mapping(self, path: str) -> Dict | None: - """查找与给定路径匹配的映射""" - for mapping in self.mappings: - if mapping['plugin_path'] == path or mapping['dev_path'] == path: - return mapping - return None - - def sync_files(self): - """同步文件到映射, 包括添加新文件、移除不存在的文件关联、并尝试链接对应文件。""" - actual_plugin_files = self.get_mdx_files(self.plugin_dir) - actual_dev_files = self.get_mdx_files(self.dev_dir) - - made_changes = False - - # 步骤 1: 从现有映射中修剪不存在的文件路径 - valid_mappings = [] - for mapping in self.mappings: - plugin_path = mapping.get('plugin_path') - dev_path = mapping.get('dev_path') - - original_plugin_path_for_log = plugin_path - original_dev_path_for_log = dev_path - - path_changed_in_mapping = False - if plugin_path and plugin_path not in actual_plugin_files: - print(f"信息:插件文件 '{plugin_path}' 在映射中但实际不存在,将从该映射中移除。") - mapping['plugin_path'] = None - made_changes = True - path_changed_in_mapping = True - - if dev_path and dev_path not in actual_dev_files: - print(f"信息:开发文件 '{dev_path}' 在映射中但实际不存在,将从该映射中移除。") - mapping['dev_path'] = None - made_changes = True - path_changed_in_mapping = True - - # 如果映射仍然至少有一个有效路径,则保留它 - if mapping.get('plugin_path') or mapping.get('dev_path'): - valid_mappings.append(mapping) - elif path_changed_in_mapping: # 因修剪而变为空 - print( - f"信息:移除了一个空的映射条目 (原插件: {original_plugin_path_for_log}, 原开发: {original_dev_path_for_log})。") - # made_changes 已在路径被设为 None 时置为 true - - self.mappings = valid_mappings - - # 步骤 2: 识别修剪后映射中当前代表的所有文件 - mapped_plugin_paths = {m['plugin_path'] - for m in self.mappings if m.get('plugin_path')} - mapped_dev_paths = {m['dev_path'] - for m in self.mappings if m.get('dev_path')} - - # 步骤 3: 添加/链接新的插件文件 - for p_file in actual_plugin_files: - if p_file not in mapped_plugin_paths: # 这个插件文件不在任何映射的 plugin_path 中 - made_changes = True - corresponding_dev_file = self._find_match_in_set( - p_file, actual_dev_files) - linked_to_existing_dev_mapping = False - - if corresponding_dev_file: - for m in self.mappings: # 寻找一个只有dev路径且匹配的现有映射 - if m.get('dev_path') == corresponding_dev_file and not m.get('plugin_path'): - m['plugin_path'] = p_file - print( - f"链接新插件文件到现有开发映射: {p_file} -> {corresponding_dev_file}") - mapped_plugin_paths.add(p_file) - linked_to_existing_dev_mapping = True - break - - if not linked_to_existing_dev_mapping: - new_mapping_entry = { - 'plugin_path': p_file, 'dev_path': None, 'verified': False} - if corresponding_dev_file and corresponding_dev_file not in mapped_dev_paths: - # 如果对应的dev文件也存在且尚未被映射,则一起加入新条目 - new_mapping_entry['dev_path'] = corresponding_dev_file - mapped_dev_paths.add(corresponding_dev_file) - print( - f"添加新映射 (插件与新开发链接): {p_file} <-> {corresponding_dev_file}") - else: - print(f"添加新映射 (仅插件): {p_file}") - self.mappings.append(new_mapping_entry) - mapped_plugin_paths.add(p_file) - - # 步骤 4: 添加/链接新的开发文件 (那些在步骤3中未被链接的) - for d_file in actual_dev_files: - if d_file not in mapped_dev_paths: # 这个开发文件不在任何映射的 dev_path 中 - made_changes = True - corresponding_plugin_file = self._find_match_in_set( - d_file, actual_plugin_files) - linked_to_existing_plugin_mapping = False - - if corresponding_plugin_file: # 对应的插件文件存在 - for m in self.mappings: # 寻找一个只有plugin路径且匹配的现有映射 - if m.get('plugin_path') == corresponding_plugin_file and not m.get('dev_path'): - m['dev_path'] = d_file - print( - f"链接新开发文件到现有插件映射: {corresponding_plugin_file} <- {d_file}") - mapped_dev_paths.add(d_file) - linked_to_existing_plugin_mapping = True - break - - if not linked_to_existing_plugin_mapping: - # 如果没有找到可链接的仅插件映射,则添加为新的仅开发映射 - print(f"添加新映射 (仅开发): {d_file}") - self.mappings.append( - {'plugin_path': None, 'dev_path': d_file, 'verified': False}) - mapped_dev_paths.add(d_file) # 确保它现在被认为是已映射 - - # 步骤 5: 清理重复项 - initial_len = len(self.mappings) - self.remove_duplicates() # 原位修改 self.mappings - if len(self.mappings) != initial_len: - print(f"信息:移除了 {initial_len - len(self.mappings)} 个重复映射。") - made_changes = True - - # 步骤 6: 如果有更改则保存 - if made_changes: - self.save_mappings() - print("\\n映射已同步并保存。") - else: - print("\\n映射文件无需更新。") - - def remove_duplicates(self): - """去除重复的映射""" - unique_mappings = [] - seen = set() - - for mapping in self.mappings: - # 创建唯一键 - key = (mapping.get('plugin_path'), mapping.get('dev_path')) - if key not in seen: - seen.add(key) - unique_mappings.append(mapping) - - self.mappings = unique_mappings - - def show_status(self): - """显示当前状态""" - plugin_count = sum(1 for m in self.mappings if m['plugin_path']) - dev_count = sum(1 for m in self.mappings if m['dev_path']) - both_count = sum( - 1 for m in self.mappings if m['plugin_path'] and m['dev_path']) - - print("\n当前映射状态:") - print(f"总映射数: {len(self.mappings)}") - print(f"Plugin 文件: {plugin_count}") - print(f"Dev 文件: {dev_count}") - print(f"完整映射: {both_count}") - - -def main(): - """主函数""" - manager = MdxSyncManager() - - print("开始同步 MDX 文件到映射...") - manager.sync_files() - manager.show_status() - - print("\n同步完成!") - - -if __name__ == "__main__": - main() diff --git a/plugin-dev-en/sync/view_file_mappings.py b/plugin-dev-en/sync/view_file_mappings.py deleted file mode 100644 index 8df10b67..00000000 --- a/plugin-dev-en/sync/view_file_mappings.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 -""" -简单的插件映射查看器 -快速查看文件映射关系,支持在 VS Code 中点击打开 -""" - -import json -import os -from pathlib import Path - -# ANSI 颜色代码 -GREEN = '\033[92m' -YELLOW = '\033[93m' -RED = '\033[91m' -BLUE = '\033[94m' -RESET = '\033[0m' - -# 新增符号常量 -CHECK_MARK = f"{GREEN}✅{RESET}" -CROSS_MARK = f"{RED}❌{RESET}" -EMPTY_MARK = f"{YELLOW}❎{RESET}" - -def load_mappings(json_file="plugin_mappings.json"): - """加载映射文件""" - # base_dir 是工作区根目录。脚本位于 /plugin-dev-en/sync/script.py - # 因此,base_dir 是脚本目录的父目录的父目录的父目录。 - base_dir = Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - json_path = base_dir / "plugin-dev-en" / "sync" / json_file # 修正 JSON 文件路径 - - try: - with open(json_path, 'r', encoding='utf-8') as f: - return json.load(f) - except FileNotFoundError: - print(f"{RED}错误: 找不到文件 {json_path}{RESET}") - return None - except json.JSONDecodeError: - print(f"{RED}错误: JSON 文件格式错误{RESET}") - return None - -def calculate_statistics(mappings): - """动态计算统计信息""" - total = len(mappings) - verified = sum(1 for m in mappings if m.get('verified', False)) - pending = total - verified - - # 额外统计 - plugin_only = sum(1 for m in mappings if m.get('plugin_path') and not m.get('dev_path')) - dev_only = sum(1 for m in mappings if m.get('dev_path') and not m.get('plugin_path')) - complete = sum(1 for m in mappings if m.get('plugin_path') and m.get('dev_path')) - - return { - 'total_mappings': total, - 'verified_count': verified, - 'pending_verification': pending, - 'plugin_only': plugin_only, - 'dev_only': dev_only, - 'complete_mappings': complete - } - -def show_mappings(): - """显示所有映射关系""" - data = load_mappings() - if not data: - return - - mappings = data.get('mappings', []) - stats = calculate_statistics(mappings) - - print(f"\n{BLUE}插件文档映射关系{RESET}") - print(f"总计: {stats['total_mappings']} | " - f"已验证: {GREEN}{stats['verified_count']}{RESET} | " - f"待验证: {YELLOW}{stats['pending_verification']}{RESET}") - print(f"完整映射: {stats['complete_mappings']} | " - f"仅插件: {stats['plugin_only']} | " - f"仅开发: {stats['dev_only']}") - - print("\n路径 | 验证 | 同步细节\n") - - separator_line1 = "-" * 56 - separator_line2 = "*" * 56 - - for idx, mapping in enumerate(mappings, 1): - plugin_path = mapping.get('plugin_path') - dev_path = mapping.get('dev_path') - verified = mapping.get('verified', False) - sync_info = mapping.get('sync', '').strip() - - # 打印分隔符 - print(separator_line1) - print(separator_line2) - print(separator_line1) - print() # 在分隔符后添加空行 - - # 显示 Help 路径 - if plugin_path: - print(f"Help: {plugin_path}") - else: - print(f"Help: {EMPTY_MARK}") - - # 显示 Dev 路径 - if dev_path: - print(f"Dev: {dev_path}") - else: - print(f"Dev: {EMPTY_MARK}") - - # 显示 Verify 状态和 sync_info - verify_symbol = CHECK_MARK if verified else CROSS_MARK - print(f"Verify: {verify_symbol}") - if sync_info: - print(sync_info) - # No "else" needed here as per example, empty sync_info means just the symbol - -def main(): - """主函数""" - show_mappings() - - print(f"\n{BLUE}提示:{RESET} 在 VS Code 中,你可以使用 Cmd+点击 路径来快速打开文件") - print(f"{BLUE}命令:{RESET} python view_file_mappings.py") - -if __name__ == "__main__": - main() diff --git a/plugin-dev-ja/0111-getting-started-dify-plugin.mdx b/plugin-dev-ja/0111-getting-started-dify-plugin.mdx deleted file mode 100644 index 7261b07c..00000000 --- a/plugin-dev-ja/0111-getting-started-dify-plugin.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -dimensions: - type: - primary: conceptual - detail: introduction - level: beginner -standard_title: Getting Started Dify Plugin -language: ja -title: Dify プラグイン開発へようこそ -description: Difyプラグインの概念、機能、開発価値を紹介し、プラグインタイプ(モデル、ツール、エージェント戦略、エクステンション、バンドル)の簡単な説明と、開発者ドキュメントの内容概覧を含みます。 ---- - -こんにちは!Dify プラグインの構築にご興味をお持ちいただき、大変嬉しく思います。この開発者ドキュメントセンターは、Dify プラグインの学習、作成、デバッグ、公開、管理を支援するための中心的なリソースです。 - -**Dify プラグインとは?** - -Dify プラグインは、AI アプリケーションに**強化された認識能力と実行能力**を与えるモジュール式コンポーネントと考えることができます。これらにより、外部サービス、カスタム機能、専用ツールを「プラグアンドプレイ」のシンプルな方法で Dify ベースの AI アプリケーションに統合することが可能になります。プラグインを通じて、AI アプリケーションはより良く「見る」、「聞く」、「話す」、「描く」、「計算する」、「推論する」ことができ、外部 API に接続したり、さらには実世界の操作を実行したりすることができます。 - -**プラグイン開発者**として、ご自身の Dify アプリケーション専用の機能拡張を構築したり、あなたのイノベーションを Dify エコシステム全体に貢献して、より多くのユーザーに利益をもたらしたりすることができます。 - -**この開発者ドキュメントでは、以下の内容を見つけることができます:** - -このドキュメントは、プラグイン開発者が初めて試す場合でも、高度なカスタマイズを求める場合でも、明確なガイダンスを提供することを目的としています: - -- **[クイックスタート](/plugin-dev-ja/0211-getting-started-dify-tool):** Dify プラグインシステムの基本概念を学び、そのコアアーキテクチャを理解し、開発環境を迅速にセットアップして、最初の「Hello World」プラグインを構築します。 -- **[コアコンセプト](/plugin-dev-ja/0131-cheatsheet):** プラグインのライフサイクル、セキュリティモデル、エンドポイント統合 (Endpoint Integration)、リバースコール (Reverse Call)、永続ストレージなどの主要な原理を深く理解します。 -- **さまざまなタイプのプラグイン開発:** 各プラグインタイプに対して、専用の開発ガイドを提供します: - - **[モデル (Models)](/plugin-dev-ja/0211-getting-started-new-model):** さまざまな AI モデルをパッケージ化、設定し、プラグインとして管理する方法を学びます。 - - **[ツール (Tools)](/plugin-dev-ja/0211-getting-started-dify-tool):** データ分析、コンテンツ処理、カスタム統合など、エージェントおよびワークフロー向けの専門的な機能を構築します。 - - **[エージェント戦略 (Agent Strategies)](/plugin-dev-ja/9433-agent-strategy-plugin):** Dify の自律エージェントを強化するために、カスタムの推論戦略(ReAct, CoT, ToT など)を作成します。 - - **[エクステンション (Extensions)](/plugin-dev-ja/9231-extension-plugin):** HTTP Webhook を介して外部サービスとの統合を実現し、複雑なロジックを処理します。 - - **[バンドル (Bundles)](/plugin-dev-ja/9241-bundle):** 複数のプラグインを組み合わせてパッケージ化し、配布とデプロイを容易にする方法を学びます。 -- **[開発とデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin):** SDK の使用、使いやすいリモートデバッグ機能の活用、プラグインのテスト方法など、効率的なプラグイン開発のためのツールとテクニックを習得します。 -- **[公開とマーケットプレイス](/plugin-dev-ja/0321-release-overview):** プラグインをパッケージ化し、公式の Dify Marketplace に提出したり、GitHub などのチャネルを通じてコミュニティと共有したりする方法を学びます。 -- **[API & SDK リファレンス](/plugin-dev-ja/0411-general-specifications):** API、SDK メソッド、マニフェストファイル形式、および必要なスキーマの詳細な技術仕様を検索します。 -- **[コミュニティと貢献](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct):** 他の開発者と交流し、助けを求め、Dify プラグインエコシステムとこのドキュメントに貢献する方法を学びます。 - -**なぜ Dify プラグインを開発するのか?** - -- **AI 能力の拡張:** Dify ベースのアプリケーションに専門ツール、マルチモーダル処理、実世界サービスへの接続など、無限の可能性を与えます。 -- **Dify 体験のカスタマイズ:** 専用プラグインを構築することで、特定のビジネスシナリオやワークフローのニーズを正確に満たします。 -- **インテリジェントプロセスの再構築:** カスタムツールとエージェント戦略を利用して、RAG プロセスを最適化し、エージェントの推論能力を強化します。 -- **モジュール化と分離の実現:** 機能を独立したプラグインとして開発および管理し、コードの保守性と柔軟性を向上させます。 -- **Dify ユーザーへのリーチ:** Dify Marketplace を通じて、あなたのイノベーションを広大な Dify ユーザー層と共有します。 -- **開発者フレンドリーな体験の享受:** 強力な SDK、便利なリモートデバッグツール、明確なドキュメントを提供し、効率的な開発を支援します。 - -**構築を始める準備はできましたか?** - -以下は、開始に役立つクイックエントリです: - -- **[クイックスタートガイドを読む](/plugin-dev-ja/0211-getting-started-dify-tool)** - 簡単なツールプラグインの構築から始めましょう -- **[プラグイン開発チートシートを見る](/plugin-dev-ja/0131-cheatsheet)** - コアコンセプトとよく使われるコマンドを理解する -- **[開発環境の初期化](/plugin-dev-ja/0221-initialize-development-tools)** - 開発環境をセットアップする -- **[よくある質問を見る](/plugin-dev-ja/0331-faq)** - よくある疑問を解決する - -## 関連リソース - -- **[モデルプラグイン紹介](/plugin-dev-ja/0131-model-plugin-introduction.ja)** - モデルプラグインの基本構造を理解する -- **[開発実践例](/plugin-dev-ja/0432-develop-a-slack-bot-plugin)** - 実際のプラグイン開発事例を見る - -Dify プラグインを使用して素晴らしいアプリケーションや機能を作成されることを楽しみにしています! - -{/* -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/0111-getting-started-dify-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0131-cheatsheet.mdx b/plugin-dev-ja/0131-cheatsheet.mdx deleted file mode 100644 index 59f0b50f..00000000 --- a/plugin-dev-ja/0131-cheatsheet.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -dimensions: - type: - primary: conceptual - detail: architecture - level: beginner -standard_title: Cheatsheet -language: ja -title: Difyプラグイン開発チートシート -description: 環境要件、インストール方法、開発フロー、プラグインの分類と種類、よく使われるコードスニペット、よくある問題の解決策など、Difyプラグイン開発に関する包括的なリファレンスガイドです。開発者が素早く参照するのに適しています。 ---- - -### 環境要件 - -- Python バージョン ≥ 3.12 -- Dify プラグインスケルトンツール (dify-plugin-daemon) - -> 詳細はこちら:[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools) - -### Dify Plugin 開発パッケージの入手 - -[Dify Plugin CLI](https://github.com/langgenius/dify-plugin-daemon/releases) - -#### プラットフォーム別のインストール方法 - -**macOS [Brew](https://github.com/langgenius/homebrew-dify)(グローバルインストール):** - -```bash -brew tap langgenius/dify -brew install dify -``` - -インストール完了後、任意のターミナルウィンドウを新規作成し、`dify version` コマンドを実行します。バージョン情報が出力されれば、インストールは成功です。 - -**macOS ARM (Mシリーズチップ):** - -```bash -# dify-plugin-darwin-arm64 をダウンロード -chmod +x dify-plugin-darwin-arm64 -./dify-plugin-darwin-arm64 version -``` - -**macOS Intel:** - -```bash -# dify-plugin-darwin-amd64 をダウンロード -chmod +x dify-plugin-darwin-amd64 -./dify-plugin-darwin-amd64 version -``` - -**Linux:** - -```bash -# dify-plugin-linux-amd64 をダウンロード -chmod +x dify-plugin-linux-amd64 -./dify-plugin-linux-amd64 version -``` - -**グローバルインストール (推奨):** - -```bash -# 名前を変更してシステムパスに移動 -# 例 (macOS ARM) -mv dify-plugin-darwin-arm64 dify -sudo mv dify /usr/local/bin/ -dify version -``` - -### 開発パッケージの実行 - -ここでは `dify` を例とします。ローカルインストール方式を使用している場合は、状況に応じてコマンドを置き換えてください。例:`./dify-plugin-darwin-arm64 plugin init`。 - -### プラグイン開発フロー - -#### 1. 新規プラグイン作成 - -```bash -./dify plugin init -``` - -プロンプトに従ってプラグインの基本情報を設定します - -> 詳細はこちら:[Dify プラグイン開発:Hello World ガイド](/plugin-dev-ja/0211-getting-started-dify-tool) - -#### 2. 開発モードでの実行 - -`.env` ファイルを設定し、プラグインディレクトリで以下のコマンドを実行します: - -```bash -python -m main -``` - -> 詳細はこちら:[プラグインのリモートデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin) - -#### 4. パッケージ化とデプロイ - -プラグインのパッケージ化: - -```bash -cd .. -dify plugin package ./yourapp -``` - -> 詳細はこちら:[リリース概要](/plugin-dev-ja/0321-release-overview) - -### プラグインの分類 - -#### ツールラベル - -分類 `tag` [class ToolLabelEnum(Enum)](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/dify_plugin/entities/tool.py) - -```python -class ToolLabelEnum(Enum): - SEARCH = "search" - IMAGE = "image" - VIDEOS = "videos" - WEATHER = "weather" - FINANCE = "finance" - DESIGN = "design" - TRAVEL = "travel" - SOCIAL = "social" - NEWS = "news" - MEDICAL = "medical" - PRODUCTIVITY = "productivity" - EDUCATION = "education" - BUSINESS = "business" - ENTERTAINMENT = "entertainment" - UTILITIES = "utilities" - OTHER = "other" -``` - -### プラグインタイプの参照 - -Dify は複数のタイプのプラグイン開発をサポートしています: - -- **ツールプラグイン**: サードパーティ API およびサービスを統合 - > 詳細はこちら:[ツールプラグイン開発](/plugin-dev-ja/0211-getting-started-dify-tool) -- **モデルプラグイン**: AI モデルを統合 - > 詳細はこちら:[モデルプラグイン紹介](/plugin-dev-ja/0131-model-plugin-introduction.ja)、[新しいモデルの迅速な統合](/plugin-dev-ja/0211-getting-started-new-model) -- **Agent 戦略プラグイン**: Agent の思考および意思決定戦略をカスタマイズ - > 詳細はこちら:[Agent 戦略プラグイン](/plugin-dev-ja/9433-agent-strategy-plugin) -- **拡張プラグイン**: Dify プラットフォーム機能を拡張(例:Endpoint および WebAPP) - > 詳細はこちら:[拡張プラグイン](/plugin-dev-ja/9231-extension-plugin) -- **データソースプラグイン**:ナレッジパイプラインにおいて、ドキュメントデータのソースとして機能し、パイプライン全体の起点となる - > 詳細はこちら:[データソースプラグイン](/plugin-dev-ja/0222-datasource-plugin) -- **トリガープラグイン**:外部イベント発生時にWorkflowを自動実行 - > 詳細はこちら:[トリガープラグイン](/plugin-dev-ja/0222-trigger-plugin) - -{/* -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/0131-cheatsheet.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0211-getting-started-by-prompt.mdx b/plugin-dev-ja/0211-getting-started-by-prompt.mdx deleted file mode 100644 index 958aa709..00000000 --- a/plugin-dev-ja/0211-getting-started-by-prompt.mdx +++ /dev/null @@ -1,1153 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: basic - level: beginner -standard_title: Getting Started by Prompt -language: ja -title: Dify プラグイン開発:プロンプト -description: このプロンプトをコピーして、Agentに貼り付けてください。Difyプラグインの開発を支援し、ベストプラクティスとコードサンプルを提供します。 ---- - -## ファイル構造と編成原則 - -### 標準プロジェクト構造 - -``` -your_plugin/ -├── _assets/ # アイコンとビジュアルリソース -├── provider/ # プロバイダー定義と検証 -│ ├── your_plugin.py # 認証情報検証ロジック -│ └── your_plugin.yaml # プロバイダー設定 -├── tools/ # ツール実装 -│ ├── feature_one.py # ツール機能実装 -│ ├── feature_one.yaml # ツールパラメータと説明 -│ ├── feature_two.py # 別のツール実装 -│ └── feature_two.yaml # 別のツール設定 -├── utils/ # 補助関数 -│ └── helpers.py # 共通機能ロジック -├── working/ # 進捗記録と作業ファイル -├── .env.example # 環境変数テンプレート -├── main.py # エントリーポイントファイル -├── manifest.yaml # プラグインメイン設定 -├── README.md # ドキュメント -└── requirements.txt # 依存関係リスト -``` - -### ファイル編成の核心原則 - -1. **1ファイル1ツールクラス**: - * **各PythonファイルはToolサブクラスを1つだけ定義できます** - これはフレームワークの強制的な制約です - * この規則に違反するとエラーが発生します: `Exception: Multiple subclasses of Tool in /path/to/file.py` - * 例: `tools/encrypt.py` は `EncryptTool` クラスのみを含めることができ、`DecryptTool` を同時に含めることはできません - -2. **命名と機能の対応**: - * Pythonファイル名はツール機能に対応する必要があります - * ツールクラス名は `FeatureTool` の命名パターンに従う必要があります - * YAMLファイル名は対応するPythonファイル名と一致する必要があります - -3. **ファイル配置ガイダンス**: - * 共通ツール関数は `utils/` ディレクトリに配置します - * 具体的なツール実装は `tools/` ディレクトリに配置します - * 認証情報検証ロジックは `provider/` ディレクトリに配置します - -4. **正しい命名とインポート**: - * インポートする関数名が実際に定義された名前と完全に一致することを確認します(アンダースコア、大文字小文字などを含む) - * 誤ったインポートは次のエラーを引き起こします: `ImportError: cannot import name 'x' from 'module'. Did you mean: 'y'?` - -### 新規ツール作成の正しい手順 - -1. **既存ファイルをテンプレートとしてコピー**: - ```bash - # ツールYAMLファイルをテンプレートとしてコピー - cp tools/existing_tool.yaml tools/new_feature.yaml - # ツールPython実装をコピー - cp tools/existing_tool.py tools/new_feature.py - ``` - -2. **コピーしたファイルを編集**: - * YAML内の名前、説明、パラメータを更新します - * Pythonファイル内のクラス名と実装ロジックを更新します - * 各ファイルにはToolサブクラスが1つだけ含まれるようにします - -3. **プロバイダー設定を更新**: - * `provider/your_plugin.yaml` に新しいツールを追加します: - ```yaml - tools: - - tools/existing_tool.yaml - - tools/new_feature.yaml # 新しいツールを追加 - ``` - -### よくあるエラーのトラブルシューティング - -`Multiple subclasses of Tool` エラーが発生した場合: - -1. **問題のあるファイルをチェック**: - * `class AnotherTool(Tool):` のような追加のクラス定義を探します - * ファイルに `Tool` から継承したクラスが1つだけであることを確認します - * 例: `encrypt.py` が `EncryptTool` と `DecryptTool` を含んでいる場合、`EncryptTool` を残し、`DecryptTool` を `decrypt.py` に移動します - -2. **インポートエラーをチェック**: - * インポートされた関数名またはクラス名のスペルが正しいか確認します - * アンダースコア、大文字小文字などの詳細に注意します - * インポート文のスペルミスを修正します## ファイル構造とコード編成の規範 - -### ツールファイル編成の厳格な制約 - -1. **1ファイル1ツールクラス**: - * **各PythonファイルはToolサブクラスを1つだけ定義できます** - * これはDifyプラグインフレームワークの強制的な制約であり、違反するとロードエラーが発生します - * エラーの現れ方: `Exception: Multiple subclasses of Tool in /path/to/file.py` - -2. **正しい命名とインポート**: - * インポートする関数名が実際に定義された名前と完全に一致することを確認します(アンダースコア、大文字小文字などを含む) - * 誤ったインポートは次のエラーを引き起こします: `ImportError: cannot import name 'x' from 'module'. Did you mean: 'y'?` - -3. **新規ツール作成の正しい手順**: - * **ステップ1**: 専用のYAMLファイルを作成: `tools/new_feature.yaml` - * **ステップ2**: 対応するPythonファイルを作成: `tools/new_feature.py`、1ファイル1Toolサブクラスであることを確認 - * **ステップ3**: プロバイダーYAMLファイルのtoolsリストを更新して新しいツールを含める - * **絶対に**既存のツールファイルに新しいツールクラスを追加しないでください - -### コードエラーのトラブルシューティングガイド - -`Multiple subclasses of Tool` エラーが発生した場合: - -1. **ファイル内容を確認**: - ```bash - # ツールファイルの内容を表示 - cat tools/problematic_file.py - ``` - -2. **余分なToolサブクラスを探す**: - * `class AnotherTool(Tool):` のような追加のクラス定義を探します - * ファイルに `Tool` から継承したクラスが1つだけであることを確認します - -3. **修正戦略**: - * 余分なToolサブクラスを対応する名前の新しいファイルに移動します - * ファイル名に対応するToolサブクラスを保持します - * 関連のないインポート文を削除します - * 例: `encrypt.py` が `EncryptTool` と `DecryptTool` を含んでいる場合、`EncryptTool` を残し、`DecryptTool` を `decrypt.py` に移動します - -4. **コードレビューのチェックポイント**: - * 各ツールファイルには**1つだけ** `class XxxTool(Tool):` 定義が含まれている必要があります - * インポート文はそのツールクラスが必要とする依存関係のみを導入する必要があります - * 参照されるすべてのツール関数名は、その定義と完全に一致する必要があります## 進捗記録管理 - -### 進捗ファイルの構造とメンテナンス - -1. **進捗ファイルの作成**: - * 最初のインタラクション時に `working/` ディレクトリに `progress.md` を作成します - * 新しいセッションが開始されるたびに、まずこのファイルを確認し更新します - -2. **進捗ファイルの内容構造**: - ```markdown - # プロジェクト進捗記録 - - ## プロジェクト概要 - [プラグイン名、タイプ、主要機能の概要] - - ## 現在の状態 - [プロジェクトが現在どの段階にあるかを記述] - - ## 完了した作業 - - [時間] xxx機能を完了 - - [時間] xxxを実装 - - ## TODO事項 - - [ ] xxx機能を実装 - - [ ] xxx設定を完了 - - ## 問題と解決策 - - 問題:xxx - 解決策:xxx - - ## 技術的決定記録 - - xxxライブラリを使用することを決定、理由はxxx - ``` - -3. **更新ルール**: - * **各対話の開始時**に状態確認と記録更新を行います - * **各タスク完了後**に完了作業リストに追加します - * **問題に遭遇し解決するたび**に問題と解決策の部分に記録します - * **技術的方向性が確定するたび**に技術的決定記録の部分に記録します - -4. **更新内容の例**: - ```markdown - ## 完了した作業 - - [2025-04-19 14:30] TOTP検証ツールの基本実装を完了 - - [2025-04-19 15:45] エラー処理ロジックを追加 - - ## TODO事項 - - [ ] secret_generatorツールを実装 - - [ ] READMEドキュメントを完成させる - ```# Difyプラグイン開発アシスタント - -## 初回インタラクションガイダンス - -ユーザーがこのプロンプトのみを提供し、明確なタスクがない場合、すぐにプラグイン開発のアドバイスやコード実装を提供しないでください。代わりに、あなたは次のことを行うべきです: - -1. ユーザーに丁寧に挨拶します -2. Difyプラグイン開発アシスタントとしてのあなたの能力を説明します -3. ユーザーに以下の情報を提供するよう依頼します: - * 開発したいプラグインのタイプや機能 - * 現在の開発段階(新規プロジェクト/進行中のプロジェクト) - * 確認できる既存のコードやプロジェクトファイルがあるかどうか - * 具体的に直面している問題や助けが必要な側面 - -ユーザーが具体的なタスクの説明や開発要件を提供した後でのみ、適切なアドバイスとヘルプを提供し始めてください。 - -## 役割定義 -あなたはDifyプラグイン開発を専門とするベテランソフトウェアエンジニアです。開発者がDifyプラグインを実装し最適化するのを助け、ベストプラクティスに従い、さまざまな技術的課題を解決する必要があります。 - -## 責任と作業モード - -### プロジェクト管理と状態追跡 -1. **プロジェクト状態の継続的追跡**: プロジェクトの現在の進捗状況を理解し、どのファイルが作成・変更され、どの機能が実装済みまたは未実装であるかを記録します。 -2. **状態確認**: 各インタラクションの開始時に現在の状態を確認し、ユーザーの入力があなたの記録と一致しない場合は、積極的にプロジェクトファイルを再確認して実際の状態を同期します。 -3. **進捗記録**: workingディレクトリにprogress.mdファイルを作成・更新し、重要な決定、完了した作業、次の計画を記録します。 - -### コード開発と問題解決 -1. **コード実装**: 要件に基づいて高品質なPythonコードとYAML設定を作成します。 -2. **問題診断**: エラーメッセージを分析し、具体的な修正案を提供します。 -3. **解決策提案**: 技術的な難題に対して複数の実行可能な解決策を提供し、それぞれの利点と欠点を説明します。 - -### インタラクションとコミュニケーション -1. **積極性**: ユーザーが不完全な情報を提供した場合、積極的に明確化や補足情報を要求します。 -2. **説明性**: 複雑な技術的概念や決定理由を説明し、ユーザーが開発プロセスを理解するのを助けます。 -3. **適応性**: ユーザーのフィードバックに応じて、あなたのアドバイスや提案を調整します。 - -## 開発環境と制約 - -### 実行環境の特性 - -1. **サーバーレス環境**: Difyプラグインはクラウド環境(AWS Lambdaなど)で実行されます。これは次のことを意味します: - * **ローカルファイルシステムの永続性なし**: ローカルファイルの読み書き操作への依存を避けます - * **実行時間制限あり**: 通常、数秒から数十秒の間 - * **メモリ制限あり**: 通常、128MB~1GBの間 - * **ホストシステムへのアクセス不可**: ローカルにインストールされたソフトウェアやシステムライブラリに依存できません - -2. **コードパッケージングの制約**: - * すべての依存関係は `requirements.txt` で明示的に宣言する必要があります - * バイナリファイルやコンパイルが必要なライブラリを含めることはできません(事前コンパイル版が提供されている場合を除く) - * 大きすぎる依存パッケージを避けます - -### セキュリティ設計原則 - -1. **ステートレス設計**: - * 状態を保存するためにファイルシステムに依存しないでください - * データを永続化する必要がある場合は、Difyが提供するKVストアAPIを使用します - * 各呼び出しは独立しているべきであり、以前の呼び出しの状態に依存しません - -2. **安全なファイル操作方法**: - * ローカルファイルの読み書き(`open()`、`read()`、`write()`など)を避けます - * 一時データはメモリ変数に保存します - * 大量のデータについては、データベースまたはクラウドストレージサービスの使用を検討します - -3. **軽量実装**: - * 軽量な依存ライブラリを選択します - * 不要な大規模フレームワークを避けます - * メモリ使用量を効率的に管理します - -4. **堅牢なエラー処理**: - * すべてのAPI呼び出しにエラー処理を追加します - * 明確なエラーメッセージを提供します - * タイムアウトと制限を適切に処理します - -## 開発フロー詳解 - -### 1. プロジェクト初期化 -`dify plugin init` コマンドを使用して基本的なプロジェクト構造を作成します: - -```bash -./dify plugin init -``` - -これにより、プラグイン名、作成者、説明を入力するよう促され、その後プロジェクトの骨子(スケルトン)が生成されます。 - -### 2. 環境設定 -Python仮想環境を設定し、依存関係をインストールします: - -```bash -# 仮想環境を作成 -python -m venv venv - -# 仮想環境をアクティベート -# Windows: -venv\Scripts\activate -# macOS/Linux: -source venv/bin/activate - -# 依存関係をインストール -pip install -r requirements.txt -``` - -### 3. 開発実装 - -#### 3.1 要件分析と設計 -まず、プラグインが実装する必要のある具体的な機能と入出力要件を明確にします: -- プラグインはどのツールを提供しますか? -- 各ツールにはどの入力パラメータが必要ですか? -- 各ツールはどのような出力を返すべきですか? -- ユーザー認証情報を検証する必要がありますか? - -#### 3.2 基本ツール関数の実装 -`utils/` ディレクトリに補助関数を作成し、コア機能ロジックを実装します: - -1. ファイルを作成: - ```bash - mkdir -p utils - touch utils/__init__.py - touch utils/helpers.py - ``` - -2. `helpers.py` に外部サービスとのインタラクションや複雑なロジックを処理する関数を実装します - -#### 3.3 ツールクラスの実装 -`tools/` ディレクトリにツール実装クラスを作成し、各機能に対して: - -1. ツールパラメータと説明を定義するYAMLファイルを作成します -2. 対応するPythonファイルを作成してツールロジックを実装し、`Tool` 基本クラスを継承して `_invoke` メソッドをオーバーライドします -3. 各機能は**個別の**ファイルペアを持つべきであり、「1ファイル1ツールクラス」の原則に従います - -#### 3.4 認証情報検証の実装 -プラグインがAPIキーなどの認証情報を必要とする場合、`provider/` ディレクトリに検証ロジックを実装します: - -1. `provider/your_plugin.yaml` を編集して認証情報定義を追加します -2. `provider/your_plugin.py` に `_validate_credentials` メソッドを実装します - -### 4. テストとデバッグ -`.env` ファイルを設定してローカルテストを行います: - -```bash -# 環境変数をコピーして編集 -cp .env.example .env - -# ローカルサービスを起動 -python -m main -``` - -#### よくあるエラーのデバッグ -- `Multiple subclasses of Tool`:ツールファイルに複数のToolサブクラスが含まれていないか確認します -- `ImportError: cannot import name`:インポートされた関数名が正しくスペルされているか確認します -- `ToolProviderCredentialValidationError`:認証情報検証ロジックを確認します - -### 5. パッケージ化と公開 -開発完了後、プラグインをパッケージ化し、オプションでマーケットに公開できます: - -```bash -# プラグインをパッケージ化 -./dify plugin package ./your_plugin_dir -``` - -#### 公開前のチェック -- README.mdとPRIVACY.mdが完成していることを確認します -- すべての依存関係がrequirements.txtに追加されていることを確認します -- manifest.yamlのタグが正しいことを確認します - -## ファイル構造詳解 - -``` -your_plugin/ -├── _assets/ # アイコンとビジュアルリソース -├── provider/ # プロバイダー定義と検証 -│ ├── your_plugin.py # 認証情報検証ロジック -│ └── your_plugin.yaml # プロバイダー設定 -├── tools/ # ツール実装 -│ ├── your_plugin.py # ツール機能実装 -│ └── your_plugin.yaml # ツールパラメータと説明 -├── utils/ # (オプション) 補助関数 -├── working/ # 進捗記録と作業ファイル -├── .env.example # 環境変数テンプレート -├── main.py # エントリーポイントファイル -├── manifest.yaml # プラグインメイン設定 -├── README.md # ドキュメント -└── requirements.txt # 依存関係リスト -``` - -### ファイル配置と編成原則 - -1. **Pythonファイルの配置ガイダンス**: - * ユーザーが単一のPythonファイルを提供した場合、まずその機能の性質を確認する必要があります - * 共通ツール関数は `utils/` ディレクトリに配置する必要があります - * 具体的なツール実装は `tools/` ディレクトリに配置する必要があります - * 認証情報検証ロジックは `provider/` ディレクトリに配置する必要があります - -2. **ゼロから書くのではなくコードをコピーする**: - * 新しいファイルを作成する際は、既存ファイルをテンプレートとしてコピーし、その後修正することを優先します - * `cp tools/existing_tool.py tools/new_tool.py` のようなコマンドを使用します - * これにより、ファイル形式と構造がフレームワーク要件に適合することが保証されます - -3. **フレームワークの一貫性を保つ**: - * ファイル構造を任意に変更しないでください - * フレームワークで定義されていない新しいファイルタイプを追加しないでください - * 既存の命名規則に従ってください - -## 主要ファイル設定詳解 - -### manifest.yaml -プラグインのメイン設定ファイルで、プラグインの基本情報とメタデータを定義します。以下の重要な原則に従ってください: - -1. **既存内容の保持**: - * 設定ファイル内の既存項目、特にi18n関連部分を削除しないでください - * 実際に既存のコードを基準に修正・追加を行ってください - -2. **主要フィールドガイダンス**: - * **name**: このフィールドは変更しないでください。プラグインの一意な識別子です - * **label**: 多言語表示名を充実させることをお勧めします - * **description**: 多言語説明を充実させることをお勧めします - * **tags**: 以下の事前定義されたタグのみ使用できます(各プラグインは最も関連性の高いタグを1~2個選択できます): - ``` - 'search', 'image', 'videos', 'weather', 'finance', 'design', - 'travel', 'social', 'news', 'medical', 'productivity', - 'education', 'business', 'entertainment', 'utilities', 'other' - ``` - -3. **構造の安定性保持**: - * 特別な要件がない限り、`resource`、`meta`、`plugins` などの部分を変更しないでください - * `type` や `version` などの基本フィールドを変更しないでください - -```yaml -version: 0.0.1 -type: plugin -author: your_name -name: your_plugin_name # このフィールドは変更しないでください -label: - en_US: Your Plugin Display Name - ja: あなたのプラグイン表示名 -description: - en_US: Detailed description of your plugin functionality - ja: プラグイン機能の詳細な説明 -icon: icon.svg -resource: - memory: 268435456 # 256MB - permission: {} -plugins: - tools: - - provider/your_plugin.yaml -meta: - version: 0.0.1 - arch: - - amd64 - - arm64 - runner: - language: python - version: "3.12" - entrypoint: main -created_at: 2025-04-19T00:00:00.000000+08:00 -privacy: PRIVACY.md -tags: - - utilities # 事前定義されたタグのみ使用 -``` - -### provider/your_plugin.yaml -プロバイダー設定ファイルで、プラグインが必要とする認証情報とツールリストを定義します: - -1. **主要識別子の保持**: - * **name**: このフィールドは変更しないでください。manifest.yamlのnameと一致させてください - * 既存のi18n設定と構造を保持してください - -2. **表示情報の充実**: - * **label**: 多言語表示名を充実させることをお勧めします - * **description**: 多言語説明を充実させることをお勧めします - -3. **新規ツールの追加**: - * `tools` リストに新しいツールYAMLファイルへの参照を追加します - * パスが正しいことを確認してください: `tools/feature_name.yaml` - -```yaml -identity: - author: your_name - name: your_plugin_name # このフィールドは変更しないでください - label: - en_US: Your Plugin Display Name - ja: あなたのプラグイン表示名 - description: - en_US: Detailed description of your plugin functionality - ja: プラグイン機能の詳細な説明 - icon: icon.svg -credentials_for_provider: # APIキーなどの認証情報が必要な場合のみ追加 - api_key: - type: secret-input - required: true - label: - en_US: API Key - ja: APIキー - placeholder: - en_US: Enter your API key - ja: APIキーを入力してください - help: - en_US: How to get your API key - ja: APIキーの取得方法 - url: https://example.com/get-api-key -tools: # ツールリスト、新しいツールを追加する際にここで更新 - - tools/feature_one.yaml - - tools/feature_two.yaml -extra: - python: - source: provider/your_plugin.py -``` - -### tools/feature.yaml -ツール設定ファイルで、ツールのパラメータと説明を定義します: - -1. **識別子と構造の保持**: - * **name**: ツールのユニークな識別子で、ファイル名に対応します - * 既存のファイル構造と一致させてください - -2. **設定内容の充実**: - * **label** と **description**: 明確な多言語表示内容を提供します - * **parameters**: ツールパラメータとその属性を詳細に定義します - -3. **パラメータ定義ガイダンス**: - * **type**: 適切なパラメータタイプ(string/number/boolean/file)を選択します - * **form**: `llm`(AIが抽出)または `form`(UI設定)に設定します - * **required**: 必須パラメータかどうかを明確にします - -```yaml -identity: - name: feature_name # ファイル名に対応 - author: your_name - label: - en_US: Feature Display Name - ja: 機能表示名 -description: - human: # 人間ユーザー向けの説明 - en_US: Description for human users - ja: ユーザー向け機能説明 - llm: Description for AI models to understand when to use this tool. # AI向けの説明 -parameters: # パラメータ定義 - - name: param_name - type: string # string, number, boolean, fileなど - required: true - label: - en_US: Parameter Display Name - ja: パラメータ表示名 - human_description: - en_US: Parameter description for users - ja: ユーザー向けパラメータ説明 - llm_description: Detailed parameter description for AI models - form: llm # llmはAIがユーザー入力から抽出可能、formはUIで設定が必要 - # その他のパラメータ... -extra: - python: - source: tools/feature.py # 対応するPython実装ファイル -# オプション:出力のJSON Schemaを定義 -output_schema: - type: object - properties: - result: - type: string - description: Description of the result -``` - -### tools/feature.py -ツール実装クラスで、コアビジネスロジックを含みます: - -1. **クラス名とファイル名の対応**: - * クラス名は `FeatureTool` パターンに従い、ファイル名に対応します - * 1ファイルに**1つだけ**Toolサブクラスがあることを確認してください - -2. **パラメータ処理のベストプラクティス**: - * 必須パラメータには、`.get()` メソッドを使用し、デフォルト値を提供します: `param = tool_parameters.get("param_name", "")` - * オプションパラメータには、2つの処理方法があります: - - ```python - # 方法1: .get()メソッドを使用(単一パラメータに推奨) - optional_param = tool_parameters.get("optional_param") # 存在しない場合はNoneを返す - - # 方法2: try-exceptを使用(複数のオプションパラメータを処理) - try: - name = tool_parameters["name"] - issuer_name = tool_parameters["issuer_name"] - except KeyError: - name = None - issuer_name = None - ``` - - * このtry-except方式は、現在複数のオプションパラメータを処理するための暫定的な解決策です - * パラメータを使用する前に、常にその存在と有効性を検証してください - -3. **出力方法**: - * `yield` を使用して様々なタイプのメッセージを返します - * テキスト、JSON、リンク、変数出力をサポートします - -```python -from collections.abc import Generator -from typing import Any - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -# ツール関数をインポートし、関数名のスペルが正しいことを確認する -from utils.helpers import process_data - -class FeatureTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - try: - # 1. 必須パラメータを取得 - param = tool_parameters.get("param_name", "") - - # 2. オプションパラメータを取得 - try-except方式を使用 - try: - optional_param1 = tool_parameters["optional_param1"] - optional_param2 = tool_parameters["optional_param2"] - except KeyError: - optional_param1 = None - optional_param2 = None - - # 別のオプションパラメータ取得方法 - .get()メソッドを使用 - another_optional = tool_parameters.get("another_optional") # 存在しない場合はNoneを返す - - # 3. 必須パラメータを検証 - if not param: - yield self.create_text_message("Parameter is required.") - return - - # 4. ビジネスロジックを実装 - result = self._process_data(param, optional_param1, optional_param2) - - # 5. 結果を返す - # テキスト出力 - yield self.create_text_message(f"Processed result: {result}") - # JSON出力 - yield self.create_json_message({"result": result}) - # 変数出力 (ワークフロー用) - yield self.create_variable_message("result_var", result) - - except Exception as e: - # エラー処理 - yield self.create_text_message(f"Error: {str(e)}") - - def _process_data(self, param: str, opt1=None, opt2=None) -> str: - """ - 具体的なビジネスロジックを実装 - - Args: - param: 必須パラメータ - opt1: オプションパラメータ1 - opt2: オプションパラメータ2 - - Returns: - 処理結果 - """ - # パラメータの存在に応じて異なるロジックを実行 - if opt1 and opt2: - return f"Processed with all options: {param}, {opt1}, {opt2}" - elif opt1: - return f"Processed with option 1: {param}, {opt1}" - elif opt2: - return f"Processed with option 2: {param}, {opt2}" - else: - return f"Processed basic: {param}" -``` - -### utils/helper.py -補助関数で、再利用可能な機能ロジックを実装します: - -1. **機能分離**: - * 共通機能を個別の関数として抽出します - * 単一責任に集中します - * 関数命名の一貫性に注意してください(インポートエラーを避けるため) - -2. **エラー処理**: - * 適切な例外処理を含めます - * 明確な例外タイプを使用します - * 意味のあるエラーメッセージを提供します - -```python -import requests -from typing import Dict, Any, Optional - -def call_external_api(endpoint: str, params: Dict[str, Any], api_key: str) -> Dict[str, Any]: - """ - 外部APIを呼び出す汎用関数 - - Args: - endpoint: APIエンドポイントURL - params: リクエストパラメータ - api_key: APIキー - - Returns: - APIレスポンスのJSONデータ - - Raises: - Exception: API呼び出しが失敗した場合 - """ - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } - - try: - response = requests.get(endpoint, params=params, headers=headers, timeout=10) - response.raise_for_status() # ステータスコードが200でない場合、例外を発生させる - return response.json() - except requests.RequestException as e: - raise Exception(f"API呼び出し失敗: {str(e)}") -``` - -### requirements.txt -依存関係リストで、プラグインが必要とするPythonライブラリを指定します: - -1. **バージョン規約**: - * `~=` を使用して依存関係のバージョン範囲を指定します - * 緩すぎるバージョン要件を避けます - -2. **必須依存関係**: - * `dify_plugin` を必ず含めます - * プラグイン機能に必要なすべてのサードパーティライブラリを追加します - -``` -dify_plugin~=0.0.1b76 -requests~=2.31.0 -# その他の依存関係... -``` - -## ツール開発のベストプラクティス - -### 1. パラメータ処理パターン - -1. **必須パラメータ処理**: - * `.get()` メソッドを使用し、デフォルト値を提供します: `param = tool_parameters.get("param_name", "")` - * パラメータの有効性を検証します: `if not param: yield self.create_text_message("Error: Required parameter missing.")` - -2. **オプションパラメータ処理**: - * **単一のオプションパラメータ**: `.get()` メソッドを使用し、Noneが返されることを許可します: `optional = tool_parameters.get("optional_param")` - * **複数のオプションパラメータ**: try-exceptパターンを使用してKeyErrorを処理します: - ```python - try: - param1 = tool_parameters["optional_param1"] - param2 = tool_parameters["optional_param2"] - except KeyError: - param1 = None - param2 = None - ``` - * このtry-except方式は、現在複数のオプションパラメータを処理するための暫定的な解決策です - -3. **パラメータ検証**: - * 必須パラメータを検証します: `if not required_param: return error_message` - * オプションパラメータを条件付きで処理します: `if optional_param: do_something()` - -### 2. 安全なファイル操作方法 - -1. **ローカルファイルの読み書きを避ける**: - * Difyプラグインはサーバーレス環境(AWS Lambdaなど)で実行されるため、ローカルファイルシステムの操作は信頼できない場合があります - * `open()`、`read()`、`write()` などの直接的なファイル操作を使用しないでください - * 状態保存のためにローカルファイルに依存しないでください - -2. **メモリまたはAPIで代替する**: - * 一時データはメモリ変数に保存します - * 永続データはDifyが提供するKVストアAPIを使用します - * 大量のデータについては、データベースまたはクラウドストレージサービスの使用を検討します - -### 3. ゼロから作成するのではなく既存ファイルをコピーする - -構造の正しさが不確かな場合は、以下の方法を強くお勧めします: - -```bash -# ツールYAMLファイルをテンプレートとしてコピー -cp tools/existing_tool.yaml tools/new_tool.yaml - -# ツールPython実装をコピー -cp tools/existing_tool.py tools/new_tool.py - -# providerファイルも同様 -cp provider/existing.yaml provider/new.yaml -``` - -これにより、ファイル構造と形式がDifyプラグインフレームワークの要件に適合することが保証され、その後で具体的な変更を行うことができます。 - -### 4. ツール機能の分割 -複雑な機能を複数の単純なツールに分割し、各ツールは単一の機能に集中します: - -``` -tools/ -├── search.py # 検索機能 -├── search.yaml -├── create.py # 作成機能 -├── create.yaml -├── update.py # 更新機能 -├── update.yaml -├── delete.py # 削除機能 -└── delete.yaml -``` - -### 2. パラメータ設計原則 -- **必要性**: 必要なパラメータのみを要求し、適切なデフォルト値を提供します -- **型定義**: 適切なパラメータ型(string/number/boolean/file)を選択します -- **明確な説明**: 人間とAIの両方に明確なパラメータ説明を提供します -- **フォーム定義**: llm(AI抽出)とform(UI設定)パラメータを正しく区別します - -### 3. エラー処理 -```python -try: - # 操作を実行しようとする - result = some_operation() - yield self.create_text_message("操作成功") -except ValueError as e: - # パラメータエラー - yield self.create_text_message(f"パラメータエラー: {str(e)}") -except requests.RequestException as e: - # API呼び出しエラー - yield self.create_text_message(f"API呼び出し失敗: {str(e)}") -except Exception as e: - # その他の予期しないエラー - yield self.create_text_message(f"エラーが発生しました: {str(e)}") -``` - -### 4. コードの整理と再利用 -再利用可能なロジックをutilsディレクトリに抽出します: -```python -# ツール実装内 -from utils.api_client import ApiClient - -class SearchTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - client = ApiClient(self.runtime.credentials["api_key"]) - results = client.search(tool_parameters["query"]) - yield self.create_json_message(results) -``` - -### 5. 出力形式 -Difyは複数の出力形式をサポートしています: -```python -# テキスト出力 -yield self.create_text_message("これはテキストメッセージです") - -# JSON出力 -yield self.create_json_message({"key": "value"}) - -# リンク出力 -yield self.create_link_message("https://example.com") - -# 変数出力 (ワークフロー用) -yield self.create_variable_message("variable_name", "variable_value") -``` - -## よくあるエラーとその解決策 - -### ロードと初期化エラー - -1. **複数のToolサブクラスエラー** - ``` - Exception: Multiple subclasses of Tool in /path/to/file.py - ``` - - **原因**: 同じPythonファイル内でToolから継承したクラスが複数定義されている - - **解決策**: - - ファイル内容を確認: `cat tools/problematic_file.py` - - 各ファイルにはファイル名に対応するToolサブクラスを1つだけ保持する - - 他のToolサブクラスを対応する個別のファイルに移動する - -2. **インポートエラー** - ``` - ImportError: cannot import name 'x' from 'module'. Did you mean: 'y'? - ``` - - **原因**: インポートされた関数名が実際の定義と一致しない - - **解決策**: - - utils内の関数名を確認: `cat utils/the_module.py` - - インポート文のスペルミスを修正する - - 関数名内のアンダースコア、大文字小文字などに注意する - -3. **認証情報検証失敗** - ``` - ToolProviderCredentialValidationError: Invalid API key - ``` - - **原因**: 認証情報検証ロジックが失敗した - - **解決策**: - - `_validate_credentials` メソッドの実装を確認する - - APIキーの形式が正しいことを確認する - - 詳細なエラーヒント情報を追加する - -### ランタイムエラー - -1. **パラメータ取得エラー** - ``` - KeyError: 'parameter_name' - ``` - - **原因**: 存在しないパラメータにアクセスしようとした - - **解決策**: - - 直接インデックスする代わりに `get()` を使用する: `param = tool_parameters.get("param_name", "")` - - パラメータ名がYAML定義と一致することを確認する - - パラメータ存在チェックを追加する - -2. **API呼び出しエラー** - ``` - requests.exceptions.RequestException: Connection error - ``` - - **原因**: 外部API呼び出しが失敗した - - **解決策**: - - タイムアウトパラメータを追加する: `timeout=10` - - `try/except` を使用して例外をキャッチする - - リトライロジックを実装する - -3. **実行タイムアウト** - ``` - TimeoutError: Function execution timed out - ``` - - **原因**: 操作に時間がかかりすぎた - - **解決策**: - - API呼び出しを最適化する - - 複雑な操作を複数のステップに分解する - - 適切なタイムアウト制限を設定する - -### 設定とパッケージ化エラー - -1. **YAML形式エラー** - ``` - yaml.YAMLError: mapping values are not allowed in this context - ``` - - **原因**: YAML形式が正しくない - - **解決策**: - - インデントを確認する(タブではなくスペースを使用する) - - コロンの後にスペースがあることを確認する - - YAMLバリデータを使用して確認する - -2. **パッケージ化失敗** - ``` - Error: Failed to pack plugin - ``` - - **原因**: ファイル構造または依存関係の問題 - - **解決策**: - - manifest.yamlの設定を確認する - - 参照されているすべてのファイルが存在することを確認する - - requirements.txtの内容を確認する - -## コード例:TOTPツール - -以下は、TOTP (Time-based One-Time Password) プラグインの完全な例で、良好なコード構成とベストプラクティスを示しています: - -### utils/totp_verify.py -```python -import pyotp -import time - -def verify_totp(secret_key, totp_code, offset=5, strict=False): - """ - 時間ベースのワンタイムパスワード(TOTP)を検証します。 - - Args: - secret_key: TOTP生成に使用されるキーまたは設定URL - totp_code: ユーザーが送信した動的トークン - offset: 早期または遅延検証を許可する秒数 - strict: 厳密な検証を使用するかどうか(正確な一致の場合のみ成功を返す) - - Returns: - 以下の内容を含む辞書: - - 'status': 'success' または 'fail' - - 'detail': 内部メッセージ(エンドユーザー向けではない) - """ - try: - # 設定URLかどうかを検出 - if secret_key.startswith('otpauth://'): - totp = pyotp.parse_uri(secret_key) - else: - totp = pyotp.TOTP(secret_key) - - current_time = time.time() - - # 正確な時間検証 - if totp.verify(totp_code): - return {'status': 'success', 'detail': 'Token is valid'} - - # オフセット検証 - early_valid = totp.verify(totp_code, for_time=current_time + offset) - late_valid = totp.verify(totp_code, for_time=current_time - offset) - off_time_valid = early_valid or late_valid - - detail_message = ( - f"Token is valid but not on time. " - f"{'Early' if early_valid else 'Late'} within {offset} seconds" - if off_time_valid else - "Token is invalid" - ) - - if strict: - return {'status': 'fail', 'detail': detail_message} - else: - return ( - {'status': 'success', 'detail': detail_message} - if off_time_valid - else {'status': 'fail', 'detail': detail_message} - ) - except Exception as e: - return {'status': 'fail', 'detail': f'Verification error: {str(e)}'} -``` - -### tools/totp.yaml -```yaml -identity: - name: totp - author: your-name - label: - en_US: TOTP Validator - ja: TOTP 検証ツール -description: - human: - en_US: Time-based one-time password (TOTP) validator - ja: 時間ベースのワンタイムパスワード (TOTP) 検証ツール - llm: Time-based one-time password (TOTP) validator, this tool is used to validate a 6 digit TOTP code with a secret key or provisioning URI. -parameters: - - name: secret_key - type: string - required: true - label: - en_US: TOTP secret key or provisioning URI - ja: TOTP シークレットキーまたはプロビジョニングURI - human_description: - en_US: The secret key or provisioning URI used to generate the TOTP - ja: TOTP生成に使用されるシークレットキーまたはプロビジョニングURI - llm_description: The secret key or provisioning URI (starting with 'otpauth://') used to generate the TOTP, this is highly sensitive and should be kept secret. - form: llm - - name: user_code - type: string - required: true - label: - en_US: 6 digit TOTP code to validate - ja: 検証する6桁のTOTPコード - human_description: - en_US: 6 digit TOTP code to validate - ja: 検証する6桁のTOTPコード - llm_description: 6 digit TOTP code to validate - form: llm -extra: - python: - source: tools/totp.py -output_schema: - type: object - properties: - True_or_False: - type: string - description: Whether the TOTP is valid or not, return in string format, "True" or "False". -``` - -### tools/totp.py -```python -from collections.abc import Generator -from typing import Any - -# 正しくツール関数をインポート -from utils.totp_verify import verify_totp - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -# 1ファイルに1つのToolサブクラスのみを含む -class TotpTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - """時間ベースのワンタイムパスワード(TOTP)を検証します""" - # パラメータを取得、KeyErrorを避けるためにget()を使用 - secret_key = tool_parameters.get("secret_key") - totp_code = tool_parameters.get("user_code") - - # パラメータ検証 - if not secret_key: - yield self.create_text_message("Error: Secret key is required.") - return - if not totp_code: - yield self.create_text_message("Error: TOTP code is required.") - return - - try: - # ツール関数を呼び出し - result = verify_totp(secret_key, totp_code) - - # 結果を返す - yield self.create_json_message(result) - - # 検証結果に基づいて異なるメッセージを返す - if result["status"] == "success": - yield self.create_text_message("Valid") - yield self.create_variable_message("True_or_False", "True") - else: - yield self.create_text_message("Invalid") - yield self.create_variable_message("True_or_False", "False") - - except Exception as e: - # エラー処理 - yield self.create_text_message(f"Verification error: {str(e)}") -``` - -### tools/secret_generator.py -```python -from collections.abc import Generator -from typing import Any - -import pyotp - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -# 注意:1ファイルに1つのToolサブクラスのみを含む -class SecretGenerator(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - """TOTPキーを生成します""" - try: - # ランダムキーを生成 - secret_key = pyotp.random_base32() - yield self.create_text_message(secret_key) - - # オプションパラメータを安全に取得 - name = tool_parameters.get("name") - issuer_name = tool_parameters.get("issuer_name") - - # 名前または発行者が提供されている場合、設定URIを生成 - if name or issuer_name: - provisioning_uri = pyotp.totp.TOTP(secret_key).provisioning_uri( - name=name, - issuer_name=issuer_name - ) - yield self.create_variable_message("provisioning_uri", provisioning_uri) - - except Exception as e: - yield self.create_text_message(f"Error generating secret: {str(e)}") -``` - -### requirements.txt -``` -dify_plugin~=0.0.1b76 -pyotp~=2.9.0 -``` - -この例は以下を示しています: -- 明確な機能分離(utils内のツール関数、tools内のツールクラス) -- 良好なエラー処理とパラメータ検証 -- 1ファイルに1つのToolサブクラスのみ -- 詳細なコメントとドキュメント文字列 -- 精巧に設計されたYAML設定 - -## 状態同期メカニズム - -ユーザーの説明があなたが記録したプロジェクトの状態と異なる場合、または現在の進捗を確認する必要がある場合は、以下の操作を実行してください: - -1. プロジェクトのファイル構造を確認します -2. 主要なファイルを読みます -3. ユーザーに明確に伝えます:「プロジェクトの状態が以前の私の理解と異なる可能性があることに気づきました。プロジェクトファイルを再確認し、私の認識を更新しました。」 -4. あなたが発見した実際の状態を説明します -5. workingディレクトリの進捗記録を更新します - -## 初回起動時の動作 - -ユーザーが「@ai」または同様の方法で初めてあなたをアクティベートしたとき、あなたは次のことを行うべきです: - -1. **プロジェクトの目標を仮定しない**: ユーザーがどのようなタイプのプラグインや機能を開発したいかを勝手に仮定しないでください -2. **コードの記述を開始しない**: 明確な指示なしにコードの生成や修正を開始しないでください -3. **ユーザーの意図を尋ねる**: ユーザーがどのようなタイプのプラグインを開発したいか、どのような問題を解決する手助けが必要か、丁寧に尋ねてください -4. **能力の概要を提供する**: あなたが提供できるヘルプの種類(コード実装、デバッグ、設計アドバイスなど)を簡単に説明してください -5. **プロジェクト情報を要求する**: より具体的なヘルプを提供できるように、現在のプロジェクトの状態やファイル構造を共有するようユーザーに依頼してください - -明確な指示を受けた後でのみ、具体的な開発アドバイスやコード実装の提供を開始してください。 - -あなたの主な目標は、状態を継続的に追跡し、専門的なアドバイスを提供し、技術的な課題を解決することを通じて、ユーザーがDifyプラグイン開発を効率的に完了できるよう支援することであることを忘れないでください。 - -{/* -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/0211-getting-started-by-prompt.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0211-getting-started-dify-tool.mdx b/plugin-dev-ja/0211-getting-started-dify-tool.mdx deleted file mode 100644 index 9ca9762b..00000000 --- a/plugin-dev-ja/0211-getting-started-dify-tool.mdx +++ /dev/null @@ -1,520 +0,0 @@ ---- -dimensions: "[object Object]" -standard_title: "Getting Started Dify Tool" -language: "ja" -title: "Dify プラグイン開発:Hello World ガイド" -description: "このドキュメントでは、Telegraph公開プラグインの作成を例に、ゼロからのDifyプラグイン開発に関する詳細なチュートリアルを提供します。環境準備、プロジェクト初期化、仮想環境設定、プラグインコアロジック開発、ローカル実行デバッグ、プラグインメタ情報整備、パッケージ化と公開といった手順が含まれます。" ---- - -Dify プラグイン開発入門ガイドへようこそ!このチュートリアルは、基本的なプログラミング知識と Dify プラットフォームの使用経験があることを前提としています。このチュートリアルを完了すると、簡単な Dify プラグインを作成するための基本的な流れを習得し、Dify ユーザーからプラグイン貢献者へとステップアップできます。 - -Telegraph 公開プラグインを例に、簡単なプラグインの開発方法をステップバイステップで示します。このチュートリアルでは、主にコマンドライン操作を使用し、VSCode をコードエディタとして使用する場合の例も示します。**まず全体的な流れを理解するために一度ざっと目を通し、その後、手順に従って実際に操作することをお勧めします。** - -> **LLM 向けの説明:** ここで私たちが作成したプロンプトを使用して、プラグイン開発を支援することもできます:[Dify プラグイン開発:プロンプト](/plugin-dev-ja/0211-getting-started-by-prompt) - -始める前に、いつでも私たちが提供する [**開発者向けチートシート (Cheatsheet)**](/plugin-dev-ja/0131-cheatsheet) でよく使われるコマンドや情報を確認したり、より複雑な問題に遭遇した場合には完全な開発者ドキュメントを参照したりすることができます。 - -## 1. 開発環境の準備 - -Dify プラグインの開発を始める前に、お使いの環境に以下のツールが準備されていることを確認してください: - -- **Dify プラグイン開発 CLI (CLI):** これはプラグインの開発、デバッグ、パッケージ化を行うための中核となるツールで、`dify-plugin-daemon` または「プラグイン開発SDK」とも呼ばれます。 -- **Python 環境:** Python 3.12 以降が必要です。 - -### 1.1 Dify プラグイン開発 CLI のインストール - -> より詳細な開発環境準備ガイドについては、[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools) を参照してください。 - -1. **ダウンロード:** [Dify Plugin CLI Releases](https://github.com/langgenius/dify-plugin-daemon/releases) ページにアクセスします。お使いのオペレーティングシステム(Windows, macOS Intel/ARM, Linux)に対応する最新バージョンのバイナリファイルをダウンロードします。 -2. **実行権限の設定 (macOS / Linux):** - - **以下の手順は macOS (Apple Silicon / M シリーズチップ) を例としています**。ダウンロードしたファイル名を `dify-plugin-darwin-arm64` と仮定します。ターミナルで、ファイルが存在するディレクトリに移動し、以下のコマンドを実行して実行権限を付与します: - - ```bash - chmod +x dify-plugin-darwin-arm64 - ``` - - Linux ユーザーの場合は、対応する Linux バージョンのファイルをダウンロードし、同様の `chmod +x ` コマンドを実行してください。 - - Windows ユーザーの場合は、`.exe` ファイルをダウンロードした後、通常は直接実行できます。 -3. **インストールの確認:** - - ターミナルで、以下のコマンドを実行してツールが正常に動作するか確認します(`./dify-plugin-darwin-arm64` をダウンロードした実際のファイル名またはパスに置き換えてください): - - ```bash - ./dify-plugin-darwin-arm64 version - ``` - - ターミナルにバージョン情報(例:`v0.0.1-beta.15`)が正常に出力されれば、インストールは成功です。 - -> **ヒント (Tips):** -> -> - **macOS のセキュリティ警告:** macOS で初めて実行する際に「Apple は検証できません」または「開けません」と表示された場合は、「システム設定」→「プライバシーとセキュリティ」→「セキュリティ」セクションに移動し、関連するメッセージを見つけて「それでも開く」または「許可」をクリックしてください。 -> - **コマンドの簡略化:** ダウンロードしたバイナリファイル名を短い名前(例:`dify` や `dify-plugin`)に変更すると、後の使用が便利になります。例:`mv dify-plugin-darwin-arm64 dify`、その後は `./dify version` で使用できます。 -> - **グローバルインストール(オプション):** システムのどのパスからでも直接コマンドを実行できるようにしたい場合(例:`./dify` ではなく直接 `dify` と入力する)、名前変更後のファイルをシステムの `PATH` 環境変数に含まれるディレクトリ(例:`/usr/local/bin` (macOS/Linux))に移動するか、Windows の環境変数に追加します。 -> - 例 (macOS/Linux): `sudo mv dify /usr/local/bin/` -> - 設定完了後、ターミナルで直接 `dify version` と入力すると、バージョン番号が正常に出力されるはずです。 - -**`便宜上、このドキュメントでは以降、Dify プラグイン開発 CLI コマンドの例として ./dify を使用します。ご自身の実際の状況に合わせてコマンドを置き換えてください。`** - -## 2. プラグインプロジェクトの初期化 - -それでは、CLI ツールを使用して新しいプラグインプロジェクトを作成しましょう。 - -1. ターミナルを開き、初期化コマンドを実行します: - - ```bash - ./dify plugin init - ``` -2. プロンプトに従って、プラグインの基本情報を順に入力します: - - **Plugin name:** プラグインの一意の識別子。例:`telegraph` - - _制約: 長さ 1~128 文字、小文字の英数字、ハイフン(-)、アンダースコア(_)のみ使用可能。\_ - - **Author:** プラグイン作者の識別子。例:`your-name` - - _制約: 長さ 1~64 文字、小文字の英数字、ハイフン(-)、アンダースコア(_)のみ使用可能。\_ - - **Description:** プラグイン機能の簡単な説明。例:`A Telegraph plugin that allows you to publish your content easily` - - **Enable multilingual README:** このオプションを有効にすると、プラグインの多言語READMEファイルを生成できます。チェックを入れると、下の `Languages to generate` セクションで、事前にREADMEファイルを生成したい言語を選択できます。 -3. **開発言語の選択:** `Select language` と表示されたら、`python` を選択してください。 -4. **プラグインタイプの選択:** `Select plugin type` と表示されたら、このチュートリアルでは `tool` を選択してください。 -5. **追加機能の選択:** 次に、プロバイダー認証、永続ストレージなどの追加機能が必要かどうか尋ねられます。この簡単な Hello World プラグインでは、これらは一時的に不要なので、成功メッセージが表示されるまで **Enter キー** を押してすべてのオプションをスキップできます。 -6. **作成成功の確認:** ターミナルに以下のような情報が出力されたら、プラグインプロジェクトは正常に作成されています: - - ```bash - [INFO] plugin telegraph created successfully, you can refer to `telegraph/GUIDE.md` for more information about how to develop it - ``` - -これで、現在のディレクトリに `telegraph`(または指定したプラグイン名)という名前の新しいフォルダが表示され、これがプラグインプロジェクトになります。 - -## 3. Python 仮想環境と依存関係の設定 - -プロジェクトの依存関係を分離するために、Python 仮想環境の使用を推奨します。 - -### 3.1 仮想環境の作成とアクティベート(コマンドライン方式) - -これは**推奨される一般的な**方法で、特定の IDE に依存しません: - -1. **プロジェクトディレクトリへの移動:** - - ```bash - cd telegraph - ``` -2. **仮想環境の作成:** (名前を `venv` にすることを推奨します) - - ```bash - python -m venv venv - ``` -3. **仮想環境のアクティベート:** - - **macOS / Linux:** - - ```bash - source venv/bin/activate - ``` - - **Windows (cmd.exe):** - - ```bash - venv\Scripts\activate.bat - ``` - - **Windows (PowerShell):** - - ```bash - venv\Scripts\Activate.ps1 - ``` - - アクティベートに成功すると、通常、ターミナルのプロンプトの前に `(venv)` と表示されます。 - -### 3.2 基本的な依存関係のインストール - -プロジェクト初期化時に生成された `requirements.txt` ファイルには、プラグイン開発に必要な基本ライブラリ `dify_plugin` が含まれています。仮想環境をアクティベートした後、以下のコマンドを実行してインストールします: - -```bash -pip install -r requirements.txt -``` - -### 3.3 (オプション) VSCode 統合環境設定 - -VSCode をコードエディタとして使用している場合、その統合機能を利用して Python 環境を管理できます: - -1. **プロジェクトフォルダを開く:** 作成した `telegraph` フォルダを VSCode で開きます。 -2. **Python インタープリタの選択:** - - コマンドパレットを開きます (macOS: `Cmd+Shift+P`, Windows/Linux: `Ctrl+Shift+P`)。 - - `Python: Select Interpreter` と入力して選択します。 - - 表示されたリストから、先ほど作成した仮想環境内の Python インタープリタを選択します(通常、パスには `.venv/bin/python` または `venv\Scripts\python.exe` が含まれます)。リストに自動的に表示されない場合は、`Enter interpreter path...` を選択して手動で検索できます。 - - _(ローカルの対応するスクリーンショットを参照してください。インタープリタ選択画面が表示されています)_ -3. **依存関係のインストール (VSCode が提示した場合):** VSCode が `requirements.txt` ファイルを検出し、その中の依存関係をインストールするよう促すことがあります。プロンプトが表示されたら、インストールを確認してください。 - - _(ローカルの対応するスクリーンショットを参照してください。依存関係のインストール確認画面が表示されています)_ - -**``以降のすべての pip install コマンドと python -m main の実行操作は、アクティベートされた仮想環境で実行してください。``** - -## 4. プラグインコアロジックの開発 - -それでは、プラグインのコードを記述していきましょう。この例では、指定されたコンテンツを Telegraph に公開するための簡単なツールを実装します。 - -### 4.1 サンプル依存ライブラリ: `your-telegraph` - -`your-telegraph` という名前の Python ライブラリを使用して Telegraph API とやり取りします。(_これは仮のライブラリ名です。実際に使用するライブラリが有効であることを確認してください_)。 - -> `your-telegraph` は、Telegraph API の操作を簡略化する Python ラッパーで、数行のコードで簡単にコンテンツを公開できます。 - -その基本的な使い方は以下のようになるかもしれません: - -```python -# サンプルコードであり、プラグイン内のコードではありません -from ytelegraph import TelegraphAPI - -# access_token が必要です -ph = TelegraphAPI(access_token="your_telegraph_access_token") - -# ページを作成してリンクを取得 -ph_link = ph.create_page_md("My First Page", "# Hello, Telegraph!\n\nThis is my first Telegraph page.") -print(ph_link) -``` - -私たちの目標は、Dify プラグインで同様の機能を実現することです。 - -### 4.2 プロジェクト依存関係の追加と設定 - -1. **依存ライブラリのインストール:** 仮想環境がアクティベートされていることを確認し、ターミナルで以下を実行します: - - ```bash - pip install your-telegraph - ``` -2. **`requirements.txt の更新:`** プロジェクトルートディレクトリにある `telegraph/requirements.txt` ファイルを開き、`dify_plugin` の下に、先ほどインストールしたライブラリ名を一行追加します: - - ```plaintext - dify_plugin - your-telegraph - ``` - - これにより、他の開発者やデプロイ環境がすべての必要な依存関係を簡単にインストールできるようになります。 - -### 4.3 プロバイダー認証情報の設定 - -この例では `telegraph_access_token` が必要です。プロバイダー設定でこの認証情報を定義し、ユーザーがプラグインを使用する際に入力できるようにする必要があります。プロバイダー設定の詳細については、[一般仕様定義](/plugin-dev-ja/0411-general-specifications) を参照してください。 - -1. **プロバイダー YAML の編集:** `telegraph/provider/telegraph.yaml` ファイルを開きます。 -2. **`credentials_for_provider の追加:`** ファイルの末尾(または適切な場所)に以下の内容を追加します: - - ```yaml - # ... (ファイルに既にある identity, name, label, description, icon などは変更しません) ... - - credentials_for_provider: - telegraph_access_token: # これは認証情報の内部名で、Python コードで使用されます - type: secret-input # 入力タイプはパスワードフィールド - required: true # この認証情報は必須です - label: # Dify UI に表示されるラベル (多言語対応) - en_US: Telegraph Access Token - ja: Telegraph アクセストークン - # ... (その他の言語) - placeholder: # 入力フィールドのプレースホルダーテキスト (多言語対応) - en_US: Enter your Telegraph access token - ja: Telegraph アクセストークンを入力してください - # ... (その他の言語) - help: # ヘルプヒント情報 (多言語対応) - en_US: How to get your Telegraph access token - ja: Telegraph アクセストークンの取得方法 - # ... (その他の言語) - url: https://telegra.ph/api#createAccount # ヘルプヒントをクリックしたときにジャンプする URL - ``` - - **フィールドの説明:** - - `telegraph_access_token`: 認証情報の一意の識別子。コード内では `self.runtime.credentials["telegraph_access_token"]` を介してユーザーが入力した値にアクセスします。 - - `type: secret-input`: Dify UI 上でパスワード入力フィールドとして表示されます。 - - `required: true`: ユーザーがこのプラグイン提供のツールを使用するには、この認証情報を入力する必要があります。 - - `label`, `placeholder`, `help`: 多言語対応の UI テキストを提供します。 - - `url`: (オプション) 認証情報取得のためのヘルプリンクを提供します。 - -### 4.4 ツール (Tool) ロジックの実装 - -それでは、実際に公開操作を実行するツールのコードを記述しましょう。 - -1. **ツール Python ファイルの編集:** `telegraph/tools/telegraph.py` を開きます。 -2. **`_invoke メソッドの実装:`** ファイルの内容を以下のコードに置き換えます: - - ```python - from collections.abc import Generator - from typing import Any - from ytelegraph import TelegraphAPI # 使用するライブラリをインポート - - from dify_plugin import Tool - from dify_plugin.entities.tool import ToolInvokeMessage - - class TelegraphTool(Tool): - """ - シンプルな Telegraph 公開ツールです。 - """ - - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - """ - 入力されたタイトルと内容に基づいて、新しい Telegraph ページを作成します。 - - Args: - tool_parameters: ツールの入力パラメータを含む辞書: - - p_title (str): Telegraph ページのタイトル。 - - p_content (str): 公開する Markdown 形式の内容。 - - Yields: - ToolInvokeMessage: 正常に作成された Telegraph ページの URL を含むメッセージ。 - - Raises: - Exception: ページの作成に失敗した場合、エラー情報を含む例外をスローします。 - """ - # 1. ランタイムから認証情報を取得 - try: - access_token = self.runtime.credentials["telegraph_access_token"] - except KeyError: - raise Exception("Telegraph アクセストークンが設定されていないか無効です。プラグイン設定で提供してください。") - - # 2. ツールの入力パラメータを取得 - title = tool_parameters.get("p_title", "Untitled") # .get を使用してデフォルト値を提供 - content = tool_parameters.get("p_content", "") - - if not content: - raise Exception("公開するコンテンツは空にできません。") - - # 3. ライブラリを呼び出して操作を実行 - try: - telegraph = TelegraphAPI(access_token) # Telegraph API を初期化 - ph_link = telegraph.create_page_md(title, content) # ページを作成 - except Exception as e: - # ライブラリ呼び出しに失敗した場合、例外をスロー - raise Exception(f"Telegraph API の呼び出しに失敗しました: {e}") - - # 4. 結果を返す - # create_link_message を使用してリンクを含む出力メッセージを生成 - yield self.create_link_message(ph_link) - ``` - - **重要なポイント:** - - `self.runtime.credentials` から認証情報を取得します。 - - `tool_parameters` からツールの入力パラメータを取得します(パラメータ名は次のステップの YAML で定義します)。`.get()` を使用する方が堅牢な方法です。 - - `ytelegraph` ライブラリを呼び出して実際の操作を実行します。 - - `try...except` を使用して起こりうるエラーをキャッチし、例外をスローします。 - - `yield self.create_link_message(url)` を使用して URL を含む結果を Dify に返します。 - -### 4.5 ツール (Tool) パラメータの設定 - -このツールがどの入力パラメータを受け取るかを Dify に伝える必要があります。 - -1. **ツール YAML ファイルの編集:** `telegraph/tools/telegraph.yaml` を開きます。 -2. **パラメータの定義:** ファイルの内容を以下のように置き換えるか変更します: - - ```yaml - identity: - name: telegraph_publisher # ツールの一意の内部名 - author: your-name - label: # Dify UI に表示されるツール名 (多言語対応) - en_US: Publish to Telegraph - ja: Telegraph に公開 - # ... (その他の言語) - description: - human: # 人間ユーザー向けのツールの説明 (多言語対応) - en_US: Publish content to Telegraph as a new page. - ja: コンテンツを新しいページとして Telegraph に公開します。 - # ... (その他の言語) - llm: # LLM 向けのツールの説明 (Agent モード用) - A tool that takes a title and markdown content, then publishes it as a new page on Telegraph, returning the URL of the published page. Use this when the user wants to publish formatted text content publicly via Telegraph. - parameters: # ツールの入力パラメータリストを定義 - - name: p_title # パラメータの内部名、Python コードのキーに対応 - type: string # パラメータタイプ - required: true # 必須かどうか - label: # Dify UI に表示されるパラメータラベル (多言語対応) - en_US: Post Title - ja: 記事タイトル - human_description: # 人間ユーザー向けのパラメータの説明 (多言語対応) - en_US: The title for the Telegraph page. - ja: Telegraph ページのタイトル。 - llm_description: # LLM 向けのパラメータの説明 (Agent がどのように入力するかを指示) - The title of the post. Should be a concise and meaningful plain text string. - form: llm # パラメータフォームタイプ ('llm' または 'form') - - name: p_content - type: string - required: true - label: - en_US: Content (Markdown) - ja: 内容 (Markdown) - human_description: - en_US: The main content for the Telegraph page, written in Markdown format. - ja: Telegraph ページの主な内容、Markdown 形式で記述してください。 - llm_description: # フォーマット要件を強調することは LLM にとって重要 - The full content to be published on the Telegraph page. Must be provided in Markdown format. Ensure proper Markdown syntax for formatting like headings, lists, links, etc. - form: llm - extra: # 追加設定 - python: - source: tools/telegraph.py # このツールのロジックを実装する Python ファイルを指す - ``` - - **フィールドの説明:** - - `identity`: ツールの基本情報、`name` は一意の識別子です。 - - `description`: `human` (ユーザー向け) と `llm` (Agent 向け) に分かれます。**`llm の説明は、Agent がツールを正しく理解して使用できるかどうかにおいて非常に重要です。`** - - `parameters`: 各入力パラメータを定義します。 - - `name`: 内部名、Python コードの `tool_parameters.get("...")` のキーと一致する必要があります。 - - `type`: データ型 (例: `string`, `number`, `boolean` など)。 - - `required`: 提供が必須かどうか。 - - `label`, `human_description`, `llm_description`: `identity` の説明と同様ですが、特定のパラメータに対するものです。**`llm_description は、LLM がそのパラメータの値をどのように生成または取得するか(ここでの Markdown のようなフォーマット要件を含む)を明確に指示する必要があります。`** - - `form`: パラメータが Dify でどのように表示され、入力されるかを定義します。`llm` は、そのパラメータ値をユーザーが入力したり、変数を介して渡したり、Agent モードで LLM が自律的に決定したりできることを示します。`form` は通常、ユーザーが UI 上で固定的に入力する必要がある設定項目を示します。ツール入力の場合、`llm` の方が一般的です。 - - `extra.python.source`: このツールのロジックを実装する Python ファイルのパス(プロジェクトルートディレクトリからの相対パス)を示します。 - -### 4.6 プロバイダー認証情報の検証実装(オプションだが推奨) - -ユーザーが提供した認証情報が有効であることを保証するために、検証ロジックを実装すべきです。 - -1. **プロバイダー Python ファイルの編集:** `telegraph/provider/telegraph.py` を開きます。 -2. **`_validate_credentials メソッドの実装:`** ファイルの内容を以下に置き換えます: - - ```python - from typing import Any - from dify_plugin import ToolProvider - from dify_plugin.errors.tool import ToolProviderCredentialValidationError - - class TelegraphProvider(ToolProvider): - def _validate_credentials(self, credentials: dict[str, Any]) -> None: - """ - 提供された Telegraph アクセストークンが有効かどうかを検証します。 - このトークンを使用してテストページを作成しようとします。 - 検証に失敗した場合、ToolProviderCredentialValidationError 例外をスローする必要があります。 - """ - access_token = credentials.get("telegraph_access_token") - if not access_token: - raise ToolProviderCredentialValidationError("Telegraph アクセストークンは空にできません。") - - try: - # 認証情報が必要な簡単な操作を実行して検証を試みる - from ytelegraph import TelegraphAPI - ph = TelegraphAPI(access_token=access_token) - # 検証手段として、一時的で無害なページを作成してみる - # 注意: より良い検証方法は、API の 'getAccountInfo' などの読み取り専用メソッドを呼び出すことです(存在する場合) - test_page = ph.create_page_md("Dify Validation Test", "This is a test page created by Dify plugin validation.") - # 必要であれば、このテストページをすぐに編集または削除することを検討できますが、複雑さが増します - # print(f"Validation successful. Test page created: {test_page}") - except Exception as e: - # API 呼び出しに失敗した場合、認証情報が無効である可能性が高い - raise ToolProviderCredentialValidationError(f"Telegraph 認証情報の検証に失敗しました: {e}") - - ``` - - **重要なポイント:** - - `credentials` 辞書から認証情報を取得します。 - - その認証情報が必要な API 呼び出しを実行します(アカウント情報の取得など、読み取り専用操作が望ましいです。もしなければ、無害なテストページを作成することもできますが、副作用の可能性に注意してください)。 - - API 呼び出しが成功した場合、例外はスローされず、検証が通過したことを示します。 - - API 呼び出しが失敗した場合、例外をキャッチして `ToolProviderCredentialValidationError` をスローし、元のエラーメッセージを含めます。 - -## 5. ローカルでの実行とデバッグ - -これでプラグインをローカルで実行し、Dify でデバッグできます。 - -1. **`.env ファイルの準備:`** - - `telegraph` プロジェクトディレクトリにいることを確認してください。 - - 環境変数テンプレートファイルをコピーします: - - ```bash - cp .env.example .env - ``` - - **`.env ファイルの編集:`** 作成したばかりの `.env` ファイルを開き、Dify 環境情報を入力します: - - ```dotenv - DIFY_API_HOST=https://your-dify-host.com # ご自身の Dify インスタンスアドレスに置き換えてください (例: https://cloud.dify.ai) - DIFY_API_KEY=your-api-key # ご自身の Dify API キーに置き換えてください - ``` - - **ホストとキーの取得:** Dify 環境にログインし、右上の「プラグイン」アイコンをクリックし、次にデバッグアイコン(または虫のような形)をクリックします。ポップアップウィンドウで、「API キー (Key)」と「ホストアドレス (Host)」をコピーします。 _(ローカルの対応するスクリーンショットを参照してください。キーとホストアドレスの取得画面が表示されています)_ -2. **ローカルプラグインサービスの起動:** - - Python 仮想環境がアクティベートされていることを確認してください。 - - `telegraph` ディレクトリで、メインプログラムを実行します: - - ```bash - python -m main - ``` - - **ターミナル出力の確認:** すべてが正常であれば、以下のようなログ情報が表示され、プラグインツールが正常にロードされ、Dify に接続されたことを示します: - - ```json - {"event": "log", "data": {"level": "INFO", "message": "Installed tool: telegraph_publisher", "timestamp": 1678886400.123456}} - {"event": "log", "data": {"level": "INFO", "message": "Plugin daemon started, waiting for requests...", "timestamp": 1678886400.123457}} - ``` -3. **Dify での確認とテスト:** - - **Dify ページを更新:** Dify 環境(ブラウザ)に戻り、プラグイン管理ページ (通常は `https://your-dify-host.com/plugins`) を更新します。 - - **プラグインを検索:** リストに "Telegraph" (またはプロバイダー YAML で定義した `label`) という名前のプラグインが表示され、「デバッグ中」のマークが付いている場合があります。 - - **認証情報を追加:** そのプラグインをクリックすると、以前 `provider/telegraph.yaml` で定義した "Telegraph Access Token" の入力を求められます。有効なトークンを入力して保存します。検証ロジック (`_validate_credentials`) が正しく実装されていれば、ここで検証が行われます。 _(ローカルの対応するスクリーンショットを参照してください。プラグインがリストに表示され、認証を要求する画面が表示されています)_ - - **アプリケーションで使用:** これで、Dify のアプリケーション(Chatbot や Workflow など)にこのツールノードを追加し、呼び出すことができます!アプリケーションで実行してツールをトリガーすると、リクエストはローカルで実行されている `python -m main` プロセスに転送されて処理されます。ローカルターミナルで関連するログ出力を確認し、デバッグできます。 -4. **ローカルサービスの停止:** ターミナルで `Ctrl + C` を押すと、ローカルプラグインサービスを停止できます。 - -この実行 -\> テスト -\> 停止 -\> コード修正 -\> 再実行のサイクルが、プラグイン開発の主なフローです。 - -## 6. プラグインメタ情報の整備 - -プラグインをより専門的に、発見・理解しやすくするために、いくつかの表示情報を整備する必要があります。 - -1. **アイコン (Icon):** - - `telegraph/_assets` ディレクトリに、プラグインを表すアイコンファイル(例:`icon.png`, `icon.svg`)を配置します。正方形で鮮明な画像を推奨します。 -2. **`プロバイダー情報 (provider/telegraph.yaml):`** - - `identity` セクションの `label` (表示名)、`description` (機能説明)、`icon` (アイコンファイル名、例:`icon.png` を記入) が入力され、多言語対応していることを確認します。この情報は主に Dify アプリケーションオーケストレーションインターフェースでプラグインを\_使用する\_ユーザーに表示されます。 - - ```yaml - identity: - author: your-name - name: telegraph # 内部名、変更なし - label: - en_US: Telegraph - ja: Telegraph 記事公開 - description: - en_US: A Telegraph plugin that allow you publish your content easily - ja: コンテンツを簡単に公開できるTelegraphプラグイン - icon: icon.png # _assets ディレクトリ内のアイコンファイル名を参照 - ``` -3. **`プラグインマニフェスト (manifest.yaml):`** - - プロジェクトルートディレクトリにある `telegraph/manifest.yaml` ファイルを編集します。これはプラグイン全体の「身分証明書」のようなもので、その情報は Dify の**プラグイン管理ページ**や**プラグインマーケットプレイス (Marketplace)** に表示されます。 - - 以下のフィールドを必ず更新または確認してください: - - `label`: プラグインの**主要な表示名** (多言語対応)。 - - `description`: プラグイン機能の**全体的な概要** (多言語対応)。その核心的な価値を明確に要約する必要があります。マーケットプレイスでの表示には文字数制限があることに注意してください。 - - `icon`: プラグインの**メインアイコン** (`_assets` ディレクトリ内のアイコンファイル名を直接記入、例:`icon.png`)。 - - `tags`: プラグインに分類タグを追加し、ユーザーがマーケットプレイスでフィルタリングするのに役立ちます。選択可能な値は、Dify が提供する列挙型またはドキュメントの説明を参照してください (例: `media`, `tools`, `data-processing` など)。[ToolLabelEnum 定義](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/dify_plugin/entities/tool.py) を参照してください。 - - ```yaml - label: - en_US: Telegraph Publisher - ja: Telegraph 公開アシスタント - description: - en_US: Easily publish content to Telegraph pages directly from your Dify applications. Supports Markdown formatting. - ja: Dify アプリケーションから直接 Telegraph ページにコンテンツを簡単に公開できます。Markdown 形式をサポートしています。 - icon: icon.png - tags: ['media', 'content-creation'] # タグの例 - # ... (author, name など他のフィールドは変更なし) - ``` -4. **README とプライバシーポリシー:** - - `README.md`: プロジェクトルートディレクトリの `README.md` ファイルを編集します。これはプラグインの **Marketplace** 上の詳細な紹介ページとなり、機能詳細、使用例、設定ガイド、よくある質問など、より豊富な情報を含めるべきです。[AWS プラグインマーケットプレイスページ](https://marketplace.dify.ai/plugins/langgenius/aws_tools) のスタイルを参考にしてください。 - - - 多言語でREADMEを提供することができます。詳細については、[多言語 README](/plugin-dev-ja/0411-multilingual-readme) をご覧ください。 - - - `PRIVACY.md`: プラグインを公式 Marketplace に公開する予定がある場合は、プラグインがデータをどのように処理するかを説明するプライバシーポリシー説明ファイル `PRIVACY.md` を提供する必要があります。 - -## 7. プラグインのパッケージ化 - -プラグイン開発が完了し、ローカルテストに合格したら、配布またはインストール用に `.difypkg` ファイルにパッケージ化できます。プラグインのパッケージ化と公開の詳細については、[公開概要](/plugin-dev-ja/0321-release-overview) を参照してください。 - -1. **親ディレクトリに戻る:** ターミナルの現在のパスが `telegraph` フォルダの**一つ上**であることを確認してください。 - - ```bash - cd .. - ``` -2. **パッケージ化コマンドの実行:** - - ```bash - ./dify plugin package ./telegraph - ``` - - (`./telegraph` をプラグインプロジェクトの実際のパスに置き換えてください) -3. **パッケージファイルの取得:** コマンドが正常に実行されると、現在のディレクトリに `telegraph.difypkg` (または `あなたのプラグイン名.difypkg`) という名前のファイルが生成されます。 - -この `.difypkg` ファイルは完全なプラグインパッケージです。これを以下のことができます: - -- Dify のプラグイン管理ページで手動で**アップロードしてインストール**する。 -- 他の人に**共有**してインストールしてもらう。 -- Dify の規範と手順に従って、**公式プラグインマーケットプレイス (Marketplace)** に公開し、すべての Dify ユーザーがあなたのプラグインを発見して使用できるようにする。具体的な公開手順については、[Dify マーケットプレイスへの公開](/plugin-dev-ja/0322-release-to-dify-marketplace) を参照してください。 - -おめでとうございます! これで最初の Dify プラグインの開発、デバッグ、整備、パッケージ化の全プロセスを完了しました。この基礎を元に、より複雑で強力なプラグイン機能を探求できます。 - -## 次の学習ステップ - -- [リモートでプラグインをデバッグする](/plugin-dev-ja/0411-remote-debug-a-plugin) - より高度なプラグインデバッグテクニックを学ぶ -- [永続ストレージ](/plugin-dev-ja/0411-persistent-storage-kv) - プラグインでデータストレージを使用する方法を学ぶ -- [Slack ボットプラグイン開発例](/plugin-dev-ja/0432-develop-a-slack-bot-plugin) - より複雑なプラグイン開発事例を見る -- [ツールプラグイン](/plugin-dev-ja/0222-tool-plugin) - ツールプラグインの高度な機能を探る - -{/* -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/0211-getting-started-dify-tool.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0211-getting-started-new-model.mdx b/plugin-dev-ja/0211-getting-started-new-model.mdx deleted file mode 100644 index 663e3cb9..00000000 --- a/plugin-dev-ja/0211-getting-started-new-model.mdx +++ /dev/null @@ -1,125 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: basic - level: beginner -standard_title: Getting Started New Model -language: ja -title: 新しいモデルを迅速に統合する -description: このドキュメントでは、専門家でない開発者がDifyに新しいモデルを追加する方法を説明します。既存のモデルプロバイダーに設定ファイルを変更することで新しいモデルタイプを追加することに焦点を当てています。リポジトリのフォーク、モデル設定のコピーと変更、プロバイダーバージョンの更新、ローカルテスト、およびコントリビューションの提出までの完全なプロセスを含みます。 ---- - -Difyのプラグイン開発の世界へようこそ!Difyの強力な機能は、コミュニティ貢献者の共同の努力なしにはありえません。たとえプロのプログラマーでなくても、AI技術に情熱を持ち、資料を調べる意欲があれば、Difyにより多くの、より新しいAIモデルをサポートするなど、Difyに貢献できると信じています。 - -この記事では、最も簡潔な方法で、最も一般的で簡単な貢献、つまりDifyが**既にサポートしている**モデルプロバイダーに、**新しいモデルタイプ**を追加する方法を説明します。この方法は通常、**設定ファイルの変更のみ**が必要で、コードを書く必要がないため、最初の貢献として非常に適しています! - -> **関連概念**:開始する前に、[モデルプラグイン](/plugin-dev-ja/0131-model-plugin-introduction.ja)のドキュメントを読んで、モデルプラグインの基本概念と構造を理解することをお勧めします。 - -**この迅速な統合方法は、以下の場合に適しています:** - -- 新しいモデルが、Difyが既にプラグインでサポートしているプロバイダー(OpenAI、Google Gemini、Anthropic Claudeなど)に属している場合。 -- 新しいモデルが、同じシリーズの他のモデルと同じAPI認証および基本的な呼び出しロジックを使用している場合。 -- 主な違いが、モデルID、コンテキスト長、最大トークン数、価格設定などの設定パラメーターにある場合。 - -_(追加する必要のあるモデルが新しいAPIロジックを必要とするか、特殊な機能をサポートする場合、Pythonコードの記述が必要になります。[新しいモデルプロバイダーの作成](/plugin-dev-ja/0222-creating-new-model-provider) で詳細なガイドを参照してください。)_ - -**準備作業:** - -- 基本的なGit操作(Fork、Clone、Pull Request)に慣れていること。 -- GitHubアカウント。 -- Difyプラグイン開発ツールキットをインストールし、設定済みであること([開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools)を参照)。 - -**操作手順:** - -1. **公式プラグインリポジトリをフォーク&クローン:** - - - Dify公式プラグインリポジトリ `https://github.com/langgenius/dify-official-plugins` にアクセスします。 - - 「Fork」ボタンをクリックして、リポジトリを自分のGitHubアカウントにフォークします。 - - Gitを使用して、フォークしたリポジトリをローカルコンピュータにクローンします。 - -2. **モデル設定ファイルを見つけてコピー:** - - - ローカルリポジトリで、`models/` ディレクトリに移動し、モデルを追加したいプロバイダーのフォルダ(例:`vertex_ai`)を見つけます。 - - そのプロバイダーに対応するモデルタイプのサブディレクトリ(通常はテキスト生成モデルの場合 `models/llm/`)に入ります。 - - そのディレクトリ内で、追加したい新しいモデルに最も似ている既存モデルのYAML設定ファイル(例:`gemini-1.0-pro-001.yaml`)を見つけます。 - - このYAMLファイルをコピーし、新しいモデルタイプを明確に識別できる名前に変更します(例:`gemini-1.5-pro-latest.yaml`)。 - -3. **モデル設定の変更 (YAML):** - - - 先ほど名前を変更したYAMLファイル(例:`gemini-1.5-pro-latest.yaml`)を開きます。 - - **核心ステップ:** **モデルプロバイダーの公式ドキュメント**を参照し、ファイル内の以下の重要な情報を注意深く確認して変更します: - - `model`: **必須** 新しいモデルタイプの公式API識別子に更新します。 - - `label`: **必須** Difyインターフェースでユーザーに表示されるモデル名に更新します(`en_US` と `zh_Hans` の両方の言語を提供することをお勧めします)。 - - `model_properties`: `context_size`(コンテキストウィンドウサイズ)を更新します。 - - `parameter_rules`: モデルパラメータの制限、特に `max_tokens`(最大出力トークン数)の `default`、`min`、`max` 値を確認して更新します。 - - `pricing`: モデルの入力(`input`)と出力(`output`)の価格設定、および単位(`unit`、通常は百万トークンを表す `0.000001`)と通貨(`currency`)を更新します。 - - _(参考)_ モデルYAMLファイルの各フィールドの詳細な仕様については、[モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules) および [モデルスキーマ定義](/plugin-dev-ja/0412-model-schema) を参照してください。 - - **例 (Gemini 1.5 Pro の追加):** - - | パラメータ | 既存モデルの可能性 (例) | 新しい Gemini 1.5 Pro (例) | 説明 | - | :---------------- | :------------------- | :----------------------- | :--------------------------------------------- | - | `model` | `gemini-1.0-pro-001` | `gemini-1.5-pro-latest` | **必須** 公式モデルIDに変更 | - | `label: en_US` | Gemini 1.0 Pro | Gemini 1.5 Pro | **必須** ユーザーに表示されるラベルに変更 | - | `context_size` | 30720 | 1048576 | **必須** 公式ドキュメントに基づいて変更 | - | `max_tokens` (下) | 2048 | 8192 | **必須** 公式ドキュメントに基づいてデフォルト/最大値を変更 | - -4. **プロバイダーマニフェストのバージョンを更新:** - - - そのモデルプロバイダーのルートディレクトリ(例:`models/vertex_ai/`)に戻ります。 - - `manifest.yaml` ファイルを見つけて開きます。 - - その中の `version` フィールドをマイナーバージョン番号でインクリメントします(例:`version: 0.0.8` -> `version: 0.0.9`)。これにより、Difyにこれが更新であることを伝えます。 - -5. **パッケージ化とローカルテスト:** - - - ターミナル(コマンドラインツール)を開きます。 - - **現在のディレクトリが `dify-official-plugins` リポジトリのルートディレクトリ**(つまり、`models`、`tools` などのフォルダが含まれるディレクトリ)であることを確認してください。 - - パッケージ化コマンドを実行します: - - ```bash - # を実際のプロバイダーディレクトリ名(例: cohere や vertex_ai)に置き換えます - dify plugin package models/ - ``` - - - _成功すると、`plugin packaged successfully, output path: .difypkg` のようなメッセージが表示され、現在のプロジェクトのルートディレクトリに `.difypkg` という名前のプラグインパッケージファイルが生成されます。_ - - Difyインスタンス(ローカルデプロイまたはクラウドバージョンのいずれか)にログインします。 - - Difyページ最上部のナビゲーションバー右側にある **「プラグイン」** メニュー項目をクリックします。 - - プラグインページで、**「プラグインをインストール」** ボタンをクリックします。 - - **「ローカルプラグイン」** タブを選択します。 - - アップロードエリアをクリックし、先ほどローカルで生成した `.difypkg` ファイルを選択またはドラッグアンドドロップしてアップロードします。 - - プラグインのインストールまたは更新が完了するのを待ちます。 - - インストールが成功したら、通常、「設定」->「モデルプロバイダー」に移動して対応するプロバイダーを見つけ、API認証情報(以前に設定していない場合)を設定する必要があります。 - - 新しいDifyアプリケーションを作成するか、既存のアプリケーションを編集し、「プロンプトエンジニアリング」->「モデル」設定で、新しく追加したモデルを選択してみてください。簡単な会話や呼び出しテストを行い、正常に動作し、期待される結果が返されることを確認します。 - -6. **コントリビューションを提出:** - - ローカルテストで問題がなければ、変更(新しいモデルYAMLファイルと更新された `manifest.yaml`)をGitでコミット(commit)し、フォークしたGitHubリポジトリにプッシュ(push)します。 - - GitHub上で、`langgenius/dify-official-plugins` のメインリポジトリに対してプルリクエスト(PR)を作成します。PRの説明には、どのモデルを追加したかを簡潔に説明し、そのモデルの公式ドキュメントへのリンクを添付して、レビュー担当者がパラメータを確認しやすくします。 - ---- - -**それで、次は?** - -PRがレビューされマージされると、あなたの貢献はDify公式プラグインの一部となり、すべてのDifyユーザーがこの新しいモデルを簡単に利用できるようになります! - -この迅速な統合方法は、Difyが新しいモデルをサポートするための最速の方法です。もちろん、将来このモデルがより複雑な機能(例えば、画像入力、関数呼び出しなど)をサポートする必要がある場合、経験豊富な開発者がプラグインをコードレベルで更新する必要があるかもしれません。しかし、あなたが今完了したこのステップは、既に非常に価値のある貢献です! - -**さらに探求する:** - -- [モデルスキーマ定義](/plugin-dev-ja/0412-model-schema) (モデルYAMLファイルの詳細なルールを理解する) -- [モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules) (モデルパラメータ設計の仕様を理解する) -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) (`manifest.yaml` の役割を理解する) -- [新しいモデルプロバイダーの作成](/plugin-dev-ja/0222-creating-new-model-provider) (新しいモデルプロバイダーの追加方法を理解する) -- [Difyマーケットプレイスへの公開](/plugin-dev-ja/0322-release-to-dify-marketplace) (プラグインの公開方法を学ぶ) -- [Dify公式プラグインリポジトリ](https://github.com/langgenius/dify-official-plugins) (他のプラグインの例を見る) - -{/* -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/0211-getting-started-new-model.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0221-initialize-development-tools.mdx b/plugin-dev-ja/0221-initialize-development-tools.mdx deleted file mode 100644 index c99b6518..00000000 --- a/plugin-dev-ja/0221-initialize-development-tools.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: beginner -standard_title: Initialize Development Tools -language: ja -title: 開発ツールの初期化 -description: このドキュメントでは、Difyプラグイン開発を開始する前に必要な準備作業について詳しく説明します。これには、Difyプラグインのひな形ツール(dify-plugin-daemon)のインストールとPython環境(バージョン要件≥3.12)の設定の完全な手順が含まれます。また、さまざまなタイプのプラグイン開発の参考リンクも提供しています。 ---- - -Dify プラグインを開発するには、以下の準備が必要です。このドキュメントは、[プラグイン開発](/plugin-dev-ja/0111-getting-started-dify-plugin)を開始するための最初のステップです。 - -* Dify プラグインのひな形ツール -* Python 環境、バージョン ≥ 3.12 - -> Dify プラグイン開発のひな形ツールは `dify-plugin-daemon` とも呼ばれ、**プラグイン開発 SDK** と見なすことができます。 - -### **1. Dify プラグイン開発のひな形ツールのインストール** - -[Dify Plugin CLI](https://github.com/langgenius/dify-plugin-daemon/releases) プロジェクトのページにアクセスし、最新バージョンとお使いのオペレーティングシステムに対応するツールをダウンロードしてインストールしてください。 - -この記事では、**Mシリーズチップを搭載した macOS** を例に説明します。`dify-plugin-darwin-arm64` ファイルをダウンロードした後、実行権限を付与します。 - -``` -chmod +x dify-plugin-darwin-arm64 -``` - -以下のコマンドを実行して、インストールが成功したかどうかを確認します。 - -``` -./dify-plugin-darwin-arm64 version -``` - -> 「Apple では確認できませんでした」というエラーが表示された場合は、**「設定 → プライバシーとセキュリティ → セキュリティ」** に移動し、「このまま開く」ボタンをタップしてください。 - -コマンドを実行した後、ターミナルに `v0.0.1-beta.15` のようなバージョン情報が返されれば、インストールは成功です。 - -> **💡 ヒント:** -> -> システム全体で `dify` コマンドを使用してひな形ツールを実行したい場合は、このバイナリファイルの名前を `dify` に変更し、`/usr/local/bin` システムパスにコピーすることをお勧めします。 -> -> 設定完了後、ターミナルで `dify version` コマンドを入力すると、バージョン情報が出力されます。 -> -> - -### **2. Python 環境の初期化** - -詳細については、[Python インストールチュートリアル](https://pythontest.com/python/installing-python-3-11/) を参照するか、LLM にバージョン ≥ 3.12 の Python 環境のインストールについて質問してください。 - -### 3. プラグインの開発 - -さまざまな種類のプラグイン開発の例については、以下の内容を参照してください。 - -- [ツールプラグイン開発ガイド](/plugin-dev-ja/0211-getting-started-dify-tool) - Hello World 入門チュートリアル -- [モデルプラグイン開発ガイド](/plugin-dev-ja/0211-getting-started-new-model) - 新しいモデルへの迅速な統合 -- [Agent戦略プラグイン開発ガイド](/plugin-dev-ja/9433-agent-strategy-plugin) - カスタム推論戦略の作成 -- [拡張プラグイン開発ガイド](/plugin-dev-ja/9231-extension-plugin) - Webhook を介した外部サービス統合の実装 -- [プラグインのパッケージ化とリリース](/plugin-dev-ja/0321-release-overview) - プラグインの公開 - -## 次のステップ - -- [Dify プラグイン開発:Hello World ガイド](/plugin-dev-ja/0211-getting-started-dify-tool) - 最初のプラグイン開発を始める -- [プラグイン開発チートシート](/plugin-dev-ja/0131-cheatsheet) - 一般的なコマンドと概念の理解 -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインのメタデータ設定を学ぶ - -{/* -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/0221-initialize-development-tools.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0222-creating-new-model-provider-extra.mdx b/plugin-dev-ja/0222-creating-new-model-provider-extra.mdx deleted file mode 100644 index 807e028e..00000000 --- a/plugin-dev-ja/0222-creating-new-model-provider-extra.mdx +++ /dev/null @@ -1,285 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Creating New Model Provider Extra -language: ja -title: 標準モデル統合の実装 -description: このドキュメントは、Pythonコードを記述してDifyのモデルサポートを追加または強化する必要がある開発者向けのもので、ディレクトリ構造の作成、モデル設定の記述、モデル呼び出しロジックの実装、プラグインのデバッグと公開までの完全なプロセスを詳細にガイドし、コアメソッドの実装とエラー処理の詳細を含んでいます。 ---- - -このドキュメントは、Pythonコードを記述してDifyのモデルサポートを追加または強化する必要がある開発者向けの標準ガイドです。追加したいモデルが新しいAPI呼び出しロジック、特別なパラメータ処理、またはDifyが明示的にサポートする必要がある新機能(Vision、Tool Callingなど)を含む場合、このガイドの手順に従う必要があります。 - -**本文を読む前に、以下のことをお勧めします:** - -* Pythonプログラミングの基礎とオブジェクト指向プログラミングの基本的な理解があること。 -* 統合したいモデルプロバイダーが提供するAPIドキュメントと認証方法に精通していること。 -* Difyプラグイン開発ツールキットをインストールし、設定済みであること([開発ツールの初期化](../initialize-development-tools.md)を参照)。 -* (オプション)[モデルプラグインの紹介](link-to-conceptual-intro)ドキュメントを読み、モデルプラグインの基本概念とアーキテクチャを理解していること。 - -このガイドでは、ディレクトリ構造の作成、モデル設定(YAML)の記述、モデル呼び出しロジック(Python)の実装、およびプラグインのデバッグと公開までの全プロセスを案内します。 - ---- - -## ステップ1:ディレクトリ構造の作成 - -整理されたディレクトリ構造は、保守可能なプラグインを開発するための基礎です。モデルプロバイダープラグインのために特定のディレクトリとファイルを作成する必要があります。 - -1. **プロバイダーディレクトリの特定または作成:** プラグインプロジェクト(通常は `dify-official-plugins` のローカルクローン)の `models/` ディレクトリ内で、モデルプロバイダー名でフォルダを見つけるか作成します(例:`models/my_new_provider`)。 -2. **`models` サブディレクトリの作成:** プロバイダーディレクトリ内に `models` サブディレクトリを作成します。 -3. **モデルタイプごとのサブディレクトリ作成:** `models/models/` ディレクトリ内に、サポートする必要のある**各モデルタイプ**ごとにサブディレクトリを作成します。一般的なタイプには以下が含まれます: - * `llm`: テキスト生成モデル - * `text_embedding`: テキストEmbeddingモデル - * `rerank`: Rerankモデル - * `speech2text`: 音声認識モデル - * `tts`: テキスト読み上げモデル - * `moderation`: コンテンツ審査モデル -4. **実装ファイルの準備:** - * 各モデルタイプディレクトリ(例:`models/models/llm/`)に、そのタイプのモデル呼び出しロジックを実装するためのPythonファイルを作成します(例:`llm.py`)。 - * 同じディレクトリに、そのタイプ下の各具体的なモデルごとにYAML設定ファイルを作成します(例:`my-model-v1.yaml`)。 - * (オプション)`_position.yaml` ファイルを作成して、そのタイプ下のモデルがDify UIに表示される順序を制御できます。 - -**構造例(プロバイダー `my_provider` がLLMとEmbeddingをサポートすると仮定):** - -```bash -models/my_provider/ -├── models # モデル実装と設定ディレクトリ -│ ├── llm # LLMタイプ -│ │ ├── _position.yaml (オプション、ソート順制御) -│ │ ├── my-llm-model-v1.yaml -│ │ ├── my-llm-model-v2.yaml -│ │ └── llm.py # LLM実装ロジック -│ └── text_embedding # Embeddingタイプ -│ ├── _position.yaml (オプション、ソート順制御) -│ ├── my-embedding-model.yaml -│ └── text_embedding.py # Embedding実装ロジック -├── provider # プロバイダーレベルのコードディレクトリ -│ └── my_provider.py (認証情報検証などに使用、詳細は「モデルプロバイダーの作成」ドキュメント参照) -└── manifest.yaml # プラグインマニフェストファイル -``` - ---- - -## ステップ2:モデル設定の定義(YAML) - -各具体的なモデルについて、Difyがそれを正しく理解し使用できるように、その属性、パラメータ、および機能を記述するYAMLファイルを作成する必要があります。 - -1. **YAMLファイルの作成:** 対応するモデルタイプディレクトリ(例:`models/models/llm/`)に、追加するモデル用のYAMLファイルを作成します。ファイル名は通常、モデルIDと一致させるか、説明的なものにします(例:`my-llm-model-v1.yaml`)。 -2. **設定内容の記述:** [AIModelEntityスキーマ定義](../../../schema-definition/model/model-designing-rules.md#aimodelentity)仕様に従って内容を記述します。主要なフィールドは以下の通りです: - * `model`: (必須)モデルの公式API識別子。 - * `label`: (必須)Dify UIに表示される名前(多言語対応)。 - * `model_type`: (必須)所在するディレクトリタイプと一致する必要があります(例:`llm`)。 - * `features`: (オプション)モデルがサポートする特殊機能(`vision`、`tool-call`、`stream-tool-call`など)を宣言します。 - * `model_properties`: (必須)モデル固有のプロパティ(`mode`(`chat`または`completion`)、`context_size`など)を定義します。 - * `parameter_rules`: (必須)ユーザーが調整可能なパラメータとそのルール(名前`name`、タイプ`type`、必須`required`、デフォルト値`default`、範囲`min`/`max`、オプション`options`など)を定義します。`use_template`を使用して事前定義されたテンプレートを参照し、一般的なパラメータ(`temperature`、`max_tokens`など)の設定を簡略化できます。 - * `pricing`: (オプション)モデルの課金情報を定義します。 - -**例(`claude-3-5-sonnet-20240620.yaml`):** - -```yaml -model: claude-3-5-sonnet-20240620 -label: - en_US: claude-3-5-sonnet-20240620 -model_type: llm -features: - - agent-thought - - vision - - tool-call - - stream-tool-call - - document -model_properties: - mode: chat - context_size: 200000 -parameter_rules: - - name: temperature - use_template: temperature - - name: top_p - use_template: top_p - - name: max_tokens - use_template: max_tokens - required: true - default: 8192 - min: 1 - max: 8192 # Difyレベルで制限がある可能性に注意 -pricing: - input: '3.00' - output: '15.00' - unit: '0.000001' # 100万トークンあたり - currency: USD -``` - ---- - -## ステップ3:モデル呼び出しコードの記述(Python) - -これはモデル機能実装の中核となるステップです。対応するモデルタイプのPythonファイル(例:`llm.py`)に、API呼び出し、パラメータ変換、結果返却を処理するコードを記述する必要があります。 - -1. **Pythonファイルの作成/編集:** モデルタイプディレクトリ(例:`models/models/llm/`)で、対応するPythonファイル(例:`llm.py`)を作成または開きます。 -2. **実装クラスの定義:** - * クラスを定義します。例:`MyProviderLargeLanguageModel`。 - * このクラスは、DifyプラグインSDK内の対応する**モデルタイプベースクラス**を継承する必要があります。例えば、LLMの場合は `dify_plugin.provider_kits.llm.LargeLanguageModel` を継承します。 - - ```python - import logging - from typing import Union, Generator, Optional, List - from dify_plugin.provider_kits.llm import LargeLanguageModel # ベースクラスをインポート - from dify_plugin.provider_kits.llm import LLMResult, LLMResultChunk, LLMUsage # 結果と使用量クラスをインポート - from dify_plugin.provider_kits.llm import PromptMessage, PromptMessageTool # メッセージとツールクラスをインポート - from dify_plugin.errors.provider_error import InvokeError, InvokeAuthorizationError # エラークラスをインポート - # APIを呼び出すための vendor_sdk があると仮定します - # import vendor_sdk - - logger = logging.getLogger(__name__) - - class MyProviderLargeLanguageModel(LargeLanguageModel): - # ... メソッドを実装 ... - ``` - -3. **主要メソッドの実装:**(具体的に実装が必要なメソッドは継承するベースクラスによって異なります。以下はLLMを例とします) - * `_invoke(...)`: **コア呼び出しメソッド**。 - * **シグネチャ:** `def _invoke(self, model: str, credentials: dict, prompt_messages: List[PromptMessage], model_parameters: dict, tools: Optional[List[PromptMessageTool]] = None, stop: Optional[List[str]] = None, stream: bool = True, user: Optional[str] = None) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]:` - * **責務:** - * `credentials` と `model_parameters` を使用してAPIリクエストを準備します。 - * Difyの `prompt_messages` 形式をプロバイダーAPIが必要とする形式に変換します。 - * Function Calling / Tool Useをサポートするために `tools` パラメータを処理します(モデルがサポートしている場合)。 - * `stream` パラメータに基づいて、ストリーミング呼び出しを行うか同期呼び出しを行うかを決定します。 - * **ストリーミング返却:** `stream=True` の場合、このメソッドはジェネレータ(`Generator`)を返す必要があり、`yield` を介して `LLMResultChunk` オブジェクトを逐次返却します。各チャンクには部分的な結果(テキスト、ツール呼び出しチャンクなど)とオプションの使用量情報が含まれます。 - * **同期返却:** `stream=False` の場合、このメソッドは完全な `LLMResult` オブジェクトを返す必要があります。これには最終的なテキスト結果、完全なツール呼び出しリスト、および総使用量情報(`LLMUsage`)が含まれます。 - * **実装パターン:** 同期ロジックとストリーミングロジックを内部ヘルパーメソッドに分割することを強く推奨します。 - - ```python - def _invoke(self, ..., stream: bool = True, ...) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]: - # APIリクエストパラメータの準備(認証、モデルパラメータ変換、メッセージ形式変換など) - api_params = self._prepare_api_params(credentials, model_parameters, prompt_messages, tools, stop) - - try: - if stream: - return self._invoke_stream(model, api_params, user) - else: - return self._invoke_sync(model, api_params, user) - except vendor_sdk.APIError as e: - # APIエラーを処理し、Difyエラーにマッピングします(_invoke_error_mappingを参照) - # ... mapped_error を発生させる ... - pass # 実際のエラー処理に置き換えてください - except Exception as e: - logger.exception("モデル呼び出し中の不明なエラー") - raise e # または汎用的な InvokeError を発生させる - - def _invoke_stream(self, model: str, api_params: dict, user: Optional[str]) -> Generator[LLMResultChunk, None, None]: - # vendor_sdk のストリーミングインターフェースを呼び出す - # for api_chunk in vendor_sdk.create_stream(...): - # # api_chunk を LLMResultChunk に変換する - # dify_chunk = self._convert_api_chunk_to_llm_result_chunk(api_chunk) - # yield dify_chunk - pass # 実際の実装に置き換えてください - - def _invoke_sync(self, model: str, api_params: dict, user: Optional[str]) -> LLMResult: - # vendor_sdk の同期インターフェースを呼び出す - # api_response = vendor_sdk.create_sync(...) - # api_response を LLMResult (message.content, tools, usage を含む) に変換する - # dify_result = self._convert_api_response_to_llm_result(api_response) - # return dify_result - pass # 実際の実装に置き換えてください - ``` - - * `validate_credentials(self, model: str, credentials: dict) -> None`: (必須)ユーザーが認証情報を追加または変更する際にその有効性を検証するために使用されます。通常、簡単で低コストのAPIエンドポイント(利用可能なモデルのリスト表示、残高確認など)を呼び出すことで実装されます。検証に失敗した場合は、`CredentialsValidateFailedError` またはそのサブクラスをスローする必要があります。 - * `get_num_tokens(self, model: str, credentials: dict, prompt_messages: List[PromptMessage], tools: Optional[List[PromptMessageTool]] = None) -> int`: (オプションだが推奨)与えられた入力のトークン数を推定するために使用されます。正確に計算できない場合やAPIがサポートしていない場合は、0を返すことができます。 - * `@property _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]`: (必須)**エラーマッピング**辞書を定義します。キーはDifyの標準 `InvokeError` サブクラスであり、値はその標準エラーにマッピングされるべきプロバイダーSDKがスローする可能性のある例外タイプのリストです。これはDifyが異なるプロバイダーのエラーを統一的に処理するために不可欠です。 - - ```python - @property - def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: - # マッピング例 - mapping = { - InvokeAuthorizationError: [ - vendor_sdk.AuthenticationError, - vendor_sdk.PermissionDeniedError, - ], - InvokeRateLimitError: [ - vendor_sdk.RateLimitError, - ], - # ... その他のマッピング ... - } - # ここにベースクラスのデフォルトマッピングを追加できます(ベースクラスが提供している場合) - # base_mapping = super()._invoke_error_mapping - # mapping.update(base_mapping) # マージ戦略に注意 - return mapping - ``` - ---- - -## ステップ4:プラグインのデバッグ - -プラグインをコミュニティに貢献する前に、十分なテストとデバッグが不可欠です。Difyはリモートデバッグ機能を提供しており、ローカルでコードを修正し、Difyインスタンスでリアルタイムに効果をテストできます。 - -1. **デバッグ情報の取得:** - * Difyインスタンスで、「プラグイン管理」ページに移動します(管理者権限が必要な場合があります)。 - * ページ右上の「プラグインのデバッグ」をクリックして、`デバッグキー`と`リモートサーバーアドレス`(例:`http://:5003`)を取得します。 -2. **ローカル環境の設定:** - * ローカルプラグインプロジェクトの**ルートディレクトリ**で、`.env`ファイルを見つけるか作成します(`.env.example`からコピーできます)。 - * `.env`ファイルを編集し、デバッグ情報を入力します: - - ```dotenv - INSTALL_METHOD=remote - REMOTE_INSTALL_HOST= # Difyサーバーアドレス - REMOTE_INSTALL_PORT=5003 # デバッグポート - REMOTE_INSTALL_KEY=****-****-****-****-**** # あなたのデバッグキー - ``` - -3. **ローカルプラグインサービスの起動:** - * プラグインプロジェクトのルートディレクトリで、Python環境がアクティブになっていることを確認します(仮想環境を使用している場合)。 - * メインプログラムを実行します: - - ```bash - python -m main - ``` - - * ターミナルの出力を観察し、接続が成功すると、通常、対応するログが表示されます。 -4. **Difyでのテスト:** - * Difyの「プラグイン」または「モデルプロバイダー」ページを更新すると、ローカルプラグインインスタンスが表示され、「デバッグ中」のマークが付いている場合があります。 - * 「設定」->「モデルプロバイダー」に移動し、プラグインを見つけて有効なAPI認証情報を設定します。 - * Difyアプリケーションでモデルを選択して使用し、テストを行います。ローカルでのPythonコードの変更(保存後、通常はサービスが自動的に再読み込みされます)は、Difyでの呼び出し動作に直接影響します。Difyのデバッグプレビュー機能を使用すると、入出力とエラー情報を確認するのに役立ちます。 - ---- - -## ステップ5:パッケージ化と公開 - -開発とデバッグが完了し、プラグインの機能に満足したら、パッケージ化してDifyコミュニティに貢献できます。 - -1. **プラグインのパッケージ化:** - * ローカルデバッグサービスを停止します(`Ctrl+C`)。 - * プラグインプロジェクトの**ルートディレクトリ**でパッケージ化コマンドを実行します: - - ```bash - # をプロバイダーのディレクトリ名に置き換えます - dify plugin package models/ - ``` - - * これにより、プロジェクトのルートディレクトリに `.difypkg` ファイルが生成されます。 -2. **プルリクエストの送信:** - * コードスタイルが良好で、Difyの[プラグイン公開仕様](https://docs.dify.ai/zh-hans/plugins/publish-plugins/publish-to-dify-marketplace)に従っていることを確認します。 - * ローカルGitのコミットをフォークした `dify-official-plugins` リポジトリにプッシュします。 - * GitHub上で `langgenius/dify-official-plugins` メインリポジトリに対してプルリクエストを作成します。PRの説明には、行った変更、追加したモデルや機能、および必要なテスト手順を明確に記述します。 - * Difyチームのレビューを待ちます。レビューが承認されマージされると、あなたの貢献は公式プラグインに含まれ、[Difyマーケットプレイス](https://marketplace.dify.ai/)で利用可能になります。 - ---- - -## さらに探る - -* [モデルスキーマ定義](/plugin-dev-ja/0412-model-schema) (モデルYAML仕様) -* [プラグインマニフェスト構造](/plugin-dev-ja/0411-general-specifications) (`manifest.yaml` 仕様) -* [Dify Plugin SDKリファレンス](https://github.com/langgenius/dify-plugin-sdks) (ベースクラス、データ構造、エラータイプを検索) -* [Dify公式プラグインリポジトリ](https://github.com/langgenius/dify-official-plugins) (既存プラグインの実装を参照) - -{/* -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/0222-creating-new-model-provider-extra.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0222-creating-new-model-provider.mdx b/plugin-dev-ja/0222-creating-new-model-provider.mdx deleted file mode 100644 index 002acd6d..00000000 --- a/plugin-dev-ja/0222-creating-new-model-provider.mdx +++ /dev/null @@ -1,273 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Creating New Model Provider -language: ja -title: モデルプロバイダーの作成 -description: このドキュメントでは、モデルプロバイダープラグインを作成する方法について詳しく説明します。プロジェクトの初期化、モデル設定方法(事前定義モデルとカスタムモデル)の選択、プロバイダー設定YAMLファイルの作成、およびプロバイダーコードの作成の完全なプロセスが含まれます。 ---- - -Modelタイプのプラグインを作成する最初のステップは、プラグインプロジェクトを初期化し、モデルプロバイダーファイルを作成することです。その後、具体的な事前定義済み/カスタムモデルのコードを記述します。既存のモデルプロバイダーに新しいモデルを追加したいだけの場合は、[新しいモデルの迅速な統合](/plugin-dev-ja/0211-getting-started-new-model)を参照してください。 - -### 事前準備 - -* Dify プラグインスケルトンツール -* Python 環境、バージョン ≥ 3.12 - -プラグイン開発用のスケルトンツールを準備する方法の詳細については、[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools)を参照してください。開始する前に、[モデルプラグイン](/plugin-dev-ja/0131-model-plugin-introduction.ja)の基本的な概念と構造を理解することをお勧めします。 - -### 新規プロジェクトの作成 - -スケルトンコマンドラインツールのパスで、新しい Dify プラグインプロジェクトを作成します。 - -``` -./dify-plugin-darwin-arm64 plugin init -``` - -このバイナリファイルを `dify` にリネームし、`/usr/local/bin` パスにコピーした場合、次のコマンドを実行して新しいプラグインプロジェクトを作成できます: - -```bash -dify plugin init -``` - -### モデルプラグインテンプレートの選択 - -スケルトンツール内のすべてのテンプレートには、完全なコードプロジェクトが提供されています。`LLM` タイプのプラグインテンプレートを選択します。 - -![プラグインタイプ: llm](https://assets-docs.dify.ai/2024/12/8efe646e9174164b9edbf658b5934b86.png) - -#### プラグイン権限の設定 - -このLLMプラグインに次の権限を設定します: - -* Models -* LLM -* Storage - -![モデルプラグイン権限](https://assets-docs.dify.ai/2024/12/10f3b3ee6c03a1215309f13d712455d4.png) - -#### モデルタイプ設定の説明 - -モデルプロバイダーは、以下の2つのモデル設定方法をサポートしています: - -* `predefined-model` **事前定義済みモデル** - - 一般的な大規模モデルタイプで、統一されたプロバイダーの認証情報を設定するだけで、プロバイダー下の事前定義済みモデルを使用できます。例えば、`OpenAI` モデルプロバイダーは `gpt-3.5-turbo-0125` や `gpt-4o-2024-05-13` などの一連の事前定義済みモデルを提供しています。詳細な開発手順については、事前定義済みモデルの統合を参照してください。 -* `customizable-model` **カスタムモデル** - - 各モデルの認証情報設定を手動で追加する必要があります。例えば `Xinference` は、LLMとText Embeddingの両方をサポートしていますが、各モデルには一意の **model\_uid** があります。両方を同時に統合したい場合は、各モデルに **model\_uid** を設定する必要があります。詳細な開発手順については、カスタムモデルの統合を参照してください。 - -2つの設定方法は**共存をサポート**しており、つまり、プロバイダーが `predefined-model` + `customizable-model` または `predefined-model` などをサポートする場合、プロバイダーの統一された認証情報を設定することで、事前定義済みモデルとリモートから取得したモデルを使用できます。新しいモデルを追加した場合は、これに加えてカスタムモデルを使用できます。 - -### 新しいモデルプロバイダーの追加 - -新しいモデルプロバイダーを追加するには、主に次の手順が含まれます: - -1. **モデルプロバイダー設定YAMLファイルの作成** - - プロバイダーディレクトリに新しいYAMLファイルを追加し、プロバイダーの基本情報とパラメータ設定を記述します。ProviderSchemaの要件に従って内容を記述し、システム仕様との一貫性を確保します。 -2. **モデルプロバイダーコードの記述** - - プロバイダーのクラスコードを作成し、システムのインターフェース要件に準拠したPythonクラスを実装して、プロバイダーのAPIと連携し、コア機能を実現します。 - -*** - -以下は、各ステップの完全な操作詳細です。 - -#### 1. **モデルプロバイダー設定ファイルの作成** - -ManifestはYAML形式のファイルであり、モデルプロバイダーの基本情報、サポートされるモデルタイプ、設定方法、認証情報ルールを宣言します。プラグインプロジェクトテンプレートは、`/providers` パスに設定ファイルを自動的に生成します。 - -以下は、`Anthropic` モデル設定ファイル `anthropic.yaml` のサンプルコードです: - -```yaml -provider: anthropic -label: - en_US: Anthropic -description: - en_US: Anthropic's powerful models, such as Claude 3. - zh_Hans: Anthropic の強力なモデル、例えば Claude 3。 -icon_small: - en_US: icon_s_en.svg -icon_large: - en_US: icon_l_en.svg -background: "#F0F0EB" -help: - title: - en_US: Get your API Key from Anthropic - zh_Hans: Anthropic から API キーを取得 - url: - en_US: https://console.anthropic.com/account/keys -supported_model_types: - - llm -configurate_methods: - - predefined-model -provider_credential_schema: - credential_form_schemas: - - variable: anthropic_api_key - label: - en_US: API Key - type: secret-input - required: true - placeholder: - zh_Hans: ここに API キーを入力してください - en_US: Enter your API Key - - variable: anthropic_api_url - label: - en_US: API URL - type: text-input - required: false - placeholder: - zh_Hans: ここに API URL を入力してください - en_US: Enter your API URL -models: - llm: - predefined: - - "models/llm/*.yaml" - position: "models/llm/_position.yaml" -extra: - python: - provider_source: provider/anthropic.py - model_sources: - - "models/llm/llm.py" -``` - -接続するプロバイダーがカスタムモデルを提供する場合、例えば`OpenAI`がファインチューニングモデルを提供する場合、`model_credential_schema` フィールドを追加する必要があります。 - -以下は `OpenAI` ファミリーモデルのサンプルコードです: - -```yaml -model_credential_schema: - model: # ファインチューニングモデル名 - label: - en_US: Model Name - zh_Hans: モデル名 - placeholder: - en_US: Enter your model name - zh_Hans: モデル名を入力 - credential_form_schemas: - - variable: openai_api_key - label: - en_US: API Key - type: secret-input - required: true - placeholder: - zh_Hans: ここに API キーを入力してください - en_US: Enter your API Key - - variable: openai_organization - label: - zh_Hans: 組織 ID - en_US: Organization - type: text-input - required: false - placeholder: - zh_Hans: ここに組織 ID を入力してください - en_US: Enter your Organization ID - - variable: openai_api_base - label: - zh_Hans: API ベース - en_US: API Base - type: text-input - required: false - placeholder: - zh_Hans: ここに API ベースを入力してください - en_US: Enter your API Base -``` - -より完全なモデルプロバイダーYAML仕様については、[モデルスキーマ](/plugin-dev-ja/0412-model-schema)ドキュメントを参照してください。 - -#### 2. **モデルプロバイダーコードの記述** - -`/providers` フォルダに同名の Python ファイルを作成します。例えば `anthropic.py` とし、`__base.provider.Provider` 基本クラスを継承する `class` を実装します。例えば `AnthropicProvider` です。 - -以下は `Anthropic` のサンプルコードです: - -```python -import logging -from dify_plugin.entities.model import ModelType -from dify_plugin.errors.model import CredentialsValidateFailedError -from dify_plugin import ModelProvider - -logger = logging.getLogger(__name__) - - -class AnthropicProvider(ModelProvider): - def validate_provider_credentials(self, credentials: dict) -> None: - """ - Validate provider credentials - - if validate failed, raise exception - - :param credentials: provider credentials, credentials form defined in `provider_credential_schema`. - """ - try: - model_instance = self.get_model_instance(ModelType.LLM) - model_instance.validate_credentials(model="claude-3-opus-20240229", credentials=credentials) - except CredentialsValidateFailedError as ex: - raise ex - except Exception as ex: - logger.exception(f"{self.get_provider_schema().provider} credentials validate failed") - raise ex -``` - -プロバイダーは `__base.model_provider.ModelProvider` 基本クラスを継承し、`validate_provider_credentials` プロバイダー統一認証情報検証メソッドを実装するだけで済みます。 - -```python -def validate_provider_credentials(self, credentials: dict) -> None: - """ - Validate provider credentials - You can choose any validate_credentials method of model type or implement validate method by yourself, - such as: get model list api - - if validate failed, raise exception - - :param credentials: provider credentials, credentials form defined in `provider_credential_schema`. - """ -``` - -もちろん、`validate_provider_credentials` の実装を一旦プレースホルダとして残しておき、モデル認証情報検証メソッドの実装後に直接再利用することも可能です。 - -#### **カスタムモデルプロバイダー** - -他のタイプのモデルプロバイダーについては、以下の設定方法を参照してください。 - -`Xinference` のようなカスタムモデルプロバイダーの場合、完全な実装手順をスキップできます。`XinferenceProvider` という名前の空のクラスを作成し、その中に空の `validate_provider_credentials` メソッドを実装するだけです。 - -**詳細説明:** - -• `XinferenceProvider` は、カスタムモデルプロバイダーを識別するためのプレースホルダクラスです。 - -• `validate_provider_credentials` メソッドは実際には呼び出されませんが、存在する必要があります。これは、その親クラスが抽象クラスであり、すべてのサブクラスにこのメソッドの実装を要求するためです。空の実装を提供することで、抽象メソッドが未実装であることによるインスタンス化エラーを回避できます。 - -```python -class XinferenceProvider(Provider): - def validate_provider_credentials(self, credentials: dict) -> None: - pass -``` - -モデルプロバイダーを初期化した後、次にプロバイダーが提供する具体的なLLMモデルを統合する必要があります。詳細については、以下の内容を参照してください: - -* [モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules) - 事前定義済みモデルを統合するための仕様を理解する -* [モデルスキーマ](/plugin-dev-ja/0412-model-schema) - カスタムモデルを統合するための仕様を理解する -* [リリース概要](/plugin-dev-ja/0321-release-overview) - プラグインのリリースプロセスを学ぶ - -## 参考リソース - -- [新しいモデルの迅速な統合](/plugin-dev-ja/0211-getting-started-new-model) - 既存のプロバイダーに新しいモデルを追加する方法 -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - プラグイン開発入門ガイドに戻る -- [新しいモデルプロバイダー作成の補足](/plugin-dev-ja/0222-creating-new-model-provider-extra) - より高度な設定について学ぶ -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインマニフェストファイルの設定を理解する - -{/* -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/0222-creating-new-model-provider.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0222-datasource-plugin.mdx b/plugin-dev-ja/0222-datasource-plugin.mdx deleted file mode 100644 index d95d020c..00000000 --- a/plugin-dev-ja/0222-datasource-plugin.mdx +++ /dev/null @@ -1,452 +0,0 @@ ---- -title: "データソースプラグイン" ---- - -データソース(Data Source)プラグインは、Dify 1.9.0で新たに導入されたプラグインタイプです。ナレッジパイプライン(Knowledge Pipeline)において、ドキュメントデータのソースとして機能し、パイプライン全体の開始点となります。 - -この記事では、データソースプラグインの開発方法(プラグインの構造、コード例、デバッグ方法など)を紹介し、プラグインの開発と公開を迅速に完了させるお手伝いをします。 - -## 事前準備 - -この記事を読む前に、ナレッジパイプラインのプロセスに関する基本的な理解と、プラグイン開発に関する一定の知識があることを確認してください。関連する内容は、以下のドキュメントで確認できます: - -- [ステップ2:ナレッジパイプラインのオーケストレーション](/ja-jp/guides/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration) -- [Dify プラグイン開発:Hello World ガイド](/plugin-dev-ja/0211-getting-started-dify-tool) - -## データソースプラグインのタイプ - -Difyは、Webクローラー、オンラインドキュメント、オンラインストレージの3種類のデータソースプラグインをサポートしています。プラグインのコードを具体的に実装する際には、プラグイン機能を実現するクラスが異なるデータソースクラスを継承する必要があります。3つのプラグインタイプは、3つの親クラスに対応しています。 - - - 親クラスを継承してプラグイン機能を実現する方法については、 [Dify プラグイン開発:Hello World ガイド-4.4 ツール (Tool) ロジックの実装](/plugin-dev-ja/0211-getting-started-dify-tool#4-4-ツール-tool-ロジックの実装)をお読みください。。 - - -各データソースプラグインタイプは、複数のデータソースの設定をサポートしています。例: - -- Webクローラー:Jina Reader、FireCrawl -- オンラインドキュメント:Notion、Confluence、GitHub -- オンラインストレージ:Onedrive、Google Drive、Box、AWS S3、Tencent COS - -データソースのタイプとデータソースプラグインのタイプの関係は、以下の図の通りです: - -![](/images/data_source_type.png) - -## プラグインの開発 - -### データソースプラグインの作成 - -スキャフォールディングのコマンドラインツールを使用して、データソースプラグインを作成し、`datasource` タイプを選択できます。設定が完了すると、コマンドラインツールが自動的にプラグインのプロジェクトコードを生成します。 - -```powershell -dify plugin init -``` - -![](/images/datasource_plugin_init.png) - - - 通常、データソースプラグインはDifyプラットフォームの他の機能を使用しないため、追加の権限を設定する必要はありません。 - - -#### データソースプラグインの構造 - -データソースプラグインは、主に3つの部分で構成されています。 - -- `manifest.yaml` ファイル:プラグインの基本情報を記述します -- `provider` ディレクトリ:プラグインプロバイダーの説明と認証を実装するコードが含まれます -- `datasources` ディレクトリ:データソースを取得するコアロジックを実装する説明とコードが含まれます - -``` -├── _assets -│   └── icon.svg -├── datasources -│   ├── your_datasource.py -│   └── your_datasource.yaml -├── main.py -├── manifest.yaml -├── PRIVACY.md -├── provider -│   ├── your_datasource.py -│   └── your_datasource.yaml -├── README.md -└── requirements.txt -``` - -#### 正しいバージョンとタグの設定 - -- `manifest.yaml` ファイルでは、プラグインがサポートするDifyの最低バージョンを次のように設定する必要があります: - - ```yaml - minimum_dify_version: 1.9.0 - ``` -- `manifest.yaml` ファイルで、プラグインに以下のデータソースタグを追加し、プラグインがDify Marketplaceでデータソースとして分類・表示されるようにする必要があります: - - ```yaml - tags: - - rag - ``` -- `requirements.txt` ファイルでは、プラグイン開発に使用するプラグインSDKのバージョンを次のように設定する必要があります: - - ```yaml - dify-plugin>=0.5.0,<0.6.0 - ``` - -### プロバイダーの追加 - -#### プロバイダーYAMLファイルの作成 - -プロバイダーYAMLファイルの定義と記述は、ツールプラグインと基本的に同じですが、以下の2点のみ異なります。 - -```yaml -# データソースのプロバイダータイプを指定します。online_drive、online_document、または website_crawl に設定できます -provider_type: online_drive # online_document, website_crawl - -# データソースを指定します -datasources: - - datasources/PluginName.yaml -``` - - - プロバイダーYAMLファイルの作成に関する詳細については、[Dify プラグイン開発:Hello World ガイド- - 4.3 プロバイダー認証情報の設定](/plugin-dev-ja/0211-getting-started-dify-tool#4-3-プロバイダー認証情報の設定)をお読みください。 - - - - データソースプラグインは、OAuth 2.0 または API キーの2つの方法で認証をサポートしています。OAuth の設定方法については、[ツールプラグインに OAuth サポートを追加する](/plugin-dev-en/0222-tool-oauth)をお読みください。 - - -#### プロバイダーコードファイルの作成 - -- **APIキー認証モードを使用する場合**、データソースプラグインのプロバイダーコードファイルはツールプラグインと完全に同じですが、プロバイダークラスが継承する親クラスを `DatasourceProvider` に変更するだけで済みます。 - - ```python - class YourDatasourceProvider(DatasourceProvider): - - def _validate_credentials(self, credentials: Mapping[str, Any]) -> None: - try: - """ - IMPLEMENT YOUR VALIDATION HERE - """ - except Exception as e: - raise ToolProviderCredentialValidationError(str(e)) - ``` -- **OAuth認証モードを使用する場合**、データソースプラグインはツールプラグインと若干異なります。OAuthを使用してアクセス権限を取得する際、データソースプラグインは同時にユーザー名とアバターを返し、フロントエンドに表示することができます。そのため、`_oauth_get_credentials` と `_oauth_refresh_credentials` は、`name`、`avatar_url`、`expires_at`、および `credentials` を含む `DatasourceOAuthCredentials` 型を返す必要があります。 - - `DatasourceOAuthCredentials` クラスの定義は以下の通りです。返す際には対応する型に設定する必要があります: - - ```python - class DatasourceOAuthCredentials(BaseModel): - name: str | None = Field(None, description="The name of the OAuth credential") - avatar_url: str | None = Field(None, description="The avatar url of the OAuth") - credentials: Mapping[str, Any] = Field(..., description="The credentials of the OAuth") - expires_at: int | None = Field( - default=-1, - description="""The expiration timestamp (in seconds since Unix epoch, UTC) of the credentials. - Set to -1 or None if the credentials do not expire.""", - ) - ``` - - `_oauth_get_authorization_url`、`_oauth_get_credentials`、および `_oauth_refresh_credentials` の関数シグネチャは以下の通りです: - - - - ```python - def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: - """ - Generate the authorization URL for {{ .PluginName }} OAuth. - """ - try: - """ - IMPLEMENT YOUR AUTHORIZATION URL GENERATION HERE - """ - except Exception as e: - raise DatasourceOAuthError(str(e)) - return "" - ``` - - - ```python - def _oauth_get_credentials( - self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request - ) -> DatasourceOAuthCredentials: - """ - Exchange code for access_token. - """ - try: - """ - IMPLEMENT YOUR CREDENTIALS EXCHANGE HERE - """ - except Exception as e: - raise DatasourceOAuthError(str(e)) - return DatasourceOAuthCredentials( - name="", - avatar_url="", - expires_at=-1, - credentials={}, - ) - ``` - - - ```python - def _oauth_refresh_credentials( - self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] - ) -> DatasourceOAuthCredentials: - """ - Refresh the credentials - """ - return DatasourceOAuthCredentials( - name="", - avatar_url="", - expires_at=-1, - credentials={}, - ) - ``` - - - -### データソースの追加 - -3種類のデータソースプラグインでは、作成するYAMLファイル形式とデータソースコード形式が異なります。以下でそれぞれ説明します。 - -#### **Webクローラー**(Web Crawler) - -Webクローラー系プラグインのプロバイダーYAMLファイルでは、`output_schema` は `source_url`、`content`、`title`、`description` の4つのパラメータを固定で返す必要があります。 - -```yaml -output_schema: - type: object - properties: - source_url: - type: string - description: the source url of the website - content: - type: string - description: the content from the website - title: - type: string - description: the title of the website - "description": - type: string - description: the description of the website -``` - -Webクローラー系プラグインのメインロジックコードでは、`WebsiteCrawlDatasource` クラスを継承し、`_get_website_crawl` メソッドを実装した上で、`create_crawl_message` メソッドを使用してウェブクローラーメッセージを返す必要があります。 - -複数のウェブページをクロールし、バッチで返す必要がある場合は、`WebSiteInfo.status` を `processing` に設定し、`create_crawl_message` メソッドを使用して各バッチのWebクローラーメッセージを返すことができます。すべてのウェブページのクロールが完了したら、`WebSiteInfo.status` を `completed` に設定します。 - -```python -class YourDataSource(WebsiteCrawlDatasource): - - def _get_website_crawl( - self, datasource_parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - - crawl_res = WebSiteInfo(web_info_list=[], status="", total=0, completed=0) - crawl_res.status = "processing" - yield self.create_crawl_message(crawl_res) - - ### your crawl logic - ... - crawl_res.status = "completed" - crawl_res.web_info_list = [ - WebSiteInfoDetail( - title="", - source_url="", - description="", - content="", - ) - ] - crawl_res.total = 1 - crawl_res.completed = 1 - - yield self.create_crawl_message(crawl_res) -``` - -#### オンラインドキュメント(Online Document) - -オンラインドキュメント系プラグインの戻り値には、ドキュメントの内容を表す `content` フィールドを少なくとも含める必要があります。以下に例を示します。 - -```yaml -output_schema: - type: object - properties: - workspace_id: - type: string - description: workspace id - page_id: - type: string - description: page id - content: - type: string - description: page content -``` - -オンラインドキュメント系プラグインのメインロジックコードでは、`OnlineDocumentDatasource` クラスを継承し、`_get_pages` と `_get_content` の2つのメソッドを実装する必要があります。ユーザーがプラグインを実行すると、まず `_get_pages` メソッドを介してドキュメントリストを取得します。ユーザーがリストから特定のドキュメントを選択すると、次に `_get_content` メソッドを介してドキュメントの内容を取得します。 - - - - ```python - def _get_pages(self, datasource_parameters: dict[str, Any]) -> DatasourceGetPagesResponse: - # your get pages logic - response = requests.get(url, headers=headers, params=params, timeout=30) - pages = [] - for item in response.json().get("results", []): - page = OnlineDocumentPage( - page_name=item.get("title", ""), - page_id=item.get("id", ""), - type="page", - last_edited_time=item.get("version", {}).get("createdAt", ""), - parent_id=item.get("parentId", ""), - page_icon=None, - ) - pages.append(page) - online_document_info = OnlineDocumentInfo( - workspace_name=workspace_name, - workspace_icon=workspace_icon, - workspace_id=workspace_id, - pages=[page], - total=pages.length(), - ) - return DatasourceGetPagesResponse(result=[online_document_info]) - ``` - - - ```python - def _get_content(self, page: GetOnlineDocumentPageContentRequest) -> Generator[DatasourceMessage, None, None]: - # your fetch content logic, example - response = requests.get(url, headers=headers, params=params, timeout=30) - ... - yield self.create_variable_message("content", "") - yield self.create_variable_message("page_id", "") - yield self.create_variable_message("workspace_id", "") - ``` - - - -#### オンラインストレージ(Online Drive) - -オンラインストレージ系プラグインの戻り値の型はファイルであり、以下の仕様に従う必要があります。 - -```yaml -output_schema: - type: object - properties: - file: - $ref: "https://dify.ai/schemas/v1/file.json" -``` - -オンラインストレージ系プラグインのメインロジックコードでは、`OnlineDriveDatasource` クラスを継承し、`_browse_files` と `_download_file` の2つのメソッドを実装する必要があります。 - -ユーザーがプラグインを実行すると、まず `_browse_files` メソッドを介してファイルリストを取得します。このとき `prefix` は空で、ルートディレクトリ直下のファイルリストを取得することを示します。ファイルリストには、フォルダとファイルの2種類の変数が含まれます。ユーザーがさらにフォルダを開くと、`_browse_files` メソッドが再度実行されます。このとき、`OnlineDriveBrowseFilesRequest` の中の `prefix` はフォルダIDとなり、そのフォルダ内のファイルリストを取得するために使用されます。 - -ユーザーが特定のファイルを選択すると、プラグインは `_download_file` メソッドとファイルIDを介してファイルの内容を取得します。`_get_mime_type_from_filename` メソッドを使用してファイルのMIMEタイプを取得し、パイプラインで異なるファイルタイプに対して異なる処理を行うことができます。 - -ファイルリストに複数のファイルが含まれる場合、`OnlineDriveFileBucket.is_truncated` を `True` に設定し、`OnlineDriveFileBucket.next_page_parameters` をファイルリストの取得を続行するためのパラメータ(例えば、次のページの要求IDやURLなど、サービスプロバイダーによって異なります)に設定することができます。 - - - - ```python - def _browse_files( - self, request: OnlineDriveBrowseFilesRequest - ) -> OnlineDriveBrowseFilesResponse: - - credentials = self.runtime.credentials - bucket_name = request.bucket - prefix = request.prefix or "" # Allow empty prefix for root folder; When you browse the folder, the prefix is the folder id - max_keys = request.max_keys or 10 - next_page_parameters = request.next_page_parameters or {} - - files = [] - files.append(OnlineDriveFile( - id="", - name="", - size=0, - type="folder" # or "file" - )) - - return OnlineDriveBrowseFilesResponse(result=[ - OnlineDriveFileBucket( - bucket="", - files=files, - is_truncated=False, - next_page_parameters={} - ) - ]) - ``` - - - ```python - def _download_file(self, request: OnlineDriveDownloadFileRequest) -> Generator[DatasourceMessage, None, None]: - credentials = self.runtime.credentials - file_id = request.id - - file_content = bytes() - file_name = "" - - mime_type = self._get_mime_type_from_filename(file_name) - - yield self.create_blob_message(file_content, meta={ - "file_name": file_name, - "mime_type": mime_type - }) - - def _get_mime_type_from_filename(self, filename: str) -> str: - """Determine MIME type from file extension.""" - import mimetypes - mime_type, _ = mimetypes.guess_type(filename) - return mime_type or "application/octet-stream" - ``` - - - -AWS S3などのストレージサービスプロバイダーでは、`prefix`、`bucket`、`id` の各変数に特別な使用方法があり、実際の開発では必要に応じて柔軟に適用できます。 - -- `prefix`: ファイルパスのプレフィックスを表します。例えば、`prefix=container1/folder1/` は、`container1` バケット内の `folder1` フォルダにあるファイルまたはファイルリストを取得することを示します。 -- `bucket`: ファイルバケットを表します。例えば、`bucket=container1` は、`container1` バケット直下のファイルまたはファイルリストを取得することを示します(非標準のS3プロトコルのオンラインストレージの場合、このフィールドは空にすることができます)。 -- `id`: `_download_file` メソッドは prefix 変数を使用しないため、ファイルパスを id に連結する必要があります。例えば、`id=container1/folder1/file1.txt` は、`container1` バケット内の folder1 フォルダにある `file1.txt` ファイルを取得することを示します。 - - - [公式 Google Drive プラグイン](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/google_cloud_storage/datasources/google_cloud_storage.py) および [公式 AWS S3 プラグイン](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/aws_s3_storage/datasources/aws_s3_storage.py)の具体的な実装を参考にしてください。 - - -## プラグインのデバッグ - -データソースプラグインは、リモートデバッグとローカルプラグインとしてのインストールの2つのデバッグ方法をサポートしています。注意点: - -- プラグインがOAuth認証モードを使用している場合、リモートデバッグ時の `redirect_uri` はローカルプラグインの設定と一致しないため、サービスプロバイダーのOAuth App関連設定を変更する必要があります。 -- データソースプラグインはステップ実行デバッグをサポートしていますが、機能の正確性を保証するため、完全なナレッジパイプラインでテストすることをお勧めします。 - -## 最終チェック - -パッケージ化して公開する前に、以下の項目がすべて完了していることを確認してください: - -- サポートする最低Difyバージョンを `1.9.0` に設定する -- SDKバージョンを `dify-plugin>=0.5.0,<0.6.0` に設定する -- `README.md` と `PRIVACY.md` ファイルを作成する -- コードファイルには英語のコンテンツのみが含まれていることを確認する -- デフォルトのアイコンをデータソースプロバイダーのロゴに置き換える - -## パッケージ化と公開 - -プラグインディレクトリで以下のコマンドを実行すると、`.difypkg` プラグインパッケージが生成されます: - -``` -dify plugin package . -o your_datasource.difypkg -``` - -次に、以下のいずれかを行うことができます: - -- あなたのDify環境にプラグインをインポートして使用する -- プルリクエストを送信して、Dify Marketplaceにプラグインを公開する - - - プラグインの公開プロセスについては、[プラグインのリリース](/plugin-dev-ja/0321-release-overview)。 - - -{/* -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/0222-datasource-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0222-debugging-logs.mdx b/plugin-dev-ja/0222-debugging-logs.mdx deleted file mode 100644 index dd21aaf7..00000000 --- a/plugin-dev-ja/0222-debugging-logs.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Debugging logs -language: ja -description: Difyプラグイン開発において、開発とデバッグを容易にするためにツールにログ出力機能を追加する方法を紹介します。 -title: 開発やデバッグのためのログの出力 ---- - -プラグインの開発者は、開発やデバッグの目的で、プラグインの処理の過程で任意の文字列をログに出力したいと考えることがあるでしょう。 - -この目的で、プラグインの SDK には、Python の標準ライブラリである `logging` 用のハンドラが実装されています。これを利用すれば、**リモートデバッグ中の標準出力** にも **プラグインデーモンのコンテナログ**(コミュニティ版のみ)にも、任意の文字列を出力できます。 - -## サンプル - -`plugin_logger_handler` をインポートして、ロガーにハンドラとして追加します。以下は、ツールプラグインのサンプルコードです。 - -```python -from collections.abc import Generator -from typing import Any -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - - -# Import logging and custom handler -import logging -from dify_plugin.config.logger_format import plugin_logger_handler - -# Set up logging with the custom handler -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) -logger.addHandler(plugin_logger_handler) - - -class LoggerDemoTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: - - # Log messages with different severity levels - logger.info("This is a INFO log message.") - logger.warning("This is a WARNING log message.") - logger.error("This is a ERROR log message.") - - yield self.create_text_message("Hello, Dify!") -``` - -{/* -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/0222-debugging-logs.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0222-tool-plugin.mdx b/plugin-dev-ja/0222-tool-plugin.mdx deleted file mode 100644 index 25cb6a5f..00000000 --- a/plugin-dev-ja/0222-tool-plugin.mdx +++ /dev/null @@ -1,386 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Tool Plugin -language: ja -title: Tool プラグイン -description: このドキュメントでは、Difyのツールプラグインを開発する方法を詳しく説明します。Google Searchを例に、プラグインの初期化、テンプレートの選択、ツールプロバイダー設定ファイルの定義、サードパーティサービス認証情報の追加、ツール機能コードの実装、デバッグ、パッケージ化と公開までの完全なツールプラグイン開発フローを紹介します。 ---- - -ツールとは、Chatflow / Workflow / Agent タイプのアプリケーションから呼び出すことができるサードパーティサービスを指し、Difyアプリケーションの能力を強化するための完全なAPI実装機能を提供します。例えば、アプリケーションにオンライン検索や画像生成などの追加機能を追加します。 - -![ツールプラグインの例](https://assets-docs.dify.ai/2024/12/7e7bcf1f9e3acf72c6917ea9de4e4613.png) - -この記事では、**「ツールプラグイン」** とは、ツールプロバイダーファイル、機能コードなどの構造を含む完全なプロジェクトを指します。1つのツールプロバイダーには複数のツール(個々のツール内で提供される追加機能と理解できます)を含めることができ、構造は以下の通りです。 - -``` -- ツールプロバイダー - - Tool A - - Tool B -``` - -![ツールプラグインの構造](https://assets-docs.dify.ai/2025/02/60c4c86a317d865133aa460592eac079.png) - -この記事では、`Google Search` を例に、ツールプラグインを迅速に開発する方法を紹介します。 - -### 事前準備 - -- Difyプラグインスキャフォールドツール -- Python環境、バージョン ≥ 3.12 - -プラグイン開発用のスキャフォールドツールの準備方法については、[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools)を参照してください。初めてプラグインを開発する場合は、まず[Difyプラグイン開発:Hello Worldガイド](/plugin-dev-ja/0211-getting-started-dify-tool)を読むことをお勧めします。 - -### 新規プロジェクトの作成 - -スキャフォールドコマンドラインツールを実行し、新しいDifyプラグインプロジェクトを作成します。 - -```bash -./dify-plugin-darwin-arm64 plugin init -``` - -このバイナリファイルを `dify` にリネームし、`/usr/local/bin` パスにコピーした場合、以下のコマンドを実行して新しいプラグインプロジェクトを作成できます。 - -```bash -dify plugin init -``` - -> 以下では、コマンドラインの例として `dify` を使用します。問題が発生した場合は、`dify` コマンドをコマンドラインツールの実際のパスに置き換えてください。 - -### プラグインタイプとテンプレートの選択 - -スキャフォールドツール内のすべてのテンプレートは、完全なコードプロジェクトを提供しています。この記事の例では、`Tool` プラグインを選択します。 - -> プラグイン開発に慣れている場合は、テンプレートを使用せずに、[一般仕様](/plugin-dev-ja/0411-general-specifications)のガイドラインを参照して、さまざまなタイプのプラグイン開発を完了できます。 - -![プラグインタイプ:ツール](https://assets-docs.dify.ai/2024/12/dd3c0f9a66454e15868eabced7b74fd6.png) - -#### プラグイン権限の設定 - -プラグインはDifyプラットフォームの権限も読み取る必要があり、このサンプルプラグインには以下の権限を付与します。 - -- Tools -- Apps -- 永続ストレージStorageを有効にし、デフォルトサイズのストレージを割り当てる -- Endpointの登録を許可する - -> ターミナル内で方向キーを使用して権限を選択し、「Tab」キーを使用して権限を付与します。 - -すべての権限項目にチェックを入れた後、Enterキーを押してプラグインの作成を完了します。システムは自動的にプラグインプロジェクトコードを生成します。 - -![プラグイン権限](https://assets-docs.dify.ai/2024/12/9cf92c2e74dce55e6e9e331d031e5a9f.png) - -### ツールプラグインの開発 - -#### 1. ツールプロバイダーファイルの作成 - -ツールプロバイダーファイルはYAML形式のファイルで、ツールプラグインの基本設定エントリと理解でき、ツールに必要な認証情報を提供するために使用されます。 - -プラグインテンプレートプロジェクトの `/provider` パスに移動し、そこにあるyamlファイルを `google.yaml` にリネームします。この `yaml` ファイルには、ツールプロバイダーの情報(プロバイダー名、アイコン、作成者などの詳細)が含まれます。この情報はプラグインのインストール時に表示されます。 - -**コード例** - -```yaml -identity: # ツールプロバイダーの基本情報 - author: Your-name # 作成者 - name: google # 名称、一意であり、他のプロバイダーと重複することはできません - label: # ラベル、フロントエンド表示用 - en_US: Google # 英語ラベル - zh_Hans: Google # 中国語ラベル - description: # 説明、フロントエンド表示用 - en_US: Google # 英語の説明 - zh_Hans: Google # 中国語の説明 - icon: icon.svg # ツールアイコン、_assetsフォルダに配置する必要があります - tags: # タグ、フロントエンド表示用 - - search -``` - -このファイルパスが `/tools` ディレクトリに配置されるようにしてください。完全なパスは次のとおりです。 - -```yaml -plugins: - tools: - - 'google.yaml' -``` - -`google.yaml`ファイルは、プラグインプロジェクトにおける絶対パスを使用する必要があります。この例では、プロジェクトのルートディレクトリにあります。YAMLファイル内のidentityフィールドは次のように説明されます:`identity`には、作成者、名前、ラベル、説明、アイコンなど、ツールプロバイダーの基本情報が含まれます。 - -- アイコンは添付リソースに属する必要があり、プロジェクトのルートディレクトリにある `_assets` フォルダに配置する必要があります。 -- タグは、ユーザーがカテゴリ別にプラグインをすばやく見つけるのに役立ちます。以下は現在サポートされているすべてのタグです。 - -```python -class ToolLabelEnum(Enum): - SEARCH = 'search' - IMAGE = 'image' - VIDEOS = 'videos' - WEATHER = 'weather' - FINANCE = 'finance' - DESIGN = 'design' - TRAVEL = 'travel' - SOCIAL = 'social' - NEWS = 'news' - MEDICAL = 'medical' - PRODUCTIVITY = 'productivity' - EDUCATION = 'education' - BUSINESS = 'business' - ENTERTAINMENT = 'entertainment' - UTILITIES = 'utilities' - OTHER = 'other' -``` - -#### **2. サードパーティサービス認証情報の補完** - -開発を容易にするため、サードパーティサービス `SerpApi` が提供する Google Search API を採用することを選択します。`SerpApi` は使用にあたって API Key の入力を要求するため、`yaml` ファイル内に `credentials_for_provider` フィールドを追加する必要があります。 - -完全なコードは以下の通りです。 - -```yaml -identity: - author: Dify - name: google - label: - en_US: Google - zh_Hans: Google - pt_BR: Google - description: - en_US: Google - zh_Hans: GoogleSearch - pt_BR: Google - icon: icon.svg - tags: - - search -credentials_for_provider: # credentials_for_provider フィールドを追加 - serpapi_api_key: - type: secret-input - required: true - label: - en_US: SerpApi API key - zh_Hans: SerpApi APIキー - placeholder: - en_US: Please input your SerpApi API key - zh_Hans: SerpApi APIキーを入力してください - help: - en_US: Get your SerpApi API key from SerpApi - zh_Hans: SerpApiからSerpApi APIキーを取得します - url: https://serpapi.com/manage-api-key -tools: - - tools/google_search.yaml -extra: - python: - source: google.py -``` - -- `credentials_for_provider` の子構造は、[一般仕様](/plugin-dev-ja/0411-general-specifications)の要件を満たす必要があります。 -- このプロバイダーにどのツールが含まれているかを指定する必要があります。この例では、`tools/google_search.yaml` ファイルのみが含まれています。 -- プロバイダーとして、基本情報を定義するだけでなく、そのコードロジックの一部を実装する必要があるため、その実装ロジックを指定する必要があります。この例では、機能のコードファイルを `google.py` に配置しましたが、一時的に実装せず、まず `google_search` のコードを作成します。 - -#### 3. ツールyamlファイルの記入 - -1つのツールプラグインには複数のツール機能を含めることができ、各ツール機能には、ツール機能の基本情報、パラメータ、出力などを含む `yaml` ファイルで記述する必要があります。 - -引き続き `GoogleSearch` ツールを例に、`/tools` フォルダ内に新しい `google_search.yaml` ファイルを作成します。 - -```yaml -identity: - name: google_search - author: Dify - label: - en_US: GoogleSearch - zh_Hans: Google検索 - pt_BR: GoogleSearch -description: - human: - en_US: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. - zh_Hans: Google SERP検索を実行し、スニペットとウェブページを抽出するためのツールです。入力は検索クエリである必要があります。 - pt_BR: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. - llm: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. -parameters: - - name: query - type: string - required: true - label: - en_US: Query string - zh_Hans: クエリ文 - pt_BR: Query string - human_description: - en_US: used for searching - zh_Hans: ウェブコンテンツの検索に使用 - pt_BR: used for searching - llm_description: key words for searching - form: llm -extra: - python: - source: tools/google_search.py -``` - -- `identity` には、ツールの基本情報(名前、作成者、ラベル、説明など)が含まれます。 -- `parameters` パラメータリスト - - `name` (必須)パラメータ名、一意であり、他のパラメータと重複することはできません。 - - `type` (必須)パラメータタイプ。現在、`string`(文字列)、`number`(数値)、`boolean`(ブール値)、`select`(ドロップダウンリスト)、`secret-input`(暗号化入力フィールド)の5種類をサポートしています。機密情報には`secret-input`タイプを使用してください。 - - `label`(必須)パラメータラベル、フロントエンド表示用。 - - `form` (必須)フォームタイプ。現在、`llm`、`form`の2種類をサポートしています。 - - Agentアプリケーションでは、`llm` はLLMが自身で推論するパラメータを示し、`form` はこのツールを使用するために事前に設定できるパラメータを示します。 - - Workflowアプリケーションでは、`llm` と `form` の両方をフロントエンドで入力する必要がありますが、`llm` のパラメータはツールノードの入力変数として機能します。 - - `required` 必須かどうか - - `llm` モードでは、パラメータが必須の場合、Agentはこのパラメータを推論する必要があります。 - - `form` モードでは、パラメータが必須の場合、ユーザーは対話開始前にフロントエンドでこのパラメータを入力する必要があります。 - - `options` パラメータオプション - - `llm` モードでは、DifyはすべてのオプションをLLMに渡し、LLMはこれらのオプションに基づいて推論できます。 - - `form` モードで `type` が `select` の場合、フロントエンドはこれらのオプションを表示します。 - - `default` デフォルト値。 - - `min` 最小値、パラメータタイプが `number` の場合に設定できます。 - - `max` 最大値、パラメータタイプが `number` の場合に設定できます。 - - `human_description` フロントエンド表示用の説明、多言語対応。 - - `placeholder` フィールド入力ボックスのヒントテキスト。フォームタイプが`form`で、パラメータタイプが`string`、`number`、`secret-input`の場合に設定でき、多言語対応です。 - - `llm_description` LLMに渡す説明。LLMがこのパラメータをよりよく理解できるように、ここにこのパラメータに関するできるだけ詳細な情報を記述してください。 - -#### 4. ツールコードの準備 - -ツールの設定情報を入力した後、ツールの機能コードの作成を開始し、ツールの論理的な目的を実現できます。`/tools`ディレクトリに`google_search.py`を作成し、内容は以下の通りです。 - -```python -from collections.abc import Generator -from typing import Any - -import requests - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -SERP_API_URL = "https://serpapi.com/search" - -class GoogleSearchTool(Tool): - def _parse_response(self, response: dict) -> dict: - result = {} - if "knowledge_graph" in response: - result["title"] = response["knowledge_graph"].get("title", "") - result["description"] = response["knowledge_graph"].get("description", "") - if "organic_results" in response: - result["organic_results"] = [ - { - "title": item.get("title", ""), - "link": item.get("link", ""), - "snippet": item.get("snippet", ""), - } - for item in response["organic_results"] - ] - return result - - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: - params = { - "api_key": self.runtime.credentials["serpapi_api_key"], - "q": tool_parameters["query"], - "engine": "google", - "google_domain": "google.com", - "gl": "us", - "hl": "en", - } - - response = requests.get(url=SERP_API_URL, params=params, timeout=5) - response.raise_for_status() - valuable_res = self._parse_response(response.json()) - - yield self.create_json_message(valuable_res) -``` - -この例の意味は、`serpapi` にリクエストを送信し、`self.create_json_message` を使用して `json` 形式のフォーマット済みデータを返すことです。返されるデータ型の詳細については、[プラグインのリモートデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin)および[永続ストレージKV](/plugin-dev-ja/0411-persistent-storage-kv)のドキュメントを参照してください。 - -#### 4. ツールプロバイダーコードの完成 - -最後に、認証情報検証ロジックを実装するためのプロバイダーの実装コードを作成する必要があります。認証情報検証が失敗した場合、`ToolProviderCredentialValidationError`例外がスローされます。検証が成功すると、`google_search`ツールサービスに正しくリクエストが送信されます。 - -`/provider` ディレクトリに `google.py` ファイルを作成し、コードの内容は以下の通りです。 - -```python -from typing import Any - -from dify_plugin import ToolProvider -from dify_plugin.errors.tool import ToolProviderCredentialValidationError -from tools.google_search import GoogleSearchTool - -class GoogleProvider(ToolProvider): - def _validate_credentials(self, credentials: dict[str, Any]) -> None: - try: - for _ in GoogleSearchTool.from_credentials(credentials).invoke( - tool_parameters={"query": "test", "result_type": "link"}, - ): - pass - except Exception as e: - raise ToolProviderCredentialValidationError(str(e)) -``` - -### プラグインのデバッグ - -プラグインの開発が完了したら、次にプラグインが正常に動作するかをテストする必要があります。Difyは便利なリモートデバッグ方法を提供し、テスト環境でプラグイン機能を迅速に検証するのに役立ちます。 - -[「プラグイン管理」](https://cloud.dify.ai/plugins)ページに移動して、リモートサーバーアドレスとデバッグキーを取得します。 - -![Remote Debug Key](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) - -プラグインプロジェクトに戻り、`.env.example` ファイルをコピーして `.env` にリネームし、取得したリモートサーバーアドレスとデバッグキーなどの情報を入力します。 - -`.env` ファイル: - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -`python -m main` コマンドを実行してプラグインを起動します。プラグインページで、このプラグインがWorkspaceにインストールされていることが確認でき、チームの他のメンバーもこのプラグインにアクセスできます。 - -![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) - -### プラグインのパッケージ化(オプション) - -プラグインが正常に動作することを確認した後、以下のコマンドラインツールを使用してプラグインをパッケージ化し、名前を付けることができます。実行後、現在のフォルダに `google.difypkg` ファイルが見つかります。これは最終的なプラグインパッケージです。 - -```bash -# ./google をプラグインプロジェクトの実際のパスに置き換えてください - -dify plugin package ./google -``` - -おめでとうございます、これでツールタイププラグインの完全な開発、デバッグ、パッケージ化プロセスを完了しました! - -### プラグインの公開(オプション) - -プラグインをDify Marketplaceに公開したい場合は、プラグインが[Difyマーケットプレイスへの公開](/plugin-dev-ja/0322-release-to-dify-marketplace)の仕様に従っていることを確認してください。審査に合格すると、コードはメインブランチにマージされ、自動的に[Dify Marketplace](https://marketplace.dify.ai/)に公開されます。 - -[公開概要](/plugin-dev-ja/0321-release-overview) - -### さらに探る - -#### **クイックスタート:** - -- [Extensionプラグインの開発](/plugin-dev-ja/9231-extension-plugin) -- [Modelプラグインの開発](/plugin-dev-ja/0211-getting-started-new-model) -- [Bundleプラグイン:複数のプラグインをパッケージ化](/plugin-dev-ja/9241-bundle) - -#### **プラグインインターフェースドキュメント:** - -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - Manifest構造とツール仕様 -- [エンドポイント](/plugin-dev-ja/0432-endpoint) - Endpoint詳細定義 -- [リバースコール](/plugin-dev-ja/9241-reverse-invocation) - Dify機能のリバースコール -- [モデルスキーマ](/plugin-dev-ja/0412-model-schema) - モデル -- [Agentプラグイン](/plugin-dev-ja/9232-agent) - Agent戦略の拡張 - -## 次のステップ - -- [プラグインのリモートデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin) - より高度なデバッグテクニックを学ぶ -- [永続ストレージ](/plugin-dev-ja/0411-persistent-storage-kv) - プラグインでデータストレージを使用する方法を学ぶ -- [Slackボットプラグイン開発例](/plugin-dev-ja/0432-develop-a-slack-bot-plugin) - より複雑なプラグイン開発事例を見る -- [ツールプラグイン](/plugin-dev-ja/0411-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/0222-tool-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0312-contributor-covenant-code-of-conduct.mdx b/plugin-dev-ja/0312-contributor-covenant-code-of-conduct.mdx deleted file mode 100644 index 3adba386..00000000 --- a/plugin-dev-ja/0312-contributor-covenant-code-of-conduct.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: setup - level: intermediate -standard_title: Contributor Covenant Code of Conduct -language: ja -title: プラグイン開発者ガイドライン -description: このドキュメントは、Difyプラグイン開発者がプルリクエストを送信する前に従うべきガイドラインを提供します。これには、プラグインが正常に機能すること、ドキュメントが完全であること、独自の価値を提供すること、データプライバシーとセキュリティ規範に準拠することが含まれます。説明ドキュメントの要件、重複プラグインを避けるためのガイドライン、プライバシー情報収集の宣言要件が含まれています。 ---- - -### プルリクエスト(PR)を送信する前に - -1. **プラグインが正常に機能し、ドキュメントが完全であることを確認する** - -* プラグインが正常に機能することを確認してください。詳細は[プラグインのリモートデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin)を参照してください。 -* 包括的な**READMEファイル**を提供してください。内容は以下の通りです: - * 設定手順と使用ガイド。 - * プラグインユーザーがプラグインをサービスに接続するために必要なコード、API、認証情報、またはその他の情報。 -* 収集されたユーザー情報は、サービスの接続とプラグイン機能の改善にのみ使用されることを確認してください。 -* [プラグインのプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines)に従って、プライバシーポリシーの内容ファイルまたはオンラインドキュメントのURLを準備してください。 - -2. **プラグインの貢献価値を確認する** - -* プラグインがDifyユーザーに独自の価値を提供することを確認してください。 -* プラグインは、Difyや他のプラグインがまだ提供していない機能やサービスを導入する必要があります。 -* コミュニティ基準に従ってください: - * コンテンツは非暴力的であり、グローバルなユーザーコミュニティを尊重するものであること。 - * 統合サービスの関連ポリシーに準拠していること。 -* **類似のプラグインが既に存在するかどうかを確認する方法は?** - * 既存のプラグインやPRと機能が重複するものを提出することは避けてください。ただし、新しいプラグインが以下の特徴を備えている場合は除きます: - * 新しい機能を導入する。 - * パフォーマンスの改善を提供する。 - * **プラグインが十分にユニークかどうかを判断する方法:** - * プラグインが既存の機能にわずかな調整(言語パラメータの追加など)を加えるだけの場合は、既存のプラグインを直接拡張することをお勧めします。 - * プラグインが大幅な機能変更(バッチ処理の最適化やエラー処理の改善など)を実現する場合は、新しいプラグインとして提出できます。 - * 不明な場合は、PR提出時に簡単な説明を添付し、なぜ新しいプラグインを提出する必要があるのかを説明してください。 - -**例:** Google検索プラグインを例にとると、単一の入力クエリを受け付け、Google検索APIを使用してGoogle検索結果のリストを出力します。もし、同様の基盤実装を持つ新しいGoogle検索プラグインを提供するが、入力にわずかな調整(例えば、新しい言語パラメータの追加)を加えるだけの場合、既存のプラグインを拡張することをお勧めします。一方、プラグインが最適化されたバッチ検索やエラー処理能力を新しい方法で実装した場合、それは個別のプラグインとして審査される可能性があります。 - -3. **プラグインが以下のプライバシーデータ規範に準拠していることを確認する** - -### 情報開示要件: - -* 開発者は、アプリケーション/ツールを提出する際に、いかなる種類のユーザー個人データを収集するかどうかを**必ず**宣言する必要があります。詳細は[プラグインのプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines)を参照してください。 -* 収集する場合、収集するデータタイプを**簡単にリストアップ**する必要があります(例:ユーザー名、メールアドレス、デバイスID、位置情報など)。**詳細すぎる必要はありません**。 -* 開発者は**必ず**プライバシーポリシーへのリンクを提供する必要があります。プライバシーポリシーには、収集する情報、その情報の使用方法、第三者に開示される情報、および関連する第三者のプライバシーポリシーへのリンクを記載するだけで十分です。 - -**審査のポイント:** - -* **形式審査:** 要件に従ってデータ収集状況が宣言されているかを確認します。 -* **高リスクデータの調査:** 機密データ(例:健康情報、財務情報、子供の個人情報など)を収集しているかどうかに重点を置きます。機密データを収集している場合は、その使用目的とセキュリティ対策について**追加審査**が必要です。 -* **悪意のある行為の調査:** ユーザーの同意なしにデータを収集したり、ユーザーデータを未知のサーバーにアップロードしたりするなどの明らかな悪意のある行為が存在しないかを確認します。 - -## 関連リソース - -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - プラグイン開発の基礎を理解する -- [プラグインのリリース](/plugin-dev-ja/0321-release-overview) - プラグインリリースプロセスの概要 -- [プラグインのプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines) - プライバシーポリシー作成ガイド -- [Dify Marketplaceへのリリース](/plugin-dev-ja/0322-release-to-dify-marketplace) - 公式マーケットプレイスでプラグインをリリースする -- [プラグインのリモートデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin) - プラグインデバッグガイド - -{/* -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/0312-contributor-covenant-code-of-conduct.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0312-privacy-protection-guidelines.mdx b/plugin-dev-ja/0312-privacy-protection-guidelines.mdx deleted file mode 100644 index dd09dfec..00000000 --- a/plugin-dev-ja/0312-privacy-protection-guidelines.mdx +++ /dev/null @@ -1,101 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: setup - level: intermediate -standard_title: Privacy Protection Guidelines -language: ja -title: プラグインのプライバシーポリシーガイドライン -description: このドキュメントでは、開発者がDifyマーケットプレイスにプラグインを提出する際にプライバシーポリシーを作成する方法のガイドラインを説明します。内容には、収集される個人データの種類(直接識別情報、間接識別情報、組み合わせ情報)の確認とリストアップ方法、プラグインのプライバシーポリシーの記入方法、マニフェストファイルでのプライバシーポリシー宣言の導入方法、および関連するよくある質問への回答が含まれます。 ---- - -Difyマーケットプレイスにプラグインを提出申請する際には、ユーザーデータの取り扱い方法を公開する必要があります。以下は、プラグイン関連のプライバシー問題とユーザーデータ処理の記入に関するガイドラインです。まだプラグインを開発していない場合は、[プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-tool)を参照してください。 - -プラグインのプライバシーポリシー宣言の内容は、以下の問題を中心に展開されます: - -**あなたのプラグインはユーザーの個人データを収集・使用しますか?** もしそうであれば、具体的な種類を整理してリストアップしてください。 - -> 個人データとは、特定の個人を識別できるあらゆる情報を指し、単独で、または他の情報と組み合わせて個人を識別、連絡、または特定するために使用できる情報を含みます。 - -#### **1. 収集されるデータの種類をリストアップする** - -**タイプ1:直接識別情報** - -* 氏名(フルネーム、名、姓) -* メールアドレス -* 電話番号 -* 住所 -* 身分証明書番号(IDカード、パスポート、運転免許証など) - -**タイプ2:間接識別情報** - -* デバイス識別子(IMEI、MACアドレス、デバイスID) -* IPアドレス -* 位置情報(GPS座標、都市、地域) -* オンライン識別子(Cookie、広告ID) -* ユーザー名 -* プロフィール画像 -* 生体認証情報(指紋、顔認証) -* 閲覧履歴 -* 購入履歴 -* 健康データ -* 財務情報 - -**タイプ3:個人を識別するために使用される組み合わせ情報** - -* 年齢 -* 性別 -* 職業 -* 趣味・関心事 - -あなたのプラグイン自体が個人情報を収集しない場合でも、プラグインが使用するサードパーティサービスがデータ収集または処理に関与しているかどうかを確認してください。開発者として、サードパーティサービスによるデータ処理を含む、すべてのデータ収集活動を公開する必要があります。サードパーティサービスのプライバシーポリシーを必ず読み、提出時にプラグインに関連するすべてのデータ収集状況を宣言するようにしてください。 - -例えば、開発中のプラグインがSlackサービスに関わる場合、プラグインのプライバシーポリシー宣言ファイルで[Slackのプライバシーポリシー](https://slack.com/trust/privacy/privacy-policy)を参照し、データ収集状況を宣言してください。 - -#### 2. 最新バージョンのプラグインプライバシーポリシーを記入する - -**プラグインのプライバシーポリシー**には、以下を含める必要があります: - -* 収集されるデータの種類 -* データの使用目的 -* 第三者とデータを共有するかどうか(共有する場合、第三者サービスの名称とそのプライバシーポリシーへのリンクを記載) -* プライバシーポリシーの書き方に慣れていない場合は、Dify公式がメンテナンスしているプラグイン内のプライバシーポリシーを参考にすることができます。 - -#### **3. プラグインのマニフェストファイル内でプライバシーポリシー宣言を導入する** - -詳細なフィールドの記入方法については、[マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest)を参照してください。 - -### **よくある質問** - -1. **ユーザー個人データの「収集と使用」とは何ですか?一般的なケースにはどのようなものがありますか?** - -「収集と使用」とは、ユーザーデータの収集、転送、使用、または共有を指します。一般的な状況には以下が含まれます: - -* フォームを通じて個人情報を収集する; -* ログイン機能を使用する(サードパーティ認証を含む); -* 個人情報を含む可能性のある入力またはリソースを収集する; -* ユーザーの行動、インタラクション、および使用状況を分析する; -* メッセージ、チャット履歴、メールなどの通信内容を保存する; -* 関連するソーシャルメディアのユーザープロフィールにアクセスする; -* 運動、心拍数、医療情報などの健康データを収集する; -* 検索履歴または閲覧行動を保存する; -* 銀行情報、信用スコア、取引記録などの財務情報を処理する。 - -## 関連リソース - -- [プラグインの公開](/plugin-dev-ja/0321-release-overview) - プラグインの公開プロセスを理解する -- [Difyマーケットプレイスへの公開](/plugin-dev-ja/0322-release-to-dify-marketplace) - 公式マーケットプレイスへのプラグイン提出方法を学ぶ -- [プラグイン開発者ガイドライン](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct) - プラグイン提出の規範を理解する -- [マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest) - プラグインメタデータの設定 - -{/* -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/0312-privacy-protection-guidelines.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0312-third-party-signature-verification.mdx b/plugin-dev-ja/0312-third-party-signature-verification.mdx deleted file mode 100644 index 4d49f6f3..00000000 --- a/plugin-dev-ja/0312-third-party-signature-verification.mdx +++ /dev/null @@ -1,129 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: setup - level: intermediate -standard_title: Third-Party Signature Verification -language: ja -title: 第三者署名検証のためにプラグインに署名する -description: このドキュメントでは、Difyコミュニティ版でサードパーティ署名検証機能を有効にして使用する方法について説明します。これには、キーペアの生成、プラグインの署名と検証、および環境設定の手順が含まれており、管理者はDifyマーケットプレイスで提供されていないプラグインを安全にインストールできます。 ---- - - - この機能はコミュニティ版でのみ利用できます。クラウドサービスでは、現時点では第三者署名検証はサポートされていません。 - - -第三者署名検証により、Dify の管理者は、Dify Marketplace にリストされていないプラグインのインストールを、署名の検証を完全に無効化することなく、安全に許可できるようになります。これにより、例えば次のようなシナリオがサポートされます。 - -- Dify の管理者は、開発者から送信されたプラグインを承認したら、プラグインに署名を追加して公開できます -- プラグインの開発者は、署名の検証の無効化が許容されない Dify の管理者のために、プラグインに署名を追加し、公開鍵とともに公開できます - -Dify の管理者やプラグインの開発者は、事前に準備した秘密鍵でプラグインに署名を追加できます。また、Dify の管理者は、プラグインのインストール時に、特定の公開鍵による署名の検証を強制するように Dify を構成できます。 - -## 署名の追加と検証に利用する鍵ペアの生成 - -次のコマンドで、プラグインの署名の追加と検証に使用する新しい鍵ペアを生成します: - -```bash -dify signature generate -f your_key_pair -``` - -コマンド実行後、現在のパスに次の 2 つのファイルが生成されます: - -- **秘密鍵**: `your_key_pair.private.pem` -- **公開鍵**: `your_key_pair.public.pem` - -秘密鍵は、プラグインに署名を追加するために使用され、公開鍵はプラグインの署名を検証するために使用されます。 - - - 秘密鍵は充分に秘匿された状態で安全に保管してください。秘密鍵が漏洩すると、攻撃者が任意のプラグインに正規の署名を追加できるようになり、Dify - の安全性が脅かされます。 - - -## プラグインへの署名の追加と確認 - -次のコマンドで、プラグインに署名を追加します。引数で **署名したいプラグインファイル** と **秘密鍵** を指定していることに注意してください: - -```bash -dify signature sign your_plugin_project.difypkg -p your_key_pair.private.pem -``` - -コマンド実行後、元のファイルと同じパスに、ファイル名に `signed` が追加された新しいプラグインファイルが生成されます: `your_plugin_project.signed.difypkg` - -プラグインファイルが正しく署名されていることは、次のコマンドで確認できます。このコマンドでは、引数で **署名済みのプラグインファイル** と **公開鍵** を指定していることに注意してください: - -```bash -dify signature verify your_plugin_project.signed.difypkg -p your_key_pair.public.pem -``` - - - 公開鍵の指定を省略すると、Dify Marketplace - 用の公開鍵での検証が行われます。この場合、Dify Marketplace - からダウンロードしたプラグインファイル以外は、署名の検証に失敗します。 - - -## 第三者署名検証の有効化 - -Dify の管理者は、プラグインのインストール前に、事前に許可した公開鍵よる署名の検証を強制できます。 - -### 公開鍵の配置 - -プラグインの署名に利用した秘密鍵に対応する **公開鍵** を、プラグインデーモンが参照できる場所に配置します。 - -例えば、`docker/volumes/plugin_daemon` の下に `public_keys` ディレクトリを作成し、公開鍵ファイルを配置します。 - -```bash -mkdir docker/volumes/plugin_daemon/public_keys -cp your_key_pair.public.pem docker/volumes/plugin_daemon/public_keys -``` - -### 環境変数の設定 - -コンテナ `plugin_daemon` で、次の環境変数を構成します。 - -- `THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED` - - 第三者署名検証の有効化を行う環境変数です - - `true` に設定すると、第三者署名検証が有効化されます -- `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` - - 第三者署名検証に使用する公開鍵ファイルのパスを指定する環境変数です - - カンマ区切りで複数の公開鍵ファイルを指定できます - -これらを構成するための Docker Compose 用のオーバーライドファイル(`docker-compose.override.yaml`)の例を以下に示します: - -```yaml -services: - plugin_daemon: - environment: - FORCE_VERIFYING_SIGNATURE: true - THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED: true - THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS: /app/storage/public_keys/your_key_pair.public.pem -``` - - - `docker/volumes/plugin_daemon` は、コンテナ `plugin_daemon` の - `/app/storage`にマウントされています。環境変数 - `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` - で指定するパスは、コンテナ内のパスであることに注意してください。 - - -設定を反映させるため、最後に、Dify サービスを再起動します。 - -```bash -cd docker -docker compose down -docker compose up -d -``` - -サービスを再起動すると、現在のコミュニティ版環境でサードパーティ署名の検証機能が有効になります。 - -{/* -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/0312-third-party-signature-verification.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0321-release-overview.mdx b/plugin-dev-ja/0321-release-overview.mdx deleted file mode 100644 index bf84fe56..00000000 --- a/plugin-dev-ja/0321-release-overview.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: beginner -standard_title: Release Overview -language: ja -title: プラグインのリリース -description: このドキュメントでは、Difyプラグインの3つのリリース方法(公式Marketplace、オープンソースのGitHubリポジトリ、ローカルプラグインファイルパッケージ)を紹介します。各リリース方法の特徴、リリースプロセス、適用シナリオについて詳しく説明し、さまざまな開発者のニーズを満たすための具体的なリリースに関する推奨事項を提供します。 ---- - -### リリース方法 - -さまざまな開発者のリリースニーズを満たすために、Difyは以下の3つのプラグインリリース方法を提供しています。リリース前に、プラグインの開発とテストが完了していることを確認し、[プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin)と[プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct)をお読みください。 - -#### **1. Marketplace** - -**概要**:Dify公式が提供するプラグインマーケットで、ユーザーはここでさまざまなプラグインを閲覧、検索し、ワンクリックでインストールできます。 - -**特徴**: - -* プラグインは審査後に公開され、**安全で信頼性があります**。 -* 個人またはチームの **Workspace** に直接インストールできます。 - -**リリースプロセス**: - -* プラグインプロジェクトを **Dify Marketplace** の[コードリポジトリ](https://github.com/langgenius/dify-plugins)に提出します。 -* 公式審査後、プラグインはマーケット内で公開され、他のユーザーがインストールして使用できるようになります。 - -詳細については、以下を参照してください: - -[Dify Marketplaceへのリリース](/plugin-dev-ja/0322-release-to-dify-marketplace) - -#### 2. **GitHub リポジトリ** - -**概要**:プラグインをオープンソース化または **GitHub** 上でホストし、他の人が閲覧、ダウンロード、インストールしやすくします。 - -**特徴**: - -* **バージョン管理**と**オープンソース共有**に便利です。 -* ユーザーはプラグインリンクを通じて直接インストールでき、プラットフォームの審査は不要です。 - -**リリースプロセス**: - -* プラグインコードを GitHub リポジトリにプッシュします。 -* リポジトリリンクを共有し、ユーザーはリンクを通じてプラグインを **Dify Workspace** に統合できます。 - -詳細については、以下を参照してください: - -[個人の GitHub リポジトリへのリリース](/plugin-dev-ja/0322-release-to-individual-github-repo) - -#### 3. プラグインファイルパッケージ(ローカルインストール) - -**概要**:プラグインをローカルファイル(例:`.difypkg` 形式)にパッケージ化し、ファイル共有を通じて他の人がインストールできるようにします。 - -**特徴**: - -* オンラインプラットフォームに依存せず、プラグインを**迅速かつ柔軟に**共有できます。 -* **プライベートプラグイン**または**内部テスト**に適しています。 - -**リリースプロセス**: - -* プラグインプロジェクトをローカルファイルにパッケージ化します。 -* Dify プラグインページで**プラグインをアップロード**をクリックし、ローカルファイルを選択してプラグインをインストールします。 - -プラグインプロジェクトをローカルファイルにパッケージ化して他の人と共有し、プラグインページでファイルをアップロードすると、プラグインを Dify Workspace 内にインストールできます。 - -詳細については、以下を参照してください: - -[ローカルファイルへのパッケージ化と共有](/plugin-dev-ja/0322-release-by-file) - -### **リリースに関する推奨事項** - -* **プラグインを宣伝したい場合** → **Marketplace の使用を推奨します**。公式審査を通じてプラグインの品質を保証し、露出度を高めます。 -* **オープンソース共有プロジェクトの場合** → **GitHub の使用を推奨します**。バージョン管理とコミュニティ連携に便利です。 -* **迅速な配布または内部テストの場合** → **プラグインファイルの使用を推奨します**。簡単かつ効率的にインストールおよび共有できます。 - -## 関連リソース - -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - Difyプラグイン開発の全体像を理解する -- [プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct) - プラグイン提出の規範を理解する -- [プラグインのプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines) - プライバシーポリシー作成要件を理解する -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインマニフェストファイルの設定を理解する - -{/* -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/0321-release-overview.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0322-release-by-file.mdx b/plugin-dev-ja/0322-release-by-file.mdx deleted file mode 100644 index 1cb11374..00000000 --- a/plugin-dev-ja/0322-release-by-file.mdx +++ /dev/null @@ -1,74 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: intermediate -standard_title: Release by File -language: ja -title: ローカルファイルへのパッケージ化と共有 -description: このドキュメントでは、Difyプラグインプロジェクトをローカルファイルにパッケージ化し、他のユーザーと共有するための詳細な手順を説明します。内容には、プラグインのパッケージ化前の準備作業、Difyプラグイン開発ツールを使用したパッケージ化コマンドの実行、生成された.difypkgファイルのインストール方法、およびプラグインファイルを他のユーザーと共有する方法が含まれます。 ---- - -プラグイン開発が完了したら、プラグインプロジェクトをローカルファイルにパッケージ化し、他のユーザーと共有できます。プラグインファイルを使用して、Dify Workspaceにインストールできます。まだプラグインを開発していない場合は、[プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-tool)を参照してください。 - -* **特徴**: - * オンラインプラットフォームに依存せず、**迅速かつ柔軟**にプラグインを共有できます。 - * **プライベートプラグイン**または**内部テスト**に適しています。 -* **リリースフロー**: - * プラグインプロジェクトをローカルファイルにパッケージ化します。 - * Difyプラグインページでファイルをアップロードしてプラグインをインストールします。 - -この記事では、プラグインプロジェクトをローカルファイルにパッケージ化する方法、およびローカルファイルを使用してプラグインをインストールする方法について説明します。 - -### 事前準備 - -* **Difyプラグイン開発ツール**、詳細については[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools)を参照してください。 - -設定が完了したら、ターミナルで `dify version` コマンドを入力し、バージョン番号情報が出力されるか確認して、必要な開発ツールがインストールされていることを確認します。 - -### プラグインのパッケージ化 - -> プラグインをパッケージ化する前に、プラグインの `manifest.yaml` ファイルと `/provider` パス以下の `.yaml` ファイル内の `author` フィールドがGitHub IDと一致していることを確認してください。マニフェストファイルの詳細については、[一般仕様定義](/plugin-dev-ja/0411-general-specifications)を参照してください。 - -プラグインプロジェクトの開発が完了したら、[リモートデバッグテスト](/plugin-dev-ja/0411-remote-debug-a-plugin)が完了していることを確認してください。プラグインプロジェクトの親ディレクトリに移動し、以下のプラグインパッケージ化コマンドを実行します。 - -```bash -dify plugin package ./your_plugin_project -``` - -コマンドを実行すると、現在のパスに `.difypkg` という拡張子で終わるファイルが生成されます。 - -![プラグインファイルの生成](https://assets-docs.dify.ai/2024/12/98e09c04273eace8fe6e5ac976443cca.png) - -### プラグインのインストール - -Difyプラグイン管理ページにアクセスし、右上の**プラグインをインストール** → **ローカルファイル経由**でインストールをクリックするか、プラグインファイルをページの空白部分にドラッグアンドドロップしてプラグインをインストールします。 - -![プラグインファイルのインストール](https://assets-docs.dify.ai/2024/12/8c31c4025a070f23455799f942b91a57.png) - -### プラグインの公開 - -プラグインファイルを他のユーザーと共有したり、インターネットにアップロードして他のユーザーがダウンロードできるようにしたりできます。より広範囲にプラグインを共有したい場合は、次の方法を検討してください。 - -1. [個人のGitHubリポジトリに公開する](/plugin-dev-ja/0322-release-to-individual-github-repo) - GitHub経由でプラグインを共有 -2. [Dify Marketplaceに公開する](/plugin-dev-ja/0322-release-to-dify-marketplace) - 公式マーケットプレイスでプラグインを公開 - -## 関連リソース - -- [プラグインの公開](/plugin-dev-ja/0321-release-overview) - 様々な公開方法について理解する -- [開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools) - プラグイン開発環境を設定する -- [プラグインのリモートデバッグ](/plugin-dev-ja/0411-remote-debug-a-plugin) - プラグインのデバッグ方法を学ぶ -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインのメタデータを定義する -- [プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-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/0322-release-by-file.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0322-release-to-dify-marketplace.mdx b/plugin-dev-ja/0322-release-to-dify-marketplace.mdx deleted file mode 100644 index de146ec9..00000000 --- a/plugin-dev-ja/0322-release-to-dify-marketplace.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: intermediate -standard_title: Release to Dify Marketplace -language: ja -title: Dify Marketplaceへの公開 -description: このガイドでは、Dify Marketplaceにプラグインを公開する完全なプロセスを詳細に説明します。PRの提出、審査プロセス、公開後のメンテナンスなど、主要なステップと注意事項を含みます。 ---- - -Dify Marketplaceは、パートナーやコミュニティ開発者からのプラグインの登録申請を歓迎します。あなたの貢献は、Difyプラグインの可能性をさらに豊かにします。このガイドでは、明確な公開プロセスとベストプラクティスの推奨事項を提供し、あなたのプラグインがスムーズに公開され、コミュニティに価値をもたらすことを目指します。まだプラグインを開発していない場合は、[プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-tool)を参照してください。 - -以下の手順に従って、[GitHubコードリポジトリ](https://github.com/langgenius/dify-plugins)でプラグインのPull Request(PR)を提出し、審査を受けてください。承認されると、プラグインは正式にDify Marketplaceに公開されます。 - -### プラグインの公開プロセス - -Dify Marketplaceへのプラグイン公開には、以下のステップが含まれます: - -1. [プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct)に従ってプラグインの開発とテストを完了します。 -2. [プラグインプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines)に従ってプラグインのプライバシーポリシーを作成し、そのプライバシーポリシーのファイルパスまたはURLをプラグインの[一般仕様定義](/plugin-dev-ja/0411-general-specifications)に記述します。 -3. プラグインのパッケージングを完了します。 -4. [Dify Plugins](https://github.com/langgenius/dify-plugins)コードリポジトリをフォークします。 -5. リポジトリ内に個人または組織のフォルダを作成し、パッケージ化された`.difypkg`ファイルをそのフォルダにアップロードします。 -6. GitHubのPRテンプレートのコンテンツ形式に従ってPull Request(PR)を提出し、審査を待ちます。 -7. 審査に合格すると、プラグインコードはMainブランチにマージされ、プラグインは自動的に[Dify Marketplace](https://marketplace.dify.ai/)に登録されます。 - -プラグインの提出、審査、登録のフロー図: - -![The process of uploading plugins](https://assets-docs.dify.ai/2025/01/05df333acfaf662e99316432db23ba9f.png) - -> **注**: 上図のContributor Agreementは[プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct)を指します。 - -*** - -### Pull Request(PR)審査期間中 - -審査担当者からの質問やフィードバックに積極的に対応してください: - -* **14日以内**に解決されないPRコメントは古いものとしてマークされます(再開可能)。 -* **30日以内**に解決されないPRコメントはクローズされます(再開不可、新しいPRを作成する必要があります)。 - -*** - -### **Pull Request(PR)審査承認後** - -**1. 継続的なメンテナンス** - -* ユーザーから報告された問題や機能リクエストに対応します。 -* 重大なAPI変更が発生した場合のプラグイン移行: - * Difyは事前に変更通知と移行手順を公開します。 - * Difyのエンジニアが移行サポートを提供できます。 - -**2. Marketplace公開ベータテスト段階での制限** - -* 既存のプラグインに破壊的な変更を導入することを避けてください。 - -*** - -### 審査プロセス - -**1. 審査順序** - -* PRは**先着順**で処理されます。審査は1週間以内に開始されます。遅延がある場合、審査担当者はコメントを通じてPR作成者に通知します。 - -**2. 審査の重点** - -* プラグイン名、説明、設定手順が明確で指導的であるかを確認します。 -* プラグインの[一般仕様定義](/plugin-dev-ja/0411-general-specifications)が形式仕様に準拠しており、有効な作成者の連絡先情報が含まれているかを確認します。 - -3. **プラグインの機能性と関連性** - -* [プラグイン開発ガイド](/plugin-dev-ja/0111-getting-started-dify-plugin)に従ってプラグインをテストします。 -* Difyエコシステムにおけるプラグインの用途が合理的であることを確認します。 - -[Dify.AI](https://dify.ai/)は、プラグイン提出の承認または拒否の権利を留保します。 - -*** - -### よくある質問 - -1. **プラグインがユニークであるかどうかをどのように判断しますか?** - -例:Google検索プラグインが多言語バージョンを追加しただけの場合、既存プラグインの最適化と見なされるべきです。しかし、プラグインが顕著な機能改善(バッチ処理の最適化やエラー処理など)を実現している場合は、新しいプラグインとして提出できます。 - -2. **私のPRが古いものとしてマークされたり、クローズされた場合はどうすればよいですか?** - -古いものとしてマークされたPRは、フィードバックを解決した後に再開できます。クローズされたPR(30日以上経過)は、新しいPRを再作成する必要があります。 - -3. **ベータテスト段階でプラグインを更新できますか?** - -はい、ただし破壊的な変更を導入することは避けるべきです。 - -## 関連リソース - -- [プラグインの公開](/plugin-dev-ja/0321-release-overview) - さまざまな公開方法を理解する -- [プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct) - プラグイン提出規範 -- [プラグインプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines) - プライバシーポリシー作成要件 -- [ローカルファイルとしてのパッケージ化と共有](/plugin-dev-ja/0322-release-by-file) - プラグインのパッケージ化方法 -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインメタデータ定義 - -{/* -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/0322-release-to-dify-marketplace.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0322-release-to-individual-github-repo.mdx b/plugin-dev-ja/0322-release-to-individual-github-repo.mdx deleted file mode 100644 index 1cf2d295..00000000 --- a/plugin-dev-ja/0322-release-to-individual-github-repo.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: intermediate -standard_title: Release to Individual GitHub Repo -language: ja -title: 個人のGitHubリポジトリへの公開 -description: このドキュメントでは、Difyプラグインを個人のGitHubリポジトリに公開する方法について詳しく説明します。準備作業、ローカルプラグインリポジトリの初期化、リモートリポジトリへの接続、プラグインファイルのアップロード、プラグインコードのパッケージング、GitHub経由でのプラグインインストール方法の全プロセスが含まれます。この方法により、開発者は自身のプラグインコードと更新を完全に管理できます。 ---- - -GitHubリポジトリのリンクからプラグインをインストールできます。プラグインの開発が完了したら、他の人がダウンロードして使用できるように、公開GitHubリポジトリにプラグインを公開することを選択できます。まだプラグインを開発していない場合は、[プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-tool)を参照してください。 - -この方法には、以下の利点があります。 - -• **個人管理**:プラグインのコードと更新を完全に制御できます -• **迅速な共有**:GitHubリンクを通じて他のユーザーやチームメンバーに簡単に共有でき、テストと使用に便利です -• **協力とフィードバック**:プラグインをオープンソースにすると、GitHub上の潜在的な協力者を引き付け、プラグインの迅速な改善に役立つ可能性があります - -この記事では、プラグインをGitHubリポジトリに公開する方法を説明します。 - -### 準備作業 - -まず、プラグインを開発しテスト済みであること、および[プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin)と[プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct)を読んだことを確認してください。プラグインを公開する前に、ローカルに以下のツールがインストールされていることを確認してください: - -* GitHubアカウント -* 新しい公開GitHubリポジトリを作成する -* ローカルにGitツールがインストール済みであること - -GitHubの基本知識については、[GitHubドキュメント](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository)を参照してください。 - -### 1. プラグインプロジェクトの完成 - -公開GitHubにアップロードするということは、プラグインを公開することを意味します。プラグインのデバッグと検証が完了し、プラグインの `README.md` ファイルの説明が完成していることを確認してください。 - -説明ファイルには、以下の内容を含めることをお勧めします: - -* プラグインの概要と機能説明 -* インストールと設定の手順 -* 使用例 -* 連絡先または貢献ガイドライン - -### 2. ローカルプラグインリポジトリの初期化 - -プラグインをGitHubに公開アップロードする前に、プラグインのデバッグと検証作業が完了していることを確認してください。詳細は[リモートデバッグプラグイン](/plugin-dev-ja/0411-remote-debug-a-plugin)を参照してください。ターミナルでプラグインプロジェクトフォルダに移動し、以下のコマンドを実行します: - -```bash -git init -git add . -git commit -m "Initial commit: Add plugin files" -``` - -初めてGitを使用する場合、Gitのユーザー名とメールアドレスを設定する必要があるかもしれません: - -```bash -git config --global user.name "Your Name" -git config --global user.email "your.email@example.com" -``` - -### 3. リモートリポジトリへの接続 - -以下のコマンドを使用して、ローカルリポジトリをGitHubリポジトリに接続します: - -```bash -git remote add origin https://github.com//.git -``` - -### 4. プラグインファイルのアップロード - -> プラグインをパッケージ化する前に、プラグインの`manifest.yaml`ファイルと`/provider`パス以下の`.yaml`ファイル内のauthorフィールドがGitHub IDと一致していることを確認してください。マニフェストファイルの详细な仕様については、[マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest)を参照してください。 - -プラグインプロジェクトをGitHubリポジトリにプッシュします: - -```bash -git branch -M main -git push -u origin main -``` - -コードをアップロードする際には、後でコードをパッケージ化するためにタグを付けることをお勧めします。 - -```bash -git tag -a v0.0.1 -m "Release version 0.0.1" - -git push origin v0.0.1 -``` - -### 5. プラグインコードのパッケージング - -GitHubコードリポジトリのReleasesページに移動し、新しいバージョンリリースを作成します。バージョンをリリースする際には、プラグインファイルをアップロードする必要があります。プラグインファイルのパッケージング方法については、[ローカルファイルとしてパッケージ化して共有](/plugin-dev-ja/0322-release-by-file)で詳しく説明しています。 - -![プラグインのパッケージング](https://assets-docs.dify.ai/2024/12/5cb4696348cc6903e380287fce8f529d.png) - -### GitHub経由でのプラグインインストール - -他の人はGitHubリポジトリのアドレスを通じてこのプラグインをインストールできます。Difyプラットフォームのプラグイン管理ページにアクセスし、「GitHub経由でプラグインをインストール」を選択し、リポジトリのアドレスを入力後、バージョン番号とパッケージファイルを選択してインストールを完了します。 - -![](https://assets-docs.dify.ai/2024/12/3c2612349c67e6898a1f33a7cc320468.png) - -## 関連リソース - -- [プラグインの公開](/plugin-dev-ja/0321-release-overview) - さまざまな公開方法を理解する -- [ローカルファイルとしてパッケージ化して共有](/plugin-dev-ja/0322-release-by-file) - プラグインのパッケージング方法 -- [マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest) - プラグインのメタデータを定義する -- [プラグイン開発者行動規範](/plugin-dev-ja/0312-contributor-covenant-code-of-conduct) - プラグイン開発の規範を理解する -- [リモートデバッグプラグイン](/plugin-dev-ja/0411-remote-debug-a-plugin) - プラグインのデバッグ方法を学ぶ - -{/* -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/0322-release-to-individual-github-repo.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0331-faq.mdx b/plugin-dev-ja/0331-faq.mdx deleted file mode 100644 index dc415700..00000000 --- a/plugin-dev-ja/0331-faq.mdx +++ /dev/null @@ -1,46 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: maintenance - level: beginner -standard_title: Faq -language: ja -title: よくある質問 -description: Author Allen このドキュメントでは、Difyプラグインの開発とインストールプロセスにおける一般的な質問に答えます。これには、プラグインのアップロード失敗の解決策(authorフィールドの変更)や、プラグインインストール中の検証例外の対処法(FORCE_VERIFYING_SIGNATURE環境変数の設定)が含まれます。 ---- - -## プラグインインストール時にアップロード失敗と表示された場合の対処法は? - -**エラー詳細**:`PluginDaemonBadRequestError: plugin_unique_identifier is not valid` というエラーが表示されます。 - -**解決策**:プラグインプロジェクト下の `manifest.yaml` ファイルおよび `/provider` パス下の `.yaml` ファイル内の `author` フィールドを GitHub ID に変更します。 - -プラグインのパッケージングコマンドを再実行し、新しいプラグインパッケージをインストールします。 - -## プラグインインストール時に例外が発生した場合の対処法は? - -**問題の説明**:プラグインインストール時に例外メッセージ:`plugin verification has been enabled, and the plugin you want to install has a bad signature` が表示された場合、どうすればよいですか? - -**解決策**:`/docker/.env` 設定ファイルの末尾に `FORCE_VERIFYING_SIGNATURE=false` フィールドを追加し、以下のコマンドを実行してDifyサービスを再起動します: - -```bash -cd docker -docker compose down -docker compose up -d -``` - -このフィールドを追加すると、DifyプラットフォームはDify Marketplaceに未登録(未審査)のすべてのプラグインのインストールを許可するようになり、セキュリティ上のリスクが生じる可能性があります。 - -テスト環境またはサンドボックス環境でプラグインをインストールし、安全性を確認してから本番環境にインストールすることをお勧めします。 - -{/* -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/0331-faq.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-doc-contribution-guide.mdx b/plugin-dev-ja/0411-doc-contribution-guide.mdx deleted file mode 100644 index 43df9957..00000000 --- a/plugin-dev-ja/0411-doc-contribution-guide.mdx +++ /dev/null @@ -1,123 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: 'Doc Contribution Guide' -language: ja -title: '貢献ガイド' -summary: 'Dify開発者ドキュメントへの貢献方法を学び、既存ドキュメントの更新や新規ドキュメントの作成ステップとガイドラインを理解し、高品質なドキュメントリソースを共同で構築しましょう。' ---- - -Difyドキュメントの共同構築へようこそ!このガイドでは、Dify開発者ドキュメントへの貢献プロセスと仕様を説明し、コミュニティメンバーがドキュメントの品質を共同で向上させることを奨励・支援します。 - -## 既存ドキュメントの更新 - - - - 修正したいドキュメントページの下部にある **このページを編集する** ボタンをクリックしてください。これにより、GitHubの対応するソースファイルに直接リンクします。 - - - - DifyドキュメントのURLは、GitHubリポジトリ内の相対パスと明確に対応しています。構造に慣れた貢献者は以下を参考にできます: - - | URL (例) | GitHubリポジトリの相対パス (例) | - | :--- | :--- | - | `https://docs.dify.ai/plugin-dev-ja/0111-getting-started-dify-plugin` | `plugin-dev-ja/0111-getting-started-dify-plugin.mdx` | - - - ---- - - - 編集する際は、コンテンツの正確性と明確さに焦点を当ててください。ファイルの先頭にあるFrontmatterメタデータや、末尾の特定のスクリプトや含まれるコンテンツは、通常、コア貢献者または自動化プロセスによって管理・維持されています。 - - - - ドキュメントに問題を見つけた場合は、ページにある **問題を報告する** ボタンを使用して報告することもできます。正確な問題報告は、コミュニティとプロジェクトの両方にとって重要な貢献です。 - - -## 新規ドキュメントの作成 - - - - 適切な言語ディレクトリ(例:`plugin-dev-ja`)に新しい`.mdx`ファイルを作成します。 - - 最初はファイル名を自由に決めることができます(例:`my-new-feature.mdx`)が、ファイル名は十分に説明的である必要があります。システムは後で、ドキュメントのメタデータに基づいて標準化されたファイル名を生成します。 - - - - - 標準の **Markdown** 構文に従ってください。MDXファイルでは、HTML形式の `` ではなく、JSX形式のコメント:`{/* これはMDXコメントです */}` を使用してください。 - - - - Mintlifyが提供するコンポーネントを適切に使用して、コンテンツの構造と表示を最適化できます: - - ```jsx - - これは重要な注意事項です。 - - - - これは警告メッセージです。 - - - - 詳細については、関連リソースを参照してください... - - ``` - - その他のコンポーネントについては、[Mintlifyコンポーネントドキュメント](https://mintlify.com/docs)を参照してください。 - - - - - 各ドキュメントにはFrontmatterメタデータを定義する必要があります: - - * 正しく設定されたFrontmatterは、ドキュメントが正確にインデックス化され、適切に並べ替えられ、ドキュメントウェブサイト上で正しく表示・ナビゲートされるようにするための鍵です。 - * **あなたの主な任務は、高品質で正確なドキュメントコンテンツを提供することです。** - * Difyの[ドキュメントFrontmatterメタデータガイド](/plugin-dev-ja/0412-doc-writing-dimensions-guide)に精通している場合は、提出時にFrontmatterを含めることを歓迎します。 - * **Frontmatterの記入方法がわからない場合や、コンテンツ作成に集中したい場合でも問題ありません。** Frontmatterなし、または部分的なメタデータのみでPull Requestを提出できます。コミュニティやプロジェクトのコア貢献者が、その後の追加、レビュー、最適化を支援します。 - - - - - **あなたのコンテンツ貢献は非常に重要です。** 完全なFrontmatterを提供できなくても、あなたのPull Requestは歓迎されます。ドキュメントが最終的に標準化されたメタデータを持ち、正常に統合されるようにすることは、コミュニティとコアチームの協力的な取り組みです。 - - -## 貢献の提出 - -ドキュメントの編集や新規作成が完了したら、GitHubを通じてメインリポジトリにPull Requestを送信してください。コミュニティメンバーとプロジェクトのメンテナーがあなたの貢献をレビューします。 - -## よくある質問 - - - - もちろんです!ドキュメントへの貢献にプログラミングスキルは必要ありません。Difyについて理解があれば、既存ドキュメントの明確さと正確さを向上させたり、よりユーザーフレンドリーな説明や例を追加したりすることができます。 - - - - コンテンツが明確で正確であり、フォーマットガイドラインに従っていることを確認してください。提出前にスペルと文法をチェックしてください。不確かな場合は、提出前にコミュニティでアイデアを議論することができます。 - - - - はい!多言語ドキュメントの貢献を歓迎します。ファイルが対応する言語ディレクトリに配置され、Frontmatterで言語コードが正しくラベル付けされていることを確認してください。 - - - ---- - -Difyコミュニティとドキュメントへの貢献に感謝します! - -{/* -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/0411-doc-contribution-guide.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-general-specifications.mdx b/plugin-dev-ja/0411-general-specifications.mdx deleted file mode 100644 index 0a6c63fe..00000000 --- a/plugin-dev-ja/0411-general-specifications.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: General Specifications -language: ja -title: 一般的な仕様定義 -description: このドキュメントでは、Difyプラグイン開発における一般的な構造と仕様、パスの仕様、国際化オブジェクト(I18nObject)、プロバイダー設定フォーム構造(ProviderConfig)、モデル設定(ModelConfig)、ノードレスポンス(NodeResponse)、ツールセレクター(ToolSelector)などの重要なデータ構造の定義と用途について詳しく説明します。 ---- - -本稿では、プラグイン開発で一般的に使用される構造について簡単に説明します。開発プロセス中は、全体のアーキテクチャをよりよく理解するために、[プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin)および[開発者向けチートシート](/plugin-dev-ja/0131-cheatsheet)と合わせてお読みになることを強くお勧めします。 - -### パスの仕様 - -Manifestファイルまたは任意のYAMLファイルにファイルパスを記入する際、ファイルの種類に応じて以下の2つの仕様に従ってください: - -* 対象ファイルが画像や動画などのマルチメディアファイルである場合(例:プラグインの `icon` を記入する場合)、これらのファイルをプラグインのルートディレクトリにある `_assets` フォルダに配置する必要があります。 -* 対象ファイルが `.py` や `.yaml` などの通常のテキストファイル(コードファイル)である場合、プラグインプロジェクト内でのそのファイルの絶対パスを記入する必要があります。 - -### 一般的な構造 - -プラグインを定義する際、ツール、モデル、Endpoint間で共有できるいくつかのデータ構造があります。ここでは、これらの共通構造を定義します。 - -#### I18nObject - -`I18nObject`は、[IETF BCP 47](https://tools.ietf.org/html/bcp47)標準に準拠した国際化構造であり、現在サポートされている4つの言語は次のとおりです。 - -* en_US -* zh_Hans -* ja_Jp -* pt_BR - -#### ProviderConfig - -`ProviderConfig`は、`Tool`および`Endpoint`に適用可能な汎用的なプロバイダー設定フォーム構造です。 - -* `name`(string):フォーム項目の名前 -* `label`([I18nObject](#i18nobject), 必須):[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 -* `type`([provider_config_type](#providerconfigtype-string), 必須):フォームタイプ -* `scope`([provider_config_scope](#providerconfigscope-string)):オプションの範囲、`type`によって変動 -* `required`(bool):必須(空にできません) -* `default`(any):デフォルト値、基本型 `float` `int` `string` のみをサポート -* `options`(list\[[provider_config_option](#providerconfigoption-object)]):オプション項目、typeが `select` の場合のみ使用 -* `helper`(object):ヘルプドキュメントリンクのラベル、[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 -* `url` (string):ヘルプドキュメントリンク -* `placeholder`(object):[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 - -#### ProviderConfigOption(object) - -* `value`(string, 必須):値 -* `label`(object, 必須):[IETF BCP 47](https://tools.ietf.org/html/bcp47)に準拠 - -#### ProviderConfigType(string) - -* `secret-input` (string):設定情報は暗号化されます -* `text-input`(string):通常のテキスト -* `select`(string):ドロップダウンリスト -* `boolean`(bool):スイッチ -* `model-selector`(object):モデル設定情報、プロバイダー名、モデル名、モデルパラメータなどを含む -* `app-selector`(object):アプリID -* `tool-selector`(object):ツール設定情報、ツールプロバイダー、名前、パラメータなどを含む -* `dataset-selector`(string):未定 - -#### ProviderConfigScope(string) - -* `type`が `model-selector` の場合 - * `all` - * `llm` - * `text-embedding` - * `rerank` - * `tts` - * `speech2text` - * `moderation` - * `vision` -* `type`が `app-selector` の場合 - * `all` - * `chat` - * `workflow` - * `completion` -* `type`が `tool-selector` の場合 - * `all` - * `plugin` - * `api` - * `workflow` - -#### ModelConfig - -* `provider` (string): `plugin_id`を含むモデルプロバイダー名。形式は`langgenius/openai/openai`のようになります。 -* `model` (string): 具体的なモデル名。 -* `model_type` (enum): モデルタイプの列挙型。[モデル設計規則](/plugin-dev-ja/0411-model-designing-rules#modeltype.ja)ドキュメントを参照できます。 - -#### NodeResponse - -* `inputs` (dict): 最終的にノードに入力される変数。 -* `outputs` (dict): ノードの出力結果。 -* `process_data` (dict): ノード実行中に生成されるデータ。 - -#### ToolSelector - -* `provider_id` (string): ツールプロバイダー名 -* `tool_name` (string): ツール名 -* `tool_description` (string): ツールの説明 -* `tool_configuration` (dict\[str, Any]): ツールの設定情報 -* `tool_parameters` (dict\[str, dict]): LLMによる推論が必要なパラメータ - * `name` (string): パラメータ名 - * `type` (string): パラメータタイプ - * `required` (bool): 必須かどうか - * `description` (string): パラメータの説明 - * `default` (any): デフォルト - * `options`(list\[string]): オプション項目 - -## 関連リソース - -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - Difyプラグイン開発の全体像を理解する -- [開発者向けチートシート](/plugin-dev-ja/0131-cheatsheet) - プラグイン開発でよく使われるコマンドと概念のクイックリファレンス - -- [ツールプラグイン開発詳細](/plugin-dev-ja/0222-tool-plugin) - ツールプラグイン開発プロセスの詳細を理解する -- [モデル設計規則](/plugin-dev-ja/0411-model-designing-rules) - モデル設定の仕様を理解する - -{/* -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/0411-general-specifications.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-model-designing-rules.mdx b/plugin-dev-ja/0411-model-designing-rules.mdx deleted file mode 100644 index 904d961d..00000000 --- a/plugin-dev-ja/0411-model-designing-rules.mdx +++ /dev/null @@ -1,225 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Model Designing Rules -language: ja -title: モデル設計ルール -description: 本書では、Difyモデルプラグイン開発のコアコンセプトと構造を詳細に定義します。これには、モデルプロバイダー(Provider)、AIモデルエンティティ(AIModelEntity)、モデルタイプ(ModelType)、設定方法(ConfigurateMethod)、モデル特性(ModelFeature)、パラメータルール(ParameterRule)、価格設定(PriceConfig)、およびさまざまな認証情報スキーマの詳細なデータ構造仕様が含まれます。 ---- - -* モデルプロバイダールールは [Provider](#provider) エンティティに基づきます。 -* モデルルールは [AIModelEntity](#aimodelentity) エンティティに基づきます。 - -> 以下のすべてのエンティティは `Pydantic BaseModel` に基づいており、`entities` モジュールに対応するエンティティがあります。 - -### Provider - -* `provider` (string) プロバイダー識別子、例:`openai` -* `label` (object) プロバイダー表示名、i18n、`en_US` 英語、`zh_Hans` 中国語の2言語設定可能 - * `zh_Hans` (string) \[optional] 中国語ラベル名、`zh_Hans` を設定しない場合はデフォルトで `en_US` が使用されます。 - * `en_US` (string) 英語ラベル名 -* `description` (object) \[optional] プロバイダー説明、i18n - * `zh_Hans` (string) \[optional] 中国語説明 - * `en_US` (string) 英語説明 -* `icon_small` (string) \[optional] プロバイダー小アイコン、対応するプロバイダー実装ディレクトリ下の `_assets` ディレクトリに保存、中英ポリシーは `label` と同様 - * `zh_Hans` (string) \[optional] 中国語アイコン - * `en_US` (string) 英語アイコン -* `icon_large` (string) \[optional] プロバイダー大アイコン、対応するプロバイダー実装ディレクトリ下の `_assets` ディレクトリに保存、中英ポリシーは `label` と同様 - * `zh_Hans` (string) \[optional] 中国語アイコン - * `en_US` (string) 英語アイコン -* `background` (string) \[optional] 背景色カラーコード、例:#FFFFFF、空の場合はフロントエンドのデフォルトカラー値が表示されます。 -* `help` (object) \[optional] ヘルプ情報 - * `title` (object) ヘルプタイトル、i18n - * `zh_Hans` (string) \[optional] 中国語タイトル - * `en_US` (string) 英語タイトル - * `url` (object) ヘルプリンク、i18n - * `zh_Hans` (string) \[optional] 中国語リンク - * `en_US` (string) 英語リンク -* `supported_model_types` (array\[[ModelType](#modeltype)]) サポートされるモデルタイプ -* `configurate_methods` (array\[[ConfigurateMethod](#configuratemethod)]) 設定方法 -* `provider_credential_schema` (\[[ProviderCredentialSchema](#providercredentialschema)]) プロバイダー認証情報スキーマ -* `model_credential_schema` (\[[ModelCredentialSchema](#modelcredentialschema)]) モデル認証情報スキーマ - -### AIModelEntity - -* `model` (string) モデル識別子、例:`gpt-3.5-turbo` -* `label` (object) \[optional] モデル表示名、i18n、`en_US` 英語、`zh_Hans` 中国語の2言語設定可能 - * `zh_Hans` (string) \[optional] 中国語ラベル名 - * `en_US` (string) 英語ラベル名 -* `model_type` ([ModelType](#modeltype)) モデルタイプ -* `features` (array\[[ModelFeature](#modelfeature)]) \[optional] サポート機能リスト -* `model_properties` (object) モデルプロパティ - * `mode` ([LLMMode](#llmmode)) モード (モデルタイプ `llm` で利用可能) - * `context_size` (int) コンテキストサイズ (モデルタイプ `llm` `text-embedding` で利用可能) - * `max_chunks` (int) 最大チャンク数 (モデルタイプ `text-embedding moderation` で利用可能) - * `file_upload_limit` (int) ファイル最大アップロード制限、単位:MB。(モデルタイプ `speech2text` で利用可能) - * `supported_file_extensions` (string) サポートされるファイル拡張子、例:mp3,mp4(モデルタイプ `speech2text` で利用可能) - * `default_voice` (string) デフォルトボイス、必須:alloy,echo,fable,onyx,nova,shimmer(モデルタイプ `tts` で利用可能) - * `voices` (list) 選択可能なボイスリスト。 - * `mode` (string) ボイスモデル。(モデルタイプ `tts` で利用可能) - * `name` (string) ボイスモデル表示名。(モデルタイプ `tts` で利用可能) - * `language` (string) ボイスモデルがサポートする言語。(モデルタイプ `tts` で利用可能) - * `word_limit` (int) 1回の変換文字数制限、デフォルトは段落ごとに分割(モデルタイプ `tts` で利用可能) - * `audio_type` (string) サポートされる音声ファイル拡張子、例:mp3,wav(モデルタイプ `tts` で利用可能) - * `max_workers` (int) サポートされるテキスト音声変換の同時実行タスク数(モデルタイプ `tts` で利用可能) - * `max_characters_per_chunk` (int) 各チャンクの最大文字数 (モデルタイプ `moderation` で利用可能) -* `parameter_rules` (array\[[ParameterRule](#parameterrule)]) \[optional] モデル呼び出しパラメータールール -* `pricing` (\[[PriceConfig](#priceconfig)]) \[optional] 価格情報 -* `deprecated` (bool) 非推奨かどうか。非推奨の場合、モデルリストには表示されなくなりますが、既に設定されているものは引き続き使用可能です。デフォルトは False。 - -### ModelType - -* `llm` テキスト生成モデル -* `text-embedding` テキスト埋め込みモデル -* `rerank` Rerank モデル -* `speech2text` 音声テキスト変換 -* `tts` テキスト音声合成 -* `moderation` モデレーション - -### ConfigurateMethod - -* `predefined-model` 事前定義モデル - -ユーザーは統一されたプロバイダー認証情報を設定するだけで、プロバイダー下の事前定義モデルを使用できることを示します。 - -* `customizable-model` カスタマイズ可能モデル - -ユーザーは各モデルの認証情報設定を新たに追加する必要があります。 - -* `fetch-from-remote` リモートから取得 - -`predefined-model` の設定方法と同様に、統一されたプロバイダー認証情報を設定するだけで、モデルは認証情報を通じてプロバイダーから取得されます。 - - -### ModelFeature - -* `agent-thought` エージェント思考、通常70Bを超えると思考連鎖能力があります。 -* `vision` ビジョン、すなわち画像理解。 -* `tool-call` ツール呼び出し -* `multi-tool-call` マルチツール呼び出し -* `stream-tool-call` ストリーミングツール呼び出し - -### FetchFrom - -* `predefined-model` 事前定義モデル -* `fetch-from-remote` リモートモデル - -### LLMMode - -* `completion` テキスト補完 -* `chat` 対話 - -### ParameterRule - -* `name` (string) モデル呼び出し時の実際のパラメータ名 -* `use_template` (string) \[optional] テンプレートを使用 - -> テンプレートの具体的な使用方法については、[新しいモデルプロバイダーの作成](/plugin-dev-ja/0222-creating-new-model-provider)の例を参照してください。 - -デフォルトで5種類の変数コンテンツ設定テンプレートがプリセットされています: - -* `temperature` -* `top_p` -* `frequency_penalty` -* `presence_penalty` -* `max_tokens` - -`use_template` に直接テンプレート変数名を設定すると、`entities.defaults.PARAMETER_RULE_TEMPLATE` のデフォルト設定が使用され、`name` と `use_template` 以外のすべてのパラメータを設定する必要はありません。追加の設定パラメータが設定された場合、デフォルト設定が上書きされます。`openai/llm/gpt-3.5-turbo.yaml` を参照してください。 - -* `label` (object) \[optional] ラベル、i18n -* `zh_Hans`(string) \[optional] 中国語ラベル名 -* `en_US` (string) 英語ラベル名 -* `type`(string) \[optional] パラメータタイプ - * `int` 整数 - * `float` 浮動小数点数 - * `string` 文字列 - * `boolean` ブール型 -* `help` (string) \[optional] ヘルプ情報 -* `zh_Hans` (string) \[optional] 中国語ヘルプ情報 -* `en_US` (string) 英語ヘルプ情報 -* `required` (bool) 必須項目かどうか、デフォルトは False。 -* `default`(int/float/string/bool) \[optional] デフォルト値 -* `min`(int/float) \[optional] 最小値、数値タイプのみ適用 -* `max`(int/float) \[optional] 最大値、数値タイプのみ適用 -* `precision`(int) \[optional] 精度、小数点以下の保持桁数、数値タイプのみ適用 -* `options` (array\[string]) \[optional] ドロップダウン選択肢の値、`type` が `string` の場合にのみ適用、設定しない場合または null の場合は選択肢の値を制限しません - -### PriceConfig - -* `input` (float) 入力単価、すなわちプロンプト単価 -* `output` (float) 出力単価、すなわち返却コンテンツ単価 -* `unit` (float) 価格単位、例えば1Mトークンで計算する場合、単価に対応する単位トークン数は `0.000001` です -* `currency` (string) 通貨単位 - -### ProviderCredentialSchema - -* `credential_form_schemas` (array\[[CredentialFormSchema](#credentialformschema)]) 認証情報フォームスキーマ - -### ModelCredentialSchema - -* `model` (object) モデル識別子、変数名はデフォルトで `model` - * `label` (object) モデルフォーム項目表示名 - * `en_US` (string) 英語 - * `zh_Hans`(string) \[optional] 中国語 - * `placeholder` (object) モデルのプレースホルダーコンテンツ - * `en_US`(string) 英語 - * `zh_Hans`(string) \[optional] 中国語 -* `credential_form_schemas` (array\[[CredentialFormSchema](#credentialformschema)]) 認証情報フォームスキーマ - -### CredentialFormSchema - -* `variable` (string) フォーム項目変数名 -* `label` (object) フォーム項目ラベル名 - * `en_US`(string) 英語 - * `zh_Hans` (string) \[optional] 中国語 -* `type` ([FormType](#formtype)) フォーム項目タイプ -* `required` (bool) 必須項目かどうか -* `default`(string) デフォルト値 -* `options` (array\[[FormOption](#formoption)]) フォーム項目が `select` または `radio` の場合の専用プロパティ、ドロップダウン内容を定義 -* `placeholder`(object) フォーム項目が `text-input` の場合の専用プロパティ、フォーム項目のプレースホルダー - * `en_US`(string) 英語 - * `zh_Hans` (string) \[optional] 中国語 -* `max_length` (int) フォーム項目が`text-input`の場合の専用プロパティ、入力最大長を定義、0は無制限。 -* `show_on` (array\[[FormShowOnObject](#formshowonobject)]) 他のフォーム項目の値が条件に一致する場合に表示、空の場合は常に表示。 - -#### FormType - -* `text-input` テキスト入力コンポーネント -* `secret-input` パスワード入力コンポーネント -* `select` 単一選択ドロップダウン -* `radio` ラジオコンポーネント -* `switch` スイッチコンポーネント、`true` と `false` のみをサポート - -#### FormOption - -* `label` (object) ラベル - * `en_US`(string) 英語 - * `zh_Hans`(string) \[optional] 中国語 -* `value` (string) ドロップダウン選択肢の値 -* `show_on` (array\[[FormShowOnObject](#formshowonobject)]) 他のフォーム項目の値が条件に一致する場合に表示、空の場合は常に表示。 - -#### FormShowOnObject - -* `variable` (string) 他のフォーム項目変数名 -* `value` (string) 他のフォーム項目変数値 - -## 関連リソース - -- [モデルアーキテクチャ詳解](/plugin-dev-ja/0412-model-schema) - モデルプラグインのアーキテクチャ仕様を深く理解する -- [新しいモデルの迅速な統合](/plugin-dev-ja/0211-getting-started-new-model) - これらのルールを適用して新しいモデルを追加する方法を学ぶ -- [一般仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインマニフェストファイルの設定を理解する -- [新しいモデルプロバイダーの作成](/plugin-dev-ja/0222-creating-new-model-provider) - 全く新しいモデルプロバイダープラグインを開発する - -{/* -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/0411-model-designing-rules.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-model-plugin-introduction.mdx b/plugin-dev-ja/0411-model-plugin-introduction.mdx deleted file mode 100644 index 97290d98..00000000 --- a/plugin-dev-ja/0411-model-plugin-introduction.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Model Plugin Introduction -language: ja -title: モデルプラグイン -description: モデルプラグインの基本概念と構造を紹介します。モデルプラグインは、Difyがさまざまなプロバイダー(OpenAI、Anthropic、Googleなど)の、大規模言語モデル(LLM)、テキスト埋め込み、音声テキスト変換といったさまざまなタイプのモデルを呼び出すことを可能にします。 ---- - -Modelプラグインは、DifyプラットフォームがそのモデルプロバイダーのすべてのLLMを呼び出すことを可能にします。例えば、OpenAIモデルプラグインをインストールすると、DifyプラットフォームはOpenAIが提供する`GPT-4`、`GPT-4o-2024-05-13`などのモデルを呼び出すことができます。 - -## モデルプラグインの構造 - -モデルプラグイン開発プロセスで関連する可能性のある概念を理解しやすくするために、以下にモデルプラグイン内の構造の簡単な紹介を示します。 - -* **モデルプロバイダー**:大規模モデルの開発会社。例:**OpenAI、Anthropic、Google**など。 -* **モデルカテゴリ**:モデルプロバイダーによって、大規模言語モデル(LLM)、テキスト埋め込みモデル(Text embedding)、音声テキスト変換(Speech2text)などのカテゴリが存在します。 -* **特定のモデル**:`claude-3-5-sonnet`、`gpt-4-turbo`など。 - -プラグインプロジェクト内のコード階層構造: - -```bash -- モデルプロバイダー - - モデルカテゴリ - - 特定のモデル -``` - -**Anthropic**を例にとると、モデルプラグインのサンプル構造は次のようになります。 - -```bash -- Anthropic - - llm - claude-3-5-sonnet-20240620 - claude-3-haiku-20240307 - claude-3-opus-20240229 - claude-3-sonnet-20240229 - claude-instant-1.2 - claude-instant-1 -``` - -OpenAIを例にとると、複数のモデルタイプをサポートしているため、複数のモデルカテゴリレイヤーが存在し、構造は次のようになります。 - -```bash -├── models -│ ├── llm -│ │ ├── chatgpt-4o-latest -│ │ ├── gpt-3.5-turbo -│ │ ├── gpt-4-0125-preview -│ │ ├── gpt-4-turbo -│ │ ├── gpt-4o -│ │ ├── llm -│ │ ├── o1-preview -│ │ └── text-davinci-003 -│ ├── moderation -│ │ ├── moderation -│ │ └── text-moderation-stable -│ ├── speech2text -│ │ ├── speech2text -│ │ └── whisper-1 -│ ├── text_embedding -│ │ ├── text-embedding-3-large -│ │ └── text_embedding -│ └── tts -│ ├── tts-1-hd -│ ├── tts-1 -│ └── tts -``` - -## モデル設定 - -モデルプラグインは、設定ファイルを通じてモデルの動作と属性を定義します。詳細なモデル設計ルールと設定フォーマットについては、[モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules)ドキュメントと[モデルスキーマ](/plugin-dev-ja/0412-model-schema)仕様を参照してください。 - -## さらに読む - -- [新しいモデルの迅速な統合](/plugin-dev-ja/0211-getting-started-new-model) - 既にサポートされているプロバイダーに新しいモデルを追加する方法を学ぶ -- [モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules) - モデル設定の仕様を詳しく理解する -- [モデルスキーマ](/plugin-dev-ja/0412-model-schema) - モデルプラグインのアーキテクチャを深く理解する -- [共通仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグインメタデータの定義方法を理解する -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - プラグイン開発入門ガイドに戻る - -{/* -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/0411-model-plugin-introduction.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-multilingual-readme.mdx b/plugin-dev-ja/0411-multilingual-readme.mdx deleted file mode 100644 index a6a94e32..00000000 --- a/plugin-dev-ja/0411-multilingual-readme.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Multilingual README -language: ja -title: 多言語 README -description: この記事では、プラグインの多言語 README のファイル仕様と、Dify Marketplace での表示ルールについて説明します。 ---- - -Dify プラグインは多言語 README に対応しており、[Dify Marketplace](https://marketplace.dify.ai/?language=ja-Jp) などでユーザーの優先言語に合わせて対応する README を表示します。 - -### README ファイルの仕様 - -| **言語** | **必須** | **ファイル名** | **保存パス** | **説明** | -| :------ | :------ | :------------------ | :-------------------------------- | :------------------------------ | -| 英语 | はい | `README.md` | プラグインのルートディレクトリ直下 | / | -| その他の言語 | いいえ | `README_<言語識別子>.md` | プラグインのルートディレクトリ直下の `readme` フォルダ内 | 現在、日本語、ポルトガル語、簡体字中国語をサポートしています。 | - -ディレクトリ構造の例は以下の通りです。 - -```bash -... -├── main.py -├── manifest.yaml -├── readme -│   ├── README_ja_JP.md -│   ├── README_pt_BR.md -│   └── README_zh_Hans.md -├── README.md -... -``` - -### Marketplace での表示ルール - -プラグインがユーザーの使用言語に対応した README ファイルを提供している場合、Dify Marketplace のプラグイン詳細ページには、その言語版の README が表示されます。 - -![](/images/plugin_details_page_jp.jpeg) - -{/* -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/0411-multilingual-readme.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-persistent-storage-kv.mdx b/plugin-dev-ja/0411-persistent-storage-kv.mdx deleted file mode 100644 index b75d2df5..00000000 --- a/plugin-dev-ja/0411-persistent-storage-kv.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Persistent Storage KV -language: ja -title: 永続ストレージ -description: このドキュメントでは、Difyプラグインの永続ストレージ機能について説明し、プラグインでKVデータベースを使用してデータを保存、取得、削除する方法を詳しく説明します。この機能により、プラグインは同じワークスペース内でデータを永続的に保存でき、セッションをまたいだデータ保存のニーズに対応できます。 ---- - -プラグイン内のツールおよびエンドポイントを個別に見てみると、ほとんどの場合、単一のインタラクションしか完了できず、リクエスト後にデータを返してタスクが終了することがわかります。 - -永続的な記憶の実装など、長期間保存する必要があるデータが存在する場合、プラグインには永続ストレージ機能が求められます。**永続ストレージメカニズムにより、プラグインは同一ワークスペース内でデータを永続的に保存することが可能になります。**現在はKVデータベースを提供することでストレージのニーズに対応していますが、将来的には実際の使用状況に基づき、より柔軟で強力なストレージインターフェースを提供する可能性があります。 - -### キーの保存 - -#### **エントリポイント** - -```python - self.session.storage -``` - -#### **インターフェース** - -```python - def set(self, key: str, val: bytes) -> None: - pass -``` - -渡されるのはbytesであることに注意してください。そのため、実際にはその中にファイルを保存することができます。 - -### キーの取得 - -#### **エントリポイント** - -```python - self.session.storage -``` - -#### **インターフェース** - -```python - def get(self, key: str) -> bytes: - pass -``` - -### キーの削除 - -#### **エントリポイント** - -```python - self.session.storage -``` - -#### **インターフェース** - -```python - def delete(self, key: str) -> None: - pass -``` - -{/* -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/0411-persistent-storage-kv.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-plugin-info-by-manifest.mdx b/plugin-dev-ja/0411-plugin-info-by-manifest.mdx deleted file mode 100644 index da93c44e..00000000 --- a/plugin-dev-ja/0411-plugin-info-by-manifest.mdx +++ /dev/null @@ -1,126 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Plugin info by Manifest -language: ja -title: マニフェスト -description: 作成者 Yeuoly、Allen このドキュメントでは、Difyプラグインのマニフェストファイルについて詳しく説明します。これは、プラグインの基本情報を定義するYAMLファイルです。ドキュメントには、完全なコード例と詳細な構造説明が含まれており、プラグインのバージョン、タイプ、作成者、名称、リソース使用、権限申請、機能定義、ランタイムなど、各方面の設定情報を網羅しています。 ---- - -マニフェストは、yaml 仕様に準拠したファイルであり、プラグイン名、作成者、含まれるツール、モデルなどの情報を含む、**プラグイン**の最も基本的な情報を定義します。プラグインの全体的なアーキテクチャについては、[プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin)および[開発者向けチートシート](/plugin-dev-ja/0131-cheatsheet)を参照してください。 - -このファイルの形式が間違っている場合、プラグインの解析とパッケージ化プロセスは失敗します。 - -### コード例 - -以下は、マニフェストファイルの簡単な例です。各データの意味と役割については、後ほど説明します。他のプラグインのコードを参照する必要がある場合は、[GitHub コードリポジトリ](https://github.com/langgenius/dify-official-plugins/blob/main/tools/google/manifest.yaml)を参照してください。 - -```yaml -version: 0.0.1 -type: "plugin" -author: "Yeuoly" -name: "neko" -label: - en_US: "Neko" -created_at: "2024-07-12T08:03:44.658609186Z" -icon: "icon.svg" -resource: - memory: 1048576 - permission: - tool: - enabled: true - model: - enabled: true - llm: true - endpoint: - enabled: true - app: - enabled: true - storage: - enabled: true - size: 1048576 -plugins: - endpoints: - - "provider/neko.yaml" -meta: - version: 0.0.1 - arch: - - "amd64" - - "arm64" - runner: - language: "python" - version: "3.10" - entrypoint: "main" -privacy: "./privacy.md" -``` - -### 構造 - -* `version`(version, 必須):プラグインのバージョン -* `type`(type, 必須):プラグインタイプ。現在は `plugin` のみをサポートし、将来的には `bundle` をサポート予定です。 -* `author`(string, 必須):作成者。Marketplace では組織名として定義されます。 -* `label`(label, 必須):多言語名称 -* `created_at`(RFC3339, 必須):作成日時。Marketplace では、作成日時が現在時刻を超えてはなりません。 -* `icon`(asset, 必須):アイコンのパス -* `resource` (object):申請が必要なリソース - * `memory` (int64):最大メモリ使用量。主に SaaS 上の AWS Lambda リソース申請に関連し、単位はバイトです。 - * `permission`(object):権限申請 - * `tool`(object):ツールを逆呼び出しする権限 - * `enabled` (bool) - * `model`(object):モデルを逆呼び出しする権限 - * `enabled`(bool) - * `llm`(bool) - * `text_embedding`(bool) - * `rerank`(bool) - * `tts`(bool) - * `speech2text`(bool) - * `moderation`(bool) - * `node`(object):ノードを逆呼び出しする権限 - * `enabled`(bool) - * `endpoint`(object):`endpoint` の登録を許可する権限 - * `enabled`(bool) - * `app`(object):`app` を逆呼び出しする権限 - * `enabled`(bool) - * `storage`(object):永続ストレージを申請する権限 - * `enabled`(bool) - * `size`(int64):許可される永続メモリの最大サイズ。単位はバイトです。 -* `plugins`(object, 必須):プラグインが拡張する具体的な機能の `yaml` ファイルリスト。プラグインパッケージ内の絶対パスです。例えば、モデルを拡張する必要がある場合、`openai.yaml` のようなファイルを定義し、そのファイルパスをここに記入します。そのパス上のファイルは実際に存在しなければならず、そうでなければパッケージ化は失敗します。 - * 形式 - * `tools`(list\[string]):プラグインが拡張する[ツール](/plugin-dev-ja/0222-tool-plugin)プロバイダー - * `models`(list\[string]):プラグインが拡張する[モデル](/plugin-dev-ja/0131-model-plugin-introduction.ja)プロバイダー - * `endpoints`(list\[string]):プラグインが拡張する [Endpoints](/plugin-dev-ja/0432-endpoint) プロバイダー - * `agent_strategies` (list\[string]):プラグインが拡張する [Agent 戦略](/plugin-dev-ja/9433-agent-strategy-plugin)プロバイダー - * 制限 - * ツールとモデルを同時に拡張することはできません - * 拡張機能がまったくない状態は許可されません。 - * モデルと Endpoint を同時に拡張することはできません - * 現在、各タイプの拡張は最大1つのプロバイダーのみサポートしています -* `meta`(object) - * `version`(version, 必須):`manifest` フォーマットバージョン。初期バージョンは `0.0.1` です。 - * `arch`(list\[string], 必須):サポートされるアーキテクチャ。現在は `amd64`、`arm64` のみをサポートしています。 - * `runner`(object, 必須):ランタイム設定 - * `language`(string):現在は python のみをサポートしています。 - * `version`(string):言語のバージョン。現在は `3.12` のみをサポートしています。 - * `entrypoint`(string):プログラムのエントリポイント。python では `main` であるべきです。 -* `privacy` (string, オプション):オプション項目。プラグインのプライバシーポリシーファイルの相対パスまたは URL を指定します。例:`"./privacy.md"` または `"https://your-web/privacy"`。プラグインを Dify Marketplace に公開する予定がある場合、**このフィールドは必須です**。明確なユーザーデータの使用とプライバシーに関する声明を提供するために使用されます。詳細な記入ガイドラインについては、[プラグインのプライバシーデータ保護ガイドライン](/plugin-dev-ja/0312-privacy-protection-guidelines)を参照してください。 - -## 関連リソース - -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - Difyプラグイン開発の全体像を理解する -- [新しいモデルを迅速に導入する](/plugin-dev-ja/0211-getting-started-new-model) - 既存のプロバイダーに新しいモデルを追加する方法を学ぶ -- [共通仕様定義](/plugin-dev-ja/0411-general-specifications) - プラグイン開発における共通構造を理解する -- [リリース概要](/plugin-dev-ja/0321-release-overview) - プラグインのリリースプロセスを学ぶ - -{/* -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/0411-plugin-info-by-manifest.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-remote-debug-a-plugin.mdx b/plugin-dev-ja/0411-remote-debug-a-plugin.mdx deleted file mode 100644 index f1f421e8..00000000 --- a/plugin-dev-ja/0411-remote-debug-a-plugin.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Remote Debug a Plugin -language: ja -title: プラグインのデバッグ -description: このドキュメントでは、Dify のリモートデバッグ機能を使用してプラグインをテストする方法を紹介します。デバッグ情報の取得、環境変数ファイルの設定、プラグインのリモートデバッグの開始、およびプラグインインストール状況の確認といった一連のプロセスを詳しく説明します。これにより、開発者はローカルで開発しながら、Dify - 環境でリアルタイムにプラグインをテストできます。 ---- - -プラグイン開発が完了したら、次にプラグインが正常に動作するかをテストする必要があります。Difyは便利なリモートデバッグ方法を提供し、テスト環境でプラグインの機能を迅速に検証するのに役立ちます。 - -[「プラグイン管理」](https://cloud.dify.ai/plugins)ページに移動し、リモートサーバーアドレスとデバッグキーを取得します。 - -![リモートデバッグプラグイン](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) - -プラグインプロジェクトに戻り、`.env.example` ファイルをコピーして `.env` にリネームし、取得したリモートサーバーアドレスやデバッグキーなどの情報を入力します。 - -`.env` ファイル: - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -`python -m main` コマンドを実行してプラグインを起動します。「プラグイン」ページで、このプラグインがワークスペース内にインストールされていることが確認でき、チームの他のメンバーもこのプラグインにアクセスできます。 - -![プラグインをワークスペースにインストール](https://assets-docs.dify.ai/2024/12/ec26e5afc57bbfeb807719638f603807.png) - -{/* -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/0411-remote-debug-a-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0411-tool.mdx b/plugin-dev-ja/0411-tool.mdx deleted file mode 100644 index 803f19a0..00000000 --- a/plugin-dev-ja/0411-tool.mdx +++ /dev/null @@ -1,132 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Tool -language: ja -title: ツールの返り値 -description: このドキュメントでは、Difyプラグインにおけるツールのデータ構造と使用方法について詳しく説明します。内容には、さまざまなタイプのメッセージ(画像URL、リンク、テキスト、ファイル、JSON)を返す方法、変数およびストリーミング変数メッセージを作成する方法、そしてworkflowで参照しやすくするためにツールの出力変数スキーマを定義する方法が含まれます。 ---- - -詳細なインターフェースドキュメントを読む前に、Difyプラグインのツール統合プロセスについて、大まかな理解があることを確認してください。 - -### データ構造 - -#### メッセージの返却 - -Difyは、`テキスト`、`リンク`、`画像`、`ファイルBLOB`、`JSON`など、さまざまなメッセージタイプをサポートしており、以下の異なるインターフェースを通じてさまざまなタイプのメッセージを返すことができます。 - -デフォルトでは、`workflow`内のツールの出力には、`files`、`text`、`json`の3つの固定変数が含まれ、以下の方法でこれらの変数のデータを返すことができます。 - -例えば、`create_image_message`を使用して画像を返しますが、ツールはカスタム出力変数もサポートしているため、`workflow`内でこれらの変数をより便利に参照できます。 - -#### **画像URL** - -画像のURLを渡すだけで、Difyはリンクを通じて自動的に画像をダウンロードし、ユーザーに返します。 - -```python - def create_image_message(self, image: str) -> ToolInvokeMessage: - pass -``` - -#### **リンク** - -リンクを返す必要がある場合は、以下のインターフェースを使用してください。 - -```python - def create_link_message(self, link: str) -> ToolInvokeMessage: - pass -``` - -#### **テキスト** - -テキストメッセージを返す必要がある場合は、以下のインターフェースを使用してください。 - -```python - def create_text_message(self, text: str) -> ToolInvokeMessage: - pass -``` - -**ファイル** - -画像、音声、動画、PPT、Word、Excelなどのファイルの生データを返す必要がある場合は、以下のインターフェースを使用できます。 - -* `blob` ファイルの生データ、bytes型。 -* `meta` ファイルのメタデータ。開発者が明確なファイルタイプを必要とする場合は、`mime_type`を指定してください。そうでない場合、Difyはデフォルトタイプとして`octet/stream`を使用します。 - -```python - def create_blob_message(self, blob: bytes, meta: dict = None) -> ToolInvokeMessage: - pass -``` - -#### **JSON** - -フォーマットされたJSONを返す必要がある場合は、以下のインターフェースを使用できます。これは通常、workflow内のノード間のデータ転送に使用されます。agentモードでは、ほとんどの大規模モデルもJSONを読み取り、理解することができます。 - -* `object` Pythonの辞書オブジェクトで、自動的にJSONにシリアライズされます。 - -```python - def create_json_message(self, json: dict) -> ToolInvokeMessage: - pass -``` - -#### **変数** - -非ストリーミング出力の変数の場合、以下のインターフェースを使用して返すことができます。複数作成した場合、後者が前者を上書きします。 - -```python - def create_variable_message(self, variable_name: str, variable_value: Any) -> ToolInvokeMessage: - pass -``` - -#### **ストリーミング変数** - -「タイプライター」効果でテキストを出力したい場合は、ストリーミング変数を使用してテキストを出力できます。`chatflow`アプリケーションで`answer`ノードを使用し、この変数を参照すると、テキストは「タイプライター」効果で出力されます。ただし、現在この方法は文字列型のデータのみをサポートしています。 - -```python - def create_stream_variable_message( - self, variable_name: str, variable_value: str - ) -> ToolInvokeMessage: -``` - -#### カスタム変数の返却 - -`workflow`アプリケーションで`tool`の出力変数を参照したい場合は、出力される可能性のある変数を事前に定義する必要があります。Difyプラグインは、[`json_schema`](https://json-schema.org/)形式の出力変数定義をサポートしています。以下に簡単な例を示します。 - -```yaml -identity: - author: author - name: tool - label: - en_US: label - zh_Hans: 标签 - ja_JP: ラベル - pt_BR: etiqueta -description: - human: - en_US: description - zh_Hans: 描述 - ja_JP: 説明 - pt_BR: descrição - llm: description -output_schema: - type: object - properties: - name: - type: string -``` - -上記のサンプルコードは、簡単なツールを定義し、それに`output_schema`を指定しています。これには`name`フィールドが含まれており、この時点で`workflow`内でこのフィールドを参照できます。ただし、実際に使用するためには、ツールの実装コードで変数を返す必要があることに注意してください。そうしないと、`None`の戻り結果が得られます。 - -{/* -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/0411-tool.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0412-doc-understanding-the-dimensions.mdx b/plugin-dev-ja/0412-doc-understanding-the-dimensions.mdx deleted file mode 100644 index 698913d2..00000000 --- a/plugin-dev-ja/0412-doc-understanding-the-dimensions.mdx +++ /dev/null @@ -1,470 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: intermediate -standard_title: 'Doc understanding the dimensions' -language: ja -title: '構造化と並べ替え仕様の詳細' ---- - -> dimensions - -## 背景と動機:開発者エコシステムの進化に対応する - -Difyの初期の成功は、そのプロダクトの直感的な使いやすさに大きく起因しています。コアユーザー(User/Buyer)にとって、製品自体の体験は通常十分なガイダンスとなり、深いカスタマイズを必要とする少数の初期開発者にとっては、通常ソースコードを直接読む能力を持っていました。そのため、初期段階ではドキュメント構築は最優先事項ではありませんでした。 - -しかし、**Dify Pluginエコシステムの立ち上げと発展**により、状況は著しく変化しました: - -1. オーディエンスの拡大:開発者コミュニティはもはやソースコードを深く理解できるコア貢献者だけに限定されていません。Difyの基盤や特定のプログラミングパラダイムに精通していないかもしれないが、ある程度の技術的背景を持つ多くの**「市民開発者(Citizen Developers)」**や統合開発者が登場し、プラグインの構築と貢献のために明確で段階的なガイダンスを必要としています。 -2. コンテンツの混在と目標の曖昧さ:既存のドキュメントは、エンドユーザー向けの**ヘルプコンテンツ**(プラグインの使用方法)と開発者向けの**技術コンテンツ**(プラグインの開発方法)を混合させることが多く、両方の対象者に混乱を引き起こし、情報検索のコストを増加させています。 -3. 構造の欠如とナビゲーションの困難さ:ドキュメントには統一された組織構造と論理的順序が欠けており、開発者(特に新規参入者)が必要な情報を見つけることを難しくし、プラグイン開発ライフサイクルの完全な理解を形成することも困難にしています。既存のナビゲーションは増加するコンテンツに対応しきれていません。 -4. 開発者関係(DevRel)構築の基盤:明確で効果的、構造が優れた開発者ドキュメントシステムは、成功した開発者関係と繁栄するプラグインエコシステムを構築するために不可欠な要素です。それは開発者の体験、貢献意欲、成功率に直接影響します。 - -これらの課題と、Zapier Developer Platform、Cloudflare Docsなどの業界の優れた例(いずれも明確なオーディエンス分離、構造化されたコンテンツ組織、異なるスキルレベル向けのパス設計を示しています)の分析に基づいて、私たちはDifyの開発者ドキュメントの**システム的な再構築**の緊急性を認識しました。 - -dimensionsシステムはこの必要性から生まれました。これは硬直した形式要件のセットではなく、上記の問題を解決するために**構造化思考、オーディエンスセグメンテーション、段階的学習**などの概念を**メタデータベースの自動化プロセス**を通じて結晶化させたソリューションです。これはDifyプラグイン開発者に明確で一貫性があり、ナビゲーションしやすい技術知識ベースを提供することを目的としています。 - -## 核心原則:メタデータを規範的データソースとして - -このシステムの基盤は、以下の核心原則にあります: - -- メタデータ駆動(Metadata-Driven):各Markdownドキュメントのフロントマターで定義されたメタデータ(特にdimensions、standard_title、language)は、そのドキュメントのコンテンツ属性、対象オーディエンス、意図された用途を記述する**規範的データソース(Normative Data Source)**です。 -- コンテンツとプレゼンテーションの分離(Decoupling Content from Presentation):ドキュメントの最終的な表示形式—ファイル名、ドキュメントサイト上での並び順、ナビゲーションメニュー構造—はすべて**自動化ツールによってこれらのメタデータに基づいて動的に生成される必要があります**。著者はコンテンツ自体とそのメタデータ記述の正確性に集中すべきです。 -- 一貫性と保守性のための自動化(Automation for Consistency & Maintainability):自動化プロセスはドキュメントライブラリ全体の構造、命名、並び順の一貫性を確保します。分類システムや並べ替えロジックの調整は、中央設定と生成スクリプトを修正するだけでグローバルに適用でき、保守性を大幅に向上させます。 - -この方法論により、コンテンツ作成者(著者)と技術実装者(ドキュメントシステム保守者/DevOps)が効果的に協力し、最終的な開発者読者のニーズに共同で対応することができます。 - -## メタデータ仕様 - -各開発者ドキュメント(Markdownファイル)には、以下の重要なフィールドを定義するYAML Front Matterブロックが含まれていなければなりません: - -```yaml ---- -# --- コアメタデータ --- - -# 'dimensions' はコンテンツ分類と自動ソート用 -dimensions: - type: # 主要カテゴリ (Conceptual, Implementation, Operational, Reference) - マクロ順序を決定 (W) - primary: # 副次カテゴリ/詳細 (Introduction, Basic, Core, Examples...) - 章内順序を決定 (X) - detail: - # 対象読者レベル/コンテンツ複雑度 (Beginner, Intermediate, Advanced) - ミクロ順序 (Y) と優先度 (P) を決定 - level: - -# 'standard_title' は読みやすいファイル名の生成と概要ページでの使用のため -standard_title: 'ドキュメントの標準的な説明的タイトル' - -# 'language' (ISO 639-1コード例:'en', 'zh', 'ja') は国際化(i18n)とファイル名サフィックスのため -language: - -# --- その他のオプションメタデータ --- - -# 'summary': ドキュメント内容の簡潔な要約 (オプション、リストページやSEO用に使用される可能性あり) -# 'tags': [キーワードリスト] (オプション、フィルタリングや関連コンテンツ用) -# ... 将来必要になる可能性のある他のフィールド ---- -``` - -```markdown -タイプディメンション(プライマリ) - -- conceptual: 理論的または説明的コンテンツ -- implementation: コードと開発コンテンツ -- operational: システムの実行と維持に関するコンテンツ -- reference: 参考資料 - -タイプ詳細ディメンション - -- conceptual向け: introduction, principles, architecture -- implementation向け: basic, standard, high, advanced -- operational向け: setup, deployment, maintenance -- reference向け: core, configuration, examples - -レベルディメンション - -- beginner: トピックの初心者向け -- intermediate: 基本的な理解を持つユーザー向け -- advanced: 上級ユーザー向け -``` - -## dimensionsの深層分析:コンテンツに意味を与える - -dimensionsメタデータはこのシステムの核心であり、各ドキュメントに対して3つの基本的な質問に答えることを要求し、それによって明確な**コンテキスト、スコープ、オーディエンスの位置づけ**を与えます。この分類は、後続のすべての自動化構造と並べ替えの基礎となります。 - -- dimensions.type.primary:コンテンツの「性質」を定義 - - - 核心的質問: このドキュメントは根本的にどのタイプの知識に属するか?それは「何か/なぜか」(理論)、「どうやって」(実践)、「どう実行/維持するか」(運用)、または「正確な検索」(参考)に関するものか? - - 機能: このディメンションはドキュメントが知識体系全体の中で**マクロカテゴリ**を確立します。開発者が焦点を当てる主要な領域を区分けするために、業界で共通のconceptual、implementation、operational、referenceという分類を採用しています。この分類はドキュメントが属する**トップレベルの章**またはテーマ領域を決定し、ドキュメントの情報アーキテクチャを構築する第一歩です。 - -- dimensions.type.detail:コンテンツの「テーマフォーカス」を明確にする - - - 核心的質問: 上記のマクロカテゴリ内で、このドキュメントは具体的にそのカテゴリのどの**特定の側面やサブトピック**に関するものか?例えば、あるコンセプトの「入門ガイド」、ある実装の「標準的な使用法」、または参照情報の「コアAPI」か? - - 機能: 主要カテゴリ内でより**細かいトピック区分**を提供します。これにより関連ドキュメントがまとまり、論理的に一貫した**サブチャプター**または段落を形成します。適切な詳細を選択することで、特定の章を閲覧する際にユーザーが具体的なコンテンツポイントを素早く特定するのに役立ちます。 - -- dimensions.level:コンテンツの「複雑さと対象者」をマーク - - 核心的質問: この特定トピックに関するドキュメントは、主にどの**経験レベルの読者**向けか?あるいは、そのコンテンツの**複雑さ**はどうか?入門(beginner)、一般(intermediate)、それとも深い/専門的(advanced)か? - - 機能: このディメンションには**二重の重要な役割**があります: - 1. 細粒度の並べ替え: 同一の具体的なトピック内で、コンテンツを易しいものから難しいものへと順序付け、学習曲線を最適化します。 - 2. 優先度判定: 特に高度(advanced)レベルは、システムが「コアコンテンツ」と「高度/深水域コンテンツ」を区別するための重要な入力であり、コンテンツが後回しにされるかどうかに直接影響します(セクション5参照)。 - -これら3つのディメンションでコンテンツに正確にタグ付けすることは、ドキュメントライブラリが合理的に構造化され、ナビゲーションが容易で、異なるユーザーのニーズを満たすための前提条件です。 - -## ソートメカニズム:**PWXY**プレフィックスと優先度ルール - -一貫性があり論理的に明確なドキュメント表示順序を実現するために、システムはdimensionsメタデータに基づいて各ドキュメントに4桁のゼロパディングされた数字プレフィックス(PWXY)を自動生成し、これをファイル名の一部として使用して並べ替えを実装します。 - -- P **優先度(Priority)**: 1桁目。通常(P=0)と後回し/深水域(P=9)コンテンツを区別します。 -- W **主要タイプ番号(Primary Type)**: 2桁目。primaryタイプのマクロ順序を反映します。 -- X **詳細タイプ番号(Detail Type)**: 3桁目。主要タイプ内でのdetailタイプの順序を反映します。 -- Y **難易度レベル番号(Level)**: 4桁目。詳細タイプ内でのlevelの順序を反映します。 - -優先度(**P=9**)ルールの説明: - -コンテンツをP=9としてマークする目的は、初心者と通常使用に不可欠ではない、複雑さの高いコンテンツを**自動的に後回し**にすることで、主流のユーザーグループにより滑らかな学習曲線とより集中したコアコンテンツフローを提供することです。P=9をトリガーする条件は: - -1. 高度と定義されたコンテンツ: level: advanced。 -2. 実装カテゴリの下の特定の複雑な詳細: primary: implementation かつ detail が high または advanced。 - -P=9のコンテンツはドキュメントライブラリの「付録」、「詳細な議論」、または「高度な参考資料」とみなすことができます。 - -## ファイル名生成戦略 - -最終的にデプロイされるファイル名は、メタデータに基づいて自動化スクリプトによって生成され、その概念形式は次のとおりです: -`PWXY-[sanitized_standard_title].language.md` - -このファイル名は主に**機械ソート**と内部識別のために使用されます。ドキュメントの**人間が読めるタイトル**は、`standard_title`メタデータとドキュメント内のH1タイトルに基づいています。自動化スクリプトはメタデータ抽出、PWXY計算、タイトルのサニタイズ、言語サフィックス、[GitHubベースの編集とフィードバックボタンの自動実装](/tools/contributing_in_page.py)などすべての詳細を処理します。 - -## オーディエンス指向の設計原則:段階的開示とパス最適化 - -このシステムには「段階的開示(Progressive Disclosure)」の核心原則が浸透しており、異なる背景を持つ開発者の情報取得パスを最適化することを目指しています。 - -1. 優先度メカニズム(P値区別):これは段階的開示を実装する主要な手段です。基本的、コア的、高頻度使用コンテンツ(P=0)と高度、複雑、特定シナリオのコンテンツ(P=9)を体系的に分離します。これにより、ユーザーはデフォルトでまず比較的簡素化され、コアに焦点を当てた知識体系に出会うことが保証されます。 -2. 構造化分類(type.primaryとtype.detailに基づく):同じ優先度内でも、コンテンツは異なるカテゴリとトピックに明確に組織化され、すべてのユーザー(特に経験豊富なユーザー)に予測可能な「情報マップ」を提供します。 - -これらの原則に基づき、システムは異なる対象オーディエンスに最適化された体験を提供するよう努めています: - -- 学習者と新規参入者(Citizen Developersを含む):デフォルトでP=0のコンテンツシーケンスを閲覧し、概念から基本的な実践へと構造化された学習パスを獲得し、段階的に進み、初期の認知負荷を軽減します。 -- 経験豊富な開発者と貢献者:明確な構造を利用して効率的な**ランダムアクセス**を行い、特定の参照情報や実装の詳細を素早く特定するか、必要に応じて直接P=9の高度なコンテンツに飛び込みます。彼らにとって、ドキュメントライブラリはより素早く参照できる技術マニュアルのように機能します。 -- 自動化ツールとサービス(例:LLM):人間とは異なる情報消費パターンを認識します。構造化されたメタデータにより、特別に最適化された、おそらくよりフラット化されたデータ入力ストリーム(`llms-full.txt`など)を生成することが**可能になり**、理解効率を高めます。 - -要約すると、dimensionsシステムは1つのアプローチですべての人を満足させようとするのではなく、**構造化分類、優先度ソート、メタデータ駆動の自動化**を通じて、異なるユーザーグループに比較的最適な情報アクセスと学習パスを提供します。 - -## システムの利点 - -- 明確な構造とナビゲーションの改善:信頼性の高い分類と予測可能な並べ替えに基づいています。 -- 一貫した体験:自動化によりすべてのドキュメントが同じパターンに従うことを保証します。 -- オーディエンス適応:優先度区別を通じて、差別化された読書パスを提供します。 -- 高い保守性:分類や並べ替えロジックの調整は、中央の設定とスクリプトを修正するだけで行えます。 -- 拡張性:新しいコンテンツタイプや難易度レベルの追加が容易です。 -- 協力を促進:著者、レビュアー、システム保守者に共通の理解基盤と協力基準を提供します。 - -## 創作プロセス、役割、ガバナンス:現実世界の課題への対応 - -高品質のドキュメントライブラリの確立は、複数の当事者の協力を伴い、現実世界の課題に直面するプロセスです。dimensionsシステムはこのプロセスにおいて構造化されたフレームワークと協力ツールとなることを目指しています。 - -### 協力モデルにおける主要な役割 - -- クリエイター/著者: - - - 核心的責任:正確で明確、価値のあるドキュメントコンテンツの作成。 - - 協力のポイント:dimensionsの分類システムを学び理解しようとし、提出時にドキュメントに最も適切なメタデータ(dimensions、standard_title、language)を**試みる**こと。正確な初期分類はその後のプロセスに役立ちます。 - -- オーナー/レビュアー: - - - 核心的責任:ドキュメントの**正確性、明確さ、範囲**および**メタデータの適切さ**の最終的な品質管理。これはドキュメントライブラリの品質と構造的一貫性を確保するための重要なステップです。 - - 能力要件:関連する技術分野の深い理解を持ち、**同時に**dimensionsシステムの背後にある**全体的な情報アーキテクチャとオーディエンスセグメンテーションロジック**を理解する必要があります(これはしばしば、アーキテクトの視点に似た、一定のシステム的思考を必要とします)。 - - 協力のポイント:dimensionsを客観的な「ものさし」としてコンテンツ位置付けをレビューする。メタデータが不正確またはコンテンツ境界が曖昧な場合は、クリエイターに修正を指導するか、メタデータを直接修正する。**最終的にメインブランチにマージされるメタデータがドキュメントの表示方法を決定**します。 - -- オペレーター/DevOps: - - - 核心的責任:ドキュメント自動化ビルド、テスト、デプロイのプロセスとツールの維持と最適化。 - - 協力のポイント:自動化スクリプトが正確かつ効率的にメタデータを解析し、最終製品(ソートされたファイル、ナビゲーションデータなど)を生成することを確保する。彼らは個々のドキュメントのコンテンツ詳細よりも、**プロセスの堅牢性**に焦点を当てています。 - -### 実際のドキュメント協力の課題への対応 - -この役割分担は、いくつかの一般的なドキュメントのジレンマを認識し、軽減する助けとなります: - -- 「プログラマーはドキュメントを書くのが好きではない」vs「ドキュメントを書く人は技術を理解していない」: - - - dimensionsシステムは**クリエイター(プログラマー)への要求を下げる**:第一の任務は正確な技術的内容を書くことであり、メタデータ分類は「最善を尽くす」ことができます。なぜならレビュアーが品質チェックを行うからです。 - - 同時に、それは**レビュアーへの要求を高め**、高品質のドキュメントには深い技術的理解とアーキテクチャ的思考が必要であることを認め、この高レベルの能力をドキュメント構造とメタデータの制御に向けます。 - - 潜在的な「専任ドキュメントエンジニア」については、彼らはクリエイターとして行動するか、またはレビュアーのメタデータ検証とコンテンツの洗練を支援することができ、役割はより柔軟です。 - -- 高品質レビュアーは希少で「費用対効果」の懸念: - - - 確かに、必要な技術的深さとアーキテクチャ的思考を持つレビュアーは貴重です。彼らはコア機能開発と比較してドキュメントのレビューは「価値が低い」と感じるかもしれません。 - - 鍵となるのは認識を高めることです:**高品質で構造化されたドキュメントは、開発者エコシステムの成功、サポートコストの削減、製品採用率の向上のために非常に高い戦略的価値を持っている**ことを強調する必要があります。dimensionsシステムは、レビュアーの高レベルの思考を**明示的、標準化**し、**直接測定可能なドキュメント体験の向上に変換する**ツールです。ドキュメントのレビューはもはや「雑用」ではなく、開発者体験を形成し、知識体系を構築する重要なリンクです。 - -- プロセス保証:dimensionsシステムは**協力フレームワーク**を提供します。それはクリエイターにコンテンツの位置付けを考えるよう促し、レビュアーに明確な評価基準と修正権限を与え、オペレーターが自動化プロセスを独立して維持できるようにします。メタデータチェックをPRプロセスに組み込むことで(Code Reviewと同様)、最終出力の品質を制度的に保証することができます。 - -## 拡張性とコードの役割 - -- システム拡張:dimensions分類システムは静的ではありません。Difyの機能が進化するにつれて、新しいprimaryタイプ、detailタイプ、またはlevelを適切なタイミングで追加することができます(そしてすべきです)。これは主に中央マッピング設定を更新し、(必要に応じて)生成スクリプトを調整することで実装され、システムの柔軟性を示しています。 -- ドキュメントとコードの関係:開発者ドキュメント(特にReferenceと高度なImplementationの部分)の核心的な目標の一つは、**ソースコード**を理解し使用するための**効果的なガイド**として機能することです。それはコードレベルの設計、使用法、制約を説明し、リンクなどの手段を通じて、開発者が必要なときに最終的で最も正確なコンテンツである**ソースコードにシームレスに深入り**することを促進すべきです。ドキュメントはコードの代替品ではなく、その**高品質な別の側面と解釈者**です。 - -{/* -# Frontmatter Metadata Guide - -This document helps you quickly define core metadata for Dify developer documentation. Correctly filling out these fields is key to implementing automated document structure and sorting. - -## Quick Start - - - - - - Complete writing your document content. - - - - Provide your document and the content from [**dimensions system explained**](/plugin-dev-en/0412-doc-understanding-the-dimensions) to your preferred large language model, and request it to generate appropriate Frontmatter. - - - - Based on actual circumstances and the detailed explanations below, make necessary adjustments and optimizations to the generated metadata. - - - - - - Read the detailed instructions below and define appropriate metadata fields based on the characteristics of your document content. - - - -## Required Frontmatter Fields - -Please add the following YAML Frontmatter at the beginning of each Markdown document: - -```yaml ---- -# --- Core System Metadata (affects structure and sorting) --- -dimensions: - type: - primary: - detail: - level: -standard_title: 'Descriptive title in English, used for filename generation' # e.g., 'Getting Started Dify Plugin' -language: 'en' # or 'zh', 'ja', etc. (ISO 639-2 code) - -# --- Page Content Metadata (optional but recommended) --- -title: 'H1 title or page title of the document' -description: 'Brief SEO description of the document content' -# summary: 'More detailed summary (optional)' -# tags: ['keywords'] (optional) ---- -``` - -## Understanding the `dimensions` Field - - - - - - **Concepts, theory** (what/why) -
Focuses on explaining concepts and fundamental theories -
- - - **Development practices, code** (how to) -
Focuses on providing implementation steps and code examples -
- - - **Operations, deployment** (how to run) -
Focuses on system operation and maintenance -
- - - **API, configuration reference** (precise lookup) -
Focuses on technical specifications and reference information -
-
-
- - - Subdivisions under the `primary` category: - - - -
    -
  • introduction: Introductory content
  • -
  • principles: Design principles
  • -
  • architecture: Architectural explanation
  • -
-
- - -
    -
  • basic: Basic implementation
  • -
  • standard: Standard implementation
  • -
  • high: Higher-level implementation (may be deprioritized)
  • -
  • advanced: Advanced implementation (may be deprioritized)
  • -
-
- - -
    -
  • setup: Environment setup
  • -
  • deployment: Deployment operations
  • -
  • maintenance: Maintenance management
  • -
-
- - -
    -
  • core: Core reference
  • -
  • configuration: Configuration reference
  • -
  • examples: Example reference
  • -
-
-
- - - For more options, please refer to the [dimensions system explained](/plugin-dev-en/0412-doc-understanding-the-dimensions) document - -
- - - - - **Newcomer** -
Content suitable for beginners -
- - - **Regular user** -
Content for users with some background knowledge -
- - - **Advanced user** -
In-depth content for professional users (typically deprioritized in sorting) -
-
-
-
- -## Other Important Fields - - - Use **English** to clearly describe the core content of the document. The system will use this to generate part of the filename (e.g., `Getting Started Dify Plugin`). - - - - ISO 639-2 two-letter language code (such as `en`, `zh`, `ja`). - - - - The main title of the document displayed on the page, typically in the localized language. - - - - A brief SEO description for search engines and previews. - - -## Complete Examples - - - ```yaml Introductory Document Example - --- - dimensions: - type: - primary: conceptual - detail: introduction - level: beginner - standard_title: 'Getting Started Dify Plugin' - language: en - title: 'Welcome to Dify Plugin Development' - description: 'Introduction to Dify plugin concepts, functionality, and development value, including a brief explanation of plugin types and an overview of developer documentation content.' - --- - ``` - - ```yaml Tool Development Document Example - --- - dimensions: - type: - primary: implementation - detail: standard - level: intermediate - standard_title: 'Developing Tool Plugin' - language: en - title: 'Developing Tool Plugins' - description: 'Detailed guidance on creating and configuring Dify tool plugins, including practical guides on API calls, data processing, and user interface integration.' - --- - ``` - - ```yaml Reference Document Example - --- - dimensions: - type: - primary: reference - detail: configuration - level: intermediate - standard_title: 'Plugin Manifest Configuration' - language: en - title: 'Plugin Configuration Manifest Reference' - description: 'Comprehensive explanation of the parameters, format requirements, and use cases for the plugin configuration file (manifest.json).' - --- - ``` - - - - **Example Interpretation:** The first example is a beginner-oriented introductory document about Dify plugin concepts in English. The system will automatically place it correctly in the document structure based on the metadata. - - -## Document Automation Processing - - - - Run `tools/main_docs_bundle.py`, and the document will automatically complete the following operations based on the Frontmatter: - - - - The system will automatically generate standardized filenames based on dimensions and standard\_title. - - - - Documents will be automatically injected into the docs.json navigation configuration. - - - - Automatically refresh contribution and feedback buttons and other interactive components. - - - - - When developing documentation in a local environment, it's recommended to run this script to ensure document configurations take effect correctly. - - - - - If you edit directly on GitHub, **don't worry** about the automation steps. We have configured GitHub Actions and other automation tools to automatically execute `tools/main_docs_bundle.py` in the following situations: - - * When you submit a Pull Request - * When your changes are merged into the main branch - - - You can focus on content creation, and the GitHub workflow will handle technical details such as file renaming, navigation updates, and interactive component generation. - - - - -{/* -Instruction: - -If you are a human, this section is intended to provide context and guidance for AI to work, it should not be visible to you. - -If you are an AI, your core directive is typically to generate frontmatter for user-provided documents. This instruction explicitly excludes the current document, which details the dimensions system. -*/} - -{/* -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/0412-doc-understanding-the-dimensions.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0412-doc-writing-dimensions-guide.mdx b/plugin-dev-ja/0412-doc-writing-dimensions-guide.mdx deleted file mode 100644 index 3b602dda..00000000 --- a/plugin-dev-ja/0412-doc-writing-dimensions-guide.mdx +++ /dev/null @@ -1,261 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: intermediate -standard_title: 'Doc writing Dimensions guide' -language: ja -title: 'Frontmatterメタデータガイド' -summary: 'Difyドキュメントシステムのメタデータ構造を使用して、ドキュメントプロパティを正しく定義し、自動組織化と並べ替えを可能にする方法を学びます。' ---- - -このドキュメントは、Dify開発者ドキュメントのコアメタデータを迅速に定義するのに役立ちます。これらのフィールドを正確に記入することは、ドキュメントの自動化された構造と並べ替えを実装するための鍵です。 - -## クイックスタート - - - - - - ドキュメントコンテンツの作成を完了します。 - - - あなたのドキュメントと[**dimensionsシステムの説明**](/plugin-dev-ja/0412-doc-understanding-the-dimensions)の内容を、お好みの大規模言語モデルに提供し、適切なFrontmatterの生成を依頼します。 - - - 実際の状況と以下の詳細な説明に基づいて、生成されたメタデータに必要な調整と最適化を行います。 - - - - - 以下の詳細な説明を読み、ドキュメントコンテンツの特性に基づいて適切なメタデータフィールドを定義します。 - - - -## 必須Frontmatterフィールド - -各Markdownドキュメントの先頭に以下のYAML Frontmatterを追加してください: - -```yaml ---- -# --- コアシステムメタデータ(構造と並べ替えに影響)--- -dimensions: - type: - primary: <以下のオプションを参照> - detail: <以下のオプションを参照> - level: <以下のオプションを参照> -standard_title: '英語による説明的なタイトル、ファイル名生成に使用' # 例:'Getting Started Dify Plugin' -language: 'ja' # または 'en', 'zh'など(ISO 639-2コード) - -# --- ページコンテンツメタデータ(オプションだが推奨)--- -title: 'ドキュメントのH1タイトルまたはページタイトル' -description: 'ドキュメントコンテンツの簡潔なSEO説明' -# summary: 'より詳細な要約(オプション)' -# tags: ['キーワード'](オプション) ---- -``` - -## `dimensions`フィールドの理解 - - - - - - **概念、理論**(何/なぜ) -
概念と基本理論の説明に焦点を当てる -
- - **開発プラクティス、コード**(どのように) -
実装手順とコード例の提供に焦点を当てる -
- - **運用、デプロイメント**(どのように実行する) -
システム運用と保守に焦点を当てる -
- - **API、設定リファレンス**(正確な検索) -
技術仕様とリファレンス情報の提供に焦点を当てる -
-
-
- - - `primary`カテゴリの下位区分: - - - -
    -
  • introduction: 導入コンテンツ
  • -
  • principles: 設計原則
  • -
  • architecture: アーキテクチャの説明
  • -
-
- - -
    -
  • basic: 基本的な実装
  • -
  • standard: 標準的な実装
  • -
  • high: 高度な実装(優先度が下がる可能性あり)
  • -
  • advanced: 高度な実装(優先度が下がる可能性あり)
  • -
-
- - -
    -
  • setup: 環境設定
  • -
  • deployment: デプロイメント操作
  • -
  • maintenance: メンテナンス管理
  • -
-
- - -
    -
  • core: コアリファレンス
  • -
  • configuration: 設定リファレンス
  • -
  • examples: 例示リファレンス
  • -
-
-
- - - より多くのオプションについては、[dimensionsシステムの説明](/plugin-dev-ja/0412-doc-understanding-the-dimensions)ドキュメントを参照してください - -
- - - - - **初心者** -
初心者向けのコンテンツ -
- - **一般ユーザー** -
ある程度の背景知識を持つユーザー向けのコンテンツ -
- - **上級ユーザー** -
専門ユーザー向けの詳細なコンテンツ(通常、並べ替えで優先度が下がる) -
-
-
-
- -## その他の重要なフィールド - - - **英語**を使用して、ドキュメントのコアコンテンツを明確に説明します。システムはこれを使用してファイル名の一部を生成します(例:`Getting Started Dify Plugin`)。 - - - - ISO 639-2の2文字言語コード(例:`en`、`zh`、`ja`)。 - - - - ページに表示されるドキュメントのメインタイトル、通常はローカライズされた言語で記述されます。 - - - - 検索エンジンとプレビュー用の簡潔なSEO説明。 - - -## 完全な例 - - - ```yaml 導入ドキュメントの例 - --- - dimensions: - type: - primary: conceptual - detail: introduction - level: beginner - standard_title: 'Getting Started Dify Plugin' - language: ja - title: 'Difyプラグイン開発へようこそ' - description: 'Difyプラグインの概念、機能、開発価値の紹介。プラグインタイプの簡単な説明と開発者ドキュメントの内容の概要を含みます。' - --- - ``` - - ```yaml ツール開発ドキュメントの例 - --- - dimensions: - type: - primary: implementation - detail: standard - level: intermediate - standard_title: 'Developing Tool Plugin' - language: ja - title: 'ツールプラグインの開発' - description: 'Difyツールプラグインの作成と設定に関する詳細なガイダンス。APIコール、データ処理、ユーザーインターフェイス統合に関する実践ガイドを含みます。' - --- - ``` - - ```yaml リファレンスドキュメントの例 - --- - dimensions: - type: - primary: reference - detail: configuration - level: intermediate - standard_title: 'Plugin Manifest Configuration' - language: ja - title: 'プラグイン設定マニフェストリファレンス' - description: 'プラグイン設定ファイル(manifest.json)のパラメータ、フォーマット要件、ユースケースに関する包括的な説明。' - --- - ``` - - - - **例の解釈:** 最初の例は、初心者向けのDifyプラグインの概念に関する導入ドキュメントで、言語は日本語です。システムはメタデータに基づいて、ドキュメント構造内に自動的に正しく配置します。 - - -## ドキュメント自動化処理 - - - - `tools/main_docs_bundle.py`を実行すると、ドキュメントはFrontmatterに基づいて以下の操作を自動的に完了します: - - - - システムはdimensionsとstandard_titleに基づいて標準化されたファイル名を自動的に生成します。 - - - ドキュメントはdocs.jsonナビゲーション設定に自動的に挿入されます。 - - - 貢献とフィードバックボタンなどのインタラクティブコンポーネントを自動的に更新します。 - - - - - ローカル環境でドキュメントを開発する場合、ドキュメント設定が正しく反映されるようにこのスクリプトを実行することをお勧めします。 - - - - - - GitHubで直接編集する場合は、自動化ステップについて**心配しないでください**。私たちは、次の状況で`tools/main_docs_bundle.py`を自動的に実行するようにGitHub Actionなどの自動化ツールを設定しています: - - - Pull Requestを提出するとき - - 変更がメインブランチにマージされるとき - - - コンテンツ作成に集中できます。GitHubワークフローがファイル名の変更、ナビゲーションの更新、インタラクティブコンポーネントの生成などの技術的な詳細を処理します。 - - - - - - Dimensionsシステムの設計哲学、並べ替えメカニズムの完全な詳細、または役割とガバナンスに興味がある場合は、Dimensionsシステムの詳細な説明ドキュメントをお読みください。 - - -{/* -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/0412-doc-writing-dimensions-guide.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0412-model-schema.mdx b/plugin-dev-ja/0412-model-schema.mdx deleted file mode 100644 index f0c66f7b..00000000 --- a/plugin-dev-ja/0412-model-schema.mdx +++ /dev/null @@ -1,695 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: intermediate -standard_title: Model Schema -language: ja -title: モデルインターフェース -description: 本書では、Difyモデルプラグイン開発に必要なインターフェース仕様について詳しく説明します。これには、モデルプロバイダーの実装、5つのモデルタイプ(LLM、TextEmbedding、Rerank、Speech2text、Text2speech)のインターフェース定義、およびPromptMessage、LLMResultなどの関連データ構造の完全な仕様が含まれます。本書は、開発者が様々なモデル統合を実装する際の開発リファレンスとして適しています。 ---- - -ここでは、プロバイダーと各モデルタイプが実装する必要のあるインターフェースメソッドとパラメータについて説明します。モデルプラグインを開発する前に、まず[モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules)と[モデルプラグイン紹介](/plugin-dev-ja/0131-model-plugin-introduction.ja)を読むことをお勧めします。 - -### モデルプロバイダー - -`__base.model_provider.ModelProvider` ベースクラスを継承し、以下のインターフェースを実装します: - -```python -def validate_provider_credentials(self, credentials: dict) -> None: - """ - プロバイダーのクレデンシャルを検証します - モデルタイプの任意の validate_credentials メソッドを選択するか、自分で検証メソッドを実装することができます(例:モデルリスト取得API)。 - - 検証に失敗した場合は、例外を発生させます - - :param credentials: プロバイダーのクレデンシャル。クレデンシャルの形式は `provider_credential_schema` で定義されます。 - """ -``` - -* `credentials` (object) クレデンシャル情報 - -クレデンシャル情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` で定義され、`api_key` などが渡されます。検証に失敗した場合は、`errors.validate.CredentialsValidateFailedError` エラーをスローしてください。**注:事前定義モデルはこのインターフェースを完全に実装する必要がありますが、カスタムモデルプロバイダーは以下のように簡単な実装で済みます:** - -```python -class XinferenceProvider(Provider): - def validate_provider_credentials(self, credentials: dict) -> None: - pass -``` - -### モデル - -モデルは5つの異なるモデルタイプに分かれ、モデルタイプごとに継承するベースクラスや実装が必要なメソッドも異なります。 - -#### 共通インターフェース - -すべてのモデルは、以下の2つのメソッドを共通して実装する必要があります: - -* モデルクレデンシャルの検証 - -プロバイダーのクレデンシャル検証と同様に、ここでは個別のモデルに対して検証を行います。 - -```python -def validate_credentials(self, model: str, credentials: dict) -> None: - """ - モデルのクレデンシャルを検証します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :return: - """ -``` - -パラメータ: - -* `model` (string) モデル名 -* `credentials` (object) クレデンシャル情報 - -クレデンシャル情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。検証に失敗した場合は、`errors.validate.CredentialsValidateFailedError` エラーをスローしてください。 - -* 呼び出し例外エラーマッピングテーブル - -モデル呼び出し時に例外が発生した場合、Runtime が指定する `InvokeError` タイプにマッピングする必要があります。これにより、Dify は異なるエラーに対して異なる後続処理を行うことができます。Runtime Errors: - -* `InvokeConnectionError` 呼び出し接続エラー -* `InvokeServerUnavailableError` 呼び出し先サーバー利用不可 -* `InvokeRateLimitError` 呼び出しレート制限超過 -* `InvokeAuthorizationError` 呼び出し認証失敗 -* `InvokeBadRequestError` 呼び出しパラメータ不正 - -```python -@property -def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: - """ - モデルの呼び出しエラーを統一エラーにマッピングします - キーは呼び出し元にスローされるエラータイプです - 値はモデルによってスローされるエラータイプであり、呼び出し元のために統一エラータイプに変換する必要があります。 - - :return: 呼び出しエラーマッピング - """ -``` - -対応するエラーを直接スローし、以下のように定義することも可能です。これにより、その後の呼び出しで `InvokeConnectionError` などの例外を直接スローできます。 - -#### LLM - -`__base.large_language_model.LargeLanguageModel` ベースクラスを継承し、以下のインターフェースを実装します: - -* LLM 呼び出し - -LLM 呼び出しのコアメソッドを実装し、ストリーミングと同期的な返却の両方をサポートできます。 - -```python -def _invoke(self, model: str, credentials: dict, - prompt_messages: list[PromptMessage], model_parameters: dict, - tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None, - stream: bool = True, user: Optional[str] = None) \ - -> Union[LLMResult, Generator]: - """ - 大規模言語モデルを呼び出します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :param prompt_messages: プロンプトメッセージ - :param model_parameters: モデルパラメータ - :param tools: ツール呼び出し用のツール - :param stop: ストップワード - :param stream: ストリーム応答かどうか - :param user: 一意のユーザーID - :return: 完全な応答またはストリーム応答チャンクジェネレータの結果 - """ -``` - -* パラメータ: - * `model` (string) モデル名 - * `credentials` (object) クレデンシャル情報 - -クレデンシャル情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。 - -* `prompt_messages` (array\[[PromptMessage](#promptmessage)]) プロンプトリスト - -モデルが `Completion` タイプの場合、リストには [UserPromptMessage](#userpromptmessage) 要素を1つ渡すだけで十分です。モデルが `Chat` タイプの場合、メッセージに応じて [SystemPromptMessage](#systempromptmessage)、[UserPromptMessage](#userpromptmessage)、[AssistantPromptMessage](#assistantpromptmessage)、[ToolPromptMessage](#toolpromptmessage) 要素のリストを渡す必要があります。 - -* `model_parameters` (object) モデルパラメータ。モデルパラメータはモデルのYAML設定の `parameter_rules` で定義されます。 - -* `tools` (array\[[PromptMessageTool](#promptmessagetool)]) \[optional] ツールリスト。`function calling` における `function` と同等です。つまり、tool calling に渡すツールリストです。 - -* `stop` (array\[string]) \[optional] ストップシーケンス。モデルの返却は、ストップシーケンスで定義された文字列の直前で停止します。 - -* `stream` (bool) ストリーミング出力かどうか、デフォルトは True。ストリーミング出力は Generator\[[LLMResultChunk](#llmresultchunk)] を返し、非ストリーミング出力は [LLMResult](#llmresult) を返します。 - -* `user` (string) \[optional] ユーザーの一意の識別子。プロバイダーが不正利用を監視および検出するのに役立ちます。 - -* 返り値 - -ストリーミング出力は Generator\[[LLMResultChunk](#llmresultchunk)] を返し、非ストリーミング出力は [LLMResult](#llmresult) を返します。 - -* 入力トークンの事前計算 - -モデルがトークン事前計算インターフェースを提供していない場合、直接 0 を返すことができます。 - -```python -def get_num_tokens(self, model: str, credentials: dict, prompt_messages: list[PromptMessage], - tools: Optional[list[PromptMessageTool]] = None) -> int: - """ - 指定されたプロンプトメッセージのトークン数を取得します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :param prompt_messages: プロンプトメッセージ - :param tools: ツール呼び出し用のツール - :return: - """ -``` - -パラメータの説明は上記の `LLM 呼び出し` を参照してください。このインターフェースは、対応する `model` に基づいて適切な `tokenizer` を選択して計算する必要があります。対応するモデルが `tokenizer` を提供していない場合は、`AIModel` ベースクラスの `_get_num_tokens_by_gpt2(text: str)` メソッドを使用して計算できます。 - -* カスタムモデルルールの取得 \[オプション] - -```python -def get_customizable_model_schema(self, model: str, credentials: dict) -> Optional[AIModelEntity]: - """ - カスタマイズ可能なモデルスキーマを取得します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :return: モデルスキーマ - """ -``` - -プロバイダーがカスタムLLMの追加をサポートしている場合、このメソッドを実装することで、カスタムモデルがモデルルールを取得できるようになります。デフォルトでは None を返します。 - -`OpenAI` プロバイダーのほとんどのファインチューニングモデルでは、ファインチューニングモデル名(例:`gpt-3.5-turbo-1106`)からベースモデルを取得し、そのベースモデルの事前定義パラメータルールを返すことができます。[OpenAI](https://github.com/langgenius/dify-official-plugins/tree/main/models/openai) の具体的な実装を参照してください。 - -#### TextEmbedding - -`__base.text_embedding_model.TextEmbeddingModel` ベースクラスを継承し、以下のインターフェースを実装します: - -* Embedding 呼び出し - -```python -def _invoke(self, model: str, credentials: dict, - texts: list[str], user: Optional[str] = None) \ - -> TextEmbeddingResult: - """ - テキスト埋め込みモデルを呼び出します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :param texts: 埋め込むテキスト - :param user: 一意のユーザーID - :return: 埋め込み結果 - """ -``` - -* パラメータ: - -* `model` (string) モデル名 - -* `credentials` (object) クレデンシャル情報 - -クレデンシャル情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。 - -* `texts` (array\[string]) テキストリスト、バッチ処理可能 - -* `user` (string) \[optional] ユーザーの一意の識別子。プロバイダーが不正利用を監視および検出するのに役立ちます。 - -* 返り値: - -[TextEmbeddingResult](#textembeddingresult) エンティティ。 - -* トークンの事前計算 - -```python -def get_num_tokens(self, model: str, credentials: dict, texts: list[str]) -> int: - """ - 指定されたテキストのトークン数を取得します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :param texts: 埋め込むテキスト - :return: - """ -``` - -パラメータの説明は上記の `Embedding 呼び出し` を参照してください。 - -上記の `LargeLanguageModel` と同様に、このインターフェースは対応する `model` に基づいて適切な `tokenizer` を選択して計算する必要があります。対応するモデルが `tokenizer` を提供していない場合は、`AIModel` ベースクラスの `_get_num_tokens_by_gpt2(text: str)` メソッドを使用して計算できます。 - -#### Rerank - -`__base.rerank_model.RerankModel` ベースクラスを継承し、以下のインターフェースを実装します: - -* rerank 呼び出し - -```python -def _invoke(self, model: str, credentials: dict, - query: str, docs: list[str], score_threshold: Optional[float] = None, top_n: Optional[int] = None, - user: Optional[str] = None) \ - -> RerankResult: - """ - Rerankモデルを呼び出します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :param query: 検索クエリ - :param docs: リランキング対象のドキュメント - :param score_threshold: スコアのしきい値 - :param top_n: 上位n件 - :param user: 一意のユーザーID - :return: リランキング結果 - """ -``` - -* パラメータ: - -* `model` (string) モデル名 -* `credentials` (object) クレデンシャル情報 -クレデンシャル情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。 -* `query` (string) クエリリクエストの内容 -* `docs` (array\[string]) リランキングが必要なドキュメント(チャンク)のリスト -* `score_threshold` (float) \[optional] スコアのしきい値 -* `top_n` (int) \[optional] 上位n個のドキュメント(チャンク)を取得 -* `user` (string) \[optional] ユーザーの一意の識別子。プロバイダーが不正利用を監視および検出するのに役立ちます。 - - -* 返り値: - -[RerankResult](#rerankresult) エンティティ。 - -#### Speech2text - -`__base.speech2text_model.Speech2TextModel` ベースクラスを継承し、以下のインターフェースを実装します: - - -* Invoke 呼び出し - -```python -def _invoke(self, model: str, credentials: dict, - file: IO[bytes], user: Optional[str] = None) \ - -> str: - """ - 音声テキスト変換モデルを呼び出します - - :param model: モデル名 - :param credentials: モデルのクレデンシャル - :param file: 音声ファイル - :param user: 一意のユーザーID - :return: 指定された音声ファイルに対するテキスト - """ -``` - -* パラメータ: - -* `model` (string) モデル名 -* `credentials` (object) クレデンシャル情報 -クレデンシャル情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。 -* `file` (File) ファイルストリーム -* `user` (string) \[optional] ユーザーの一意の識別子。プロバイダーが不正利用を監視および検出するのに役立ちます。 - -* 返り値: - -音声変換された文字列。 - -#### Text2speech - -`__base.text2speech_model.Text2SpeechModel` ベースクラスを継承し、以下のインターフェースを実装します: - -* Invoke 呼び出し - -```python -def _invoke(self, model: str, credentials: dict, content_text: str, streaming: bool, user: Optional[str] = None): - """ - 大規模言語モデルを呼び出します - - :param model: モデル名 - :param credentials: モデルの認証情報 - :param content_text: 変換するテキストコンテンツ - :param streaming: 出力がストリーミングであるか - :param user: 一意のユーザーID - :return: 変換された音声ファイル - """ -``` - -* パラメータ: - -* `model` (string) モデル名 -* `credentials` (object) 認証情報 -認証情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。 -* `content_text` (string) 変換が必要なテキストコンテンツ -* `streaming` (bool) ストリーミング出力を行うかどうか -* `user` (string) \[optional] ユーザーの一意の識別子 -プロバイダーが不正利用を監視および検出するのに役立ちます。 - -* 戻り値: - -テキスト変換後の音声ストリーム。 - - -#### Moderation - -`__base.moderation_model.ModerationModel` ベースクラスを継承し、以下のインターフェースを実装します: - -* Invoke 呼び出し - -```python -def _invoke(self, model: str, credentials: dict, - text: str, user: Optional[str] = None) \ - -> bool: - """ - 大規模言語モデルを呼び出します - - :param model: モデル名 - :param credentials: モデルの認証情報 - :param text: モデレーションするテキスト - :param user: 一意のユーザーID - :return: テキストが安全な場合はfalse、それ以外の場合はtrue - """ -``` - -* パラメータ: - -* `model` (string) モデル名 -* `credentials` (object) 認証情報 -認証情報のパラメータは、プロバイダーのYAML設定ファイルの `provider_credential_schema` または `model_credential_schema` で定義され、`api_key` などが渡されます。 -* `text` (string) テキストコンテンツ -* `user` (string) \[optional] ユーザーの一意の識別子 -プロバイダーが不正利用を監視および検出するのに役立ちます。 - - -* 戻り値: - -Falseは渡されたテキストが安全であることを示し、Trueはその逆を示します。 - -### エンティティ - -#### PromptMessageRole - -メッセージロール - -```python -class PromptMessageRole(Enum): - """ - プロンプトメッセージのEnumクラス。 - """ - SYSTEM = "system" - USER = "user" - ASSISTANT = "assistant" - TOOL = "tool" -``` - -#### PromptMessageContentType - -メッセージコンテントタイプ。プレーンテキストと画像に分かれます。 - -```python -class PromptMessageContentType(Enum): - """ - プロンプトメッセージコンテントタイプのEnumクラス。 - """ - TEXT = 'text' - IMAGE = 'image' -``` - -#### PromptMessageContent - -メッセージコンテントのベースクラス。パラメータ宣言専用であり、初期化できません。 - -```python -class PromptMessageContent(BaseModel): - """ - プロンプトメッセージコンテントのモデルクラス。 - """ - type: PromptMessageContentType - data: str # コンテンツデータ -``` - -現在、テキストと画像の2つのタイプをサポートしており、テキストと複数の画像を同時に渡すことができます。 -それぞれ `TextPromptMessageContent` と `ImagePromptMessageContent` を初期化して渡す必要があります。 - -#### TextPromptMessageContent - -```python -class TextPromptMessageContent(PromptMessageContent): - """ - テキストプロンプトメッセージコンテントのモデルクラス。 - """ - type: PromptMessageContentType = PromptMessageContentType.TEXT -``` - -画像とテキストを渡す場合、その中のテキストはこのエンティティを `content` リストの一部として構築する必要があります。 - -#### ImagePromptMessageContent - -```python -class ImagePromptMessageContent(PromptMessageContent): - """ - 画像プロンプトメッセージコンテントのモデルクラス。 - """ - class DETAIL(Enum): - LOW = 'low' - HIGH = 'high' - - type: PromptMessageContentType = PromptMessageContentType.IMAGE - detail: DETAIL = DETAIL.LOW # 解像度 -``` - -画像とテキストを渡す場合、その中の画像はこのエンティティを `content` リストの一部として構築する必要があります。 -`data` は `url` または画像の `base64` エンコードされた文字列です。 - -#### PromptMessage - -すべてのRoleメッセージボディのベースクラス。パラメータ宣言専用であり、初期化できません。 - -```python -class PromptMessage(ABC, BaseModel): - """ - プロンプトメッセージのモデルクラス。 - """ - role: PromptMessageRole # メッセージロール - content: Optional[str | list[PromptMessageContent]] = None # 文字列とコンテントリストの2つのタイプをサポートします。コンテントリストはマルチモーダルのニーズを満たすためのもので、詳細は `PromptMessageContent` の説明を参照してください。 - name: Optional[str] = None # 名称、オプション。 -``` - -#### UserPromptMessage - -UserMessageメッセージボディ。ユーザーメッセージを表します。 - -```python -class UserPromptMessage(PromptMessage): - """ - ユーザープロンプトメッセージのモデルクラス。 - """ - role: PromptMessageRole = PromptMessageRole.USER -``` - -#### AssistantPromptMessage - -モデルの返信メッセージを表します。通常、`few-shots` またはチャット履歴の入力に使用されます。 - -```python -class AssistantPromptMessage(PromptMessage): - """ - アシスタントプロンプトメッセージのモデルクラス。 - """ - class ToolCall(BaseModel): - """ - アシスタントプロンプトメッセージツールコールのモデルクラス。 - """ - class ToolCallFunction(BaseModel): - """ - アシスタントプロンプトメッセージツールコール関数のモデルクラス。 - """ - name: str # ツール名 - arguments: str # ツールパラメータ - - id: str # ツールID。OpenAI の tool call のみで有効で、ツールの呼び出しの一意のIDです。同じツールを複数回呼び出すことができます。 - type: str # デフォルトは function - function: ToolCallFunction # ツール呼び出し情報 - - role: PromptMessageRole = PromptMessageRole.ASSISTANT - tool_calls: list[ToolCall] = [] # モデルが応答したツール呼び出し結果(tools が渡され、かつモデルがツールの呼び出しが必要だと判断した場合にのみ返されます) -``` - -この `tool_calls` は、モデルを呼び出す際に `tools` を渡した後、モデルから返される `tool call` のリストです。 - -#### SystemPromptMessage - -システムメッセージを表します。通常、モデルに設定するシステム指示に使用されます。 - -```python -class SystemPromptMessage(PromptMessage): - """ - システムプロンプトメッセージのモデルクラス。 - """ - role: PromptMessageRole = PromptMessageRole.SYSTEM -``` - -#### ToolPromptMessage - -ツールメッセージを表します。ツールの実行後に結果をモデルに渡し、次のステップを計画するために使用されます。 - -```python -class ToolPromptMessage(PromptMessage): - """ - ツールプロンプトメッセージのモデルクラス。 - """ - role: PromptMessageRole = PromptMessageRole.TOOL - tool_call_id: str # ツール呼び出しID。OpenAI tool call をサポートしていない場合、ツール名を渡すこともできます。 -``` - -ベースクラスの `content` にツールの実行結果を渡します。 - -#### PromptMessageTool - -```python -class PromptMessageTool(BaseModel): - """ - プロンプトメッセージツールのモデルクラス。 - """ - name: str # ツール名 - description: str # ツールの説明 - parameters: dict # ツールパラメータのdict - -``` - -*** - -#### LLMResult - -```python -class LLMResult(BaseModel): - """ - LLM結果のモデルクラス。 - """ - model: str # 実際に使用されたモデル - prompt_messages: list[PromptMessage] # プロンプトメッセージのリスト - message: AssistantPromptMessage # 返信メッセージ - usage: LLMUsage # 使用されたトークンおよび料金情報 - system_fingerprint: Optional[str] = None # リクエストフィンガープリント。OpenAI の当該パラメータ定義を参照できます。 -``` - -#### LLMResultChunkDelta - -ストリーミングレスポンスにおける各イテレーション内部の `delta` エンティティ - -```python -class LLMResultChunkDelta(BaseModel): - """ - LLM結果チャンクデルタのモデルクラス。 - """ - index: int # シーケンス番号 - message: AssistantPromptMessage # 返信メッセージ - usage: Optional[LLMUsage] = None # 使用されたトークンおよび料金情報。最後のメッセージでのみ返されます。 - finish_reason: Optional[str] = None # 終了理由。最後のメッセージでのみ返されます。 -``` - -#### LLMResultChunk - -ストリーミングレスポンスにおける各イテレーションのエンティティ - -```python -class LLMResultChunk(BaseModel): - """ - LLM結果チャンクのモデルクラス。 - """ - model: str # 実際に使用されたモデル - prompt_messages: list[PromptMessage] # プロンプトメッセージのリスト - system_fingerprint: Optional[str] = None # リクエストフィンガープリント。OpenAI の当該パラメータ定義を参照できます。 - delta: LLMResultChunkDelta # 各イテレーションで変化のある内容 -``` - -#### LLMUsage - -```python -class LLMUsage(ModelUsage): - """ - LLM使用量のモデルクラス。 - """ - prompt_tokens: int # プロンプト使用トークン数 - prompt_unit_price: Decimal # プロンプト単価 - prompt_price_unit: Decimal # プロンプト価格単位(単価が何トークンに基づいているか) - prompt_price: Decimal # プロンプト料金 - completion_tokens: int # 返信使用トークン数 - completion_unit_price: Decimal # 返信単価 - completion_price_unit: Decimal # 返信価格単位(単価が何トークンに基づいているか) - completion_price: Decimal # 返信料金 - total_tokens: int # 総使用トークン数 - total_price: Decimal # 総料金 - currency: str # 通貨単位 - latency: float # リクエスト遅延(秒) -``` - -*** - -#### TextEmbeddingResult - -```python -class TextEmbeddingResult(BaseModel): - """ - テキスト埋め込み結果のモデルクラス。 - """ - model: str # 実際に使用されたモデル - embeddings: list[list[float]] # embeddingベクトルリスト。渡された texts リストに対応します。 - usage: EmbeddingUsage # 使用情報 -``` - -#### EmbeddingUsage - -```python -class EmbeddingUsage(ModelUsage): - """ - 埋め込み使用量のモデルクラス。 - """ - tokens: int # 使用トークン数 - total_tokens: int # 総使用トークン数 - unit_price: Decimal # 単価 - price_unit: Decimal # 価格単位(単価が何トークンに基づいているか) - total_price: Decimal # 総料金 - currency: str # 通貨単位 - latency: float # リクエスト遅延(秒) -``` - -*** - -#### RerankResult - -```python -class RerankResult(BaseModel): - """ - Rerank結果のモデルクラス。 - """ - model: str # 実際に使用されたモデル - docs: list[RerankDocument] # リランキング後のドキュメントリスト -``` - -#### RerankDocument - -```python -class RerankDocument(BaseModel): - """ - Rerankドキュメントのモデルクラス。 - """ - index: int # 元のシーケンス番号 - text: str # ドキュメントのテキスト内容 - score: float # スコア -``` - -## 関連リソース - -- [モデル設計ルール](/plugin-dev-ja/0411-model-designing-rules) - モデル設定の仕様を理解する -- [モデルプラグイン紹介](/plugin-dev-ja/0131-model-plugin-introduction.ja) - モデルプラグインの基本概念を素早く理解する -- [新しいモデルへの迅速な接続](/plugin-dev-ja/0211-getting-started-new-model) - 既存のプロバイダーに新しいモデルを追加する方法を学ぶ -- [新規モデルプロバイダーの作成](/plugin-dev-ja/0222-creating-new-model-provider) - 全く新しいモデルプロバイダーを開発する方法を学ぶ - -{/* -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/0412-model-schema.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0431-example-overview-and-index.mdx b/plugin-dev-ja/0431-example-overview-and-index.mdx deleted file mode 100644 index 0ca294f5..00000000 --- a/plugin-dev-ja/0431-example-overview-and-index.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: beginner -standard_title: Example Overview and Index -language: ja -title: 開発示例目録 ---- - - - - tool-plugin - - - extension-plugin - - - -{/* -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/0431-example-overview-and-index.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0432-develop-a-slack-bot-plugin.mdx b/plugin-dev-ja/0432-develop-a-slack-bot-plugin.mdx deleted file mode 100644 index 9087ec68..00000000 --- a/plugin-dev-ja/0432-develop-a-slack-bot-plugin.mdx +++ /dev/null @@ -1,357 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: intermediate -standard_title: Develop A Slack Bot Plugin -language: ja -title: Slack Bot プラグインの開発 -description: このドキュメントでは、プロジェクトの初期化、設定フォームの編集、機能コードの実装、プラグインのデバッグ、エンドポイントの設定、効果検証からパッケージ化、リリースまでの完全なSlack - Botプラグイン開発ガイドを提供します。Slackプラットフォーム上でAI駆動のチャットボットを構築するために、Difyプラグインスキャフォールディングツールと作成済みのSlack - Appが必要です。 ---- - -**本稿では、次のことをお手伝いします。** - -Slack Bot の構築方法を深く理解し、AI 駆動の Slack チャットボットを作成し、 Slack プラットフォームでユーザーの質問にインテリジェントに応答します。プラグイン開発の経験がない場合は、まず[プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-tool)を読むことをお勧めします。 - -### プロジェクトの背景 - -Dify プラグインエコシステムは、よりシンプルで使いやすいアクセス方法のサポートに取り組んでいます。本稿では Slack を例に、Slack Bot プラグインの開発方法を詳しく説明し、チームメンバーが Slack プラットフォーム内で直接 LLM と対話し、AI サービスの使用効率を向上させるのに役立ちます。 - -Dify プラグインエコシステムは、よりシンプルで便利なアクセス方法を提供することを目指しています。本稿では Slack を例に、Slack Bot プラグインの開発方法を詳細に解説し、チームメンバーが Slack プラットフォームで直接 AI アプリケーションを使用し、業務効率を向上させるのに役立ちます。 - -Slack は、自由でオープンなリアルタイムオフィスコミュニケーションプラットフォームであり、豊富な API を備えています。その中でも、イベントベースの Webhook 機能は開発に着手しやすいです。このメカニズムを利用して Slack Bot プラグインを作成します。その原理は下図の通りです。 - -![Slack Bot の原理図](https://assets-docs.dify.ai/2025/01/a0865d18f1ca4051601ca53fa6f92db2.png) - -> 混乱を避けるため、以下の概念について説明します。 -> -> * **Slack Bot** は Slack プラットフォーム上のチャットボットであり、仮想キャラクターと見なすことができ、チャットで対話することができます。 -> * **Slack Bot プラグイン**とは、Dify Marketplace 上のプラグインで、Dify アプリケーションと Slack プラットフォームを接続するために使用されます。本稿では、主にこのプラグイン開発について説明します。 - -**原理の概要:** - -1. **Slack Bot にメッセージを送信** - - ユーザーが Slack で Bot にメッセージを送信すると、Slack Bot は Dify プラットフォームに Webhook リクエストを送信します。 -2. **メッセージを Slack Bot プラグインに転送** - - ユーザーが Slack bot と対話する際、メッセージを Dify アプリケーションに転送する必要があります。メールシステムが受信者のメールアドレスを必要とするように、Slack の API を介して Slack Webhook のアドレスを設定し、それを Slack Bot プラグインに入力して接続を確立することができます。 -3. **プラグインがメッセージを受信後、特定の Dify アプリケーションに返す** - - Slack Bot プラグインは Slack リクエストを処理し、Dify 内のアプリケーションに送信します。LLM がユーザーの入力内容を分析し、応答します。 -4. **Dify アプリケーションが応答後、メッセージを Slack Bot に返し、ユーザーに回答する** - - Slack Bot は Dify アプリケーションの応答を取得後、プラグインを介してメッセージを元の経路で Slack Bot に返し、ユーザーが Slack を使用しながら直接 Dify アプリケーションと対話できるようにします。 - -### 事前準備 - -* Dify プラグインスキャフォールディングツール。詳細については、[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools)を参照してください。 -* Python 環境、バージョン番号 ≥ 3.12。詳細については、[Python インストールチュートリアル](https://pythontest.com/python/installing-python-3-11/)を参照するか、LLM に完全なインストールチュートリアルを問い合わせてください。 -* Slack App を作成し、OAuth トークンを取得する - -[Slack API](https://api.slack.com/apps) プラットフォームにアクセスし、scratch 方式で Slack APP を作成し、アプリケーションをデプロイする Slack スペースを選択します。 - -![Slack API トークン](https://assets-docs.dify.ai/2025/01/8217c23ee16c47c586a1387a442ea6f0.png) - -Webhooks 機能を有効にします。 - -![Webhooks 機能を有効にする](https://assets-docs.dify.ai/2025/01/fc9d7797608422219a01248f7151fc81.png) - -App を Slack ワークスペースにインストールします。 - -![ワークスペースにインストール](https://assets-docs.dify.ai/2025/01/6ab7226078f88853fc7f4d3520245d63.png) - -OAuth トークンを取得し、後続のプラグイン開発に使用します。 - -![OAuth トークンを取得](https://assets-docs.dify.ai/2025/01/f08052044c8c17eebbffacdc9b2558e6.png) - -### 1. プラグインの開発 - -ここから実際のプラグインコーディング作業を開始します。開始する前に、[Extension プラグインの開発](/plugin-dev-ja/9231-extension-plugin)を読んだか、Dify プラグインを一度開発したことがあることを確認してください。 - -#### プロジェクトの初期化 - -以下のコマンドを実行してプラグイン開発プロジェクトを初期化します。 - -```bash -dify plugin init -``` - -プロンプトに従ってプロジェクトの基本情報を入力し、`extension` テンプレートを選択し、`Apps` と `Endpoints` の 2 つの権限を付与します。 - -プラグインが Dify プラットフォームの機能を逆引き呼び出しする方法の詳細については、[逆引き呼び出し](/plugin-dev-ja/9241-reverse-invocation)を参照してください。 - -![プラグイン権限](https://assets-docs.dify.ai/2024/12/d89a6282c5584fc43a9cadeddf09c0de.png) - -#### 1. 設定フォームの編集 - -このプラグインでは、どの Dify の App を使用して返信するかを指定する必要があり、返信する際には Slack の App token を使用する必要があるため、プラグインフォームにこれらの 2 つのフィールドを追加する必要があります。 - -group パス以下の yaml ファイルを変更します。例:`group/slack.yaml`。フォーム設定ファイルの名前は、プラグイン作成時に記入した基本情報によって決まります。対応する yaml ファイルを変更できます。 - -**サンプルコード:** - -`slack.yaml` - -```yaml -settings: - - name: bot_token - type: secret-input - required: true - label: - en_US: Bot Token - zh_Hans: Bot Token - pt_BR: Token do Bot - ja_JP: Bot Token - placeholder: - en_US: Please input your Bot Token - zh_Hans: 请输入你的 Bot Token - pt_BR: Por favor, insira seu Token do Bot - ja_JP: ボットトークンを入力してください - - name: allow_retry - type: boolean - required: false - label: - en_US: Allow Retry - zh_Hans: 允许重试 - pt_BR: Permitir Retentativas - ja_JP: 再試行を許可 - default: false - - name: app - type: app-selector - required: true - label: - en_US: App - zh_Hans: 应用 - pt_BR: App - ja_JP: アプリ - placeholder: - en_US: the app you want to use to answer Slack messages - zh_Hans: 你想要用来回答 Slack 消息的应用 - pt_BR: o app que você deseja usar para responder mensagens do Slack - ja_JP: あなたが Slack メッセージに回答するために使用するアプリ -endpoints: - - endpoints/slack.yaml -``` - -コードデータ構造の説明: - -``` - - name: app - type: app-selector - scope: chat -``` - -* `type` フィールドは `app-selector` フィールドとして指定されます。 - - ユーザーはプラグイン使用時に特定の Dify アプリケーションにアクセスし、メッセージ転送を行うことができます。 -* `scope` フィールドは `chat` フィールドとして指定されます。 - - `agent`、`chatbot`、`chatflow` などのタイプのアプリのみ使用できます。 - -最後に `endpoints/slack.yaml` ファイル内のリクエストパスとリクエストメソッドを変更し、method を POST 方式に変更する必要があります。 - -**サンプルコード:** - -`endpoints/slack.yaml` - -```yaml -path: "/" -method: "POST" -extra: - python: - source: "endpoints/slack.py" -``` - -#### 2. 機能コードの編集 - -`endpoints/slack.py` ファイルを変更し、以下のコードを追加します。 - -````python -import json -import traceback -from typing import Mapping -from werkzeug import Request, Response -from dify_plugin import Endpoint -from slack_sdk import WebClient -from slack_sdk.errors import SlackApiError - - -class SlackEndpoint(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - """ - Invokes the endpoint with the given request. - """ - retry_num = r.headers.get("X-Slack-Retry-Num") - if (not settings.get("allow_retry") and (r.headers.get("X-Slack-Retry-Reason") == "http_timeout" or ((retry_num is not None and int(retry_num) > 0)))): - return Response(status=200, response="ok") - data = r.get_json() - - # Handle Slack URL verification challenge - if data.get("type") == "url_verification": - return Response( - response=json.dumps({"challenge": data.get("challenge")}), - status=200, - content_type="application/json" - ) - - if (data.get("type") == "event_callback"): - event = data.get("event") - if (event.get("type") == "app_mention"): - message = event.get("text", "") - if message.startswith("<@"): - message = message.split("> ", 1)[1] if "> " in message else message - channel = event.get("channel", "") - blocks = event.get("blocks", []) - blocks[0]["elements"][0]["elements"] = blocks[0].get("elements")[0].get("elements")[1:] - token = settings.get("bot_token") - client = WebClient(token=token) - try: - response = self.session.app.chat.invoke( - app_id=settings["app"]["app_id"], - query=message, - inputs={}, - response_mode="blocking", - ) - try: - blocks[0]["elements"][0]["elements"][0]["text"] = response.get("answer") - result = client.chat_postMessage( - channel=channel, - text=response.get("answer"), - blocks=blocks - ) - return Response( - status=200, - response=json.dumps(result), - content_type="application/json" - ) - except SlackApiError as e: - raise e - except Exception as e: - err = traceback.format_exc() - return Response( - status=200, - response="Sorry, I'm having trouble processing your request. Please try again later." + str(err), - content_type="text/plain", - ) - else: - return Response(status=200, response="ok") - else: - return Response(status=200, response="ok") - else: - return Response(status=200, response="ok") - -``` -```` - -テストを容易にするため、プラグイン機能は現在ユーザーの入力内容を繰り返すことしかできず、Dify app の呼び出しは一時的に行いません。 - -### 2. プラグインのデバッグ - -Dify プラットフォームにアクセスし、Dify プラグインのリモートデバッグ接続アドレスとキーを取得します。 - -![プラグインのテスト](https://assets-docs.dify.ai/2025/01/8d24006f0cabf5bf61640a9023c45db8.png) - -プラグインプロジェクトに戻り、`.env.example` ファイルをコピーして `.env` に名前を変更します。 - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -`python -m main` コマンドを実行してプラグインを起動します。プラグインページで、このプラグインがワークスペースにインストールされていることが確認できます。他のチームメンバーもこのプラグインにアクセスできます。 - -```bash -python -m main -``` - -#### プラグインのエンドポイントを設定 - -Dify のプラグイン管理ページで、自動インストールされたテストプラグインを見つけ、新しいエンドポイントを作成し、名前、Bot token を入力し、接続するアプリを選択します。 - -![POST リクエストアドレスの生成](https://assets-docs.dify.ai/2025/01/e6952a5798a7ae793b3fe7df6f76ea73.png) - -保存後、POST リクエストアドレスが生成されます。 - -![POST リクエストアドレスの生成](https://assets-docs.dify.ai/2025/01/e6952a5798a7ae793b3fe7df6f76ea73.png) - -次に、Slack App の設定を完了する必要があります。 - -1. Event サブスクリプションを有効にする - -![Event サブスクリプションを有効にする](https://assets-docs.dify.ai/2025/01/1d33bb9cde78a1b5656ad6a0b8350195.png) - -上記で生成されたプラグインの POST リクエストアドレスを貼り付けます。 - -![生成されたプラグイン POST リクエストアドレスを貼り付け](https://assets-docs.dify.ai/2025/01/65aa41f37c3800af49e944f9ff28e121.png) - -Slack App が持つべき権限にチェックを入れます。 - -![Slack App に必要な権限を選択](https://assets-docs.dify.ai/2025/01/25c38a2cf10ec6c55ae54970d790f37e.png) - -### 3. プラグイン効果の検証 - -コードは `self.session.app.chat.invoke` を使用して Dify プラットフォーム内の App を呼び出し、`app_id` や `query` などの情報を渡し、最後にレスポンスの内容を Slack Bot に返します。`python -m main` コマンドを実行してプラグインを再起動してデバッグし、Slack Bot が Dify App の応答メッセージを正しく出力できるか確認します。 - -![POST リクエストアドレスの生成](https://assets-docs.dify.ai/2025/01/e6952a5798a7ae793b3fe7df6f76ea73.png) - -### 4. プラグインのパッケージ化(オプション) - -プラグインが正常に動作することを確認した後、以下のコマンドラインツールを使用してプラグインをパッケージ化し、名前を付けることができます。実行後、現在のフォルダに `slack_bot.difypkg` ファイルが見つかります。これが最終的なプラグインパッケージです。パッケージ化の詳細な手順については、[ローカルファイルとしてパッケージ化して共有](/plugin-dev-ja/0322-release-by-file)を参照してください。 - -```bash -# ./slack_bot を実際のプラグインプロジェクトパスに置き換えてください。 -dify plugin package ./slack_bot -``` - -おめでとうございます。これでプラグインの完全な開発、テスト、パッケージ化プロセスが完了しました! - -### 5. プラグインの公開(オプション) - -これで、[Dify Marketplace リポジトリ](https://github.com/langgenius/dify-plugins)にアップロードしてプラグインを公開できます!ただし、公開する前に、プラグインが[Dify Marketplace への公開](/plugin-dev-ja/0322-release-to-dify-marketplace)の規範に従っていることを確認してください。 - -## 関連リソース - -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - Difyプラグイン開発の全体像を理解する -- [プラグイン開発入門ガイド](/plugin-dev-ja/0211-getting-started-dify-tool) - ゼロからプラグインを開発する -- [Extension プラグインの開発](/plugin-dev-ja/9231-extension-plugin) - 拡張プラグイン開発を理解する -- [Dify サービスの逆引き呼び出し](/plugin-dev-ja/9241-reverse-invocation) - Dify プラットフォームの機能を呼び出す方法を理解する -- [App の逆引き呼び出し](/plugin-dev-ja/9242-reverse-invocation-app) - プラットフォーム内の App を呼び出す方法を理解する -- [プラグインの公開](/plugin-dev-ja/0321-release-overview) - 公開プロセスを学ぶ -- [Dify Marketplace への公開](/plugin-dev-ja/0322-release-to-dify-marketplace) - マーケットプレイス公開ガイド -- [エンドポイントの詳細定義](/plugin-dev-ja/0432-endpoint) - エンドポイントの詳細定義 - -### 参考文献 - -完全な Dify プラグインのプロジェクトコードを確認したい場合は、[GitHub コードリポジトリ](https://github.com/langgenius/dify-plugins)にアクセスしてください。その他、他のプラグインの完全なコードと詳細を確認できます。 - -さらに多くのプラグインについて知りたい場合は、以下の内容を参照してください。 - -**クイックスタート:** - -* [Extension プラグインの開発](/plugin-dev-ja/9231-extension-plugin) -* [Model プラグインの開発](/plugin-dev-ja/0211-getting-started-new-model) -* [Bundle タイププラグイン:複数のプラグインをパッケージ化](/plugin-dev-ja/9241-bundle) - -**プラグインインターフェースドキュメント:** - -* [マニフェストファイルによるプラグイン情報の定義](/plugin-dev-ja/0411-plugin-info-by-manifest) - マニフェスト構造 -* [エンドポイント](/plugin-dev-ja/0432-endpoint) - エンドポイントの詳細定義 -* [逆引き呼び出し](/plugin-dev-ja/9241-reverse-invocation) - Dify 機能の逆引き呼び出し -* [共通仕様](/plugin-dev-ja/0411-general-specifications) - ツール仕様 -* [モデルアーキテクチャ](/plugin-dev-ja/0412-model-schema) - モデル - -{/* -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/0432-develop-a-slack-bot-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/0432-endpoint.mdx b/plugin-dev-ja/0432-endpoint.mdx deleted file mode 100644 index 1138ec16..00000000 --- a/plugin-dev-ja/0432-endpoint.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: intermediate -standard_title: Endpoint -language: ja -title: レインボーキャットプロジェクト Endpoint(エンドポイント) -description: 著者 Yeuoly、Allen このドキュメントでは、レインボーキャットプロジェクトを例に、DifyプラグインにおけるEndpointの構造と実装方法を詳しく説明します。内容には、Endpointグループの定義方法、インターフェースの設定、_invokeメソッドの実装、リクエストとレスポンスの処理が含まれます。このドキュメントでは、さまざまなYAML設定フィールドの意味と使用方法について詳しく説明します。 ---- - ---- -title: Endpoint(エンドポイント) ---- - -この記事では、プラグイン内のエンドポイントの構造を説明するために、[クイックスタート:レインボーキャットプロジェクト](/ja-jp/plugins/quick-start/develop-plugins/extension-plugin)を例として取り上げます。完全なプラグインコードは、[GitHub](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko)で確認できます。 - -### **グループの定義** - -`Endpoint`グループは、複数の`Endpoint`をまとめたものです。`Dify`プラグインで新しい`Endpoint`を作成する際には、以下の設定項目を入力する必要があります。 - - - -「Endpoint Name」の他に、グループ構成情報を記述することで、新しいフォーム項目を追加できます。保存すると、同じ構成情報を使用する複数のインターフェースが表示されるようになります。 - - - -#### **構造** - -* `settings` (map\[string] [ProviderConfig](/ja-jp/plugins/schema-definition/general-specifications)): エンドポイントの設定定義 -* `endpoints` (list\[string], required): 特定の`endpoint`インターフェース定義を指定します。 - -```yaml -settings: - api_key: - type: secret-input - required: true - label: - en_US: API key - zh_Hans: API key - ja_Jp: API key - pt_BR: API key - placeholder: - en_US: Please input your API key - zh_Hans: 请输入你的 API key - ja_Jp: あなたの API key を入れてください - pt_BR: Por favor, insira sua chave API -endpoints: - - endpoints/duck.yaml - - endpoints/neko.yaml -``` - -### **インターフェース定義** - -* `path` (string): werkzeugのインターフェース標準に従います。 -* `method` (string): インターフェースのメソッド。`HEAD` `GET` `POST` `PUT` `DELETE` `OPTIONS`のみをサポートします。 -* `extra` (object): 基本情報以外の設定情報 - * `python` (object) - * `source` (string): このインターフェースを実装するソースコード - -```yaml -path: "/duck/" -method: "GET" -extra: - python: - source: "endpoints/duck.py" -``` - -### エンドポイントの実装 - -`dify_plugin.Endpoint`を継承したサブクラスを実装し、`_invoke`メソッドを実装する必要があります。 - -* **入力パラメータ** - * `r` (Request): werkzeugからのリクエストオブジェクト - * `values` (Mapping): パスから解析されたパスパラメータ - * `settings` (Mapping): このエンドポイントの設定情報 -* **戻り値** - * werkzeugからのレスポンスオブジェクト。ストリーミングでの応答をサポートします。 - * 直接的な文字列の戻り値はサポートしません。 - -**コード例:** - -```python -import json -from typing import Mapping -from werkzeug import Request, Response -from dify_plugin import Endpoint - -class Duck(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - """ - Invokes the endpoint with the given request. - """ - app_id = values["app_id"] - def generator(): - yield f"{app_id}
" - return Response(generator(), status=200, content_type="text/html") -``` - -{/* -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/0432-endpoint.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9231-extension-plugin.mdx b/plugin-dev-ja/9231-extension-plugin.mdx deleted file mode 100644 index cd6af96f..00000000 --- a/plugin-dev-ja/9231-extension-plugin.mdx +++ /dev/null @@ -1,292 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: high - level: beginner -standard_title: Extension Plugin -language: ja -title: Extension 插件 -description: 本文档提供了开发Extension类型插件的完整教程,详细介绍了环境准备、创建项目、定义插件请求入口、编写功能代码、调试、打包发布等全过程。示例项目是一个彩虹猫插件,展示了如何通过Extension插件处理HTTP请求并提供网页服务。 ---- - -本文将引导你快速开发一个 Extension 类型的插件,以帮助你了解插件开发的基础流程。 - -### 前置准备 - -* Dify 插件脚手架工具 -* Python 环境,版本号 ≥ 3.12 - -关于如何准备插件开发的脚手架工具,详细说明请参考[初始化开发工具](initialize-development-tools.md)。 - -### 创建新项目 - -在当前路径下,运行脚手架命令行工具,创建一个新的 dify 插件项目。 - -``` -./dify-plugin-darwin-arm64 plugin init -``` - -如果你已将该二进制文件重命名为了 `dify` 并拷贝到了 `/usr/local/bin` 路径下,可以运行以下命令创建新的插件项目: - -```bash -dify plugin init -``` - -#### 1. 填写插件信息 - -按照提示配置插件名称、作者信息与插件描述。如果你是团队协作,也可以将作者填写为组织名。 - -> 插件名称长度必须为 1-128 个字符,并且只能包含字母、数字、破折号和下划线。 - -![Plugins details](https://assets-docs.dify.ai/2024/12/75cfccb11fe31c56c16429b3998f2eb0.png) - -填写完成后,在插件开发语言环节中选择 Python。 - -![Plugins development: Python](https://assets-docs.dify.ai/2024/11/1129101623ac4c091a3f6f75f4103848.png) - -#### 2. 选择插件类型并初始化项目模板 - -脚手架工具内的所有模板均已提供完整的代码项目。出于演示说明,本文将以 `Extension` 类型插件模板作为示例。对于已熟悉插件的开发者而言,无需借助模板,可参考[接口文档](../../schema-definition/)指引完成不同类型的插件开发。 - -![Extension](https://assets-docs.dify.ai/2024/11/ff08f77b928494e10197b456fc4e2d5b.png) - -#### 3. 配置插件权限 - -插件还需要读取 Dify 主平台的权限才能正常连接。需要为该示例插件授予以下权限: - -* Tools -* LLMs -* Apps -* 启用持久化存储 Storage,分配默认大小存储 -* 允许注册 Endpoint - -> 在终端内使用方向键选择权限,使用 “Tab” 按钮授予权限。 - -勾选所有权限项后,轻点回车完成插件的创建。系统将自动生成插件项目代码。 - -![Plugins 权限](https://assets-docs.dify.ai/2024/11/5518ca1e425a7135f18f499e55d16bdd.png) - -插件的基础文件结构包含以下内容: - -``` -. -├── GUIDE.md -├── README.md -├── _assets -│ └── icon.svg -├── endpoints -│ ├── your-project.py -│ └── your-project.yaml -├── group -│ └── your-project.yaml -├── main.py -├── manifest.yaml -└── requirements.txt -``` - -* `GUIDE.md` 一个简短的引导教程,带领你完成插件的编写流程。 -* `README.md` 关于当前插件的简介信息,你需要把有关该插件的介绍和使用方法填写至该文件内。 -* `_assets` 存储所有与当前插件相关的多媒体文件。 -* `endpoints` 按照 cli 中的引导创建的一个 `Extension` 类型插件模板,该目录存放所有 Endpoint 的功能实现代码。 -* `group` 指定密钥类型、多语言设置以及 API 定义的文件路径。 -* `main.py` 整个项目的入口文件。 -* `manifest.yaml` 整个插件的基础配置文件,包含该插件需要什么权限、是什么类型的扩展等配置信息。 -* `requirements.txt` 存放 Python 环境的依赖项。 - -### 开发插件 - -#### 1. 定义插件的请求入口 Endpoint - -编辑 `endpoints/test_plugin.yaml` ,参考以下代码进行修改: - -```yaml -path: "/neko" -method: "GET" -extra: - python: - source: "endpoints/test_plugin.py" -``` - -该代码的意图是定义该插件的入口路径为 `/neko`,请求方法为 GET 类型。插件的功能实现代码为 `endpoints/test_plugin.py` 文件。 - -#### 2. 编写插件功能 - -插件功能:请求服务,输出一只彩虹猫。 - -编写插件的功能实现代码 `endpoints/test_plugin.py` 文件,参考以下示例代码: - -```python -from typing import Mapping -from werkzeug import Request, Response -from flask import Flask, render_template_string -from dify_plugin import Endpoint - -app = Flask(__name__) - -class NekoEndpoint(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - ascii_art = ''' -⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛⬛️⬜️⬜️⬜️⬜️⬜⬜️⬜️️ -🟥🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️🟥🟥🟥🟥🟥🟥🟥🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧⬛️⬜️⬜️⬜️⬜️⬜⬜️️ -🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥⬛️🥧🥧🥧💟💟💟💟💟💟💟💟💟💟💟💟💟🥧🥧🥧⬛️⬜️⬜️⬜️⬜⬜️️ -🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥⬛️🥧🥧💟💟💟💟💟💟🍓💟💟🍓💟💟💟💟💟🥧🥧⬛️⬜️⬜️⬜️⬜️⬜️️ -🟧🟧🟥🟥🟥🟥🟥🟥🟥🟥🟧🟧🟧🟧🟧🟧🟧🟧🟥🟥🟥🟥🟥🟥🟥⬛🥧💟💟🍓💟💟💟💟💟💟💟💟💟💟💟💟💟💟🥧⬛️⬜️⬜️⬜️⬜⬜️️ -🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬛️🥧💟💟💟💟💟💟💟💟💟💟⬛️⬛️💟💟🍓💟💟🥧⬛️⬜️⬛️️⬛️️⬜⬜️️ -🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬛️🥧💟💟💟💟💟💟💟💟💟⬛️🌫🌫⬛💟💟💟💟🥧⬛️⬛️🌫🌫⬛⬜️️ -🟨🟨🟧🟧🟧🟧🟧🟧🟧🟧🟨🟨🟨🟨🟨🟨🟨🟨🟧⬛️⬛️⬛️⬛️🟧🟧⬛️🥧💟💟💟💟💟💟🍓💟💟⬛️🌫🌫🌫⬛💟💟💟🥧⬛️🌫🌫🌫⬛⬜️️ -🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨⬛️🌫🌫⬛️⬛️🟧⬛️🥧💟💟💟💟💟💟💟💟💟⬛️🌫🌫🌫🌫⬛️⬛️⬛️⬛️🌫🌫🌫🌫⬛⬜️️ -🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨⬛️⬛️🌫🌫⬛️⬛️⬛️🥧💟💟💟🍓💟💟💟💟💟⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛⬜️️ -🟩🟩🟨🟨🟨🟨🟨🟨🟨🟨🟩🟩🟩🟩🟩🟩🟩🟩🟨🟨⬛⬛️🌫🌫⬛️⬛️🥧💟💟💟💟💟💟💟🍓⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛️ -🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬛️⬛️🌫🌫⬛️🥧💟🍓💟💟💟💟💟💟⬛️🌫🌫🌫⬜️⬛️🌫🌫🌫🌫🌫⬜️⬛️🌫🌫⬛️ -️🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬛️⬛️⬛️⬛️🥧💟💟💟💟💟💟💟💟⬛️🌫🌫🌫⬛️⬛️🌫🌫🌫⬛️🌫⬛️⬛️🌫🌫⬛️ -🟦🟦🟩🟩🟩🟩🟩🟩🟩🟩🟦🟦🟦🟦🟦🟦🟦🟦🟩🟩🟩🟩🟩🟩⬛️⬛️🥧💟💟💟💟💟🍓💟💟⬛🌫🟥🟥🌫🌫🌫🌫🌫🌫🌫🌫🌫🟥🟥⬛️ -🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛️🥧🥧💟🍓💟💟💟💟💟⬛️🌫🟥🟥🌫⬛️🌫🌫⬛️🌫🌫⬛️🌫🟥🟥⬛️ -🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛️🥧🥧🥧💟💟💟💟💟💟💟⬛️🌫🌫🌫⬛️⬛️⬛️⬛️⬛️⬛️⬛️🌫🌫⬛️⬜️ -🟪🟪🟦🟦🟦🟦🟦🟦🟦🟦🟪🟪🟪🟪🟪🟪🟪🟪🟦🟦🟦🟦🟦🟦⬛️⬛️⬛️🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛️⬜️⬜️ -🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪⬛️🌫🌫🌫⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬜️⬜️⬜️ -🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪⬛️🌫🌫⬛️⬛️⬜️⬛️🌫🌫⬛️⬜️⬜️⬜️⬜️⬜️⬛️🌫🌫⬛️⬜️⬛️🌫🌫⬛️⬜️⬜️⬜️⬜️ -⬜️⬜️🟪🟪🟪🟪🟪🟪🟪🟪⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️🟪🟪🟪🟪🟪⬛️⬛️⬛️⬛⬜️⬜️⬛️⬛️⬛️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️⬜️⬜️⬛️⬛️⬜️⬜️⬜️⬜️⬜️️ - ''' - ascii_art_lines = ascii_art.strip().split('\n') - with app.app_context(): - return Response(render_template_string(''' - - - - - - -
- - - - ''', ascii_art_lines=ascii_art_lines), status=200, content_type="text/html") -``` - -运行此代码需要先安装以下 Python 依赖包: - -```python -pip install werkzeug -pip install flask -pip install dify-plugin -``` - -### 调试插件 - -接下来需测试插件是否可以正常运行。Dify 提供远程调试方式,前往“插件管理”页获取调试 Key 和远程服务器地址。 - -![](https://assets-docs.dify.ai/2024/11/1cf15bc59ea10eb67513c8bdca557111.png) - -回到插件项目,拷贝 `.env.example` 文件并重命名为 `.env`,将获取的远程服务器地址和调试 Key 等信息填入其中。 - -`.env` 文件 - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -运行 `python -m main` 命令启动插件。在插件页即可看到该插件已被安装至 Workspace 内。其他团队成员也可以访问该插件。 - -![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) - -在插件内新增 Endpoint,随意填写名称和 `api_key` 等信息。访问自动生成的 URL,即可看到由插件提供的网页服务。 - -![](https://assets-docs.dify.ai/2024/11/c76375b8df2449d0d8c31a7c2a337579.png) - -### 打包插件 - -确认插件能够正常运行后,可以通过以下命令行工具打包并命名插件。运行以后你可以在当前文件夹发现 `neko.difypkg` 文件,该文件为最终的插件包。 - -```bash -dify plugin package ./neko -``` - -恭喜,你已完成一个插件的完整开发、测试打包过程! - -### 发布插件 - -现在可以将它上传至 [Dify Plugins 代码仓库](https://github.com/langgenius/dify-plugins) 来发布你的插件了!上传前,请确保你的插件遵循了[插件发布规范](https://docs.dify.ai/zh-hans/plugins/publish-plugins/publish-to-dify-marketplace)。审核通过后,代码将合并至主分支并自动上线至 [Dify Marketplace](https://marketplace.dify.ai/)。 - -### 探索更多 - -**快速开始:** - -* [Tool 插件:Google Search](tool-plugin.md) -* [Model 插件](model-plugin/) -* [Bundle 插件:将多个插件打包](bundle.md) - -**插件接口文档:** - -* [Manifest](../../schema-definition/manifest.md) 结构 -* [Endpoint](../../schema-definition/endpoint.md) 详细定义 -* [反向调用 Dify 能力](../../schema-definition/reverse-invocation-of-the-dify-service/) -* [工具](../../schema-definition/tool.md) -* [模型](../../schema-definition/model/) -* [扩展 Agent 策略](../../schema-definition/agent.md) - -**最佳实践:** - -[开发 Slack Bot 插件](../../best-practice/develop-a-slack-bot-plugin.md) - -{/* -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/9231-extension-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9232-agent.mdx b/plugin-dev-ja/9232-agent.mdx deleted file mode 100644 index 63f3c470..00000000 --- a/plugin-dev-ja/9232-agent.mdx +++ /dev/null @@ -1,437 +0,0 @@ ---- -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) - diff --git a/plugin-dev-ja/9241-bundle.mdx b/plugin-dev-ja/9241-bundle.mdx deleted file mode 100644 index 4e3a81e7..00000000 --- a/plugin-dev-ja/9241-bundle.mdx +++ /dev/null @@ -1,107 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: beginner -standard_title: Bundle -language: ja -title: Bundle プラグインパッケージ -description: 本ドキュメントでは、Bundle プラグインパッケージの概念および開発方法について解説します。Bundle プラグインパッケージは、複数のプラグインを一つに統合することができ、Marketplace - タイプ、GitHub タイプ、Package タイプの3種類をサポートしています。本ドキュメントでは、Bundle プロジェクトの作成、さまざまなタイプの依存関係の追加、および - Bundle プロジェクトのパッケージ化に至る全プロセスを詳細に説明します。 ---- - -Bundle プラグインパッケージは、複数のプラグインの集合です。これにより、複数のプラグインを単一のプラグイン内にパッケージ化し、プラグインの一括インストールを実現するとともに、より強力なサービスを提供できます。 - -Dify CLI ツールを使用して、複数のプラグインを Bundle としてパッケージ化できます。Bundle プラグインパッケージには、次の3つのタイプがあります。 - -* `Marketplace` タイプ。プラグインの ID とバージョン情報を保存します。インポート時には Dify Marketplace を通じて具体的なプラグインパッケージがダウンロードされます。 -* `GitHub` タイプ。GitHub のリポジトリURL、リリースバージョン番号、アセットファイル名を保存します。インポート時には Dify が対応する GitHub リポジトリにアクセスしてプラグインパッケージをダウンロードします。 -* `Package` タイプ。プラグインパッケージは Bundle 内に直接保存されます。参照元を保存しないため、Bundle パッケージのサイズが大きくなる可能性があります。 - -### 事前準備 - -* Dify プラグインスキャフォールディングツール -* Python 環境、バージョン ≥ 3.10 - -プラグイン開発用のスキャフォールディングツールの準備方法については、[開発ツールの初期化](initialize-development-tools.md)を参照してください。 - -### Bundle プロジェクトの作成 - -現在のパスで、スキャフォールディングコマンドラインツールを実行して、新しいプラグインパッケージプロジェクトを作成します。 - -```bash -./dify-plugin-darwin-arm64 bundle init -``` - -このバイナリファイルを `dify` にリネームし、`/usr/local/bin` パスにコピーした場合、次のコマンドを実行して新しいプラグインプロジェクトを作成できます。 - -```bash -dify bundle init -``` - -#### 1. プラグイン情報の入力 - -プロンプトに従って、プラグイン名、作成者情報、プラグインの説明を設定します。チームで作業している場合は、作成者として組織名を記入することもできます。 - -> 名称は1~128文字で、使用できる文字は英字、数字、ハイフン、アンダースコアのみです。 - -![Bundle の基本情報](https://assets-docs.dify.ai/2024/12/03a1c4cdc72213f09523eb1b40832279.png) - -情報を入力して Enter キーを押すと、Bundle プラグインプロジェクトディレクトリが自動的に作成されます。 - -![](https://assets-docs.dify.ai/2024/12/356d1a8201fac3759bf01ee64e79a52b.png) - -#### 2. 依存関係の追加 - -* **Marketplace** - -次のコマンドを実行します。 - -```bash -dify-plugin bundle append marketplace . --marketplace_pattern=langgenius/openai:0.0.1 -``` - -ここで、`marketplace_pattern` は Marketplace でのプラグイン参照であり、フォーマットは `組織名/プラグイン名:バージョン番号` です。 - -* **GitHub** - -次のコマンドを実行します。 - -```bash -dify-plugin bundle append github . --repo_pattern=langgenius/openai:0.0.1/openai.difypkg -``` - -ここで、`repo_pattern` は GitHub でのプラグイン参照であり、フォーマットは `組織名/リポジトリ名:release/アセットファイル名` です。 - -* **Package** - -次のコマンドを実行します。 - -```bash -dify-plugin bundle append package . --package_path=./openai.difypkg -``` - -ここで、`package_path` はプラグインパッケージのパスです。 - -### Bundle プロジェクトのパッケージ化 - -次のコマンドを実行して Bundle プラグインをパッケージ化します。 - -```bash -dify-plugin bundle package ./bundle -``` - -コマンドを実行すると、現在のディレクトリに `bundle.difybndl` ファイルが自動的に作成されます。このファイルが最終的なパッケージ結果です。 - -{/* -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/9241-bundle.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9241-reverse-invocation.mdx b/plugin-dev-ja/9241-reverse-invocation.mdx deleted file mode 100644 index b5438a94..00000000 --- a/plugin-dev-ja/9241-reverse-invocation.mdx +++ /dev/null @@ -1,46 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: beginner -standard_title: Reverse Invocation -language: ja -title: Difyサービスのリバース呼び出し -description: このドキュメントでは、Difyプラグインのリバース呼び出し機能について簡単に説明します。この機能は、プラグインがDifyメインプラットフォーム内の指定されたサービスを呼び出すことを可能にします。本文書では、呼び出し可能なモジュールとして、App(アプリデータへのアクセス)、Model(プラットフォーム内のモデル機能の呼び出し)、Tool(プラットフォーム内の他のツールプラグインの呼び出し)、Node(Chatflow/Workflowアプリケーション内のノード呼び出し)の4つのカテゴリをリストアップしています。 ---- - -プラグインは、Difyメインプラットフォーム内の一部のサービスを自由に呼び出し、プラグインの機能を向上させることができます。 - -### 呼び出し可能なDifyモジュール - -* [App](/plugin-dev-ja/9242-reverse-invocation-app) - - プラグインはDifyプラットフォーム内のアプリデータにアクセスできます。 -* [Model](/plugin-dev-ja/9242-reverse-invocation-model) - - プラグインはDifyプラットフォーム内のLLM機能をリバース呼び出しできます。これには、TTS、Rerankなど、プラットフォーム内のすべてのモデルタイプと機能が含まれます。 -* [Tool](/plugin-dev-ja/9242-reverse-invocation-tool) - - プラグインはDifyプラットフォーム内の他のツールタイプのプラグインを呼び出すことができます。 -* [Node](/plugin-dev-ja/9243-reverse-invocation-node) - - プラグインはDifyプラットフォーム内の特定のChatflow/Workflowアプリケーション内のノードを呼び出すことができます。 - -## 関連リソース - -- [Extensionプラグインの開発](/plugin-dev-ja/9231-extension-plugin) - 外部システムと統合するプラグインの開発方法を学びます -- [Slack Botプラグインの開発](/plugin-dev-ja/0432-develop-a-slack-bot-plugin) - リバース呼び出しを使用してSlackプラットフォームとの統合を実現する実装例 -- [バンドルタイプのプラグイン](/plugin-dev-ja/9241-bundle) - リバース呼び出しを使用する複数のプラグインをパッケージ化する方法を学びます -- [永続ストレージの使用](/plugin-dev-ja/0411-persistent-storage-kv) - KVストレージを通じてプラグインの機能を向上させます - -{/* -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/9241-reverse-invocation.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9242-reverse-invocation-app.mdx b/plugin-dev-ja/9242-reverse-invocation-app.mdx deleted file mode 100644 index f03dac47..00000000 --- a/plugin-dev-ja/9242-reverse-invocation-app.mdx +++ /dev/null @@ -1,134 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: intermediate -standard_title: Reverse Invocation App -language: ja -title: アプリ -description: このドキュメントでは、プラグインがDifyプラットフォーム内のAppサービスをリバース呼び出しする方法について詳しく説明します。内容には、チャットインターフェース(Chatbot/Agent/Chatflowタイプのアプリケーションに適用)、Workflowインターフェース、Completionインターフェースの3種類のインターフェースが含まれ、各インターフェースのエントリーポイント、呼び出し規約、および実際の呼び出し例のコードが提供されています。 ---- - -アプリのリバース呼び出しとは、プラグインがDify内のアプリデータにアクセスできることを指します。このモジュールは、ストリーミングと非ストリーミングの両方のアプリ呼び出しをサポートしています。リバース呼び出しの基本的な概念にまだ慣れていない場合は、まず[Difyサービスのリバース呼び出し](/plugin-dev-ja/9241-reverse-invocation)をお読みください。 - -**インターフェースタイプ:** - -* `Chatbot/Agent/Chatflow` タイプのアプリケーションはすべてチャットタイプのアプリケーションであり、同じタイプの入力パラメータと出力パラメータを持つため、統一して**チャットインターフェース**と見なすことができます。 -* Workflowアプリケーションの場合、単独で**Workflowインターフェース**を占有します。 -* Completion(テキスト生成アプリケーション)アプリケーションの場合、単独で**Completionインターフェース**を占有します。 - -注意:プラグインは、プラグインが存在するワークスペース内のアプリにのみアクセスできます。 - -### チャットインターフェースの呼び出し - -#### **エントリーポイント** - -```python - self.session.app.chat -``` - -#### **インターフェース規約** - -```python - def invoke( - self, - app_id: str, - inputs: dict, - response_mode: Literal["streaming", "blocking"], - conversation_id: str, - files: list, - ) -> Generator[dict, None, None] | dict: - pass -``` - -`response_mode` が `streaming` の場合、このインターフェースは直接 `Generator[dict]` を返します。そうでない場合は直接 `dict` を返します。具体的なインターフェースフィールドについては、`ServiceApi` の戻り結果を参照してください。 - -#### **使用例** - -`Endpoint`内でチャットタイプのアプリを呼び出し、結果を直接返すことができます。 - -```python -import json -from typing import Mapping -from werkzeug import Request, Response -from dify_plugin import Endpoint - -class Duck(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - """ - Invokes the endpoint with the given request. - """ - app_id = values["app_id"] - - def generator(): - response = self.session.app.workflow.invoke( - app_id=app_id, inputs={}, response_mode="streaming", files=[] - ) - - for data in response: - yield f"{json.dumps(data)}
" - - return Response(generator(), status=200, content_type="text/html") -``` - -### Workflowインターフェースの呼び出し - -#### **エントリーポイント** - -```python - self.session.app.workflow -``` - -#### **インターフェース規約** - -```python - def invoke( - self, - app_id: str, - inputs: dict, - response_mode: Literal["streaming", "blocking"], - files: list, - ) -> Generator[dict, None, None] | dict: - pass -``` - -### Completionインターフェースの呼び出し - -#### **エントリーポイント** - -```python - self.session.app.completion -``` - -**インターフェース規約** - -```python - def invoke( - self, - app_id: str, - inputs: dict, - response_mode: Literal["streaming", "blocking"], - files: list, - ) -> Generator[dict, None, None] | dict: - pass -``` - -## 関連リソース - -- [Difyサービスのリバース呼び出し](/plugin-dev-ja/9241-reverse-invocation) - リバース呼び出しの基本的な概念を理解する -- [モデルのリバース呼び出し](/plugin-dev-ja/9242-reverse-invocation-model) - プラットフォーム内のモデル機能を呼び出す方法を理解する -- [ツールのリバース呼び出し](/plugin-dev-ja/9242-reverse-invocation-tool) - 他のプラグインを呼び出す方法を理解する -- [Slack Botプラグインの開発](/plugin-dev-ja/0432-develop-a-slack-bot-plugin) - リバース呼び出しを使用した実際の応用例 -- [拡張機能プラグインの開発](/plugin-dev-ja/9231-extension-plugin) - 拡張機能プラグインの開発方法を学ぶ - -{/* -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/9242-reverse-invocation-app.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9242-reverse-invocation-tool.mdx b/plugin-dev-ja/9242-reverse-invocation-tool.mdx deleted file mode 100644 index 38add909..00000000 --- a/plugin-dev-ja/9242-reverse-invocation-tool.mdx +++ /dev/null @@ -1,102 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: intermediate -standard_title: Reverse Invocation Tool -language: ja -title: ツール -description: このドキュメントでは、プラグインがDifyプラットフォーム内のツールサービスをリバース呼び出しする方法について詳しく説明します。内容は、インストール済みのツール(Built-in - Tool)の呼び出し、Workflow as Toolの呼び出し、カスタムツール(Custom Tool)の呼び出しという3つの異なるタイプのツール呼び出し方法を網羅しています。各呼び出し方法には、対応するエントリポイントとインターフェースパラメータの説明が付いています。 ---- - -リバース呼び出しツールとは、プラグインがDifyプラットフォーム内の他のツールタイプのプラグインを呼び出すことができることを指します。リバース呼び出しの基本概念にまだ慣れていない場合は、まず[Difyサービスのリバース呼び出し](/plugin-dev-ja/9241-reverse-invocation)をお読みください。 - -次のような要求に遭遇した場合: - -* あるツールタイプのプラグインが既に機能を実装しているが、期待通りの効果が得られず、データの二次加工が必要な場合。 -* あるタスクでクローラーを使用する必要があり、クローラーサービスを自由に選択したい場合。 -* 複数のツールの結果を統合する必要があるが、Workflowアプリケーションでは処理が難しい場合。 - -この場合、プラグイン内で既に実装されている他のツールを呼び出す必要があります。そのツールは、マーケットプレイスのツールプラグイン、独自に構築したWorkflow as a Tool、またはカスタムツールである可能性があります。 - -上記の要求は、プラグインの `self.session.tool` フィールドを呼び出すことで実現できます。 - -### インストール済みのツールの呼び出し - -プラグインが現在のワークスペースにインストールされている各ツール(他のツールタイプのプラグインも含む)を呼び出すことを許可します。 - -**エントリポイント** - -```python - self.session.tool -``` - -**インターフェース** - -```python - def invoke_builtin_tool( - self, provider: str, tool_name: str, parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - pass -``` - -ここで、provider はプラグインのIDにツールサプライヤー名を加えたもので、`langgenius/google/google` のような形式です。tool\_name は具体的なツール名で、`parameters` は最終的にそのツールに渡されるパラメータです。 - -### Workflow as Tool の呼び出し - -**エントリポイント** - -```python - self.session.tool -``` - -**インターフェース** - -```python - def invoke_workflow_tool( - self, provider: str, tool_name: str, parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - pass -``` - -この場合、provider はそのツールのIDです。tool\_name はそのツールの作成時に記入が求められます。 - -### カスタムツールの呼び出し - -**エントリポイント** - -```python - self.session.tool -``` - -**インターフェース** - -```python - def invoke_api_tool( - self, provider: str, tool_name: str, parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - pass -``` - -この場合、`provider` はそのツールのIDです。`tool_name` は OpenAPI の `operation_id` であり、存在しない場合は Dify が自動生成した `tool_name` となります。具体的な名称はツール管理ページで確認できます。 - -## 関連リソース - -- [Difyサービスのリバース呼び出し](/plugin-dev-ja/9241-reverse-invocation) - リバース呼び出しの基本概念を理解する -- [Appのリバース呼び出し](/plugin-dev-ja/9242-reverse-invocation-app) - プラットフォーム内のAppを呼び出す方法を理解する -- [Modelのリバース呼び出し](/plugin-dev-ja/9242-reverse-invocation-model) - プラットフォーム内のモデル機能を呼び出す方法を理解する -- [ツールプラグイン開発ガイド](/plugin-dev-ja/0211-getting-started-dify-tool) - ツールプラグインの開発方法を学ぶ -- [高度なツールプラグイン](/plugin-dev-ja/9223-tool.ja) - Workflow as 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/9242-reverse-invocation-tool.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9243-customizable-model.mdx b/plugin-dev-ja/9243-customizable-model.mdx deleted file mode 100644 index 3223ae5e..00000000 --- a/plugin-dev-ja/9243-customizable-model.mdx +++ /dev/null @@ -1,361 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: advanced -standard_title: Customizable Model -language: ja -title: カスタムモデルの統合 -description: このドキュメントでは、Difyでカスタムモデルを統合する方法を、Xinferenceモデルを例に詳しく説明します。ドキュメントには、モデルプロバイダーファイルの作成、モデルタイプに応じたコードの記述、モデル呼び出しロジックと例外処理の実装、デバッグと公開までの完全なプロセスが含まれています。特に、LLM呼び出し、トークン計算、認証情報検証、パラメータ生成などのコアメソッドの実装について詳しく説明しています。 ---- - -カスタムモデルとは、自身でデプロイまたは設定する必要があるLLMを指します。本稿では、[Xinferenceモデル](https://inference.readthedocs.io/en/latest/)を例に、モデルプラグイン内でカスタムモデルを統合する方法を説明します。 - -カスタムモデルはデフォルトでモデルタイプとモデル名の2つのパラメータを含んでおり、プロバイダーのYAMLファイルで定義する必要はありません。 - -プロバイダー設定ファイルでは、`validate_provider_credential`を実装する必要はありません。Runtimeは、ユーザーが選択したモデルタイプまたはモデル名に基づいて、対応するモデルレイヤーの`validate_credentials`メソッドを自動的に呼び出して検証を行います。 - -### カスタムモデルプラグインの統合 - -カスタムモデルの統合は、以下のステップに分かれます: - -1. **モデルプロバイダーファイルの作成** - - カスタムモデルに含まれるモデルタイプを明確にします。 -2. **モデルタイプに基づいたコードファイルの作成** - - モデルのタイプ(例:`llm`または`text_embedding`)に基づいてコードファイルを作成します。各モデルタイプが独立したロジックレイヤーを持つようにし、保守と拡張を容易にします。 -3. **異なるモデルモジュールに基づいたモデル呼び出しコードの記述** - - 対応するモデルタイプモジュールの下に、モデルタイプと同名のPythonファイル(例:llm.py)を作成します。ファイル内で具体的なモデルロジックを実装するクラスを定義し、そのクラスはシステムのモデルインターフェース仕様に準拠する必要があります。 -4. **プラグインのデバッグ** - - 新たに追加されたプロバイダー機能に対して単体テストと結合テストを作成し、すべての機能モジュールが期待通りに動作することを確認します。 - -*** - -### 1. **モデルプロバイダーファイルの作成** - -プラグインプロジェクトの`/provider`パスの下に、新しい`xinference.yaml`ファイルを作成します。 - -`Xinference`ファミリーモデルは`LLM`、`Text Embedding`、`Rerank`モデルタイプをサポートしているため、`xinference.yaml`ファイルにこれらのモデルタイプを含める必要があります。 - -サンプルコード: - -```yaml -provider: xinference # プロバイダー識別子を決定 -label: # プロバイダー表示名。en_US (英語)、zh_Hans (中国語)の2言語を設定可能。zh_Hans を設定しない場合はデフォルトで en_US が使用されます。 - en_US: Xorbits Inference - zh_Hans: Xorbits Inference # 中国語の表示名(例として英語と同じにしていますが、通常は中国語訳) -icon_small: # 小アイコン。他のプロバイダーのアイコンを参考に、対応するプロバイダー実装ディレクトリ下の _assets ディレクトリに保存。中英ポリシーは label と同様。 - en_US: icon_s_en.svg -icon_large: # 大アイコン - en_US: icon_l_en.svg -help: # ヘルプ - title: - en_US: How to deploy Xinference - zh_Hans: Xinferenceのデプロイ方法 - url: - en_US: https://github.com/xorbitsai/inference -supported_model_types: # サポートされるモデルタイプ。XinferenceはLLM/Text Embedding/Rerankを同時にサポートします。 -- llm -- text-embedding -- rerank -configurate_methods: # Xinferenceはローカルデプロイのプロバイダーであり、事前定義されたモデルはありません。どのモデルを使用するかはXinferenceのドキュメントに従ってデプロイする必要があるため、ここのメソッドはカスタムモデルです。 -- customizable-model -provider_credential_schema: - credential_form_schemas: -``` - -次に、`provider_credential_schema`フィールドを定義する必要があります。`Xinference`は`text-generation`、`embeddings`、`reranking`モデルをサポートしています。サンプルコードは以下の通りです: - -```yaml -provider_credential_schema: - credential_form_schemas: - - variable: model_type - type: select - label: - en_US: Model type - zh_Hans: モデルタイプ - required: true - options: - - value: text-generation - label: - en_US: Language Model - zh_Hans: 言語モデル - - value: embeddings - label: - en_US: Text Embedding - zh_Hans: テキスト埋め込み # 中国語の表示名(例) - - value: reranking - label: - en_US: Rerank - zh_Hans: リランク # 中国語の表示名(例) -``` - -Xinferenceの各モデルでは、名前`model_name`を定義する必要があります。 - -```yaml - - variable: model_name - type: text-input - label: - en_US: Model name - zh_Hans: モデル名 - required: true - placeholder: - zh_Hans: モデル名を入力してください - en_US: Input model name -``` - -Xinferenceモデルでは、ユーザーがモデルのローカルデプロイアドレスを入力する必要があります。プラグイン内では、Xinferenceモデルのローカルデプロイアドレス(server\_url)とモデルUIDを入力できる場所を提供する必要があります。サンプルコードは以下の通りです: - -```yaml - - variable: server_url - label: - zh_Hans: サーバーURL - en_US: Server url - type: text-input - required: true - placeholder: - zh_Hans: ここにXinferenceのサーバーアドレスを入力してください(例:https://example.com/xxx) - en_US: Enter the url of your Xinference, for example https://example.com/xxx - - variable: model_uid - label: - zh_Hans: モデルUID - en_US: Model uid - type: text-input - required: true - placeholder: - zh_Hans: ここにあなたのモデルUIDを入力してください - en_US: Enter the model uid -``` - -すべてのパラメータを入力すると、カスタムモデルプロバイダーのYAML設定ファイルの作成が完了します。次に、設定ファイル内で定義されたモデルに具体的な機能コードファイルを追加する必要があります。 - -### 2. モデルコードの記述 - -Xinferenceモデルプロバイダーのモデルタイプには、llm、rerank、speech2text、ttsタイプが含まれるため、`/models`パスの下に各モデルタイプごとに独立したグループを作成し、対応する機能コードファイルを作成する必要があります。 - -以下では、llmタイプを例に、`llm.py`コードファイルの作成方法を説明します。コード作成時には、`XinferenceAILargeLanguageModel`という名前のXinference LLMクラスを作成し、`__base.large_language_model.LargeLanguageModel`ベースクラスを継承し、以下のいくつかのメソッドを実装する必要があります: - -* **LLM呼び出し** - - LLM呼び出しのコアメソッドであり、ストリーミングと同期の両方のレスポンスをサポートします。 - -```python -def _invoke(self, model: str, credentials: dict, - prompt_messages: list[PromptMessage], model_parameters: dict, - tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None, - stream: bool = True, user: Optional[str] = None) \ - -> Union[LLMResult, Generator]: - """ - 大規模言語モデルを呼び出す - - :param model: モデル名 - :param credentials: モデルの認証情報 - :param prompt_messages: プロンプトメッセージ - :param model_parameters: モデルパラメータ - :param tools: ツール呼び出し用のツール - :param stop: ストップワード - :param stream: ストリーム応答であるか - :param user: 一意のユーザーID - :return: 完全な応答またはストリーム応答チャンクジェネレータの結果 - """ -``` - - コードを実装する際には、同期応答とストリーミング応答をそれぞれ処理するために、2つの関数を使用してデータを返す必要があることに注意してください。 - - Pythonは、関数内に`yield`キーワードが含まれる関数をジェネレータ関数として認識し、返されるデータ型は`Generator`に固定されるため、同期応答とストリーミング応答をそれぞれ実装する必要があります。例えば、以下のサンプルコードです: - -> この例では簡略化されたパラメータを使用しています。実際のコード作成時には、上記のパラメータリストを参照してください。 - -```python -def _invoke(self, stream: bool, **kwargs) \ - -> Union[LLMResult, Generator]: - if stream: - return self._handle_stream_response(**kwargs) - return self._handle_sync_response(**kwargs) - -def _handle_stream_response(self, **kwargs) -> Generator: - for chunk in response: - yield chunk -def _handle_sync_response(self, **kwargs) -> LLMResult: - return LLMResult(**response) -``` - -* **入力トークンの事前計算** - - モデルがトークンを事前計算するインターフェースを提供していない場合は、直接0を返すことができます。 - -```python -def get_num_tokens(self, model: str, credentials: dict, prompt_messages: list[PromptMessage], - tools: Optional[list[PromptMessageTool]] = None) -> int: - """ - 指定されたプロンプトメッセージのトークン数を取得する - - :param model: モデル名 - :param credentials: モデルの認証情報 - :param prompt_messages: プロンプトメッセージ - :param tools: ツール呼び出し用のツール - :return: - """ -``` - - 場合によっては、直接0を返したくない場合は、`self._get_num_tokens_by_gpt2(text: str)`メソッドを使用してトークンを計算できます。このメソッドは`AIModel`ベースクラスにあり、GPT-2のTokenizerを使用して計算します。ただし、これは代替案であり、計算結果にはある程度の誤差が生じる可能性があることに注意してください。 - -* **モデル認証情報検証** - - プロバイダーの認証情報検証と同様に、ここでは個別のモデルに対して検証を行います。 - -```python -def validate_credentials(self, model: str, credentials: dict) -> None: - """ - モデルの認証情報を検証する - - :param model: モデル名 - :param credentials: モデルの認証情報 - :return: - """ -``` - -* **モデルパラメータスキーマ** - - [事前定義済みモデルタイプ](integrate-the-predefined-model.md)とは異なり、YAMLファイルでモデルがサポートするパラメータが事前設定されていないため、モデルパラメータのスキーマを動的に生成する必要があります。 - - 例えば、Xinferenceは`max_tokens`、`temperature`、`top_p`の3つのモデルパラメータをサポートしています。しかし、一部のプロバイダー(例えばOpenLLM)は、具体的なモデルによって異なるパラメータをサポートします。 - - 例を挙げると、プロバイダー`OpenLLM`のAモデルは`top_k`パラメータをサポートしていますが、Bモデルは`top_k`をサポートしていません。この場合、各モデルに対応するパラメータスキーマを動的に生成する必要があります。サンプルコードは以下の通りです: - -```python - def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity | None: - """ - カスタマイズ可能なモデルスキーマを定義するために使用されます - """ - rules = [ - ParameterRule( - name='temperature', type=ParameterType.FLOAT, - use_template='temperature', - label=I18nObject( - zh_Hans='温度', en_US='Temperature' - ) - ), - ParameterRule( - name='top_p', type=ParameterType.FLOAT, - use_template='top_p', - label=I18nObject( - zh_Hans='Top P', en_US='Top P' - ) - ), - ParameterRule( - name='max_tokens', type=ParameterType.INT, - use_template='max_tokens', - min=1, - default=512, - label=I18nObject( - zh_Hans='最大生成長', en_US='Max Tokens' - ) - ) - ] - - # モデルがAの場合、top_kをルールに追加 - if model == 'A': - rules.append( - ParameterRule( - name='top_k', type=ParameterType.INT, - use_template='top_k', - min=1, - default=50, - label=I18nObject( - zh_Hans='Top K', en_US='Top K' - ) - ) - ) - - """ - ここには重要でないコードがあります - """ - - entity = AIModelEntity( - model=model, - label=I18nObject( - en_US=model, - zh_Hans=model # 必要に応じて翻訳 - ), - fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, - model_type=model_type, - model_properties={ - ModelPropertyKey.MODE: ModelType.LLM, - }, - parameter_rules=rules - ) - - return entity -``` - -* **呼び出し例外エラーマッピング表** - - モデル呼び出しが例外をスローした場合、Runtimeが指定する`InvokeError`タイプにマッピングする必要があります。これにより、Difyが異なるエラーに対して異なる後続処理を行うのに便利です。 - - Runtimeエラー: - - * `InvokeConnectionError` 呼び出し接続エラー - * `InvokeServerUnavailableError` 呼び出しサービス利用不可 - * `InvokeRateLimitError` 呼び出しレート制限到達 - * `InvokeAuthorizationError` 呼び出し認証失敗 - * `InvokeBadRequestError` 呼び出しパラメータ不正 - -```python -@property -def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: - """ - モデル呼び出しエラーを統一エラーにマッピングする - キーは呼び出し元にスローされるエラータイプです - 値はモデルによってスローされるエラータイプであり、呼び出し元のために統一されたエラータイプに変換する必要があります。 - - :return: 呼び出しエラーマッピング - """ -``` - - より多くのインターフェースメソッドについては、[インターフェースドキュメント:Model](../../../schema-definition/model/)を参照してください。 - - 本稿で扱った完全なコードファイルを入手するには、[GitHubコードリポジトリ](https://github.com/langgenius/dify-official-plugins/tree/main/models/xinference)にアクセスしてください。 - -### 3. プラグインのデバッグ - -プラグインの開発が完了したら、次にプラグインが正常に動作するかをテストする必要があります。詳細については、以下を参照してください: - -[debug-plugin.md](../../debug-plugin.md) - -### 4. プラグインの公開 - -プラグインをDify Marketplaceに公開したい場合は、以下の内容を参照してください: - -[publish-to-dify-marketplace](../../../publish-plugins/publish-to-dify-marketplace/) - -### **さらに探索** - -**クイックスタート:** - -* [Extensionプラグインの開発](../extension-plugin.md) -* [Toolプラグインの開発](../tool-plugin.md) -* [Bundleプラグイン:複数のプラグインをバンドルする](../bundle.md) - -**プラグインインターフェースドキュメント:** - -* [Manifest構造](../../../schema-definition/manifest.md) -* [Endpoint詳細定義](../../../schema-definition/endpoint.md) -* [Dify機能の逆呼び出し](../../../schema-definition/reverse-invocation-of-the-dify-service/) -* [ツール](../../../schema-definition/tool.md) -* [モデル](../../../schema-definition/model/) - -{/* -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/9243-customizable-model.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9243-reverse-invocation-node.mdx b/plugin-dev-ja/9243-reverse-invocation-node.mdx deleted file mode 100644 index c8205645..00000000 --- a/plugin-dev-ja/9243-reverse-invocation-node.mdx +++ /dev/null @@ -1,107 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: advanced -standard_title: Reverse Invocation Node -language: ja -title: ノード -description: このドキュメントでは、プラグインがDifyプラットフォーム内のChatflow/Workflowアプリケーションノード機能を逆呼び出しする方法について説明します。主な内容は、パラメータ抽出器ノード(ParameterExtractor)と問題分類器ノード(QuestionClassifier)という2つの特殊なノードの呼び出し方法です。また、これら2つのノードの呼び出しエントリーポイント、インターフェースパラメータ、および使用例コードについて詳しく説明します。 ---- - -逆呼び出しノードとは、プラグインがDify内のChatflow/Workflowアプリケーション内部のノードにアクセスできる機能を指します。 - -`Workflow` 内の `ParameterExtractor(パラメータ抽出器)`と `QuestionClassifier(問題分類器)`ノードは、より複雑なプロンプトとコードロジックをカプセル化しており、LLM を通じて多くのハードコーディングでは解決困難なタスクを完了することができます。プラグインはこれら2つのノードを呼び出すことができます。 - -### パラメータ抽出器ノードの呼び出し; - -#### **エントリーポイント** - -```python - self.session.workflow_node.parameter_extractor -``` - -#### **インターフェース** - -```python - def invoke( - self, - parameters: list[ParameterConfig], - model: ModelConfig, - query: str, - instruction: str = "", - ) -> NodeResponse - pass -``` - -ここで、`parameters` は抽出する必要のあるパラメータのリストであり、`model` は `LLMModelConfig` 仕様に準拠し、`query` はパラメータを抽出する元のテキストであり、`instruction` はLLMに追加で与える必要のある可能性のある指示です。`NodeResponse` の構造については、こちらの[ドキュメント](../general-specifications.md#noderesponse)を参照してください。 - -#### **使用例** - -会話の中から特定の人物名を抽出したい場合は、以下のコードを参照してください。 - -```python -from collections.abc import Generator -from dify_plugin.entities.tool import ToolInvokeMessage -from dify_plugin import Tool -from dify_plugin.entities.workflow_node import ModelConfig, ParameterConfig - -class ParameterExtractorTool(Tool): - def _invoke( - self, tool_parameters: dict - ) -> Generator[ToolInvokeMessage, None, None]: - response = self.session.workflow_node.parameter_extractor.invoke( - parameters=[ - ParameterConfig( - name="name", - description="name of the person", - required=True, - type="string", - ) - ], - model=ModelConfig( - provider="langgenius/openai/openai", - name="gpt-4o-mini", - completion_params={}, - ), - query="My name is John Doe", - instruction="Extract the name of the person", - ) - - yield self.create_text_message(response.outputs["name"]) -``` - -### 問題分類器ノードの呼び出し - -#### **エントリーポイント** - -```python - self.session.workflow_node.question_classifier -``` - -#### **インターフェース** - -```python - def invoke( - self, - classes: list[ClassConfig], - model: ModelConfig, - query: str, - instruction: str = "", - ) -> NodeResponse: - pass -``` - -このインターフェースパラメータは `ParameterExtractor` と同じで、最終的な戻り結果は `NodeResponse.outputs['class_name']` に格納されます。 - -{/* -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/9243-reverse-invocation-node.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/9433-agent-strategy-plugin.mdx b/plugin-dev-ja/9433-agent-strategy-plugin.mdx deleted file mode 100644 index cc542e3f..00000000 --- a/plugin-dev-ja/9433-agent-strategy-plugin.mdx +++ /dev/null @@ -1,1101 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: advanced -standard_title: Agent Strategy Plugin -language: ja -title: Agent戦略プラグイン -description: このドキュメントでは、Agent戦略プラグインの開発方法について、プラグインテンプレートの初期化から、モデル呼び出し、ツール呼び出し、ログ出力、パッケージ化、公開までの全プロセスを詳細に説明します。LLMが推論や意思決定ロジックを実行するのを支援する自動ツール呼び出し機能の実装方法など、詳細なコード例も提供します。 ---- - -Agent戦略プラグインは、LLMが推論や意思決定ロジックを実行するのを支援し、ツールの選択、呼び出し、結果処理を含め、より自動化された方法で問題を処理できるようにします。 - -この記事では、ツール呼び出し(Function Calling)機能を備え、現在の正確な時刻を自動的に取得するプラグインを作成する方法をデモンストレーションします。 - -### 事前準備 - -* Dify プラグインスケルトンツール -* Python 環境、バージョン番号 ≥ 3.12 - -プラグイン開発用のスケルトンツールの準備方法に関する詳細については、[開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools)を参照してください。 - -**Tips**:ターミナルで `dify version` コマンドを実行し、バージョン番号が表示されるかどうかを確認して、スケルトンツールが正常にインストールされたことを確認してください。 - -### 1. プラグインテンプレートの初期化 - -次のコマンドを実行して、Agent プラグイン開発テンプレートを初期化します。 - -``` -dify plugin init -``` - -ページの指示に従って、対応する情報を入力します。以下のコードのコメント情報を参照して設定してください。 - -``` -➜ Dify Plugins Developing dify plugin init -Edit profile of the plugin -Plugin name (press Enter to next step): # プラグイン名を入力 -Author (press Enter to next step): Author name # プラグインの作者を入力 -Description (press Enter to next step): Description # プラグインの説明を入力 ---- -Select the language you want to use for plugin development, and press Enter to con -BTW, you need Python 3.12+ to develop the Plugin if you choose Python. --> python # Python 環境を選択 - go (not supported yet) ---- -Based on the ability you want to extend, we have divided the Plugin into four type - -- Tool: It's a tool provider, but not only limited to tools, you can implement an -- Model: Just a model provider, extending others is not allowed. -- Extension: Other times, you may only need a simple http service to extend the fu -- Agent Strategy: Implement your own logics here, just by focusing on Agent itself - -What's more, we have provided the template for you, you can choose one of them b - tool --> agent-strategy # Agent 戦略テンプレートを選択 - llm - text-embedding ---- -Configure the permissions of the plugin, use up and down to navigate, tab to sel -Backwards Invocation: -Tools: - Enabled: [✔] You can invoke tools inside Dify if it's enabled # デフォルトで有効 -Models: - Enabled: [✔] You can invoke models inside Dify if it's enabled # デフォルトで有効 - LLM: [✔] You can invoke LLM models inside Dify if it's enabled # デフォルトで有効 - Text Embedding: [✘] You can invoke text embedding models inside Dify if it' - Rerank: [✘] You can invoke rerank models inside Dify if it's enabled -... -``` - -プラグインテンプレートを初期化すると、プラグイン開発プロセスに必要な完全なリソースを含むコードフォルダが生成されます。Agent 戦略プラグインの全体的なコード構造を理解することは、プラグインの開発プロセスに役立ちます。 - -``` -├── GUIDE.md # ユーザーガイドとドキュメント -├── PRIVACY.md # プライバシーポリシーとデータ処理ガイドライン -├── README.md # プロジェクト概要とセットアップ手順 -├── _assets/ # 静的アセットディレクトリ -│ └── icon.svg # Agent 戦略プロバイダーのアイコン/ロゴ -├── main.py # メインアプリケーションエントリーポイント -├── manifest.yaml # 基本プラグイン設定 -├── provider/ # プロバイダー設定ディレクトリ -│ └── basic_agent.yaml # あなたの Agent プロバイダー設定 -├── requirements.txt # Python 依存関係リスト -└── strategies/ # 戦略実装ディレクトリ - ├── basic_agent.py # 基本 Agent 戦略実装 - └── basic_agent.yaml # 基本 Agent 戦略設定 -``` - -プラグインの機能コードは `strategies/` ディレクトリに集約されています。 - -### 2. プラグイン機能の開発 - -Agent 戦略プラグインの開発は、主に以下の2つのファイルを中心に行われます。 - -* プラグイン宣言ファイル:`strategies/basic_agent.yaml` -* プラグイン機能コード:`strategies/basic_agent.py` - -#### 2.1 パラメータの定義 - -Agent プラグインを作成するには、まず `strategies/basic_agent.yaml` ファイルでプラグインに必要なパラメータを定義する必要があります。これらのパラメータは、LLM モデルの呼び出しやツールの使用能力など、プラグインのコア機能を決定します。 - -以下の4つの基本パラメータを優先的に設定することをお勧めします。 - -1. **model**:呼び出す大規模言語モデル(LLM)を指定します(例:GPT-4、GPT-4o-mini など)。 -2. **tools**:プラグインが使用できるツールリストを定義し、プラグイン機能を強化します。 -3. **query**:モデルと対話するためのプロンプトまたは入力内容を設定します。 -4. **maximum_iterations**:プラグイン実行の最大反復回数を制限し、過剰な計算を回避します。 - -コード例: - -```yaml -identity: - name: basic_agent # agent_strategy の名前 - author: novice # agent_strategy の作成者 - label: - en_US: BasicAgent # agent_strategy の英語ラベル -description: - en_US: BasicAgent # agent_strategy の英語の説明 -parameters: - - name: model # model パラメータの名前 - type: model-selector # モデルタイプ - scope: tool-call&llm # パラメータのスコープ - required: true - label: - en_US: Model - zh_Hans: 模型 - pt_BR: Model - - name: tools # tools パラメータの名前 - type: array[tools] # tool パラメータのタイプ - required: true - label: - en_US: Tools list - zh_Hans: 工具列表 - pt_BR: Tools list - - name: query # query パラメータの名前 - type: string # query パラメータのタイプ - required: true - label: - en_US: Query - zh_Hans: 查询 - pt_BR: Query - - name: maximum_iterations - type: number - required: false - default: 5 - label: - en_US: Maxium Iterations - zh_Hans: 最大迭代次数 - pt_BR: Maxium Iterations - max: 50 # 最大値と最小値を設定すると、パラメータの表示はスライダーになります - min: 1 -extra: - python: - source: strategies/basic_agent.py - -``` - -パラメータ設定が完了すると、プラグインは対応する設定の使用ページを自動生成し、直感的で便利な調整と使用が可能になります。 - -![Agent戦略プラグインの使用ページ](https://assets-docs.dify.ai/2025/01/d011e2eba4c37f07a9564067ba787df8.png) - -#### 2.2 パラメータの取得と実行 - -ユーザーがプラグインの使用ページで基本情報を入力した後、プラグインは入力されたパラメータを処理する必要があります。そのため、まず `strategies/basic_agent.py` ファイル内で後で使用するための Agent パラメータクラスを定義する必要があります。 - -入力パラメータの検証: - -```python -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -``` - -パラメータを取得した後、具体的なビジネスロジックを実行します。 - -```python -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) -``` - -### 3. モデルの呼び出し - -Agent 戦略プラグインにおいて、**モデルの呼び出し**はコア実行ロジックの1つです。SDK が提供する `session.model.llm.invoke()` メソッドを使用して、LLM モデルを効率的に呼び出し、テキスト生成、対話処理などの機能を実現できます。 - -モデルに**ツール呼び出し**機能を持たせたい場合は、まずモデルがツール呼び出し形式に準拠した入力パラメータを出力できることを確認する必要があります。つまり、モデルはユーザーの指示に基づいて、ツールインターフェースの要件に適合するパラメータを生成する必要があります。 - -以下のパラメータを構築します。 - -* model:モデル情報 -* prompt_messages:プロンプトメッセージ -* tools:ツール情報(Function Calling 関連) -* stop:停止トークン -* stream:ストリーミング出力をサポートするかどうか - -メソッド定義のコード例: - -```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:... -``` - -完全な機能実装を確認するには、モデル呼び出しの[コード例](agent-strategy-plugin.md#diao-yong-gong-ju-1)を参照してください。 - -このコードは以下の機能を実現します。ユーザーが指示を入力すると、Agent 戦略プラグインは自動的に LLM を呼び出し、生成結果に基づいてツール呼び出しに必要なパラメータを構築・送信し、モデルが接続済みのツールを柔軟にスケジュールして、複雑なタスクを効率的に完了できるようにします。 - -![ツールリクエストパラメータの生成](https://assets-docs.dify.ai/2025/01/01e32c2d77150213c7c929b3cceb4dae.png) - -### 4. ツールの呼び出し - -ツールパラメータを入力した後、Agent 戦略プラグインに実際にツールを呼び出す能力を与える必要があります。SDK の `session.tool.invoke()` 関数を使用してツールを呼び出すことができます。 - -以下のパラメータを構築します。 - -* provider:ツールプロバイダー -* tool_name:ツール名 -* parameters:入力パラメータ - -メソッド定義のコード例: - -```python - def invoke( - self, - provider_type: ToolProviderType, - provider: str, - tool_name: str, - parameters: dict[str, Any], - ) -> Generator[ToolInvokeMessage, None, None]:... -``` - -LLM を介して直接パラメータを生成し、ツール呼び出しを完了したい場合は、以下のツール呼び出しのコード例を参照してください。 - -```python -tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} -) -for tool_call_id, tool_call_name, tool_call_args in tool_calls: - tool_instance = tool_instances[tool_call_name] - 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}, - ) -``` - -完全な機能コードを確認するには、ツール呼び出しの[コード例](agent-strategy-plugin.md#diao-yong-gong-ju-1)をお読みください。 - -この部分の機能コードを実装すると、Agent 戦略プラグインは自動 Function Calling 機能を持つようになります。例えば、現在の時刻を自動的に取得するなどです。 - -![ツール呼び出し](https://assets-docs.dify.ai/2025/01/80e5de8acc2b0ed00524e490fd611ff5.png) - -### 5. ログ作成 - -**Agent 戦略プラグイン**では、複雑なタスクを完了するために通常、複数回の操作を実行する必要があります。各操作の実行結果を記録することは、開発者にとって非常に重要であり、Agent の実行プロセスを追跡し、各ステップの決定根拠を分析し、戦略効果をより良く評価・最適化するのに役立ちます。 - -この機能を実現するために、SDK の `create_log_message` および `finish_log_message` メソッドを使用してログを記録できます。この方法では、モデル呼び出しの前後で操作状態をリアルタイムに記録できるだけでなく、開発者が問題を迅速に特定するのにも役立ちます。 - -シナリオ例: - -* モデル呼び出しの前に、「モデル呼び出し開始」というログを記録し、開発者がタスクの実行進捗を明確に把握できるようにします。 -* モデル呼び出しが成功した後、「呼び出し成功」というログを記録し、モデル応答の完全性を追跡しやすくします。 - -```python -model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - ) -yield model_log -self.session.model.llm.invoke(...) -yield self.finish_log_message( - log=model_log, - data={ - "output": response, - "tool_name": tool_call_names, - "tool_input": tool_call_inputs, - }, - metadata={ - "started_at": model_started_at, - "finished_at": time.perf_counter(), - "elapsed_time": time.perf_counter() - model_started_at, - "provider": params.model.provider, - }, -) -``` - -設定完了後、ワークフローログに実行結果が出力されます。 - -![Agent 実行結果の出力](https://assets-docs.dify.ai/2025/01/96516388a4fb1da9cea85fc1804ff377.png) - -Agent の実行過程では、複数ラウンドのログが生成される可能性があります。ログが階層構造を持つと、開発者にとって確認しやすくなります。ログ記録時に parent パラメータを渡すことで、異なるラウンドのログが親子関係を形成し、ログ表示がより明確で追跡しやすくなります。 - -**参照方法:** - -```python -function_call_round_log = self.create_log_message( - label="Function Call Round1 ", - data={}, - metadata={}, -) -yield function_call_round_log - -model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - # add parent log - parent=function_call_round_log, -) -yield model_log -``` - -#### プラグイン機能のコード例 - - -#### モデルの呼び出し - -以下のコードは、Agent 戦略プラグインにモデル呼び出し機能を与える方法を示します。 - -```python -import json -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - -#### ツールの呼び出し - -以下のコードは、Agent 戦略プラグインにモデル呼び出しを実装し、ツールに正規化されたリクエストを送信する方法を示します。 - -```python -import json -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - -#### 完全な機能コード例 - -**モデル呼び出し、ツール呼び出し**、および**複数ラウンドログ出力機能**を含む完全なプラグインコード例: - -```python -import json -import time -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - function_call_round_log = self.create_log_message( - label="Function Call Round1 ", - data={}, - metadata={}, - ) - yield function_call_round_log - model_started_at = time.perf_counter() - model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - parent=function_call_round_log, - ) - yield model_log - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - tool_call_names = "" - tool_call_inputs = "" - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.finish_log_message( - log=model_log, - data={ - "output": response, - "tool_name": tool_call_names, - "tool_input": tool_call_inputs, - }, - metadata={ - "started_at": model_started_at, - "finished_at": time.perf_counter(), - "elapsed_time": time.perf_counter() - model_started_at, - "provider": params.model.provider, - }, - ) - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - -### 3. プラグインのデバッグ - -プラグインの宣言ファイルと機能コードを設定した後、プラグインのディレクトリ内で `python -m main` コマンドを実行してプラグインを再起動します。次に、プラグインが正常に動作するかをテストする必要があります。Dify はリモートデバッグ方法を提供しており、[「プラグイン管理」](https://console-plugin.dify.dev/plugins)にアクセスしてデバッグキーとリモートサーバーアドレスを取得します。 - -![リモートデバッグプラグイン](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) - -プラグインプロジェクトに戻り、`.env.example` ファイルをコピーして `.env` に名前変更し、取得したリモートサーバーアドレスとデバッグキーなどの情報を `REMOTE_INSTALL_HOST` および `REMOTE_INSTALL_KEY` パラメータに入力します。 - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -`python -m main` コマンドを実行してプラグインを起動します。プラグインページで、このプラグインが Workspace にインストールされていることを確認できます。他のチームメンバーもこのプラグインにアクセスできます。 - -![プラグインへのアクセス](https://assets-docs.dify.ai/2025/01/c82ec0202e5bf914b36e06c796398dd6.png) - -### プラグインのパッケージ化(オプション) - -プラグインが正常に動作することを確認した後、以下のコマンドラインツールを使用してプラグインをパッケージ化し、名前を付けることができます。実行後、現在のフォルダに `google.difypkg` ファイルが見つかります。これが最終的なプラグインパッケージです。 - -```bash -# ./basic_agent をプラグインプロジェクトの実際のパスに置き換えてください -dify plugin package ./basic_agent/ -``` - -おめでとうございます!これでツールタイププラグインの完全な開発、デバッグ、パッケージ化プロセスが完了しました。 - -### プラグインの公開(オプション) - -これで、[Dify Plugins コードリポジトリ](https://github.com/langgenius/dify-plugins)にアップロードしてプラグインを公開できます。アップロードする前に、プラグインが[プラグイン公開規範](https://docs.dify.ai/ja/plugins/publish-plugins/publish-to-dify-marketplace)に従っていることを確認してください。審査に合格すると、コードはメインブランチにマージされ、自動的に [Dify Marketplace](https://marketplace.dify.ai/) に公開されます。 - -### さらに探求する - -複雑なタスクは、多くの場合、複数回の思考と複数回のツール呼び出しを必要とします。よりインテリジェントなタスク処理を実現するために、通常、**モデル呼び出し → ツール呼び出し**というループ実行戦略が採用され、タスクが完了するか、設定された最大反復回数に達するまで続けられます。 - -このプロセスでは、プロンプト管理が特に重要になります。モデル入力を効率的に整理し、動的に調整するために、プラグイン内の Function Calling 機能の[完全な実装コード](https://github.com/langgenius/dify-official-plugins/blob/main/agent-strategies/cot_agent/strategies/function_calling.py)を参照し、標準化された方法でモデルに外部ツールを呼び出させ、返された結果を処理する方法を理解することをお勧めします。 - -## 関連リソース - -- [Agent プラグイン開発の基礎](/plugin-dev-ja/9232-agent) - Agent 戦略プラグインの基本概念を理解する -- [プラグイン開発の基本概念](/plugin-dev-ja/0111-getting-started-dify-plugin) - プラグイン開発の全体的なアーキテクチャを理解する -- [開発ツールの初期化](/plugin-dev-ja/0221-initialize-development-tools) - 開発環境の構築方法を学ぶ -- [モデルの逆呼び出し](/plugin-dev-ja/9242-reverse-invocation-model) - プラットフォーム内のモデル機能を呼び出す方法を理解する -- [ツールの逆呼び出し](/plugin-dev-ja/9242-reverse-invocation-tool) - 他のプラグインを呼び出す方法を理解する -- [プラグイン公開の概要](/plugin-dev-ja/0321-release-overview) - プラグイン公開プロセスを学ぶ - -{/* -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/9433-agent-strategy-plugin.mdx) | [問題を報告する](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-ja/sync/check_mapping_consistency.py b/plugin-dev-ja/sync/check_mapping_consistency.py deleted file mode 100644 index 4fc39d79..00000000 --- a/plugin-dev-ja/sync/check_mapping_consistency.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python3 -""" -文件映射一致性检查工具 -对比 JSON 映射记录与实际文件情况,确保映射准确无误 -""" - -import json -import os -from pathlib import Path -from typing import Set, Dict - -# ANSI 颜色代码 -GREEN = '\033[92m' -YELLOW = '\033[93m' -RED = '\033[91m' -BLUE = '\033[94m' -CYAN = '\033[96m' -RESET = '\033[0m' - - -class MappingValidator: - def __init__(self, json_file: str = "plugin_mappings.json"): - self.base_dir = Path(os.path.dirname(os.path.dirname( - os.path.dirname(os.path.abspath(__file__))))) - self.json_file = self.base_dir / "plugin-dev-ja" / "sync" / json_file - self.plugin_dir = self.base_dir / "ja-jp" / "plugins" - self.dev_dir = self.base_dir / "plugin-dev-ja" - self.mappings = [] - self.load_mappings() - - def load_mappings(self): - """加载映射文件""" - try: - with open(self.json_file, 'r', encoding='utf-8') as f: - data = json.load(f) - self.mappings = data.get('mappings', []) - except FileNotFoundError: - print(f"{RED}错误: 找不到文件 {self.json_file}{RESET}") - self.mappings = [] - except json.JSONDecodeError: - print(f"{RED}错误: JSON 文件格式错误{RESET}") - self.mappings = [] - - def count_mdx_files(self, directory: Path) -> int: - """递归统计目录中的 .mdx 文件数量""" - count = 0 - for file in directory.rglob('*.mdx'): - count += 1 - return count - - def get_actual_file_paths(self, directory: Path) -> Set[str]: - """获取目录中所有 .mdx 文件的相对路径""" - files = set() - for file in directory.rglob('*.mdx'): - relative_path = str(file.relative_to(self.base_dir)) - files.add(relative_path) - return files - - def calculate_mapping_stats(self) -> Dict: - """计算映射统计""" - total = len(self.mappings) - plugin_only = sum(1 for m in self.mappings if m.get( - 'plugin_path') and not m.get('dev_path')) - dev_only = sum(1 for m in self.mappings if m.get( - 'dev_path') and not m.get('plugin_path')) - complete = sum(1 for m in self.mappings if m.get( - 'plugin_path') and m.get('dev_path')) - - # 计算预期的文件数 - expected_plugin_files = total - dev_only # 总数 - 仅开发 = 插件文件数 - expected_dev_files = total - plugin_only # 总数 - 仅插件 = 开发文件数 - - return { - 'total_mappings': total, - 'plugin_only': plugin_only, - 'dev_only': dev_only, - 'complete_mappings': complete, - 'expected_plugin_files': expected_plugin_files, - 'expected_dev_files': expected_dev_files - } - - def validate(self): - """执行验证""" - print(f"\n{CYAN}=== 插件文档映射一致性检查工具 ==={RESET}") - print(f"{CYAN}功能:对比 JSON 映射记录与实际文件,确保映射准确无遗漏{RESET}\n") - - # 统计实际文件数 - actual_plugin_count = self.count_mdx_files(self.plugin_dir) - actual_dev_count = self.count_mdx_files(self.dev_dir) - - # 获取映射统计 - stats = self.calculate_mapping_stats() - - # 显示映射统计 - print(f"{BLUE}【JSON 映射统计情况】{RESET}") - print(f" 总映射记录数: {stats['total_mappings']} 条") - print(f" 完整映射(两边都有): {stats['complete_mappings']} 条") - print(f" 仅插件文档: {stats['plugin_only']} 条") - print(f" 仅开发文档: {stats['dev_only']} 条\n") - - # 显示预期vs实际 - print(f"{BLUE}【运行时文件计数情况】{RESET}") - print(" 📁 插件文件夹 (ja-jp/plugins):") - print(f" JSON 映射预期: {stats['expected_plugin_files']} 个文件") - print(f" 实际扫描结果: {actual_plugin_count} 个 .mdx 文件") - if actual_plugin_count == stats['expected_plugin_files']: - print(f" 状态: {GREEN}✓ 完全一致{RESET}") - else: - diff = actual_plugin_count - stats['expected_plugin_files'] - print(f" 状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}") - - print("\n 📁 开发文件夹 (plugin-dev-ja):") - print(f" JSON 映射预期: {stats['expected_dev_files']} 个文件") - print(f" 实际扫描结果: {actual_dev_count} 个 .mdx 文件") - if actual_dev_count == stats['expected_dev_files']: - print(f" 状态: {GREEN}✓ 完全一致{RESET}") - else: - diff = actual_dev_count - stats['expected_dev_files'] - print(f" 状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}") - - # 显示计算公式说明 - print(f"\n{BLUE}【预期文件数计算说明】{RESET}") - print( - f" 插件预期数 = 总映射数({stats['total_mappings']}) - 仅开发数({stats['dev_only']}) = {stats['expected_plugin_files']}") - print( - f" 开发预期数 = 总映射数({stats['total_mappings']}) - 仅插件数({stats['plugin_only']}) = {stats['expected_dev_files']}") - - # 如果有差异,找出具体文件 - if actual_plugin_count != stats['expected_plugin_files'] or actual_dev_count != stats['expected_dev_files']: - self.find_discrepancies() - else: - print(f"\n{GREEN}✅ 检查完成:所有文件映射完全一致!{RESET}") - - def find_discrepancies(self): - """找出映射和实际文件的差异""" - print(f"\n{YELLOW}【差异详细分析】{RESET}\n") - - # 获取实际文件路径 - actual_plugin_files = self.get_actual_file_paths(self.plugin_dir) - actual_dev_files = self.get_actual_file_paths(self.dev_dir) - - # 获取映射中的文件路径 - mapped_plugin_files = set(m['plugin_path'] - for m in self.mappings if m.get('plugin_path')) - mapped_dev_files = set(m['dev_path'] - for m in self.mappings if m.get('dev_path')) - - # 找出未映射的文件 - unmapped_plugin_files = actual_plugin_files - mapped_plugin_files - unmapped_dev_files = actual_dev_files - mapped_dev_files - - # 找出映射中但不存在的文件 - nonexistent_plugin_files = mapped_plugin_files - actual_plugin_files - nonexistent_dev_files = mapped_dev_files - actual_dev_files - - has_issues = False - - if unmapped_plugin_files: - has_issues = True - print(f"{RED}❗ 实际存在但 JSON 中未记录的插件文件:{RESET}") - for file in sorted(unmapped_plugin_files): - print(f" - {file}") - - if unmapped_dev_files: - has_issues = True - print(f"\n{RED}❗ 实际存在但 JSON 中未记录的开发文件:{RESET}") - for file in sorted(unmapped_dev_files): - print(f" - {file}") - - if nonexistent_plugin_files: - has_issues = True - print(f"\n{RED}❗ JSON 中记录但实际不存在的插件文件:{RESET}") - for file in sorted(nonexistent_plugin_files): - print(f" - {file}") - - if nonexistent_dev_files: - has_issues = True - print(f"\n{RED}❗ JSON 中记录但实际不存在的开发文件:{RESET}") - for file in sorted(nonexistent_dev_files): - print(f" - {file}") - - if has_issues: - print(f"\n{YELLOW}💡 建议:运行 sync_mdx_to_json.py 同步文件到映射{RESET}") - else: - print(f"{GREEN}未发现具体文件差异,检查完成{RESET}") - - -def main(): - """主函数""" - validator = MappingValidator() - validator.validate() - - -if __name__ == "__main__": - main() diff --git a/plugin-dev-ja/sync/plugin_mappings.json b/plugin-dev-ja/sync/plugin_mappings.json deleted file mode 100644 index c97f6038..00000000 --- a/plugin-dev-ja/sync/plugin_mappings.json +++ /dev/null @@ -1,244 +0,0 @@ -{ - "mappings": [ - { - "plugin_path": "ja-jp/plugins/introduction.mdx", - "dev_path": null, - "verified": true - }, - - { - "plugin_path": "ja-jp/plugins/manage-plugins.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/README.mdx", - "dev_path": "plugin-dev-ja/0111-getting-started-dify-plugin.ja.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-ja/0211-getting-started-new-model.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/faq.mdx", - "dev_path": "plugin-dev-ja/0331-faq.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/tool-plugin.mdx", - "dev_path": "plugin-dev-ja/0222-tool-plugin.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/model-plugin/README.mdx", - "dev_path": "plugin-dev-ja/0411-model-plugin-introduction.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/initialize-development-tools.mdx", - "dev_path": "plugin-dev-ja/0221-initialize-development-tools.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/model-plugin/create-model-providers.mdx", - "dev_path": "plugin-dev-ja/0222-creating-new-model-provider.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/README.mdx", - "dev_path": "plugin-dev-ja/0321-release-overview.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/package-plugin-file-and-publish.mdx", - "dev_path": "plugin-dev-ja/0322-release-by-file.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/publish-to-dify-marketplace/README.mdx", - "dev_path": "plugin-dev-ja/0322-release-to-dify-marketplace.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/publish-plugin-on-personal-github-repo.mdx", - "dev_path": "plugin-dev-ja/0322-release-to-individual-github-repo.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/publish-to-dify-marketplace/plugin-developer-guidelines.mdx", - "dev_path": "plugin-dev-ja/0312-contributor-covenant-code-of-conduct.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/publish-to-dify-marketplace/plugin-privacy-protection-guidelines.mdx", - "dev_path": "plugin-dev-ja/0312-privacy-protection-guidelines.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/general-specifications.mdx", - "dev_path": "plugin-dev-ja/0411-general-specifications.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/model/model-designing-rules.mdx", - "dev_path": "plugin-dev-ja/0411-model-designing-rules.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/persistent-storage.mdx", - "dev_path": "plugin-dev-ja/0411-persistent-storage-kv.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/manifest.mdx", - "dev_path": "plugin-dev-ja/0411-plugin-info-by-manifest.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/debug-plugin.mdx", - "dev_path": "plugin-dev-ja/0411-remote-debug-a-plugin.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/tool.mdx", - "dev_path": "plugin-dev-ja/0411-tool.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/model/model-schema.mdx", - "dev_path": "plugin-dev-ja/0412-model-schema.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/best-practice/develop-a-slack-bot-plugin.mdx", - "dev_path": "plugin-dev-ja/0432-develop-a-slack-bot-plugin.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/endpoint.mdx", - "dev_path": "plugin-dev-ja/0432-endpoint.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/extension-plugin.mdx", - "dev_path": "plugin-dev-ja/9231-extension-plugin.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/agent.mdx", - "dev_path": "plugin-dev-ja/9232-agent.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/bundle.mdx", - "dev_path": "plugin-dev-ja/9241-bundle.ja.mdx", - "verified": true, - "sync": "内容高度相同,已确认同步。" - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/reverse-invocation-of-the-dify-service/README.mdx", - "dev_path": "plugin-dev-ja/9241-reverse-invocation.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/reverse-invocation-of-the-dify-service/app.mdx", - "dev_path": "plugin-dev-ja/9242-reverse-invocation-app.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/reverse-invocation-of-the-dify-service/model.mdx", - "dev_path": "plugin-dev-ja/9242-reverse-invocation-model.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/reverse-invocation-of-the-dify-service/tool.mdx", - "dev_path": "plugin-dev-ja/9242-reverse-invocation-tool.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/model-plugin/customizable-model.mdx", - "dev_path": "plugin-dev-ja/9243-customizable-model.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/reverse-invocation-of-the-dify-service/node.mdx", - "dev_path": "plugin-dev-ja/9243-reverse-invocation-node.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/agent-strategy-plugin.mdx", - "dev_path": "plugin-dev-ja/9433-agent-strategy-plugin.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/install-plugins.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/best-practice/how-to-print-strings-to-logs-for-debugging.mdx", - "dev_path": "plugin-dev-ja/0222-debugging-logs.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/best-practice/how-to-use-mcp-zapier.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/develop-plugins/model-plugin/integrate-the-predefined-model.mdx", - "dev_path": "plugin-dev-ja/0222-creating-new-model-provider-extra.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/plugin-auto-publish-pr.mdx", - "dev_path": "plugin-dev-ja/0321-plugin-auto-publish-pr.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/publish-plugins/signing-plugins-for-third-party-signature-verification.mdx", - "dev_path": "plugin-dev-ja/0312-third-party-signature-verification.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/quick-start/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 需要进行适配" - }, - { - "plugin_path": "ja-jp/plugins/best-practice/README.mdx", - "dev_path": "plugin-dev-ja/0431-example-overview-and-index.ja.mdx", - "verified": true - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/model/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - }, - { - "plugin_path": "ja-jp/plugins/schema-definition/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-ja/0131-cheatsheet.ja.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-ja/0211-getting-started-dify-tool.ja.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-ja/0211-getting-started-by-prompt.ja.mdx", - "verified": true - } - ] -} diff --git a/plugin-dev-ja/sync/sync_all_mdx_files_to_json.py b/plugin-dev-ja/sync/sync_all_mdx_files_to_json.py deleted file mode 100644 index 58766cd3..00000000 --- a/plugin-dev-ja/sync/sync_all_mdx_files_to_json.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python3 -""" -同步 MDX 文件到映射 -确保所有 mdx 文件都在 JSON 映射中,并去除 metadata -""" - -import json -import os -from pathlib import Path -from typing import Set, Dict - - -class MdxSyncManager: - def __init__(self, json_file: str = "plugin_mappings.json"): - self.base_dir = Path(os.path.dirname( - # 指向项目根目录 - os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) - self.json_file = self.base_dir / "plugin-dev-ja" / \ - "sync" / json_file # 修正 JSON 文件路径 - self.plugin_dir = self.base_dir / "ja-jp" / "plugins" # 指向日文插件目录 - self.dev_dir = self.base_dir / "plugin-dev-ja" # 指向日文开发目录 - self.mappings = [] - self.load_mappings() - - def load_mappings(self): - """加载现有映射""" - try: - with open(self.json_file, 'r', encoding='utf-8') as f: - data = json.load(f) - # 只加载 mappings,忽略 metadata - self.mappings = data.get('mappings', []) - except FileNotFoundError: - print(f"创建新的映射文件: {self.json_file}") - self.mappings = [] - except json.JSONDecodeError: - print("JSON 文件格式错误,创建新文件") - self.mappings = [] - - def save_mappings(self): - """保存映射(不包含 metadata)""" - # 只保存 mappings,不保存 metadata - data = { - 'mappings': self.mappings - } - with open(self.json_file, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - - def get_mdx_files(self, directory: Path) -> Set[str]: - """获取目录中所有 mdx 文件的相对路径""" - mdx_files = set() - for file in directory.rglob('*.mdx'): - relative_path = str(file.relative_to(self.base_dir)) - mdx_files.add(relative_path) - return mdx_files - - def get_existing_paths(self) -> Dict[str, Dict]: - """获取现有映射中的所有路径""" - existing = {} - for mapping in self.mappings: - if mapping['plugin_path']: - existing[mapping['plugin_path']] = mapping - if mapping['dev_path']: - existing[mapping['dev_path']] = mapping - return existing - - def get_base_filename(self, filepath: str) -> str: - """从文件路径中提取基本名称,移除扩展名和常见的语言代码。""" - name = os.path.basename(filepath) - # 顺序很重要:先匹配更具体的(如 .mdx),再匹配通用的(如 .mdx) - if name.endswith('.mdx'): - return name[:-7] - elif name.endswith('.mdx'): # 保留以处理多语言情况 - return name[:-7] - elif name.endswith('.ja.mdx'): # 保留以处理多语言情况 - return name[:-7] - elif name.endswith('.mdx'): # 通用 .mdx - return name[:-4] - return os.path.splitext(name)[0] # 备选方案:返回不含最后一个扩展名的名称 - - def _find_match_in_set(self, source_file_path: str, target_file_set: Set[str]) -> str | None: - """通过比较基本名称,在目标集合中查找源文件的匹配项。""" - source_base = self.get_base_filename(source_file_path) - for target_file in target_file_set: - if self.get_base_filename(target_file) == source_base: - return target_file - return None - - def find_matching_mapping(self, path: str) -> Dict | None: - """查找与给定路径匹配的映射""" - for mapping in self.mappings: - if mapping['plugin_path'] == path or mapping['dev_path'] == path: - return mapping - return None - - def sync_files(self): - """同步文件到映射, 包括添加新文件、移除不存在的文件关联、并尝试链接对应文件。""" - actual_plugin_files = self.get_mdx_files(self.plugin_dir) - actual_dev_files = self.get_mdx_files(self.dev_dir) - - made_changes = False - - # 步骤 1: 从现有映射中修剪不存在的文件路径 - valid_mappings = [] - for mapping in self.mappings: - plugin_path = mapping.get('plugin_path') - dev_path = mapping.get('dev_path') - - original_plugin_path_for_log = plugin_path - original_dev_path_for_log = dev_path - - path_changed_in_mapping = False - if plugin_path and plugin_path not in actual_plugin_files: - print(f"信息:插件文件 '{plugin_path}' 在映射中但实际不存在,将从该映射中移除。") - mapping['plugin_path'] = None - made_changes = True - path_changed_in_mapping = True - - if dev_path and dev_path not in actual_dev_files: - print(f"信息:开发文件 '{dev_path}' 在映射中但实际不存在,将从该映射中移除。") - mapping['dev_path'] = None - made_changes = True - path_changed_in_mapping = True - - # 如果映射仍然至少有一个有效路径,则保留它 - if mapping.get('plugin_path') or mapping.get('dev_path'): - valid_mappings.append(mapping) - elif path_changed_in_mapping: # 因修剪而变为空 - print( - f"信息:移除了一个空的映射条目 (原插件: {original_plugin_path_for_log}, 原开发: {original_dev_path_for_log})。") - # made_changes 已在路径被设为 None 时置为 true - - self.mappings = valid_mappings - - # 步骤 2: 识别修剪后映射中当前代表的所有文件 - mapped_plugin_paths = {m['plugin_path'] - for m in self.mappings if m.get('plugin_path')} - mapped_dev_paths = {m['dev_path'] - for m in self.mappings if m.get('dev_path')} - - # 步骤 3: 添加/链接新的插件文件 - for p_file in actual_plugin_files: - if p_file not in mapped_plugin_paths: # 这个插件文件不在任何映射的 plugin_path 中 - made_changes = True - corresponding_dev_file = self._find_match_in_set( - p_file, actual_dev_files) - linked_to_existing_dev_mapping = False - - if corresponding_dev_file: - for m in self.mappings: # 寻找一个只有dev路径且匹配的现有映射 - if m.get('dev_path') == corresponding_dev_file and not m.get('plugin_path'): - m['plugin_path'] = p_file - print( - f"链接新插件文件到现有开发映射: {p_file} -> {corresponding_dev_file}") - mapped_plugin_paths.add(p_file) - linked_to_existing_dev_mapping = True - break - - if not linked_to_existing_dev_mapping: - new_mapping_entry = { - 'plugin_path': p_file, 'dev_path': None, 'verified': False} - if corresponding_dev_file and corresponding_dev_file not in mapped_dev_paths: - # 如果对应的dev文件也存在且尚未被映射,则一起加入新条目 - new_mapping_entry['dev_path'] = corresponding_dev_file - mapped_dev_paths.add(corresponding_dev_file) - print( - f"添加新映射 (插件与新开发链接): {p_file} <-> {corresponding_dev_file}") - else: - print(f"添加新映射 (仅插件): {p_file}") - self.mappings.append(new_mapping_entry) - mapped_plugin_paths.add(p_file) - - # 步骤 4: 添加/链接新的开发文件 (那些在步骤3中未被链接的) - for d_file in actual_dev_files: - if d_file not in mapped_dev_paths: # 这个开发文件不在任何映射的 dev_path 中 - made_changes = True - corresponding_plugin_file = self._find_match_in_set( - d_file, actual_plugin_files) - linked_to_existing_plugin_mapping = False - - if corresponding_plugin_file: # 对应的插件文件存在 - for m in self.mappings: # 寻找一个只有plugin路径且匹配的现有映射 - if m.get('plugin_path') == corresponding_plugin_file and not m.get('dev_path'): - m['dev_path'] = d_file - print( - f"链接新开发文件到现有插件映射: {corresponding_plugin_file} <- {d_file}") - mapped_dev_paths.add(d_file) - linked_to_existing_plugin_mapping = True - break - - if not linked_to_existing_plugin_mapping: - # 如果没有找到可链接的仅插件映射,则添加为新的仅开发映射 - print(f"添加新映射 (仅开发): {d_file}") - self.mappings.append( - {'plugin_path': None, 'dev_path': d_file, 'verified': False}) - mapped_dev_paths.add(d_file) # 确保它现在被认为是已映射 - - # 步骤 5: 清理重复项 - initial_len = len(self.mappings) - self.remove_duplicates() # 原位修改 self.mappings - if len(self.mappings) != initial_len: - print(f"信息:移除了 {initial_len - len(self.mappings)} 个重复映射。") - made_changes = True - - # 步骤 6: 如果有更改则保存 - if made_changes: - self.save_mappings() - print("\\n映射已同步并保存。") - else: - print("\\n映射文件无需更新。") - - def remove_duplicates(self): - """去除重复的映射""" - unique_mappings = [] - seen = set() - - for mapping in self.mappings: - # 创建唯一键 - key = (mapping.get('plugin_path'), mapping.get('dev_path')) - if key not in seen: - seen.add(key) - unique_mappings.append(mapping) - - self.mappings = unique_mappings - - def show_status(self): - """显示当前状态""" - plugin_count = sum(1 for m in self.mappings if m['plugin_path']) - dev_count = sum(1 for m in self.mappings if m['dev_path']) - both_count = sum( - 1 for m in self.mappings if m['plugin_path'] and m['dev_path']) - - print("\n当前映射状态:") - print(f"总映射数: {len(self.mappings)}") - print(f"Plugin 文件: {plugin_count}") - print(f"Dev 文件: {dev_count}") - print(f"完整映射: {both_count}") - - -def main(): - """主函数""" - manager = MdxSyncManager() - - print("开始同步 MDX 文件到映射...") - manager.sync_files() - manager.show_status() - - print("\n同步完成!") - - -if __name__ == "__main__": - main() diff --git a/plugin-dev-ja/sync/view_file_mappings.py b/plugin-dev-ja/sync/view_file_mappings.py deleted file mode 100644 index ad60eee8..00000000 --- a/plugin-dev-ja/sync/view_file_mappings.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -""" -简单的插件映射查看器 -快速查看文件映射关系,支持在 VS Code 中点击打开 -""" - -import json -import os -from pathlib import Path - -# ANSI 颜色代码 -GREEN = '\033[92m' -YELLOW = '\033[93m' -RED = '\033[91m' -BLUE = '\033[94m' -RESET = '\033[0m' - -# 新增符号常量 -CHECK_MARK = f"{GREEN}✅{RESET}" -CROSS_MARK = f"{RED}❌{RESET}" -EMPTY_MARK = f"{YELLOW}❎{RESET}" - -def load_mappings(json_file="plugin_mappings.json"): - """加载映射文件""" - base_dir = Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # 修改 base_dir 指向项目根目录 - json_path = base_dir / "plugin-dev-ja" / "sync" / json_file # 修正 json_path - - try: - with open(json_path, 'r', encoding='utf-8') as f: - return json.load(f) - except FileNotFoundError: - print(f"{RED}错误: 找不到文件 {json_path}{RESET}") - return None - except json.JSONDecodeError: - print(f"{RED}错误: JSON 文件格式错误{RESET}") - return None - -def calculate_statistics(mappings): - """动态计算统计信息""" - total = len(mappings) - verified = sum(1 for m in mappings if m.get('verified', False)) - pending = total - verified - - # 额外统计 - plugin_only = sum(1 for m in mappings if m.get('plugin_path') and not m.get('dev_path')) - dev_only = sum(1 for m in mappings if m.get('dev_path') and not m.get('plugin_path')) - complete = sum(1 for m in mappings if m.get('plugin_path') and m.get('dev_path')) - - return { - 'total_mappings': total, - 'verified_count': verified, - 'pending_verification': pending, - 'plugin_only': plugin_only, - 'dev_only': dev_only, - 'complete_mappings': complete - } - -def show_mappings(): - """显示所有映射关系""" - data = load_mappings() - if not data: - return - - mappings = data.get('mappings', []) - stats = calculate_statistics(mappings) - - print(f"\n{BLUE}插件文档映射关系{RESET}") - print(f"总计: {stats['total_mappings']} | " - f"已验证: {GREEN}{stats['verified_count']}{RESET} | " - f"待验证: {YELLOW}{stats['pending_verification']}{RESET}") - print(f"完整映射: {stats['complete_mappings']} | " - f"仅插件: {stats['plugin_only']} | " - f"仅开发: {stats['dev_only']}") # Removed trailing \n here - - print("\n路径 | 验证 | 同步细节\n") # Added newlines for spacing - - separator_line1 = "-" * 56 - separator_line2 = "*" * 56 - - for idx, mapping in enumerate(mappings, 1): - plugin_path = mapping.get('plugin_path') - dev_path = mapping.get('dev_path') - verified = mapping.get('verified', False) - sync_info = mapping.get('sync', '').strip() - - # 打印分隔符 - print(separator_line1) - print(separator_line2) - print(separator_line1) - print() # 在分隔符后添加空行 - - # 显示 Help 路径 - if plugin_path: - print(f"Help: {plugin_path}") - else: - print(f"Help: {EMPTY_MARK}") - - # 显示 Dev 路径 - if dev_path: - print(f"Dev: {dev_path}") - else: - print(f"Dev: {EMPTY_MARK}") - - # 显示 Verify 状态和 sync_info - verify_symbol = CHECK_MARK if verified else CROSS_MARK - print(f"Verify: {verify_symbol}") - if sync_info: - print(sync_info) - # No "else" needed here as per example, empty sync_info means just the symbol - -def main(): - """主函数""" - show_mappings() - - print(f"\n{BLUE}提示:{RESET} 在 VS Code 中,你可以使用 Cmd+点击 路径来快速打开文件") - print(f"{BLUE}命令:{RESET} python view_file_mappings.py") - -if __name__ == "__main__": - main() diff --git a/plugin-dev-zh/0111-getting-started-dify-plugin.mdx b/plugin-dev-zh/0111-getting-started-dify-plugin.mdx deleted file mode 100644 index 7cd334bc..00000000 --- a/plugin-dev-zh/0111-getting-started-dify-plugin.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -dimensions: - type: - primary: conceptual - detail: introduction - level: beginner -standard_title: Getting Started Dify Plugin -language: zh -title: 欢迎开始 Dify 插件开发 -description: 介绍Dify插件的概念、功能和开发价值,包括插件类型(模型、工具、Agent策略、扩展、包)的简要说明,以及开发者文档的内容概览。 ---- - -你好!我们非常高兴你对构建 Dify 插件感兴趣。本开发者文档中心是你的核心资源库,旨在帮助你学习、创建、调试、发布和管理 Dify 插件。 - - -**Dify 插件是什么?** - -你可以将 Dify 插件想象成赋予 AI 应用**增强感知和执行能力**的模块化组件。它们使得将外部服务、自定义功能以及专用工具以"即插即用"的简洁方式集成到基于 Dify 构建的 AI 应用中成为可能。通过插件,你的 AI 应用可以更好地"看"、"听"、"说"、"画"、"计算"、"推理",连接外部 API,甚至执行真实世界的操作。 - -作为**插件开发者**,你可以为自己的 Dify 应用构建专属的功能扩展,或者将你的创新贡献给整个 Dify 生态系统,让更多用户受益。 - -**在本开发者文档中,你将找到:** - -本文档旨在为插件开发者提供清晰的指引,无论你是初次尝试还是寻求高级定制: - -- **[快速入门](/plugin-dev-zh/0211-getting-started-dify-tool):** 学习 Dify 插件系统的基本概念,理解其核心架构,并快速搭建你的开发环境,构建第一个"Hello World"插件。 -- **[核心概念](/plugin-dev-zh/0131-cheatsheet):** 深入理解插件生命周期、安全模型、端点集成 (Endpoint Integration)、反向调用 (Reverse Call)、持久化存储等关键原理。 -- **开发不同类型的插件:** 针对每种插件类型,提供专门的开发指南: - - **[模型 (Models)](/plugin-dev-zh/0211-getting-started-new-model):** 学习如何将不同的 AI 模型打包、配置并作为插件进行管理。 - - **[工具 (Tools)](/plugin-dev-zh/0211-getting-started-dify-tool):** 为 Agent 和工作流构建专业能力,如数据分析、内容处理、自定义集成等。 - - **[Agent 策略 (Agent Strategies)](/plugin-dev-zh/9433-agent-strategy-plugin):** 创建自定义的推理策略(如 ReAct, CoT, ToT)来赋能 Dify 中的自主 Agent。 - - **[扩展 (Extensions)](/plugin-dev-zh/9231-extension-plugin):** 通过 HTTP Webhook 实现与外部服务的集成,处理复杂逻辑。 - - **[包 (Bundles)](/plugin-dev-zh/9241-bundle):** 了解如何将多个插件组合打包,以便于分发和部署。 -- **[开发与调试](/plugin-dev-zh/0411-remote-debug-a-plugin):** 掌握高效插件开发的工具和技巧,包括使用 SDK、利用我们友好的远程调试功能,以及如何测试你的插件。 -- **[发布与市场](/plugin-dev-zh/0321-release-overview):** 学习如何打包你的插件,将其提交到官方的 Dify Marketplace,或通过 GitHub 等渠道与社区分享。 -- **[API & SDK 参考](/plugin-dev-zh/0411-general-specifications):** 查找 API、SDK 方法、Manifest 文件格式以及所需 Schema 的详细技术规范。 -- **[社区与贡献](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct):** 了解如何与其他开发者交流、寻求帮助,以及如何为 Dify 插件生态和本文档做出贡献。 - -**为什么选择开发 Dify 插件?** - -- **扩展 AI 能力:** 为基于 Dify 的应用赋予专业工具、多模态处理、连接现实世界服务等无限可能。 -- **定制化 Dify 体验:** 通过构建专属插件,精准满足特定业务场景或工作流的需求。 -- **重塑智能流程:** 利用自定义工具和 Agent 策略,优化 RAG 流程、增强 Agent 推理能力。 -- **实现模块化与解耦:** 将功能作为独立的插件进行开发和管理,提高代码的可维护性和灵活性。 -- **触达 Dify 用户:** 通过 Dify Marketplace 将你的创新成果分享给广大的 Dify 用户群体。 -- **享受开发者友好体验:** 我们提供强大的 SDK、便捷的远程调试工具和清晰的文档,助你高效开发。 - -**准备好开始构建了吗?** - -以下是一些快速入口,助你启程: - -- **[阅读快速入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)** - 从构建一个简单的工具插件开始 -- **[探索插件开发速查表](/plugin-dev-zh/0131-cheatsheet)** - 了解核心概念和常用命令 -- **[初始化开发环境](/plugin-dev-zh/0221-initialize-development-tools)** - 搭建你的开发环境 -- **[查看常见问题解答](/plugin-dev-zh/0331-faq)** - 解决常见疑问 - -## 相关资源 - -- **[模型插件介绍](/plugin-dev-zh/0131-model-plugin-introduction)** - 了解模型插件的基本结构 -- **[开发实践示例](/plugin-dev-zh/0432-develop-a-slack-bot-plugin)** - 查看实际的插件开发案例 - -我们期待看到你使用 Dify 插件创造出色的应用和功能! - -{/* -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-zh/0111-getting-started-dify-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0131-cheatsheet.mdx b/plugin-dev-zh/0131-cheatsheet.mdx deleted file mode 100644 index a2ae7c0c..00000000 --- a/plugin-dev-zh/0131-cheatsheet.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -dimensions: - type: - primary: conceptual - detail: architecture - level: beginner -standard_title: Cheatsheet -language: zh -title: Dify Plugin 开发速查表 -description: 全面的Dify插件开发参考指南,包括环境要求、安装方法、开发流程、插件分类及类型、常用代码片段和常见问题解决方案。适合开发者快速查阅和参考。 ---- - -### 环境要求 - -- Python 版本 ≥ 3.12 -- Dify 插件脚手架工具 (dify-plugin-daemon) - -> 了解更多:[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools) - -### 获取 Dify Plugin 开发包 - -[Dify Plugin CLI](https://github.com/langgenius/dify-plugin-daemon/releases) - -#### 不同平台安装方法 - -**macOS [Brew](https://github.com/langgenius/homebrew-dify)(全局安装):** - -```bash -brew tap langgenius/dify -brew install dify -``` - -安装完成后,新建任意终端窗口,输出 `dify version` 命令,若输出版本号信息,则说明安装成功。 - -**macOS ARM (M 系列芯片):** - -```bash -# 下载 dify-plugin-darwin-arm64 -chmod +x dify-plugin-darwin-arm64 -./dify-plugin-darwin-arm64 version -``` - -**macOS Intel:** - -```bash -# 下载 dify-plugin-darwin-amd64 -chmod +x dify-plugin-darwin-amd64 -./dify-plugin-darwin-amd64 version -``` - -**Linux:** - -```bash -# 下载 dify-plugin-linux-amd64 -chmod +x dify-plugin-linux-amd64 -./dify-plugin-linux-amd64 version -``` - -**全局安装 (推荐):** - -```bash -# 重命名并移动到系统路径 -# 示例 (macOS ARM) -mv dify-plugin-darwin-arm64 dify -sudo mv dify /usr/local/bin/ -dify version -``` - -### 运行开发包 - -这里以 `dify` 为例。如果你使用的是局部的安装方式,请根据情况替换指令例如 `./dify-plugin-darwin-arm64 plugin init`。 - - - -### 插件开发流程 - -#### 1. 新建插件 - -```bash -./dify plugin init -``` - -按提示完成插件基本信息配置 - -> 了解更多:[Dify 插件开发:Hello World 指南](/plugin-dev-zh/0211-getting-started-dify-tool) - -#### 2. 开发模式运行 - -配置 `.env` 文件,然后在插件目录下运行以下命令: - -```bash -python -m main -``` - -> 了解更多:[远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin) - -#### 4. 打包与部署 - -打包插件: - -```bash -cd .. -dify plugin package ./yourapp -``` - -> 了解更多:[发布概览](/plugin-dev-zh/0321-release-overview) - -### 插件分类 - -#### 工具标签 - -分类 `tag` [class ToolLabelEnum(Enum)](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/dify_plugin/entities/tool.py) - -```python -class ToolLabelEnum(Enum): - SEARCH = "search" - IMAGE = "image" - VIDEOS = "videos" - WEATHER = "weather" - FINANCE = "finance" - DESIGN = "design" - TRAVEL = "travel" - SOCIAL = "social" - NEWS = "news" - MEDICAL = "medical" - PRODUCTIVITY = "productivity" - EDUCATION = "education" - BUSINESS = "business" - ENTERTAINMENT = "entertainment" - UTILITIES = "utilities" - OTHER = "other" -``` - -### 插件类型参考 - -Dify 支持多种类型的插件开发: - -- **工具插件**:集成第三方 API 和服务 - > 了解更多:[工具插件开发](/plugin-dev-zh/0211-getting-started-dify-tool) -- **模型插件**:集成 AI 模型 - > 了解更多:[模型插件介绍](/plugin-dev-zh/0131-model-plugin-introduction)、[快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model) -- **Agent 策略插件**:自定义 Agent 思考和决策策略 - > 了解更多:[Agent 策略插件](/plugin-dev-zh/9433-agent-strategy-plugin) -- **扩展插件**:扩展 Dify 平台功能,例如 Endpoint 和 WebAPP - > 了解更多:[扩展插件](/plugin-dev-zh/9231-extension-plugin) -- **数据源插件**:在知识流水线中,作为文档数据的来源并充当整个流水线的起始点 - > 了解更多:[数据源插件](/plugin-dev-zh/0222-datasource-plugin) -- **触发器插件**:外部事件发生时,自动触发 Workflow 运行 - > 了解更多:[触发器插件](/plugin-dev-zh/0222-trigger-plugin) - -{/* -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-zh/0131-cheatsheet.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0211-getting-started-by-prompt.mdx b/plugin-dev-zh/0211-getting-started-by-prompt.mdx deleted file mode 100644 index c329f5a2..00000000 --- a/plugin-dev-zh/0211-getting-started-by-prompt.mdx +++ /dev/null @@ -1,1153 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: basic - level: beginner -standard_title: Getting Started by Prompt -language: zh -title: Dify 插件开发:Prompt -description: 请复制这个prompt,并将其粘贴到你的 Agent 中。它将协助你开发 Dify 插件,提供最佳实践和代码示例。 ---- - -## 文件结构与组织原则 - -### 标准项目结构 - -``` -your_plugin/ -├── _assets/ # 图标和视觉资源 -├── provider/ # 提供者定义和验证 -│ ├── your_plugin.py # 凭证验证逻辑 -│ └── your_plugin.yaml # 提供者配置 -├── tools/ # 工具实现 -│ ├── feature_one.py # 工具功能实现 -│ ├── feature_one.yaml # 工具参数和描述 -│ ├── feature_two.py # 另一个工具实现 -│ └── feature_two.yaml # 另一个工具配置 -├── utils/ # 辅助函数 -│ └── helpers.py # 通用功能逻辑 -├── working/ # 进度记录和工作文件 -├── .env.example # 环境变量模板 -├── main.py # 入口文件 -├── manifest.yaml # 插件主配置 -├── README.md # 文档 -└── requirements.txt # 依赖列表 -``` - -### 文件组织核心原则 - -1. **一个文件一个工具类**: - - **每个Python文件只能定义一个Tool子类** - 这是框架的强制限制 - - 违反此规则会导致错误:`Exception: Multiple subclasses of Tool in /path/to/file.py` - - 示例:`tools/encrypt.py`只能包含`EncryptTool`类,不能同时包含`DecryptTool` - -2. **命名和功能对应**: - - Python文件名应与工具功能相对应 - - 工具类名应遵循`FeatureTool`的命名模式 - - YAML文件名应与对应的Python文件名保持一致 - -3. **文件位置指导**: - - 通用工具函数放在`utils/`目录 - - 具体工具实现放在`tools/`目录 - - 凭证验证逻辑放在`provider/`目录 - -4. **正确的命名和导入**: - - 确保导入的函数名与实际定义的名称完全匹配(包括下划线、大小写等) - - 错误导入会导致:`ImportError: cannot import name 'x' from 'module'. Did you mean: 'y'?` - -### 创建新工具的正确流程 - -1. **复制现有文件作为模板**: - ```bash - # 复制工具YAML文件作为模板 - cp tools/existing_tool.yaml tools/new_feature.yaml - # 复制工具Python实现 - cp tools/existing_tool.py tools/new_feature.py - ``` - -2. **编辑复制的文件**: - - 更新YAML中的名称、描述和参数 - - 更新Python文件中的类名和实现逻辑 - - 确保每个文件只包含一个Tool子类 - -3. **更新provider配置**: - - 在`provider/your_plugin.yaml`中添加新工具: - ```yaml - tools: - - tools/existing_tool.yaml - - tools/new_feature.yaml # 添加新工具 - ``` - -### 常见错误排查 - -当遇到`Multiple subclasses of Tool`错误时: - -1. **检查问题文件**: - - 寻找形如`class AnotherTool(Tool):`的额外类定义 - - 确保文件中只有一个继承自`Tool`的类 - - 例如:如果`encrypt.py`包含`EncryptTool`和`DecryptTool`,保留`EncryptTool`并将`DecryptTool`移至`decrypt.py` - -2. **检查导入错误**: - - 确认导入的函数名或类名是否拼写正确 - - 注意下划线、大小写等细节 - - 修正导入语句中的拼写错误## 文件结构与代码组织规范 - -### 工具文件组织的严格限制 - -1. **一个文件一个工具类**: - - **每个Python文件只能定义一个Tool子类** - - 这是Dify插件框架的强制限制,违反会导致加载错误 - - 错误表现为:`Exception: Multiple subclasses of Tool in /path/to/file.py` - -2. **正确的命名和导入**: - - 确保导入的函数名与实际定义的名称完全匹配(包括下划线、大小写等) - - 错误导入会导致:`ImportError: cannot import name 'x' from 'module'. Did you mean: 'y'?` - -3. **创建新工具的正确流程**: - - **步骤1**: 创建专门的YAML文件:`tools/new_feature.yaml` - - **步骤2**: 创建对应的Python文件:`tools/new_feature.py`,确保一个文件只有一个Tool子类 - - **步骤3**: 更新provider YAML文件中的tools列表以包含新工具 - - **切勿**在现有工具文件中添加新工具类 - -### 代码错误排查指南 - -当遇到 `Multiple subclasses of Tool` 错误时: - -1. **检查文件内容**: - ```bash - # 查看工具文件内容 - cat tools/problematic_file.py - ``` - -2. **查找多余的Tool子类**: - - 寻找形如 `class AnotherTool(Tool):` 的额外类定义 - - 确保文件中只有一个继承自`Tool`的类 - -3. **修复策略**: - - 将多余的Tool子类移动到对应名称的新文件中 - - 保留文件名对应的Tool子类 - - 移除不相关的导入语句 - - 示例:如果`encrypt.py`包含`EncryptTool`和`DecryptTool`,则保留`EncryptTool`并将`DecryptTool`移至`decrypt.py` - -4. **代码审查检查点**: - - 每个工具文件只应包含**一个**`class XxxTool(Tool):`定义 - - 导入语句应只引入该工具类需要的依赖 - - 所有引用的工具函数名称应该与其定义完全一致## 进度记录管理 - -### 进度文件结构与维护 - -1. **创建进度文件**: - - 首次交互时在`working/`目录创建`progress.md` - - 每次新会话开始时首先检查并更新此文件 - -2. **进度文件内容结构**: - ```markdown - # 项目进度记录 - - ## 项目概述 - [插件名称、类型和主要功能简介] - - ## 当前状态 - [描述项目当前所处阶段] - - ## 已完成工作 - - [时间] 完成了xxx功能 - - [时间] 实现了xxx - - ## 待办事项 - - [ ] 实现xxx功能 - - [ ] 完成xxx配置 - - ## 问题与解决方案 - - 问题:xxx - 解决方案:xxx - - ## 技术决策记录 - - 决定使用xxx库,原因是xxx - ``` - -3. **更新规则**: - - **每次对话开始**时进行状态检查和记录更新 - - **每次完成任务**后添加到已完成工作列表 - - **每次遇到并解决问题**时记录在问题与解决方案部分 - - **每次确定技术方向**时记录在技术决策记录部分 - -4. **更新内容示例**: - ```markdown - ## 已完成工作 - - [2025-04-19 14:30] 完成了TOTP验证工具的基本实现 - - [2025-04-19 15:45] 添加了错误处理逻辑 - - ## 待办事项 - - [ ] 实现secret_generator工具 - - [ ] 完善README文档 - ```# Dify插件开发助手 - -## 初始交互指导 - -当用户仅提供了这个prompt但没有明确任务时,不要立即开始提供插件开发建议或代码实现。相反,你应该: - -1. 礼貌地欢迎用户 -2. 解释你作为Dify插件开发助手的能力 -3. 请求用户提供以下信息: - - 他们想要开发的插件类型或功能 - - 当前开发阶段(新项目/进行中的项目) - - 是否有现有代码或项目文件可以检查 - - 具体面临的问题或需要帮助的方面 - -只有在用户提供了具体任务描述或开发需求后,才开始提供相应的建议和帮助。 - -## 角色定义 -你是一位资深软件工程师,专门负责Dify插件开发。你需要帮助开发者实现和优化Dify插件,遵循最佳实践并解决各种技术挑战。 - -## 责任与工作模式 - -### 项目管理与状态追踪 -1. **持续跟踪项目状态**:维护对项目当前进度的理解,记录哪些文件已被创建、修改,以及哪些功能已实现或待实现。 -2. **状态确认**:在每次交互开始时确认当前状态,如果用户输入与你的记录不一致,主动重新检查项目文件来同步实际状态。 -3. **进度记录**:在working目录中创建并更新progress.md文件,记录重要决策、已完成工作和下一步计划。 - -### 代码开发与问题解决 -1. **代码实现**:根据需求编写高质量的Python代码和YAML配置。 -2. **问题诊断**:分析错误信息,提供具体的修复方案。 -3. **解决方案建议**:为技术难题提供多个可行的解决方案,并解释各自的优缺点。 - -### 交互与沟通 -1. **主动性**:当用户提供不完整信息时,主动请求澄清或补充信息。 -2. **解释性**:解释复杂的技术概念和决策理由,帮助用户理解开发过程。 -3. **适应性**:根据用户反馈调整你的建议和方案。 - -## 开发环境与限制 - -### 执行环境特性 - -1. **无服务器环境**:Dify插件在云环境(如AWS Lambda)中运行,这意味着: - - **无本地文件系统持久性**:避免依赖本地文件读写操作 - - **有执行时间限制**:通常在几秒到几十秒之间 - - **有内存限制**:通常在128MB-1GB之间 - - **无法访问主机系统**:不能依赖本地安装的软件或系统库 - -2. **代码打包限制**: - - 所有依赖必须在`requirements.txt`中明确声明 - - 不能包含二进制文件或需要编译的库(除非提供预编译版本) - - 避免过大的依赖包 - -### 安全设计原则 - -1. **无状态设计**: - - 不要依赖于文件系统来存储状态 - - 如需持久化数据,使用Dify提供的KV存储API - - 每次调用都应该是独立的,不依赖于之前的调用状态 - -2. **安全的文件操作方式**: - - 避免本地文件读写(`open()`, `read()`, `write()`等) - - 临时数据使用内存变量存储 - - 对于大量数据,考虑使用数据库或云存储服务 - -3. **轻量级实现**: - - 选择轻量级的依赖库 - - 避免不必要的大型框架 - - 高效管理内存使用 - -4. **健壮的错误处理**: - - 为所有API调用添加错误处理 - - 提供明确的错误信息 - - 优雅地处理超时和限制 - -## 开发流程详解 - -### 1. 项目初始化 -使用`dify plugin init`命令创建基本项目结构: - -```bash -./dify plugin init -``` - -这将引导你输入插件名称、作者和描述,然后生成项目骨架。 - -### 2. 环境配置 -设置Python虚拟环境并安装依赖: - -```bash -# 创建虚拟环境 -python -m venv venv - -# 激活虚拟环境 -# Windows: -venv\Scripts\activate -# macOS/Linux: -source venv/bin/activate - -# 安装依赖 -pip install -r requirements.txt -``` - -### 3. 开发实现 - -#### 3.1 需求分析与设计 -首先明确插件需要实现的具体功能和输入/输出要求: -- 插件将提供哪些工具? -- 每个工具需要哪些输入参数? -- 每个工具应该返回什么输出? -- 是否需要验证用户凭证? - -#### 3.2 实现基础工具函数 -在`utils/`目录中创建辅助函数,实现核心功能逻辑: - -1. 创建文件: - ```bash - mkdir -p utils - touch utils/__init__.py - touch utils/helpers.py - ``` - -2. 在`helpers.py`中实现与外部服务交互或处理复杂逻辑的函数 - -#### 3.3 实现工具类 -在`tools/`目录中创建工具实现类,对每个功能: - -1. 创建YAML文件定义工具参数和描述 -2. 创建对应的Python文件实现工具逻辑,继承`Tool`基类并重写`_invoke`方法 -3. 每个功能应该有**单独的**文件对,遵循"一个文件一个工具类"原则 - -#### 3.4 实现凭证验证 -如果插件需要API密钥等凭证,在`provider/`目录中实现验证逻辑: - -1. 编辑`provider/your_plugin.yaml`添加凭证定义 -2. 在`provider/your_plugin.py`中实现`_validate_credentials`方法 - -### 4. 测试与调试 -配置`.env`文件进行本地测试: - -```bash -# 复制并编辑环境变量 -cp .env.example .env - -# 启动本地服务 -python -m main -``` - -#### 调试常见错误 -- `Multiple subclasses of Tool`:检查工具文件是否包含多个Tool子类 -- `ImportError: cannot import name`:检查导入的函数名是否拼写正确 -- `ToolProviderCredentialValidationError`:检查凭证验证逻辑 - -### 5. 打包与发布 -完成开发后,打包插件并可选择发布到市场: - -```bash -# 打包插件 -./dify plugin package ./your_plugin_dir -``` - -#### 发布前检查 -- 确认README.md和PRIVACY.md已完善 -- 确认所有依赖都已添加到requirements.txt -- 检查manifest.yaml中的标签是否正确 - -## 文件结构详解 - -``` -your_plugin/ -├── _assets/ # 图标和视觉资源 -├── provider/ # 提供者定义和验证 -│ ├── your_plugin.py # 凭证验证逻辑 -│ └── your_plugin.yaml # 提供者配置 -├── tools/ # 工具实现 -│ ├── your_plugin.py # 工具功能实现 -│ └── your_plugin.yaml # 工具参数和描述 -├── utils/ # (可选) 辅助函数 -├── working/ # 进度记录和工作文件 -├── .env.example # 环境变量模板 -├── main.py # 入口文件 -├── manifest.yaml # 插件主配置 -├── README.md # 文档 -└── requirements.txt # 依赖列表 -``` - -### 文件位置与组织原则 - -1. **Python文件位置指导**: - - 当用户提供单个Python文件时,应先检查其功能性质 - - 通用工具函数应放在`utils/`目录下 - - 具体工具实现应放在`tools/`目录下 - - 凭证验证逻辑应放在`provider/`目录下 - -2. **代码复制而非从头编写**: - - 创建新文件时,优先通过复制现有文件作为模板,然后进行修改 - - 使用命令如:`cp tools/existing_tool.py tools/new_tool.py` - - 这样可确保文件格式和结构符合框架要求 - -3. **保持框架一致性**: - - 不随意修改文件结构 - - 不添加框架未定义的新文件类型 - - 遵循既定的命名约定 - -## 关键文件配置详解 - -### manifest.yaml -插件的主配置文件,定义了插件的基本信息和元数据。请遵循以下重要原则: - -1. **保留已有内容**: - - 不要删除配置文件中已有的项目,尤其是i18n相关部分 - - 以实际已有代码为基准进行修改和添加 - -2. **关键字段指导**: - - **name**:不要修改此字段,它是插件的唯一标识符 - - **label**:建议完善多语言显示名称 - - **description**:建议完善多语言描述 - - **tags**:只能使用以下预定义的标签(每个插件只能选择1-2个最相关的标签): - ``` - 'search', 'image', 'videos', 'weather', 'finance', 'design', - 'travel', 'social', 'news', 'medical', 'productivity', - 'education', 'business', 'entertainment', 'utilities', 'other' - ``` - -3. **保持结构稳定**: - - 除非有特殊需求,不要修改`resource`、`meta`、`plugins`等部分 - - 不要更改`type`和`version`等基础字段 - -```yaml -version: 0.0.1 -type: plugin -author: your_name -name: your_plugin_name # 不要修改此字段 -label: - en_US: Your Plugin Display Name - zh_Hans: 你的插件显示名称 -description: - en_US: Detailed description of your plugin functionality - zh_Hans: 插件功能的详细描述 -icon: icon.svg -resource: - memory: 268435456 # 256MB - permission: {} -plugins: - tools: - - provider/your_plugin.yaml -meta: - version: 0.0.1 - arch: - - amd64 - - arm64 - runner: - language: python - version: "3.12" - entrypoint: main -created_at: 2025-04-19T00:00:00.000000+08:00 -privacy: PRIVACY.md -tags: - - utilities # 只使用预定义的标签 -``` - -### provider/your_plugin.yaml -提供者配置文件,定义了插件所需的凭证和工具列表: - -1. **保留关键标识**: - - **name**:不要修改此字段,保持与manifest.yaml中的name一致 - - 保留已有的i18n配置和结构 - -2. **完善显示信息**: - - **label**:建议完善多语言显示名称 - - **description**:建议完善多语言描述 - -3. **添加新工具**: - - 在`tools`列表中添加对新工具YAML文件的引用 - - 注意保持路径正确:`tools/feature_name.yaml` - -```yaml -identity: - author: your_name - name: your_plugin_name # 不要修改此字段 - label: - en_US: Your Plugin Display Name - zh_Hans: 你的插件显示名称 - description: - en_US: Detailed description of your plugin functionality - zh_Hans: 插件功能的详细描述 - icon: icon.svg -credentials_for_provider: # 仅在需要API密钥等凭证时添加 - api_key: - type: secret-input - required: true - label: - en_US: API Key - zh_Hans: API密钥 - placeholder: - en_US: Enter your API key - zh_Hans: 输入你的API密钥 - help: - en_US: How to get your API key - zh_Hans: 如何获取API密钥 - url: https://example.com/get-api-key -tools: # 工具列表,添加新工具时在此更新 - - tools/feature_one.yaml - - tools/feature_two.yaml -extra: - python: - source: provider/your_plugin.py -``` - -### tools/feature.yaml -工具配置文件,定义了工具的参数和描述: - -1. **保留标识与结构**: - - **name**:工具的唯一标识,与文件名相对应 - - 保持与现有文件结构一致 - -2. **完善配置内容**: - - **label**和**description**:提供清晰的多语言显示内容 - - **parameters**:详细定义工具参数及其属性 - -3. **参数定义指导**: - - **type**:选择适当的参数类型(string/number/boolean/file) - - **form**:设置为`llm`(由AI提取)或`form`(UI配置) - - **required**:明确是否为必需参数 - -```yaml -identity: - name: feature_name # 与文件名对应 - author: your_name - label: - en_US: Feature Display Name - zh_Hans: 功能显示名称 -description: - human: # 给人类用户看的描述 - en_US: Description for human users - zh_Hans: 面向用户的功能描述 - llm: Description for AI models to understand when to use this tool. # 给AI看的描述 -parameters: # 参数定义 - - name: param_name - type: string # string, number, boolean, file等 - required: true - label: - en_US: Parameter Display Name - zh_Hans: 参数显示名称 - human_description: - en_US: Parameter description for users - zh_Hans: 面向用户的参数描述 - llm_description: Detailed parameter description for AI models - form: llm # llm表示可由AI从用户输入中提取,form表示需要在UI中配置 - # 其他参数... -extra: - python: - source: tools/feature.py # 对应的Python实现文件 -# 可选:定义输出的JSON Schema -output_schema: - type: object - properties: - result: - type: string - description: Description of the result -``` - -### tools/feature.py -工具实现类,包含核心业务逻辑: - -1. **类名与文件名对应**: - - 类名遵循`FeatureTool`模式,与文件名相对应 - - 确保一个文件中**只有一个**Tool子类 - -2. **参数处理最佳实践**: - - 对于必需参数,使用`.get()`方法并提供默认值:`param = tool_parameters.get("param_name", "")` - - 对于可选参数,有两种处理方式: - - ```python - # 方法1: 使用.get()方法(推荐用于单个参数) - optional_param = tool_parameters.get("optional_param") # 如果不存在返回None - - # 方法2: 使用try-except(处理多个可选参数) - try: - name = tool_parameters["name"] - issuer_name = tool_parameters["issuer_name"] - except KeyError: - name = None - issuer_name = None - ``` - - - 这种try-except方式是当前处理多个可选参数的临时解决方案 - - 始终在使用参数前验证其存在性和有效性 - -3. **输出方式**: - - 使用`yield`返回各种类型的消息 - - 支持文本、JSON、链接和变量输出 - -```python -from collections.abc import Generator -from typing import Any - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -# 导入工具函数,确保函数名称拼写正确 -from utils.helpers import process_data - -class FeatureTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - try: - # 1. 获取必需参数 - param = tool_parameters.get("param_name", "") - - # 2. 获取可选参数 - 使用try-except方式 - try: - optional_param1 = tool_parameters["optional_param1"] - optional_param2 = tool_parameters["optional_param2"] - except KeyError: - optional_param1 = None - optional_param2 = None - - # 另一种可选参数获取方式 - 使用.get()方法 - another_optional = tool_parameters.get("another_optional") # 如果不存在返回None - - # 3. 验证必需参数 - if not param: - yield self.create_text_message("Parameter is required.") - return - - # 4. 实现业务逻辑 - result = self._process_data(param, optional_param1, optional_param2) - - # 5. 返回结果 - # 文本输出 - yield self.create_text_message(f"Processed result: {result}") - # JSON输出 - yield self.create_json_message({"result": result}) - # 变量输出 (用于工作流) - yield self.create_variable_message("result_var", result) - - except Exception as e: - # 错误处理 - yield self.create_text_message(f"Error: {str(e)}") - - def _process_data(self, param: str, opt1=None, opt2=None) -> str: - """ - 实现具体的业务逻辑 - - Args: - param: 必需的参数 - opt1: 可选参数1 - opt2: 可选参数2 - - Returns: - 处理结果 - """ - # 根据参数是否存在执行不同的逻辑 - if opt1 and opt2: - return f"Processed with all options: {param}, {opt1}, {opt2}" - elif opt1: - return f"Processed with option 1: {param}, {opt1}" - elif opt2: - return f"Processed with option 2: {param}, {opt2}" - else: - return f"Processed basic: {param}" -``` - -### utils/helper.py -辅助函数,实现可复用的功能逻辑: - -1. **功能分离**: - - 将通用功能抽取为单独的函数 - - 专注于单一职责 - - 注意函数命名的一致性(避免导入错误) - -2. **错误处理**: - - 包含适当的异常处理 - - 使用明确的异常类型 - - 提供有意义的错误消息 - -```python -import requests -from typing import Dict, Any, Optional - -def call_external_api(endpoint: str, params: Dict[str, Any], api_key: str) -> Dict[str, Any]: - """ - 调用外部API的通用函数 - - Args: - endpoint: API端点URL - params: 请求参数 - api_key: API密钥 - - Returns: - API响应的JSON数据 - - Raises: - Exception: 如果API调用失败 - """ - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } - - try: - response = requests.get(endpoint, params=params, headers=headers, timeout=10) - response.raise_for_status() # 如果状态码不是200,抛出异常 - return response.json() - except requests.RequestException as e: - raise Exception(f"API调用失败: {str(e)}") -``` - -### requirements.txt -依赖列表,指定插件所需的Python库: - -1. **版本规范**: - - 使用`~=`指定依赖版本范围 - - 避免过于宽松的版本要求 - -2. **必要依赖**: - - 必须包含`dify_plugin` - - 添加插件功能所需的所有第三方库 - -``` -dify_plugin~=0.0.1b76 -requests~=2.31.0 -# 其他依赖... -``` - -## 工具开发最佳实践 - -### 1. 参数处理模式 - -1. **必需参数处理**: - - 使用`.get()`方法并提供默认值:`param = tool_parameters.get("param_name", "")` - - 验证参数有效性:`if not param: yield self.create_text_message("Error: Required parameter missing.")` - -2. **可选参数处理**: - - **单个可选参数**:使用`.get()`方法,允许返回None:`optional = tool_parameters.get("optional_param")` - - **多个可选参数**:使用try-except模式处理KeyError: - ```python - try: - param1 = tool_parameters["optional_param1"] - param2 = tool_parameters["optional_param2"] - except KeyError: - param1 = None - param2 = None - ``` - - 这种try-except方式是当前处理多个可选参数的临时解决方案 - -3. **参数验证**: - - 对必需参数进行验证:`if not required_param: return error_message` - - 对可选参数进行条件处理:`if optional_param: do_something()` - -### 2. 安全的文件操作方式 - -1. **避免本地文件读写**: - - Dify插件运行在无服务器环境(如AWS Lambda)中,本地文件系统操作可能不可靠 - - 不要使用`open()`, `read()`, `write()`等直接文件操作 - - 不依赖本地文件作为状态存储 - -2. **使用内存或API替代**: - - 临时数据使用内存变量存储 - - 持久化数据使用Dify提供的KV存储API - - 对于大量数据,考虑使用数据库或云存储服务 - -### 3. 复制现有文件而非从头创建 - -对于不确定结构正确性的情况,强烈建议使用下列方法: - -```bash -# 复制工具YAML文件作为模板 -cp tools/existing_tool.yaml tools/new_tool.yaml - -# 复制工具Python实现 -cp tools/existing_tool.py tools/new_tool.py - -# 同理适用于provider文件 -cp provider/existing.yaml provider/new.yaml -``` - -这样可以确保文件结构和格式符合Dify插件框架的要求,然后再进行针对性修改。 - -### 4. 拆分工具功能 -将复杂功能拆分为多个简单工具,每个工具专注于单一功能: - -``` -tools/ -├── search.py # 搜索功能 -├── search.yaml -├── create.py # 创建功能 -├── create.yaml -├── update.py # 更新功能 -├── update.yaml -├── delete.py # 删除功能 -└── delete.yaml -``` - -### 2. 参数设计原则 -- **必要性**:只要求必要的参数,提供合理默认值 -- **类型定义**:选择合适的参数类型(string/number/boolean/file) -- **清晰描述**:为人类和AI提供清晰的参数描述 -- **表单定义**:正确区分llm(AI提取)和form(UI配置)参数 - -### 3. 错误处理 -```python -try: - # 尝试执行操作 - result = some_operation() - yield self.create_text_message("操作成功") -except ValueError as e: - # 参数错误 - yield self.create_text_message(f"参数错误: {str(e)}") -except requests.RequestException as e: - # API调用错误 - yield self.create_text_message(f"API调用失败: {str(e)}") -except Exception as e: - # 其他未预期错误 - yield self.create_text_message(f"发生错误: {str(e)}") -``` - -### 4. 代码组织与复用 -将可复用的逻辑抽取到utils目录: -```python -# 在工具实现中 -from utils.api_client import ApiClient - -class SearchTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - client = ApiClient(self.runtime.credentials["api_key"]) - results = client.search(tool_parameters["query"]) - yield self.create_json_message(results) -``` - -### 5. 输出格式 -Dify支持多种输出格式: -```python -# 文本输出 -yield self.create_text_message("这是文本消息") - -# JSON输出 -yield self.create_json_message({"key": "value"}) - -# 链接输出 -yield self.create_link_message("https://example.com") - -# 变量输出 (用于工作流) -yield self.create_variable_message("variable_name", "variable_value") -``` - -## 常见错误与解决方案 - -### 加载和初始化错误 - -1. **多个Tool子类错误** - ``` - Exception: Multiple subclasses of Tool in /path/to/file.py - ``` - - **原因**:同一个Python文件中定义了多个继承自Tool的类 - - **解决**: - - 检查文件内容:`cat tools/problematic_file.py` - - 每个文件保留一个与文件名对应的Tool子类 - - 将其他Tool子类移至对应的单独文件 - -2. **导入错误** - ``` - ImportError: cannot import name 'x' from 'module'. Did you mean: 'y'? - ``` - - **原因**:导入的函数名与实际定义不匹配 - - **解决**: - - 检查utils中的函数名称:`cat utils/the_module.py` - - 修正导入语句中的拼写错误 - - 注意函数名中的下划线、大小写等 - -3. **凭证验证失败** - ``` - ToolProviderCredentialValidationError: Invalid API key - ``` - - **原因**:凭证验证逻辑失败 - - **解决**: - - 检查`_validate_credentials`方法实现 - - 确保API密钥格式正确 - - 添加详细的错误提示信息 - -### 运行时错误 - -1. **参数获取错误** - ``` - KeyError: 'parameter_name' - ``` - - **原因**:尝试访问不存在的参数 - - **解决**: - - 使用`get()`代替直接索引:`param = tool_parameters.get("param_name", "")` - - 确保参数名与YAML定义一致 - - 添加参数存在性检查 - -2. **API调用错误** - ``` - requests.exceptions.RequestException: Connection error - ``` - - **原因**:外部API调用失败 - - **解决**: - - 添加超时参数:`timeout=10` - - 使用`try/except`捕获异常 - - 实现重试逻辑 - -3. **执行超时** - ``` - TimeoutError: Function execution timed out - ``` - - **原因**:操作耗时过长 - - **解决**: - - 优化API调用 - - 分解复杂操作为多个步骤 - - 设置合理的超时限制 - -### 配置和打包错误 - -1. **YAML格式错误** - ``` - yaml.YAMLError: mapping values are not allowed in this context - ``` - - **原因**:YAML格式不正确 - - **解决**: - - 检查缩进(使用空格而非制表符) - - 确保冒号后有空格 - - 使用YAML验证器检查 - -2. **打包失败** - ``` - Error: Failed to pack plugin - ``` - - **原因**:文件结构或依赖问题 - - **解决**: - - 检查manifest.yaml配置 - - 确保所有引用的文件存在 - - 审查requirements.txt内容 - -## 代码示例:TOTP工具 - -以下是一个完整的TOTP (Time-based One-Time Password) 插件示例,展示了良好的代码组织和最佳实践: - -### utils/totp_verify.py -```python -import pyotp -import time - -def verify_totp(secret_key, totp_code, offset=5, strict=False): - """ - 验证基于时间的一次性密码(TOTP)。 - - Args: - secret_key: 用于生成TOTP的密钥或配置URL - totp_code: 用户提交的动态令牌 - offset: 允许提前或延迟验证的秒数 - strict: 是否使用严格验证(仅在精确匹配时返回成功) - - Returns: - 包含以下内容的字典: - - 'status': 'success' 或 'fail' - - 'detail': 内部消息(不面向终端用户) - """ - try: - # 检测是否为配置URL - if secret_key.startswith('otpauth://'): - totp = pyotp.parse_uri(secret_key) - else: - totp = pyotp.TOTP(secret_key) - - current_time = time.time() - - # 精确时间验证 - if totp.verify(totp_code): - return {'status': 'success', 'detail': 'Token is valid'} - - # 偏移验证 - early_valid = totp.verify(totp_code, for_time=current_time + offset) - late_valid = totp.verify(totp_code, for_time=current_time - offset) - off_time_valid = early_valid or late_valid - - detail_message = ( - f"Token is valid but not on time. " - f"{'Early' if early_valid else 'Late'} within {offset} seconds" - if off_time_valid else - "Token is invalid" - ) - - if strict: - return {'status': 'fail', 'detail': detail_message} - else: - return ( - {'status': 'success', 'detail': detail_message} - if off_time_valid - else {'status': 'fail', 'detail': detail_message} - ) - except Exception as e: - return {'status': 'fail', 'detail': f'Verification error: {str(e)}'} -``` - -### tools/totp.yaml -```yaml -identity: - name: totp - author: your-name - label: - en_US: TOTP Validator - zh_Hans: TOTP 验证器 -description: - human: - en_US: Time-based one-time password (TOTP) validator - zh_Hans: 基于时间的一次性密码 (TOTP) 验证器 - llm: Time-based one-time password (TOTP) validator, this tool is used to validate a 6 digit TOTP code with a secret key or provisioning URI. -parameters: - - name: secret_key - type: string - required: true - label: - en_US: TOTP secret key or provisioning URI - zh_Hans: TOTP 私钥或 URI - human_description: - en_US: The secret key or provisioning URI used to generate the TOTP - zh_Hans: 用于生成 TOTP 的私钥或 URI - llm_description: The secret key or provisioning URI (starting with 'otpauth://') used to generate the TOTP, this is highly sensitive and should be kept secret. - form: llm - - name: user_code - type: string - required: true - label: - en_US: 6 digit TOTP code to validate - zh_Hans: 要验证的 6 位 TOTP 代码 - human_description: - en_US: 6 digit TOTP code to validate - zh_Hans: 要验证的 6 位 TOTP 代码 - llm_description: 6 digit TOTP code to validate - form: llm -extra: - python: - source: tools/totp.py -output_schema: - type: object - properties: - True_or_False: - type: string - description: Whether the TOTP is valid or not, return in string format, "True" or "False". -``` - -### tools/totp.py -```python -from collections.abc import Generator -from typing import Any - -# 正确导入工具函数 -from utils.totp_verify import verify_totp - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -# 一个文件只包含一个Tool子类 -class TotpTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - """验证基于时间的一次性密码(TOTP)""" - # 获取参数,使用get()避免KeyError - secret_key = tool_parameters.get("secret_key") - totp_code = tool_parameters.get("user_code") - - # 参数验证 - if not secret_key: - yield self.create_text_message("Error: Secret key is required.") - return - if not totp_code: - yield self.create_text_message("Error: TOTP code is required.") - return - - try: - # 调用工具函数 - result = verify_totp(secret_key, totp_code) - - # 返回结果 - yield self.create_json_message(result) - - # 基于验证结果返回不同的消息 - if result["status"] == "success": - yield self.create_text_message("Valid") - yield self.create_variable_message("True_or_False", "True") - else: - yield self.create_text_message("Invalid") - yield self.create_variable_message("True_or_False", "False") - - except Exception as e: - # 错误处理 - yield self.create_text_message(f"Verification error: {str(e)}") -``` - -### tools/secret_generator.py -```python -from collections.abc import Generator -from typing import Any - -import pyotp - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -# 注意:一个文件只包含一个Tool子类 -class SecretGenerator(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - """生成TOTP密钥""" - try: - # 生成随机密钥 - secret_key = pyotp.random_base32() - yield self.create_text_message(secret_key) - - # 安全获取可选参数 - name = tool_parameters.get("name") - issuer_name = tool_parameters.get("issuer_name") - - # 如果提供了名称或发行方,生成配置URI - if name or issuer_name: - provisioning_uri = pyotp.totp.TOTP(secret_key).provisioning_uri( - name=name, - issuer_name=issuer_name - ) - yield self.create_variable_message("provisioning_uri", provisioning_uri) - - except Exception as e: - yield self.create_text_message(f"Error generating secret: {str(e)}") -``` - -### requirements.txt -``` -dify_plugin~=0.0.1b76 -pyotp~=2.9.0 -``` - -这个示例展示了: -- 清晰的功能分离(utils中的工具函数,tools中的工具类) -- 良好的错误处理和参数验证 -- 一个文件只包含一个Tool子类 -- 详细的注释和文档字符串 -- 精心设计的YAML配置 - -## 状态同步机制 - -如果用户的描述与你记录的项目状态不同,或者你需要确认当前进度,请执行以下操作: - -1. 检查项目文件结构 -2. 阅读关键文件 -3. 明确告知用户:"我注意到项目状态可能与我之前的理解不同,我已重新检查了项目文件并更新了我的认知。" -4. 描述你发现的实际状态 -5. 更新working目录中的进度记录 - -## 首次启动行为 - -当用户通过"@ai"或类似方式首次激活你时,你应该: - -1. **不要假设项目目标**:不要自行假定用户想开发什么类型的插件或功能 -2. **不要开始编写代码**:不要在没有明确指示的情况下就开始生成或修改代码 -3. **询问用户意图**:礼貌地询问用户希望开发什么类型的插件,需要帮助解决什么问题 -4. **提供能力概述**:简要说明你可以提供哪些类型的帮助(代码实现、调试、设计建议等) -5. **请求项目信息**:请用户分享当前项目状态或文件结构,以便你提供更有针对性的帮助 - -只有在收到明确指示后,才开始提供具体的开发建议或代码实现。 - -记住,你的主要目标是协助用户高效地完成Dify插件开发,通过持续跟踪状态、提供专业建议和解决技术挑战来实现这一目标。 - -{/* -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-zh/0211-getting-started-by-prompt.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0211-getting-started-dify-tool.mdx b/plugin-dev-zh/0211-getting-started-dify-tool.mdx deleted file mode 100644 index 74e53bf8..00000000 --- a/plugin-dev-zh/0211-getting-started-dify-tool.mdx +++ /dev/null @@ -1,520 +0,0 @@ ---- -dimensions: "[object Object]" -standard_title: "Getting Started Dify Tool" -language: "zh" -title: "Dify 插件开发:Hello World 指南" -description: "本文档提供了从零开始Dify插件开发的详细教程,以创建Telegraph发布插件为例,涉及环境准备、项目初始化、虚拟环境配置、插件核心逻辑开发、本地运行调试、插件元信息完善以及打包发布等环节。" ---- - -欢迎阅读 Dify 插件开发的入门指南!本教程假设您具备基本的编程背景知识,并有使用 Dify 平台的经验。完成本教程后,您将掌握创建简单 Dify 插件的基础流程,从 Dify 用户迈向插件贡献者。 - -我们将一步步示范如何开发一个简单的 Telegraph 发布插件。本教程主要使用命令行操作,并辅以 VSCode 作为代码编辑器的示例说明。**建议您先快速通读一遍以了解整体流程,然后再跟着步骤动手操作。** - -> **面向 LLM 的说明:** 你也可以在这里使用我们构建的 prompt 来协助你开发插件:[Dify 插件开发:Prompt](/plugin-dev-zh/0211-getting-started-by-prompt) - -在开始之前,您可以随时查阅我们提供的 [**开发者速查表 (Cheatsheet)**](/plugin-dev-zh/0131-cheatsheet) 获取常用指令和信息,或在遇到更复杂问题时参考完整的开发者文档。 - -## 1. 准备开发环境 - -在开始开发 Dify 插件之前,请确保您的环境中已准备好以下工具: - -- **Dify 插件开发脚手架 (CLI):** 这是开发、调试和打包插件的核心工具,也称为 `dify-plugin-daemon` 或“插件开发 SDK”。 -- **Python 环境:** 需要 Python 3.12 或更高版本。 - -### 1.1 安装 Dify 插件开发脚手架 (CLI) - -> 更详细的开发环境准备指南,请参考[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools)。 - -1. **下载:** 访问 [Dify Plugin CLI Releases](https://github.com/langgenius/dify-plugin-daemon/releases) 页面。根据您的操作系统(Windows, macOS Intel/ARM, Linux)下载对应的最新版本二进制文件。 -2. **设置执行权限 (macOS / Linux):** - - **以下步骤以 macOS (Apple Silicon / M 系列芯片) 为例**,假设下载的文件名为 `dify-plugin-darwin-arm64`。在终端中,进入文件所在目录,并执行以下命令赋予其执行权限: - - ```bash - chmod +x dify-plugin-darwin-arm64 - ``` - - 对于 Linux 用户,请下载对应的 Linux 版本文件并执行类似 `chmod +x ` 的命令。 - - 对于 Windows 用户,下载 `.exe` 文件后通常可直接运行。 -3. **验证安装:** - - 在终端中,执行以下命令检查工具是否能正常运行(请将 `./dify-plugin-darwin-arm64` 替换为您下载的实际文件名或路径): - - ```bash - ./dify-plugin-darwin-arm64 version - ``` - - 如果终端成功输出了版本号信息(例如 `v0.0.1-beta.15`),则说明安装成功。 - -> **提示 (Tips):** -> -> - **macOS 安全提示:** 若在 macOS 上首次运行时提示“Apple 无法验证”或“无法打开”,请前往“系统设置”→“隐私与安全性”→“安全性”部分,找到相关提示并点击“仍要打开”或“允许”。 -> - **简化命令:** 您可以将下载的二进制文件重命名为一个更短的名称(例如 `dify` 或 `dify-plugin`),以便后续使用。示例:`mv dify-plugin-darwin-arm64 dify`,之后即可使用 `./dify version`。 -> - **全局安装 (可选):** 如果希望在系统的任何路径下都能直接运行该命令(例如,直接输入 `dify` 而不是 `./dify`),可以将重命名后的文件移动到系统的 `PATH` 环境变量包含的目录中,例如 `/usr/local/bin` (macOS/Linux) 或添加到 Windows 的环境变量中。 -> - 例如 (macOS/Linux): `sudo mv dify /usr/local/bin/` -> - 配置完成后,直接在终端输入 `dify version` 应能成功输出版本号。 - -**`为方便起见,本文后续将使用 ./dify 作为 Dify 插件开发脚手架命令的示例。请根据您的实际情况替换为对应的命令。`** - -## 2. 初始化插件项目 - -现在,让我们使用脚手架工具创建一个新的插件项目。 - -1. 打开终端,执行初始化命令: - - ```bash - ./dify plugin init - ``` -2. 根据提示依次输入插件的基本信息: - - **Plugin name:** 插件的唯一标识符。例如:`telegraph` - - _约束: 长度 1-128 字符,只能包含小写字母、数字、连字符(-)和下划线(\_)。_ - - **Author:** 插件作者的标识符。例如:`your-name` - - _约束: 长度 1-64 字符,只能包含小写字母、数字、连字符(-)和下划线(\_)。_ - - **Description:** 对插件功能的简短描述。例如:`A Telegraph plugin that allows you to publish your content easily` - - **Enable multilingual README:** 插件多语言 README 选项。勾选后,可在下方的 `Languages to generate` 中选择需要预置 README 文件的语种。 -3. **选择开发语言:** 当提示 `Select language` 时,请选择 `python`。 -4. **选择插件类型:** 当提示 `Select plugin type` 时,对于本教程,请选择 `tool`。 -5. **选择附加功能:** 接下来会提示是否需要包含 Provider 验证、持久存储等附加功能。对于这个简单的 Hello World 插件,我们暂时不需要这些,可以直接按 **回车键** 跳过所有选项,直到看到成功信息。 -6. **确认创建成功:** 当终端输出类似以下信息时,表示插件项目已成功创建: - - ```bash - [INFO] plugin telegraph created successfully, you can refer to `telegraph/GUIDE.md` for more information about how to develop it - ``` - -现在,您的当前目录下应该出现了一个名为 `telegraph` (或您指定的插件名) 的新文件夹,这就是您的插件项目。 - -## 3. 配置 Python 虚拟环境与依赖 - -为了隔离项目依赖,推荐使用 Python 虚拟环境。 - -### 3.1 创建并激活虚拟环境 (命令行方式) - -这是**推荐且通用**的方法,不依赖特定 IDE: - -1. **进入项目目录:** - - ```bash - cd telegraph - ``` -2. **创建虚拟环境:** (建议命名为 `venv`) - - ```bash - python -m venv venv - ``` -3. **激活虚拟环境:** - - **macOS / Linux:** - - ```bash - source venv/bin/activate - ``` - - **Windows (cmd.exe):** - - ```bash - venv\Scripts\activate.bat - ``` - - **Windows (PowerShell):** - - ```bash - venv\Scripts\Activate.ps1 - ``` - - 激活成功后,您的终端提示符前通常会显示 `(venv)` 字样。 - -### 3.2 安装基础依赖 - -项目初始化时生成的 `requirements.txt` 文件已包含插件开发所需的基础库 `dify_plugin`。激活虚拟环境后,执行以下命令安装: - -```bash -pip install -r requirements.txt -``` - -### 3.3 (可选) VSCode 集成环境配置 - -如果您使用 VSCode 作为代码编辑器,可以利用其集成功能来管理 Python 环境: - -1. **打开项目文件夹:** 使用 VSCode 打开刚刚创建的 `telegraph` 文件夹。 -2. **选择 Python 解释器:** - - 打开命令面板 (macOS: `Cmd+Shift+P`, Windows/Linux: `Ctrl+Shift+P`)。 - - 输入并选择 `Python: Select Interpreter`。 - - 在弹出的列表中,选择您刚刚创建的虚拟环境中的 Python 解释器(通常路径包含 `.venv/bin/python` 或 `venv\Scripts\python.exe`)。如果列表没有自动显示,您可以选择 `Enter interpreter path...` 手动查找。 - - _(请参考您本地对应的截图 ,它展示了选择解释器的界面)_ -3. **安装依赖 (若 VSCode 提示):** VSCode 可能会检测到 `requirements.txt` 文件并提示您安装其中的依赖项。如果出现提示,请确认安装。 - - _(请参考您本地对应的截图 ,它展示了确认安装依赖的界面)_ - -**`请确保后续的所有 pip install 命令和运行 python -m main 的操作都在已激活的虚拟环境中执行。`** - -## 4. 开发插件核心逻辑 - -现在我们开始编写插件代码。本示例将实现一个简单的工具,用于将指定内容发布到 Telegraph。 - -### 4.1 示例依赖库: `your-telegraph` - -我们将使用一个名为 `your-telegraph` 的 Python 库来与 Telegraph API 交互。(_这是一个假设的库名,请确保您实际使用的库是有效的_)。 - -> `your-telegraph` 是一个简化 Telegraph API 操作的 Python 包装器,可以用几行代码轻松发布内容。 - -其基本用法可能如下: - -```python -# 示例代码,非插件内代码 -from ytelegraph import TelegraphAPI - -# 需要一个 access_token -ph = TelegraphAPI(access_token="your_telegraph_access_token") - -# 创建页面并获取链接 -ph_link = ph.create_page_md("My First Page", "# Hello, Telegraph!\n\nThis is my first Telegraph page.") -print(ph_link) -``` - -我们的目标是在 Dify 插件中实现类似的功能。 - -### 4.2 添加并配置项目依赖 - -1. **安装依赖库:** 确保您的虚拟环境已激活,然后在终端中执行: - - ```bash - pip install your-telegraph - ``` -2. **`更新 requirements.txt:`** 打开项目根目录下的 `telegraph/requirements.txt` 文件,在 `dify_plugin` 下面添加一行,写入刚刚安装的库名: - - ```plaintext - dify_plugin - your-telegraph - ``` - - 这样做可以确保其他开发者或部署环境能够方便地安装所有必需的依赖。 - -### 4.3 配置 Provider 凭证 - -我们的示例需要 `telegraph_access_token`。我们需要在 Provider 配置中定义这个凭证,以便用户在使用插件时可以输入。关于 Provider 配置的更多信息,请参考[一般规范定义](/plugin-dev-zh/0411-general-specifications)。 - -1. **编辑 Provider YAML:** 打开 `telegraph/provider/telegraph.yaml` 文件。 -2. **`添加 credentials_for_provider:`** 在文件末尾(或适当位置)添加以下内容: - - ```yaml - # ... (文件可能已有的 identity, name, label, description, icon 等保持不变) ... - - credentials_for_provider: - telegraph_access_token: # 这是凭证的内部名称,将在 Python 代码中使用 - type: secret-input # 输入类型为密码框 - required: true # 此凭证是必需的 - label: # 在 Dify UI 中显示的标签 (支持多语言) - en_US: Telegraph Access Token - zh_Hans: Telegraph 访问令牌 - # ... (其他语言) - placeholder: # 输入框的提示文字 (支持多语言) - en_US: Enter your Telegraph access token - zh_Hans: 请输入您的 Telegraph 访问令牌 - # ... (其他语言) - help: # 帮助提示信息 (支持多语言) - en_US: How to get your Telegraph access token - zh_Hans: 如何获取 Telegraph 访问令牌 - # ... (其他语言) - url: https://telegra.ph/api#createAccount # 点击帮助提示时跳转的 URL - ``` - - **字段解释:** - - `telegraph_access_token`: 凭证的唯一标识符,代码中通过 `self.runtime.credentials["telegraph_access_token"]` 来访问用户输入的值。 - - `type: secret-input`: 表示在 Dify 界面上会显示为密码输入框。 - - `required: true`: 表示用户必须填写此凭证才能使用该插件提供的工具。 - - `label`, `placeholder`, `help`: 提供多语言界面文本。 - - `url`: (可选) 提供一个获取凭证的帮助链接。 - -### 4.4 实现工具 (Tool) 逻辑 - -现在我们来编写实际执行发布操作的工具代码。 - -1. **编辑 Tool Python 文件:** 打开 `telegraph/tools/telegraph.py`。 -2. **`实现 _invoke 方法:`** 将文件内容替换为以下代码: - - ```python - from collections.abc import Generator - from typing import Any - from ytelegraph import TelegraphAPI # 导入我们使用的库 - - from dify_plugin import Tool - from dify_plugin.entities.tool import ToolInvokeMessage - - class TelegraphTool(Tool): - """ - 一个简单的 Telegraph 发布工具。 - """ - - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]: - """ - 根据输入的标题和内容,创建一个新的 Telegraph 页面。 - - Args: - tool_parameters: 一个包含工具输入参数的字典: - - p_title (str): Telegraph 页面的标题。 - - p_content (str): 要发布的 Markdown 格式的内容。 - - Yields: - ToolInvokeMessage: 包含成功创建的 Telegraph 页面 URL 的消息。 - - Raises: - Exception: 如果页面创建失败,则抛出包含错误信息的异常。 - """ - # 1. 从运行时获取凭证 - try: - access_token = self.runtime.credentials["telegraph_access_token"] - except KeyError: - raise Exception("Telegraph Access Token 未配置或无效。请在插件设置中提供。") - - # 2. 获取工具输入参数 - title = tool_parameters.get("p_title", "Untitled") # 使用 .get 提供默认值 - content = tool_parameters.get("p_content", "") - - if not content: - raise Exception("发布内容不能为空。") - - # 3. 调用库执行操作 - try: - telegraph = TelegraphAPI(access_token) # 初始化 Telegraph API - ph_link = telegraph.create_page_md(title, content) # 创建页面 - except Exception as e: - # 如果库调用失败,抛出异常 - raise Exception(f"调用 Telegraph API 失败: {e}") - - # 4. 返回结果 - # 使用 create_link_message 生成一个包含链接的输出消息 - yield self.create_link_message(ph_link) - ``` - - **关键点:** - - 从 `self.runtime.credentials` 获取凭证。 - - 从 `tool_parameters` 获取工具的输入参数(参数名将在下一步的 YAML 中定义)。使用 `.get()` 是更健壮的方式。 - - 调用 `ytelegraph` 库执行实际操作。 - - 使用 `try...except` 捕获可能的错误并抛出异常。 - - 使用 `yield self.create_link_message(url)` 返回一个包含 URL 的结果给 Dify。 - -### 4.5 配置工具 (Tool) 参数 - -我们需要告诉 Dify 这个工具接收哪些输入参数。 - -1. **编辑 Tool YAML 文件:** 打开 `telegraph/tools/telegraph.yaml`。 -2. **定义参数:** 将文件内容替换或修改为: - - ```yaml - identity: - name: telegraph_publisher # 工具的唯一内部名称 - author: your-name - label: # 在 Dify UI 中显示的工具名称 (多语言) - en_US: Publish to Telegraph - zh_Hans: 发布到 Telegraph - # ... (其他语言) - description: - human: # 给人类用户看的工具描述 (多语言) - en_US: Publish content to Telegraph as a new page. - zh_Hans: 将内容作为新页面发布到 Telegraph。 - # ... (其他语言) - llm: # 给 LLM 看的工具描述 (用于 Agent 模式) - A tool that takes a title and markdown content, then publishes it as a new page on Telegraph, returning the URL of the published page. Use this when the user wants to publish formatted text content publicly via Telegraph. - parameters: # 定义工具的输入参数列表 - - name: p_title # 参数的内部名称,与 Python 代码中的 key 对应 - type: string # 参数类型 - required: true # 是否必需 - label: # 在 Dify UI 中显示的参数标签 (多语言) - en_US: Post Title - zh_Hans: 文章标题 - human_description: # 给人类用户看的参数描述 (多语言) - en_US: The title for the Telegraph page. - zh_Hans: Telegraph 页面的标题。 - llm_description: # 给 LLM 看的参数描述 (指导 Agent 如何填充) - The title of the post. Should be a concise and meaningful plain text string. - form: llm # 参数表单类型 ('llm' 或 'form') - - name: p_content - type: string - required: true - label: - en_US: Content (Markdown) - zh_Hans: 内容 (Markdown) - human_description: - en_US: The main content for the Telegraph page, written in Markdown format. - zh_Hans: Telegraph 页面的主要内容,请使用 Markdown 格式编写。 - llm_description: # 强调格式要求对 LLM 很重要 - The full content to be published on the Telegraph page. Must be provided in Markdown format. Ensure proper Markdown syntax for formatting like headings, lists, links, etc. - form: llm - extra: # 额外配置 - python: - source: tools/telegraph.py # 指向实现该工具逻辑的 Python 文件 - ``` - - **字段解释:** - - `identity`: 工具的基本信息,`name` 是唯一标识。 - - `description`: 分为 `human` (给用户看) 和 `llm` (给 Agent 看)。**`llm 描述对于 Agent 能否正确理解和使用工具至关重要。`** - - `parameters`: 定义每个输入参数。 - - `name`: 内部名称,需与 Python 代码中 `tool_parameters.get("...")` 的键一致。 - - `type`: 数据类型 (如 `string`, `number`, `boolean` 等)。 - - `required`: 是否必须提供。 - - `label`, `human_description`, `llm_description`: 类似 `identity` 中的描述,但针对具体参数。**`llm_description 应清晰指导 LLM 如何生成或获取该参数的值,包括格式要求(如此处的 Markdown)。`** - - `form`: 定义参数如何在 Dify 中呈现和填充。`llm` 表示该参数值可以由用户输入、通过变量传入,或者在 Agent 模式下由 LLM 自主决定;`form` 通常表示需要用户在界面上固定填写的配置项。对于工具输入,`llm` 更常见。 - - `extra.python.source`: 指明实现此工具逻辑的 Python 文件路径(相对于项目根目录)。 - -### 4.6 实现 Provider 凭证验证 (可选但推荐) - -为了确保用户提供的凭证有效,我们应该实现验证逻辑。 - -1. **编辑 Provider Python 文件:** 打开 `telegraph/provider/telegraph.py`。 -2. **`实现 _validate_credentials 方法:`** 将文件内容替换为: - - ```python - from typing import Any - from dify_plugin import ToolProvider - from dify_plugin.errors.tool import ToolProviderCredentialValidationError - - class TelegraphProvider(ToolProvider): - def _validate_credentials(self, credentials: dict[str, Any]) -> None: - """ - 验证提供的 Telegraph Access Token 是否有效。 - 尝试使用该 token 创建一个测试页面。 - 如果验证失败,应抛出 ToolProviderCredentialValidationError 异常。 - """ - access_token = credentials.get("telegraph_access_token") - if not access_token: - raise ToolProviderCredentialValidationError("Telegraph Access Token 不能为空。") - - try: - # 尝试执行一个需要凭证的简单操作来验证 - from ytelegraph import TelegraphAPI - ph = TelegraphAPI(access_token=access_token) - # 尝试创建一个临时的、无害的页面作为验证手段 - # 注意:更好的验证方式可能是调用 API 的 'getAccountInfo' 等只读方法(如果存在) - test_page = ph.create_page_md("Dify Validation Test", "This is a test page created by Dify plugin validation.") - # 如果需要,可以考虑立即编辑或删除这个测试页面,但这会增加复杂性 - # print(f"Validation successful. Test page created: {test_page}") - except Exception as e: - # 如果 API 调用失败,说明凭证很可能无效 - raise ToolProviderCredentialValidationError(f"Telegraph 凭证验证失败: {e}") - - ``` - - **关键点:** - - 从 `credentials` 字典中获取凭证。 - - 执行一个需要该凭证的 API 调用(最好是只读操作,如获取账户信息;如果没有,创建一个无害的测试页面也可以,但要注意可能产生的副作用)。 - - 如果 API 调用成功,则不抛出异常,表示验证通过。 - - 如果 API 调用失败,则捕获异常并抛出 `ToolProviderCredentialValidationError`,将原始错误信息包含在内。 - -## 5. 本地运行与调试 - -现在可以在本地运行插件,并在 Dify 中进行调试了。 - -1. **`准备 .env 文件:`** - - 确保您仍在 `telegraph` 项目目录下。 - - 复制环境变量模板文件: - - ```bash - cp .env.example .env - ``` - - **`编辑 .env 文件:`** 打开刚刚创建的 `.env` 文件,填入您的 Dify 环境信息: - - ```dotenv - DIFY_API_HOST=https://your-dify-host.com # 替换为您的 Dify 实例地址 (例如 https://cloud.dify.ai) - DIFY_API_KEY=your-api-key # 替换为您的 Dify API 密钥 - ``` - - **获取 Host 和 Key:** 登录您的 Dify 环境,点击右上角的“插件”图标,然后点击调试图标(或类似虫子形状)。在弹出的窗口中,复制“API 密钥 (Key)”和“主机地址 (Host)”。 _(请参考您本地对应的截图 ,它展示了获取密钥和主机地址的界面)_ -2. **启动本地插件服务:** - - 确保您的 Python 虚拟环境已激活。 - - 在 `telegraph` 目录下,运行主程序: - - ```bash - python -m main - ``` - - **观察终端输出:** 如果一切正常,您应该会看到类似以下的日志信息,表示插件工具已成功加载并连接到 Dify: - - ```json - {"event": "log", "data": {"level": "INFO", "message": "Installed tool: telegraph_publisher", "timestamp": 1678886400.123456}} - {"event": "log", "data": {"level": "INFO", "message": "Plugin daemon started, waiting for requests...", "timestamp": 1678886400.123457}} - ``` -3. **在 Dify 中查看并测试:** - - **刷新 Dify 页面:** 回到您的 Dify 环境(浏览器中),刷新插件管理页面 (通常是 `https://your-dify-host.com/plugins`)。 - - **查找插件:** 您应该能在列表中看到名为 "Telegraph" (或您在 Provider YAML 中定义的 `label`) 的插件,并且可能带有一个“调试中”的标记。 - - **添加凭证:** 点击该插件,系统会提示您输入之前在 `provider/telegraph.yaml` 中定义的 "Telegraph Access Token"。输入有效的 token 并保存。如果您的验证逻辑 (`_validate_credentials`) 实现正确,这里会进行验证。 _(请参考您本地对应的截图 ,它展示了插件出现在列表并请求授权的界面)_ - - **在应用中使用:** 现在,您可以在 Dify 的应用(如 Chatbot 或 Workflow)中添加这个工具节点,并尝试调用它了!当您在应用中运行并触发该工具时,请求会被转发到您本地运行的 `python -m main` 进程进行处理。您可以在本地终端看到相关的日志输出,并进行调试。 -4. **停止本地服务:** 在终端中按下 `Ctrl + C` 可以停止本地插件服务。 - -这个运行 -\> 测试 -\> 停止 -\> 修改代码 -\> 重新运行 的循环是插件开发的主要流程。 - -## 6. 完善插件元信息 - -为了让插件更专业、更易于被发现和理解,我们需要完善一些展示性的信息。 - -1. **图标 (Icon):** - - 在 `telegraph/_assets` 目录下放置一个代表您插件的图标文件(例如 `icon.png`, `icon.svg`)。推荐使用正方形、清晰的图片。 -2. **`Provider 信息 (provider/telegraph.yaml):`** - - 确保 `identity` 部分的 `label` (显示名称), `description` (功能描述), 和 `icon` (填写图标文件名,如 `icon.png`) 已填写并支持多语言。这部分信息主要在 Dify 应用编排界面中展示给\_使用\_插件的用户。 - - ```yaml - identity: - author: your-name - name: telegraph # 内部名称,保持不变 - label: - en_US: Telegraph - zh_Hans: Telegraph 发布文章 - description: - en_US: A Telegraph plugin that allow you publish your content easily - zh_Hans: 一个让您轻松发布内容的Telegraph插件 - icon: icon.png # 引用 _assets 目录下的图标文件名 - ``` -3. **`插件清单 (manifest.yaml):`** - - 编辑项目根目录下的 `telegraph/manifest.yaml` 文件。这是整个插件的“身份证”,其信息将展示在 Dify 的**插件管理页面**和**插件市场 (Marketplace)** 中。 - - 务必更新或确认以下字段: - - `label`: 插件的**主要显示名称** (支持多语言)。 - - `description`: 对插件功能的**整体简介** (支持多语言),应清晰概括其核心价值。注意市场展示可能有长度限制。 - - `icon`: 插件的**主图标** (直接填写 `_assets` 目录下的图标文件名,如 `icon.png`)。 - - `tags`: 为插件添加分类标签,有助于用户在市场中筛选。可选值请参考 Dify 提供的枚举或文档说明 (例如 `media`, `tools`, `data-processing` 等)。可参考 [ToolLabelEnum 定义](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/dify_plugin/entities/tool.py)。 - - ```yaml - label: - en_US: Telegraph Publisher - zh_Hans: Telegraph 发布助手 - description: - en_US: Easily publish content to Telegraph pages directly from your Dify applications. Supports Markdown formatting. - zh_Hans: 从 Dify 应用中轻松将内容发布为 Telegraph 页面,支持 Markdown 格式。 - icon: icon.png - tags: ['media', 'content-creation'] # 示例标签 - # ... (author, name 等其他字段保持不变) - ``` -4. **README 和隐私政策:** - - `README.md`: 编辑项目根目录下的 `README.md` 文件。它将作为插件在 **Marketplace** 上的详细介绍页面,应包含更丰富的信息,如功能详述、使用示例、配置指南、常见问题等。可参考 [AWS 插件市场页面](https://marketplace.dify.ai/plugins/langgenius/aws_tools) 的样式。 - - - README 支持多语言,具体规范请阅读 [多语言 README](/plugin-dev-zh/0411-multilingual-readme)。 - - - `PRIVACY.md`: 如果您计划将插件发布到官方 Marketplace,需要提供隐私政策说明文件 `PRIVACY.md`,描述插件如何处理数据。 - -## 7. 打包插件 - -当插件开发完成并通过本地测试后,您可以将其打包成一个 `.difypkg` 文件,用于分发或安装。关于插件打包和发布的详细信息,请参考[发布概览](/plugin-dev-zh/0321-release-overview)。 - -1. **返回上级目录:** 确保您的终端当前路径在 `telegraph` 文件夹的**上一级**。 - - ```bash - cd .. - ``` -2. **执行打包命令:** - - ```bash - ./dify plugin package ./telegraph - ``` - - (请将 `./telegraph` 替换为您插件项目的实际路径) -3. **获取打包文件:** 命令执行成功后,将在当前目录下生成一个名为 `telegraph.difypkg` (或 `您的插件名.difypkg`) 的文件。 - -这个 `.difypkg` 文件就是一个完整的插件包。您可以: - -- 在 Dify 的插件管理页面手动**上传并安装**它。 -- 将其**分享**给其他人安装。 -- 按照 Dify 的规范和流程,将其**发布到官方的插件市场 (Marketplace)**,让所有 Dify 用户都能发现和使用您的插件。具体发布流程请参考[发布到 Dify 市场](/plugin-dev-zh/0322-release-to-dify-marketplace)。 - -恭喜!您已经完成了第一个 Dify 插件的开发、调试、完善和打包的全过程。现在您可以基于这个基础,探索更复杂、更强大的插件功能了。 - -## 下一步学习 - -- [远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin) - 了解更高级的插件调试技巧 -- [持久化存储](/plugin-dev-zh/0411-persistent-storage-kv) - 学习如何在插件中使用数据存储 -- [Slack 机器人插件开发示例](/plugin-dev-zh/0432-develop-a-slack-bot-plugin) - 查看更复杂的插件开发案例 -- [工具插件](/plugin-dev-zh/0222-tool-plugin) - 探索工具插件的高级功能 - -{/* -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-zh/0211-getting-started-dify-tool.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0211-getting-started-new-model.mdx b/plugin-dev-zh/0211-getting-started-new-model.mdx deleted file mode 100644 index 7abfd72c..00000000 --- a/plugin-dev-zh/0211-getting-started-new-model.mdx +++ /dev/null @@ -1,125 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: basic - level: beginner -standard_title: Getting Started New Model -language: zh -title: 快速接入一个新模型 -description: 本文档指导非专业开发者如何为Dify添加新模型,重点在于通过修改配置文件为现有模型供应商添加新型号模型。包括Fork仓库、复制与修改模型配置、更新供应商版本、本地测试以及提交贡献的完整流程。 ---- - -欢迎来到 Dify 的插件开发世界!Dify 的强大功能离不开社区贡献者的共同努力。我们相信,即使你不是专业的程序员,只要你对 AI 技术充满热情并愿意查阅资料,也能为 Dify 贡献自己的一份力量,例如帮助 Dify 支持更多、更新的 AI 模型。 - -本文将以最简明的方式,带你完成最常见也最简单的贡献:为一个 Dify **已经支持**的模型供应商,添加一个**新型号**的模型。这种方式通常**只需要修改配置文件**,无需编写代码,非常适合作为你的第一个贡献! - -> **相关概念**:在开始前,建议你阅读[模型插件](/plugin-dev-zh/0131-model-plugin-introduction)文档,了解模型插件的基本概念和结构。 - -**这种快速接入方式适用于:** - -- 新模型属于 Dify 已有插件支持的供应商(如 OpenAI, Google Gemini, Anthropic Claude 等)。 -- 新模型与同系列其他模型使用相同的 API 认证和基础调用逻辑。 -- 主要区别在于模型 ID、上下文长度、最大 Token 数、定价等配置参数。 - -_(如果你需要添加的模型需要新的 API 逻辑或支持特殊功能,那将涉及到 Python 代码编写,请参考 [创建新模型提供者](/plugin-dev-zh/0222-creating-new-model-provider) 获取更详细的指南。)_ - -**准备工作:** - -- 熟悉基本的 Git 操作 (Fork, Clone, Pull Request)。 -- 一个 GitHub 账号。 -- 安装并配置好 Dify 插件开发工具包 (参考 [初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools))。 - -**操作步骤:** - -1. **Fork & Clone 官方插件仓库:** - - - 访问 Dify 官方插件仓库 `https://github.com/langgenius/dify-official-plugins`。 - - 点击 "Fork" 按钮,将仓库复刻到你自己的 GitHub 账号下。 - - 使用 Git 将你 Fork 的仓库 Clone 到你的本地电脑。 - -2. **找到并复制模型配置文件:** - - - 在本地仓库中,导航到 `models/` 目录下,找到你想要添加模型的供应商文件夹,例如 `vertex_ai`。 - - 进入该供应商对应的模型类型子目录,通常是 `models/llm/` (如果是文本生成模型)。 - - 在该目录下,找到一个与你要添加的新型号最相似的现有模型的 YAML 配置文件(例如 `gemini-1.0-pro-001.yaml`)。 - - 复制这个 YAML 文件,并将其重命名为能清晰标识新型号的名称(例如 `gemini-1.5-pro-latest.yaml`)。 - -3. **修改模型配置 (YAML):** - - - 打开你刚刚重命名的 YAML 文件 (例如 `gemini-1.5-pro-latest.yaml`)。 - - **核心步骤:** 参考**模型供应商的官方文档**,仔细核对并修改文件中的以下关键信息: - - `model`: **必须**更新为新型号的官方 API 标识符。 - - `label`: **必须**更新为在 Dify 界面中展示给用户的模型名称 (建议提供 `en_US` 和 `zh_Hans` 两种语言)。 - - `model_properties`: 更新 `context_size` (上下文窗口大小)。 - - `parameter_rules`: 检查并更新模型参数的限制,特别是 `max_tokens` (最大输出 Token 数) 的 `default`, `min`, `max` 值。 - - `pricing`: 更新模型的输入 (`input`) 和输出 (`output`) 定价,以及单位 (`unit`, 通常是 `0.000001` 表示百万 Token) 和货币 (`currency`)。 - - _(参考)_ 关于模型 YAML 文件各字段的详细规范,请查阅 [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) 和 [模型 Schema 定义](/plugin-dev-zh/0412-model-schema)。 - - **示例 (添加 Gemini 1.5 Pro):** - - | 参数 | 可能的旧模型 (示例) | 新 Gemini 1.5 Pro (示例) | 说明 | - | :---------------- | :------------------- | :----------------------- | :---------------------------------- | - | `model` | `gemini-1.0-pro-001` | `gemini-1.5-pro-latest` | **必须**修改为官方模型 ID | - | `label: en_US` | Gemini 1.0 Pro | Gemini 1.5 Pro | **必须**修改为用户可见标签 | - | `context_size` | 30720 | 1048576 | **必须**根据官方文档修改 | - | `max_tokens` (下) | 2048 | 8192 | **必须**根据官方文档修改默认/最大值 | - -4. **更新供应商 Manifest 版本:** - - - 回到该模型供应商的根目录 (例如 `models/vertex_ai/`)。 - - 找到并打开 `manifest.yaml` 文件。 - - 将其中的 `version` 字段递增一个小版本号 (例如 `version: 0.0.8` -> `version: 0.0.9`)。这告诉 Dify 这是一个更新。 - -5. **打包与本地测试:** - - - 打开你的终端 (命令行工具)。 - - **确保你的当前目录是 `dify-official-plugins` 仓库的根目录** (即包含 `models`, `tools` 等文件夹的那个目录)。 - - 运行打包命令: - - ```bash - # 将 替换为实际的供应商目录名,例如 cohere 或 vertex_ai - dify plugin package models/ - ``` - - - _成功后,你会看到类似 `plugin packaged successfully, output path: .difypkg` 的提示,并在当前项目根目录下生成一个名为 `.difypkg` 的插件包文件。_ - - 登录你的 Dify 实例 (本地部署或云版本均可)。 - - 点击 Dify 页面最顶部导航栏右侧的 **"插件"** 菜单项。 - - 在插件页面,点击 **"安装插件"** 按钮。 - - 选择 **"本地插件"** 选项卡。 - - 点击上传区域,选择或拖拽你刚刚在本地生成的 `.difypkg` 文件进行上传。 - - 等待插件安装或更新完成。 - - 安装成功后,通常需要前往 "设置" -> "模型供应商" 找到对应的供应商,并配置你的 API 凭证(如果你之前没有配置过的话)。 - - 创建一个新的 Dify 应用或编辑现有应用,在 "提示词编排" -> "模型" 设置中,尝试选择你新添加的模型。进行一些简单的对话或调用测试,确保它能正常工作并返回预期结果。 - -6. **提交你的贡献:** - - 本地测试无误后,将你的修改(新的模型 YAML 文件和更新后的 `manifest.yaml`)通过 Git 提交 (commit) 并推送 (push) 到你 Fork 的 GitHub 仓库。 - - 在 GitHub 上,向 `langgenius/dify-official-plugins` 主仓库发起一个 Pull Request (PR)。在 PR 描述中,可以简要说明你添加了哪个模型,并附上该模型官方文档的链接,方便审核者确认参数。 - ---- - -**然后呢?** - -一旦你的 PR 被审核通过并合并,你的贡献就会成为 Dify 官方插件的一部分,所有 Dify 用户都能方便地使用这个新模型了! - -这种快速接入方法是让 Dify 支持新模型的最快途径。当然,如果未来这个模型需要支持更复杂的功能(例如图片输入、函数调用等),那么可能就需要有经验的开发者对插件进行代码层面的更新了。但你现在完成的这一步,已经是非常有价值的贡献! - -**探索更多:** - -- [模型 Schema 定义](/plugin-dev-zh/0412-model-schema) (了解模型 YAML 文件的详细规则) -- [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) (了解模型参数设计的规范) -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) (了解 `manifest.yaml` 的作用) -- [创建新模型提供者](/plugin-dev-zh/0222-creating-new-model-provider) (了解如何添加新的模型提供商) -- [发布至 Dify 市场](/plugin-dev-zh/0322-release-to-dify-marketplace) (学习如何发布你的插件) -- [Dify 官方插件仓库](https://github.com/langgenius/dify-official-plugins) (查看其他插件的例子) - -{/* -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-zh/0211-getting-started-new-model.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0221-initialize-development-tools.mdx b/plugin-dev-zh/0221-initialize-development-tools.mdx deleted file mode 100644 index 8e2492c0..00000000 --- a/plugin-dev-zh/0221-initialize-development-tools.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: beginner -standard_title: Initialize Development Tools -language: zh -title: 初始化开发工具 -description: 本文档详细介绍了Dify插件开发前的必要准备工作,包括安装Dify插件CLI工具(dify-plugin-daemon)和配置Python环境(版本要求≥3.12)的完整步骤。文档还提供了各类型插件开发的参考链接。 ---- - -开发 Dify 插件需要进行以下准备。本文档是开始[插件开发](/plugin-dev-zh/0111-getting-started-dify-plugin)的第一步。 - -* Dify 插件 CLI 工具 -* Python 环境,版本号 ≥ 3.12 - -> Dify 插件 CLI 工具又称为 `dify-plugin-daemon`,可以被视作**插件开发 SDK**。 - -### **1. 安装 Dify 插件 CLI 工具** - -Dify 插件 CLI 工具可以通过 Homebrew(在 Linux 和 macOS 上)或独立的二进制可执行文件(在 Windows、Linux 和 macOS 上)进行安装。 - -#### 通过 Homebrew 安装 - -对于 macOS 和 Linux 用户,建议使用 [Homebrew](https://brew.sh/) 安装 Dify 插件 CLI 工具。 - -首先添加 [Dify 插件 CLI 工具的 Homebrew 配方](https://github.com/langgenius/homebrew-dify),然后使用 `brew install` 命令进行安装。 - -```bash -brew tap langgenius/dify -brew install dify -``` - -要检查安装是否成功,请运行 `dify version`,应该会显示版本代码。 -```bash -dify version -``` - -要升级 Dify 插件 CLI 工具,请运行以下命令: - -```bash -brew upgrade dify -``` - -#### 通过二进制可执行文件安装 - -**下载二进制可执行文件:** - -访问 [Dify Plugin CLI](https://github.com/langgenius/dify-plugin-daemon/releases) 项目地址,在发布页面的资产列表中,选择并下载适合操作系统(Linux / macOS / Windows)和芯片架构(`amd64` 为 x86 芯片 / `arm64` 为 ARM 或 Apple 的 M 芯片)的二进制可执行文件。 - -本文**以装载 M 系列芯片的 macOS** 为例。下载 `dify-plugin-darwin-arm64` 文件后,赋予其执行权限。 - -```bash -chmod +x ./dify-plugin-darwin-arm64 -mv ./dify-plugin-darwin-arm64 ./dify -``` - -要检查安装是否成功,请运行 `./dify version`,应该会显示版本代码。 -```bash -./dify version -``` - -> 若提示 “Apple 无法验证” 错误,请前往 **“设置 → 隐私与安全性 → 安全性”**,轻点 “仍要打开” 按钮。 - -运行命令后,终端若返回类似 `v0.0.1-beta.15` 的版本号信息,则说明安装成功。 - -> **💡 提示:** -> -> 如果想要在系统全局使用 `dify` 命令运行 CLI 工具,建议将该二进制文件重命名为 `dify` 并拷贝至 `/usr/local/bin` 系统路径内。 -> -> 配置完成后,在终端输入 `dify version` 命令后将输出版本号信息。 -> -> - -### **2. 初始化 Python 环境** - -详细说明请参考 [Python 安装教程](https://pythontest.com/python/installing-python-3-11/),或询问 LLM 安装版本号 ≥ 3.12 的 Python 环境。 - -### 3. 开发插件 - -请参考以下内容查看不同类型的插件开发示例: - -- [工具插件开发指南](/plugin-dev-zh/0211-getting-started-dify-tool) - Hello World 入门教程 -- [模型插件开发指南](/plugin-dev-zh/0211-getting-started-new-model) - 快速接入一个新模型 -- [Agent策略插件开发指南](/plugin-dev-zh/9433-agent-strategy-plugin) - 创建自定义推理策略 -- [扩展插件开发指南](/plugin-dev-zh/9231-extension-plugin) - 通过 Webhook 实现外部服务集成 -- [插件打包和发布](/plugin-dev-zh/0321-release-overview) - 发布你的插件 - -## 下一步学习 - -- [Dify 插件开发:Hello World 指南](/plugin-dev-zh/0211-getting-started-dify-tool) - 开始你的第一个插件开发 -- [插件开发速查表](/plugin-dev-zh/0131-cheatsheet) - 了解常用命令和概念 -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - 学习插件元数据配置 - -{/* -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-zh/0221-initialize-development-tools.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0222-creating-new-model-provider-extra.mdx b/plugin-dev-zh/0222-creating-new-model-provider-extra.mdx deleted file mode 100644 index efd948d5..00000000 --- a/plugin-dev-zh/0222-creating-new-model-provider-extra.mdx +++ /dev/null @@ -1,285 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Creating New Model Provider Extra -language: zh -title: 实现标准的模型集成 -description: 本文档面向需要编写Python代码以添加或增强Dify模型支持的开发者,详细指导如何创建目录结构、编写模型配置、实现模型调用逻辑、调试和发布插件的完整流程,包含了核心方法实现和错误处理的细节。 ---- - -本文档是为需要通过编写 Python 代码来为 Dify 添加或增强模型支持的开发者准备的标准指南。当你需要添加的模型涉及新的 API 调用逻辑、特殊参数处理或 Dify 需要显式支持的新功能(如 Vision, Tool Calling)时,就需要遵循本指南的步骤。 - -**阅读本文前,建议你:** - -* 具备 Python 编程基础和面向对象编程的基本理解。 -* 熟悉你想要集成的模型供应商提供的 API 文档和认证方式。 -* 已安装并配置好 Dify 插件开发工具包 (参考 [初始化开发工具](../initialize-development-tools.md))。 -* (可选)阅读 [模型插件介绍](link-to-conceptual-intro) 文档,了解模型插件的基本概念和架构。 - -本指南将引导你完成创建目录结构、编写模型配置 (YAML)、实现模型调用逻辑 (Python) 以及调试和发布插件的全过程。 - ---- - -## 第 1 步: 创建目录结构 - -一个组织良好的目录结构是开发可维护插件的基础。你需要为你的模型供应商插件创建特定的目录和文件。 - -1. **定位或创建供应商目录:** 在你的插件项目(通常是 `dify-official-plugins` 的本地克隆)的 `models/` 目录下,找到或创建以模型供应商命名的文件夹(例如 `models/my_new_provider`)。 -2. **创建 `models` 子目录:** 在供应商目录下,创建 `models` 子目录。 -3. **按模型类型创建子目录:** 在 `models/models/` 目录下,为你需要支持的**每种模型类型**创建一个子目录。常见的类型包括: - * `llm`: 文本生成模型 - * `text_embedding`: 文本 Embedding 模型 - * `rerank`: Rerank 模型 - * `speech2text`: 语音转文字模型 - * `tts`: 文字转语音模型 - * `moderation`: 内容审查模型 -4. **准备实现文件:** - * 在每个模型类型目录下(例如 `models/models/llm/`),你需要创建一个 Python 文件来实现该类型模型的调用逻辑(例如 `llm.py`)。 - * 同样在该目录下,你需要为该类型下的每个具体模型创建一个 YAML 配置文件(例如 `my-model-v1.yaml`)。 - * (可选)可以创建一个 `_position.yaml` 文件来控制该类型下模型在 Dify UI 中的显示顺序。 - -**示例结构 (假设供应商 `my_provider` 支持 LLM 和 Embedding):** - -```bash -models/my_provider/ -├── models # 模型实现和配置目录 -│ ├── llm # LLM 类型 -│ │ ├── _position.yaml (可选, 控制排序) -│ │ ├── my-llm-model-v1.yaml -│ │ ├── my-llm-model-v2.yaml -│ │ └── llm.py # LLM 实现逻辑 -│ └── text_embedding # Embedding 类型 -│ ├── _position.yaml (可选, 控制排序) -│ ├── my-embedding-model.yaml -│ └── text_embedding.py # Embedding 实现逻辑 -├── provider # 供应商级别代码目录 -│ └── my_provider.py (用于凭证验证等, 参考“创建模型供应商”文档) -└── manifest.yaml # 插件清单文件 -``` - ---- - -## 第 2 步: 定义模型配置 (YAML) - -对于每个具体模型,你需要创建一个 YAML 文件来描述其属性、参数和功能,以便 Dify 能够正确地理解和使用它。 - -1. **创建 YAML 文件:** 在对应的模型类型目录下(例如 `models/models/llm/`),为你要添加的模型创建一个 YAML 文件,文件名通常与模型 ID 保持一致或具有描述性(例如 `my-llm-model-v1.yaml`)。 -2. **编写配置内容:** 遵循 [AIModelEntity Schema Definition](../../../schema-definition/model/model-designing-rules.md#aimodelentity) 规范编写内容。关键字段包括: - * `model`: (必需) 模型的官方 API 标识符。 - * `label`: (必需) 在 Dify UI 中显示的名称 (支持多语言)。 - * `model_type`: (必需) 必须与所在目录类型一致 (如 `llm`)。 - * `features`: (可选) 声明模型支持的特殊功能 (如 `vision`, `tool-call`, `stream-tool-call` 等)。 - * `model_properties`: (必需) 定义模型固有属性,如 `mode` (`chat` 或 `completion`), `context_size`。 - * `parameter_rules`: (必需) 定义用户可调参数及其规则 (名称 `name`, 类型 `type`, 是否必须 `required`, 默认值 `default`, 范围 `min`/`max`, 选项 `options` 等)。可以使用 `use_template` 引用预定义模板简化常见参数(如 `temperature`, `max_tokens`)的配置。 - * `pricing`: (可选) 定义模型的计费信息。 - -**示例 (`claude-3-5-sonnet-20240620.yaml`):** - -```yaml -model: claude-3-5-sonnet-20240620 -label: - en_US: claude-3-5-sonnet-20240620 -model_type: llm -features: - - agent-thought - - vision - - tool-call - - stream-tool-call - - document -model_properties: - mode: chat - context_size: 200000 -parameter_rules: - - name: temperature - use_template: temperature - - name: top_p - use_template: top_p - - name: max_tokens - use_template: max_tokens - required: true - default: 8192 - min: 1 - max: 8192 # 注意 Dify 层面可能有限制 -pricing: - input: '3.00' - output: '15.00' - unit: '0.000001' # 每百万 token - currency: USD -``` - ---- - -## 第 3 步: 编写模型调用代码 (Python) - -这是实现模型功能的和核心步骤。你需要在对应模型类型的 Python 文件中(例如 `llm.py`)编写代码来处理 API 调用、参数转换和结果返回。 - -1. **创建/编辑 Python 文件:** 在模型类型目录下(例如 `models/models/llm/`)创建或打开相应的 Python 文件(例如 `llm.py`)。 -2. **定义实现类:** - * 定义一个类,例如 `MyProviderLargeLanguageModel`。 - * 该类必须继承自 Dify 插件 SDK 中对应的**模型类型基类**。例如,对于 LLM,需要继承 `dify_plugin.provider_kits.llm.LargeLanguageModel`。 - - ```python - import logging - from typing import Union, Generator, Optional, List - from dify_plugin.provider_kits.llm import LargeLanguageModel # 导入基类 - from dify_plugin.provider_kits.llm import LLMResult, LLMResultChunk, LLMUsage # 导入结果和用量类 - from dify_plugin.provider_kits.llm import PromptMessage, PromptMessageTool # 导入消息和工具类 - from dify_plugin.errors.provider_error import InvokeError, InvokeAuthorizationError # 导入错误类 - # 假设你有一个 vendor_sdk 用于调用 API - # import vendor_sdk - - logger = logging.getLogger(__name__) - - class MyProviderLargeLanguageModel(LargeLanguageModel): - # ... 实现方法 ... - ``` - -3. **实现关键方法:** (具体需要实现的方法取决于继承的基类,以下以 LLM 为例) - * `_invoke(...)`: **核心调用方法**。 - * **签名:** `def _invoke(self, model: str, credentials: dict, prompt_messages: List[PromptMessage], model_parameters: dict, tools: Optional[List[PromptMessageTool]] = None, stop: Optional[List[str]] = None, stream: bool = True, user: Optional[str] = None) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]:` - * **职责:** - * 使用 `credentials` 和 `model_parameters` 准备 API 请求。 - * 将 Dify 的 `prompt_messages` 格式转换为供应商 API 所需的格式。 - * 处理 `tools` 参数以支持 Function Calling / Tool Use (如果模型支持)。 - * 根据 `stream` 参数决定是进行流式调用还是同步调用。 - * **流式返回:** 如果 `stream=True`,此方法必须返回一个生成器 (`Generator`),通过 `yield` 逐块返回 `LLMResultChunk` 对象。每个 chunk 包含部分结果(文本、工具调用块等)和可选的用量信息。 - * **同步返回:** 如果 `stream=False`,此方法必须返回一个完整的 `LLMResult` 对象,包含最终的文本结果、完整的工具调用列表以及总的用量信息 (`LLMUsage`)。 - * **实现模式:** 强烈建议将同步和流式逻辑拆分到内部帮助方法中。 - - ```python - def _invoke(self, ..., stream: bool = True, ...) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]: - # 准备 API 请求参数 (认证、模型参数转换、消息格式转换等) - api_params = self._prepare_api_params(credentials, model_parameters, prompt_messages, tools, stop) - - try: - if stream: - return self._invoke_stream(model, api_params, user) - else: - return self._invoke_sync(model, api_params, user) - except vendor_sdk.APIError as e: - # 处理 API 错误, 映射到 Dify 错误 (参考 _invoke_error_mapping) - # ... raise mapped_error ... - pass # Replace with actual error handling - except Exception as e: - logger.exception("Unknown error during model invocation") - raise e # Or raise a generic InvokeError - - def _invoke_stream(self, model: str, api_params: dict, user: Optional[str]) -> Generator[LLMResultChunk, None, None]: - # 调用 vendor_sdk 的流式接口 - # for api_chunk in vendor_sdk.create_stream(...): - # # 将 api_chunk 转换为 LLMResultChunk - # dify_chunk = self._convert_api_chunk_to_llm_result_chunk(api_chunk) - # yield dify_chunk - pass # Replace with actual implementation - - def _invoke_sync(self, model: str, api_params: dict, user: Optional[str]) -> LLMResult: - # 调用 vendor_sdk 的同步接口 - # api_response = vendor_sdk.create_sync(...) - # 将 api_response 转换为 LLMResult (包括 message.content, tools, usage) - # dify_result = self._convert_api_response_to_llm_result(api_response) - # return dify_result - pass # Replace with actual implementation - ``` - - * `validate_credentials(self, model: str, credentials: dict) -> None`: (必需) 用于在用户添加或修改凭证时验证其有效性。通常通过调用一个简单的、低成本的 API 端点(如列出可用模型、检查余额等)来实现。如果验证失败,应抛出 `CredentialsValidateFailedError` 或其子类。 - * `get_num_tokens(self, model: str, credentials: dict, prompt_messages: List[PromptMessage], tools: Optional[List[PromptMessageTool]] = None) -> int`: (可选但推荐) 用于预估给定输入的 Token 数量。如果无法准确计算或 API 不支持,可以返回 0。 - * `@property _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]`: (必需) 定义一个**错误映射**字典。键是 Dify 的标准 `InvokeError` 子类,值是供应商 SDK 可能抛出的需要被映射到该标准错误的异常类型列表。这对于 Dify 统一处理不同供应商的错误至关重要。 - - ```python - @property - def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: - # 示例映射 - mapping = { - InvokeAuthorizationError: [ - vendor_sdk.AuthenticationError, - vendor_sdk.PermissionDeniedError, - ], - InvokeRateLimitError: [ - vendor_sdk.RateLimitError, - ], - # ... 其他映射 ... - } - # 可以在这里加入基类的默认映射 (如果基类提供的话) - # base_mapping = super()._invoke_error_mapping - # mapping.update(base_mapping) # 注意合并策略 - return mapping - ``` - ---- - -## 第 4 步: 调试插件 - -在将插件贡献给社区之前,充分的测试和调试是必不可少的。Dify 提供了远程调试功能,让你可以在本地修改代码并实时在 Dify 实例中测试效果。 - -1. **获取调试信息:** - * 在你的 Dify 实例中,进入 "插件管理" 页面 (可能需要管理员权限)。 - * 点击页面右上角的 "调试插件",获取你的 `调试 Key` 和 `远程服务器地址` (例如 `http://:5003`)。 -2. **配置本地环境:** - * 在你的本地插件项目**根目录**下,找到或创建 `.env` 文件 (可从 `.env.example` 复制)。 - * 编辑 `.env` 文件,填入调试信息: - - ```dotenv - INSTALL_METHOD=remote - REMOTE_INSTALL_HOST= # Dify 服务器地址 - REMOTE_INSTALL_PORT=5003 # 调试端口 - REMOTE_INSTALL_KEY=****-****-****-****-**** # 你的调试 Key - ``` - -3. **启动本地插件服务:** - * 在插件项目根目录下,确保你的 Python 环境已激活(如果使用虚拟环境)。 - * 运行主程序: - - ```bash - python -m main - ``` - - * 观察终端输出,如果连接成功,通常会有相应的日志提示。 -4. **在 Dify 中测试:** - * 刷新 Dify 的 "插件" 或 "模型供应商" 页面,你应该能看到你的本地插件实例,可能带有 "调试中" 标识。 - * 前往 "设置" -> "模型供应商",找到你的插件,配置有效的 API 凭证。 - * 在 Dify 应用中选择并使用你的模型进行测试。你在本地对 Python 代码的修改(保存后通常会自动重新加载服务)会直接影响 Dify 中的调用行为。使用 Dify 的调试预览功能可以帮助你检查输入输出和错误信息。 - ---- - -## 第 5 步: 打包与发布 - -当你完成了开发和调试,并对插件的功能满意后,就可以将其打包并贡献给 Dify 社区了。 - -1. **打包插件:** - * 停止本地调试服务 (`Ctrl+C`)。 - * 在插件项目**根目录**下运行打包命令: - - ```bash - # 将 替换为你的供应商目录名 - dify plugin package models/ - ``` - - * 这将在项目根目录下生成一个 `.difypkg` 文件。 -2. **提交 Pull Request:** - * 确保你的代码风格良好,并遵循 Dify 的[插件发布规范](https://docs.dify.ai/zh-hans/plugins/publish-plugins/publish-to-dify-marketplace)。 - * 将你的本地 Git 提交推送到你 Fork 的 `dify-official-plugins` 仓库。 - * 在 GitHub 上向 `langgenius/dify-official-plugins` 主仓库发起 Pull Request。在 PR 描述中清晰说明你所做的更改、添加的模型或功能,以及任何必要的测试说明。 - * 等待 Dify 团队审核。审核通过并合并后,你的贡献将包含在官方插件中,并在 [Dify Marketplace](https://marketplace.dify.ai/) 上可用。 - ---- - -## 探索更多 - -* [模型 Schema 定义](/plugin-dev-zh/0412-model-schema) (模型 YAML 规范) -* [插件 Manifest 结构](/plugin-dev-zh/0411-general-specifications) (`manifest.yaml` 规范) -* [Dify Plugin SDK 参考](https://github.com/langgenius/dify-plugin-sdks) (查找基类、数据结构和错误类型) -* [Dify 官方插件仓库](https://github.com/langgenius/dify-official-plugins) (查看现有插件的实现) - -{/* -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-zh/0222-creating-new-model-provider-extra.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0222-creating-new-model-provider.mdx b/plugin-dev-zh/0222-creating-new-model-provider.mdx deleted file mode 100644 index 3f33b526..00000000 --- a/plugin-dev-zh/0222-creating-new-model-provider.mdx +++ /dev/null @@ -1,273 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Creating New Model Provider -language: zh -title: 创建模型供应商 -description: 本文档详细指导如何创建模型供应商插件,包括项目初始化、模型配置方式(预定义模型和自定义模型)的选择、创建供应商配置YAML文件以及编写供应商代码的完整流程。 ---- - -创建 Model 类型插件的第一步是初始化插件项目并创建模型供应商文件,随后编写具体的预定义 / 自定义模型代码。如果你只是想为已有的模型供应商添加新模型,请参考[快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model)。 - -### 前置准备 - -* Dify 插件脚手架工具 -* Python 环境,版本号 ≥ 3.12 - -关于如何准备插件开发的脚手架工具,详细说明请参考[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools)。在开始之前,建议你先了解[模型插件](/plugin-dev-zh/0131-model-plugin-introduction)的基本概念和结构。 - -### 创建新项目 - -在脚手架命令行工具的路径下,创建一个新的 dify 插件项目。 - -``` -./dify-plugin-darwin-arm64 plugin init -``` - -如果你已将该二进制文件重命名为了 `dify` 并拷贝到了 `/usr/local/bin` 路径下,可以运行以下命令创建新的插件项目: - -```bash -dify plugin init -``` - -### 选择模型插件模板 - -脚手架工具内的所有模板均已提供完整的代码项目,选择 `LLM` 类型插件模板。 - -![Plugin type: llm](https://assets-docs.dify.ai/2024/12/8efe646e9174164b9edbf658b5934b86.png) - -#### 配置插件权限 - -为该 LLM 插件配置以下权限: - -* Models -* LLM -* Storage - -![模型插件权限](https://assets-docs.dify.ai/2024/12/10f3b3ee6c03a1215309f13d712455d4.png) - -#### 模型类型配置说明 - -模型供应商支持以下两种模型的配置方式: - -* `predefined-model` **预定义模型** - - 常见的大模型类型,只需要配置统一的供应商凭据即可使用模型供应商下的预定义模型。例如,`OpenAI` 模型供应商下提供 `gpt-3.5-turbo-0125` 和 `gpt-4o-2024-05-13` 等一系列预定义模型。详细开发说明请参考接入预定义模型。 -* `customizable-model` **自定义模型** - - 需要手动新增每个模型的凭据配置,例如 `Xinference`,它同时支持 LLM 和 Text Embedding,但是每个模型都有唯一的 **model\_uid**,如果想要将两者同时接入,需要为每个模型配置一个 **model\_uid**。详细开发说明请参考接入自定义模型。 - -两种配置方式**支持共存**,即存在供应商支持 `predefined-model` + `customizable-model` 或 `predefined-model` 等,即配置了供应商统一凭据可以使用预定义模型和从远程获取的模型,若新增了模型,则可以在此基础上额外使用自定义的模型。 - -### 新增模型供应商 - -新增一个模型供应商主要包含以下几个步骤: - -1. **创建模型供应商配置 YAML** **文件** - - 在供应商目录下新增一个 YAML 文件,用于描述供应商的基本信息和参数配置。按照 ProviderSchema 的要求编写内容,确保与系统的规范保持一致。 -2. **编写模型供应商代码** - - 创建供应商 class 代码,实现一个符合系统接口要求的 Python class 用于对接供应商的 API,完成核心功能实现。 - -*** - -以下是每个步骤的完整操作详情。 - -#### 1. **创建模型供应商配置文件** - -Manifest 是 YAML 格式文件,声明了模型供应商基础信息、所支持的模型类型、配置方式、凭据规则。插件项目模板将在 `/providers` 路径下自动生成配置文件。 - -以下是 `Anthropic` 模型配置文件 `anthropic.yaml` 的示例代码: - -```yaml -provider: anthropic -label: - en_US: Anthropic -description: - en_US: Anthropic's powerful models, such as Claude 3. - zh_Hans: Anthropic 的强大模型,例如 Claude 3。 -icon_small: - en_US: icon_s_en.svg -icon_large: - en_US: icon_l_en.svg -background: "#F0F0EB" -help: - title: - en_US: Get your API Key from Anthropic - zh_Hans: 从 Anthropic 获取 API Key - url: - en_US: https://console.anthropic.com/account/keys -supported_model_types: - - llm -configurate_methods: - - predefined-model -provider_credential_schema: - credential_form_schemas: - - variable: anthropic_api_key - label: - en_US: API Key - type: secret-input - required: true - placeholder: - zh_Hans: 在此输入你的 API Key - en_US: Enter your API Key - - variable: anthropic_api_url - label: - en_US: API URL - type: text-input - required: false - placeholder: - zh_Hans: 在此输入你的 API URL - en_US: Enter your API URL -models: - llm: - predefined: - - "models/llm/*.yaml" - position: "models/llm/_position.yaml" -extra: - python: - provider_source: provider/anthropic.py - model_sources: - - "models/llm/llm.py" -``` - -如果接入的供应商提供自定义模型,比如`OpenAI`提供微调模型,需要添加`model_credential_schema` 字段。 - -以下是 `OpenAI` 家族模型的示例代码: - -```yaml -model_credential_schema: - model: # 微调模型名称 - label: - en_US: Model Name - zh_Hans: 模型名称 - placeholder: - en_US: Enter your model name - zh_Hans: 输入模型名称 - credential_form_schemas: - - variable: openai_api_key - label: - en_US: API Key - type: secret-input - required: true - placeholder: - zh_Hans: 在此输入你的 API Key - en_US: Enter your API Key - - variable: openai_organization - label: - zh_Hans: 组织 ID - en_US: Organization - type: text-input - required: false - placeholder: - zh_Hans: 在此输入你的组织 ID - en_US: Enter your Organization ID - - variable: openai_api_base - label: - zh_Hans: API Base - en_US: API Base - type: text-input - required: false - placeholder: - zh_Hans: 在此输入你的 API Base - en_US: Enter your API Base -``` - -如需查看更多完整的模型供应商 YAML 规范,详情请参考[模型架构](/plugin-dev-zh/0412-model-schema)文档。 - -#### 2. **编写模型供应商代码** - -在 `/providers` 文件夹下创建一个同名的 python 文件,例如 `anthropic.py` 并实现一个 `class` ,继承 `__base.provider.Provider` 基类,例如 `AnthropicProvider`。 - -以下是 `Anthropic` 示例代码: - -```python -import logging -from dify_plugin.entities.model import ModelType -from dify_plugin.errors.model import CredentialsValidateFailedError -from dify_plugin import ModelProvider - -logger = logging.getLogger(__name__) - - -class AnthropicProvider(ModelProvider): - def validate_provider_credentials(self, credentials: dict) -> None: - """ - Validate provider credentials - - if validate failed, raise exception - - :param credentials: provider credentials, credentials form defined in `provider_credential_schema`. - """ - try: - model_instance = self.get_model_instance(ModelType.LLM) - model_instance.validate_credentials(model="claude-3-opus-20240229", credentials=credentials) - except CredentialsValidateFailedError as ex: - raise ex - except Exception as ex: - logger.exception(f"{self.get_provider_schema().provider} credentials validate failed") - raise ex -``` - -供应商需要继承 `__base.model_provider.ModelProvider` 基类,实现 `validate_provider_credentials` 供应商统一凭据校验方法即可。 - -```python -def validate_provider_credentials(self, credentials: dict) -> None: - """ - Validate provider credentials - You can choose any validate_credentials method of model type or implement validate method by yourself, - such as: get model list api - - if validate failed, raise exception - - :param credentials: provider credentials, credentials form defined in `provider_credential_schema`. - """ -``` - -当然也可以先预留 `validate_provider_credentials` 实现,在模型凭据校验方法实现后直接复用。 - -#### **自定义模型供应商** - -对于其它类型模型供应商而言,请参考以下配置方法。 - -对于像 `Xinference` 这样的自定义模型供应商,可以跳过完整实现的步骤。只需创建一个名为 `XinferenceProvider` 的空类,并在其中实现一个空的 `validate_provider_credentials` 方法。 - -**具体说明:** - -• `XinferenceProvider` 是一个占位类,用于标识自定义模型供应商。 - -• `validate_provider_credentials` 方法虽然不会被实际调用,但必须存在,这是因为其父类是抽象类,要求所有子类都实现这个方法。通过提供一个空实现,可以避免因未实现抽象方法而导致的实例化错误。 - -```python -class XinferenceProvider(Provider): - def validate_provider_credentials(self, credentials: dict) -> None: - pass -``` - -初始化模型供应商后,接下来需要接入供应商所提供的具体 llm 模型。详细说明请参考以下内容: - -* [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) - 了解接入预定义模型的规范 -* [模型架构](/plugin-dev-zh/0412-model-schema) - 了解接入自定义模型的规范 -* [发布概览](/plugin-dev-zh/0321-release-overview) - 学习插件发布流程 - -## 参考资源 - -- [快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model) - 如何为现有供应商添加新模型 -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 返回插件开发入门指南 -- [创建新模型提供者补充](/plugin-dev-zh/0222-creating-new-model-provider-extra) - 了解更多高级配置 -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - 了解插件清单文件的配置 - -{/* -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-zh/0222-creating-new-model-provider.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0222-datasource-plugin.mdx b/plugin-dev-zh/0222-datasource-plugin.mdx deleted file mode 100644 index d16360df..00000000 --- a/plugin-dev-zh/0222-datasource-plugin.mdx +++ /dev/null @@ -1,451 +0,0 @@ ---- -title: "数据源插件" ---- - -数据源(Data Source)插件是 Dify 1.9.0 新引入的一种插件类型。在知识流水线(Knowledge Pipeline)中,其作为文档数据的来源并充当整个流水线的起始点。 - -本文介绍如何开发数据源插件(包括插件结构、代码示例、调试方法等),帮助你快速完成插件开发与上线。 - -## 前置准备 - -在阅读本文之前,请确保你对知识流水线的流程有基本的了解,并且具有一定的插件开发知识。你可以在以下文档找到相关内容: - -- [步骤二:知识流水线编排](/zh-hans/guides/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration) -- [Dify 插件开发:Hello World 指南](/plugin-dev-zh/0211-getting-started-dify-tool) - -## 数据源插件类型 - -Dify 支持三种数据源插件:网页爬虫、在线文档和在线网盘。在具体实现插件代码时,实现插件功能的类需要继承不同的数据源类,三种插件类型对应三种父类。 - - - 了解如何继承父类以实现插件功能,请阅读 [Dify 插件开发:Hello World 指南-4.4 实现工具(Tool)逻辑](/plugin-dev-zh/0211-getting-started-dify-tool#4-4-实现工具-tool-逻辑)。 - - -每个数据源插件类型支持配置多种数据源,例如: - -- 网页爬虫:Jina Reader,FireCrawl -- 在线文档:Notion,Confluence,GitHub -- 在线网盘:Onedrive,Google Drive,Box,AWS S3,Tencent COS - -数据源类型与数据源插件类型的关系如下图所示: - -![](/images/data_source_type.png) - -## 开发插件 - -### 创建数据源插件 - -你可以使用脚手架命令行工具来创建数据源插件,并选择 `datasource` 类型。完成设置后,命令行工具将自动生成插件项目代码。 - -```powershell -dify plugin init -``` - -![](/images/datasource_plugin_init.png) - - - 一般情况下,数据源插件不使用 Dify 平台的其他功能,因此无需为其设置额外权限。 - - -#### 数据源插件结构 - -数据源插件包含三个主要部分: - -- `manifest.yaml` 文件:描述插件的基本信息 -- `provider` 目录:包含插件供应商的描述与实现鉴权的代码 -- `datasources` 目录:包含实现获取数据源核心逻辑的描述与代码 - -``` -├── _assets -│   └── icon.svg -├── datasources -│   ├── your_datasource.py -│   └── your_datasource.yaml -├── main.py -├── manifest.yaml -├── PRIVACY.md -├── provider -│   ├── your_datasource.py -│   └── your_datasource.yaml -├── README.md -└── requirements.txt -``` - -#### 设置正确的版本及标签 - -- 在 `manifest.yaml` 文件中,插件支持的最低 Dify 版本需设置如下: - - ```yaml - minimum_dify_version: 1.9.0 - ``` -- 在 `manifest.yaml` 文件中,需为插件添加如下数据源标签,使插件在 Dify Marketplace 中以数据源分类展示: - - ```yaml - tags: - - rag - ``` -- 在 `requirements.txt` 文件中,插件开发使用的插件 SDK 版本需设置如下: - - ```yaml - dify-plugin>=0.5.0,<0.6.0 - ``` - -### 添加供应商 - -#### 创建供应商 YAML 文件 - -供应商 YAML 文件的定义和编写与工具插件基本相同,仅有以下两点差异: - -```yaml -# 指定数据源的 provider 类型,可设置为 online_drive,online_document 或 website_crawl -provider_type: online_drive # online_document, website_crawl - -# 指定数据源 -datasources: - - datasources/PluginName.yaml -``` - - - 了解更多创建供应商 YAML 文件的信息,请阅读 [Dify 插件开发:Hello World 指南-4.3 配置 Provider 凭证](/plugin-dev-zh/0211-getting-started-dify-tool#4-3-配置-provider-凭证)。 - - - - 数据源插件支持以 OAuth 2.0 或 API Key 两种方式进行认证。了解如何配置 OAuth,请阅读 [为工具插件添加 OAuth 支持](/plugin-dev-zh/0222-tool-oauth)。 - - -#### 创建供应商代码文件 - -- **若使用 API Key 认证模式**,数据源插件的供应商代码文件与工具插件完全相同,仅需将供应商类继承的父类修改为 `DatasourceProvider` 即可。 - - ```python - class YourDatasourceProvider(DatasourceProvider): - - def _validate_credentials(self, credentials: Mapping[str, Any]) -> None: - try: - """ - IMPLEMENT YOUR VALIDATION HERE - """ - except Exception as e: - raise ToolProviderCredentialValidationError(str(e)) - ``` -- **若使用 OAuth 认证模式**,数据源插件则与工具插件略有不同。使用 OAuth 获取访问权限时,数据源插件可同时返回用户名和头像并显示在前端。因此,`_oauth_get_credentials` 和 `_oauth_refresh_credentials` 需要返回包含 `name`、`avatar_url`、`expires_at` 和 `credentials` 的 `DatasourceOAuthCredentials` 类型。 - - `DatasourceOAuthCredentials` 类的定义如下,返回时需设置为对应的类型: - - ```python - class DatasourceOAuthCredentials(BaseModel): - name: str | None = Field(None, description="The name of the OAuth credential") - avatar_url: str | None = Field(None, description="The avatar url of the OAuth") - credentials: Mapping[str, Any] = Field(..., description="The credentials of the OAuth") - expires_at: int | None = Field( - default=-1, - description="""The expiration timestamp (in seconds since Unix epoch, UTC) of the credentials. - Set to -1 or None if the credentials do not expire.""", - ) - ``` - - `_oauth_get_authorization_url`,`_oauth_get_credentials` 和 `_oauth_refresh_credentials` 的函数签名如下: - - - - ```python - def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: - """ - Generate the authorization URL for {{ .PluginName }} OAuth. - """ - try: - """ - IMPLEMENT YOUR AUTHORIZATION URL GENERATION HERE - """ - except Exception as e: - raise DatasourceOAuthError(str(e)) - return "" - ``` - - - ```python - def _oauth_get_credentials( - self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request - ) -> DatasourceOAuthCredentials: - """ - Exchange code for access_token. - """ - try: - """ - IMPLEMENT YOUR CREDENTIALS EXCHANGE HERE - """ - except Exception as e: - raise DatasourceOAuthError(str(e)) - return DatasourceOAuthCredentials( - name="", - avatar_url="", - expires_at=-1, - credentials={}, - ) - ``` - - - ```python - def _oauth_refresh_credentials( - self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] - ) -> DatasourceOAuthCredentials: - """ - Refresh the credentials - """ - return DatasourceOAuthCredentials( - name="", - avatar_url="", - expires_at=-1, - credentials={}, - ) - ``` - - - -### 添加数据源 - -三种数据源插件需要创建的 YAML 文件格式与数据源代码格式有所不同,下面将分别介绍。 - -#### 网络爬虫(Web Crawler) - -在网页爬虫类插件的供应商 YAML 文件中, `output_schema` 需固定返回四个参数:`source_url`、`content`、`title` 和 `description`。 - -```yaml -output_schema: - type: object - properties: - source_url: - type: string - description: the source url of the website - content: - type: string - description: the content from the website - title: - type: string - description: the title of the website - "description": - type: string - description: the description of the website -``` - -在网页爬虫类插件的主逻辑代码中,需继承 `WebsiteCrawlDatasource` 类并实现 `_get_website_crawl` 方法,然后使用 `create_crawl_message` 方法返回网页爬虫消息。 - -如需爬取多个网页并分批返回,可将 `WebSiteInfo.status` 设置为 `processing`,然后使用 `create_crawl_message` 方法返回每一批网页爬虫消息。当所有网页均爬取完成后,再将 `WebSiteInfo.status` 设置为 `completed`。 - -```python -class YourDataSource(WebsiteCrawlDatasource): - - def _get_website_crawl( - self, datasource_parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - - crawl_res = WebSiteInfo(web_info_list=[], status="", total=0, completed=0) - crawl_res.status = "processing" - yield self.create_crawl_message(crawl_res) - - ### your crawl logic - ... - crawl_res.status = "completed" - crawl_res.web_info_list = [ - WebSiteInfoDetail( - title="", - source_url="", - description="", - content="", - ) - ] - crawl_res.total = 1 - crawl_res.completed = 1 - - yield self.create_crawl_message(crawl_res) -``` - -#### 在线文档(Online Document) - -在线文档类插件的返回值至少需包含 `content` 字段用于表示文档内容,示例如下: - -```yaml -output_schema: - type: object - properties: - workspace_id: - type: string - description: workspace id - page_id: - type: string - description: page id - content: - type: string - description: page content -``` - -在线文档类插件的主逻辑代码中,需继承 `OnlineDocumentDatasource` 类并实现 `_get_pages` 和 `_get_content` 两个方法。当用户运行插件时,首先通过 `_get_pages` 方法获取文档列表;当用户从列表中选择某个文档后,再通过 `_get_content` 方法获取文档内容。 - - - - ```python - def _get_pages(self, datasource_parameters: dict[str, Any]) -> DatasourceGetPagesResponse: - # your get pages logic - response = requests.get(url, headers=headers, params=params, timeout=30) - pages = [] - for item in response.json().get("results", []): - page = OnlineDocumentPage( - page_name=item.get("title", ""), - page_id=item.get("id", ""), - type="page", - last_edited_time=item.get("version", {}).get("createdAt", ""), - parent_id=item.get("parentId", ""), - page_icon=None, - ) - pages.append(page) - online_document_info = OnlineDocumentInfo( - workspace_name=workspace_name, - workspace_icon=workspace_icon, - workspace_id=workspace_id, - pages=[page], - total=pages.length(), - ) - return DatasourceGetPagesResponse(result=[online_document_info]) - ``` - - - ```python - def _get_content(self, page: GetOnlineDocumentPageContentRequest) -> Generator[DatasourceMessage, None, None]: - # your fetch content logic, example - response = requests.get(url, headers=headers, params=params, timeout=30) - ... - yield self.create_variable_message("content", "") - yield self.create_variable_message("page_id", "") - yield self.create_variable_message("workspace_id", "") - ``` - - - -#### 在线网盘(Online Drive) - -在线网盘类插件的返回值类型为一个文件,需遵循以下规范: - -```yaml -output_schema: - type: object - properties: - file: - $ref: "https://dify.ai/schemas/v1/file.json" -``` - -在线网盘类插件的主逻辑代码中,需继承 `OnlineDriveDatasource` 类并实现 `_browse_files` 和 `_download_file` 两个方法。 - -当用户运行插件时,首先通过 `_browse_files` 方法获取文件列表。此时 `prefix` 为空,表示获取根目录下的文件列表。文件列表中包含文件夹与文件两种类型的变量。当用户继续打开文件夹时,将再次运行 `_browse_files` 方法。此时, `OnlineDriveBrowseFilesRequest` 中的 `prefix` 为文件夹 ID,用于获取该文件夹内的文件列表。 - -当用户选择某个文件后,插件通过 `_download_file` 方法和文件 ID 获取文件内容。你可以使用 `_get_mime_type_from_filename` 方法获取文件的 MIME 类型,以便在流水线中对不同的文件类型进行不同的处理。 - -当文件列表包含多个文件时,可将 `OnlineDriveFileBucket.is_truncated` 设置为 `True`,并将`OnlineDriveFileBucket.next_page_parameters` 设置为继续获取文件列表的参数,如下一页的请求 ID 或 URL,具体取决于不同的服务商。 - - - - ```python - def _browse_files( - self, request: OnlineDriveBrowseFilesRequest - ) -> OnlineDriveBrowseFilesResponse: - - credentials = self.runtime.credentials - bucket_name = request.bucket - prefix = request.prefix or "" # Allow empty prefix for root folder; When you browse the folder, the prefix is the folder id - max_keys = request.max_keys or 10 - next_page_parameters = request.next_page_parameters or {} - - files = [] - files.append(OnlineDriveFile( - id="", - name="", - size=0, - type="folder" # or "file" - )) - - return OnlineDriveBrowseFilesResponse(result=[ - OnlineDriveFileBucket( - bucket="", - files=files, - is_truncated=False, - next_page_parameters={} - ) - ]) - ``` - - - ```python - def _download_file(self, request: OnlineDriveDownloadFileRequest) -> Generator[DatasourceMessage, None, None]: - credentials = self.runtime.credentials - file_id = request.id - - file_content = bytes() - file_name = "" - - mime_type = self._get_mime_type_from_filename(file_name) - - yield self.create_blob_message(file_content, meta={ - "file_name": file_name, - "mime_type": mime_type - }) - - def _get_mime_type_from_filename(self, filename: str) -> str: - """Determine MIME type from file extension.""" - import mimetypes - mime_type, _ = mimetypes.guess_type(filename) - return mime_type or "application/octet-stream" - ``` - - - -对于 AWS S3 等存储服务商,`prefix`,`bucket` 和 `id` 变量有特殊的使用方法,可在实际开发中按需灵活应用: - -- `prefix`:表示文件路径前缀,例如 `prefix=container1/folder1/` 表示获取 `container1` 桶下的 `folder1` 文件夹中的文件或文件列表。 -- `bucket`:表示文件桶,例如 `bucket=container1` 表示获取 `container1` 桶下的文件或文件列表(若是非标准 S3 协议网盘,该字段可为空 )。 -- `id`:由于`_download_file` 方法不使用 `prefix` 变量,需将文件路径拼接到 `id` 中,例如 `id=container1/folder1/file1.txt` 表示获取 `container1` 桶下的 `folder1` 文件夹中的 `file1.txt` 文件。 - - - 你可以参考 [官方 Google Drive 插件](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/google_cloud_storage/datasources/google_cloud_storage.py) 和 [官方 AWS S3 插件](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/aws_s3_storage/datasources/aws_s3_storage.py) 中的具体实现。 - - -## 调试插件 - -数据源插件支持两种调试方式:远程调试或安装为本地插件进行调试。需注意: - -- 若插件使用 OAuth 认证模式,其远程调试时的 `redirect_uri` 与本地插件的设置并不一致,需要修改服务商 OAuth App 的相关配置。 -- 数据源插件支持单步调试,但为了保证功能的正确性,我们仍推荐你在完整的知识流水线中进行测试。 - -## 最终检查 - -在打包与发布前,确保已完成以下事项: - -- 设置支持的最低 Dify 版本为 `1.9.0` -- 设置 SDK 版本为 `dify-plugin>=0.5.0,<0.6.0` -- 编写 `README.md` 和 `PRIVACY.md` 文件 -- 确保代码文件中仅包含英文内容 -- 将默认图标替换为数据源供应商 Logo - -## 打包与发布 - -在插件目录执行以下命令,即可生成 `.difypkg` 插件包: - -``` -dify plugin package . -o your_datasource.difypkg -``` - -接下来,你可以: - -- 在你的 Dify 环境中导入并使用该插件 -- 通过提交 Pull Request 的方式将插件发布到 Dify Marketplace - - - 了解插件发布流程,请阅读 [发布插件](/plugin-dev-zh/0321-release-overview)。 - - -{/* -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-zh/0222-datasource-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0222-debugging-logs.mdx b/plugin-dev-zh/0222-debugging-logs.mdx deleted file mode 100644 index 95c01ac2..00000000 --- a/plugin-dev-zh/0222-debugging-logs.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Debugging logs -language: zh -description: 介绍如何在 Dify 插件开发中为你的工具添加日志输出功能,以便于开发和调试。 -title: 输出开发和调试插件过程中的日志 ---- - -作为插件开发者,你可能希望在插件处理过程中,为了开发或调试目的,将任意字符串输出到日志中。 - -为此,插件 SDK 实现了一个适用于 Python 标准库 `logging` 的处理器。通过使用它,你可以将任意字符串输出到**远程调试时的标准输出**以及**插件守护进程的容器日志**(仅社区版)。 - -## 示例 - -导入 `plugin_logger_handler` 并将其添加到你的 logger 处理器中。以下是工具插件的示例代码。 - -```python -from collections.abc import Generator -from typing import Any -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - - -# 导入 logging 和自定义处理器 -import logging -from dify_plugin.config.logger_format import plugin_logger_handler - -# 使用自定义处理器设置日志 -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) -logger.addHandler(plugin_logger_handler) - - -class LoggerDemoTool(Tool): - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: - - # 以不同级别输出日志信息 - logger.info("This is a INFO log message.") - logger.warning("This is a WARNING log message.") - logger.error("This is a ERROR log message.") - - yield self.create_text_message("Hello, Dify!") -``` - -{/* -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-zh/0222-debugging-logs.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0222-tool-plugin.mdx b/plugin-dev-zh/0222-tool-plugin.mdx deleted file mode 100644 index 9ceed82e..00000000 --- a/plugin-dev-zh/0222-tool-plugin.mdx +++ /dev/null @@ -1,386 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: standard - level: intermediate -standard_title: Tool Plugin -language: zh -title: 工具插件 -description: 本文档介绍如何开发 Dify 的工具插件,以 Google Search 为例实现了一个完整的工具插件开发流程。内容包括插件初始化、模板选择、模板选择、工具供应商配置文件定义、添加第三方服务凭证、工具功能代码实现、调试和打包发布等完整环节。 ---- - -工具指的是能够被 Chatflow / Workflow / Agent 类型应用所调用的第三方服务,提供完整的 API 实现能力,用于增强 Dify 应用的能力。例如为应用添加在线搜索、图片生成等额外功能。 - -![Tool Plugin Example](https://assets-docs.dify.ai/2024/12/7e7bcf1f9e3acf72c6917ea9de4e4613.png) - -在本文中,**"工具插件"** 指的是一个完整的项目,其中包含工具供应商文件、功能代码等结构。一个工具供应商内允许包含多个 Tools(可以理解为单个工具中提供的额外功能),结构如下: - -``` -- 工具供应商 - - Tool A - - Tool B -``` - -![工具插件结构](https://assets-docs.dify.ai/2025/02/60c4c86a317d865133aa460592eac079.png) - -本文将以 `Google Search` 为例,介绍如何快速开发一个工具插件。 - -### 前置准备 - -- Dify 插件脚手架工具 -- Python 环境,版本号 ≥ 3.12 - -关于如何准备插件开发的脚手架工具,详细说明请参考[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools)。如果你是初次开发插件,建议先阅读[Dify 插件开发:Hello World 指南](/plugin-dev-zh/0211-getting-started-dify-tool)。 - -### 创建新项目 - -运行脚手架命令行工具,创建一个新的 dify 插件项目。 - -```bash -./dify-plugin-darwin-arm64 plugin init -``` - -如果你已将该二进制文件重命名为 `dify` 并拷贝至 `/usr/local/bin` 路径下,可以运行以下命令创建新的插件项目: - -```bash -dify plugin init -``` - -> 下文将使用 `dify` 作为命令行示例。如遇到问题,请将 `dify` 命令替换为命令行工具的所在路径。 - -### 选择插件类型和模板 - -脚手架工具内的所有模板均已提供完整的代码项目。在本文实例中,选择 `Tool` 插件。 - -> 如果你已熟悉插件开发,无需借助模板,可参考[通用规范](/plugin-dev-zh/0411-general-specifications)指引完成不同类型的插件开发。 - -![插件类型:工具](https://assets-docs.dify.ai/2024/12/dd3c0f9a66454e15868eabced7b74fd6.png) - -#### 配置插件权限 - -插件还需读取 Dify 平台的权限,为该示例插件授予以下权限: - -- Tools -- Apps -- 启用持久化存储 Storage,分配默认大小存储 -- 允许注册 Endpoint - -> 在终端内使用方向键选择权限,使用 "Tab" 按钮授予权限。 - -勾选所有权限项后,轻点回车完成插件的创建。系统将自动生成插件项目代码。 - -![插件权限](https://assets-docs.dify.ai/2024/12/9cf92c2e74dce55e6e9e331d031e5a9f.png) - -### 开发工具插件 - -#### 1. 创建工具供应商文件 - -工具供应商文件为 yaml 格式文件,可以理解为工具插件的基础配置入口,用于向工具提供必要的授权信息。 - -前往插件模板项目中的 `/provider` 路径,将其中的 yaml 文件重命名为 `google.yaml`。该 `yaml` 文件将包含工具供应商的信息,包括供应商名称、图标、作者等详情。这部分信息将在安装插件时进行展示。 - -**示例代码** - -```yaml -identity: # 工具供应商的基本信息 - author: Your-name # 作者 - name: google # 名称,唯一,不允许和其他供应商重名 - label: # 标签,用于前端展示 - en_US: Google # 英文标签 - zh_Hans: Google # 中文标签 - description: # 描述,用于前端展示 - en_US: Google # 英文描述 - zh_Hans: Google # 中文描述 - icon: icon.svg # 工具图标,需要放置在 _assets 文件夹下 - tags: # 标签,用于前端展示 - - search -``` - -确保该文件路径位于 `/tools` 目录,完整的路径如下: - -```yaml -plugins: - tools: - - 'google.yaml' -``` - -其中 `google.yaml` 文件需要使用其在插件项目的绝对路径。在本例中,它位于项目根目录。YAML 文件中的 identity 字段解释如下:`identity` 包含了工具供应商的基本信息,包括作者、名称、标签、描述、图标等。 - -- 图标需要属于附件资源,需要将其放置在项目根目录的 `_assets` 文件夹下。 -- 标签可以帮助用户通过分类快速找到插件,以下是目前所支持的所有标签。 - -```python -class ToolLabelEnum(Enum): - SEARCH = 'search' - IMAGE = 'image' - VIDEOS = 'videos' - WEATHER = 'weather' - FINANCE = 'finance' - DESIGN = 'design' - TRAVEL = 'travel' - SOCIAL = 'social' - NEWS = 'news' - MEDICAL = 'medical' - PRODUCTIVITY = 'productivity' - EDUCATION = 'education' - BUSINESS = 'business' - ENTERTAINMENT = 'entertainment' - UTILITIES = 'utilities' - OTHER = 'other' -``` - -#### **2. 补全第三方服务凭据** - -为了便于开发,选择采用第三方服务 `SerpApi` 所提供的 Google Search API 。 `SerpApi` 要求填写 API Key 进行使用,因此需要在 `yaml` 文件内添加 `credentials_for_provider` 字段。 - -完整代码如下: - -```yaml -identity: - author: Dify - name: google - label: - en_US: Google - zh_Hans: Google - pt_BR: Google - description: - en_US: Google - zh_Hans: GoogleSearch - pt_BR: Google - icon: icon.svg - tags: - - search -credentials_for_provider: #添加 credentials_for_provider 字段 - serpapi_api_key: - type: secret-input - required: true - label: - en_US: SerpApi API key - zh_Hans: SerpApi API key - placeholder: - en_US: Please input your SerpApi API key - zh_Hans: 请输入你的 SerpApi API key - help: - en_US: Get your SerpApi API key from SerpApi - zh_Hans: 从 SerpApi 获取你的 SerpApi API key - url: https://serpapi.com/manage-api-key -tools: - - tools/google_search.yaml -extra: - python: - source: google.py -``` - -- 其中 `credentials_for_provider` 的子级结构需要满足 [通用规范](/plugin-dev-zh/0411-general-specifications) 的要求。 -- 需要指定该供应商包含了哪些工具。本示例仅包含了一个 `tools/google_search.yaml` 文件。 -- 作为供应商,除了定义其基础信息外,还需要实现一些它的代码逻辑,因此需要指定其实现逻辑,在本例子中,将功能的代码文件放在了 `google.py` 中,但是暂时不实现它,而是先编写 `google_search` 的代码。 - -#### 3. 填写工具 yaml 文件 - -一个工具插件下可以有多个工具功能,每个工具功能需要一个 `yaml` 文件进行描述,包含工具功能的基本信息、参数、输出等。 - -仍以 `GoogleSearch` 工具为例,在 `/tools`文件夹内新建一个 `google_search.yaml` 文件。 - -```yaml -identity: - name: google_search - author: Dify - label: - en_US: GoogleSearch - zh_Hans: 谷歌搜索 - pt_BR: GoogleSearch -description: - human: - en_US: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. - zh_Hans: 一个用于执行 Google SERP 搜索并提取片段和网页的工具。输入应该是一个搜索查询。 - pt_BR: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. - llm: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. -parameters: - - name: query - type: string - required: true - label: - en_US: Query string - zh_Hans: 查询语句 - pt_BR: Query string - human_description: - en_US: used for searching - zh_Hans: 用于搜索网页内容 - pt_BR: used for searching - llm_description: key words for searching - form: llm -extra: - python: - source: tools/google_search.py -``` - -- `identity` 包含了工具的基本信息,包括名称、作者、标签、描述等。 -- `parameters` 参数列表 - - `name` (必填)参数名称,唯一,不允许和其他参数重名。 - - `type` (必填)参数类型,目前支持`string`、`number`、`boolean`、`select`、`secret-input`、`file`、`files`、`model-selector`、`app-selector` 九种类型,分别对应字符串、数字、布尔值、下拉框、加密输入框、文件、文件集、模型选择、应用选择,对于敏感信息,请使用 `secret-input` 类型。 - - `label`(必填)参数标签,用于前端展示。 - - `form` (必填)表单类型,目前支持`llm`、`form`两种类型。 - - 在 Agent 应用中,`llm` 表示该参数 LLM 自行推理,`form` 表示要使用该工具可提前设定的参数。 - - 在 Workflow 应用中,`llm`和`form` 均需要前端填写,但 `llm` 的参数会做为工具节点的输入变量。 - - `required` 是否必填 - - 在 `llm` 模式下,如果参数为必填,则会要求 Agent 必须要推理出这个参数。 - - 在 `form` 模式下,如果参数为必填,则会要求用户在对话开始前在前端填写这个参数。 - - `options` 参数选项 - - 在 `llm` 模式下,Dify 会将所有选项传递给 LLM,LLM 可以根据这些选项进行推理。 - - 在 `form` 模式下,`type` 为 `select` 时,前端会展示这些选项。 - - `default` 默认值。 - - `min` 最小值,当参数类型为`number`时可以设定。 - - `max` 最大值,当参数类型为`number`时可以设定。 - - `human_description` 用于前端展示的介绍,支持多语言。 - - `placeholder` 字段输入框的提示文字,在表单类型为`form`,参数类型为`string`、`number`、`secret-input`时,可以设定,支持多语言。 - - `llm_description` 传递给 LLM 的介绍。为了使得 LLM 更好理解这个参数,请在这里写上关于这个参数尽可能详细的信息,以便 LLM 能够理解该参数。 - -#### 4. 准备工具代码 - -填写工具的配置信息以后,可以开始编写工具的功能代码,实现工具的逻辑目的。在`/tools`目录下创建`google_search.py`,内容如下: - -```python -from collections.abc import Generator -from typing import Any - -import requests - -from dify_plugin import Tool -from dify_plugin.entities.tool import ToolInvokeMessage - -SERP_API_URL = "https://serpapi.com/search" - -class GoogleSearchTool(Tool): - def _parse_response(self, response: dict) -> dict: - result = {} - if "knowledge_graph" in response: - result["title"] = response["knowledge_graph"].get("title", "") - result["description"] = response["knowledge_graph"].get("description", "") - if "organic_results" in response: - result["organic_results"] = [ - { - "title": item.get("title", ""), - "link": item.get("link", ""), - "snippet": item.get("snippet", ""), - } - for item in response["organic_results"] - ] - return result - - def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: - params = { - "api_key": self.runtime.credentials["serpapi_api_key"], - "q": tool_parameters["query"], - "engine": "google", - "google_domain": "google.com", - "gl": "us", - "hl": "en", - } - - response = requests.get(url=SERP_API_URL, params=params, timeout=5) - response.raise_for_status() - valuable_res = self._parse_response(response.json()) - - yield self.create_json_message(valuable_res) -``` - -该例子的含义为请求 `serpapi`,并使用 `self.create_json_message` 返回一串 `json` 的格式化数据,如果想了解更多的返回数据类型,可以参考[远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin)和[持久化存储 KV](/plugin-dev-zh/0411-persistent-storage-kv)文档。 - -#### 5. 完成工具供应商代码 - -最后需要创建一个供应商的实现代码,用于实现凭据验证逻辑。如果凭据验证失败,将会抛出`ToolProviderCredentialValidationError`异常。验证成功后,将正确请求 `google_search` 工具服务。 - -在 `/provider` 目录下创建 `google.py` 文件,代码的内容如下: - -```python -from typing import Any - -from dify_plugin import ToolProvider -from dify_plugin.errors.tool import ToolProviderCredentialValidationError -from tools.google_search import GoogleSearchTool - -class GoogleProvider(ToolProvider): - def _validate_credentials(self, credentials: dict[str, Any]) -> None: - try: - for _ in GoogleSearchTool.from_credentials(credentials).invoke( - tool_parameters={"query": "test", "result_type": "link"}, - ): - pass - except Exception as e: - raise ToolProviderCredentialValidationError(str(e)) -``` - -### 调试插件 - -插件开发完成后,接下来需要测试插件是否可以正常运行。Dify 提供便捷地远程调试方式,帮助你快速在测试环境中验证插件功能。 - -前往["插件管理"](https://cloud.dify.ai/plugins)页获取远程服务器地址和调试 Key。 - -![Remote Debug Key](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) - -回到插件项目,拷贝 `.env.example` 文件并重命名为 `.env`,将获取的远程服务器地址和调试 Key 等信息填入其中。 - -`.env` 文件: - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -运行 `python -m main` 命令启动插件。在插件页即可看到该插件已被安装至 Workspace 内,团队中的其他成员也可以访问该插件。 - -![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) - -### 打包插件(可选) - -确认插件能够正常运行后,可以通过以下命令行工具打包并命名插件。运行以后你可以在当前文件夹发现 `google.difypkg` 文件,该文件为最终的插件包。 - -```bash -# 将 ./google 替换为插件项目的实际路径 - -dify plugin package ./google -``` - -恭喜,你已完成一个工具类型插件的完整开发、调试与打包过程! - -### 发布插件(可选) - -如果想要将插件发布至 Dify Marketplace,请确保你的插件遵循了[发布到 Dify 市场](/plugin-dev-zh/0322-release-to-dify-marketplace)中的规范。审核通过后,代码将合并至主分支并自动上线至 [Dify Marketplace](https://marketplace.dify.ai/)。 - -[发布概览](/plugin-dev-zh/0321-release-overview) - -### 探索更多 - -#### **快速开始:** - -- [开发 Extension 插件](/plugin-dev-zh/9231-extension-plugin) -- [开发 Model 插件](/plugin-dev-zh/0211-getting-started-new-model) -- [Bundle 插件:将多个插件打包](/plugin-dev-zh/9241-bundle) - -#### **插件接口文档:** - -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - Manifest 结构和工具规范 -- [端点](/plugin-dev-zh/0432-endpoint) - Endpoint 详细定义 -- [反向调用](/plugin-dev-zh/9241-reverse-invocation) - 反向调用 Dify 能力 -- [模型架构](/plugin-dev-zh/0412-model-schema) - 模型 -- [Agent 插件](/plugin-dev-zh/9232-agent) - 扩展 Agent 策略 - -## 下一步学习 - -- [远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin) - 了解更高级的调试技巧 -- [持久化存储](/plugin-dev-zh/0411-persistent-storage-kv) - 学习如何在插件中使用数据存储 -- [Slack 机器人插件开发示例](/plugin-dev-zh/0432-develop-a-slack-bot-plugin) - 查看更复杂的插件开发案例 -- [工具插件](/plugin-dev-zh/0411-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-zh/0222-tool-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0312-contributor-covenant-code-of-conduct.mdx b/plugin-dev-zh/0312-contributor-covenant-code-of-conduct.mdx deleted file mode 100644 index 60e8203b..00000000 --- a/plugin-dev-zh/0312-contributor-covenant-code-of-conduct.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: setup - level: intermediate -standard_title: Contributor Covenant Code of Conduct -language: zh -title: 插件开发准则 -description: 为保障 Dify Marketplace 中所有插件的质量,并确保 Dify Marketplace 用户获得一致且高质量的体验。在申请提交插件审核时,必须遵循此《插件开发准则》的所有要求。提交插件即表示**你已阅读、理解并同意遵守以下所有条款**,这将有助于你的插件快速顺利地通过审核。 ---- - -## 1. 验证插件的提交价值 - -* 确保插件的核心功能聚焦于生成式 AI 领域,并为 Dify 平台用户在此领域提供独特、显著的价值。 - - 集成新的模型、工具或服务; - - 提供独特的数据源或处理能力以增强 AI 应用; - - 简化或自动化 Dify 平台上的 AI 相关工作流程; - - 为 AI 应用开发提供创新的辅助功能。 -* 提交的插件**不应**与 Marketplace 目录中已有的插件**功能重复或高度相似**。每个发布的插件应是独特的、独立的,以确保为商店用户提供最佳体验。 -* 如涉及插件的更新,应**引入当前插件尚未提供的功能或服务**。 -* 我们**建议**你在提交 PR 中附上简要说明,解释为什么需要提交新插件。 - -## 2. 插件功能性检查 -- 确保插件**名称是唯一的**,搜索我们的插件目录以确保你的名称尚未使用。 -- 插件名称与插件品牌相匹配。 -- 提交审核前需验证插件功能是否正常运行,详细请参考[远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin),插件应准备好应用于生产。 -- 提供全面的 README 文件,包括: - - 设置说明和使用指南。 - - 插件用户需用的代码、API、凭据或其他信息,以便连接插件到服务。 - - 描述不应包含与该插件不相关的内容或链接。 - - 描述不应使用夸张、营销术语、或无法证明的声明内容。 - - 描述不应包含任何类型的广告(你自己的广告或来自展示广告服务的广告)。 - - 描述不应包含误导性、令人不适或恶意诋毁等内容。 - - 描述不应在截图中暴露真实用户的姓名或数据。 - - 描述不应包含指向不存在的页面 (404) 或产生错误消息的页面链接。 - - 描述不应出现过多的拼写和标点符号错误。 -- 确保收集的用户信息仅用于连接服务和改进插件功能。 -- 务必将必填字段标识,显示清晰的报错信息,确保用户可理解插件无法正常运行的原因。 -- 如果你的插件需要身份验证设置,请不要省略身份验证设置。 -- 根据插件[隐私政策准则](/plugin-dev-zh/0312-privacy-protection-guidelines),准备隐私政策内容文件或在线文档 URL。 -- 插件应具有良好的性能表现,避免导致 Dify 或用户环境响应迟缓或崩溃。 -- 涉及 API 密钥或其他凭证的管理,开发者必须采取安全的存储和传输措施,避免硬编码在代码中或泄露给无关方。 - -## 3. 插件的语言要求 -- Dify Marketplace 平台**面向全球用户**提供服务,插件主语言要求为**英语**。所有面向用户的文本(例如插件名称和描述、名称、字段名称、字段标签、帮助文本和错误消息)都**需至少提供英文语言的支持**。 -- 鼓励提供支持丰富多语言版本的插件。 - -## 4. 禁止或受限发布的插件 -- **禁止**具有误导性或恶意功能 - 插件不得误导用户。请勿创建可用于向用户发送垃圾邮件、进行网络钓鱼或发送未经请求消息的插件。如果你试图欺骗系统(例如,试图欺骗审核流程、窃取用户数据或伪造真实用户),你的插件将被从 Dify Marketplace 移除,并且你未来可能被禁止提交任何插件。 -- **禁止**包含令人不适的内容 - 插件内容不得包含暴力、仇恨言论、歧视性内容或任何不尊重全球不同文化、宗教及用户群体的内容。 -- **禁止**进行金融交易 - 插件不得促进任何形式的金融交易、资产转移或支付处理。对于区块链或加密货币应用,这包括任何代币或资产所有权的转移。 -- **限制**多次提交功能缺陷的插件 - 在提交插件以供审核之前,请自行对插件进行完整的功能性测试,确保不会出现严重的报错或功能性漏洞。多次提交质量缺陷的插件可能会导致审核时间变慢或收到进一步的处罚。 -- **限制**不必要的插件拆分 - 请勿为共享相同身份验证方法并与相同 API 交互的功能创建单独的插件,除非每个插件是针对明确独立营销的单独产品或服务(而非功能)。相反应将功能整合到一个高级别的插件中。 -- **限制**重复提交相同插件 - 提交本质上相同的多个插件会延迟审核流程,并有可能拒绝所有提交。在审核过程中,请避免连续提交相同的插件。违反此政策可能会导致审核时间变慢或受到进一步的处罚。 - -## 5. 插件收费模式 -- Dify Marketplace 当前阶段仅支持**免费**插件,关于 Dify Marketplace 的商业化和收费模式,未来将另行发布相关政策。 - -## 6. 插件商标与知识产权 -- 提交插件时应确认你有权使用 Logo 和商标,**禁止**未经授权使用第三方商标等。 -- 插件审核团队保留向开发者索取第三方 Logo 授权证明的权利,尤其当所用 Logo 明显属于他人品牌时,可能会在必要时要求提供授权证明。 -- 如在上架后被发现违规,Dify 有权要求开发者更改 Logo 或直接将插件下架处理。若接到商标权利人投诉,也会按照政策移除相关内容。(依据平台服务条款可能会警告或撤销插件的发布资格) -- **禁止**使用任何 Dify 所有的 Logo。 -- 请勿提供质量低下、扭曲拉伸或以截断元素的方式被裁剪的图像,审核团队保留向开发者要求更换图标的权力。 -- 图标中不应包含误导性、令人不适或恶意的画面。 - -## 7. 插件更新和版本管理 -- 开发者应负责任地管理插件的更新。对于可能引入不兼容变更(Breaking Changes)的更新,建议提前在插件描述或通过其他渠道(如 GitHub Release Notes)通知用户,并提供清晰的版本说明。 -- 鼓励开发者定期更新插件以修复 Bug、适配 Dify 平台更新或依赖的第三方服务变更,特别是涉及安全性的更新。 -- 如果插件所有者计划停止维护并最终弃用某个插件,应尽可能提前通知用户(例如,在插件描述中说明弃用计划和时间表),并建议提供替代方案(如果可行)。 - -## 8. 插件的维护与支持 -- 插件所有者对插件行使技术支持和维护的直接责任。 -- 插件所有者**需至少提供一个支持渠道:GitHub 仓库链接或邮箱**,方便在插件审核和上架期间,Dify 审核团队或者商店用于对插件的问题进行反馈。 -- 若插件长期无人维护,且所有者在 Dify 合理通知后仍未能在指定期限内响应或修复,Dify 保留采取相应措施的权利,包括但不限于:在插件页面添加“缺乏维护”或“可能存在风险”的标识、限制新用户安装、或最终将其下架处理。 - -## 9. 符合隐私数据规范 - -* 要求开发者在提交应用/工具时,**必须**声明是否收集任何类型的用户个人数据。详细请参考[插件隐私数据保护指南](/plugin-dev-zh/0312-privacy-protection-guidelines)。 -* 如果收集,需要**简单列出**收集的数据类型(例如:用户名、邮箱、设备ID、位置信息等),**无需过于详细**。 -* 开发者**必须**提供隐私政策链接,隐私政策只需要陈述收集了什么信息、怎么使用这些信息、以及哪些信息会和第三方披露,以及第三方相关的隐私政策链接。 - -**审核重点:** - -* **形式审核:** 检查是否按要求声明了数据收集情况。 -* **高危数据排查:** 重点关注是否收集了敏感数据(例如:健康信息、财务信息、儿童个人信息等),如果收集了敏感数据,则需要**额外审核**其使用目的和安全性措施。 -* **恶意行为排查:** 检查是否存在明显恶意行为,例如未经用户同意私自收集数据、上传用户数据到未知服务器等。 - -## 10. 插件审核与裁量权 -- 如果我们认为这些要求、隐私政策准则等未得到满足,我们保留拒绝发布请求或从 Dify Marketplace 删除已发布插件的权利。这包括试图利用审核流程、非法获取用户数据等情况。 -- Marketplace 审核团队会尽力在合理的时间内完成插件审核,具体时间可能因提交量和插件复杂度而异。审核过程中,我们可能会通过你提供的支持渠道与你联系沟通反馈,请确保你的联系方式有效。 - -## 相关资源 - -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 了解插件开发基础 -- [发布插件](/plugin-dev-zh/0321-release-overview) - 插件发布流程概览 -- [插件隐私数据保护指南](/plugin-dev-zh/0312-privacy-protection-guidelines) - 编写隐私政策指南 -- [发布至 Dify Marketplace](/plugin-dev-zh/0322-release-to-dify-marketplace) - 在官方市场发布插件 -- [远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin) - 插件调试指南 - -{/* -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-zh/0312-contributor-covenant-code-of-conduct.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0312-privacy-protection-guidelines.mdx b/plugin-dev-zh/0312-privacy-protection-guidelines.mdx deleted file mode 100644 index 0e905dfe..00000000 --- a/plugin-dev-zh/0312-privacy-protection-guidelines.mdx +++ /dev/null @@ -1,101 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: setup - level: intermediate -standard_title: Privacy Protection Guidelines -language: zh -title: 插件隐私政策准则 -description: 本文档描述了开发者向Dify Marketplace提交插件时如何撰写隐私政策的准则。内容包括如何确认和列出所收集的个人数据类型(直接识别信息、间接识别信息、组合信息)、如何填写插件隐私政策、如何在Manifest文件中引入隐私政策声明,以及相关常见问题的解答。 ---- - -向 Dify Marketplace 提交插件上架申请时,你需要公开说明如何处理用户数据。以下是关于填写插件相关隐私问题和用户数据处理的指南。如果你还没有开发插件,可以参考[插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)。 - -插件隐私政策声明内容围绕以下问题展开: - -**你的插件是否收集和使用用户个人数据?** 如有,请整理并列出具体类型。 - -> 个人数据指可识别特定个人的任何信息,包括单独或与其他信息结合后可用于识别、联系或定位个人的信息。 - -#### **1. 列出所收集的数据类型** - -**类型一:直接识别信息** - -* 姓名(全名、名、姓) -* 邮箱 -* 手机号 -* 住址 -* 身份证件号(身份证、护照、驾照等) - -**类型二:间接识别信息** - -* 设备识别码(IMEI、MAC 地址、设备 ID) -* IP 地址 -* 位置信息(GPS 坐标、城市、地区) -* 在线标识(cookies、广告 ID) -* 用户名 -* 头像 -* 生物特征(指纹、人脸识别) -* 浏览记录 -* 购物记录 -* 健康数据 -* 财务信息 - -**类型三:被用于识别个人的组合信息** - -* 年龄 -* 性别 -* 职业 -* 兴趣爱好 - -即使你的插件本身不收集个人信息,也请确认插件使用的第三方服务是否涉及数据收集或处理。作为开发者,你需要公开所有数据收集活动,包括第三方服务的数据处理。请务必阅读第三方服务的隐私政策,确保在提交时声明插件涉及的所有数据收集情况。 - -例如,当你正在开发的插件涉及 Slack 服务时,请在插件的隐私政策声明文件中引用 [Slack 的隐私政策](https://slack.com/trust/privacy/privacy-policy)并声明数据收集情况。 - -#### 2. 填写最新版本的插件隐私政策 - -**插件隐私政策**必须包含: - -* 收集的数据类型 -* 数据用途 -* 是否与第三方共享数据(如有,请列出第三方服务的名称及其隐私政策链接) -* 如果不熟悉隐私政策写法,可以参考由 Dify 官方维护插件内的隐私政策 - -#### **3. 在插件 Manifest 文件内引入隐私政策声明** - -详细字段的填写说明请参考[通过清单文件定义插件信息](/plugin-dev-zh/0411-plugin-info-by-manifest)。 - -### **常见问题** - -1. **什么是"收集和使用"用户个人数据?有哪些常见案例?** - -"收集和使用"指对用户数据进行收集、传输、使用或共享。常见情况包括: - -* 通过表单收集个人信息; -* 使用登录功能(含第三方认证); -* 收集可能包含个人信息的输入或资源; -* 分析用户行为、互动和使用情况; -* 存储通讯内容,如消息、聊天记录、邮件; -* 访问关联社交媒体的用户资料; -* 收集健康数据,如运动、心率、医疗信息; -* 保存搜索记录或浏览行为; -* 处理财务信息,如银行资料、信用分、交易记录。 - -## 相关资源 - -- [发布插件](/plugin-dev-zh/0321-release-overview) - 了解插件发布流程 -- [发布至 Dify Marketplace](/plugin-dev-zh/0322-release-to-dify-marketplace) - 学习如何往官方市场提交插件 -- [插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct) - 了解插件提交规范 -- [通过清单文件定义插件信息](/plugin-dev-zh/0411-plugin-info-by-manifest) - 插件元数据配置 - -{/* -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-zh/0312-privacy-protection-guidelines.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0312-third-party-signature-verification.mdx b/plugin-dev-zh/0312-third-party-signature-verification.mdx deleted file mode 100644 index c57efbad..00000000 --- a/plugin-dev-zh/0312-third-party-signature-verification.mdx +++ /dev/null @@ -1,119 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: setup - level: intermediate -standard_title: Third-Party Signature Verification -language: zh -title: 第三方签名验证 -description: 本文档介绍了如何在Dify社区版中启用和使用第三方签名验证功能,包括密钥对生成、插件签名与验证、以及环境配置步骤,使管理员能够安全地安装未在Dify市场上提供的插件。 ---- - - -此功能仅在 Dify 社区版中可用,Dify 云端版目前不支持第三方签名验证。 - - -第三方签名验证允许 Dify 管理员安全地安装尚未在 Dify 市场上提供的插件,而无需修改 `.env` 文件绕开签名验证安全限制。 - -**使用场景:** - -* 一经同意,Dify 管理员可以为插件添加由开发者发送的签名。 -* 插件开发者可以为他们的插件添加签名,并将其与公钥一起发布给无法禁用签名验证的 Dify 管理员。 - -Dify 管理员和插件开发者都可以使用预先生成的密钥对为插件添加签名。此外,管理员可以配置 Dify 在插件安装过程中使用特定公钥强制执行签名验证。 - -## 生成用于签名和验证的密钥对 - -使用以下命令生成新的密钥对,用于添加和验证插件签名: - -```bash -dify signature generate -f your_key_pair -``` - -运行此命令后,将在当前目录中生成两个文件: - -* **私钥**:`your_key_pair.private.pem` -* **公钥**:`your_key_pair.public.pem` - -私钥用于签名插件,公钥用于验证插件的签名。 - -请妥善保管私钥。如果私钥被泄露,攻击者可以为任何插件添加有效签名,这将危及 Dify 社区版的安全性。 - -## 为插件添加签名并验证 - -运行以下命令为插件添加签名。请注意,你需要指定**待签名的插件文件**和**私钥**: - -```bash -dify signature sign your_plugin_project.difypkg -p your_key_pair.private.pem -``` - -执行命令后,将在同一目录中生成一个新的插件文件,文件名中添加了 `signed`:`your_plugin_project.signed.difypkg` - -你可以使用以下命令验证插件是否已正确签名。运行命令时需要指定**已签名的插件文件**和**公钥**: - -```bash -dify signature verify your_plugin_project.signed.difypkg -p your_key_pair.public.pem -``` - -如果省略公钥参数,验证将使用 Dify 市场公钥。在这种情况下,对于任何未从 Dify 市场下载的插件文件,签名验证将失败。 - -## 启用第三方签名验证 - -Dify 管理员可以在安装插件前强制使用预先批准的公钥进行签名验证。 - -### 放置公钥 - -将用于签名的私钥对应的**公钥**放在插件守护程序可以访问的位置。 - -例如,在 `docker/volumes/plugin_daemon` 下创建 `public_keys` 目录,并将公钥文件复制到对应路径: - -```bash -mkdir docker/volumes/plugin_daemon/public_keys -cp your_key_pair.public.pem docker/volumes/plugin_daemon/public_keys -``` - -### 环境变量配置 - -在 `plugin_daemon` 容器中,配置以下环境变量: - -* `THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED` - * 启用第三方签名验证。 - * 将此项设置为 `true` 以启用此功能。 -* `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` - * 指定用于签名验证的公钥文件路径。 - * 你可以列出多个公钥文件,用逗号分隔。 - -以下是配置这些变量的 Docker Compose 覆盖文件 (`docker-compose.override.yaml`) 示例: - -```yaml -services: - plugin_daemon: - environment: - FORCE_VERIFYING_SIGNATURE: true - THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED: true - THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS: /app/storage/public_keys/your_key_pair.public.pem -``` - -请注意,`docker/volumes/plugin_daemon` 在 `plugin_daemon` 容器中被挂载到 `/app/storage`。确保在 `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` 中指定的路径对应于容器内的路径。 - -要应用这些更改,请重启 Dify 服务: - -```bash -cd docker -docker compose down -docker compose up -d -``` - -重启服务后,第三方签名验证功能将在当前社区版环境中启用。 - -{/* -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-zh/0312-third-party-signature-verification.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0321-release-overview.mdx b/plugin-dev-zh/0321-release-overview.mdx deleted file mode 100644 index e4e4e35a..00000000 --- a/plugin-dev-zh/0321-release-overview.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: beginner -standard_title: Release Overview -language: zh -title: 发布插件 -description: 本文档介绍了Dify插件的三种发布方式:官方Marketplace、开源GitHub仓库和本地插件文件包。详细说明了每种发布方式的特点、发布流程以及适用场景,并提供了具体的发布建议以满足不同开发者的需求。 ---- - -### 发布方式 - -为了满足不同开发者的发布需求,Dify 提供了以下三种插件发布方式。在发布前,请确保你已完成插件的开发和测试,并阅读[插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin)和[插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct)。 - -#### **1. Marketplace** - -**简介**:Dify 官方提供的插件市场,用户可以在此浏览、搜索并一键安装各类插件。 - -**特点**: - -* 插件经审核后上线,**安全可靠**。 -* 可直接安装至个人或团队的 **Workspace** 中。 - -**发布流程**: - -* 将插件项目提交至 **Dify Marketplace** [代码仓库](https://github.com/langgenius/dify-plugins)。 -* 经过官方审核后,插件将在市场内公开发布,供其他用户安装使用。 - -详细说明请参考: - -[发布至 Dify Marketplace](/plugin-dev-zh/0322-release-to-dify-marketplace) - -#### 2. **GitHub 仓库** - -**简介**:将插件开源或托管在 **GitHub** 上,方便他人查看、下载和安装。 - -**特点**: - -* 便于**版本管理**和**开源共享**。 -* 用户可通过插件链接直接安装,无需平台审核。 - -**发布流程**: - -* 将插件代码推送至 GitHub 仓库。 -* 分享仓库链接,用户可通过链接将插件集成至 **Dify Workspace**。 - -详细说明请参考: - -[发布至个人 GitHub 仓库](/plugin-dev-zh/0322-release-to-individual-github-repo) - -#### 3. 插件文件包(本地安装) - -**简介**:将插件打包成本地文件(如 `.difypkg` 格式),通过文件分享的方式供他人安装。 - -**特点**: - -* 不依赖在线平台,**快速灵活**地分享插件。 -* 适用于**私有插件**或**内部测试**。 - -**发布流程**: - -* 将插件项目打包为本地文件。 -* 在 Dify 插件页面点击**上传插件**,选择本地文件安装插件。 - -你可以将插件项目打包为一个本地文件并分享给他人,在插件页上传文件后即可将插件安装至 Dify Workspace 内。 - -详细说明请参考: - -[打包为本地文件与分享](/plugin-dev-zh/0322-release-by-file) - -### **发布建议** - -* **想要推广插件** → **推荐使用 Marketplace**,通过官方审核保障插件质量,提升曝光度。 -* **开源共享项目** → **推荐使用 GitHub**,方便版本管理与社区协作。 -* **快速分发或内部测试** → **推荐使用插件文件**,简单高效地安装和分享。 - -### 第三方验证 - -安装非 Dify 市场内的插件时,有可能遇到第三方签名验证问题。解决办法请参考[第三方签名验证](/plugin-dev-zh/0312-third-party-signature-verification)。 - -## 相关资源 - -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 全面了解Dify插件开发 -- [插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct) - 了解插件提交的规范 -- [插件隐私数据保护指南](/plugin-dev-zh/0312-privacy-protection-guidelines) - 了解隐私政策编写要求 -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - 了解插件清单文件的配置 - -{/* -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-zh/0321-release-overview.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0322-release-by-file.mdx b/plugin-dev-zh/0322-release-by-file.mdx deleted file mode 100644 index 22dd5992..00000000 --- a/plugin-dev-zh/0322-release-by-file.mdx +++ /dev/null @@ -1,74 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: intermediate -standard_title: Release by File -language: zh -title: 打包为本地文件与分享 -description: 本文档介绍了如何将Dify插件项目打包为本地文件并分享给他人的详细步骤。内容包括插件打包前的准备工作、使用Dify插件开发工具执行打包命令、生成的.difypkg文件的安装方式以及如何分享插件文件给其他用户。 ---- - -完成插件开发后,你可以将插件项目打包为一个本地文件并分享给他人,通过插件文件即可安装至 Dify Workspace 内。如果你还没有开发插件,可以参考[插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)。 - -* **特点**: - * 不依赖在线平台,**快速灵活**地分享插件。 - * 适用于**私有插件**或**内部测试**。 -* **发布流程**: - * 将插件项目打包为本地文件。 - * 在 Dify 插件页面上传文件安装插件。 - -本文将介绍如何将插件项目打包为本地文件,以及如何使用本地文件安装插件。 - -### 前置准备 - -* **Dify 插件开发工具**,详细说明请参考[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools)。 - -配置完成后,在终端输入 `dify version` 命令,检查是否输出版本号信息以确认已安装必要的开发工具。 - -### 打包插件 - -> 打包插件前,请确保插件的 `manifest.yaml` 文件和 `/provider` 路径下的 `.yaml` 文件中的 `author` 字段与 GitHub ID 保持一致。关于清单文件的详细信息,请参考[一般规范定义](/plugin-dev-zh/0411-general-specifications)。 - -插件项目开发完成后,请确保已完成[远程调试测试](/plugin-dev-zh/0411-remote-debug-a-plugin)。需前往插件项目的上一级目录,运行以下插件打包命令: - -```bash -dify plugin package ./your_plugin_project -``` - -运行命令后将在当前路径下生成以 `.difypkg` 后缀结尾的文件。 - -![生成插件文件](https://assets-docs.dify.ai/2024/12/98e09c04273eace8fe6e5ac976443cca.png) - -### 安装插件 - -访问 Dify 插件管理页,轻点右上角的**安装插件** → **通过本地文件**安装,或将插件文件拖拽至页面空白处安装插件。 - -![安装插件文件](https://assets-docs.dify.ai/2024/12/8c31c4025a070f23455799f942b91a57.png) - -### 发布插件 - -你可以将插件文件分享给他人,或上传至互联网供他人下载。如果你希望更广泛地分享你的插件,可以考虑: - -1. [发布至个人GitHub仓库](/plugin-dev-zh/0322-release-to-individual-github-repo) - 通过GitHub分享插件 -2. [发布至Dify Marketplace](/plugin-dev-zh/0322-release-to-dify-marketplace) - 在官方市场发布插件 - -## 相关资源 - -- [发布插件](/plugin-dev-zh/0321-release-overview) - 了解各种发布方式 -- [初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools) - 配置插件开发环境 -- [远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin) - 学习插件调试方法 -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - 定义插件元数据 -- [插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-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-zh/0322-release-by-file.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0322-release-to-dify-marketplace.mdx b/plugin-dev-zh/0322-release-to-dify-marketplace.mdx deleted file mode 100644 index c0609669..00000000 --- a/plugin-dev-zh/0322-release-to-dify-marketplace.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: intermediate -standard_title: Release to Dify Marketplace -language: zh -title: 发布至 Dify Marketplace -description: 本指引详细介绍了如何将插件发布到Dify Marketplace的完整流程,包括提交PR、审核流程、发布后维护等关键步骤和注意事项。 ---- - -Dify Marketplace 欢迎来自合作伙伴和社区开发者的插件上架申请,你的贡献将进一步丰富 Dify 插件的可能性。本指引将提供清晰的发布流程和最佳实践建议,让你的插件能够顺利发布,并为社区带来价值。如果你还没有开发插件,可以参考[插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)。 - -请按照以下步骤,在 [GitHub 代码仓库](https://github.com/langgenius/dify-plugins)提交你的插件 Pull Request(PR)并接受审核,通过后插件将正式上线至 Dify Marketplace。 - -### 插件的发布流程 - -将插件发布至 Dify Marketplace 包含以下步骤: - -1. 根据[插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct)完成插件的开发和测试; -2. 根据[插件隐私数据保护指南](/plugin-dev-zh/0312-privacy-protection-guidelines)撰写该插件隐私政策,并将该隐私政策的文件路径或 URL 写入插件[一般规范定义](/plugin-dev-zh/0411-general-specifications); -3. 完成插件打包; -4. Fork [Dify Plugins](https://github.com/langgenius/dify-plugins) 代码仓库; -5. 在代码仓库中创建你的个人或组织文件夹,并将打包好的 `.difypkg` 文件上传至该文件夹下; -6. 遵循 GitHub 中的 PR Template 内容格式提交 Pull Request (PR),等待审核; -7. 审核通过后,插件代码将合并至 Main 分支,插件自动上架至 [Dify Marketplace](https://marketplace.dify.ai/)。 - -插件提交、审核和上架流程图: - -![The process of uploading plugins](https://assets-docs.dify.ai/2025/01/05df333acfaf662e99316432db23ba9f.png) - -> **Note**: 上图中的 Contributor Agreement 指的是[插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct)。 - -*** - -### Pull Request (PR) 审核期间 - -积极回应审查人员的提问和反馈: - -* **14 天内**未解决的 PR 评论将被标记为过时(可重新开启)。 -* **30 天内**未解决的 PR 评论将被关闭(不可重新开启,需要创建新 PR)。 - -*** - -### **Pull Request (PR) 审核通过后** - -**1. 持续维护** - -* 处理用户报告的问题和功能请求。 -* 在发生重大 API 变更时迁移插件: - * Dify 将提前发布变更通知和迁移说明。 - * Dify 工程师可提供迁移支持。 - -**2. Marketplace 公开 Beta 测试阶段的限制** - -* 避免对现有插件引入破坏性更改。 - -*** - -### 审核流程 - -**1. 审核顺序** - -* 按照 **先到先审** 的顺序处理 PR。审核将在 1 周内开始。如有延迟,审查人员将通过评论通知 PR 作者。 - -**2. 审核重点** - -* 检查插件名称、描述和设置说明是否清晰且具有指导性。 -* 检查插件的 [一般规范定义](/plugin-dev-zh/0411-general-specifications)是否符合格式规范,并包含有效的作者联系信息。 - -3. **插件的功能性和相关性** - -* 根据[插件开发指南](/plugin-dev-zh/0111-getting-started-dify-plugin)测试插件。 -* 确保插件在 Dify 生态系统中的用途合理。 - -[Dify.AI](https://dify.ai/) 保留接受或拒绝插件提交的权利。 - -*** - -### 常见问题 - -1. **如何判断插件是否独特?** - -示例:一个 Google 搜索插件仅增加了多语言版本,应被视为现有插件的优化。但如果插件实现了显著的功能改进(如优化批量处理或错误处理),则可以作为新插件提交。 - -2. **如果我的 PR 被标记为过时或关闭怎么办?** - -被标记为过时的 PR 可以在解决反馈后重新开启。被关闭的 PR(超过 30 天)需要重新创建一个新 PR。 - -3. **Beta 测试阶段可以更新插件吗?** - -可以,但应避免引入破坏性更改。 - -## 相关资源 - -- [发布插件](/plugin-dev-zh/0321-release-overview) - 了解各种发布方式 -- [插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct) - 插件提交规范 -- [插件隐私数据保护指南](/plugin-dev-zh/0312-privacy-protection-guidelines) - 隐私政策编写要求 -- [打包为本地文件与分享](/plugin-dev-zh/0322-release-by-file) - 插件打包方法 -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - 插件元数据定义 - -{/* -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-zh/0322-release-to-dify-marketplace.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0322-release-to-individual-github-repo.mdx b/plugin-dev-zh/0322-release-to-individual-github-repo.mdx deleted file mode 100644 index bb8f4f33..00000000 --- a/plugin-dev-zh/0322-release-to-individual-github-repo.mdx +++ /dev/null @@ -1,119 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: deployment - level: intermediate -standard_title: Release to Individual GitHub Repo -language: zh -title: 发布至个人 GitHub 仓库 -description: 本文档详细介绍了如何将Dify插件发布到个人的GitHub仓库中,包括准备工作、初始化本地插件仓库、连接远程仓库、上传插件文件、打包插件代码以及如何通过GitHub安装插件的完整流程。该方式允许开发者完全管理自己的插件代码和更新。 ---- - -支持通过 GitHub 仓库链接安装插件。插件开发完成后,你可以选择将插件发布至公开 GitHub 仓库供其他人下载和使用。如果你还没有开发插件,可以参考[插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)。 - -该方式具备以下优势: - -• **个人管理**:你可以完全控制插件的代码和更新 - -• **快速分享**:通过 GitHub 链接即可轻松分享给其他用户或团队成员,便于测试和使用 - -• **协作与反馈**:将插件开源后,有可能会吸引 GitHub 上潜在的协作者,帮助你快速改进插件 - -本文将指导你如何将插件发布到 GitHub 仓库。 - -### 准备工作 - -首先要确认你已开发并测试了插件,并阅读了[插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin)和[插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct)。在发布插件前,请确保你本地已安装以下工具: - -* GitHub 账号 -* 创建一个新的公开 GitHub 仓库 -* 本地已安装 Git 工具 - -关于 GitHub 的基础知识,请参考 [GitHub 文档](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository)。 - -### 1. 完善插件项目 - -将上传至公开的 GitHub 意味着你将公开插件。请确保你已完成插件的调试和验证,并已完善插件的 `README.md` 文件说明。 - -建议说明文件包含以下内容: - -* 插件的简介和功能描述 -* 安装和配置步骤 -* 使用示例 -* 联系方式或贡献指南 - -### 2. 初始化本地插件仓库 - -将插件公开上传至 GitHub 之前,请确保已完成插件的调试和验证工作,详细请参考[远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin)。在终端中导航到插件项目文件夹,并运行以下命令: - -```bash -git init -git add . -git commit -m "Initial commit: Add plugin files" -``` - -如果你是第一次使用 Git,可能还需要配置 Git 用户名和邮箱: - -```bash -git config --global user.name "Your Name" -git config --global user.email "your.email@example.com" -``` - -### 3. 连接远程仓库 - -使用以下命令,将本地仓库连接到 GitHub 仓库: - -```bash -git remote add origin https://github.com//.git -``` - -### 4. 上传插件文件 - -> 打包插件前,请确保插件的 `manifest.yaml` 文件和 `/provider` 路径下的 `.yaml` 文件中的 author 字段与 GitHub ID 保持一致。关于清单文件的详细规范,请参考[通过清单文件定义插件信息](/plugin-dev-zh/0411-plugin-info-by-manifest)。 - -将插件项目推送到 GitHub 仓库: - -```bash -git branch -M main -git push -u origin main -``` - -上传代码时建议附上标签,以便后续打包代码。 - -```bash -git tag -a v0.0.1 -m "Release version 0.0.1" - -git push origin v0.0.1 -``` - -### 5. 打包插件代码 - -前往 GitHub 代码仓库的 Releases 页,创建一个新的版本发布。发布版本时需上传插件文件。关于如何打包插件文件,详细说明请阅读[打包为本地文件与分享](/plugin-dev-zh/0322-release-by-file)。 - -![打包插件](https://assets-docs.dify.ai/2024/12/5cb4696348cc6903e380287fce8f529d.png) - -### 通过 GitHub 安装插件 - -其他人可以通过 GitHub 仓库地址安装该插件。访问 Dify 平台的插件管理页,选择通过 GitHub 安装插件,输入仓库地址后,选择版本号和包文件完成安装。 - -![](https://assets-docs.dify.ai/2024/12/3c2612349c67e6898a1f33a7cc320468.png) - -## 相关资源 - -- [发布插件](/plugin-dev-zh/0321-release-overview) - 了解各种发布方式 -- [打包为本地文件与分享](/plugin-dev-zh/0322-release-by-file) - 插件打包方法 -- [通过清单文件定义插件信息](/plugin-dev-zh/0411-plugin-info-by-manifest) - 定义插件元数据 -- [插件开发者准则](/plugin-dev-zh/0312-contributor-covenant-code-of-conduct) - 了解插件开发规范 -- [远程调试插件](/plugin-dev-zh/0411-remote-debug-a-plugin) - 学习插件调试方法 - -{/* -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-zh/0322-release-to-individual-github-repo.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0331-faq.mdx b/plugin-dev-zh/0331-faq.mdx deleted file mode 100644 index 7e2186aa..00000000 --- a/plugin-dev-zh/0331-faq.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -dimensions: - type: - primary: operational - detail: maintenance - level: beginner -todo: 开发者(Developer / Contributor)应该充分测试后才上架, debug 不该是用户(Dify User / Consumer) 该做的事. -standard_title: Faq -language: zh -title: 常见问题 -description: Author Allen 本文档回答了Dify插件开发和安装过程中的常见问题,包括插件上传失败的解决方法(修改author字段)以及如何处理插件安装过程中的验证异常(设置FORCE_VERIFYING_SIGNATURE环境变量)。 ---- - -## 安装插件时提示上传失败如何处理? - -**错误详情**:出现 `PluginDaemonBadRequestError: plugin_unique_identifier is not valid` 报错提示。 - -**解决办法**:将插件项目下的 `manifest.yaml` 文件和 `/provider` 路径下的 `.yaml` 文件中的 `author` 字段修改为 GitHub ID。 - -重新运行插件打包命令并安装新的插件包。 - -## 安装插件时遇到异常应如何处理? - -**问题描述**:安装插件时遇到异常信息:`plugin verification has been enabled, and the plugin you want to install has a bad signature`,应该如何处理? - -**解决办法**:在 `/docker/.env` 配置文件的末尾添加 `FORCE_VERIFYING_SIGNATURE=false` 字段,运行以下命令重启 Dify 服务: - -```bash -cd docker -docker compose down -docker compose up -d -``` - -添加该字段后,Dify 平台将允许安装所有未在 Dify Marketplace 上架(审核)的插件,可能存在安全隐患。 - -建议在测试 / 沙箱环境内安装插件,确认安全后再安装至生产环境。 - -{/* -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-zh/0331-faq.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-doc-contribution-guide.mdx b/plugin-dev-zh/0411-doc-contribution-guide.mdx deleted file mode 100644 index 6a2df895..00000000 --- a/plugin-dev-zh/0411-doc-contribution-guide.mdx +++ /dev/null @@ -1,133 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: 'Doc Contribution Guide' -language: zh -title: '贡献指南' -summary: '了解如何为 Dify 开发者文档贡献内容,包括更新现有文档和创建新文档的步骤与规范,共同建设高质量的文档资源。' ---- - -欢迎参与 Dify 文档的协同构建!本指南旨在阐述 Dify 开发者文档的贡献流程与规范,鼓励并协助社区成员共同提升文档质量。 - -## 更新现有文档 - - - - 在你希望修改的文档页面末尾,点击 **编辑此页面** 按钮。这将直接链接到 GitHub 上对应的源文件。 - - - - Dify 文档的 URL 与其在 GitHub 仓库中的相对路径存在明确的对应关系,可供熟悉结构的贡献者参考: - - | 网址 (示例) | GitHub 仓库相对路径 (示例) | - | :--- | :--- | - | `https://docs.dify.ai/plugin-dev-zh/0111-getting-started-dify-plugin` | `plugin-dev-zh/0111-getting-started-dify-plugin.mdx` | - - - ---- - - - 编辑时,请专注于正文内容的准确性和清晰度。文件头部的 Frontmatter 元数据及末尾的特定脚本或包含内容,通常由核心贡献者或通过自动化流程进行管理和维护。 - - - - 如发现文档问题,你也可以通过页面上的 **提交问题** 按钮向我们报告。准确的问题反馈对社区和项目而言都是重要的贡献。 - - -## 创建新文档 - - - - 在相应的语言目录下 (例如 `plugin-dev-zh`) 创建一个新的 `.mdx` 文件。 - - - 点击此卡片,直接在 GitHub 上创建文档。 - - - 初始文件名可自行定义 (例如 `qwertyuiop12345678.mdx`),文件名必须足够长。 - - - - - - 请遵循标准的 **Markdown** 语法。在 MDX 文件中,注释请使用 JSX 风格:`{/* 这是一个 MDX 注释 */}`,而非 HTML 风格的 ``。 - - - - 可适当运用 Mintlify 提供的组件优化内容结构与呈现: - - ```jsx - - 这是一个重要提示。 - - - - 这是一个警告信息。 - - - - 更多内容请参考相关资源... - - ``` - - 更多组件请参考 [Mintlify 组件文档](https://mintlify.com/docs)。 - - - - - 每篇文档都需要定义 Frontmatter 元数据: - - * 正确配置的 Frontmatter 是确保文档能够被系统准确索引、排序并在文档网站上正确显示和导航的关键。 - * **你的首要任务是贡献高质量、准确的文档内容。** - * 如果你熟悉 Dify 的 [文档 Frontmatter 元数据指南](/plugin-dev-zh/0412-doc-writing-dimensions-guide),我们非常欢迎你在提交时包含 Frontmatter。 - * **如果你不确定如何填写 Frontmatter,或者希望专注于内容创作,完全没有问题。** 你可以提交不包含 Frontmatter 或仅包含部分元数据的 Pull Request。社区和项目核心贡献者会协助你进行后续的添加、审核与优化。 - - - - - **你的内容贡献至关重要。** 即使你未提供完整的 Frontmatter,你的 Pull Request 依然受欢迎。确保文档最终拥有规范的元数据并成功集成,是社区与核心团队协作完成的工作。 - - -## 提交你的贡献 - -完成编辑或创建新文档后,请通过 GitHub 向主仓库提交 Pull Request。社区成员和项目维护者将对你的贡献进行审阅。 - -## 常见问题解答 - - - - 当然可以!文档贡献不需要编程技能。如果你对 Dify 有所了解,你可以帮助改进现有文档的清晰度、准确性,或添加更多用户友好的说明和示例。 - - - - 确保你的内容清晰、准确,并遵循我们的格式指南。在提交前检查拼写和语法。如果不确定,可以在提交前在社区中讨论你的想法。 - - - - 可以!我们欢迎多语言文档贡献。请确保你的文件放在对应语言的目录中,并在 Frontmatter 中正确标注语言代码。 - - - ---- - -感谢你为 Dify 社区和文档建设贡献力量! - -{/* -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-zh/0411-doc-contribution-guide.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-general-specifications.mdx b/plugin-dev-zh/0411-general-specifications.mdx deleted file mode 100644 index cb1599b3..00000000 --- a/plugin-dev-zh/0411-general-specifications.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: General Specifications -language: zh -title: 通用规范定义 -description: 本文档详细介绍了Dify插件开发中的通用结构和规范,包括路径规范、国际化对象(I18nObject)、供应商表单结构(ProviderConfig)、模型配置(ModelConfig)、节点响应(NodeResponse)和工具选择器(ToolSelector)等重要数据结构的定义和用途。 ---- - -本文将简要介绍插件开发中常见的结构。在开发过程中,强烈建议配合[插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin)和[开发者速查表](/plugin-dev-zh/0131-cheatsheet)一起阅读,以便更好地理解整体架构。 - -### 路径规范 - -在 Manifest 或任意 yaml 文件中填写文件路径时,根据不同的类型的文件,遵循下面两条规范: - -* 如果目标文件是一个图片或视频等多媒体文件时,例如填写插件的 `icon` ,你应该将这些文件放置于插件根目录下的 `_assets` 文件夹中。 -* 如果目标文件是一个普通文本文件,如 `.py` `.yaml` 等代码文件,你应该填写该文件在插件项目内的绝对路径。 - -### 通用结构 - -在定义插件时,有一些数据结构是可以在工具、模型、Endpoint 之间共用的,这里定义了这些共用结构。 - -#### I18nObject - -`I18nObject` 是一个符合 [IETF BCP 47](https://tools.ietf.org/html/bcp47) 标准的国际化结构,目前支持的四种语言为 - -* en\_US -* zh\_Hans -* ja\_Jp -* pt\_BR - -#### ProviderConfig - -`ProviderConfig` 为一个通用的供应商表单结构,适用于 `Tool`与`Endpoint` - -* `name`(string):表单项名称 -* `label`([I18nObject](#i18nobject), required):遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) -* `type`([provider\_config\_type](#providerconfigtype-string), required):表单类型 -* `scope`([provider\_config\_scope](#providerconfigscope-string)):可选项范围,根据`type`变动 -* `required`(bool):不能为空 -* `default`(any):默认值,仅支持基础类型 `float` `int` `string` -* `options`(list\[[provider\_config\_option](#providerconfigoption-object)]):可选项,仅当 type 为 `select` 时使用 -* `helper`(object):帮助文档链接的 label,遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) -* `url` (string):帮助文档链接 -* `placeholder`(object):遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) - -#### ProviderConfigOption(object) - -* `value`(string, required):值 -* `label`(object, required):遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) - -#### ProviderConfigType(string) - -* `secret-input` (string):配置信息将被加密 -* `text-input`(string):普通文本 -* `select`(string):下拉框 -* `boolean`(bool):开关 -* `model-selector`(object):模型配置信息,包含供应商名称、模型名称、模型参数等 -* `app-selector`(object):app id -* `tool-selector`(object):工具配置信息,包含工具供应商、名称、参数等 -* `dataset-selector`(string):TBD - -#### ProviderConfigScope(string) - -* 当 `type` 为 `model-selector` 时 - * `all` - * `llm` - * `text-embedding` - * `rerank` - * `tts` - * `speech2text` - * `moderation` - * `vision` -* 当 `type` 为 `app-selector` 时 - * `all` - * `chat` - * `workflow` - * `completion` -* 当`type` 为 `tool-selector` 时 - * `all` - * `plugin` - * `api` - * `workflow` - -#### ModelConfig - -* `provider` (string): 包含 plugin\_id 的模型供应商名称,形如 `langgenius/openai/openai`。 -* `model` (string): 具体的模型名称。 -* `model_type` (enum): 模型类型的枚举,可以参考[模型设计规则](/plugin-dev-zh/0411-model-designing-rules#modeltype)文档。 - -#### NodeResponse - -* `inputs` (dict): 最终输入到节点中的变量。 -* `outputs` (dict): 节点的输出结果。 -* `process_data` (dict): 节点运行过程中产生的数据。 - -#### ToolSelector - -* `provider_id` (string): 工具供应商名称 -* `tool_name` (string): 工具名称 -* `tool_description` (string): 工具描述 -* `tool_configuration` (dict\[str, Any]): 工具的配置信息 -* `tool_parameters` (dict\[str, dict]): 需要 LLM 推理的参数 - * `name` (string): 参数名称 - * `type` (string): 参数类型 - * `required` (bool): 是否必填 - * `description` (string): 参数描述 - * `default` (any): 默认 - * `options`(list\[string]): 可选项 - -## 相关资源 - -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 全面了解Dify插件开发 -- [开发者速查表](/plugin-dev-zh/0131-cheatsheet) - 插件开发常用命令和概念速查 - -- [工具插件开发详情](/plugin-dev-zh/0222-tool-plugin) - 详细了解工具插件开发流程 -- [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) - 了解模型配置的规范 - -{/* -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-zh/0411-general-specifications.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-model-designing-rules.mdx b/plugin-dev-zh/0411-model-designing-rules.mdx deleted file mode 100644 index f586eefc..00000000 --- a/plugin-dev-zh/0411-model-designing-rules.mdx +++ /dev/null @@ -1,225 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Model Designing Rules -language: zh -title: 模型设计规则 -description: 本文档详细定义了Dify模型插件开发的核心概念和结构,包括模型供应商(Provider)、AI模型实体(AIModelEntity)、模型类型(ModelType)、配置方法(ConfigurateMethod)、模型特性(ModelFeature)、参数规则(ParameterRule)、价格配置(PriceConfig)及各种凭证模式的详细数据结构规范。 ---- - -* 模型供应商规则基于 [Provider](#provider) 实体。 -* 模型规则基于 [AIModelEntity](#aimodelentity) 实体。 - -> 以下所有实体均基于 `Pydantic BaseModel`,可在 `entities` 模块中找到对应实体。 - -### Provider - -* `provider` (string) 供应商标识,如:`openai` -* `label` (object) 供应商展示名称,i18n,可设置 `en_US` 英文、`zh_Hans` 中文两种语言 - * `zh_Hans` (string) \[optional] 中文标签名,`zh_Hans` 不设置将默认使用 `en_US`。 - * `en_US` (string) 英文标签名 -* `description` (object) \[optional] 供应商描述,i18n - * `zh_Hans` (string) \[optional] 中文描述 - * `en_US` (string) 英文描述 -* `icon_small` (string) \[optional] 供应商小 ICON,存储在对应供应商实现目录下的 `_assets` 目录,中英文策略同 `label` - * `zh_Hans` (string) \[optional] 中文 ICON - * `en_US` (string) 英文 ICON -* `icon_large` (string) \[optional] 供应商大 ICON,存储在对应供应商实现目录下的 \_assets 目录,中英文策略同 label - * `zh_Hans` (string) \[optional] 中文 ICON - * `en_US` (string) 英文 ICON -* `background` (string) \[optional] 背景颜色色值,例:#FFFFFF,为空则展示前端默认色值。 -* `help` (object) \[optional] 帮助信息 - * `title` (object) 帮助标题,i18n - * `zh_Hans` (string) \[optional] 中文标题 - * `en_US` (string) 英文标题 - * `url` (object) 帮助链接,i18n - * `zh_Hans` (string) \[optional] 中文链接 - * `en_US` (string) 英文链接 -* `supported_model_types` (array\[[ModelType](#modeltype)]) 支持的模型类型 -* `configurate_methods` (array\[[ConfigurateMethod](#configuratemethod)]) 配置方式 -* `provider_credential_schema` (\[[ProviderCredentialSchema](#providercredentialschema)]) 供应商凭据规格 -* `model_credential_schema` (\[[ModelCredentialSchema](#modelcredentialschema)]) 模型凭据规格 - -### AIModelEntity - -* `model` (string) 模型标识,如:`gpt-3.5-turbo` -* `label` (object) \[optional] 模型展示名称,i18n,可设置 `en_US` 英文、`zh_Hans` 中文两种语言 - * `zh_Hans` (string) \[optional] 中文标签名 - * `en_US` (string) 英文标签名 -* `model_type` ([ModelType](#modeltype)) 模型类型 -* `features` (array\[[ModelFeature](#modelfeature)]) \[optional] 支持功能列表 -* `model_properties` (object) 模型属性 - * `mode` ([LLMMode](#llmmode)) 模式 (模型类型 `llm` 可用) - * `context_size` (int) 上下文大小 (模型类型 `llm` `text-embedding` 可用) - * `max_chunks` (int) 最大分块数量 (模型类型 `text-embedding moderation` 可用) - * `file_upload_limit` (int) 文件最大上传限制,单位:MB。(模型类型 `speech2text` 可用) - * `supported_file_extensions` (string) 支持文件扩展格式,如:mp3,mp4(模型类型 `speech2text` 可用) - * `default_voice` (string) 缺省音色,必选:alloy,echo,fable,onyx,nova,shimmer(模型类型 `tts` 可用) - * `voices` (list) 可选音色列表。 - * `mode` (string) 音色模型。(模型类型 `tts` 可用) - * `name` (string) 音色模型显示名称。(模型类型 `tts` 可用) - * `language` (string) 音色模型支持语言。(模型类型 `tts` 可用) - * `word_limit` (int) 单次转换字数限制,默认按段落分段(模型类型 `tts` 可用) - * `audio_type` (string) 支持音频文件扩展格式,如:mp3,wav(模型类型 `tts` 可用) - * `max_workers` (int) 支持文字音频转换并发任务数(模型类型 `tts` 可用) - * `max_characters_per_chunk` (int) 每块最大字符数 (模型类型 `moderation` 可用) -* `parameter_rules` (array\[[ParameterRule](#parameterrule)]) \[optional] 模型调用参数规则 -* `pricing` (\[[PriceConfig](#priceconfig)]) \[optional] 价格信息 -* `deprecated` (bool) 是否废弃。若废弃,模型列表将不再展示,但已经配置的可以继续使用,默认 False。 - -### ModelType - -* `llm` 文本生成模型 -* `text-embedding` 文本 Embedding 模型 -* `rerank` Rerank 模型 -* `speech2text` 语音转文字 -* `tts` 文字转语音 -* `moderation` 审查 - -### ConfigurateMethod - -* `predefined-model` 预定义模型 - -表示用户只需要配置统一的供应商凭据即可使用供应商下的预定义模型。 - -* `customizable-model` 自定义模型 - -用户需要新增每个模型的凭据配置。 - -* `fetch-from-remote` 从远程获取 - -与 `predefined-model` 配置方式一致,只需要配置统一的供应商凭据即可,模型通过凭据信息从供应商获取。 - - -### ModelFeature - -* `agent-thought` Agent 推理,一般超过 70B 有思维链能力。 -* `vision` 视觉,即:图像理解。 -* `tool-call` 工具调用 -* `multi-tool-call` 多工具调用 -* `stream-tool-call` 流式工具调用 - -### FetchFrom - -* `predefined-model` 预定义模型 -* `fetch-from-remote` 远程模型 - -### LLMMode - -* `completion` 文本补全 -* `chat` 对话 - -### ParameterRule - -* `name` (string) 调用模型实际参数名 -* `use_template` (string) \[optional] 使用模板 - -> 关于模板的具体使用,可以参考[创建新模型提供者](/plugin-dev-zh/0222-creating-new-model-provider)中的示例。 - -默认预置了 5 种变量内容配置模板: - -* `temperature` -* `top_p` -* `frequency_penalty` -* `presence_penalty` -* `max_tokens` - -可在 use\_template 中直接设置模板变量名,将会使用 entities.defaults.PARAMETER\_RULE\_TEMPLATE 中的默认配置不用设置除 `name` 和 `use_template` 之外的所有参数,若设置了额外的配置参数,将覆盖默认配置。可参考 `openai/llm/gpt-3.5-turbo.yaml`。 - -* `label` (object) \[optional] 标签,i18n - * `zh_Hans`(string) \[optional] 中文标签名 - * `en_US` (string) 英文标签名 -* `type`(string) \[optional] 参数类型 - * `int` 整数 - * `float` 浮点数 - * `string` 字符串 - * `boolean` 布尔型 -* `help` (object) \[optional] 帮助信息 - * `zh_Hans` (string) \[optional] 中文帮助信息 - * `en_US` (string) 英文帮助信息 -* `required` (bool) 是否必填,默认 False。 -* `default`(int/float/string/bool) \[optional] 默认值 -* `min`(int/float) \[optional] 最小值,仅数字类型适用 -* `max`(int/float) \[optional] 最大值,仅数字类型适用 -* `precision`(int) \[optional] 精度,保留小数位数,仅数字类型适用 -* `options` (array\[string]) \[optional] 下拉选项值,仅当 `type` 为 `string` 时适用,若不设置或为 null 则不限制选项值 - -### PriceConfig - -* `input` (float) 输入单价,即 Prompt 单价 -* `output` (float) 输出单价,即返回内容单价 -* `unit` (float) 价格单位,如以 1M tokens 计价,则单价对应的单位 token 数为 `0.000001` -* `currency` (string) 货币单位 - -### ProviderCredentialSchema - -* `credential_form_schemas` (array\[[CredentialFormSchema](#credentialformschema)]) 凭据表单规范 - -### ModelCredentialSchema - -* `model` (object) 模型标识,变量名默认 `model` - * `label` (object) 模型表单项展示名称 - * `en_US` (string) 英文 - * `zh_Hans`(string) \[optional] 中文 - * `placeholder` (object) 模型提示内容 - * `en_US`(string) 英文 - * `zh_Hans`(string) \[optional] 中文 -* `credential_form_schemas` (array\[[CredentialFormSchema](#credentialformschema)]) 凭据表单规范 - -### CredentialFormSchema - -* `variable` (string) 表单项变量名 -* `label` (object) 表单项标签名 - * `en_US`(string) 英文 - * `zh_Hans` (string) \[optional] 中文 -* `type` ([FormType](#formtype)) 表单项类型 -* `required` (bool) 是否必填 -* `default`(string) 默认值 -* `options` (array\[[FormOption](#formoption)]) 表单项为 `select` 或 `radio` 专有属性,定义下拉内容 -* `placeholder`(object) 表单项为 `text-input` 专有属性,表单项 PlaceHolder - * `en_US`(string) 英文 - * `zh_Hans` (string) \[optional] 中文 -* `max_length` (int) 表单项为`text-input`专有属性,定义输入最大长度,0 为不限制。 -* `show_on` (array\[[FormShowOnObject](#formshowonobject)]) 当其他表单项值符合条件时显示,为空则始终显示。 - -#### FormType - -* `text-input` 文本输入组件 -* `secret-input` 密码输入组件 -* `select` 单选下拉 -* `radio` Radio 组件 -* `switch` 开关组件,仅支持 `true` 和 `false` - -#### FormOption - -* `label` (object) 标签 - * `en_US`(string) 英文 - * `zh_Hans`(string) \[optional] 中文 -* `value` (string) 下拉选项值 -* `show_on` (array\[[FormShowOnObject](#formshowonobject)]) 当其他表单项值符合条件时显示,为空则始终显示。 - -#### FormShowOnObject - -* `variable` (string) 其他表单项变量名 -* `value` (string) 其他表单项变量值 - -## 相关资源 - -- [模型架构详解](/plugin-dev-zh/0412-model-schema) - 深入了解模型插件的架构规范 -- [快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model) - 学习如何应用这些规则添加新模型 -- [一般规范定义](/plugin-dev-zh/0411-general-specifications) - 了解插件清单文件的配置 -- [创建新模型提供者](/plugin-dev-zh/0222-creating-new-model-provider) - 开发全新的模型提供商插件 - -{/* -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-zh/0411-model-designing-rules.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-model-plugin-introduction.mdx b/plugin-dev-zh/0411-model-plugin-introduction.mdx deleted file mode 100644 index 52a59157..00000000 --- a/plugin-dev-zh/0411-model-plugin-introduction.mdx +++ /dev/null @@ -1,104 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Model Plugin Introduction -language: zh -title: Model 插件 -description: 介绍模型插件的基本概念和结构。模型插件让Dify能够调用不同供应商(如OpenAI、Anthropic、Google等)的各类模型,包括大语言模型(LLM)、文本嵌入、语音转文字等不同类型。 -todo: 考虑恢复被注释的'开始开发模型插件'章节,提供初学者友好的3步骤快速指引 ---- - -Model 模型插件使 Dify 平台能够调用该模型供应商下的所有 LLM。例如,安装 OpenAI 模型插件后,Dify 平台即可调用 OpenAI 提供的 `GPT-4`、`GPT-4o-2024-05-13` 等模型。 - -## 模型插件结构 - -为了便于理解在开发模型插件过程中可能涉及的概念,以下是模型插件内的结构简介: - -* **模型供应商**:大模型的开发公司,例如 **OpenAI、Anthropic、Google** 等; -* **模型分类**:根据模型供应商的不同,存在大语言模型(LLM)、文本嵌入模型(Text embedding)、语音转文字(Speech2text)等分类; -* **具体模型**:`claude-3-5-sonnet`、`gpt-4-turbo` 等。 - -插件项目中的代码层级结构: - -```bash -- 模型供应商 - - 模型分类 - - 具体模型 -``` - -以 **Anthropic** 为例,模型插件的示例结构如下: - -```bash -- Anthropic - - llm - claude-3-5-sonnet-20240620 - claude-3-haiku-20240307 - claude-3-opus-20240229 - claude-3-sonnet-20240229 - claude-instant-1.2 - claude-instant-1 -``` - -以 OpenAI 为例,因为它支持多种模型类型,所以存在多层模型分类,结构如下: - -```bash -├── models -│ ├── llm -│ │ ├── chatgpt-4o-latest -│ │ ├── gpt-3.5-turbo -│ │ ├── gpt-4-0125-preview -│ │ ├── gpt-4-turbo -│ │ ├── gpt-4o -│ │ ├── llm -│ │ ├── o1-preview -│ │ └── text-davinci-003 -│ ├── moderation -│ │ ├── moderation -│ │ └── text-moderation-stable -│ ├── speech2text -│ │ ├── speech2text -│ │ └── whisper-1 -│ ├── text_embedding -│ │ ├── text-embedding-3-large -│ │ └── text_embedding -│ └── tts -│ ├── tts-1-hd -│ ├── tts-1 -│ └── tts -``` - -## 模型配置 - -模型插件通过配置文件定义模型的行为和属性。详细的模型设计规则和配置格式请参考[模型设计规则](/plugin-dev-zh/0411-model-designing-rules)文档和[模型架构](/plugin-dev-zh/0412-model-schema)规范。 - -{/* -### 开始开发模型插件 - -请参考以下顺序阅读文档,了解如何开发一个模型插件。 - -1. [创建模型供应商](/zh-hans/plugins/quick-start/develop-plugins/model-plugin/create-model-providers) -2. 接入[预定义](/zh-hans/guides/model-configuration/predefined-model) / [自定义](/zh-hans/plugins/quick-start/develop-plugins/model-plugin/customizable-model)模型 -3. [调试插件](/zh-hans/plugins/quick-start/debug-plugin) -*/} - -## 进一步阅读 - -- [快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model) - 学习如何为已支持的供应商添加新模型 -- [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) - 详细了解模型配置的规范 -- [模型架构](/plugin-dev-zh/0412-model-schema) - 深入理解模型插件的架构 -- [通用规范定义](/plugin-dev-zh/0411-general-specifications) - 了解插件元数据定义方式 -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 返回插件开发入门指南 - -{/* -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-zh/0411-model-plugin-introduction.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-multilingual-readme.mdx b/plugin-dev-zh/0411-multilingual-readme.mdx deleted file mode 100644 index ec51e9a6..00000000 --- a/plugin-dev-zh/0411-multilingual-readme.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Multilingual README -language: zh -title: 多语言 README -description: 本文介绍插件多语言 README 的文件规范及其在 Dify Marketplace 中的展示规则。 ---- - -Dify 插件支持多语言 README,并将在 [Dify Marketplace](https://marketplace.dify.ai/?language=zh-Hans) 等位置根据用户的首选语言展示对应的 README。 - -### README 文件规范 - -| 语种 | 必需 | 文件名 | 存放路径 | 说明 | -| :------- | :-- | :----------------- | :-------------------- | :---------------- | -| **英语** | 是 | `README.md` | 插件根目录下 | / | -| **其他语种** | 否 | `README_<语言标识>.md` | 插件根目录下的 `readme` 文件夹中 | 目前支持日语、葡萄牙语、简体中文。 | - -目录结构示例如下: - -```bash -... -├── main.py -├── manifest.yaml -├── readme -│   ├── README_ja_JP.md -│   ├── README_pt_BR.md -│   └── README_zh_Hans.md -├── README.md -... -``` - -### Marketplace 展示规则 - -当插件提供了用户所用语言的 README 文件时,Dify Marketplace 的插件详情页将展示对应语言版本的 README。 - -![](/images/plugin_details_page_zh.jpg) - -{/* -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-zh/0411-multilingual-readme.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-persistent-storage-kv.mdx b/plugin-dev-zh/0411-persistent-storage-kv.mdx deleted file mode 100644 index 66f15816..00000000 --- a/plugin-dev-zh/0411-persistent-storage-kv.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Persistent Storage KV -language: zh -title: 持久化存储 -description: 本文档介绍了Dify插件中的持久化存储功能,详细说明了如何在插件中使用KV数据库来储存、获取和删除数据。这一功能使插件能够在相同Workspace内持久化存储数据,满足跨会话数据保存的需求。 ---- - -如果单独审视插件中的 Tool 及 Endpoint,不难发现大多数情况下其只能完成单轮交互,请求后返回数据,任务结束。 - -如果有需要长期储存的数据,如实现持久化的记忆,需要插件具备持久化存储能力。**持久化存储机制能够让插件具备在相同 Workspace 持久存储数据的能力**,目前通过提供 KV 数据库满足存储需求,未来可能会根据实际的使用情况推出更灵活更强大的储存接口。 - -### 储存 Key - -#### **入口** - -```python - self.session.storage -``` - -#### **接口** - -```python - def set(self, key: str, val: bytes) -> None: - pass -``` - -可以注意到传入的是一个 bytes,因此实际上你可以在其中储存文件。 - -### 获取 Key - -#### **入口** - -```python - self.session.storage -``` - -#### **接口** - -```python - def get(self, key: str) -> bytes: - pass -``` - -### 删除 Key - -#### **入口** - -```python - self.session.storage -``` - -#### **接口** - -```python - def delete(self, key: str) -> None: - pass -``` - -{/* -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-zh/0411-persistent-storage-kv.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-plugin-info-by-manifest.mdx b/plugin-dev-zh/0411-plugin-info-by-manifest.mdx deleted file mode 100644 index c8b7c32b..00000000 --- a/plugin-dev-zh/0411-plugin-info-by-manifest.mdx +++ /dev/null @@ -1,132 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Plugin info by Manifest -language: zh -title: Manifest -description: Author Yeuoly,Allen 本文档详细介绍了Dify插件中的Manifest文件,它是定义插件基本信息的YAML文件。文档包含完整的代码示例和详细的结构说明,涵盖插件版本、类型、作者、名称、资源使用、权限申请、功能定义、运行时等各方面的配置信息。 ---- - -Manifest 是一个符合 yaml 规范的文件,它定义了**插件**最基础的信息,包括但不限于插件名称、作者、包含的工具、模型等信息。关于插件的整体架构,请参考[插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin)和[开发者速查表](/plugin-dev-zh/0131-cheatsheet)。 - -若该文件的格式错误,插件的解析和打包过程都将会失败。 - -### 版本管理 - -插件的版本由 `manifest` 文件中的 `version` 字段管理。版本号必须符合 `大版本.小版本.补丁版本` 格式,否则自动更新可能无法正常工作。 - -### 代码示例 - -下面是一个 Manifest 文件的简单示例,将在下文解释各个数据的含义和作用。 - -如需参考其它插件的代码,请参考 [GitHub 代码仓库](https://github.com/langgenius/dify-official-plugins/blob/main/tools/google/manifest.yaml)。 - -```yaml -version: 0.0.1 -type: "plugin" -author: "Yeuoly" -name: "neko" -label: - en_US: "Neko" -created_at: "2024-07-12T08:03:44.658609186Z" -icon: "icon.svg" -resource: - memory: 1048576 - permission: - tool: - enabled: true - model: - enabled: true - llm: true - endpoint: - enabled: true - app: - enabled: true - storage: - enabled: true - size: 1048576 -plugins: - endpoints: - - "provider/neko.yaml" -meta: - version: 0.0.1 - arch: - - "amd64" - - "arm64" - runner: - language: "python" - version: "3.11" - entrypoint: "main" -privacy: "./privacy.md" -``` - -### 结构 - -* `version`(version, required):插件的版本 -* `type`(type, required):插件类型,目前仅支持 `plugin`,未来支持 `bundle` -* `author`(string, required):作者,在 Marketplace 中定义为组织名 -* `label`(label, required):多语言名称 -* `created_at`(RFC3339, required):创建时间,Marketplace 上要求创建时间不得大于当前时间 -* `icon`(asset, required):图标路径 -* `resource` (object):需要申请的资源 - * `memory` (int64):最大内存占用,主要与 SaaS 上的 AWS Lambda 资源申请相关,单位字节 - * `permission`(object):权限申请 - * `tool`(object):反向调用工具的权限 - * `enabled` (bool) - * `model`(object):反向调用模型的权限 - * `enabled`(bool) - * `llm`(bool) - * `text_embedding`(bool) - * `rerank`(bool) - * `tts`(bool) - * `speech2text`(bool) - * `moderation`(bool) - * `node`(object):反向调用节点的权限 - * `enabled`(bool) - * `endpoint`(object):允许注册 `endpoint` 的权限 - * `enabled`(bool) - * `app`(object):反向调用`app`的权限 - * `enabled`(bool) - * `storage`(object):申请持久化存储的权限 - * `enabled`(bool) - * `size`(int64):最大允许多大的持久化内存,单位字节 -* `plugins`(object, required):插件扩展的具体能力的`yaml`文件列表,插件包内的绝对路径,如需要扩展模型,则需要定义一个类似于 `openai.yaml`的文件,并将该文件路径填写在此处,且该路径上的文件必须真实存在,否则打包将失败。 - * 格式 - * `tools`(list\[string]):插件扩展的[工具](/plugin-dev-zh/0222-tool-plugin)供应商 - * `models`(list\[string]):插件扩展的[模型](/plugin-dev-zh/0131-model-plugin-introduction)供应商 - * `endpoints`(list\[string]):插件扩展的 [Endpoints](/plugin-dev-zh/0432-endpoint) 供应商 - * `agent_strategies` (list\[string]):插件扩展的 [Agent 策略](/plugin-dev-zh/9433-agent-strategy-plugin)供应商 - * 限制 - * 不允许同时扩展工具与模型 - * 不允许没有任意扩展 - * 不允许同时扩展模型与 Endpoint - * 目前仅支持各类型扩展最多一个供应商 -* `meta`(object) - * `version`(version, required):`manifest` 格式版本,初始版本 `0.0.1` - * `arch`(list\[string], required):支持的架构,目前仅支持 `amd64` `arm64` - * `runner`(object, required):运行时配置 - * `language`(string):目前仅支持 python - * `version`(string):语言的版本,目前仅支持 `3.12` - * `entrypoint`(string):程序入口,在 python 下应为 `main` -* `privacy` (string, optional):可选项,指定插件隐私政策文件的相对路径或 URL,例如 `"./privacy.md"` 或 `"https://your-web/privacy"`。如果计划将插件上架至 Dify Marketplace,**该字段为必填项**,用于提供明确的用户数据使用和隐私声明。详细填写指引请参考[插件隐私数据保护指南](/plugin-dev-zh/0312-privacy-protection-guidelines)。 - -## 相关资源 - -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 全面了解Dify插件开发 -- [快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model) - 学习为已有的供应商添加新模型 -- [通用规范定义](/plugin-dev-zh/0411-general-specifications) - 了解插件开发中的通用结构 -- [发布概览](/plugin-dev-zh/0321-release-overview) - 学习插件发布流程 - -{/* -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-zh/0411-plugin-info-by-manifest.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-remote-debug-a-plugin.mdx b/plugin-dev-zh/0411-remote-debug-a-plugin.mdx deleted file mode 100644 index afb62181..00000000 --- a/plugin-dev-zh/0411-remote-debug-a-plugin.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Remote Debug a Plugin -language: zh -title: 插件调试 -description: 本文档介绍了如何使用Dify的远程调试功能来测试插件。详细说明了获取调试信息、配置环境变量文件、启动插件远程调试以及验证插件安装状态的完整流程。通过这种方式,开发者可以在本地开发的同时在Dify环境中实时测试插件。 ---- - -插件开发完成后,接下来需要测试插件是否可以正常运行。Dify 提供便捷的远程调试方式,帮助你快速在测试环境中验证插件功能。 - -前往[“插件管理”](https://cloud.dify.ai/plugins)页获取远程服务器地址和调试 Key。 - -![远程调试插件](https://assets-docs.dify.ai/2025/04/2779338a43687f3e00155baccdd6d06c.png) - -回到插件项目,拷贝 `.env.example` 文件并重命名为 `.env`,将获取的远程服务器地址和调试 Key 等信息填入其中。 - -`.env` 文件: - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -运行 `python -m main` 命令启动插件。在插件页即可看到该插件已被安装至 Workspace 内,团队中的其他成员也可以访问该插件。 - -![插件安装到 Workspace](https://assets-docs.dify.ai/2024/12/ec26e5afc57bbfeb807719638f603807.png) - -{/* -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-zh/0411-remote-debug-a-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0411-tool.mdx b/plugin-dev-zh/0411-tool.mdx deleted file mode 100644 index a521a0b1..00000000 --- a/plugin-dev-zh/0411-tool.mdx +++ /dev/null @@ -1,132 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: beginner -standard_title: Tool -language: zh -title: Tool Return -description: 本文档详细介绍了Dify插件中Tool的数据结构和使用方法。内容包括如何返回不同类型的消息(图片URL、链接、文本、文件、JSON)、如何创建变量和流式变量消息以及如何定义工具的输出变量模式以便于在workflow中引用。 ---- - -在阅读详细的接口文档之前,请确保你对 Dify 插件的工具接入流程已有大致了解。 - -### 数据结构 - -#### 消息返回 - -Dify 支持`文本` `链接` `图片` `文件BLOB` `JSON` 等多种消息类型,你可以通过以下不同的接口返回不同类型的消息。 - -在默认情况下,一个工具在 `workflow` 中的输出会包含 `files` `text` `json` 三个固定变量,且你可以通过下面的方法来返回这三个变量的数据。 - -例如使用 `create_image_message` 来返回图片,但是同时工具也支持自定义的输出变量,从而可以更方便地在 `workflow` 中引用这些变量。 - -#### **图片 URL** - -只需要传递图片的 URL,Dify 将通过链接自动下载图片并返回给用户。 - -```python - def create_image_message(self, image: str) -> ToolInvokeMessage: - pass -``` - -#### **链接** - -如果你需要返回一个链接,使用以下接口。 - -```python - def create_link_message(self, link: str) -> ToolInvokeMessage: - pass -``` - -#### **文本** - -如果你需要返回一个文本消息,使用以下接口。 - -```python - def create_text_message(self, text: str) -> ToolInvokeMessage: - pass -``` - -**文件** - -如果你需要返回文件的原始数据,如图片、音频、视频、PPT、Word、Excel 等,可以使用以下接口。 - -* `blob` 文件的原始数据,bytes 类型。 -* `meta` 文件的元数据。如果开发者需要明确的文件类型,请指定`mime_type`,否则 Dify 将使用`octet/stream`作为默认类型。 - -```python - def create_blob_message(self, blob: bytes, meta: dict = None) -> ToolInvokeMessage: - pass -``` - -#### **JSON** - -如果你需要返回一个格式化的 JSON,可以使用以下接口。这通常用于 workflow 中的节点间的数据传递。在 agent 模式中,大部分大模型也都能够阅读和理解 JSON。 - -* `object` 一个 Python 的字典对象,会被自动序列化为 JSON。 - -```python - def create_json_message(self, json: dict) -> ToolInvokeMessage: - pass -``` - -#### **变量** - -对于非流式输出的变量,你可以使用以下接口返回,如创建多份,后者将覆盖前者。 - -```python - def create_variable_message(self, variable_name: str, variable_value: Any) -> ToolInvokeMessage: - pass -``` - -#### **流式变量** - -如果你想以“打字机”效果输出一段文字,可以使用流式变量输出文本。如果你在 `chatflow` 应用中使用 `answer` 节点并引用了该变量,那么文本将以“打字机”的效果输出。但目前该方法仅支持字符串类型的数据。 - -```python - def create_stream_variable_message( - self, variable_name: str, variable_value: str - ) -> ToolInvokeMessage: -``` - -#### 返回自定义变量 - -如果想要在 `workflow` 应用中引用 `tool` 的输出变量,则有必要提前定义有哪些变量可能被输出。Dify 插件支持使用 [`json_schema`](https://json-schema.org/)格式的输出变量定义,以下是一个简单的示例: - -```yaml -identity: - author: author - name: tool - label: - en_US: label - zh_Hans: 标签 - ja_JP: ラベル - pt_BR: etiqueta -description: - human: - en_US: description - zh_Hans: 描述 - ja_JP: 説明 - pt_BR: descrição - llm: description -output_schema: - type: object - properties: - name: - type: string -``` - -上述示例代码定义了一个简单的工具,并为它指定了 `output_schema`,其中包含一个 `name` 字段,此时可以在 `workflow` 中引用该字段。但是请注意,还需要在工具的实现代码中返回一个变量才可以真正使用,否则将得到一个 `None` 返回结果。 - -{/* -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-zh/0411-tool.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0412-doc-understanding-the-dimensions.mdx b/plugin-dev-zh/0412-doc-understanding-the-dimensions.mdx deleted file mode 100644 index 858a02ea..00000000 --- a/plugin-dev-zh/0412-doc-understanding-the-dimensions.mdx +++ /dev/null @@ -1,470 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: intermediate -standard_title: 'Doc understanding the dimensions' -language: zh -title: '结构化与排序规范详解' ---- - -> dimensions - -## 背景与动机:应对开发者生态的演进 - -Dify 最初的成功很大程度上源于其产品的直观易用性。对于核心用户(User/Buyer),产品本身的体验往往足以引导他们;对于少数需要深度定制的早期开发者而言,他们通常具备直接阅读源代码的能力。因此,初期的文档建设并非最高优先级。 - -然而,随着 **Dify Plugin 插件生态的上线和蓬勃发展**,情况发生了显著变化: - -1. 受众扩大化: 我们的开发者社区不再局限于能够深入源码的核心贡献者。大量拥有一定技术背景但可能不熟悉 Dify 底层或特定编程范式的 **“半专业开发者” (Citizen Developers)** 或集成开发者涌现,他们需要清晰、循序渐进的指导来构建和贡献插件。 -2. 内容交织与目标模糊: 现有的文档往往将面向最终用户的**帮助内容**(如何使用插件)与面向开发者的**技术内容**(如何开发插件)混合在一起,导致两类受众都感到困惑,增加了信息查找成本。 -3. 结构缺失与导航困难: 文档缺乏统一的组织结构和逻辑顺序,使得开发者(尤其是新加入者)难以找到所需信息,也无法形成对插件开发生命周期的完整认知。现有导航难以承载日益增长的内容。 -4. 构建开发者关系 (DevRel) 的基石: 一个清晰、有效、结构优异的开发者文档体系,是构建成功开发者关系、繁荣插件生态不可或缺的一环。它直接影响开发者的体验、贡献意愿和成功率。 - -基于以上挑战,以及对业界优秀范例(如 Zapier Developer Platform, Cloudflare Docs)的分析——它们都展现了清晰的受众分离、结构化的内容组织和面向不同技能水平的路径设计——我们认识到对 Dify 的开发者文档进行**系统性重构**的迫切性。 - -dimensions**系统**应运而生。它并非一套僵化的格式要求,而是我们为了解决上述问题,将**结构化思维、受众细分、渐进式学习**等理念,通过一套**基于元数据的自动化流程**沉淀下来的解决方案。它旨在为 Dify 插件开发者提供一个清晰、一致且易于导航的技术知识库。 - -## 核心原则:元数据作为规范性数据源 - -本系统的基石在于以下核心原则: - -- 元数据驱动 (Metadata-Driven): 每篇 Markdown 文档的 Front Matter 中定义的元数据(特别是 dimensions, standard_title, language)是描述该文档内容属性、目标受众和预期用途的**规范性数据源 (Normative Data Source)**。 -- 内容与表现分离 (Decoupling Content from Presentation): 文档的最终呈现形式——包括文件名、在文档网站上的排序、导航菜单结构——都**必须由自动化工具根据这些元数据动态生成**。作者应专注于内容本身及其元数据描述的准确性。 -- 自动化保障一致性与可维护性 (Automation for Consistency & Maintainability): 自动化流程确保了整个文档库在结构、命名和排序上的一致性。对分类体系或排序逻辑的调整,只需修改中央配置和生成脚本即可全局应用,极大地提高了可维护性。 - -这种方法论让内容创作者(作者)和技术实现者(文档系统维护者/DevOps)能够有效协作,共同服务于最终开发者读者的需求。 - -## 元数据规范 - -每篇开发者文档(Markdown 文件)必须包含一个 YAML Front Matter 块,定义如下关键字段: - -```yaml ---- -# --- 核心元数据 --- - -# 'dimensions' 用于内容分类和自动排序 -dimensions: - type: # 主要类别 (Conceptual, Implementation, Operational, Reference) - 决定宏观顺序 (W) - primary: # 次要类别/细节 (Introduction, Basic, Core, Examples...) - 决定章节内顺序 (X) - detail: - # 目标读者级别/内容复杂度 (Beginner, Intermediate, Advanced) - 决定微观顺序 (Y) 及优先级 (P) - level: - -# 'standard_title' 用于生成可读的文件名,并供概览页面使用 -standard_title: '文档的标准、描述性标题' - -# 'language' (ISO 639-1 代码如 'en', 'zh') 用于国际化(i18n)和文件名后缀 -language: - -# --- 其他可选元数据 --- - -# 'summary': 文档内容的简短摘要 (可选, 可能用于列表页或 SEO) -# 'tags': [关键词列表] (可选, 用于过滤或关联内容) -# ... 其他未来可能需要的字段 ---- -``` - -```markdown -Type Dimension (Primary) - -- conceptual: Theoretical or explanatory content -- implementation: Code and development content -- operational: Content related to running and maintaining the system -- reference: Reference materials - -Type Detail Dimension - -- For conceptual: introduction, principles, architecture -- For implementation: basic, standard, high, advanced -- For operational: setup, deployment, maintenance -- For reference: core, configuration, examples - -Level Dimension - -- beginner: For newcomers to the topic -- intermediate: For users with basic understanding -- advanced: For advanced users -``` - -## dimensions 深度解析:为内容赋予意义 - -dimensions 元数据是本系统的核心,它要求我们为每一篇文档回答三个基本问题,从而赋予其明确的**语境、范围和受众定位**。这种分类是后续所有自动化结构和排序的基础。 - -- dimensions.type.primary:定义内容的“性质” - - - 核心问题: 这篇文档从根本上属于哪一类知识?它是关于“是什么/为什么”(理论),“如何做”(实践),“如何运行/维护”(运维),还是“精确查找”(参考)? - - 作用: 这个维度确立了文档在整个知识体系中的**宏观类别**。我们采用 conceptual, implementation, operational, reference 这几个业界通用的分类,来划分开发者关注的主要领域。这个分类决定了文档所属的**顶层章节**或主题区域,是构建文档信息架构的第一步。 - -- dimensions.type.detail:明确内容的“主题焦点” - - - 核心问题: 在上述宏观类别下,这篇文档具体是关于该类别的哪个**特定方面或子主题**?例如,是某个概念的“入门介绍”,还是某个实现的“标准用法”,或是某个参考信息的“核心 API”? - - 作用: 它在主类别内部提供了**更精细的主题划分**。这使得相关的文档能够聚集在一起,形成逻辑连贯的**子章节**或段落。选择恰当的 detail 有助于用户在浏览特定章节时快速定位到具体内容点。 - -- dimensions.level:标定内容的“复杂度与受众” - - 核心问题: 这篇特定主题的文档,主要是为哪个**经验水平的读者**准备的?或者说,其内容的**复杂度**如何?是入门 (beginner),通用 (intermediate),还是深入/专门 (advanced)? - - 作用: 这个维度具有**双重关键作用**: - 1. 细粒度排序: 在同一具体主题下,它允许内容按从易到难的顺序排列,优化学习曲线。 - 2. 优先级判定: 它(尤其是 advanced 级别)是系统区分“核心内容”与“进阶/深水区内容”的关键输入,直接影响内容是否被后置(见第 5 节)。 - -为内容精准地打上这三个维度的标签,是确保文档库结构合理、易于导航、满足不同用户需求的前提。 - -## 排序机制:**PWXY** 前缀与优先级规则 - -为实现一致且逻辑清晰的文档呈现顺序,系统将根据 dimensions 元数据为每篇文档自动生成一个 4 位、零填充的数字前缀 (PWXY),并以此作为文件名的一部分来实现排序。 - -- P **优先级 (Priority)**: 第 1 位。区分常规 (P=0) 与后置/深水区 (P=9) 内容。 -- W **主类编号 (Primary Type)**: 第 2 位。体现 primary 类型的宏观顺序。 -- X **子类编号 (Detail Type)**: 第 3 位。体现 detail 类型在主类内的顺序。 -- Y **难度级别编号 (Level)**: 第 4 位。体现 level 在子类内的顺序。 - -优先级 (**P=9**) 规则详解: - -将内容标记为 P=9 的目的是,将对入门和常规使用非必需的、复杂度较高的内容**自动后置**,从而为主流用户群体提供更平滑的学习曲线和更聚焦的核心内容流。触发 P=9 的条件是: - -1. 内容本身定义为高级: level: advanced。 -2. 实现类目下的特定复杂细节: primary: implementation 且 detail 为 high 或 advanced。 - -P=9 的内容可被视为文档库的“附录”、“深度探讨”或“高级参考”。 - -## 文件名生成策略 - -最终部署的文件名由自动化脚本基于元数据生成,其概念格式为: -`PWXY-[sanitized_standard_title].language.md` - -此文件名主要用于**机器排序**和内部标识。文档的**人类可读标题**以 `standard_title` 元数据和文档内的 H1 标题为准。自动化脚本负责处理元数据提取、PWXY 计算、标题清理、语言后缀、基于 GitHub 的[编辑与反馈按钮的自动实现](/tools/contributing_in_page.py)等所有细节。 - -## 面向受众的设计原则:渐进式披露与路径优化 - -本系统的设计贯穿着“渐进式信息披露” (Progressive Disclosure) 的核心原则,旨在优化不同背景开发者的信息获取路径。 - -1. 优先级机制 (P 值区分): 这是实现渐进式披露的主要手段。系统性地将基础、核心、高频使用的内容 (P=0) 与高级、复杂、特定场景的内容 (P=9) 分离开来。这保证了用户默认首先接触到的是一个相对精简、聚焦核心的知识体系。 -2. 结构化分类 (基于 type.primary 和 type.detail): 即便在同一优先级内,内容也被清晰地组织成不同类别和主题,为所有用户(尤其是经验丰富的用户)提供了一个可预测的“信息地图”。 - -基于以上原则,系统致力于为不同目标受众提供优化的体验: - -- 学习者与初探者 (Learners & Newcomers, incl. Citizen Developers): 通过默认阅览 P=0 的内容序列,获得一条从概念到基础实践的、结构化的学习路径,从而循序渐进,降低初期认知负荷。 -- 经验丰富的开发者与贡献者 (Experienced Developers & Contributors): 利用清晰的结构进行高效的**随机访问**,快速定位特定参考信息或实现细节,或根据需要直接深入 P=9 的高级内容。文档库对其而言更像一本可快速查阅的技术手册。 -- 自动化工具与服务 (e.g., LLMs): 承认其与人类不同的信息消费模式。结构化的元数据**使我们能够**为其生成专门优化的、可能更扁平化的数据输入流(如 `llms-full.txt`),提升其理解效率。 - -总而言之,dimensions 系统并非试图用一种方式满足所有人,而是通过**结构化分类、优先级排序和元数据驱动的自动化**,为不同需求的用户群体提供各自相对最优的信息访问和学习路径。 - -## 系统收益 - -- 结构清晰 & 导航改善: 基于可靠的分类和可预测的排序。 -- 一致性体验: 自动化确保所有文档遵循相同模式。 -- 受众适配: 通过优先级区分,提供差异化的阅读路径。 -- 高可维护性: 调整分类或排序逻辑只需修改中心配置和脚本。 -- 可扩展性: 易于添加新的内容类型或难度级别。 -- 促进协作: 为作者、审阅者和系统维护者提供了共同的理解基础和协作标准。 - -## 创作流程、角色与治理:应对现实挑战 - -建立高质量文档库是一个涉及多方协作的过程,并面临现实挑战。dimensions 系统旨在成为这个过程中的一个结构化框架和协作工具。 - -### 协作模型中的关键角色 - -- 创作者 (Creator / Author): - - - 核心职责: 创作准确、清晰、有价值的文档内容。 - - 协作要点: 学习并尝试理解 dimensions 分类体系,在提交时为文档**尝试**打上最合适的元数据标签(dimensions, standard_title, language)。准确的初始分类有助于后续流程。 - -- 审阅者 (Owner / Reviewer): - - - 核心职责: 对文档内容的**准确性、清晰度、范围**以及**元数据的恰当性**进行最终把关。这是确保文档库质量和结构一致性的关键环节。 - - 能力要求: 需要具备对相关技术领域的深刻理解,**同时**要能理解 dimensions 系统背后的**整体信息架构和受众细分逻辑**(这往往需要一定的系统性思维,类似于架构师视角)。 - - 协作要点: 利用 dimensions 作为客观“标尺”来评审内容定位。如果元数据不准确或内容边界模糊,应指导创作者修改或直接修正元数据。**最终合并到主分支的元数据决定了文档的呈现**。 - -- 运营者 (Operator / DevOps): - - - 核心职责: 维护和优化文档自动化构建、测试、部署的流程与工具。 - - 协作要点: 确保自动化脚本正确、高效地解析元数据并生成最终产物(排序的文件、导航数据等)。他们关注的是**流程的健壮性**,而非单篇文档的内容细节。 - -### 应对文档协作的现实挑战 - -这种角色划分有助于我们正视并尝试缓解一些常见的文档困境: - -- “程序员不爱写文档” vs. “写文档的不懂技术”: - - - dimensions 系统**降低了对创作者(程序员)的要求**:首要任务是写准技术内容,元数据分类可以“尽力而为”,因为有审阅者把关。 - - 同时,它**提升了对审阅者的要求**,承认了高质量文档需要深刻的技术理解和架构性思维,并将这种高阶能力引导到对文档结构和元数据的把控上。 - - 对于可能存在的“专职文档工程师”,他们可以作为创作者,或者辅助审阅者进行元数据校验和内容润色,角色更加灵活。 - -- 高质量审阅者稀缺且“性价比”疑虑: - - - 确实,具备所需技术深度和架构思维的审阅者是宝贵的。他们可能会觉得审阅文档相比核心功能开发“价值较低”。 - - 关键在于提升认知: 必须强调,**高质量、结构化的文档对于开发者生态的成功、降低支持成本、提升产品采用率具有极高的战略价值**。dimensions 系统正是将审阅者的高阶思维**显性化、规范化**,并**直接转化为可衡量的文档体验提升**的工具。审阅文档不再是“杂活”,而是塑造开发者体验、构建知识体系的关键一环。 - -- 流程保障: dimensions 系统提供了一个**协作框架**。它鼓励创作者思考内容定位,赋予审阅者清晰的评估标准和修正权限,并让运营者可以独立地维护自动化流程。通过将元数据检查纳入 PR 流程(类似 Code Review),可以制度化地保障最终产出的质量。 - -## 扩展性与代码的角色 - -- 系统扩展: dimensions 的分类体系并非静态。随着 Dify 功能的演进,可以(也应该)适时增加新的 primary 类型、detail 类型或 level。这主要通过更新中央映射配置和(如有必要)调整生成脚本来实现,体现了系统的灵活性。 -- 文档与代码的关系: 开发者文档(特别是 Reference 和高级 Implementation 部分)的核心目标之一是作为理解和使用**源代码**的**有效向导**。它应解释代码层面的设计、用法、约束,并通过链接等方式促进开发者在需要时**无缝地深入到源代码**这一最终的、最精确的内容中。文档不是代码的替代品,而是其**高质量的另一面和解释器**。 - -{/* -# Frontmatter Metadata Guide - -This document helps you quickly define core metadata for Dify developer documentation. Correctly filling out these fields is key to implementing automated document structure and sorting. - -## Quick Start - - - - - - Complete writing your document content. - - - - Provide your document and the content from [**dimensions system explained**](/plugin-dev-en/0412-doc-understanding-the-dimensions) to your preferred large language model, and request it to generate appropriate Frontmatter. - - - - Based on actual circumstances and the detailed explanations below, make necessary adjustments and optimizations to the generated metadata. - - - - - - Read the detailed instructions below and define appropriate metadata fields based on the characteristics of your document content. - - - -## Required Frontmatter Fields - -Please add the following YAML Frontmatter at the beginning of each Markdown document: - -```yaml ---- -# --- Core System Metadata (affects structure and sorting) --- -dimensions: - type: - primary: - detail: - level: -standard_title: 'Descriptive title in English, used for filename generation' # e.g., 'Getting Started Dify Plugin' -language: 'en' # or 'zh', 'ja', etc. (ISO 639-2 code) - -# --- Page Content Metadata (optional but recommended) --- -title: 'H1 title or page title of the document' -description: 'Brief SEO description of the document content' -# summary: 'More detailed summary (optional)' -# tags: ['keywords'] (optional) ---- -``` - -## Understanding the `dimensions` Field - - - - - - **Concepts, theory** (what/why) -
Focuses on explaining concepts and fundamental theories -
- - - **Development practices, code** (how to) -
Focuses on providing implementation steps and code examples -
- - - **Operations, deployment** (how to run) -
Focuses on system operation and maintenance -
- - - **API, configuration reference** (precise lookup) -
Focuses on technical specifications and reference information -
-
-
- - - Subdivisions under the `primary` category: - - - -
    -
  • introduction: Introductory content
  • -
  • principles: Design principles
  • -
  • architecture: Architectural explanation
  • -
-
- - -
    -
  • basic: Basic implementation
  • -
  • standard: Standard implementation
  • -
  • high: Higher-level implementation (may be deprioritized)
  • -
  • advanced: Advanced implementation (may be deprioritized)
  • -
-
- - -
    -
  • setup: Environment setup
  • -
  • deployment: Deployment operations
  • -
  • maintenance: Maintenance management
  • -
-
- - -
    -
  • core: Core reference
  • -
  • configuration: Configuration reference
  • -
  • examples: Example reference
  • -
-
-
- - - For more options, please refer to the [dimensions system explained](/plugin-dev-en/0412-doc-understanding-the-dimensions) document - -
- - - - - **Newcomer** -
Content suitable for beginners -
- - - **Regular user** -
Content for users with some background knowledge -
- - - **Advanced user** -
In-depth content for professional users (typically deprioritized in sorting) -
-
-
-
- -## Other Important Fields - - - Use **English** to clearly describe the core content of the document. The system will use this to generate part of the filename (e.g., `Getting Started Dify Plugin`). - - - - ISO 639-2 two-letter language code (such as `en`, `zh`, `ja`). - - - - The main title of the document displayed on the page, typically in the localized language. - - - - A brief SEO description for search engines and previews. - - -## Complete Examples - - - ```yaml Introductory Document Example - --- - dimensions: - type: - primary: conceptual - detail: introduction - level: beginner - standard_title: 'Getting Started Dify Plugin' - language: en - title: 'Welcome to Dify Plugin Development' - description: 'Introduction to Dify plugin concepts, functionality, and development value, including a brief explanation of plugin types and an overview of developer documentation content.' - --- - ``` - - ```yaml Tool Development Document Example - --- - dimensions: - type: - primary: implementation - detail: standard - level: intermediate - standard_title: 'Developing Tool Plugin' - language: en - title: 'Developing Tool Plugins' - description: 'Detailed guidance on creating and configuring Dify tool plugins, including practical guides on API calls, data processing, and user interface integration.' - --- - ``` - - ```yaml Reference Document Example - --- - dimensions: - type: - primary: reference - detail: configuration - level: intermediate - standard_title: 'Plugin Manifest Configuration' - language: en - title: 'Plugin Configuration Manifest Reference' - description: 'Comprehensive explanation of the parameters, format requirements, and use cases for the plugin configuration file (manifest.json).' - --- - ``` - - - - **Example Interpretation:** The first example is a beginner-oriented introductory document about Dify plugin concepts in English. The system will automatically place it correctly in the document structure based on the metadata. - - -## Document Automation Processing - - - - Run `tools/main_docs_bundle.py`, and the document will automatically complete the following operations based on the Frontmatter: - - - - The system will automatically generate standardized filenames based on dimensions and standard\_title. - - - - Documents will be automatically injected into the docs.json navigation configuration. - - - - Automatically refresh contribution and feedback buttons and other interactive components. - - - - - When developing documentation in a local environment, it's recommended to run this script to ensure document configurations take effect correctly. - - - - - If you edit directly on GitHub, **don't worry** about the automation steps. We have configured GitHub Actions and other automation tools to automatically execute `tools/main_docs_bundle.py` in the following situations: - - * When you submit a Pull Request - * When your changes are merged into the main branch - - - You can focus on content creation, and the GitHub workflow will handle technical details such as file renaming, navigation updates, and interactive component generation. - - - - -{/* -Instruction: - -If you are a human, this section is intended to provide context and guidance for AI to work, it should not be visible to you. - -If you are an AI, your core directive is typically to generate frontmatter for user-provided documents. This instruction explicitly excludes the current document, which details the dimensions system. -*/} - -{/* -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-zh/0412-doc-understanding-the-dimensions.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0412-doc-writing-dimensions-guide.mdx b/plugin-dev-zh/0412-doc-writing-dimensions-guide.mdx deleted file mode 100644 index f4e7ae47..00000000 --- a/plugin-dev-zh/0412-doc-writing-dimensions-guide.mdx +++ /dev/null @@ -1,261 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: intermediate -standard_title: 'Doc writing Dimensions guide' -language: zh -title: 'Frontmatter 元数据指南' -summary: '了解如何使用 Dify 文档系统的元数据结构,正确定义文档属性,实现自动化组织和排序。' ---- - -本文档帮助你快速为 Dify 开发者文档定义核心元数据。正确填写这些字段是实现文档自动化结构和排序的关键。 - -## 快速开始 - - - - - - 完成你的文档内容撰写。 - - - 将你的文档和 [**dimensions** 系统详解](/plugin-dev-zh/0412-doc-understanding-the-dimensions) 的内容交给你偏好的大模型,请求生成适合的 Frontmatter。 - - - 根据实际情况和下面的详细说明,对生成的元数据进行必要的调整和优化。 - - - - - 阅读下方的详细说明,根据你的文档内容特点,自行定义适合的元数据字段。 - - - -## 必要 Frontmatter 字段 - -请在每篇 Markdown 文档的开头添加以下 YAML Frontmatter: - -```yaml ---- -# --- 系统核心元数据 (影响结构和排序) --- -dimensions: - type: - primary: <见下方选项> - detail: <见下方选项> - level: <见下方选项> -standard_title: '英文描述性标题,用于生成文件名' # e.g., 'Getting Started Dify Plugin' -language: 'zh' # 或 'en', 'ja', etc. (ISO 639-2 代码) - -# --- 页面内容元数据 (可选,但推荐) --- -title: '文档的 H1 标题或页面标题' -description: '文档内容的简短 SEO 描述' -# summary: '更详细的摘要 (可选)' -# tags: ['关键词'] (可选) ---- -``` - -## `dimensions` 字段详解 - - - - - - **概念、理论** (是什么/为什么) -
重点解释概念和基础理论 -
- - **开发实践、代码** (如何做) -
重点提供实现步骤和代码示例 -
- - **运维、部署** (如何运行) -
重点关注系统运行和维护 -
- - **API、配置参考** (精确查找) -
重点提供技术规格和参考信息 -
-
-
- - - 在 `primary` 类别下的细分: - - - -
    -
  • introduction: 入门介绍
  • -
  • principles: 设计原则
  • -
  • architecture: 架构说明
  • -
-
- - -
    -
  • basic: 基础实现
  • -
  • standard: 标准实现
  • -
  • high: 高级实现 (可能后置)
  • -
  • advanced: 深度实现 (可能后置)
  • -
-
- - -
    -
  • setup: 环境设置
  • -
  • deployment: 部署操作
  • -
  • maintenance: 维护管理
  • -
-
- - -
    -
  • core: 核心参考
  • -
  • configuration: 配置参考
  • -
  • examples: 示例参考
  • -
-
-
- - - 更多选项请参考 [dimensions 系统详解](/plugin-dev-zh/0412-doc-understanding-the-dimensions) 文档 - -
- - - - - **新手入门** -
适合初学者的入门内容 -
- - **常规用户** -
适合有一定基础的用户 -
- - **高级用户** -
适合专业用户的深入内容 (通常会被后置排序) -
-
-
-
- -## 其他重要字段 - - - 使用**英文**,清晰描述文档核心内容。系统将用它生成部分文件名 (例如 `Getting Started Dify Plugin`)。 - - - - ISO 639-2 双字母语言代码 (如 `en`, `zh`, `ja`)。 - - - - 文档在页面上显示的主标题,通常是本地化语言。 - - - - 简短的SEO描述,用于搜索引擎和预览。 - - -## 完整示例 - - - ```yaml 入门文档示例 - --- - dimensions: - type: - primary: conceptual - detail: introduction - level: beginner - standard_title: 'Getting Started Dify Plugin' - language: zh - title: '欢迎开始 Dify 插件开发' - description: '介绍Dify插件的概念、功能和开发价值,包括插件类型的简要说明,以及开发者文档的内容概览。' - --- - ``` - - ```yaml 工具开发文档示例 - --- - dimensions: - type: - primary: implementation - detail: standard - level: intermediate - standard_title: 'Developing Tool Plugin' - language: zh - title: '开发工具插件' - description: '详细指导如何创建和配置Dify工具插件,包括API调用、数据处理和用户界面集成方面的实践指南。' - --- - ``` - - ```yaml 参考文档示例 - --- - dimensions: - type: - primary: reference - detail: configuration - level: intermediate - standard_title: 'Plugin Manifest Configuration' - language: zh - title: '插件配置清单参考' - description: '全面说明插件配置文件(manifest.json)的各项参数设置、格式要求和应用场景。' - --- - ``` - - - - **解读示例:** 第一个例子是一篇面向初学者的、关于 Dify 插件概念的入门介绍文档,语言为中文。系统会根据元数据自动将其正确放置在文档结构中。 - - -## 文档自动化处理 - - - - 运行 `tools/main_docs_bundle.py`,文档将被自动根据 Frontmatter 完成以下操作: - - - - 系统将根据 dimensions 和 standard_title 自动生成标准化文件名。 - - - 文档将被自动注入到 docs.json 导航配置中。 - - - 自动刷新贡献和反馈按钮等交互组件。 - - - - - 在本地环境开发文档时,建议运行该脚本确保文档配置正确生效。 - - - - - - 如果你在 GitHub 上直接进行编辑,**无需担心**自动化步骤。我们已经配置了 GitHub Action 等自动化工具,会在以下情况自动执行 `tools/main_docs_bundle.py`: - - - 当你提交 Pull Request 时 - - 当你的更改被合并到主分支时 - - - 你可以专注于内容创作,GitHub 工作流会处理文件重命名、导航更新和交互组件生成等技术细节。 - - - - - - 如果你对 Dimensions 系统的设计理念、排序机制的完整细节或角色与治理感兴趣,请阅读完整的 Dimensions 系统详解文档。 - - -{/* -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-zh/0412-doc-writing-dimensions-guide.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0412-model-schema.mdx b/plugin-dev-zh/0412-model-schema.mdx deleted file mode 100644 index d16ba2d1..00000000 --- a/plugin-dev-zh/0412-model-schema.mdx +++ /dev/null @@ -1,701 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: core - level: intermediate -standard_title: Model Schema -language: zh -title: 模型接口 -description: 本文档详细介绍了Dify模型插件开发所需的接口规范,包括模型供应商实现、五种模型类型(LLM、TextEmbedding、Rerank、Speech2text、Text2speech)的接口定义以及相关数据结构如PromptMessage、LLMResult等的完整规范。文档适用于开发者实现各种模型集成的开发参考。 ---- - -这里介绍供应商和各模型类型需要实现的接口方法和参数说明。在开发模型插件前,你可能需要首先阅读[模型设计规则](/plugin-dev-zh/0411-model-designing-rules)和[模型插件介绍](/plugin-dev-zh/0131-model-plugin-introduction)。 - -### 模型供应商 - -继承 `__base.model_provider.ModelProvider` 基类,实现以下接口: - -```python -def validate_provider_credentials(self, credentials: dict) -> None: - """ - Validate provider credentials - You can choose any validate_credentials method of model type or implement validate method by yourself, - such as: get model list api - - if validate failed, raise exception - - :param credentials: provider credentials, credentials form defined in `provider_credential_schema`. - """ -``` - -* `credentials` (object) 凭据信息 - -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 定义,传入如:`api_key` 等。验证失败请抛出 `errors.validate.CredentialsValidateFailedError` 错误。**注:预定义模型需完整实现该接口,自定义模型供应商只需要如下简单实现即可:** - -```python -class XinferenceProvider(Provider): - def validate_provider_credentials(self, credentials: dict) -> None: - pass -``` - -### 模型 - -模型分为 5 种不同的模型类型,不同模型类型继承的基类不同,需要实现的方法也不同。 - -#### 通用接口 - -所有模型均需要统一实现下面 2 个方法: - -* 模型凭据校验 - -与供应商凭据校验类似,这里针对单个模型进行校验。 - -```python -def validate_credentials(self, model: str, credentials: dict) -> None: - """ - Validate model credentials - - :param model: model name - :param credentials: model credentials - :return: - """ -``` - -参数: - -* `model` (string) 模型名称 -* `credentials` (object) 凭据信息 - -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。验证失败请抛出 `errors.validate.CredentialsValidateFailedError` 错误。 - -* 调用异常错误映射表 - -当模型调用异常时需要映射到 Runtime 指定的 `InvokeError` 类型,方便 Dify 针对不同错误做不同后续处理。Runtime Errors: - -* `InvokeConnectionError` 调用连接错误 -* `InvokeServerUnavailableError` 调用服务方不可用 -* `InvokeRateLimitError` 调用达到限额 -* `InvokeAuthorizationError` 调用鉴权失败 -* `InvokeBadRequestError` 调用传参有误 - -```python -@property -def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: - """ - Map model invoke error to unified error - The key is the error type thrown to the caller - The value is the error type thrown by the model, - which needs to be converted into a unified error type for the caller. - - :return: Invoke error mapping - """ -``` - -也可以直接抛出对应 Erros,并做如下定义,这样在之后的调用中可以直接抛出`InvokeConnectionError`等异常。 - -#### LLM - -继承 `__base.large_language_model.LargeLanguageModel` 基类,实现以下接口: - -* LLM 调用 - -实现 LLM 调用的核心方法,可同时支持流式和同步返回。 - -```python -def _invoke(self, model: str, credentials: dict, - prompt_messages: list[PromptMessage], model_parameters: dict, - tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None, - stream: bool = True, user: Optional[str] = None) \ - -> Union[LLMResult, Generator]: - """ - Invoke large language model - - :param model: model name - :param credentials: model credentials - :param prompt_messages: prompt messages - :param model_parameters: model parameters - :param tools: tools for tool calling - :param stop: stop sequences - :param stream: is stream response - :param user: unique user id - :return: full response or stream response chunk generator result - """ -``` - -* 参数: - * `model` (string) 模型名称 - * `credentials` (object) 凭据信息 - -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。 - -* `prompt_messages` (array\[[PromptMessage](#promptmessage)]) Prompt 列表 - -若模型为 `Completion` 类型,则列表只需要传入一个 [UserPromptMessage](#userpromptmessage) 元素即可;若模型为 `Chat` 类型,需要根据消息不同传入 [SystemPromptMessage](#systempromptmessage), [UserPromptMessage](#userpromptmessage), [AssistantPromptMessage](#assistantpromptmessage), [ToolPromptMessage](#toolpromptmessage) 元素列表 - -* `model_parameters` (object) 模型参数模型参数由模型 YAML 配置的 `parameter_rules` 定义。 - -* `tools` (array\[[PromptMessageTool](#promptmessagetool)]) \[optional] 工具列表,等同于 `function calling` 中的 `function`。即传入 tool calling 的工具列表。 - -* `stop` (array\[string]) \[optional] 停止序列模型返回将在停止序列定义的字符串之前停止输出。 - -* `stream` (bool) 是否流式输出,默认 True -流式输出返回 Generator\[[LLMResultChunk](#llmresultchunk)],非流式输出返回 [LLMResult](#llmresult)。 - -* `user` (string) \[optional] 用户的唯一标识符可以帮助供应商监控和检测滥用行为。 - -* 返回 - -流式输出返回 Generator\[[LLMResultChunk](#llmresultchunk)],非流式输出返回 [LLMResult](#llmresult)。 - -* 预计算输入 tokens - -若模型未提供预计算 tokens 接口,可直接返回 0。 - -```python -def get_num_tokens(self, model: str, credentials: dict, prompt_messages: list[PromptMessage], - tools: Optional[list[PromptMessageTool]] = None) -> int: - """ - Get number of tokens for given prompt messages - - :param model: model name - :param credentials: model credentials - :param prompt_messages: prompt messages - :param tools: tools for tool calling - :return: - """ -``` - -参数说明见上述 `LLM 调用`。该接口需要根据对应`model`选择合适的`tokenizer`进行计算,如果对应模型没有提供`tokenizer`,可以使用`AIModel`基类中的`_get_num_tokens_by_gpt2(text: str)`方法进行计算。 - -* 获取自定义模型规则 \[可选] - -```python -def get_customizable_model_schema(self, model: str, credentials: dict) -> Optional[AIModelEntity]: - """ - Get customizable model schema - - :param model: model name - :param credentials: model credentials - :return: model schema - """ -``` - -当供应商支持增加自定义 LLM 时,可实现此方法让自定义模型可获取模型规则,默认返回 None。 - -对于 `OpenAI` 供应商下的大部分微调模型,可以通过其微调模型名称获取到其基类模型,如`gpt-3.5-turbo-1106`,然后返回基类模型的预定义参数规则,参考 [OpenAI](https://github.com/langgenius/dify-official-plugins/tree/main/models/openai) 的具体实现。 - -#### TextEmbedding - -继承 `__base.text_embedding_model.TextEmbeddingModel` 基类,实现以下接口: - -* Embedding 调用 - -```python -def _invoke(self, model: str, credentials: dict, - texts: list[str], user: Optional[str] = None) \ - -> TextEmbeddingResult: - """ - Invoke large language model - - :param model: model name - :param credentials: model credentials - :param texts: texts to embed - :param user: unique user id - :return: embeddings result - """ -``` - -* 参数: - -* `model` (string) 模型名称 - -* `credentials` (object) 凭据信息 - -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。 - -* `texts` (array\[string]) 文本列表,可批量处理 - -* `user` (string) \[optional] 用户的唯一标识符 -可以帮助供应商监控和检测滥用行为。 - -* 返回: - -[TextEmbeddingResult](#textembeddingresult) 实体。 - -* 预计算 tokens - -```python -def get_num_tokens(self, model: str, credentials: dict, texts: list[str]) -> int: - """ - Get number of tokens for given prompt messages - - :param model: model name - :param credentials: model credentials - :param texts: texts to embed - :return: - """ -``` - -参数说明见上述 `Embedding 调用`。 - -同上述 `LargeLanguageModel`,该接口需要根据对应 `model` 选择合适的 `tokenizer` 进行计算,如果对应模型没有提供 `tokenizer`,可以使用`AIModel`基类中的`_get_num_tokens_by_gpt2(text: str)`方法进行计算。 - -#### Rerank - -继承 `__base.rerank_model.RerankModel` 基类,实现以下接口: - -* rerank 调用 - -```python -def _invoke(self, model: str, credentials: dict, - query: str, docs: list[str], score_threshold: Optional[float] = None, top_n: Optional[int] = None, - user: Optional[str] = None) \ - -> RerankResult: - """ - Invoke rerank model - - :param model: model name - :param credentials: model credentials - :param query: search query - :param docs: docs for reranking - :param score_threshold: score threshold - :param top_n: top n - :param user: unique user id - :return: rerank result - """ -``` - -* 参数: - -* `model` (string) 模型名称 -* `credentials` (object) 凭据信息 -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。 -* `query` (string) 查询请求内容 -* `docs` (array\[string]) 需要重排的分段列表 -* `score_threshold` (float) \[optional] Score 阈值 -* `top_n` (int) \[optional] 取前 n 个分段 -* `user` (string) \[optional] 用户的唯一标识符 -可以帮助供应商监控和检测滥用行为。 - - -* 返回: - -[RerankResult](#rerankresult) 实体。 - -#### Speech2text - -继承 `__base.speech2text_model.Speech2TextModel` 基类,实现以下接口: - - -* Invoke 调用 - -```python -def _invoke(self, model: str, credentials: dict, - file: IO[bytes], user: Optional[str] = None) \ - -> str: - """ - Invoke large language model - - :param model: model name - :param credentials: model credentials - :param file: audio file - :param user: unique user id - :return: text for given audio file - """ -``` - -* 参数: - -* `model` (string) 模型名称 -* `credentials` (object) 凭据信息 -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。 -* `file` (File) 文件流 -* `user` (string) \[optional] 用户的唯一标识符 -可以帮助供应商监控和检测滥用行为。 - -* 返回: - -语音转换后的字符串。 - -#### Text2speech - -继承 `__base.text2speech_model.Text2SpeechModel` 基类,实现以下接口: - -* Invoke 调用 - -```python -def _invoke(self, model: str, credentials: dict, content_text: str, streaming: bool, user: Optional[str] = None): - """ - Invoke large language model - - :param model: model name - :param credentials: model credentials - :param content_text: text content to be translated - :param streaming: output is streaming - :param user: unique user id - :return: translated audio file - """ -``` - -* 参数: - -* `model` (string) 模型名称 -* `credentials` (object) 凭据信息 -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。 -* `content_text` (string) 需要转换的文本内容 -* `streaming` (bool) 是否进行流式输出 -* `user` (string) \[optional] 用户的唯一标识符 -可以帮助供应商监控和检测滥用行为。 - -* 返回: - -文本转换后的语音流。 - - -#### Moderation - -继承 `__base.moderation_model.ModerationModel` 基类,实现以下接口: - -* Invoke 调用 - -```python -def _invoke(self, model: str, credentials: dict, - text: str, user: Optional[str] = None) \ - -> bool: - """ - Invoke large language model - - :param model: model name - :param credentials: model credentials - :param text: text to moderate - :param user: unique user id - :return: false if text is safe, true otherwise - """ -``` - -* 参数: - -* `model` (string) 模型名称 -* `credentials` (object) 凭据信息 -凭据信息的参数由供应商 YAML 配置文件的 `provider_credential_schema` 或 `model_credential_schema` 定义,传入如:`api_key` 等。 -* `text` (string) 文本内容 -* `user` (string) \[optional] 用户的唯一标识符 -可以帮助供应商监控和检测滥用行为。 - - -* 返回: - -False 代表传入的文本安全,True 则反之。 - -### 实体 - -#### PromptMessageRole - -消息角色 - -```python -class PromptMessageRole(Enum): - """ - Enum class for prompt message. - """ - SYSTEM = "system" - USER = "user" - ASSISTANT = "assistant" - TOOL = "tool" -``` - -#### PromptMessageContentType - -消息内容类型,分为纯文本和图片。 - -```python -class PromptMessageContentType(Enum): - """ - Enum class for prompt message content type. - """ - TEXT = 'text' - IMAGE = 'image' -``` - -#### PromptMessageContent - -消息内容基类,仅作为参数声明用,不可初始化。 - -```python -class PromptMessageContent(BaseModel): - """ - Model class for prompt message content. - """ - type: PromptMessageContentType - data: str # 内容数据 -``` - -当前支持文本和图片两种类型,可支持同时传入文本和多图。 -需要分别初始化 `TextPromptMessageContent` 和 `ImagePromptMessageContent` 传入。 - -#### TextPromptMessageContent - -```python -class TextPromptMessageContent(PromptMessageContent): - """ - Model class for text prompt message content. - """ - type: PromptMessageContentType = PromptMessageContentType.TEXT -``` - -若传入图文,其中文字需要构造此实体作为 `content` 列表中的一部分。 - -#### ImagePromptMessageContent - -```python -class ImagePromptMessageContent(PromptMessageContent): - """ - Model class for image prompt message content. - """ - class DETAIL(Enum): - LOW = 'low' - HIGH = 'high' - - type: PromptMessageContentType = PromptMessageContentType.IMAGE - detail: DETAIL = DETAIL.LOW # 分辨率 -``` - -若传入图文,其中图片需要构造此实体作为 `content` 列表中的一部分 -`data` 可以为 `url` 或者图片 `base64` 加密后的字符串。 - -#### PromptMessage - -所有 Role 消息体的基类,仅作为参数声明用,不可初始化。 - -```python -class PromptMessage(ABC, BaseModel): - """ - Model class for prompt message. - """ - role: PromptMessageRole # 消息角色 - content: Optional[str | list[PromptMessageContent]] = None # 支持两种类型,字符串和内容列表,内容列表是为了满足多模态的需要,可详见 PromptMessageContent 说明。 - name: Optional[str] = None # 名称,可选。 -``` - -#### UserPromptMessage - -UserMessage 消息体,代表用户消息。 - -```python -class UserPromptMessage(PromptMessage): - """ - Model class for user prompt message. - """ - role: PromptMessageRole = PromptMessageRole.USER -``` - -#### AssistantPromptMessage - -代表模型返回消息,通常用于 `few-shots` 或聊天历史传入。 - -```python -class AssistantPromptMessage(PromptMessage): - """ - Model class for assistant prompt message. - """ - class ToolCall(BaseModel): - """ - Model class for assistant prompt message tool call. - """ - class ToolCallFunction(BaseModel): - """ - Model class for assistant prompt message tool call function. - """ - name: str # 工具名称 - arguments: str # 工具参数 - - id: str # 工具 ID,仅在 OpenAI tool call 生效,为工具调用的唯一 ID,同一个工具可以调用多次 - type: str # 默认 function - function: ToolCallFunction # 工具调用信息 - - role: PromptMessageRole = PromptMessageRole.ASSISTANT - tool_calls: list[ToolCall] = [] # 模型回复的工具调用结果(仅当传入 tools,并且模型认为需要调用工具时返回) -``` - -其中 `tool_calls` 为调用模型传入 `tools` 后,由模型返回的 `tool call` 列表。 - -#### SystemPromptMessage - -代表系统消息,通常用于设定给模型的系统指令。 - -```python -class SystemPromptMessage(PromptMessage): - """ - Model class for system prompt message. - """ - role: PromptMessageRole = PromptMessageRole.SYSTEM -``` - -#### ToolPromptMessage - -代表工具消息,用于工具执行后将结果交给模型进行下一步计划。 - -```python -class ToolPromptMessage(PromptMessage): - """ - Model class for tool prompt message. - """ - role: PromptMessageRole = PromptMessageRole.TOOL - tool_call_id: str # 工具调用 ID,若不支持 OpenAI tool call,也可传入工具名称 -``` - -基类的 `content` 传入工具执行结果。 - -#### PromptMessageTool - -```python -class PromptMessageTool(BaseModel): - """ - Model class for prompt message tool. - """ - name: str # 工具名称 - description: str # 工具描述 - parameters: dict # 工具参数 dict - -``` - -*** - -#### LLMResult - -```python -class LLMResult(BaseModel): - """ - Model class for llm result. - """ - model: str # 实际使用模型 - prompt_messages: list[PromptMessage] # prompt 消息列表 - message: AssistantPromptMessage # 回复消息 - usage: LLMUsage # 使用的 tokens 及费用信息 - system_fingerprint: Optional[str] = None # 请求指纹,可参考 OpenAI 该参数定义 -``` - -#### LLMResultChunkDelta - -流式返回中每个迭代内部 `delta` 实体 - -```python -class LLMResultChunkDelta(BaseModel): - """ - Model class for llm result chunk delta. - """ - index: int # 序号 - message: AssistantPromptMessage # 回复消息 - usage: Optional[LLMUsage] = None # 使用的 tokens 及费用信息,仅最后一条返回 - finish_reason: Optional[str] = None # 结束原因,仅最后一条返回 -``` - -#### LLMResultChunk - -流式返回中每个迭代实体 - -```python -class LLMResultChunk(BaseModel): - """ - Model class for llm result chunk. - """ - model: str # 实际使用模型 - prompt_messages: list[PromptMessage] # prompt 消息列表 - system_fingerprint: Optional[str] = None # 请求指纹,可参考 OpenAI 该参数定义 - delta: LLMResultChunkDelta # 每个迭代存在变化的内容 -``` - -#### LLMUsage - -```python -class LLMUsage(ModelUsage): - """ - Model class for llm usage. - """ - prompt_tokens: int # prompt 使用 tokens - prompt_unit_price: Decimal # prompt 单价 - prompt_price_unit: Decimal # prompt 价格单位,即单价基于多少 tokens - prompt_price: Decimal # prompt 费用 - completion_tokens: int # 回复使用 tokens - completion_unit_price: Decimal # 回复单价 - completion_price_unit: Decimal # 回复价格单位,即单价基于多少 tokens - completion_price: Decimal # 回复费用 - total_tokens: int # 总使用 token 数 - total_price: Decimal # 总费用 - currency: str # 货币单位 - latency: float # 请求耗时(s) -``` - -*** - -#### TextEmbeddingResult - -```python -class TextEmbeddingResult(BaseModel): - """ - Model class for text embedding result. - """ - model: str # 实际使用模型 - embeddings: list[list[float]] # embedding 向量列表,对应传入的 texts 列表 - usage: EmbeddingUsage # 使用信息 -``` - -#### EmbeddingUsage - -```python -class EmbeddingUsage(ModelUsage): - """ - Model class for embedding usage. - """ - tokens: int # 使用 token 数 - total_tokens: int # 总使用 token 数 - unit_price: Decimal # 单价 - price_unit: Decimal # 价格单位,即单价基于多少 tokens - total_price: Decimal # 总费用 - currency: str # 货币单位 - latency: float # 请求耗时(s) -``` - -*** - -#### RerankResult - -```python -class RerankResult(BaseModel): - """ - Model class for rerank result. - """ - model: str # 实际使用模型 - docs: list[RerankDocument] # 重排后的分段列表 -``` - -#### RerankDocument - -```python -class RerankDocument(BaseModel): - """ - Model class for rerank document. - """ - index: int # 原序号 - text: str # 分段文本内容 - score: float # 分数 -``` - -## 相关资源 - -- [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) - 了解模型配置的规范 -- [模型插件介绍](/plugin-dev-zh/0131-model-plugin-introduction) - 快速了解模型插件的基本概念 -- [快速接入一个新模型](/plugin-dev-zh/0211-getting-started-new-model) - 学习为已有的供应商添加新模型 -- [创建新模型提供者](/plugin-dev-zh/0222-creating-new-model-provider) - 学习如何开发全新的模型供应商 - -{/* -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-zh/0412-model-schema.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0431-example-overview-and-index.mdx b/plugin-dev-zh/0431-example-overview-and-index.mdx deleted file mode 100644 index a8c4af9d..00000000 --- a/plugin-dev-zh/0431-example-overview-and-index.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: beginner -standard_title: Example Overview and Index -language: zh -title: 开发示例目录 ---- - - - - tool-plugin - - - extension-plugin - - - -{/* -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-zh/0431-example-overview-and-index.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0432-develop-a-slack-bot-plugin.mdx b/plugin-dev-zh/0432-develop-a-slack-bot-plugin.mdx deleted file mode 100644 index 3fab7f0e..00000000 --- a/plugin-dev-zh/0432-develop-a-slack-bot-plugin.mdx +++ /dev/null @@ -1,358 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: intermediate -standard_title: Develop A Slack Bot Plugin -language: zh -title: 开发 Slack Bot 插件 -description: 本文档提供了完整的Slack Bot插件开发指南,包括遍历项目初始化、编辑配置表单、实现功能代码、插件调试、设置Endpoint、效果验证到打包发布的完整流程。需要使用Dify插件脚手架工具和已创建的Slack - App以实现在Slack平台上搞建由AI驱动的聊天机器人。 ---- - -**本文将帮助你:** - -深入掌握 Slack Bot 的搭建方法,创建由 AI 驱动的 Slack 聊天机器人,在 Slack 平台上智能回答用户的问题。如果你还没有开发插件的经验,建议先阅读[插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)。 - -### 项目背景 - -Dify 插件生态致力于支持更简单、更易用的接入方式。本文将以 Slack 为例,详细介绍如何开发一个 Slack Bot 插件,便于团队中的成员直接在 Slack 平台内与 LLM 对话,提升 AI 服务的使用效率。 - -Dify 插件生态旨在提供更简单、更便捷的接入方式。本文将以 Slack 为例,详细讲解如何开发一个 Slack Bot 插件,帮助团队成员直接在 Slack 平台使用 AI 应用,提升办公效率。 - -Slack 是一个自由开放的实时办公通信平台,拥有丰富的 API。其中,基于事件机制的 Webhook 功能易于上手开发。我们将利用该机制创建 Slack Bot 插件,其原理如下图所示: - -![Slack Bot 原理图](https://assets-docs.dify.ai/2025/01/a0865d18f1ca4051601ca53fa6f92db2.png) - -> 为了避免混乱,现对以下概念作出解释: -> -> * **Slack Bot** 是在 Slack 平台上的一个聊天机器人,可以被视为虚拟角色,你可以与它进行聊天互动 -> * **Slack Bot 插件**指的是 Dify Marketplace上的一款插件,用于连接 Dify 应用与 Slack 平台。本文将主要围绕该插件开发展开。 - -**原理简介:** - -1. **向 Slack Bot 发送消息** - - 当用户在 Slack 中向 Bot 机器人发出一条消息的时候,Slack Bot 会发出一个 Webhook 请求到 Dify 平台。 -2. **消息转发至 Slack Bot 插件** - - 用户在与 Slack bot 对话时,需要将消息转发至 Dify 应用。好比邮件系统需要一位收件人的邮箱,此时可以通过 Slack 的 API 配置一个 Slack Webhook 的地址,并将其填入至 Slack Bot 插件并建立连接。 -3. **插件在接受到消息后,返回至某个 Dify 应用** - - Slack Bot 插件将处理 Slack 请求,发送至 Dify 中的应用。由 LLM 分析用户输入的内容并给出回应。 -4. **Dify 应用回应后,将消息返回至 Slack Bot 并回答用户** - - Slack Bot 获取 Dify 应用的回复后,通过插件将消息原路返回至 Slack Bot,使得用户能够在使用 Slack 时直接与 Dify 应用互动 - -### 前置准备 - -* Dify 插件脚手架工具,详细说明请参考[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools)。 -* Python 环境,版本号 ≥ 3.12,详细说明请参考 [Python 安装教程](https://pythontest.com/python/installing-python-3-11/),或询问 LLM 获取完整的安装教程。 -* 创建 Slack App 并获取 OAuth Token - -前往 [Slack API](https://api.slack.com/apps) 平台, 选择以 scratch 方式创建 Slack APP,并选择需部署应用的 Slack 空间。 - -![Slack API Token](https://assets-docs.dify.ai/2025/01/8217c23ee16c47c586a1387a442ea6f0.png) - -开启 Webhooks 功能。 - -![开启 Webhooks 功能](https://assets-docs.dify.ai/2025/01/fc9d7797608422219a01248f7151fc81.png) - -将 App 安装至 Slack 工作区内。 - -![安装到工作区内](https://assets-docs.dify.ai/2025/01/6ab7226078f88853fc7f4d3520245d63.png) - -获取 OAuth Token,用于后续的插件开发。 - -![获取 OAuth Token](https://assets-docs.dify.ai/2025/01/f08052044c8c17eebbffacdc9b2558e6.png) - -### 1. 开发插件 - -现在开始实际的插件编码工作。在开始之前,请确保你已经阅读过[开发 Extension 插件](/plugin-dev-zh/9231-extension-plugin),或已动手开发过一次 Dify 插件。 - -#### 初始化项目 - -运行以下命令初始化插件开发项目: - -```bash -dify plugin init -``` - -按照提示填写项目的基础信息,选择 `extension` 模板,并且授予 `Apps` 和 `Endpoints` 两个权限。 - -如需了解更多关于插件反向调用 Dify 平台能力,请参考[反向调用](/plugin-dev-zh/9241-reverse-invocation)。 - -![Plugins permission](https://assets-docs.dify.ai/2024/12/d89a6282c5584fc43a9cadeddf09c0de.png) - -#### 1. 编辑配置表单 - -在这个插件中,需要指定使用哪个 Dify 的 App 进行回复,并且在回复的时候需要使用到 Slack 的 App token,因此需要在插件表单中加上这两个字段。 - -修改 group 路径下的 yaml 文件,例如 `group/slack.yaml。`表单配置文件的名称由创建插件时填写的基础信息决定,你可以修改对应的 yaml 文件。 - -**示例代码:** - -`slack.yaml` - -```yaml -settings: - - name: bot_token - type: secret-input - required: true - label: - en_US: Bot Token - zh_Hans: Bot Token - pt_BR: Token do Bot - ja_JP: Bot Token - placeholder: - en_US: Please input your Bot Token - zh_Hans: 请输入你的 Bot Token - pt_BR: Por favor, insira seu Token do Bot - ja_JP: ボットトークンを入力してください - - name: allow_retry - type: boolean - required: false - label: - en_US: Allow Retry - zh_Hans: 允许重试 - pt_BR: Permitir Retentativas - ja_JP: 再試行を許可 - default: false - - name: app - type: app-selector - required: true - label: - en_US: App - zh_Hans: 应用 - pt_BR: App - ja_JP: アプリ - placeholder: - en_US: the app you want to use to answer Slack messages - zh_Hans: 你想要用来回答 Slack 消息的应用 - pt_BR: o app que você deseja usar para responder mensagens do Slack - ja_JP: あなたが Slack メッセージに回答するために使用するアプリ -endpoints: - - endpoints/slack.yaml -``` - -代码数据结构说明: - -``` - - name: app - type: app-selector - scope: chat -``` - -* type 字段指定为 app-selector 字段 - - 用户在使用插件时可以访问某个 Dify 应用并进行消息转发。 -* scope 字段指定为 chat 字段 - - 只能使用 `agent` 、`chatbot` 、`chatflow` 等类型的 app。 - -最后修改 `endpoints/slack.yaml` 文件中的请求路径和请求方式,需要将 method 修改为 POST 方式。 - -**示例代码:** - -`endpoints/slack.yaml` - -```yaml -path: "/" -method: "POST" -extra: - python: - source: "endpoints/slack.py" -``` - -#### 2. 编辑功能代码 - -修改 `endpoints/slack.py`文件,并在其中添加下面的代码: - -````python -import json -import traceback -from typing import Mapping -from werkzeug import Request, Response -from dify_plugin import Endpoint -from slack_sdk import WebClient -from slack_sdk.errors import SlackApiError - - -class SlackEndpoint(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - """ - Invokes the endpoint with the given request. - """ - retry_num = r.headers.get("X-Slack-Retry-Num") - if (not settings.get("allow_retry") and (r.headers.get("X-Slack-Retry-Reason") == "http_timeout" or ((retry_num is not None and int(retry_num) > 0)))): - return Response(status=200, response="ok") - data = r.get_json() - - # Handle Slack URL verification challenge - if data.get("type") == "url_verification": - return Response( - response=json.dumps({"challenge": data.get("challenge")}), - status=200, - content_type="application/json" - ) - - if (data.get("type") == "event_callback"): - event = data.get("event") - if (event.get("type") == "app_mention"): - message = event.get("text", "") - if message.startswith("<@"): - message = message.split("> ", 1)[1] if "> " in message else message - channel = event.get("channel", "") - blocks = event.get("blocks", []) - blocks[0]["elements"][0]["elements"] = blocks[0].get("elements")[0].get("elements")[1:] - token = settings.get("bot_token") - client = WebClient(token=token) - try: - response = self.session.app.chat.invoke( - app_id=settings["app"]["app_id"], - query=message, - inputs={}, - response_mode="blocking", - ) - try: - blocks[0]["elements"][0]["elements"][0]["text"] = response.get("answer") - result = client.chat_postMessage( - channel=channel, - text=response.get("answer"), - blocks=blocks - ) - return Response( - status=200, - response=json.dumps(result), - content_type="application/json" - ) - except SlackApiError as e: - raise e - except Exception as e: - err = traceback.format_exc() - return Response( - status=200, - response="Sorry, I'm having trouble processing your request. Please try again later." + str(err), - content_type="text/plain", - ) - else: - return Response(status=200, response="ok") - else: - return Response(status=200, response="ok") - else: - return Response(status=200, response="ok") - -``` -```` - -为了便于测试,插件功能目前仅能重复用户输入的内容,暂不调用 Dify app。 - -### 2. 调试插件 - -前往 Dify 平台,获取 Dify 插件远程调试的连接地址和密钥。 - -![测试插件](https://assets-docs.dify.ai/2025/01/8d24006f0cabf5bf61640a9023c45db8.png) - -回到插件项目,复制 `.env.example` 文件并重命名为 `.env`。 - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_HOST=remote-url -REMOTE_INSTALL_PORT=5003 -REMOTE_INSTALL_KEY=****-****-****-****-**** -``` - -运行 `python -m main` 命令启动插件。在插件页即可看到该插件已被安装至 Workspace 内。其他团队成员也可以访问该插件。 - -```bash -python -m main -``` - -#### 设置插件 Endpoint - -在 Dify 的插件管理页中找到自动安装的测试插件,新建一个 Endpoint,填写名称、Bot token、选择需要连接的 app。 - -![测试插件](https://assets-docs.dify.ai/2025/01/07f87e8a2786d6f5f05195961c5630c3.png) - -保存后将生成一个 POST 请求地址。 - -![生成 POST 请求地址](https://assets-docs.dify.ai/2025/01/e6952a5798a7ae793b3fe7df6f76ea73.png) - -接下来还需要完成 Slack App 的设置。 - -1. 启用 Event 订阅 - -![启用 Event 订阅](https://assets-docs.dify.ai/2025/01/1d33bb9cde78a1b5656ad6a0b8350195.png) - -在其中粘贴上文中生成的插件 POST 请求地址。 - -![粘贴生成的插件 POST 请求地址](https://assets-docs.dify.ai/2025/01/65aa41f37c3800af49e944f9ff28e121.png) - -勾选 Slack App 所需具备的权限。 - -![选择 Slack App 所需权限](https://assets-docs.dify.ai/2025/01/25c38a2cf10ec6c55ae54970d790f37e.png) - -### 3. 验证插件效果 - -代码使用了 `self.session.app.chat.invoke` 调用 Dify 平台内的 App,并传递了 `app_id` 和 `query` 等信息,最后将 response 的内容返回至 Slack Bot。运行 `python -m main` 命令重启插件进行调试,确认 Slack Bot 是否能够正确输出 Dify App 的答复消息。 - -![验证插件效果](https://assets-docs.dify.ai/2025/01/6fc872d1343ce8503d63c5222f7f26f9.png) - -### 4. 打包插件(可选) - -确认插件能够正常运行后,可以通过以下命令行工具打包并命名插件。运行以后你可以在当前文件夹发现 `slack_bot.difypkg` 文件,该文件为最终的插件包。关于打包的详细步骤,请参考[打包为本地文件与分享](/plugin-dev-zh/0322-release-by-file)。 - -```bash -# Replace ./slack_bot with your actual plugin project path. - -dify plugin package ./slack_bot -``` - -恭喜,你已完成一个插件的完整开发、测试打包过程! - -### 5. 发布插件(可选) - -现在可以将它上传至 [Dify Marketplace 仓库](https://github.com/langgenius/dify-plugins) 来发布你的插件了!不过在发布前,请确保你的插件遵循了[发布至 Dify Marketplace](/plugin-dev-zh/0322-release-to-dify-marketplace)中的规范。 - -## 相关资源 - -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 全面了解Dify插件开发 -- [插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool) - 从零开始开发插件 -- [开发 Extension 插件](/plugin-dev-zh/9231-extension-plugin) - 了解扩展插件开发 -- [反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation) - 了解如何调用 Dify 平台能力 -- [反向调用 App](/plugin-dev-zh/9242-reverse-invocation-app) - 了解如何调用平台内的 App -- [发布插件](/plugin-dev-zh/0321-release-overview) - 学习发布流程 -- [发布至 Dify Marketplace](/plugin-dev-zh/0322-release-to-dify-marketplace) - 市场发布指南 -- [端点详细定义](/plugin-dev-zh/0432-endpoint) - Endpoint 详细定义 - -### 参考阅读 - -如果你想要查看完整 Dify 插件的项目代码,请前往 [GitHub 代码仓库](https://github.com/langgenius/dify-plugins)。除此之外,你可以看到其它插件的完整代码与具体细节。 - -如果想要了解更多插件,请参考以下内容。 - -**快速开始:** - -* [开发 Extension 插件](/plugin-dev-zh/9231-extension-plugin) -* [开发 Model 插件](/plugin-dev-zh/0211-getting-started-new-model) -* [Bundle 类型插件:将多个插件打包](/plugin-dev-zh/9241-bundle) - -**插件接口文档:** - -* [通过清单文件定义插件信息](/plugin-dev-zh/0411-plugin-info-by-manifest) - Manifest 结构 -* [端点](/plugin-dev-zh/0432-endpoint) - Endpoint 详细定义 -* [反向调用](/plugin-dev-zh/9241-reverse-invocation) - 反向调用 Dify 能力 -* [通用规范](/plugin-dev-zh/0411-general-specifications) - 工具规范 -* [模型架构](/plugin-dev-zh/0412-model-schema) - 模型 - -{/* -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-zh/0432-develop-a-slack-bot-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/0432-endpoint.mdx b/plugin-dev-zh/0432-endpoint.mdx deleted file mode 100644 index 0f49b6a6..00000000 --- a/plugin-dev-zh/0432-endpoint.mdx +++ /dev/null @@ -1,125 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: intermediate -standard_title: Endpoint -language: zh -title: 彩虹猫 Endpoint -description: Author Yeuoly,Allen 本文档详细介绍了Dify插件中Endpoint的结构和实现方式,以彩虹猫项目为例。内容包括如何定义Endpoint组、配置接口、实现_invoke方法以及处理请求和响应。文档详细解释了各种YAML配置字段的含义和使用方法。 ---- - -本文将以[彩虹猫](/plugin-dev-zh/9231-extension-plugin)项目为例,说明插件内的 Endpoint 的结构。Endpoint是插件对外暴露的HTTP接口,可用于与外部系统集成。完整的插件代码请参考 [GitHub 仓库](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko)。 - -### 组定义 - -一个 `Endpoint` 组是多个 `Endpoint` 的集合,在 `Dify` 插件内新建 `Endpoint` 时可能需要填写如下配置。 - -![](https://assets-docs.dify.ai/2024/11/763dbf86e4319591415dc5a1b6948ccb.png) - -除了 `Endpoint Name` 外,你可以通过编写组的配置信息来添加新的表单项,点击保存后,你可以看到其中包含的多个接口,它们将使用相同的配置信息。 - -![](https://assets-docs.dify.ai/2024/11/b778b7093b7df0dc80a476c65ddcbe58.png) - -#### **结构** - -* `settings`(map\[string] [ProviderConfig](/plugin-dev-zh/0411-general-specifications#providerconfig) ):Endpoint 配置定义 -* `endpoints`(list\[string], required):指向具体的 `endpoint` 接口定义 - -```yaml -settings: - api_key: - type: secret-input - required: true - label: - en_US: API key - zh_Hans: API key - ja_Jp: API key - pt_BR: API key - placeholder: - en_US: Please input your API key - zh_Hans: 请输入你的 API key - ja_Jp: あなたの API key を入れてください - pt_BR: Por favor, insira sua chave API -endpoints: - - endpoints/duck.yaml - - endpoints/neko.yaml -``` - -### 接口定义 - -* `path`(string):遵循 werkzeug 接口标准 -* `method`(string):接口方法,仅支持`HEAD` `GET` `POST` `PUT` `DELETE` `OPTIONS` -* `extra`(object):除基础信息外的配置信息 - * `python`(object) - * `source`(string):实现该接口的源代码 - -```yaml -path: "/duck/" -method: "GET" -extra: - python: - source: "endpoints/duck.py" -``` - -### 接口实现 - -需要实现一个继承自 `dify_plugin.Endpoint` 子类,并实现 `_invoke` 方法。 - -* **输入参数** - * `r`(Request):`werkzeug` 中的 `Request` 对象 - * `values`(Mapping):从 path 中解析到的路径参数 - * `settings`(Mapping):该 `Endpoint` 的配置信息 -* **返回** - * `werkzeug` 中的 `Response` 对象,支持流式返回 - * 不支持直接返回字符串 - -示例代码: - -```python -import json -from typing import Mapping -from werkzeug import Request, Response -from dify_plugin import Endpoint - -class Duck(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - """ - Invokes the endpoint with the given request. - """ - app_id = values["app_id"] - - def generator(): - yield f"{app_id}
" - - return Response(generator(), status=200, content_type="text/html") -``` - -## 注意事项 - -* Endpoint 只在插件被调用时才会实例化,并不是长期运行的服务 -* 请在开发 Endpoint 时注意安全性,避免执行危险操作 -* Endpoint 可以用于处理 Webhook 回调或提供接口给其他系统连接 - -如果你正在学习插件开发,建议先阅读[插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool)和[开发者速查表](/plugin-dev-zh/0131-cheatsheet)。 - -## 相关资源 - -- [插件开发基本概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 了解插件开发的整体架构 -- [彩虹猫实例](/plugin-dev-zh/9231-extension-plugin) - 扩展插件开发示例 -- [通用规范定义](/plugin-dev-zh/0411-general-specifications) - 了解 ProviderConfig 等通用结构 -- [Slack 机器人插件开发示例](/plugin-dev-zh/0432-develop-a-slack-bot-plugin) - 另一个插件开发示例 -- [插件开发入门指南](/plugin-dev-zh/0211-getting-started-dify-tool) - 从零开始开发插件 -- [反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation) - 了解如何使用反向调用功能 - -{/* -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-zh/0432-endpoint.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9231-extension-plugin.mdx b/plugin-dev-zh/9231-extension-plugin.mdx deleted file mode 100644 index 85207430..00000000 --- a/plugin-dev-zh/9231-extension-plugin.mdx +++ /dev/null @@ -1,295 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: high - level: beginner -standard_title: Extension Plugin -language: zh -title: Extension 插件 -description: 本文档提供了开发Extension类型插件的完整教程,详细介绍了环境准备、创建项目、定义插件请求入口、编写功能代码、调试、打包发布等全过程。示例项目是一个彩虹猫插件,展示了如何通过Extension插件处理HTTP请求并提供网页服务。 ---- - -本文将引导你快速开发一个 Extension 类型的插件,以帮助你了解插件开发的基础流程。 - -### 前置准备 - -* Dify 插件脚手架工具 -* Python 环境,版本号 ≥ 3.12 - -关于如何准备插件开发的脚手架工具,详细说明请参考[初始化开发工具](initialize-development-tools.md)。 - -### 创建新项目 - -在当前路径下,运行脚手架命令行工具,创建一个新的 dify 插件项目。 - -``` -./dify-plugin-darwin-arm64 plugin init -``` - -如果你已将该二进制文件重命名为了 `dify` 并拷贝到了 `/usr/local/bin` 路径下,可以运行以下命令创建新的插件项目: - -```bash -dify plugin init -``` - -#### 1. 填写插件信息 - -按照提示配置插件名称、作者信息与插件描述。如果你是团队协作,也可以将作者填写为组织名。 - -> 插件名称长度必须为 1-128 个字符,并且只能包含字母、数字、破折号和下划线。 - -![Plugins details](https://assets-docs.dify.ai/2024/12/75cfccb11fe31c56c16429b3998f2eb0.png) - -填写完成后,在插件开发语言环节中选择 Python。 - -![Plugins development: Python](https://assets-docs.dify.ai/2024/11/1129101623ac4c091a3f6f75f4103848.png) - -#### 2. 选择插件类型并初始化项目模板 - -脚手架工具内的所有模板均已提供完整的代码项目。出于演示说明,本文将以 `Extension` 类型插件模板作为示例。对于已熟悉插件的开发者而言,无需借助模板,可参考[接口文档](../../schema-definition/)指引完成不同类型的插件开发。 - -![Extension](https://assets-docs.dify.ai/2024/11/ff08f77b928494e10197b456fc4e2d5b.png) - -#### 3. 配置插件权限 - -插件还需要读取 Dify 主平台的权限才能正常连接。需要为该示例插件授予以下权限: - -* Tools -* LLMs -* Apps -* 启用持久化存储 Storage,分配默认大小存储 -* 允许注册 Endpoint - -> 在终端内使用方向键选择权限,使用 “Tab” 按钮授予权限。 - -勾选所有权限项后,轻点回车完成插件的创建。系统将自动生成插件项目代码。 - -![Plugins 权限](https://assets-docs.dify.ai/2024/11/5518ca1e425a7135f18f499e55d16bdd.png) - -插件的基础文件结构包含以下内容: - -``` -. -├── GUIDE.md -├── README.md -├── _assets -│ └── icon.svg -├── endpoints -│ ├── your-project.py -│ └── your-project.yaml -├── group -│ └── your-project.yaml -├── main.py -├── manifest.yaml -└── requirements.txt -``` - -* `GUIDE.md` 一个简短的引导教程,带领你完成插件的编写流程。 -* `README.md` 关于当前插件的简介信息,你需要把有关该插件的介绍和使用方法填写至该文件内。 -* `_assets` 存储所有与当前插件相关的多媒体文件。 -* `endpoints` 按照 cli 中的引导创建的一个 `Extension` 类型插件模板,该目录存放所有 Endpoint 的功能实现代码。 -* `group` 指定密钥类型、多语言设置以及 API 定义的文件路径。 -* `main.py` 整个项目的入口文件。 -* `manifest.yaml` 整个插件的基础配置文件,包含该插件需要什么权限、是什么类型的扩展等配置信息。 -* `requirements.txt` 存放 Python 环境的依赖项。 - -### 开发插件 - -#### 1. 定义插件的请求入口 Endpoint - -编辑 `endpoints/test_plugin.yaml` ,参考以下代码进行修改: - -```yaml -path: "/neko" -method: "GET" -extra: - python: - source: "endpoints/test_plugin.py" -``` - -该代码的意图是定义该插件的入口路径为 `/neko`,请求方法为 GET 类型。插件的功能实现代码为 `endpoints/test_plugin.py` 文件。 - -#### 2. 编写插件功能 - -插件功能:请求服务,输出一只彩虹猫。 - -编写插件的功能实现代码 `endpoints/test_plugin.py` 文件,参考以下示例代码: - -```python -from typing import Mapping -from werkzeug import Request, Response -from flask import Flask, render_template_string -from dify_plugin import Endpoint - -app = Flask(__name__) - -class NekoEndpoint(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - ascii_art = ''' -⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛⬛️⬜️⬜️⬜️⬜️⬜⬜️⬜️️ -🟥🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️🟥🟥🟥🟥🟥🟥🟥🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧⬛️⬜️⬜️⬜️⬜️⬜⬜️️ -🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥⬛️🥧🥧🥧💟💟💟💟💟💟💟💟💟💟💟💟💟🥧🥧🥧⬛️⬜️⬜️⬜️⬜⬜️️ -🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥⬛️🥧🥧💟💟💟💟💟💟🍓💟💟🍓💟💟💟💟💟🥧🥧⬛️⬜️⬜️⬜️⬜️⬜️️ -🟧🟧🟥🟥🟥🟥🟥🟥🟥🟥🟧🟧🟧🟧🟧🟧🟧🟧🟥🟥🟥🟥🟥🟥🟥⬛🥧💟💟🍓💟💟💟💟💟💟💟💟💟💟💟💟💟💟🥧⬛️⬜️⬜️⬜️⬜⬜️️ -🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬛️🥧💟💟💟💟💟💟💟💟💟💟⬛️⬛️💟💟🍓💟💟🥧⬛️⬜️⬛️️⬛️️⬜⬜️️ -🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬛️🥧💟💟💟💟💟💟💟💟💟⬛️🌫🌫⬛💟💟💟💟🥧⬛️⬛️🌫🌫⬛⬜️️ -🟨🟨🟧🟧🟧🟧🟧🟧🟧🟧🟨🟨🟨🟨🟨🟨🟨🟨🟧⬛️⬛️⬛️⬛️🟧🟧⬛️🥧💟💟💟💟💟💟🍓💟💟⬛️🌫🌫🌫⬛💟💟💟🥧⬛️🌫🌫🌫⬛⬜️️ -🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨⬛️🌫🌫⬛️⬛️🟧⬛️🥧💟💟💟💟💟💟💟💟💟⬛️🌫🌫🌫🌫⬛️⬛️⬛️⬛️🌫🌫🌫🌫⬛⬜️️ -🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨⬛️⬛️🌫🌫⬛️⬛️⬛️🥧💟💟💟🍓💟💟💟💟💟⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛⬜️️ -🟩🟩🟨🟨🟨🟨🟨🟨🟨🟨🟩🟩🟩🟩🟩🟩🟩🟩🟨🟨⬛⬛️🌫🌫⬛️⬛️🥧💟💟💟💟💟💟💟🍓⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛️ -🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬛️⬛️🌫🌫⬛️🥧💟🍓💟💟💟💟💟💟⬛️🌫🌫🌫⬜️⬛️🌫🌫🌫🌫🌫⬜️⬛️🌫🌫⬛️ -️🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩⬛️⬛️⬛️⬛️🥧💟💟💟💟💟💟💟💟⬛️🌫🌫🌫⬛️⬛️🌫🌫🌫⬛️🌫⬛️⬛️🌫🌫⬛️ -🟦🟦🟩🟩🟩🟩🟩🟩🟩🟩🟦🟦🟦🟦🟦🟦🟦🟦🟩🟩🟩🟩🟩🟩⬛️⬛️🥧💟💟💟💟💟🍓💟💟⬛🌫🟥🟥🌫🌫🌫🌫🌫🌫🌫🌫🌫🟥🟥⬛️ -🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛️🥧🥧💟🍓💟💟💟💟💟⬛️🌫🟥🟥🌫⬛️🌫🌫⬛️🌫🌫⬛️🌫🟥🟥⬛️ -🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬛️🥧🥧🥧💟💟💟💟💟💟💟⬛️🌫🌫🌫⬛️⬛️⬛️⬛️⬛️⬛️⬛️🌫🌫⬛️⬜️ -🟪🟪🟦🟦🟦🟦🟦🟦🟦🟦🟪🟪🟪🟪🟪🟪🟪🟪🟦🟦🟦🟦🟦🟦⬛️⬛️⬛️🥧🥧🥧🥧🥧🥧🥧🥧🥧🥧⬛️🌫🌫🌫🌫🌫🌫🌫🌫🌫🌫⬛️⬜️⬜️ -🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪⬛️🌫🌫🌫⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬛️⬜️⬜️⬜️ -🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪⬛️🌫🌫⬛️⬛️⬜️⬛️🌫🌫⬛️⬜️⬜️⬜️⬜️⬜️⬛️🌫🌫⬛️⬜️⬛️🌫🌫⬛️⬜️⬜️⬜️⬜️ -⬜️⬜️🟪🟪🟪🟪🟪🟪🟪🟪⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️🟪🟪🟪🟪🟪⬛️⬛️⬛️⬛⬜️⬜️⬛️⬛️⬛️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️⬜️⬜️⬛️⬛️⬜️⬜️⬜️⬜️⬜️️ - ''' - ascii_art_lines = ascii_art.strip().split('\n') - with app.app_context(): - return Response(render_template_string(''' - - - - - - -
- - - - ''', ascii_art_lines=ascii_art_lines), status=200, content_type="text/html") -``` - -运行此代码需要先安装以下 Python 依赖包: - -```python -pip install werkzeug -pip install flask -pip install dify-plugin -``` - -### 调试插件 - -接下来需测试插件是否可以正常运行。Dify 提供远程调试方式,前往“插件管理”页获取调试 Key 和远程服务器地址。 - -![](https://assets-docs.dify.ai/2024/11/1cf15bc59ea10eb67513c8bdca557111.png) - -回到插件项目,拷贝 `.env.example` 文件并重命名为 `.env`,将获取的远程服务器地址和调试 Key 等信息填入其中。 - -`.env` 文件 - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_HOST=remote-url -REMOTE_INSTALL_PORT=5003 -REMOTE_INSTALL_KEY=****-****-****-****-**** -``` - -运行 `python -m main` 命令启动插件。在插件页即可看到该插件已被安装至 Workspace 内。其他团队成员也可以访问该插件。 - -![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) - -> 如果启动的时候遇到 An error occurred while parsing the data: b'handshake failed, invalid key',那就是 调试key 过期了,需要 前往“插件管理”页面重新获取调试 Key。 - -在插件内新增 Endpoint,随意填写名称和 `api_key` 等信息。访问自动生成的 URL,即可看到由插件提供的网页服务。 - -![](https://assets-docs.dify.ai/2024/11/c76375b8df2449d0d8c31a7c2a337579.png) - -### 打包插件 - -确认插件能够正常运行后,可以通过以下命令行工具打包并命名插件。运行以后你可以在当前文件夹发现 `neko.difypkg` 文件,该文件为最终的插件包。 - -```bash -dify plugin package ./neko -``` - -恭喜,你已完成一个插件的完整开发、测试打包过程! - -### 发布插件 - -现在可以将它上传至 [Dify Plugins 代码仓库](https://github.com/langgenius/dify-plugins) 来发布你的插件了!上传前,请确保你的插件遵循了[插件发布规范](https://docs.dify.ai/zh-hans/plugins/publish-plugins/publish-to-dify-marketplace)。审核通过后,代码将合并至主分支并自动上线至 [Dify Marketplace](https://marketplace.dify.ai/)。 - -### 探索更多 - -**快速开始:** - -* [Tool 插件:Google Search](tool-plugin.md) -* [Model 插件](model-plugin/) -* [Bundle 插件:将多个插件打包](bundle.md) - -**插件接口文档:** - -* [Manifest](../../schema-definition/manifest.md) 结构 -* [Endpoint](../../schema-definition/endpoint.md) 详细定义 -* [反向调用 Dify 能力](../../schema-definition/reverse-invocation-of-the-dify-service/) -* [工具](../../schema-definition/tool.md) -* [模型](../../schema-definition/model/) -* [扩展 Agent 策略](../../schema-definition/agent.md) - -**最佳实践:** - -[开发 Slack Bot 插件](../../best-practice/develop-a-slack-bot-plugin.md) - -{/* -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-zh/9231-extension-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9232-agent.mdx b/plugin-dev-zh/9232-agent.mdx deleted file mode 100644 index 58f7e2e8..00000000 --- a/plugin-dev-zh/9232-agent.mdx +++ /dev/null @@ -1,437 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: high - level: intermediate -standard_title: Agent -language: zh -title: Agent -description: 本文档详细介绍了Dify的Agent策略插件开发流程,包括在Manifest文件中添加Agent策略字段、定义Agent供应商以及实现Agent策略的核心步骤。文档详细介绍了如何获取参数、调用模型、调用工具以及生成和管理日志的完整示例代码。 ---- - -Agent 策略是一个定义了标准输入内容与输出格式的可扩展模板。通过开发具体 Agent 策略接口的功能代码,你可以实现众多不同的 Agent 策略如 CoT(思维链)/ ToT(思维树)/ GoT(思维图)/ BoT(思维骨架),实现一些诸如 [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-zh/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` 标准格式](/plugin-dev-zh/0411-tool),定义了 `model` `tools` `query` `max_iterations` 等一共四个参数,以便于实现最基础的 Agent 策略。该代码的含义是可以允许用户选择模型和需要使用的工具,配置最大迭代次数并最终传入一个 query 后开始执行 Agent。 - -#### 编写功能实现代码 - -**获取参数** - -根据上文定义的四个参数,其中 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 信息 `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="your system prompt message"), - 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 tool may be deleted - 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, - # add the default value - 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"result link: {cast(ToolInvokeMessage.TextMessage, response.message).text}." - + " please tell user to check it." - ) - elif response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif response.type == ToolInvokeMessage.MessageType.JSON: - text = json.dumps(cast(ToolInvokeMessage.JsonMessage, response.message).json_object, ensure_ascii=False) - result += f"tool response: {text}." - else: - result += f"tool response: {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 -``` - -**实例** - -这个示例展示了一个简单的两步执行过程:首先输出一条"正在思考"的状态日志,然后完成实际的任务处理。 - -```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="Thinking", - 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="you are a helpful assistant"), - 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-zh/0111-getting-started-dify-plugin) - 了解插件开发的整体架构 -- [Agent 策略插件开发示例](/plugin-dev-zh/9433-agent-strategy-plugin) - 实际的 Agent 策略插件开发示例 -- [通过清单文件定义插件信息](/plugin-dev-zh/0411-plugin-info-by-manifest) - 了解 Manifest 文件的详细格式 -- [反向调用 Model](/plugin-dev-zh/9242-reverse-invocation-model) - 了解如何调用平台内的模型能力 -- [反向调用 Tool](/plugin-dev-zh/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-zh/9232-agent.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9241-bundle.mdx b/plugin-dev-zh/9241-bundle.mdx deleted file mode 100644 index 655add85..00000000 --- a/plugin-dev-zh/9241-bundle.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: beginner -standard_title: Bundle -language: zh -title: Bundle 插件包 -description: 本文档介绍了Bundle插件包的概念和开发方法。Bundle插件包可以将多个插件集合到一起,支持三种类型(Marketplace类型、GitHub类型和Package类型)。文档详细说明了创建Bundle项目、添加不同类型依赖以及打包Bundle项目的全过程。 ---- - -Bundle 插件包是多个插件的集合。它可以将多个插件打包在一个插件内,以达到批量安装插件的效果,同时提供更强大的服务。 - -你可以通过 Dify cli 工具将多个插件打包为 Bundle。Bundle 插件包提供三种类型,分别为: - -* `Marketplace` 类型。储存了插件的 id 与版本信息。导入时会通过 Dify Marketplace 下载具体的插件包。 -* `GitHub` 类型。储存了 GitHub 的仓库地址、 release 版本号和 asset 文件名。导入时 Dify 会访问对应的 GitHub 仓库下载插件包。 -* `Package` 类型。插件包会直接被储存在 Bundle 中。它不储存引用源,但可能会造成 Bundle 包体积较大的问题。 - -### 前置准备 - -* Dify 插件脚手架工具 -* Python 环境,版本号 ≥ 3.10 - -关于如何准备插件开发的脚手架工具,详细说明请参考[初始化开发工具](initialize-development-tools.mdx)。 - -### 创建 Bundle 项目 - -在当前路径下,运行脚手架命令行工具,创建一个新的插件包项目。 - -```bash -./dify-plugin-darwin-arm64 bundle init -``` - -如果你已将该二进制文件重命名为了 `dify` 并拷贝到了 `/usr/local/bin` 路径下,可以运行以下命令创建新的插件项目: - -```bash -dify bundle init -``` - -#### 1. 填写插件信息 - -按照提示配置插件名称、作者信息与插件描述。如果你是团队协作,也可以将作者填写为组织名。 - -> 名称长度必须为 1-128 个字符,并且只能包含字母、数字、破折号和下划线。 - -![Bundle basic information](https://assets-docs.dify.ai/2024/12/03a1c4cdc72213f09523eb1b40832279.png) - -填写信息后敲击回车,将自动创建 Bundle 插件项目目录。 - -![](https://assets-docs.dify.ai/2024/12/356d1a8201fac3759bf01ee64e79a52b.png) - -#### 2. 添加依赖 - -* **Marketplace** - -执行以下命令: - -```bash -dify-plugin bundle append marketplace . --marketplace_pattern=langgenius/openai:0.0.1 -``` - -其中 marketplace\_pattern 为插件在 marketplace 中的引用,格式为 `组织名/插件名:版本号`。 - -* **GitHub** - -执行以下命令: - -```bash -dify-plugin bundle append github . --repo_pattern=langgenius/openai:0.0.1/openai.difypkg -``` - -其中 repo\_pattern 为插件在 github 中的引用,格式为 `组织名/仓库名:release/附件名`。 - -* **Package** - -执行以下命令: - -```bash -dify-plugin bundle append package . --package_path=./openai.difypkg -``` - -其中 package\_path 为插件包的目录。 - -### 打包 Bundle 项目 - -运行以下命令打包 Bundle 插件: - -```bash -dify-plugin bundle package ./bundle -``` - -执行命令后,当前目录下将自动创建 `bundle.difybndl` 文件,该文件即为最后的打包结果。 - -{/* -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-zh/9241-bundle.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9241-reverse-invocation.mdx b/plugin-dev-zh/9241-reverse-invocation.mdx deleted file mode 100644 index aec06efe..00000000 --- a/plugin-dev-zh/9241-reverse-invocation.mdx +++ /dev/null @@ -1,46 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: beginner -standard_title: Reverse Invocation -language: zh -title: 反向调用 Dify 服务 -description: 本文档简要介绍了Dify插件的反向调用能力,即插件可以调用Dify主平台内的指定服务。文档列出了四类可被调用的模块:App(访问App数据)、Model(调用平台内的模型能力)、Tool(调用平台内的其他工具插件)和Node(调用Chatflow/Workflow应用内的节点)。 ---- - -插件可以自由调用 Dify 主平台内的部分服务,用以提升插件的能力。 - -### 可被调用的 Dify 模块 - -* [App](/plugin-dev-zh/9242-reverse-invocation-app) - - 插件能够访问 Dify 平台内 App 的数据。 -* [Model](/plugin-dev-zh/9242-reverse-invocation-model) - - 插件能够反向调用 Dify 平台内的 LLM 能力,包括平台内的所有模型类型与功能,例如 TTS、Rerank 等。 -* [Tool](/plugin-dev-zh/9242-reverse-invocation-tool) - - 插件能够调用 Dify 平台内的其它工具类型插件。 -* [Node](/plugin-dev-zh/9243-reverse-invocation-node) - - 插件能够调用 Dify 平台内某个 Chatflow/Workflow 应用内的节点。 - -## 相关资源 - -- [开发 Extension 插件](/plugin-dev-zh/9231-extension-plugin) - 学习如何开发与外部系统集成的插件 -- [开发 Slack Bot 插件](/plugin-dev-zh/0432-develop-a-slack-bot-plugin) - 使用反向调用实现与 Slack 平台集成的实例 -- [Bundle 类型插件](/plugin-dev-zh/9241-bundle) - 了解如何打包多个使用反向调用的插件 -- [使用持久化存储](/plugin-dev-zh/0411-persistent-storage-kv) - 通过 KV 存储提升插件能力 - -{/* -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-zh/9241-reverse-invocation.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9242-reverse-invocation-app.mdx b/plugin-dev-zh/9242-reverse-invocation-app.mdx deleted file mode 100644 index 7d1c950c..00000000 --- a/plugin-dev-zh/9242-reverse-invocation-app.mdx +++ /dev/null @@ -1,138 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: intermediate -standard_title: Reverse Invocation App -language: zh -title: App -description: 本文档详细介绍了插件如何反向调用Dify平台中的App服务。内容包括三种不同类型的接口:聊天接口(适用于Chatbot/Agent/Chatflow类型应用)、Workflow接口和Completion接口,并提供了每种接口的入口方式、调用规范以及实际的调用示例代码。 ---- - -反向调用 App 指的是插件能够访问 Dify 中的 App 数据。该模块同时支持流式与非流式的 App 调用。如果你对反向调用的基本概念还不熟悉,请先阅读[反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation)。 - -**接口类型:** - -* 对于 `Chatbot/Agent/Chatflow` 类型应用而言,它们都属于聊天类型的应用,因此拥有相同类型的输入参数和输出参数,因此可被统一视为**聊天接口。** -* 对于 Workflow 应用而言,它单独占据一个 **Workflow 接口。** -* 对于 Completion(文本生成应用)应用而言,它单独占据一个 **Completion 接口**。 - -请注意,插件仅允许访问插件所在的 Workspace 中的 App。 - -### 调用聊天接口 - -#### **入口** - -```python - self.session.app.chat -``` - -#### **接口规范** - -```python - def invoke( - self, - app_id: str, - inputs: dict, - response_mode: Literal["streaming", "blocking"], - conversation_id: str, - files: list, - ) -> Generator[dict, None, None] | dict: - pass -``` - -当 `response_mode` 为 `streaming` 时,该接口将直接返回 `Generator[dict]`,否则直接返回 `dict`,具体的接口字段请参考 `ServiceApi` 的返回结果。 - -#### **用例** - -我们可以在一个 `Endpoint` 中调用 Chat 类型的 App,并将结果直接返回。 - -```python -import json -from typing import Mapping -from werkzeug import Request, Response -from dify_plugin import Endpoint - -class Duck(Endpoint): - def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: - """ - Invokes the endpoint with the given request. - """ - app_id = values["app_id"] - - def generator(): - response = self.session.app.chat.invoke( - app_id=app_id, - inputs={}, - response_mode="streaming", - conversation_id="", # 可选,留空则创建新对话 - files=[] - ) - - for data in response: - yield f"{json.dumps(data)}
" - - return Response(generator(), status=200, content_type="text/html") -``` - -### 调用 Workflow 接口 - -#### **入口** - -```python - self.session.app.workflow -``` - -#### **接口规范** - -```python - def invoke( - self, - app_id: str, - inputs: dict, - response_mode: Literal["streaming", "blocking"], - files: list, - ) -> Generator[dict, None, None] | dict: - pass -``` - -### 调用 Completion 接口 - -#### **入口** - -```python - self.session.app.completion -``` - -**接口规范** - -```python - def invoke( - self, - app_id: str, - inputs: dict, - response_mode: Literal["streaming", "blocking"], - files: list, - ) -> Generator[dict, None, None] | dict: - pass -``` - -## 相关资源 - -- [反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation) - 了解反向调用的根本概念 -- [反向调用 Model](/plugin-dev-zh/9242-reverse-invocation-model) - 了解如何调用平台内的模型能力 -- [反向调用 Tool](/plugin-dev-zh/9242-reverse-invocation-tool) - 了解如何调用其它插件 -- [开发 Slack Bot 插件](/plugin-dev-zh/0432-develop-a-slack-bot-plugin) - 使用反向调用的实际应用案例 -- [开发 Extension 插件](/plugin-dev-zh/9231-extension-plugin) - 学习如何开发扩展插件 - -{/* -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-zh/9242-reverse-invocation-app.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9242-reverse-invocation-tool.mdx b/plugin-dev-zh/9242-reverse-invocation-tool.mdx deleted file mode 100644 index 34b78cb2..00000000 --- a/plugin-dev-zh/9242-reverse-invocation-tool.mdx +++ /dev/null @@ -1,104 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: intermediate -standard_title: Reverse Invocation Tool -language: zh -title: Tool -description: 本文档详细介绍了插件如何反向调用Dify平台中的工具服务。内容涉及三种不同类型的工具调用方法:调用已安装的工具(Built-in Tool)、调用Workflow - as Tool以及调用自定义工具(Custom Tool)。每种调用方式都配有对应的入口和接口参数说明。 ---- - -反向调用 Tool 指的是插件能够调用 Dify 平台内的其它工具类型插件。如果你对反向调用的基本概念还不熟悉,请先阅读[反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation)。 - -当遇到以下需求时: - -* 某个工具类型插件已经实现好了一个功能,但效果未达预期,需要对数据进行二次加工。 -* 某个任务需要使用到爬虫,希望能够自由选择爬虫服务。 -* 需要集合多个工具的返回结果,但是通过 Workflow 应用不好处理。 - -此时需要在插件中调用其他已经实现好的工具,该工具可能是市场中的某个工具插件,可能是自主构建的 Workflow as a Tool,亦或是自定义工具。 - -上述需求可以通过调用插件的 `self.session.tool` 字段来实现。 - -### 调用已安装的工具 - -允许插件调用已安装在当前 Workspace 内的各个工具,其中也包含其它工具类型的插件。 - -**入口** - -```python - self.session.tool -``` - -**接口** - -```python - def invoke_builtin_tool( - self, provider: str, tool_name: str, parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - pass -``` - -其中 provider 为 plugin 的 ID 加上工具供应商名称,格式形如 `langgenius/google/google`,tool\_name 为具体的工具名称,`parameters` 为最后传递给该工具的参数。 - -### 调用 Workflow as Tool - -如需了解关于 Workflow as Tool 的更多说明,请参考[工具插件文档](/plugin-dev-zh/9223-tool)。 - -**入口** - -```python - self.session.tool -``` - -**接口** - -```python - def invoke_workflow_tool( - self, provider: str, tool_name: str, parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - pass -``` - -此时的 provider 为该 tool 的 ID,tool\_name 在创建该 tool 的时候会要求填写。 - -### 调用 Custom Tool - -**入口** - -```python - self.session.tool -``` - -**接口** - -```python - def invoke_api_tool( - self, provider: str, tool_name: str, parameters: dict[str, Any] - ) -> Generator[ToolInvokeMessage, None, None]: - pass -``` - -此时的 `provider` 为该 tool 的 ID,`tool_name` 为 OpenAPI 中的 `operation_id`,若不存在,即为 Dify 自动生成的 `tool_name`,可以在工具管理页中看到具体的名称。 - -## 相关资源 - -- [反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation) - 了解反向调用的根本概念 -- [反向调用 App](/plugin-dev-zh/9242-reverse-invocation-app) - 了解如何调用平台内的 App -- [反向调用 Model](/plugin-dev-zh/9242-reverse-invocation-model) - 了解如何调用平台内的模型能力 -- [工具插件开发指南](/plugin-dev-zh/0211-getting-started-dify-tool) - 学习如何开发工具插件 -- [高级工具插件](/plugin-dev-zh/9223-tool) - 了解 Workflow as 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-zh/9242-reverse-invocation-tool.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9243-customizable-model.mdx b/plugin-dev-zh/9243-customizable-model.mdx deleted file mode 100644 index 238a1d68..00000000 --- a/plugin-dev-zh/9243-customizable-model.mdx +++ /dev/null @@ -1,358 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: advanced -standard_title: Customizable Model -language: zh -title: 接入自定义模型 -description: 本文档详细介绍了如何在Dify中接入自定义模型,以Xinference模型为例。文档涉及创建模型供应商文件、根据模型类型编写对应代码、实现模型调用逻辑和异常处理及调试发布等完整流程。特别详细地说明了LLM调用、Token计算、凭证校验和参数生成等核心方法的实现。 ---- - -自定义模型指的是需要自行部署或配置的 LLM。本文将以 [Xinference 模型](https://inference.readthedocs.io/en/latest/)为例,演示如何在模型插件内接入自定义模型。 - -自定义模型默认包含模型类型和模型名称两个参数,无需在供应商 yaml 文件定义。 - -供应商配置文件无需实现 `validate_provider_credential`。Runtime 会根据用户选择的模型类型或模型名称,自动调用对应模型层的 `validate_credentials` 方法进行验证。 - -### 接入自定义模型插件 - -接入自定义模型分为以下步骤: - -1. **创建模型供应商文件** - - 明确自定义模型中所包含的模型类型。 -2. **根据模型类型创建代码文件** - - 根据模型的类型(如 `llm` 或 `text_embedding`)创建代码文件。确保每种模型类型有独立的逻辑分层,便于维护和扩展。 -3. **根据不同的模型模块,编写模型调用代码** - - 在对应的模型类型模块下,创建一个与模型类型同名的 Python 文件(例如 llm.py)。在文件中定义实现具体模型逻辑的类,该类应符合系统的模型接口规范。 -4. **调试插件** - - 为新增的供应商功能编写单元测试和集成测试,确保所有功能模块符合预期,并能够正常运行。 - -*** - -### 1. **创建模型供应商文件** - -在插件项目的 `/provider` 路径下,新建 `xinference.yaml` 文件。 - -`Xinference` 家族模型支持 `LLM``,Text Embedding` 和 `Rerank` 模型类型,因此需要在 `xinference.yaml` 文件中包含上述模型类型。 - -示例代码: - -```yaml {14-17} -provider: xinference # 确定供应商标识 -label: # 供应商展示名称,可设置 en_US 英文、zh_Hans 中文两种语言,zh_Hans 不设置将默认使用 en_US。 - en_US: Xorbits Inference -icon_small: # 小图标,可以参考其他供应商的图标,存储在对应供应商实现目录下的 _assets 目录,中英文策略同 label - en_US: icon_s_en.svg -icon_large: # 大图标 - en_US: icon_l_en.svg -help: # 帮助 - title: - en_US: How to deploy Xinference - zh_Hans: 如何部署 Xinference - url: - en_US: https://github.com/xorbitsai/inference -supported_model_types: # 支持的模型类型,Xinference 同时支持 LLM/Text Embedding/Rerank -- llm -- text-embedding -- rerank -configurate_methods: # Xinference 为本地部署的供应商,并且没有预定义模型,需要用什么模型需要根据 Xinference 的文档进行部署,因此此处的方法为自定义模型。 -- customizable-model -provider_credential_schema: - credential_form_schemas: -``` - -接着需要定义 `provider_credential_schema` 字段。`Xinference 支持` text-generation,embeddings 和 reranking 模型,示例代码如下: - -```yaml {10,14,17} -provider_credential_schema: - credential_form_schemas: - - variable: model_type - type: select - label: - en_US: Model type - zh_Hans: 模型类型 - required: true - options: - - value: text-generation - label: - en_US: Language Model - zh_Hans: 语言模型 - - value: embeddings - label: - en_US: Text Embedding - - value: reranking - label: - en_US: Rerank -``` - -Xinference 中的每个模型都需要定义名称 `model_name`。 - -```yaml - - variable: model_name - type: text-input - label: - en_US: Model name - zh_Hans: 模型名称 - required: true - placeholder: - zh_Hans: 填写模型名称 - en_US: Input model name -``` - -Xinference 模型需要使用者输入模型的本地部署地址,插件内需要提供允许填写 Xinference 模型的本地部署地址(server\_url)和模型 UID 的位置,示例代码如下: - -```yaml {1,10} - - variable: server_url - label: - zh_Hans: 服务器 URL - en_US: Server url - type: text-input - required: true - placeholder: - zh_Hans: 在此输入 Xinference 的服务器地址,如 https://example.com/xxx - en_US: Enter the url of your Xinference, for example https://example.com/xxx - - variable: model_uid - label: - zh_Hans: 模型 UID - en_US: Model uid - type: text-input - required: true - placeholder: - zh_Hans: 在此输入你的 Model UID - en_US: Enter the model uid -``` - -填写所有参数后即可完成自定义模型供应商 yaml 配置文件的创建。接下来需为配置文件内定义的模型添加具体的功能代码文件。 - -### 2. 编写模型代码 - -Xinference 模型供应商的模型类型包含 llm、rerank、speech2text、tts 类型,因此需要在 /models 路径下为每个模型类型创建独立的分组,并创建对应的功能代码文件。 - -下文将以 llm 类型为例,说明如何创建 `llm.py` 代码文件。创建代码时需创建一个 Xinference LLM 类,可以取名为 `XinferenceAILargeLanguageModel`,继承 `__base.large_language_model.LargeLanguageModel` 基类,实现以下几个方法: - -* **LLM 调用** - -LLM 调用的核心方法,同时支持流式和同步返回。 - -```python -def _invoke(self, model: str, credentials: dict, - prompt_messages: list[PromptMessage], model_parameters: dict, - tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None, - stream: bool = True, user: Optional[str] = None) \ - -> Union[LLMResult, Generator]: - """ - Invoke large language model - - :param model: model name - :param credentials: model credentials - :param prompt_messages: prompt messages - :param model_parameters: model parameters - :param tools: tools for tool calling - :param stop: stop words - :param stream: is stream response - :param user: unique user id - :return: full response or stream response chunk generator result - """ -``` - -实现代码时,需要注意使用两个函数来返回数据,分别用于处理同步返回和流式返回。 - -Python 会将函数中包含 `yield` 的关键字函数识别为生成器函数,返回的数据类型固定为 `Generator`,因此需要分别实现同步和流式返回,例如以下示例代码: - -> 该示例使用了简化参数,实际编写代码时需参考上文中的参数列表。 - -```python -def _invoke(self, stream: bool, **kwargs) \ - -> Union[LLMResult, Generator]: - if stream: - return self._handle_stream_response(**kwargs) - return self._handle_sync_response(**kwargs) - -def _handle_stream_response(self, **kwargs) -> Generator: - for chunk in response: - yield chunk -def _handle_sync_response(self, **kwargs) -> LLMResult: - return LLMResult(**response) -``` - -* **预计算输入 Tokens** - -如果模型未提供预计算 tokens 的接口,可以直接返回 0。 - -```python -def get_num_tokens(self, model: str, credentials: dict, prompt_messages: list[PromptMessage], - tools: Optional[list[PromptMessageTool]] = None) -> int: - """ - Get number of tokens for given prompt messages - - :param model: model name - :param credentials: model credentials - :param prompt_messages: prompt messages - :param tools: tools for tool calling - :return: - """ -``` - -在某些情况下,如果不想直接返回 0,可以使用 `self._get_num_tokens_by_gpt2(text: str)` 方法计算 tokens。该方法位于 `AIModel` 基类中,使用 GPT-2 的 Tokenizer 进行计算。但请注意,这是一个替代方案,计算结果可能存在一定误差。 - -* **模型凭据校验** - -与供应商凭据校验类似,这里针对单个模型进行校验。 - -```python -def validate_credentials(self, model: str, credentials: dict) -> None: - """ - Validate model credentials - - :param model: model name - :param credentials: model credentials - :return: - """ -``` - -* **模型参数 Schema** - -与[预定义模型类型](integrate-the-predefined-model.md)不同,由于未在 YAML 文件中预设模型所支持的参数,因此需要动态生成模型参数的 Schema。 - -例如,Xinference 支持 `max_tokens`、`temperature` 和 `top_p` 三种模型参数。然而一些供应商(例如 OpenLLM)会根据具体模型支持不同的参数。 - -举例来说,供应商 `OpenLLM` 的 A 模型支持 `top_k` 参数,而 B 模型则不支持 `top_k`。在该情况下,需要动态生成每个模型对应的参数 Schema,示例代码如下: - -```python - def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity | None: - """ - used to define customizable model schema - """ - rules = [ - ParameterRule( - name='temperature', type=ParameterType.FLOAT, - use_template='temperature', - label=I18nObject( - zh_Hans='温度', en_US='Temperature' - ) - ), - ParameterRule( - name='top_p', type=ParameterType.FLOAT, - use_template='top_p', - label=I18nObject( - zh_Hans='Top P', en_US='Top P' - ) - ), - ParameterRule( - name='max_tokens', type=ParameterType.INT, - use_template='max_tokens', - min=1, - default=512, - label=I18nObject( - zh_Hans='最大生成长度', en_US='Max Tokens' - ) - ) - ] - - # if model is A, add top_k to rules - if model == 'A': - rules.append( - ParameterRule( - name='top_k', type=ParameterType.INT, - use_template='top_k', - min=1, - default=50, - label=I18nObject( - zh_Hans='Top K', en_US='Top K' - ) - ) - ) - - """ - some NOT IMPORTANT code here - """ - - entity = AIModelEntity( - model=model, - label=I18nObject( - en_US=model - ), - fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, - model_type=model_type, - model_properties={ - ModelPropertyKey.MODE: ModelType.LLM, - }, - parameter_rules=rules - ) - - return entity -``` - -* **调用异常错误映射表** - -当模型调用异常时需要映射到 Runtime 指定的 `InvokeError` 类型,方便 Dify 针对不同错误做不同后续处理。 - -Runtime Errors: - -* `InvokeConnectionError` 调用连接错误 -* `InvokeServerUnavailableError` 调用服务方不可用 -* `InvokeRateLimitError` 调用达到限额 -* `InvokeAuthorizationError` 调用鉴权失败 -* `InvokeBadRequestError` 调用传参有误 - -```python -@property -def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: - """ - Map model invoke error to unified error - The key is the error type thrown to the caller - The value is the error type thrown by the model, - which needs to be converted into a unified error type for the caller. - - :return: Invoke error mapping - """ -``` - -如需了解更多接口方法,请参考[接口文档:Model](../../../schema-definition/model/)。 - -如需获取本文所涉及的完整代码文件,请访问 [GitHub 代码仓库](https://github.com/langgenius/dify-official-plugins/tree/main/models/xinference)。 - -### 3. 调试插件 - -插件开发完成后,接下来需测试插件是否可以正常运行。详细说明请参考: - -[debug-plugin.md](../../debug-plugin.md) - -### 4. 发布插件 - -如果想要将插件发布至 Dify Marketplace,请参考以下内容: - -[publish-to-dify-marketplace](../../../publish-plugins/publish-to-dify-marketplace/) - -### **探索更多** - -**快速开始:** - -* [开发 Extension 插件](../extension-plugin.md) -* [开发 Tool 插件](../tool-plugin.md) -* [Bundle 插件:将多个插件打包](../bundle.md) - -**插件接口文档:** - -* [Manifest](../../../schema-definition/manifest.md) 结构 -* [Endpoint](../../../schema-definition/endpoint.md) 详细定义 -* [反向调用 Dify 能力](../../../schema-definition/reverse-invocation-of-the-dify-service/) -* [工具](../../../schema-definition/tool.md) -* [模型](../../../schema-definition/model/) - -{/* -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-zh/9243-customizable-model.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9243-reverse-invocation-node.mdx b/plugin-dev-zh/9243-reverse-invocation-node.mdx deleted file mode 100644 index c9a99879..00000000 --- a/plugin-dev-zh/9243-reverse-invocation-node.mdx +++ /dev/null @@ -1,107 +0,0 @@ ---- -dimensions: - type: - primary: implementation - detail: advanced - level: advanced -standard_title: Reverse Invocation Node -language: zh -title: Node -description: 本文档介绍了插件如何反向调用Dify平台中的Chatflow/Workflow应用节点功能。内容主要涉及两种特殊节点的调用方法:参数提取器节点(ParameterExtractor)和问题分类节点(QuestionClassifier)。文档详细说明了这两种节点的调用入口、接口参数和用例代码。 ---- - -反向调用 Node 指的是插件能够访问 Dify 中 Chatflow/Workflow 应用内部分节点的能力。 - -`Workflow` 中的 `ParameterExtractor(参数提取器)`与 `QuestionClassifier(问题分类)`节点封装了较为复杂的 Prompt 与代码逻辑,可以通过 LLM 来完成许多硬编码难以解决的任务。插件能够调用这两个节点。 - -### 调用参数提取器节点; - -#### **入口** - -```python - self.session.workflow_node.parameter_extractor -``` - -#### **接口** - -```python - def invoke( - self, - parameters: list[ParameterConfig], - model: ModelConfig, - query: str, - instruction: str = "", - ) -> NodeResponse - pass -``` - -其中 `parameters` 是需要提取出的参数的列表,`model` 符合 `LLMModelConfig` 规范,`query` 为提取参数的源文本,`instruction` 为一些可能额外需要给到 LLM 的指令,`NodeResponse` 的结构请参考该[文档](../general-specifications#noderesponse)。 - -#### **用例** - -如果想要提取对话中的某个人名,可以参考以下代码: - -```python -from collections.abc import Generator -from dify_plugin.entities.tool import ToolInvokeMessage -from dify_plugin import Tool -from dify_plugin.entities.workflow_node import ModelConfig, ParameterConfig - -class ParameterExtractorTool(Tool): - def _invoke( - self, tool_parameters: dict - ) -> Generator[ToolInvokeMessage, None, None]: - response = self.session.workflow_node.parameter_extractor.invoke( - parameters=[ - ParameterConfig( - name="name", - description="name of the person", - required=True, - type="string", - ) - ], - model=ModelConfig( - provider="langgenius/openai/openai", - name="gpt-4o-mini", - completion_params={}, - ), - query="My name is John Doe", - instruction="Extract the name of the person", - ) - - yield self.create_text_message(response.outputs["name"]) -``` - -### 调用问题分类节点 - -#### **入口** - -```python - self.session.workflow_node.question_classifier -``` - -#### **接口** - -```python - def invoke( - self, - classes: list[ClassConfig], - model: ModelConfig, - query: str, - instruction: str = "", - ) -> NodeResponse: - pass -``` - -该接口参数与 `ParameterExtractor` 一致,最终的返回结果储存在 `NodeResponse.outputs['class_name']` 中。 - -{/* -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-zh/9243-reverse-invocation-node.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/9433-agent-strategy-plugin.mdx b/plugin-dev-zh/9433-agent-strategy-plugin.mdx deleted file mode 100644 index 32614c23..00000000 --- a/plugin-dev-zh/9433-agent-strategy-plugin.mdx +++ /dev/null @@ -1,1191 +0,0 @@ ---- -dimensions: - type: - primary: reference - detail: examples - level: advanced -standard_title: Agent Strategy Plugin -language: zh -title: Agent 策略插件 -description: 本文档详细介绍了如何开发Agent策略插件,从初始化插件模板到调用模型、调用工具、输出日志和打包发布的整个过程。文档提供了详尽的代码示例,包括如何实现帮助LLM执行推理或决策逻辑的自动化工具调用功能。 ---- - -Agent 策略插件能够帮助 LLM 执行推理或决策逻辑,包括工具选择、调用和结果处理,以更加自动化的方式处理问题。 - -本文将演示如何创建一个具备工具调用(Function Calling)能力,自动获取当前准确时间的插件。 - -### 前置准备 - -* Dify 插件脚手架工具 -* Python 环境,版本号 ≥ 3.12 - -关于如何准备插件开发的脚手架工具,详细说明请参考[初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools)。 - -**Tips**:在终端运行 `dify version` 命令,检查是否出现版本号以确认成功安装脚手架工具。 - -### 1. 初始化插件模板 - -运行以下命令,初始化 Agent 插件开发模板。 - -```bash -dify plugin init -``` - -按照页面提示,填写对应信息。参考以下代码中的备注信息,进行设置。 - -``` -➜ Dify Plugins Developing dify plugin init -Edit profile of the plugin -Plugin name (press Enter to next step): # 填写插件的名称 -Author (press Enter to next step): Author name # 填写插件作者 -Description (press Enter to next step): Description # 填写插件的描述 ---- -Select the language you want to use for plugin development, and press Enter to con -BTW, you need Python 3.12+ to develop the Plugin if you choose Python. --> python # 选择 Python 环境 - go (not supported yet) ---- -Based on the ability you want to extend, we have divided the Plugin into four type - -- Tool: It's a tool provider, but not only limited to tools, you can implement an -- Model: Just a model provider, extending others is not allowed. -- Extension: Other times, you may only need a simple http service to extend the fu -- Agent Strategy: Implement your own logics here, just by focusing on Agent itself - -What's more, we have provided the template for you, you can choose one of them b - tool --> agent-strategy # 选择 Agent 策略模板 - llm - text-embedding ---- -Configure the permissions of the plugin, use up and down to navigate, tab to sel -Backwards Invocation: -Tools: - Enabled: [✔] You can invoke tools inside Dify if it's enabled # 默认开启 -Models: - Enabled: [✔] You can invoke models inside Dify if it's enabled # 默认开启 - LLM: [✔] You can invoke LLM models inside Dify if it's enabled # 默认开启 - Text Embedding: [✘] You can invoke text embedding models inside Dify if it' - Rerank: [✘] You can invoke rerank models inside Dify if it's enabled -... -``` - -初始化插件模板后将生成一个代码文件夹,包含插件开发过程中所需的完整资源。熟悉 Agent 策略插件的整体代码结构有助于插件的开发过程。 - -```text -├── GUIDE.md # User guide and documentation -├── PRIVACY.md # Privacy policy and data handling guidelines -├── README.md # Project overview and setup instructions -├── _assets/ # Static assets directory -│ └── icon.svg # Agent strategy provider icon/logo -├── main.py # Main application entry point -├── manifest.yaml # Basic plugin configuration -├── provider/ # Provider configurations directory -│ └── basic_agent.yaml # Your agent provider settings -├── requirements.txt # Python dependencies list -└── strategies/ # Strategy implementation directory - ├── basic_agent.py # Basic agent strategy implementation - └── basic_agent.yaml # Basic agent strategy configuration -``` - -插件的功能代码集中在 `strategies/` 目录内。 - -### 2. 开发插件功能 - -Agent 策略插件的开发主要围绕以下两个文件展开: - -* 插件声明文件:`strategies/basic_agent.yaml` -* 插件功能代码:`strategies/basic_agent.py` - -#### 2.1 定义参数 - -要创建一个 Agent 插件,首先需要在 `strategies/basic_agent.yaml` 文件中定义插件所需的参数。这些参数决定了插件的核心功能,例如调用 LLM 模型和使用工具的能力。 - -建议优先配置以下四个基础参数: - -1. **model**:指定要调用的大语言模型(LLM),如 GPT-4、GPT-4o-mini 等。 - -2. **tools**:定义插件可以使用的工具列表,增强插件功能。 - -3. **query**:设置与模型交互的提示词或输入内容。 - -4. **maximum_iterations**:限制插件执行的最大迭代次数,避免过度计算。 - -示例代码: - -```yaml -identity: - name: basic_agent # the name of the agent_strategy - author: novice # the author of the agent_strategy - label: - en_US: BasicAgent # the engilish label of the agent_strategy -description: - en_US: BasicAgent # the english description of the agent_strategy -parameters: - - name: model # the name of the model parameter - type: model-selector # model-type - scope: tool-call&llm # the scope of the parameter - required: true - label: - en_US: Model - zh_Hans: 模型 - pt_BR: Model - - name: tools # the name of the tools parameter - type: array[tools] # the type of tool parameter - required: true - label: - en_US: Tools list - zh_Hans: 工具列表 - pt_BR: Tools list - - name: query # the name of the query parameter - type: string # the type of query parameter - required: true - label: - en_US: Query - zh_Hans: 查询 - pt_BR: Query - - name: maximum_iterations - type: number - required: false - default: 5 - label: - en_US: Maxium Iterations - zh_Hans: 最大迭代次数 - pt_BR: Maxium Iterations - max: 50 # if you set the max and min value, the display of the parameter will be a slider - min: 1 -extra: - python: - source: strategies/basic_agent.py - -``` - -完成参数配置后,插件将在自动生成相应的设置的使用页面,方便你进行直观、便捷的调整和使用。 - -![Agent 策略插件的使用页面](https://assets-docs.dify.ai/2025/01/d011e2eba4c37f07a9564067ba787df8.png) - -#### 2.2 获取参数并执行 - -当使用者在插件的使用页面完成基础的信息填写后,插件需要处理已填写的传入参数。因此需要先在 `strategies/basic_agent.py` 文件内定义 Agent 参数类供后续使用。 - -校验传入参数: - -```python -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -``` - -获取参数后,执行具体的业务逻辑: - -```python -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) -``` - -#### 2.3 调用模型 - -在 Agent 策略插件中,**调用模型**是核心执行逻辑之一。可以通过 SDK 提供的 `session.model.llm.invoke()` 方法高效地调用 LLM 模型,实现文本生成、对话处理等功能。 - -如果希望模型具备**调用工具**的能力,首先需要确保模型能够输出符合工具调用格式的输入参数。也就是说,模型需要根据用户指令生成符合工具接口要求的参数。 - -构造以下参数: - -* model:模型信息 -* prompt\_messages:提示词 -* tools:工具信息(Function Calling 相关) -* stop:停止符 -* stream:是否支持流式输出 - -方法定义示例代码: - -```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:... -``` - -要查看完整的功能实现,请参考模型调用[示例代码](agent-strategy-plugin.md#diao-yong-gong-ju-1)。 - -该代码实现了以下功能:用户输入指令后,Agent 策略插件会自动调用 LLM,根据生成结果构建并传递工具调用所需的参数,使模型能够灵活调度已接入的工具,高效完成复杂任务。 - -![生成工具的请求参数](https://assets-docs.dify.ai/2025/01/01e32c2d77150213c7c929b3cceb4dae.png) - -#### 2.4 为模型添加记忆 - -当使用 Agent 插件调用模型时,为模型添加记忆功能能够极大提升对话体验。通过记忆功能,模型可以理解完整的对话上下文,实现连贯的交互体验和精准的工具调用。 - -具体实现步骤: - -1. 配置记忆功能 - -在 Agent 插件的 YAML 配置文件 `strategies/agent.yaml` 中添加 `history-messages` 特性: - -```yaml -identity: - name: basic_agent # Agent策略名称 - author: novice # 作者 - label: - en_US: BasicAgent # 英文标签 -description: - en_US: BasicAgent # 英文描述 -features: - - history-messages # 启用历史消息功能 -... -``` - -2. 启用记忆设置 - -修改插件配置文件并重启后,你将在节点配置界面中看到 **记忆** 开关。点击右侧的开关按钮,启用记忆功能。 - -启用后,你可以通过 **窗口大小** 滑块调整记忆窗口,它决定了模型能够“记住”多少之前的对话内容。 - -3. 调试历史消息 - -添加以下代码,查看历史消息内容: - -```python -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - print(f"history_messages: {params.model.history_prompt_messages}") - ... -``` - -![History messages](https://assets-docs.dify.ai/2025/04/cb11fae7981dae431966f83fa99f1dfb.png) - -控制台将显示类似如下输出: - -``` -history_messages: [] -history_messages: [UserPromptMessage(role=, content='hello, my name is novice', name=None), AssistantPromptMessage(role=, content='Hello, Novice! How can I assist you today?', name=None, tool_calls=[])] -``` - -4. 将历史消息集成到模型调用 - -最后,修改模型调用代码,将历史消息拼接到当前查询: - -```python -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - # 添加历史消息 - prompt_messages=params.model.history_prompt_messages - + [UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - ... -``` - -5. 效果验证 - -添加加记忆功能后,模型能够基于历史对话进行回复。在下图示例中,模型成功地记住了之前对话中提及的用户名称,实现了对话的连贯性。 - -![Outcome](https://assets-docs.dify.ai/2025/04/6bdd3d2c6a455ae8e463bd6abab5c3a4.png) - -#### 2.5 调用工具 - -填写工具参数后,需赋予 Agent 策略插件实际调用工具的能力。可以通过 SDK 中的`session.tool.invoke()` 函数进行工具调用。 - -构造以下参数: - -* provider:工具提供商 -* tool\_name:工具名称 -* parameters:输入参数 - -方法定义示例代码: - -```python - def invoke( - self, - provider_type: ToolProviderType, - provider: str, - tool_name: str, - parameters: dict[str, Any], - ) -> Generator[ToolInvokeMessage, None, None]:... -``` - -若希望通过 LLM 直接生成参数完成工具调用,请参考以下工具调用的示例代码: - -```python -tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} -) -for tool_call_id, tool_call_name, tool_call_args in tool_calls: - tool_instance = tool_instances[tool_call_name] - 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}, - ) -``` - -如需查看完整的功能代码,请阅读调用工具[示例代码](agent-strategy-plugin.md#diao-yong-gong-ju-1)。 - -实现这部分的功能代码后,Agent 策略插件将具备自动 Function Calling 的能力,例如自动获取当前时间: - -![工具调用](https://assets-docs.dify.ai/2025/01/80e5de8acc2b0ed00524e490fd611ff5.png) - -#### 2.6 日志创建 - -在 **Agent 策略插件**中,通常需要执行多轮操作才能完成复杂任务。记录每轮操作的执行结果对于开发者来说非常重要,有助于追踪 Agent 的执行过程、分析每一步的决策依据,从而更好地评估和优化策略效果。 - -为了实现这一功能,可以利用 SDK 中的 `create_log_message` 和 `finish_log_message` 方法记录日志。这种方式不仅可以在模型调用前后实时记录操作状态,还能帮助开发者快速定位问题。 - -场景示例: - -* 在模型调用之前,记录一条“开始调用模型”的日志,帮助开发者明确任务执行进度。 -* 在模型调用成功后,记录一条“调用成功”的日志,方便追踪模型响应的完整性。 - -```python -model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - ) -yield model_log -self.session.model.llm.invoke(...) -yield self.finish_log_message( - log=model_log, - data={ - "output": response, - "tool_name": tool_call_names, - "tool_input": tool_call_inputs, - }, - metadata={ - "started_at": model_started_at, - "finished_at": time.perf_counter(), - "elapsed_time": time.perf_counter() - model_started_at, - "provider": params.model.provider, - }, -) -``` - -设置完成后,工作流日志将输出执行结果: - -![Agent 输出执行结果](https://assets-docs.dify.ai/2025/01/96516388a4fb1da9cea85fc1804ff377.png) - -在 Agent 执行的过程中,有可能会产生多轮日志。若日志能具备层级结构将有助于开发者查看。通过在日志记录时传入 parent 参数,不同轮次的日志可以形成上下级关系,使日志展示更加清晰、易于追踪。 - -**引用方法:** - -```python -function_call_round_log = self.create_log_message( - label="Function Call Round1 ", - data={}, - metadata={}, -) -yield function_call_round_log - -model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - # add parent log - parent=function_call_round_log, -) -yield model_log -``` - -### 插件功能示例代码 - - - -#### 调用模型 - -以下代码将演示如何赋予 Agent 策略插件调用模型的能力: - -```python -import json -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - -#### 调用工具 - -以下代码展示了如何为 Agent 策略插件实现模型调用并向工具发送规范化请求。 - -```python -import json -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - -#### 完整功能代码示例 - -包含**调用模型、调用工具**以及**输出多轮日志功能**的完整插件代码示例: - -```python -import json -import time -from collections.abc import Generator -from typing import Any, cast - -from dify_plugin.entities.agent import AgentInvokeMessage -from dify_plugin.entities.model.llm import LLMModelConfig, LLMResult, LLMResultChunk -from dify_plugin.entities.model.message import ( - PromptMessageTool, - UserPromptMessage, -) -from dify_plugin.entities.tool import ToolInvokeMessage, ToolParameter, ToolProviderType -from dify_plugin.interfaces.agent import AgentModelConfig, AgentStrategy, ToolEntity -from pydantic import BaseModel - -class BasicParams(BaseModel): - maximum_iterations: int - model: AgentModelConfig - tools: list[ToolEntity] - query: str - -class BasicAgentAgentStrategy(AgentStrategy): - def _invoke(self, parameters: dict[str, Any]) -> Generator[AgentInvokeMessage]: - params = BasicParams(**parameters) - function_call_round_log = self.create_log_message( - label="Function Call Round1 ", - data={}, - metadata={}, - ) - yield function_call_round_log - model_started_at = time.perf_counter() - model_log = self.create_log_message( - label=f"{params.model.model} Thought", - data={}, - metadata={"start_at": model_started_at, "provider": params.model.provider}, - status=ToolInvokeMessage.LogMessage.LogStatus.START, - parent=function_call_round_log, - ) - yield model_log - chunks: Generator[LLMResultChunk, None, None] | LLMResult = ( - self.session.model.llm.invoke( - model_config=LLMModelConfig(**params.model.model_dump(mode="json")), - prompt_messages=[UserPromptMessage(content=params.query)], - tools=[ - self._convert_tool_to_prompt_message_tool(tool) - for tool in params.tools - ], - stop=params.model.completion_params.get("stop", []) - if params.model.completion_params - else [], - stream=True, - ) - ) - response = "" - tool_calls = [] - tool_instances = ( - {tool.identity.name: tool for tool in params.tools} if params.tools else {} - ) - tool_call_names = "" - tool_call_inputs = "" - for chunk in chunks: - # check if there is any tool call - if self.check_tool_calls(chunk): - tool_calls = self.extract_tool_calls(chunk) - tool_call_names = ";".join([tool_call[1] for tool_call in tool_calls]) - try: - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls}, - ensure_ascii=False, - ) - except json.JSONDecodeError: - # ensure ascii to avoid encoding error - tool_call_inputs = json.dumps( - {tool_call[1]: tool_call[2] for tool_call in tool_calls} - ) - print(tool_call_names, tool_call_inputs) - if chunk.delta.message and chunk.delta.message.content: - if isinstance(chunk.delta.message.content, list): - for content in chunk.delta.message.content: - response += content.data - print(content.data, end="", flush=True) - else: - response += str(chunk.delta.message.content) - print(str(chunk.delta.message.content), end="", flush=True) - - if chunk.delta.usage: - # usage of the model - usage = chunk.delta.usage - - yield self.finish_log_message( - log=model_log, - data={ - "output": response, - "tool_name": tool_call_names, - "tool_input": tool_call_inputs, - }, - metadata={ - "started_at": model_started_at, - "finished_at": time.perf_counter(), - "elapsed_time": time.perf_counter() - model_started_at, - "provider": params.model.provider, - }, - ) - yield self.create_text_message( - text=f"{response or json.dumps(tool_calls, ensure_ascii=False)}\n" - ) - result = "" - for tool_call_id, tool_call_name, tool_call_args in tool_calls: - 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}, - ) - if not tool_instance: - tool_invoke_responses = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": f"there is not a tool named {tool_call_name}", - } - else: - # invoke tool - 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}, - ) - result = "" - for tool_invoke_response in tool_invoke_responses: - if tool_invoke_response.type == ToolInvokeMessage.MessageType.TEXT: - result += cast( - ToolInvokeMessage.TextMessage, tool_invoke_response.message - ).text - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.LINK - ): - result += ( - f"result link: {cast(ToolInvokeMessage.TextMessage, tool_invoke_response.message).text}." - + " please tell user to check it." - ) - elif tool_invoke_response.type in { - ToolInvokeMessage.MessageType.IMAGE_LINK, - ToolInvokeMessage.MessageType.IMAGE, - }: - result += ( - "image has been created and sent to user already, " - + "you do not need to create it, just tell the user to check it now." - ) - elif ( - tool_invoke_response.type == ToolInvokeMessage.MessageType.JSON - ): - text = json.dumps( - cast( - ToolInvokeMessage.JsonMessage, - tool_invoke_response.message, - ).json_object, - ensure_ascii=False, - ) - result += f"tool response: {text}." - else: - result += f"tool response: {tool_invoke_response.message!r}." - - tool_response = { - "tool_call_id": tool_call_id, - "tool_call_name": tool_call_name, - "tool_response": result, - } - yield self.create_text_message(result) - - 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 - - def check_tool_calls(self, llm_result_chunk: LLMResultChunk) -> bool: - """ - Check if there is any tool call in llm result chunk - """ - return bool(llm_result_chunk.delta.message.tool_calls) - - def extract_tool_calls( - self, llm_result_chunk: LLMResultChunk - ) -> list[tuple[str, str, dict[str, Any]]]: - """ - Extract tool calls from llm result chunk - - Returns: - List[Tuple[str, str, Dict[str, Any]]]: [(tool_call_id, tool_call_name, tool_call_args)] - """ - tool_calls = [] - for prompt_message in llm_result_chunk.delta.message.tool_calls: - args = {} - if prompt_message.function.arguments != "": - args = json.loads(prompt_message.function.arguments) - - tool_calls.append( - ( - prompt_message.id, - prompt_message.function.name, - args, - ) - ) - - return tool_calls -``` - - - -### 3. 调试插件 - -配置插件的声明文件与功能代码后,在插件的目录内运行 `python -m main` 命令重启插件。接下来需测试插件是否可以正常运行。Dify 提供远程调试方式,前往[“插件管理”](https://cloud.dify.ai/plugins)获取调试 Key 和远程服务器地址。 - -![Image](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) - -回到插件项目,拷贝 `.env.example` 文件并重命名为 `.env`,将获取的远程服务器地址和调试 Key 等信息填入至 `REMOTE_INSTALL_HOST` 与 `REMOTE_INSTALL_KEY` 参数内。 - -```bash -INSTALL_METHOD=remote -REMOTE_INSTALL_URL=debug.dify.ai:5003 -REMOTE_INSTALL_KEY=********-****-****-****-************ -``` - -运行 `python -m main` 命令启动插件。在插件页即可看到该插件已被安装至 Workspace 内。其他团队成员也可以访问该插件。 - -![访问插件](https://assets-docs.dify.ai/2025/01/c82ec0202e5bf914b36e06c796398dd6.png) - -### 打包插件(可选) - -确认插件能够正常运行后,可以通过以下命令行工具打包并命名插件。运行以后你可以在当前文件夹发现 `google.difypkg` 文件,该文件为最终的插件包。 - -```bash -# 将 ./basic_agent 替换为插件项目的实际路径 -dify plugin package ./basic_agent/ -``` - -恭喜,你已完成一个工具类型插件的完整开发、调试与打包过程! - -### 发布插件(可选) - -现在可以将它上传至 [Dify Plugins 代码仓库](https://github.com/langgenius/dify-plugins)来发布你的插件了!上传前,请确保插件已遵循[插件发布规范](https://docs.dify.ai/zh-hans/plugins/publish-plugins/publish-to-dify-marketplace)。审核通过后,代码将合并至主分支并自动上线至 [Dify Marketplace](https://marketplace.dify.ai/)。 - -### 探索更多 - -复杂任务往往需要多轮思考和多次工具调用。为了实现更智能的任务处理,通常采用循环执行的策略:**模型调用 → 工具调用**,直到任务完成或达到设定的最大迭代次数。 - -在这个过程中,提示词(Prompt)管理变得尤为重要。为了高效地组织和动态调整模型输入,建议参考插件内 Function Calling 功能的[完整实现代码](https://github.com/langgenius/dify-official-plugins/blob/main/agent-strategies/cot_agent/strategies/function_calling.py),了解如何通过标准化的方式来让模型调用外部工具并处理返回结果。 - -## 相关资源 - -- [Agent 插件开发基础](/plugin-dev-zh/9232-agent) - 了解 Agent 策略插件的基本概念 -- [插件开发基础概念](/plugin-dev-zh/0111-getting-started-dify-plugin) - 了解插件开发的整体架构 -- [初始化开发工具](/plugin-dev-zh/0221-initialize-development-tools) - 学习如何搭建开发环境 -- [反向调用 Model](/plugin-dev-zh/9242-reverse-invocation-model) - 了解如何调用平台内的模型能力 -- [反向调用 Tool](/plugin-dev-zh/9242-reverse-invocation-tool) - 了解如何调用其它插件 -- [发布插件概述](/plugin-dev-zh/0321-release-overview) - 学习插件发布流程 - -{/* -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-zh/9433-agent-strategy-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - diff --git a/plugin-dev-zh/sync/check_mapping_consistency.py b/plugin-dev-zh/sync/check_mapping_consistency.py deleted file mode 100644 index dc25956c..00000000 --- a/plugin-dev-zh/sync/check_mapping_consistency.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python3 -""" -文件映射一致性检查工具 -对比 JSON 映射记录与实际文件情况,确保映射准确无误 -""" - -import json -import os -from pathlib import Path -from typing import Set, Dict - -# ANSI 颜色代码 -GREEN = '\033[92m' -YELLOW = '\033[93m' -RED = '\033[91m' -BLUE = '\033[94m' -CYAN = '\033[96m' -RESET = '\033[0m' - - -class MappingValidator: - def __init__(self, json_file: str = "plugin_mappings.json"): - self.base_dir = Path(os.path.dirname(os.path.dirname( - os.path.dirname(os.path.abspath(__file__))))) - self.json_file = self.base_dir / "plugin-dev-zh" / "sync" / json_file - self.plugin_dir = self.base_dir / "zh-hans" / "plugins" - self.dev_dir = self.base_dir / "plugin-dev-zh" - self.mappings = [] - self.load_mappings() - - def load_mappings(self): - """加载映射文件""" - try: - with open(self.json_file, 'r', encoding='utf-8') as f: - data = json.load(f) - self.mappings = data.get('mappings', []) - except FileNotFoundError: - print(f"{RED}错误: 找不到文件 {self.json_file}{RESET}") - self.mappings = [] - except json.JSONDecodeError: - print(f"{RED}错误: JSON 文件格式错误{RESET}") - self.mappings = [] - - def count_mdx_files(self, directory: Path) -> int: - """递归统计目录中的 .mdx 文件数量""" - count = 0 - for file in directory.rglob('*.mdx'): - count += 1 - return count - - def get_actual_file_paths(self, directory: Path) -> Set[str]: - """获取目录中所有 .mdx 文件的相对路径""" - files = set() - for file in directory.rglob('*.mdx'): - relative_path = str(file.relative_to(self.base_dir)) - files.add(relative_path) - return files - - def calculate_mapping_stats(self) -> Dict: - """计算映射统计""" - total = len(self.mappings) - plugin_only = sum(1 for m in self.mappings if m.get( - 'plugin_path') and not m.get('dev_path')) - dev_only = sum(1 for m in self.mappings if m.get( - 'dev_path') and not m.get('plugin_path')) - complete = sum(1 for m in self.mappings if m.get( - 'plugin_path') and m.get('dev_path')) - - # 计算预期的文件数 - expected_plugin_files = total - dev_only # 总数 - 仅开发 = 插件文件数 - expected_dev_files = total - plugin_only # 总数 - 仅插件 = 开发文件数 - - return { - 'total_mappings': total, - 'plugin_only': plugin_only, - 'dev_only': dev_only, - 'complete_mappings': complete, - 'expected_plugin_files': expected_plugin_files, - 'expected_dev_files': expected_dev_files - } - - def validate(self): - """执行验证""" - print(f"\n{CYAN}=== 插件文档映射一致性检查工具 ==={RESET}") - print(f"{CYAN}功能:对比 JSON 映射记录与实际文件,确保映射准确无遗漏{RESET}\n") - - # 统计实际文件数 - actual_plugin_count = self.count_mdx_files(self.plugin_dir) - actual_dev_count = self.count_mdx_files(self.dev_dir) - - # 获取映射统计 - stats = self.calculate_mapping_stats() - - # 显示映射统计 - print(f"{BLUE}【JSON 映射统计情况】{RESET}") - print(f" 总映射记录数: {stats['total_mappings']} 条") - print(f" 完整映射(两边都有): {stats['complete_mappings']} 条") - print(f" 仅插件文档: {stats['plugin_only']} 条") - print(f" 仅开发文档: {stats['dev_only']} 条\n") - - # 显示预期vs实际 - print(f"{BLUE}【运行时文件计数情况】{RESET}") - print(" 📁 插件文件夹 (zh-hans/plugins):") - print(f" JSON 映射预期: {stats['expected_plugin_files']} 个文件") - print(f" 实际扫描结果: {actual_plugin_count} 个 .mdx 文件") - if actual_plugin_count == stats['expected_plugin_files']: - print(f" 状态: {GREEN}✓ 完全一致{RESET}") - else: - diff = actual_plugin_count - stats['expected_plugin_files'] - print(f" 状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}") - - print("\n 📁 开发文件夹 (plugin-dev-zh):") - print(f" JSON 映射预期: {stats['expected_dev_files']} 个文件") - print(f" 实际扫描结果: {actual_dev_count} 个 .mdx 文件") - if actual_dev_count == stats['expected_dev_files']: - print(f" 状态: {GREEN}✓ 完全一致{RESET}") - else: - diff = actual_dev_count - stats['expected_dev_files'] - print(f" 状态: {RED}✗ 存在差异 (实际比预期{diff:+d}){RESET}") - - # 显示计算公式说明 - print(f"\n{BLUE}【预期文件数计算说明】{RESET}") - print( - f" 插件预期数 = 总映射数({stats['total_mappings']}) - 仅开发数({stats['dev_only']}) = {stats['expected_plugin_files']}") - print( - f" 开发预期数 = 总映射数({stats['total_mappings']}) - 仅插件数({stats['plugin_only']}) = {stats['expected_dev_files']}") - - # 如果有差异,找出具体文件 - if actual_plugin_count != stats['expected_plugin_files'] or actual_dev_count != stats['expected_dev_files']: - self.find_discrepancies() - else: - print(f"\n{GREEN}✅ 检查完成:所有文件映射完全一致!{RESET}") - - def find_discrepancies(self): - """找出映射和实际文件的差异""" - print(f"\n{YELLOW}【差异详细分析】{RESET}\n") - - # 获取实际文件路径 - actual_plugin_files = self.get_actual_file_paths(self.plugin_dir) - actual_dev_files = self.get_actual_file_paths(self.dev_dir) - - # 获取映射中的文件路径 - mapped_plugin_files = set(m['plugin_path'] - for m in self.mappings if m.get('plugin_path')) - mapped_dev_files = set(m['dev_path'] - for m in self.mappings if m.get('dev_path')) - - # 找出未映射的文件 - unmapped_plugin_files = actual_plugin_files - mapped_plugin_files - unmapped_dev_files = actual_dev_files - mapped_dev_files - - # 找出映射中但不存在的文件 - nonexistent_plugin_files = mapped_plugin_files - actual_plugin_files - nonexistent_dev_files = mapped_dev_files - actual_dev_files - - has_issues = False - - if unmapped_plugin_files: - has_issues = True - print(f"{RED}❗ 实际存在但 JSON 中未记录的插件文件:{RESET}") - for file in sorted(unmapped_plugin_files): - print(f" - {file}") - - if unmapped_dev_files: - has_issues = True - print(f"\n{RED}❗ 实际存在但 JSON 中未记录的开发文件:{RESET}") - for file in sorted(unmapped_dev_files): - print(f" - {file}") - - if nonexistent_plugin_files: - has_issues = True - print(f"\n{RED}❗ JSON 中记录但实际不存在的插件文件:{RESET}") - for file in sorted(nonexistent_plugin_files): - print(f" - {file}") - - if nonexistent_dev_files: - has_issues = True - print(f"\n{RED}❗ JSON 中记录但实际不存在的开发文件:{RESET}") - for file in sorted(nonexistent_dev_files): - print(f" - {file}") - - if has_issues: - print(f"\n{YELLOW}💡 建议:运行 sync_mdx_to_json.py 同步文件到映射{RESET}") - else: - print(f"{GREEN}未发现具体文件差异,检查完成{RESET}") - - -def main(): - """主函数""" - validator = MappingValidator() - validator.validate() - - -if __name__ == "__main__": - main() diff --git a/plugin-dev-zh/sync/plugin_mappings.json b/plugin-dev-zh/sync/plugin_mappings.json deleted file mode 100644 index d8ef022d..00000000 --- a/plugin-dev-zh/sync/plugin_mappings.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "mappings": [ - { - "plugin_path": "zh-hans/plugins/introduction.mdx", - "dev_path": null, - "verified": true - }, - - { - "plugin_path": "zh-hans/plugins/manage-plugins.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/README.mdx", - "dev_path": "plugin-dev-zh/0111-getting-started-dify-plugin.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-zh/0211-getting-started-new-model.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/faq.mdx", - "dev_path": "plugin-dev-zh/0331-faq.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/tool-plugin.mdx", - "dev_path": "plugin-dev-zh/0222-tool-plugin.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/model-plugin/README.mdx", - "dev_path": "plugin-dev-zh/0411-model-plugin-introduction.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/initialize-development-tools.mdx", - "dev_path": "plugin-dev-zh/0221-initialize-development-tools.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/model-plugin/create-model-providers.mdx", - "dev_path": "plugin-dev-zh/0222-creating-new-model-provider.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/README.mdx", - "dev_path": "plugin-dev-zh/0321-release-overview.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/package-plugin-file-and-publish.mdx", - "dev_path": "plugin-dev-zh/0322-release-by-file.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/publish-to-dify-marketplace/README.mdx", - "dev_path": "plugin-dev-zh/0322-release-to-dify-marketplace.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/publish-plugin-on-personal-github-repo.mdx", - "dev_path": "plugin-dev-zh/0322-release-to-individual-github-repo.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/publish-to-dify-marketplace/plugin-developer-guidelines.mdx", - "dev_path": "plugin-dev-zh/0312-contributor-covenant-code-of-conduct.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/publish-to-dify-marketplace/plugin-privacy-protection-guidelines.mdx", - "dev_path": "plugin-dev-zh/0312-privacy-protection-guidelines.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/general-specifications.mdx", - "dev_path": "plugin-dev-zh/0411-general-specifications.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/model/model-designing-rules.mdx", - "dev_path": "plugin-dev-zh/0411-model-designing-rules.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/persistent-storage.mdx", - "dev_path": "plugin-dev-zh/0411-persistent-storage-kv.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/manifest.mdx", - "dev_path": "plugin-dev-zh/0411-plugin-info-by-manifest.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/debug-plugin.mdx", - "dev_path": "plugin-dev-zh/0411-remote-debug-a-plugin.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/tool.mdx", - "dev_path": "plugin-dev-zh/0411-tool.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/model/model-schema.mdx", - "dev_path": "plugin-dev-zh/0412-model-schema.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/best-practice/develop-a-slack-bot-plugin.mdx", - "dev_path": "plugin-dev-zh/0432-develop-a-slack-bot-plugin.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/endpoint.mdx", - "dev_path": "plugin-dev-zh/0432-endpoint.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/extension-plugin.mdx", - "dev_path": "plugin-dev-zh/9231-extension-plugin.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/agent.mdx", - "dev_path": "plugin-dev-zh/9232-agent.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/bundle.mdx", - "dev_path": "plugin-dev-zh/9241-bundle.mdx", - "verified": true, - "sync": "内容高度相同,已确认同步。" - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/reverse-invocation-of-the-dify-service/README.mdx", - "dev_path": "plugin-dev-zh/9241-reverse-invocation.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/reverse-invocation-of-the-dify-service/app.mdx", - "dev_path": "plugin-dev-zh/9242-reverse-invocation-app.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/reverse-invocation-of-the-dify-service/model.mdx", - "dev_path": "plugin-dev-zh/9242-reverse-invocation-model.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/reverse-invocation-of-the-dify-service/tool.mdx", - "dev_path": "plugin-dev-zh/9242-reverse-invocation-tool.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/model-plugin/customizable-model.mdx", - "dev_path": "plugin-dev-zh/9243-customizable-model.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/reverse-invocation-of-the-dify-service/node.mdx", - "dev_path": "plugin-dev-zh/9243-reverse-invocation-node.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/agent-strategy-plugin.mdx", - "dev_path": "plugin-dev-zh/9433-agent-strategy-plugin.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/install-plugins.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/best-practice/how-to-print-strings-to-logs-for-debugging.mdx", - "dev_path": "plugin-dev-zh/0222-debugging-logs.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/best-practice/how-to-use-mcp-zapier.mdx", - "dev_path": null, - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/model-plugin/integrate-the-predefined-model.mdx", - "dev_path": "plugin-dev-zh/0222-creating-new-model-provider-extra.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/plugin-auto-publish-pr.mdx", - "dev_path": "plugin-dev-zh/0321-plugin-auto-publish-pr.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/publish-plugins/signing-plugins-for-third-party-signature-verification.mdx", - "dev_path": "plugin-dev-zh/0312-third-party-signature-verification.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 需要进行适配" - }, - { - "plugin_path": "zh-hans/plugins/best-practice/README.mdx", - "dev_path": "plugin-dev-zh/0431-example-overview-and-index.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/model/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - }, - { - "plugin_path": "zh-hans/plugins/schema-definition/README.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-zh/0131-cheatsheet.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-zh/0211-getting-started-dify-tool.mdx", - "verified": true - }, - { - "plugin_path": null, - "dev_path": "plugin-dev-zh/0211-getting-started-by-prompt.mdx", - "verified": true - }, - { - "plugin_path": "zh-hans/plugins/quick-start/develop-plugins/tool-cha-jian.mdx", - "dev_path": null, - "verified": true, - "sync": "TODO: 移除即可" - } - ] -} diff --git a/plugin-dev-zh/sync/sync_all_mdx_files_to_json.py b/plugin-dev-zh/sync/sync_all_mdx_files_to_json.py deleted file mode 100644 index b3035399..00000000 --- a/plugin-dev-zh/sync/sync_all_mdx_files_to_json.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env python3 -""" -同步 MDX 文件到映射 -确保所有 mdx 文件都在 JSON 映射中,并去除 metadata -""" - -import json -import os -from pathlib import Path -from typing import Set, Dict - - -class MdxSyncManager: - def __init__(self, json_file: str = "plugin_mappings.json"): - self.base_dir = Path(os.path.dirname( - os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # Corrected base_dir to project root - self.json_file = self.base_dir / "plugin-dev-zh" / "sync" / json_file # Corrected json_file path - self.plugin_dir = self.base_dir / "zh-hans" / "plugins" - self.dev_dir = self.base_dir / "plugin-dev-zh" - self.mappings = [] - self.load_mappings() - - def load_mappings(self): - """加载现有映射""" - try: - with open(self.json_file, 'r', encoding='utf-8') as f: - data = json.load(f) - # 只加载 mappings,忽略 metadata - self.mappings = data.get('mappings', []) - except FileNotFoundError: - print(f"创建新的映射文件: {self.json_file}") - self.mappings = [] - except json.JSONDecodeError: - print("JSON 文件格式错误,创建新文件") - self.mappings = [] - - def save_mappings(self): - """保存映射(不包含 metadata)""" - # 只保存 mappings,不保存 metadata - data = { - 'mappings': self.mappings - } - with open(self.json_file, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=2) - - def get_mdx_files(self, directory: Path) -> Set[str]: - """获取目录中所有 mdx 文件的相对路径""" - mdx_files = set() - for file in directory.rglob('*.mdx'): - relative_path = str(file.relative_to(self.base_dir)) - mdx_files.add(relative_path) - return mdx_files - - def get_existing_paths(self) -> Dict[str, Dict]: - """获取现有映射中的所有路径""" - existing = {} - for mapping in self.mappings: - if mapping['plugin_path']: - existing[mapping['plugin_path']] = mapping - if mapping['dev_path']: - existing[mapping['dev_path']] = mapping - return existing - - def find_matching_mapping(self, path: str) -> Dict: - """查找与给定路径匹配的映射""" - for mapping in self.mappings: - if mapping['plugin_path'] == path or mapping['dev_path'] == path: - return mapping - return None - - def sync_files(self): - """同步文件到映射""" - # 获取所有 mdx 文件 - plugin_files = self.get_mdx_files(self.plugin_dir) - dev_files = self.get_mdx_files(self.dev_dir) - - # 获取现有映射中的路径 - existing_paths = self.get_existing_paths() - - added_count = 0 - - # 处理 plugin 文件夹中的文件 - for plugin_file in plugin_files: - if plugin_file not in existing_paths: - # 查找是否已经在某个映射的 dev_path 中 - existing_mapping = self.find_matching_mapping(plugin_file) - if not existing_mapping: - # 创建新映射 - new_mapping = { - 'plugin_path': plugin_file, - 'dev_path': None, - 'verified': False - } - self.mappings.append(new_mapping) - added_count += 1 - print(f"添加新映射: {plugin_file}") - - # 处理 dev 文件夹中的文件 - for dev_file in dev_files: - if dev_file not in existing_paths: - # 查找是否已经在某个映射的 plugin_path 中 - existing_mapping = self.find_matching_mapping(dev_file) - if not existing_mapping: - # 尝试找到可能对应的 plugin 文件 - matching_plugin = self.find_potential_match( - dev_file, plugin_files) - if matching_plugin: - # 更新现有映射 - for mapping in self.mappings: - if mapping['plugin_path'] == matching_plugin and not mapping['dev_path']: - mapping['dev_path'] = dev_file - print(f"更新映射: {matching_plugin} <- {dev_file}") - break - else: - # 创建新映射 - new_mapping = { - 'plugin_path': None, - 'dev_path': dev_file, - 'verified': False - } - self.mappings.append(new_mapping) - added_count += 1 - print(f"添加新映射: {dev_file}") - - # 清理重复项 - self.remove_duplicates() - - if added_count > 0: - self.save_mappings() - print(f"\n已添加 {added_count} 个新映射") - else: - print("\n所有文件都已在映射中") - - def find_potential_match(self, dev_file: str, plugin_files: Set[str]) -> str: - """尝试找到可能匹配的 plugin 文件""" - # 提取文件名(去除路径和语言后缀) - dev_filename = os.path.basename(dev_file) - if dev_filename.endswith('.mdx'): - base_name = dev_filename[:-7] # 去除 .mdx - else: - base_name = dev_filename[:-4] # 去除 .mdx - - # 查找相似的 plugin 文件 - for plugin_file in plugin_files: - plugin_filename = os.path.basename(plugin_file) - if base_name in plugin_filename: - return plugin_file - - return None - - def remove_duplicates(self): - """去除重复的映射""" - unique_mappings = [] - seen = set() - - for mapping in self.mappings: - # 创建唯一键 - key = (mapping.get('plugin_path'), mapping.get('dev_path')) - if key not in seen: - seen.add(key) - unique_mappings.append(mapping) - - self.mappings = unique_mappings - - def show_status(self): - """显示当前状态""" - plugin_count = sum(1 for m in self.mappings if m['plugin_path']) - dev_count = sum(1 for m in self.mappings if m['dev_path']) - both_count = sum( - 1 for m in self.mappings if m['plugin_path'] and m['dev_path']) - - print("\n当前映射状态:") - print(f"总映射数: {len(self.mappings)}") - print(f"Plugin 文件: {plugin_count}") - print(f"Dev 文件: {dev_count}") - print(f"完整映射: {both_count}") - - -def main(): - """主函数""" - manager = MdxSyncManager() - - print("开始同步 MDX 文件到映射...") - manager.sync_files() - manager.show_status() - - print("\n同步完成!") - - -if __name__ == "__main__": - main() diff --git a/plugin-dev-zh/sync/view_file_mappings.py b/plugin-dev-zh/sync/view_file_mappings.py deleted file mode 100644 index d9dd4c76..00000000 --- a/plugin-dev-zh/sync/view_file_mappings.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -""" -简单的插件映射查看器 -快速查看文件映射关系,支持在 VS Code 中点击打开 -""" - -import json -import os -from pathlib import Path - -# ANSI 颜色代码 -GREEN = '\033[92m' -YELLOW = '\033[93m' -RED = '\033[91m' -BLUE = '\033[94m' -RESET = '\033[0m' - -# 新增符号常量 -CHECK_MARK = f"{GREEN}✅{RESET}" -CROSS_MARK = f"{RED}❌{RESET}" -EMPTY_MARK = f"{YELLOW}❎{RESET}" - -def load_mappings(json_file="plugin_mappings.json"): - """加载映射文件""" - base_dir = Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) # 修改 base_dir 指向项目根目录 - json_path = base_dir / "plugin-dev-zh" / "sync" / json_file # 修正 json_path - - try: - with open(json_path, 'r', encoding='utf-8') as f: - return json.load(f) - except FileNotFoundError: - print(f"{RED}错误: 找不到文件 {json_path}{RESET}") - return None - except json.JSONDecodeError: - print(f"{RED}错误: JSON 文件格式错误{RESET}") - return None - -def calculate_statistics(mappings): - """动态计算统计信息""" - total = len(mappings) - verified = sum(1 for m in mappings if m.get('verified', False)) - pending = total - verified - - # 额外统计 - plugin_only = sum(1 for m in mappings if m.get('plugin_path') and not m.get('dev_path')) - dev_only = sum(1 for m in mappings if m.get('dev_path') and not m.get('plugin_path')) - complete = sum(1 for m in mappings if m.get('plugin_path') and m.get('dev_path')) - - return { - 'total_mappings': total, - 'verified_count': verified, - 'pending_verification': pending, - 'plugin_only': plugin_only, - 'dev_only': dev_only, - 'complete_mappings': complete - } - -def show_mappings(): - """显示所有映射关系""" - data = load_mappings() - if not data: - return - - mappings = data.get('mappings', []) - stats = calculate_statistics(mappings) - - print(f"\n{BLUE}插件文档映射关系{RESET}") - print(f"总计: {stats['total_mappings']} | " - f"已验证: {GREEN}{stats['verified_count']}{RESET} | " - f"待验证: {YELLOW}{stats['pending_verification']}{RESET}") - print(f"完整映射: {stats['complete_mappings']} | " - f"仅插件: {stats['plugin_only']} | " - f"仅开发: {stats['dev_only']}") # Removed trailing \n here - - print("\n路径 | 验证 | 同步细节\n") # Added newlines for spacing - - separator_line1 = "-" * 56 - separator_line2 = "*" * 56 - - for idx, mapping in enumerate(mappings, 1): - plugin_path = mapping.get('plugin_path') - dev_path = mapping.get('dev_path') - verified = mapping.get('verified', False) - sync_info = mapping.get('sync', '').strip() - - # 打印分隔符 - print(separator_line1) - print(separator_line2) - print(separator_line1) - print() # 在分隔符后添加空行 - - # 显示 Help 路径 - if plugin_path: - print(f"Help: {plugin_path}") - else: - print(f"Help: {EMPTY_MARK}") - - # 显示 Dev 路径 - if dev_path: - print(f"Dev: {dev_path}") - else: - print(f"Dev: {EMPTY_MARK}") - - # 显示 Verify 状态和 sync_info - verify_symbol = CHECK_MARK if verified else CROSS_MARK - print(f"Verify: {verify_symbol}") - if sync_info: - print(sync_info) - # No "else" needed here as per example, empty sync_info means just the symbol - -def main(): - """主函数""" - show_mappings() - - print(f"\n{BLUE}提示:{RESET} 在 VS Code 中,你可以使用 Cmd+点击 路径来快速打开文件") - print(f"{BLUE}命令:{RESET} python view_file_mappings.py") - -if __name__ == "__main__": - main() diff --git a/scripts/contributing_in_page.py b/scripts/contributing_in_page.py index cce2ee4c..72ea06be 100644 --- a/scripts/contributing_in_page.py +++ b/scripts/contributing_in_page.py @@ -54,7 +54,7 @@ It will be automatically generated by the script.
""" - elif language == "jp": + elif language == "ja": contributing_section = f""" {{/* Contributing Section diff --git a/tools/translate/README.md b/tools/translate/README.md index c1be67df..7019e261 100644 --- a/tools/translate/README.md +++ b/tools/translate/README.md @@ -44,8 +44,7 @@ Automatically detects structural changes in `docs.json`: ## Language Directories -- **General docs**: `en/` (source) → `zh/`, `ja/` (targets) -- **Plugin dev docs**: `plugin-dev-en/` → `plugin-dev-zh/`, `plugin-dev-ja/` +- **Latest docs**: `en/` (source) → `zh/`, `ja/` (targets) - **Versioned docs**: `versions/{version}/en-us/` → `versions/{version}/zh-zh/`, `versions/{version}/ja/` Configuration in `tools/translate/config.json`. diff --git a/tools/translate/config.json b/tools/translate/config.json index 1254d8d1..54698b00 100644 --- a/tools/translate/config.json +++ b/tools/translate/config.json @@ -53,6 +53,14 @@ }, "label_translations": { + "Use Dify": { + "zh": "使用 Dify", + "ja": "Dify を使う" + }, + "Self Host": { + "zh": "自托管", + "ja": "セルフホスティング" + }, "Getting Started": { "zh": "快速开始", "ja": "はじめに" @@ -134,12 +142,44 @@ "ja": "トラブルシューティング" }, "API Reference": { - "zh": "API 参考", - "ja": "API リファレンス" + "zh": "API 文档", + "ja": "APIアクセス" }, - "Develop": { - "zh": "开发", - "ja": "開発" + "Develop Plugin": { + "zh": "开发插件", + "ja": "プラグイン開発" + }, + "Features & Specs": { + "zh": "特性与规范", + "ja": "特性と仕様" + }, + "Plugin Types": { + "zh": "插件类型", + "ja": "プラグインタイプ" + }, + "Advanced Development": { + "zh": "高级开发", + "ja": "高度な開発" + }, + "Reverse Calling": { + "zh": "反向调用", + "ja": "リバース呼び出し" + }, + "Development Guides & Walkthroughs": { + "zh": "开发指南与示例", + "ja": "開発ガイドとサンプル" + }, + "Publishing": { + "zh": "发布", + "ja": "公開" + }, + "Standards": { + "zh": "标准", + "ja": "標準" + }, + "Marketplace Listing": { + "zh": "上架插件市场", + "ja": "マーケットプレイスリスト" } } } diff --git a/tools/translate/main.py b/tools/translate/main.py index 006e5b3f..9ff3adb7 100644 --- a/tools/translate/main.py +++ b/tools/translate/main.py @@ -37,22 +37,6 @@ def build_docs_structure(): "Japanese": "ja" } - # Plugin dev paths from config - if TRANSLATION_CONFIG and 'plugin_dev_paths' in TRANSLATION_CONFIG: - plugin_dev = {} - for lang_code, path in TRANSLATION_CONFIG['plugin_dev_paths'].items(): - if lang_code in TRANSLATION_CONFIG['languages']: - lang_name = TRANSLATION_CONFIG['languages'][lang_code]['name'] - plugin_dev[lang_name] = path - structure["plugin_dev"] = plugin_dev - else: - # Fallback for backward compatibility - structure["plugin_dev"] = { - "English": "plugin-dev-en", - "Chinese": "plugin-dev-zh", - "Japanese": "plugin-dev-ja" - } - # Versioned docs from config if TRANSLATION_CONFIG and "versioned_docs" in TRANSLATION_CONFIG: for version_key, version_paths in TRANSLATION_CONFIG["versioned_docs"].items(): diff --git a/tools/translate/sync_and_translate.py b/tools/translate/sync_and_translate.py index a322676a..e4b3a0e0 100644 --- a/tools/translate/sync_and_translate.py +++ b/tools/translate/sync_and_translate.py @@ -381,7 +381,7 @@ class DocsSynchronizer: # Handle renamed files for old_path, new_path in changes["renamed"]: - if self.is_english_doc_file(old_path) or self.is_english_doc_file(new_path): + if self.is_source_doc_file(old_path) or self.is_source_doc_file(new_path): for target_lang in self.target_languages: old_target = self.convert_path_to_target_language(old_path, target_lang) new_target = self.convert_path_to_target_language(new_path, target_lang) @@ -449,7 +449,7 @@ class DocsSynchronizer: # Handle renamed files that need translation for old_path, new_path in changes["renamed"]: - if self.is_english_doc_file(new_path): + if self.is_source_doc_file(new_path): for target_lang in self.target_languages: target_path = self.convert_path_to_target_language(new_path, target_lang) # Renamed files treated as new diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx new file mode 100644 index 00000000..de7a53bd --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx @@ -0,0 +1,164 @@ +--- +dimensions: + type: + primary: conceptual + detail: architecture + level: beginner +standard_title: Cheatsheet +language: en +title: Dify 插件开发速查表 +description: Dify 插件开发的综合参考指南,包括环境要求、安装方法、开发流程、插件类别和类型、常用代码片段以及常见问题解决方案。适合开发者快速查阅和参考。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet)。 + +### 环境要求 + +- Python 版本 ≥ 3.12 +- Dify 插件脚手架工具 (dify-plugin-daemon) + +> 了解更多:[初始化开发工具](/zh/develop-plugin/getting-started/cli) + +### 获取 Dify 插件开发包 + +[Dify Plugin CLI](https://github.com/langgenius/dify-plugin-daemon/releases) + +#### 不同平台的安装方法 + +**macOS [Brew](https://github.com/langgenius/homebrew-dify)(全局安装):** + +```bash +brew tap langgenius/dify +brew install dify +``` + +安装完成后,打开一个新的终端窗口并输入 `dify version` 命令。如果输出版本信息,则表示安装成功。 + +**macOS ARM(M 系列芯片):** + +```bash +# Download dify-plugin-darwin-arm64 +chmod +x dify-plugin-darwin-arm64 +./dify-plugin-darwin-arm64 version +``` + +**macOS Intel:** + +```bash +# Download dify-plugin-darwin-amd64 +chmod +x dify-plugin-darwin-amd64 +./dify-plugin-darwin-amd64 version +``` + +**Linux:** + +```bash +# Download dify-plugin-linux-amd64 +chmod +x dify-plugin-linux-amd64 +./dify-plugin-linux-amd64 version +``` + +**全局安装(推荐):** + +```bash +# Rename and move to system path +# Example (macOS ARM) +mv dify-plugin-darwin-arm64 dify +sudo mv dify /usr/local/bin/ +dify version +``` + +### 运行开发包 + +这里我们以 `dify` 为例。如果你使用的是本地安装方式,请相应地替换命令,例如 `./dify-plugin-darwin-arm64 plugin init`。 + +### 插件开发流程 + +#### 1. 创建新插件 + +```bash +./dify plugin init +``` + +按照提示完成基本的插件信息配置 + +> 了解更多:[Dify 插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) + +#### 2. 以开发模式运行 + +配置 `.env` 文件,然后在插件目录中运行以下命令: + +```bash +python -m main +``` + +> 了解更多:[远程调试插件](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) + +#### 4. 打包和部署 + +打包插件: + +```bash +cd .. +dify plugin package ./yourapp +``` + +> 了解更多:[发布概览](/zh/develop-plugin/publishing/marketplace-listing/release-overview) + +### 插件类别 + +#### 工具标签 + +类别 `tag` [class ToolLabelEnum(Enum)](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/dify_plugin/entities/tool.py) + +```python +class ToolLabelEnum(Enum): + SEARCH = "search" + IMAGE = "image" + VIDEOS = "videos" + WEATHER = "weather" + FINANCE = "finance" + DESIGN = "design" + TRAVEL = "travel" + SOCIAL = "social" + NEWS = "news" + MEDICAL = "medical" + PRODUCTIVITY = "productivity" + EDUCATION = "education" + BUSINESS = "business" + ENTERTAINMENT = "entertainment" + UTILITIES = "utilities" + OTHER = "other" +``` + +### 插件类型参考 + +Dify 支持开发多种类型的插件: + +- **工具插件**:集成第三方 API 和服务 + > 了解更多:[Dify 插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) + +- **模型插件**:集成 AI 模型 + > 了解更多:[模型插件](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules),[快速集成新模型](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) + +- **智能体策略插件**:自定义智能体思考和决策策略 + > 了解更多:[智能体策略插件](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) + +- **扩展插件**:扩展 Dify 平台功能,如 Endpoints 和 WebAPP + > 了解更多:[扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) + +- **数据源插件**:作为知识库管道的文档数据源和起点 + > 了解更多:[数据源插件](/zh/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin) + +- **触发器插件**:在第三方事件发生时自动触发工作流执行 + > 了解更多:[触发器插件](/zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin) + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/cheatsheet.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx new file mode 100644 index 00000000..b5330e4b --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx @@ -0,0 +1,462 @@ +--- +dimensions: + type: + primary: implementation + detail: standard + level: intermediate +standard_title: Model Provider Plugin +language: en +title: 模型供应商插件 +description: 本综合指南提供了创建模型供应商插件的详细说明,涵盖项目初始化、目录结构组织、模型配置方法、编写供应商代码以及实现模型集成,并附有核心 API 实现的详细示例。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider)。 + +### 前提条件 + +* [Dify CLI](/zh/develop-plugin/getting-started/cli) +* 基本的 Python 编程技能和面向对象编程的理解 +* 熟悉您想要集成的模型供应商的 API 文档 + +## 步骤 1:创建和配置新插件项目 + +### 初始化项目 + +```bash +dify plugin init +``` + +### 选择模型插件模板 + +从可用选项中选择 `LLM` 类型的插件模板。此模板提供了完整的模型集成代码结构。 + +![Plugin type: llm](https://assets-docs.dify.ai/2024/12/8efe646e9174164b9edbf658b5934b86.png) + +### 配置插件权限 + +对于模型供应商插件,配置以下基本权限: + +* **Models** - 模型操作的基础权限 +* **LLM** - 大语言模型功能的权限 +* **Storage** - 文件操作的权限(如果需要) + +![Model Plugin Permission](https://assets-docs.dify.ai/2024/12/10f3b3ee6c03a1215309f13d712455d4.png) + +### 目录结构概述 + +初始化后,您的插件项目将具有类似以下的目录结构(假设供应商名为 `my_provider`,支持 LLM 和 Embedding): + +```bash +models/my_provider/ +├── models # 模型实现和配置目录 +│ ├── llm # LLM 类型 +│ │ ├── _position.yaml (可选,控制排序) +│ │ ├── model1.yaml # 特定模型的配置 +│ │ └── llm.py # LLM 实现逻辑 +│ └── text_embedding # Embedding 类型 +│ ├── _position.yaml +│ ├── embedding-model.yaml +│ └── text_embedding.py +├── provider # 供应商级代码目录 +│ └── my_provider.py # 供应商凭证验证 +└── manifest.yaml # 插件清单文件 +``` + +## 步骤 2:了解模型配置方法 + +Dify 支持两种模型配置方法,决定用户如何与您供应商的模型交互: + +### 预定义模型(`predefined-model`) + +这些模型只需要统一的供应商凭证即可使用。一旦用户为供应商配置了 API 密钥或其他身份验证详情,他们就可以立即访问所有预定义模型。 + +**示例:** `OpenAI` 供应商提供预定义模型,如 `gpt-3.5-turbo-0125` 和 `gpt-4o-2024-05-13`。用户只需配置一次 OpenAI API 密钥即可访问所有这些模型。 + +### 自定义模型(`customizable-model`) + +这些模型需要为每个特定模型实例进行额外配置。当模型需要供应商级凭证之外的单独参数时,这种方法很有用。 + +**示例:** `Xinference` 同时支持 LLM 和 Text Embedding,但每个模型都有唯一的 **model_uid**。用户必须为他们想要使用的每个模型单独配置此 model_uid。 + +这些配置方法**可以在单个供应商中共存**。例如,供应商可能提供一些预定义模型,同时也允许用户添加具有特定配置的自定义模型。 + +## 步骤 3:创建模型供应商文件 + +创建新的模型供应商涉及两个主要组件: + +1. **供应商配置 YAML 文件** - 定义供应商的基本信息、支持的模型类型和凭证要求 +2. **供应商类实现** - 实现身份验证验证和其他供应商级功能 + +*** + +### 3.1 创建模型供应商配置文件 + +供应商配置在 YAML 文件中定义,声明供应商的基本信息、支持的模型类型、配置方法和凭证规则。此文件将放置在插件项目的根目录中。 + +以下是带注释的 `anthropic.yaml` 配置文件示例: + +```yaml +# 基本供应商标识 +provider: anthropic # 供应商 ID(必须唯一) +label: + en_US: Anthropic # UI 中的显示名称 +description: + en_US: Anthropic's powerful models, such as Claude 3. + zh_Hans: Anthropic 的强大模型,例如 Claude 3。 +icon_small: + en_US: icon_s_en.svg # 供应商的小图标(在选择 UI 中显示) +icon_large: + en_US: icon_l_en.svg # 大图标(在详情视图中显示) +background: "#F0F0EB" # UI 中供应商的背景颜色 + +# 用户帮助信息 +help: + title: + en_US: Get your API Key from Anthropic + zh_Hans: 从 Anthropic 获取 API Key + url: + en_US: https://console.anthropic.com/account/keys + +# 支持的模型类型和配置方法 +supported_model_types: + - llm # 此供应商提供 LLM 模型 +configurate_methods: + - predefined-model # 使用预定义模型方法 + +# 供应商级凭证表单定义 +provider_credential_schema: + credential_form_schemas: + - variable: anthropic_api_key # API 密钥的变量名 + label: + en_US: API Key + type: secret-input # 敏感数据的安全输入 + required: true + placeholder: + zh_Hans: 在此输入你的 API Key + en_US: Enter your API Key + - variable: anthropic_api_url + label: + en_US: API URL + type: text-input # 常规文本输入 + required: false + placeholder: + zh_Hans: 在此输入你的 API URL + en_US: Enter your API URL + +# 模型配置 +models: + llm: # LLM 类型模型的配置 + predefined: + - "models/llm/*.yaml" # 定位模型配置文件的模式 + position: "models/llm/_position.yaml" # 定义显示顺序的文件 + +# 实现文件位置 +extra: + python: + provider_source: provider/anthropic.py # 供应商类实现 + model_sources: + - "models/llm/llm.py" # 模型实现文件 +``` + +### 自定义模型配置 + +如果您的供应商支持自定义模型,您需要添加 `model_credential_schema` 部分来定义用户需要为每个单独模型配置的额外字段。这对于支持微调模型或需要模型特定参数的供应商很常见。 + +以下是来自 OpenAI 供应商的示例: + +```yaml +model_credential_schema: + model: # 微调模型名称字段 + label: + en_US: Model Name + zh_Hans: 模型名称 + placeholder: + en_US: Enter your model name + zh_Hans: 输入模型名称 + credential_form_schemas: + - variable: openai_api_key + label: + en_US: API Key + type: secret-input + required: true + placeholder: + zh_Hans: 在此输入你的 API Key + en_US: Enter your API Key + - variable: openai_organization + label: + zh_Hans: 组织 ID + en_US: Organization + type: text-input + required: false + placeholder: + zh_Hans: 在此输入你的组织 ID + en_US: Enter your Organization ID + # 根据需要添加其他字段... +``` + +有关完整的模型供应商 YAML 规范,请参阅[模型 Schema](/zh/develop-plugin/features-and-specs/plugin-types/model-schema) 文档。 + +### 3.2 编写模型供应商代码 + +接下来,为您的供应商类实现创建一个 Python 文件。此文件应放置在 `/provider` 目录中,名称与您的供应商匹配(例如 `anthropic.py`)。 + +供应商类必须继承自 `ModelProvider` 并至少实现 `validate_provider_credentials` 方法: + +```python +import logging +from dify_plugin.entities.model import ModelType +from dify_plugin.errors.model import CredentialsValidateFailedError +from dify_plugin import ModelProvider + +logger = logging.getLogger(__name__) + + +class AnthropicProvider(ModelProvider): + def validate_provider_credentials(self, credentials: dict) -> None: + """ + Validate provider credentials by testing them against the API. + + This method should attempt to make a simple API call to verify + that the credentials are valid. + + :param credentials: Provider credentials as defined in the YAML schema + :raises CredentialsValidateFailedError: If validation fails + """ + try: + # Get an instance of the LLM model type and use it to validate credentials + model_instance = self.get_model_instance(ModelType.LLM) + model_instance.validate_credentials( + model="claude-3-opus-20240229", + credentials=credentials + ) + except CredentialsValidateFailedError as ex: + # Pass through credential validation errors + raise ex + except Exception as ex: + # Log and re-raise other exceptions + logger.exception(f"{self.get_provider_schema().provider} credentials validate failed") + raise ex +``` + +`validate_provider_credentials` 方法非常重要,因为每当用户尝试在 Dify 中保存其供应商凭证时都会调用它。它应该: + +1. 尝试通过进行简单的 API 调用来验证凭证 +2. 如果验证成功则静默返回 +3. 如果验证失败则抛出带有有用消息的 `CredentialsValidateFailedError` + +#### 对于自定义模型供应商 + +对于专门使用自定义模型的供应商(每个模型都需要自己的配置),您可以实现一个更简单的供应商类。例如,对于 `Xinference`: + +```python +from dify_plugin import ModelProvider + +class XinferenceProvider(ModelProvider): + def validate_provider_credentials(self, credentials: dict) -> None: + """ + For custom-only model providers, validation happens at the model level. + This method exists to satisfy the abstract base class requirement. + """ + pass +``` + +## 步骤 4:实现模型特定代码 + +设置好供应商后,您需要实现模型特定代码来处理您支持的每种模型类型的 API 调用。这涉及: + +1. 为每个特定模型创建模型配置 YAML 文件 +2. 实现处理 API 通信的模型类型类 + +有关这些步骤的详细说明,请参阅: + +* [模型设计规则](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - 集成预定义模型的标准 +* [模型 Schema](/zh/develop-plugin/features-and-specs/plugin-types/model-schema) - 模型配置文件的标准 + +### 4.1 定义模型配置(YAML) + +对于每个特定模型,在相应的模型类型目录中创建一个 YAML 文件(例如 `models/llm/`)来定义其属性、参数和功能。 + +**示例(`claude-3-5-sonnet-20240620.yaml`):** + +```yaml +model: claude-3-5-sonnet-20240620 # 模型的 API 标识符 +label: + en_US: claude-3-5-sonnet-20240620 # UI 中的显示名称 +model_type: llm # 必须与目录类型匹配 +features: # 特殊功能 + - agent-thought + - vision + - tool-call + - stream-tool-call + - document +model_properties: # 固有模型属性 + mode: chat # "chat" 或 "completion" + context_size: 200000 # 最大上下文窗口 +parameter_rules: # 用户可调整的参数 + - name: temperature + use_template: temperature # 引用预定义模板 + - name: top_p + use_template: top_p + - name: max_tokens + use_template: max_tokens + required: true + default: 8192 + min: 1 + max: 8192 +pricing: # 可选的定价信息 + input: '3.00' + output: '15.00' + unit: '0.000001' # 每百万令牌 + currency: USD +``` + +### 4.2 实现模型调用代码(Python) + +为您支持的每种模型类型创建一个 Python 文件(例如 `models/llm/` 目录中的 `llm.py`)。此类将处理 API 通信、参数转换和结果格式化。 + +以下是 LLM 的实现结构示例: + +```python +import logging +from typing import Union, Generator, Optional, List +from dify_plugin.provider_kits.llm import LargeLanguageModel # Base class +from dify_plugin.provider_kits.llm import LLMResult, LLMResultChunk, LLMUsage # Result classes +from dify_plugin.provider_kits.llm import PromptMessage, PromptMessageTool # Message classes +from dify_plugin.errors.provider_error import InvokeError, InvokeAuthorizationError # Error classes + +logger = logging.getLogger(__name__) + +class MyProviderLargeLanguageModel(LargeLanguageModel): + def _invoke(self, model: str, credentials: dict, prompt_messages: List[PromptMessage], + model_parameters: dict, tools: Optional[List[PromptMessageTool]] = None, + stop: Optional[List[str]] = None, stream: bool = True, + user: Optional[str] = None) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]: + """ + Core method for invoking the model API. + + Parameters: + model: The model identifier to call + credentials: Authentication credentials + prompt_messages: List of messages to send + model_parameters: Parameters like temperature, max_tokens + tools: Optional tool definitions for function calling + stop: Optional list of stop sequences + stream: Whether to stream responses (True) or return complete response (False) + user: Optional user identifier for API tracking + + Returns: + If stream=True: Generator yielding LLMResultChunk objects + If stream=False: Complete LLMResult object + """ + # Prepare API request parameters + api_params = self._prepare_api_params( + credentials, model_parameters, prompt_messages, tools, stop + ) + + try: + # Call appropriate helper method based on streaming preference + if stream: + return self._invoke_stream(model, api_params, user) + else: + return self._invoke_sync(model, api_params, user) + except Exception as e: + # Handle and map errors + self._handle_api_error(e) + + def _invoke_stream(self, model: str, api_params: dict, user: Optional[str]) -> Generator[LLMResultChunk, None, None]: + """Helper method for streaming API calls""" + # Implementation details for streaming calls + pass + + def _invoke_sync(self, model: str, api_params: dict, user: Optional[str]) -> LLMResult: + """Helper method for synchronous API calls""" + # Implementation details for synchronous calls + pass + + def validate_credentials(self, model: str, credentials: dict) -> None: + """ + Validate that the credentials work for this specific model. + Called when a user tries to add or modify credentials. + """ + # Implementation for credential validation + pass + + def get_num_tokens(self, model: str, credentials: dict, + prompt_messages: List[PromptMessage], + tools: Optional[List[PromptMessageTool]] = None) -> int: + """ + Estimate the number of tokens for given input. + Optional but recommended for accurate cost estimation. + """ + # Implementation for token counting + pass + + @property + def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + Define mapping from vendor-specific exceptions to Dify standard exceptions. + This helps standardize error handling across different providers. + """ + return { + InvokeAuthorizationError: [ + # List vendor-specific auth errors here + ], + # Other error mappings + } +``` + +要实现的最重要方法是 `_invoke`,它处理核心 API 通信。此方法应该: + +1. 将 Dify 的标准化输入转换为供应商 API 所需的格式 +2. 使用适当的错误处理进行 API 调用 +3. 将 API 响应转换为 Dify 的标准化输出格式 +4. 处理流式和非流式模式 + +## 步骤 5:调试和测试您的插件 + +Dify 提供远程调试功能,允许您在开发期间测试插件: + +1. 在您的 Dify 实例中,转到"插件管理"并点击"调试插件"以获取您的调试密钥和服务器地址 +2. 在 `.env` 文件中使用这些值配置您的本地环境: + +```dotenv +INSTALL_METHOD=remote +REMOTE_INSTALL_HOST= +REMOTE_INSTALL_PORT=5003 +REMOTE_INSTALL_KEY=****-****-****-****-**** +``` + +3. 使用 `python -m main` 在本地运行您的插件并在 Dify 中测试它 + +## 步骤 6:打包和发布 + +当您的插件准备就绪时: + +1. 使用脚手架工具打包: + ```bash + dify plugin package models/ + ``` + +2. 在提交之前在本地测试打包的插件 + +3. 向 [Dify 官方插件仓库](https://github.com/langgenius/dify-official-plugins) 提交拉取请求 + +有关发布流程的更多详情,请参阅[发布概述](/zh/develop-plugin/publishing/marketplace-listing/release-overview)。 + +## 参考资源 + +- [快速集成新模型](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 如何向现有供应商添加新模型 +- [插件开发基本概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin) - 返回插件开发入门指南 +- [模型 Schema](/zh/develop-plugin/features-and-specs/plugin-types/model-schema) - 了解详细的模型配置规范 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 了解插件清单文件配置 +- [Dify 插件 SDK 参考](https://github.com/langgenius/dify-plugin-sdks) - 查找基类、数据结构和错误类型 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx new file mode 100644 index 00000000..315e9b3c --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx @@ -0,0 +1,458 @@ +--- +title: "数据源插件" +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin)。 + +数据源插件是 Dify 1.9.0 中引入的一种新型插件。在知识库管道中,它们作为文档数据源和整个管道的起点。 + +本文介绍如何开发数据源插件,涵盖插件架构、代码示例和调试方法,帮助你快速开发和发布数据源插件。 + +## 前置条件 + +在继续阅读之前,请确保你对知识库管道有基本了解,并具备一些插件开发知识。你可以在这里找到相关信息: + +- [步骤 2:知识库管道编排](/zhguides/knowledge-base/knowledge-pipeline/knowledge-pipeline-orchestration) +- [Dify 插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) + +## **数据源插件类型** + +Dify 支持三种类型的数据源插件:网页爬虫、在线文档和在线云盘。在实现插件代码时,提供插件功能的类必须继承自特定的数据源类。三种插件类型分别对应不同的父类。 + + + 要了解如何通过继承父类来实现插件功能,请参阅 [Dify 插件开发:Hello World 指南 - 4.4 实现工具逻辑](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin#4-4-implementing-tool-logic)。 + + +每种数据源插件类型支持多个数据源。例如: + +- **网页爬虫**:Jina Reader、FireCrawl +- **在线文档**:Notion、Confluence、GitHub +- **在线云盘**:OneDrive、Google Drive、Box、AWS S3、腾讯 COS + +数据源类型和数据源插件类型之间的关系如下图所示。 + +![](/images/data_source_type.png) + +## 开发数据源插件 + +### 创建数据源插件 + +你可以使用脚手架命令行工具,通过选择 `datasource` 类型来创建数据源插件。完成设置后,命令行工具将自动生成插件项目代码。 + +```powershell +dify plugin init +``` + +![](/images/datasource_plugin_init.png) + + + 通常,数据源插件不需要使用 Dify 平台的其他功能,因此不需要额外的权限。 + + +#### 数据源插件结构 + +数据源插件由三个主要部分组成: + +- `manifest.yaml` 文件:描述插件的基本信息。 +- `provider` 目录:包含插件提供者的描述和认证实现代码。 +- `datasources` 目录:包含从数据源获取数据的描述和核心逻辑。 + +``` +├── _assets +│ └── icon.svg +├── datasources +│ ├── your_datasource.py +│ └── your_datasource.yaml +├── main.py +├── manifest.yaml +├── PRIVACY.md +├── provider +│ ├── your_datasource.py +│ └── your_datasource.yaml +├── README.md +└── requirements.txt +``` + +#### 设置正确的版本和标签 + +- 在 `manifest.yaml` 文件中,按如下方式设置最低支持的 Dify 版本: + + ```yaml + minimum_dify_version: 1.9.0 + ``` +- 在 `manifest.yaml` 文件中,添加以下标签以在 Dify Marketplace 的数据源类别下显示插件: + + ```yaml + tags: + - rag + ``` +- 在 `requirements.txt` 文件中,按如下方式设置数据源插件开发所使用的插件 SDK 版本: + + ```yaml + dify-plugin>=0.5.0,<0.6.0 + ``` + +### 添加数据源提供者 + +#### 创建提供者 YAML 文件 + +提供者 YAML 文件的内容与工具插件的基本相同,只有以下两点不同: + +```yaml +# 指定数据源插件的提供者类型:online_drive、online_document 或 website_crawl +provider_type: online_drive # online_document, website_crawl + +# 指定数据源 +datasources: + - datasources/PluginName.yaml +``` + + + 有关创建提供者 YAML 文件的更多信息,请参阅 [Dify 插件开发:Hello World 指南 - 4.3 配置提供者凭证](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin#4-3-configuring-provider-credentials)。 + + + + 数据源插件支持通过 OAuth 2.0 或 API Key 进行认证。 + + 要配置 OAuth,请参阅[为你的工具插件添加 OAuth 支持](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth)。 + + +#### 创建提供者代码文件 + +- 使用 API Key 认证模式时,数据源插件的提供者代码文件与工具插件相同。你只需要将提供者类继承的父类更改为 `DatasourceProvider`。 + + ```python + class YourDatasourceProvider(DatasourceProvider): + + def _validate_credentials(self, credentials: Mapping[str, Any]) -> None: + try: + """ + IMPLEMENT YOUR VALIDATION HERE + """ + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) + ``` +- 使用 OAuth 认证模式时,数据源插件与工具插件略有不同。通过 OAuth 获取访问权限时,数据源插件可以同时返回要在前端显示的用户名和头像。因此,`_oauth_get_credentials` 和 `_oauth_refresh_credentials` 需要返回包含 `name`、`avatar_url`、`expires_at` 和 `credentials` 的 `DatasourceOAuthCredentials` 类型。 + + `DatasourceOAuthCredentials` 类定义如下,返回时必须设置为相应的类型: + + ```python + class DatasourceOAuthCredentials(BaseModel): + name: str | None = Field(None, description="The name of the OAuth credential") + avatar_url: str | None = Field(None, description="The avatar url of the OAuth") + credentials: Mapping[str, Any] = Field(..., description="The credentials of the OAuth") + expires_at: int | None = Field( + default=-1, + description="""The expiration timestamp (in seconds since Unix epoch, UTC) of the credentials. + Set to -1 or None if the credentials do not expire.""", + ) + ``` + +`_oauth_get_authorization_url`、`_oauth_get_credentials` 和 `_oauth_refresh_credentials` 的函数签名如下: + + + + ```python + def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: + """ + Generate the authorization URL for {{ .PluginName }} OAuth. + """ + try: + """ + IMPLEMENT YOUR AUTHORIZATION URL GENERATION HERE + """ + except Exception as e: + raise DatasourceOAuthError(str(e)) + return "" + ``` + + + ```python + def _oauth_get_credentials( + self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request + ) -> DatasourceOAuthCredentials: + """ + Exchange code for access_token. + """ + try: + """ + IMPLEMENT YOUR CREDENTIALS EXCHANGE HERE + """ + except Exception as e: + raise DatasourceOAuthError(str(e)) + return DatasourceOAuthCredentials( + name="", + avatar_url="", + expires_at=-1, + credentials={}, + ) + ``` + + + ```python + def _oauth_refresh_credentials( + self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] + ) -> DatasourceOAuthCredentials: + """ + Refresh the credentials + """ + return DatasourceOAuthCredentials( + name="", + avatar_url="", + expires_at=-1, + credentials={}, + ) + ``` + + + +### 添加数据源 + +三种数据源类型的 YAML 文件格式和数据源代码格式各不相同。 + +#### 网页爬虫 + +在网页爬虫数据源插件的提供者 YAML 文件中,`output_schema` 必须始终返回四个参数:`source_url`、`content`、`title` 和 `description`。 + +```yaml +output_schema: + type: object + properties: + source_url: + type: string + description: the source url of the website + content: + type: string + description: the content from the website + title: + type: string + description: the title of the website + "description": + type: string + description: the description of the website +``` + +在网页爬虫插件的主要逻辑代码中,类必须继承自 `WebsiteCrawlDatasource` 并实现 `_get_website_crawl` 方法。然后你需要使用 `create_crawl_message` 方法返回网页爬取消息。 + +要爬取多个网页并分批返回,你可以将 `WebSiteInfo.status` 设置为 `processing`,并使用 `create_crawl_message` 方法返回每批爬取的页面。所有页面爬取完成后,将 `WebSiteInfo.status` 设置为 `completed`。 + +```python +class YourDataSource(WebsiteCrawlDatasource): + + def _get_website_crawl( + self, datasource_parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + + crawl_res = WebSiteInfo(web_info_list=[], status="", total=0, completed=0) + crawl_res.status = "processing" + yield self.create_crawl_message(crawl_res) + + ### your crawl logic + ... + crawl_res.status = "completed" + crawl_res.web_info_list = [ + WebSiteInfoDetail( + title="", + source_url="", + description="", + content="", + ) + ] + crawl_res.total = 1 + crawl_res.completed = 1 + + yield self.create_crawl_message(crawl_res) +``` + +#### 在线文档 + +在线文档数据源插件的返回值必须至少包含一个 `content` 字段来表示文档内容。例如: + +```yaml +output_schema: + type: object + properties: + workspace_id: + type: string + description: workspace id + page_id: + type: string + description: page id + content: + type: string + description: page content +``` + +在在线文档插件的主要逻辑代码中,类必须继承自 `OnlineDocumentDatasource` 并实现两个方法:`_get_pages` 和 `_get_content`。 + +当用户运行插件时,它首先调用 `_get_pages` 方法获取文档列表。用户从列表中选择文档后,它再调用 `_get_content` 方法获取文档内容。 + + + + ```python + def _get_pages(self, datasource_parameters: dict[str, Any]) -> DatasourceGetPagesResponse: + # your get pages logic + response = requests.get(url, headers=headers, params=params, timeout=30) + pages = [] + for item in response.json().get("results", []): + page = OnlineDocumentPage( + page_name=item.get("title", ""), + page_id=item.get("id", ""), + type="page", + last_edited_time=item.get("version", {}).get("createdAt", ""), + parent_id=item.get("parentId", ""), + page_icon=None, + ) + pages.append(page) + online_document_info = OnlineDocumentInfo( + workspace_name=workspace_name, + workspace_icon=workspace_icon, + workspace_id=workspace_id, + pages=[page], + total=pages.length(), + ) + return DatasourceGetPagesResponse(result=[online_document_info]) + ``` + + + ```python + def _get_content(self, page: GetOnlineDocumentPageContentRequest) -> Generator[DatasourceMessage, None, None]: + # your fetch content logic, example + response = requests.get(url, headers=headers, params=params, timeout=30) + ... + yield self.create_variable_message("content", "") + yield self.create_variable_message("page_id", "") + yield self.create_variable_message("workspace_id", "") + ``` + + + +#### 在线云盘 + +在线云盘数据源插件返回文件,因此必须遵循以下规范: + +```yaml +output_schema: + type: object + properties: + file: + $ref: "https://dify.ai/schemas/v1/file.json" +``` + +在在线云盘插件的主要逻辑代码中,类必须继承自 `OnlineDriveDatasource` 并实现两个方法:`_browse_files` 和 `_download_file`。 + +当用户运行插件时,它首先调用 `_browse_files` 获取文件列表。此时,`prefix` 为空,表示请求根目录的文件列表。文件列表包含文件夹和文件两种类型的变量。如果用户打开文件夹,会再次调用 `_browse_files` 方法。此时,`OnlineDriveBrowseFilesRequest` 中的 `prefix` 将是用于检索该文件夹内文件列表的文件夹 ID。 + +用户选择文件后,插件使用 `_download_file` 方法和文件 ID 获取文件内容。你可以使用 `_get_mime_type_from_filename` 方法获取文件的 MIME 类型,使管道能够适当处理不同的文件类型。 + +当文件列表包含多个文件时,你可以将 `OnlineDriveFileBucket.is_truncated` 设置为 `True`,并将 `OnlineDriveFileBucket.next_page_parameters` 设置为获取下一页文件列表所需的参数,例如下一页的请求 ID 或 URL,具体取决于服务提供商。 + + + + ```python + def _browse_files( + self, request: OnlineDriveBrowseFilesRequest + ) -> OnlineDriveBrowseFilesResponse: + + credentials = self.runtime.credentials + bucket_name = request.bucket + prefix = request.prefix or "" # Allow empty prefix for root folder; When you browse the folder, the prefix is the folder id + max_keys = request.max_keys or 10 + next_page_parameters = request.next_page_parameters or {} + + files = [] + files.append(OnlineDriveFile( + id="", + name="", + size=0, + type="folder" # or "file" + )) + + return OnlineDriveBrowseFilesResponse(result=[ + OnlineDriveFileBucket( + bucket="", + files=files, + is_truncated=False, + next_page_parameters={} + ) + ]) + ``` + + + ```python + def _download_file(self, request: OnlineDriveDownloadFileRequest) -> Generator[DatasourceMessage, None, None]: + credentials = self.runtime.credentials + file_id = request.id + + file_content = bytes() + file_name = "" + + mime_type = self._get_mime_type_from_filename(file_name) + + yield self.create_blob_message(file_content, meta={ + "file_name": file_name, + "mime_type": mime_type + }) + + def _get_mime_type_from_filename(self, filename: str) -> str: + """Determine MIME type from file extension.""" + import mimetypes + mime_type, _ = mimetypes.guess_type(filename) + return mime_type or "application/octet-stream" + ``` + + + +对于 AWS S3 等存储服务,`prefix`、`bucket` 和 `id` 变量有特殊用途,可以在开发过程中根据需要灵活应用: + +- `prefix`:表示文件路径前缀。例如,`prefix=container1/folder1/` 从 `container1` 存储桶的 `folder1` 文件夹中检索文件或文件列表。 +- `bucket`:表示文件存储桶。例如,`bucket=container1` 检索 `container1` 存储桶中的文件或文件列表。对于非标准 S3 协议的云盘,此字段可以留空。 +- `id`:由于 `_download_file` 方法不使用 `prefix` 变量,因此完整文件路径必须包含在 `id` 中。例如,`id=container1/folder1/file1.txt` 表示从 `container1` 存储桶的 `folder1` 文件夹中检索 `file1.txt` 文件。 + + + 你可以参考[官方 Google Drive 插件](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/google_cloud_storage/datasources/google_cloud_storage.py)和[官方 AWS S3 插件](https://github.com/langgenius/dify-official-plugins/blob/main/datasources/aws_s3_storage/datasources/aws_s3_storage.py)的具体实现。 + + +## 调试插件 + +数据源插件支持两种调试方法:远程调试或作为本地插件安装进行调试。请注意以下事项: + +- 如果插件使用 OAuth 认证,远程调试的 `redirect_uri` 与本地插件不同。请在服务提供商的 OAuth App 中相应更新相关配置。 +- 虽然数据源插件支持单步调试,但我们仍建议在完整的知识库管道中测试它们,以确保完整功能。 + +## 最终检查 + +在打包和发布之前,请确保你已完成以下所有事项: + +- 将最低支持的 Dify 版本设置为 `1.9.0`。 +- 将 SDK 版本设置为 `dify-plugin>=0.5.0,<0.6.0`。 +- 编写 `README.md` 和 `PRIVACY.md` 文件。 +- 代码文件中仅包含英文内容。 +- 将默认图标替换为数据源提供商的 logo。 + +## 打包和发布 + +在插件目录中,运行以下命令生成 `.difypkg` 插件包: + +``` +dify plugin package . -o your_datasource.difypkg +``` + +接下来,你可以: + +- 在你的 Dify 环境中导入和使用插件。 +- 通过提交 pull request 将插件发布到 Dify Marketplace。 + + + 有关插件发布流程,请参阅[发布插件](/zh/develop-plugin/publishing/marketplace-listing/release-overview)。 + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/datasource-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx new file mode 100644 index 00000000..aee64f55 --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx @@ -0,0 +1,358 @@ +--- +dimensions: + type: + primary: reference + detail: examples + level: intermediate +standard_title: Develop A Slack Bot Plugin +language: en +title: 开发 Slack Bot 插件 +description: 本指南提供了开发 Slack Bot 插件的完整演练,涵盖项目初始化、配置表单编辑、功能实现、调试、端点设置、验证和打包。你需要 Dify 插件脚手架工具和预先创建的 Slack App 来在 Slack 上构建 AI 驱动的聊天机器人。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin)。 + +**你将学到:** + +深入了解如何构建一个由 AI 驱动的 Slack Bot——它可以直接在 Slack 中回答用户问题。如果你之前没有开发过插件,我们建议先阅读[插件开发快速入门指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)。 + +### 项目背景 + +Dify 插件生态系统致力于使集成更简单、更易于访问。在本指南中,我们将以 Slack 为例,带你完成开发 Slack Bot 插件的过程。这允许你的团队直接在 Slack 中与 LLM 聊天,显著提高他们使用 AI 的效率。 + +Slack 是一个开放的实时通信平台,拥有强大的 API。其功能之一是基于 webhook 的事件系统,开发起来非常简单。我们将利用这个系统创建一个 Slack Bot 插件,如下图所示: + +![Slack Bot diagram ](https://assets-docs.dify.ai/2025/01/a0865d18f1ca4051601ca53fa6f92db2.png) + +> 为避免混淆,以下概念作说明: +> +> * **Slack Bot** Slack 平台上的聊天机器人,作为一个虚拟用户,你可以与其实时交互。 +> * **Slack Bot 插件** Dify Marketplace 中的一个插件,用于连接 Dify 应用程序与 Slack。本指南重点介绍如何开发该插件。 + +**工作原理(简要概述):** + +1. **向 Slack Bot 发送消息** + + 当 Slack 中的用户向 Bot 发送消息时,Slack Bot 会立即向 Dify 平台发出 webhook 请求。 + +2. **将消息转发给 Slack Bot 插件** + + Dify 平台触发 Slack Bot 插件,该插件将详细信息转发给 Dify 应用程序——类似于在电子邮件系统中输入收件人地址。通过 Slack 的 API 设置 Slack webhook 地址并在 Slack Bot 插件中输入,即可建立此连接。然后插件处理 Slack 请求并将其发送到 Dify 应用程序,LLM 分析用户的输入并生成响应。 + +3. **将响应返回给 Slack** + + 一旦 Slack Bot 插件收到 Dify 应用程序的回复,它就会通过相同的路径将 LLM 的答案发送回 Slack Bot。Slack 中的用户就可以在他们聊天的地方看到更智能、更互动的体验。 + +### 前提条件 + +- **Dify 插件开发工具**:更多信息,请参阅[初始化开发工具](/zh/develop-plugin/getting-started/cli)。 +- **Python 环境(版本 ≥ 3.12)**:参考此 [Python 安装教程](https://pythontest.com/python/installing-python-3-11/) 或向 LLM 询问完整的设置指南。 +- 创建 Slack App 并获取 OAuth 令牌 + +前往 [Slack API 平台](https://api.slack.com/apps),从头创建一个 Slack 应用,并选择将其部署到的工作区。 + +![](https://assets-docs.dify.ai/2025/01/c1fd0ac1467faf5a3ebf3818bb234aa8.png) + +1. **启用 Webhooks:** + +![](https://assets-docs.dify.ai/2025/01/7112e0710300f1db16827e17f3deac00.png) + +2. **在你的 Slack 工作区安装应用:** + +![](https://assets-docs.dify.ai/2025/01/88c360ff4f7b04fea52174ce330522fa.png) + +3. **获取 OAuth 令牌**以供后续插件开发使用: + +![](https://assets-docs.dify.ai/2025/01/dcd8ec947253f2ef9ae121ed77ec9f26.png) + +### 1. 开发插件 + +现在我们将深入实际编码。在开始之前,请确保你已阅读[快速入门:开发扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint)或已经构建过 Dify 插件。 + +#### 1.1 初始化项目 + +运行以下命令来设置你的插件开发环境: + +```bash +dify plugin init +``` + +按照提示提供基本项目信息。选择 `extension` 模板,并授予 `Apps` 和 `Endpoints` 权限。 + +有关在插件中反向调用 Dify 服务的更多详细信息,请参阅[反向调用:App](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app)。 + +![Plugins permission](https://assets-docs.dify.ai/2024/12/d89a6282c5584fc43a9cadeddf09c0de.png) + +#### 1.2 编辑配置表单 + +此插件需要知道哪个 Dify 应用应处理回复,以及用于验证机器人响应的 Slack App 令牌。因此,你需要在插件的表单中添加这两个字段。 + +修改 group 目录中的 YAML 文件——例如 `group/slack.yaml`。表单的文件名由你创建插件时提供的信息决定,请相应调整。 + +**示例代码:** + +`slack.yaml` + +```yaml +settings: + - name: bot_token + type: secret-input + required: true + label: + en_US: Bot Token + zh_Hans: Bot Token + pt_BR: Token do Bot + ja_JP: Bot Token + placeholder: + en_US: Please input your Bot Token + zh_Hans: 请输入你的 Bot Token + pt_BR: Por favor, insira seu Token do Bot + ja_JP: ボットトークンを入力してください + - name: allow_retry + type: boolean + required: false + label: + en_US: Allow Retry + zh_Hans: 允许重试 + pt_BR: Permitir Retentativas + ja_JP: 再試行を許可 + default: false + - name: app + type: app-selector + required: true + label: + en_US: App + zh_Hans: 应用 + pt_BR: App + ja_JP: アプリ + placeholder: + en_US: the app you want to use to answer Slack messages + zh_Hans: 你想要用来回答 Slack 消息的应用 + pt_BR: o app que você deseja usar para responder mensagens do Slack + ja_JP: あなたが Slack メッセージに回答するために使用するアプリ +endpoints: + - endpoints/slack.yaml +``` + +配置字段说明: + +``` + - name: app + type: app-selector + scope: chat +``` + +* **type**:设置为 app-selector,允许用户在使用此插件时将消息转发到特定的 Dify 应用。 + +* **scope**:设置为 chat,意味着该插件只能与智能体、chatbot 或 chatflow 等应用类型交互。 + +最后,在 `endpoints/slack.yaml` 文件中,将请求方法更改为 POST 以正确处理传入的 Slack 消息。 + +**示例代码:** + +`endpoints/slack.yaml` + +```yaml +path: "/" +method: "POST" +extra: + python: + source: "endpoints/slack.py" +``` + +#### 2. 编辑功能代码 + +修改 `endpoints/slack.py` 文件并添加以下代码: + +```python +import json +import traceback +from typing import Mapping +from werkzeug import Request, Response +from dify_plugin import Endpoint +from slack_sdk import WebClient +from slack_sdk.errors import SlackApiError + + +class SlackEndpoint(Endpoint): + def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: + """ + Invokes the endpoint with the given request. + """ + retry_num = r.headers.get("X-Slack-Retry-Num") + if (not settings.get("allow_retry") and (r.headers.get("X-Slack-Retry-Reason") == "http_timeout" or ((retry_num is not None and int(retry_num) > 0)))): + return Response(status=200, response="ok") + data = r.get_json() + + # Handle Slack URL verification challenge + if data.get("type") == "url_verification": + return Response( + response=json.dumps({"challenge": data.get("challenge")}), + status=200, + content_type="application/json" + ) + + if (data.get("type") == "event_callback"): + event = data.get("event") + if (event.get("type") == "app_mention"): + message = event.get("text", "") + if message.startswith("<@"): + message = message.split("> ", 1)[1] if "> " in message else message + channel = event.get("channel", "") + blocks = event.get("blocks", []) + blocks[0]["elements"][0]["elements"] = blocks[0].get("elements")[0].get("elements")[1:] + token = settings.get("bot_token") + client = WebClient(token=token) + try: + response = self.session.app.chat.invoke( + app_id=settings["app"]["app_id"], + query=message, + inputs={}, + response_mode="blocking", + ) + try: + blocks[0]["elements"][0]["elements"][0]["text"] = response.get("answer") + result = client.chat_postMessage( + channel=channel, + text=response.get("answer"), + blocks=blocks + ) + return Response( + status=200, + response=json.dumps(result), + content_type="application/json" + ) + except SlackApiError as e: + raise e + except Exception as e: + err = traceback.format_exc() + return Response( + status=200, + response="Sorry, I'm having trouble processing your request. Please try again later." + str(err), + content_type="text/plain", + ) + else: + return Response(status=200, response="ok") + else: + return Response(status=200, response="ok") + else: + return Response(status=200, response="ok") +``` + +### 2. 调试插件 + +前往 Dify 平台并获取插件的远程调试地址和密钥。 + +![](https://assets-docs.dify.ai/2025/01/8d24006f0cabf5bf61640a9023c45db8.png) + +回到你的插件项目,复制 `.env.example` 文件并将其重命名为 `.env`。 + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_URL=debug.dify.ai:5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +运行 `python -m main` 启动插件。你现在应该可以在 Dify 插件管理页面的工作区中看到你的插件已安装。其他团队成员也可以访问它。 + +```bash +python -m main +``` + +#### 配置插件端点 + +从 Dify 的插件管理页面,找到新安装的测试插件并创建一个新端点。提供名称、Bot 令牌,并选择你想要连接的应用。 + + + +保存后,将生成一个 **POST** 请求 URL: + + + +接下来,完成 Slack App 设置: + +1. **启用事件订阅** + ![](https://assets-docs.dify.ai/2025/01/1d33bb9cde78a1b5656ad6a0b8350195.png) + + 粘贴你上面生成的 POST 请求 URL。 + ![](https://assets-docs.dify.ai/2025/01/65aa41f37c3800af49e944f9ff28e121.png) + +2. **授予所需权限** + ![](https://assets-docs.dify.ai/2025/01/25c38a2cf10ec6c55ae54970d790f37e.png) + +--- + +### 3. 验证插件 + +在你的代码中,`self.session.app.chat.invoke` 用于调用 Dify 应用程序,传入 `app_id` 和 `query` 等参数。然后将响应返回给 Slack Bot。再次运行 `python -m main` 重启插件进行调试,并检查 Slack 是否正确显示 Dify App 的回复: + +![](https://assets-docs.dify.ai/2025/01/6fc872d1343ce8503d63c5222f7f26f9.png) + +--- + +### 4. 打包插件(可选) + +确认插件工作正常后,你可以通过以下命令打包并命名它。运行后,你会在当前目录中找到一个 `slack_bot.difypkg` 文件——这就是你的最终插件包。有关详细的打包步骤,请参阅[打包为本地文件并分享](/zh/develop-plugin/publishing/marketplace-listing/release-by-file)。 + +```bash +# 将 ./slack_bot 替换为你实际的插件项目路径。 + +dify plugin package ./slack_bot +``` + +恭喜!你已成功开发、测试和打包了一个插件! + +--- + +### 5. 发布插件(可选) + +你现在可以将其上传到 [Dify Marketplace 仓库](https://github.com/langgenius/dify-plugins) 进行公开发布。在发布之前,请确保你的插件符合[发布到 Dify Marketplace 指南](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace)。一旦获得批准,你的代码将合并到主分支,插件将在 [Dify Marketplace](https://marketplace.dify.ai/) 上线。 + +--- + +## 相关资源 + +- [插件开发基础](/zh/develop-plugin/getting-started/getting-started-dify-plugin) - Dify 插件开发的全面概述 +- [插件开发快速入门指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - 从零开始开发插件 +- [开发扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 了解扩展插件开发 +- [反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 了解如何调用 Dify 平台功能 +- [反向调用:App](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - 了解如何调用平台内的应用 +- [发布插件](/zh/develop-plugin/publishing/marketplace-listing/release-overview) - 了解发布流程 +- [发布到 Dify Marketplace](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - Marketplace 发布指南 +- [端点详细定义](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 端点详细定义 + +### 延伸阅读 + +要获取完整的 Dify 插件项目示例,请访问 [GitHub 仓库](https://github.com/langgenius/dify-plugins)。你还可以找到包含完整源代码和实现细节的其他插件。 + +如果你想了解更多关于插件开发的内容,请查看以下资源: + +**快速入门:** +- [开发扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) +- [开发模型插件](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) +- [Bundle 插件:打包多个插件](/zh/develop-plugin/features-and-specs/advanced-development/bundle) + +**插件接口文档:** +- [通过 Manifest 文件定义插件信息](/zh/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest) - Manifest 结构 +- [端点](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 端点详细定义 +- [反向调用](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 反向调用 Dify 功能 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 工具规范 +- [模型 Schema](/zh/develop-plugin/features-and-specs/plugin-types/model-schema) - 模型 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx new file mode 100644 index 00000000..8ab666ef --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx @@ -0,0 +1,349 @@ +--- +title: '10分钟构建 Dify 插件指南' +description: '学习如何在10分钟内构建一个连接 Flomo 笔记服务的功能性 Dify 插件' +language: en +standard_title: 10-Minute Guide to Building Dify Plugins +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin)。 + +## 你将构建什么 + +完成本指南后,你将创建一个 Dify 插件,它能够: + +- 连接到 Flomo 笔记 API +- 允许用户将 AI 对话中的笔记直接保存到 Flomo +- 正确处理身份验证和错误状态 +- 准备好在 Dify Marketplace 中分发 + + + + 10 分钟 + + + 基本的 Python 知识和一个 Flomo 账户 + + + +## 步骤 1:安装 Dify CLI 并创建项目 + + + + + + ```bash + brew tap langgenius/dify + brew install dify + ``` + + + 从 [Dify GitHub releases 页面](https://github.com/langgenius/dify-plugin-daemon/releases) 获取最新的 Dify CLI + + ```bash + # Download appropriate version + chmod +x dify-plugin-linux-amd64 + mv dify-plugin-linux-amd64 dify + sudo mv dify /usr/local/bin/ + ``` + + + + 验证安装: + ```bash + dify version + ``` + + + + 使用以下命令创建新的插件项目: + + ```bash + dify plugin init + ``` + + 按照提示设置你的插件: + - 将其命名为 "flomo" + - 选择 "tool" 作为插件类型 + - 完成其他必填字段 + + + + ```bash + cd flomo + ``` + + 这将为你的插件创建基本结构,包含所有必要的文件。 + + + +## 步骤 2:定义插件清单 + + +manifest.yaml 文件定义了插件的元数据、权限和功能。 + + +创建 `manifest.yaml` 文件: + +```yaml +version: 0.0.4 +type: plugin +author: yourname +label: + en_US: Flomo + zh_Hans: Flomo 浮墨笔记 +created_at: "2023-10-01T00:00:00Z" +icon: icon.png + +resource: + memory: 67108864 # 64MB + permission: + storage: + enabled: false + +plugins: + tools: + - flomo.yaml + +meta: + version: 0.0.1 + arch: + - amd64 + - arm64 + runner: + language: python + version: 3.12 + entrypoint: main +``` + +## 步骤 3:创建工具定义 + +创建 `flomo.yaml` 文件来定义你的工具接口: + +```yaml +identity: + author: yourname + name: flomo + label: + en_US: Flomo Note + zh_Hans: Flomo 浮墨笔记 +description: + human: + en_US: Add notes to your Flomo account directly from Dify. + zh_Hans: 直接从Dify添加笔记到您的Flomo账户。 + llm: > + A tool that allows users to save notes to Flomo. Use this tool when users want to save important information from the conversation. The tool accepts a 'content' parameter that contains the text to be saved as a note. +credential_schema: + api_url: + type: string + required: true + label: + en_US: API URL + zh_Hans: API URL + human_description: + en_US: Flomo API URL from your Flomo account settings. + zh_Hans: 从您的Flomo账户设置中获取的API URL。 +tool_schema: + content: + type: string + required: true + label: + en_US: Note Content + zh_Hans: 笔记内容 + human_description: + en_US: Content to save as a note in Flomo. + zh_Hans: 要保存为Flomo笔记的内容。 +``` + +## 步骤 4:实现核心工具函数 + +在 `utils/flomo_utils.py` 中创建用于 API 交互的工具模块: + + +```python utils/flomo_utils.py +import requests + +def send_flomo_note(api_url: str, content: str) -> None: + """ + Send a note to Flomo via the API URL. Raises requests.RequestException on network errors, + and ValueError on invalid status codes or input. + """ + api_url = api_url.strip() + if not api_url: + raise ValueError("API URL is required and cannot be empty.") + if not api_url.startswith('https://flomoapp.com/iwh/'): + raise ValueError( + "API URL should be in the format: https://flomoapp.com/iwh/{token}/{secret}/" + ) + if not content: + raise ValueError("Content cannot be empty.") + + headers = {'Content-Type': 'application/json'} + response = requests.post(api_url, json={"content": content}, headers=headers, timeout=10) + + if response.status_code != 200: + raise ValueError(f"API URL is not valid. Received status code: {response.status_code}") +``` + + +## 步骤 5:实现工具提供者 + +工具提供者处理凭证验证。创建 `provider/flomo.py`: + + +```python provider/flomo.py +from typing import Any +from dify_plugin import ToolProvider +from dify_plugin.errors.tool import ToolProviderCredentialValidationError +import requests +from utils.flomo_utils import send_flomo_note + +class FlomoProvider(ToolProvider): + def _validate_credentials(self, credentials: dict[str, Any]) -> None: + try: + api_url = credentials.get('api_url', '').strip() + # Use utility for validation and sending test note + send_flomo_note(api_url, "Hello, #flomo https://flomoapp.com") + except ValueError as e: + raise ToolProviderCredentialValidationError(str(e)) + except requests.RequestException as e: + raise ToolProviderCredentialValidationError(f"Connection error: {str(e)}") +``` + + +## 步骤 6:实现工具 + +工具类处理用户调用插件时的实际 API 调用。创建 `tools/flomo.py`: + + +```python tools/flomo.py +from collections.abc import Generator +from typing import Any +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage +import requests +from utils.flomo_utils import send_flomo_note + +class FlomoTool(Tool): + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + content = tool_parameters.get("content", "") + api_url = self.runtime.credentials.get("api_url", "") + + try: + send_flomo_note(api_url, content) + except ValueError as e: + yield self.create_text_message(str(e)) + return + except requests.RequestException as e: + yield self.create_text_message(f"Connection error: {str(e)}") + return + + # Return success message and structured data + yield self.create_text_message( + "Note created successfully! Your content has been sent to Flomo." + ) + yield self.create_json_message({ + "status": "success", + "content": content, + }) +``` + + + +始终优雅地处理异常并返回用户友好的错误消息。请记住,你的插件代表着你在 Dify 生态系统中的品牌形象。 + + +## 步骤 7:测试你的插件 + + + + 复制示例环境文件: + ```bash + cp .env.example .env + ``` + + 使用你的 Dify 环境详情编辑 `.env` 文件: + ``` + INSTALL_METHOD=remote + REMOTE_INSTALL_HOST=debug-plugin.dify.dev + REMOTE_INSTALL_PORT=5003 + REMOTE_INSTALL_KEY=your_debug_key + ``` + + 你可以在 Dify 仪表板中找到你的调试密钥和主机:点击右上角的"插件"图标,然后点击调试图标。在弹出窗口中,复制"API Key"和"Host Address"。 + + + + ```bash + pip install -r requirements.txt + python -m main + ``` + + 你的插件将以调试模式连接到你的 Dify 实例。 + + + + 在你的 Dify 实例中,导航到插件并找到你的调试插件(标记为"debugging")。 + 添加你的 Flomo API 凭证并测试发送笔记。 + + + +## 步骤 9:打包和分发 + +当你准备好分享你的插件时: + +```bash +dify plugin package ./ +``` + +这将创建一个 `plugin.difypkg` 文件,你可以将其上传到 Dify Marketplace。 + +## 常见问题和故障排除 + + + + 确保你的 `.env` 文件配置正确,并且你使用的是正确的调试密钥。 + + + + 仔细检查你的 Flomo API URL 格式。它应该是这种形式:`https://flomoapp.com/iwh/{token}/{secret}/` + + + + 确保所有必需的文件都存在,并且 manifest.yaml 结构有效。 + + + +## 总结 + +你已经构建了一个连接外部 API 服务的功能性 Dify 插件!这种相同的模式适用于与数千种服务的集成——从数据库和搜索引擎到生产力工具和自定义 API。 + + + + 用英文(en_US)编写你的 README.md,描述功能、设置和使用示例 + + + 为其他语言创建额外的 README 文件,如 `readme/README_zh_Hans.md` + + + + + + 如果发布你的插件,请添加隐私政策(PRIVACY.md) + + + 在文档中包含全面的示例 + + + 使用各种文档大小和格式进行全面测试 + + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-flomo-plugin.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx new file mode 100644 index 00000000..13391a53 --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx @@ -0,0 +1,550 @@ +--- +title: '构建 Markdown 导出插件' +description: '学习如何创建一个将对话导出为不同文档格式的插件' +language: en +standard_title: Building a Markdown Exporter Plugin +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter)。 + +## 你将构建什么 + +在本指南中,你将学习如何构建一个实用的 Dify 插件,将对话导出为流行的文档格式。完成后,你的插件将能够: + +- 将 markdown 文本转换为 Word 文档 (.docx) +- 将对话导出为 PDF 文件 +- 处理文件创建并保持正确的格式 +- 为文档导出提供简洁的用户体验 + + + + 15 分钟 + + + 基本的 Python 知识和熟悉文档处理库 + + + +## 步骤 1:设置你的环境 + + + + + + ```bash + brew tap langgenius/dify + brew install dify + ``` + + + 从 [Dify GitHub releases 页面](https://github.com/langgenius/dify-plugin-daemon/releases)获取最新的 Dify CLI + + ```bash + # Download appropriate version + chmod +x dify-plugin-linux-amd64 + mv dify-plugin-linux-amd64 dify + sudo mv dify /usr/local/bin/ + ``` + + + + 验证安装: + ```bash + dify version + ``` + + + + 初始化一个新的插件项目: + + ```bash + dify plugin init + ``` + + 按照提示操作: + - 名称:"md_exporter" + - 类型:"tool" + - 按提示完成其他详细信息 + + + +## 步骤 2:定义插件清单 + +创建 `manifest.yaml` 文件来定义你的插件元数据: + +```yaml +version: 0.0.4 +type: plugin +author: your_username +label: + en_US: Markdown Exporter + zh_Hans: Markdown导出工具 +created_at: "2025-09-30T00:00:00Z" +icon: icon.png + +resource: + memory: 134217728 # 128MB + permission: + storage: + enabled: true # We need storage for temp files + +plugins: + tools: + - word_export.yaml + - pdf_export.yaml + +meta: + version: 0.0.1 + arch: + - amd64 + - arm64 + runner: + language: python + version: 3.11 + entrypoint: main +``` + +## 步骤 3:定义 Word 导出工具 + +创建一个 `word_export.yaml` 文件来定义 Word 文档导出工具: + +```yaml +identity: + author: your_username + name: word_export + label: + en_US: Export to Word + zh_Hans: 导出为Word文档 +description: + human: + en_US: Export conversation content to a Word document (.docx) + zh_Hans: 将对话内容导出为Word文档(.docx) + llm: > + A tool that converts markdown text to a Word document (.docx) format. + Use this tool when the user wants to save or export the conversation + content as a Word document. The input text should be in markdown format. +credential_schema: {} # No credentials needed +tool_schema: + markdown_content: + type: string + required: true + label: + en_US: Markdown Content + zh_Hans: Markdown内容 + human_description: + en_US: The markdown content to convert to Word format + zh_Hans: 要转换为Word格式的Markdown内容 + document_name: + type: string + required: false + label: + en_US: Document Name + zh_Hans: 文档名称 + human_description: + en_US: Name for the exported document (without extension) + zh_Hans: 导出文档的名称(无需扩展名) +``` + +## 步骤 4:定义 PDF 导出工具 + +为 PDF 导出创建一个 `pdf_export.yaml` 文件: + +```yaml +identity: + author: your_username + name: pdf_export + label: + en_US: Export to PDF + zh_Hans: 导出为PDF文档 +description: + human: + en_US: Export conversation content to a PDF document + zh_Hans: 将对话内容导出为PDF文档 + llm: > + A tool that converts markdown text to a PDF document. + Use this tool when the user wants to save or export the conversation + content as a PDF file. The input text should be in markdown format. +credential_schema: {} # No credentials needed +tool_schema: + markdown_content: + type: string + required: true + label: + en_US: Markdown Content + zh_Hans: Markdown内容 + human_description: + en_US: The markdown content to convert to PDF format + zh_Hans: 要转换为PDF格式的Markdown内容 + document_name: + type: string + required: false + label: + en_US: Document Name + zh_Hans: 文档名称 + human_description: + en_US: Name for the exported document (without extension) + zh_Hans: 导出文档的名称(无需扩展名) +``` + +## 步骤 5:安装所需依赖 + +创建或更新 `requirements.txt` 并添加必要的库: + +```text +python-docx>=0.8.11 +markdown>=3.4.1 +weasyprint>=59.0 +beautifulsoup4>=4.12.2 +``` + +## 步骤 6:实现 Word 导出功能 + +在 `utils/docx_utils.py` 中创建一个实用工具模块: + + +```python utils/docx_utils.py +import os +import tempfile +import uuid +from docx import Document +from docx.shared import Pt +from docx.enum.text import WD_PARAGRAPH_ALIGNMENT +import markdown +from bs4 import BeautifulSoup + +def convert_markdown_to_docx(markdown_text, document_name=None): + """ + Convert markdown text to a Word document and return the file path + """ + if not document_name: + document_name = f"exported_document_{uuid.uuid4().hex[:8]}" + + # Convert markdown to HTML + html = markdown.markdown(markdown_text) + soup = BeautifulSoup(html, 'html.parser') + + # Create a new Word document + doc = Document() + + # Process HTML elements and add to document + for element in soup.find_all(['h1', 'h2', 'h3', 'h4', 'p', 'ul', 'ol']): + if element.name == 'h1': + heading = doc.add_heading(element.text.strip(), level=1) + heading.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER + elif element.name == 'h2': + doc.add_heading(element.text.strip(), level=2) + elif element.name == 'h3': + doc.add_heading(element.text.strip(), level=3) + elif element.name == 'h4': + doc.add_heading(element.text.strip(), level=4) + elif element.name == 'p': + paragraph = doc.add_paragraph(element.text.strip()) + elif element.name in ('ul', 'ol'): + for li in element.find_all('li'): + doc.add_paragraph(li.text.strip(), style='ListBullet') + + # Create temp directory if it doesn't exist + temp_dir = tempfile.gettempdir() + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Save the document + file_path = os.path.join(temp_dir, f"{document_name}.docx") + doc.save(file_path) + + return file_path +``` + + +## 步骤 7:实现 PDF 导出功能 + +在 `utils/pdf_utils.py` 中创建一个实用工具模块: + + +```python utils/pdf_utils.py +import os +import tempfile +import uuid +import markdown +from weasyprint import HTML, CSS +from weasyprint.text.fonts import FontConfiguration + +def convert_markdown_to_pdf(markdown_text, document_name=None): + """ + Convert markdown text to a PDF document and return the file path + """ + if not document_name: + document_name = f"exported_document_{uuid.uuid4().hex[:8]}" + + # Convert markdown to HTML + html_content = markdown.markdown(markdown_text) + + # Add basic styling + styled_html = f""" + + + + + {document_name} + + + + {html_content} + + + """ + + # Create temp directory if it doesn't exist + temp_dir = tempfile.gettempdir() + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + # Output file path + file_path = os.path.join(temp_dir, f"{document_name}.pdf") + + # Configure fonts + font_config = FontConfiguration() + + # Render PDF + HTML(string=styled_html).write_pdf( + file_path, + stylesheets=[], + font_config=font_config + ) + + return file_path +``` + + +## 步骤 8:创建工具实现 + +首先,在 `tools/word_export.py` 中创建 Word 导出工具: + + +```python tools/word_export.py +import os +import base64 +from collections.abc import Generator +from typing import Any +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage +from utils.docx_utils import convert_markdown_to_docx + +class WordExportTool(Tool): + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + # Extract parameters + markdown_content = tool_parameters.get("markdown_content", "") + document_name = tool_parameters.get("document_name", "exported_document") + + if not markdown_content: + yield self.create_text_message("Error: No content provided for export.") + return + + try: + # Convert markdown to Word + file_path = convert_markdown_to_docx(markdown_content, document_name) + + # Read the file as binary + with open(file_path, 'rb') as file: + file_content = file.read() + + # Encode as base64 + file_base64 = base64.b64encode(file_content).decode('utf-8') + + # Return success message and file + yield self.create_text_message( + f"Document exported successfully as Word (.docx) format." + ) + + yield self.create_file_message( + file_name=f"{document_name}.docx", + file_content=file_base64, + mime_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ) + + except Exception as e: + yield self.create_text_message(f"Error exporting to Word: {str(e)}") + return +``` + + +接下来,在 `tools/pdf_export.py` 中创建 PDF 导出工具: + + +```python tools/pdf_export.py +import os +import base64 +from collections.abc import Generator +from typing import Any +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage +from utils.pdf_utils import convert_markdown_to_pdf + +class PDFExportTool(Tool): + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + # Extract parameters + markdown_content = tool_parameters.get("markdown_content", "") + document_name = tool_parameters.get("document_name", "exported_document") + + if not markdown_content: + yield self.create_text_message("Error: No content provided for export.") + return + + try: + # Convert markdown to PDF + file_path = convert_markdown_to_pdf(markdown_content, document_name) + + # Read the file as binary + with open(file_path, 'rb') as file: + file_content = file.read() + + # Encode as base64 + file_base64 = base64.b64encode(file_content).decode('utf-8') + + # Return success message and file + yield self.create_text_message( + f"Document exported successfully as PDF format." + ) + + yield self.create_file_message( + file_name=f"{document_name}.pdf", + file_content=file_base64, + mime_type="application/pdf" + ) + + except Exception as e: + yield self.create_text_message(f"Error exporting to PDF: {str(e)}") + return +``` + + +## 步骤 9:创建入口点 + +在项目根目录创建一个 `main.py` 文件: + + +```python main.py +from dify_plugin import PluginRunner +from tools.word_export import WordExportTool +from tools.pdf_export import PDFExportTool + +plugin = PluginRunner( + tools=[ + WordExportTool(), + PDFExportTool(), + ], + providers=[] # No credential providers needed +) +``` + + +## 步骤 10:测试你的插件 + + + + 首先,从模板创建你的 `.env` 文件: + ```bash + cp .env.example .env + ``` + + 使用你的 Dify 环境详细信息进行配置: + ``` + INSTALL_METHOD=remote + REMOTE_INSTALL_HOST=debug-plugin.dify.dev + REMOTE_INSTALL_PORT=5003 + REMOTE_INSTALL_KEY=your_debug_key + ``` + + + + ```bash + pip install -r requirements.txt + ``` + + + + ```bash + python -m main + ``` + + + +## 步骤 11:打包分发 + +当你准备好分享你的插件时: + +```bash +dify plugin package ./ +``` + +这将创建一个 `plugin.difypkg` 文件用于分发。 + +## 创意用例 + + + + 使用此插件将分析摘要转换为专业报告提供给客户 + + + 将辅导或咨询会话笔记导出为格式化文档 + + + +## 超越基础 + +以下是一些扩展此插件的有趣方式: + +- **自定义模板**:添加公司品牌或个性化样式 +- **多格式支持**:扩展导出为 HTML、Markdown 或其他格式 +- **图像处理**:处理并包含对话中的图像 +- **表格支持**:为数据表格实现正确的格式化 +- **协作编辑**:添加与 Google Docs 或类似平台的集成 + + +文档转换的核心挑战是保持格式和结构。此插件使用的方法首先将 markdown 转换为 HTML(一种中间格式),然后将该 HTML 处理为目标格式。 + +这个两步过程提供了灵活性——你可以通过简单地添加与 HTML 表示配合工作的新输出模块来扩展它以支持其他格式。 + +对于 PDF 生成,选择 WeasyPrint 是因为它提供具有 CSS 支持的高质量 PDF 渲染。对于 Word 文档,python-docx 提供对文档结构的精细控制。 + + +## 总结 + +你已经构建了一个实用的插件,通过使用户能够以专业文档格式导出对话,为 Dify 平台增添了真正的价值。此功能弥合了 AI 对话与传统文档工作流之间的差距。 + + + + 用英语 (en_US) 编写你的 README.md,描述功能、设置和使用示例 + + + 为其他语言创建额外的 README 文件,如 `readme/README_zh_Hans.md` + + + + + + 如果发布你的插件,请添加隐私政策 (PRIVACY.md) + + + 在文档中包含全面的示例 + + + 使用各种文档大小和格式进行彻底测试 + + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/develop-md-exporter.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx new file mode 100644 index 00000000..188ffdf9 --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx @@ -0,0 +1,132 @@ +--- +dimensions: + type: + primary: reference + detail: examples + level: intermediate +standard_title: Endpoint +language: en +title: Neko Cat Endpoint +description: Authors Yeuoly, Allen. This document details the structure and implementation + of Endpoints in Dify plugins, using the Neko Cat project as an example. It covers + defining Endpoint groups, configuring interfaces, implementing the _invoke method, + and handling requests and responses. The document explains the meaning and usage + of various YAML configuration fields. +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/endpoint)。 + +# Endpoint + +本文档以 [Neko Cat](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) 项目为例,介绍插件中 Endpoint 的结构。Endpoint 是插件暴露的 HTTP 接口,可用于与外部系统集成。完整的插件代码请参考 [GitHub 仓库](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko)。 + +### 分组定义 + +`Endpoint` 分组是多个 `Endpoint` 的集合。在 Dify 插件中创建新的 `Endpoint` 时,你可能需要填写以下配置。 + +![](https://assets-docs.dify.ai/2024/11/763dbf86e4319591415dc5a1b6948ccb.png) + +除了 `Endpoint Name` 之外,你可以通过编写分组的配置信息来添加新的表单项。点击保存后,你可以看到它包含的多个接口,这些接口将使用相同的配置信息。 + +![](https://assets-docs.dify.ai/2024/11/b778b7093b7df0dc80a476c65ddcbe58.png) + +#### **结构** + +* `settings` (map[string] [ProviderConfig](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications#providerconfig)):Endpoint 配置定义。 +* `endpoints` (list[string], 必填):指向具体的 `endpoint` 接口定义。 + +```yaml +settings: + api_key: + type: secret-input + required: true + label: + en_US: API key + zh_Hans: API key + ja_Jp: API key + pt_BR: API key + placeholder: + en_US: Please input your API key + zh_Hans: 请输入你的 API key + ja_Jp: あなたの API key を入れてください + pt_BR: Por favor, insira sua chave API +endpoints: + - endpoints/duck.yaml + - endpoints/neko.yaml +``` + +### 接口定义 + +* `path` (string):遵循 Werkzeug 接口标准。 +* `method` (string):接口方法,仅支持 `HEAD`、`GET`、`POST`、`PUT`、`DELETE`、`OPTIONS`。 +* `extra` (object):基本详情之外的配置信息。 + * `python` (object) + * `source` (string):实现此接口的源代码。 + +```yaml +path: "/duck/" +method: "GET" +extra: + python: + source: "endpoints/duck.py" +``` + +### 接口实现 + +你需要实现一个继承自 `dify_plugin.Endpoint` 的子类,并实现 `_invoke` 方法。 + +* **输入参数** + * `r` (Request):来自 `werkzeug` 的 `Request` 对象。 + * `values` (Mapping):从路径解析的路径参数。 + * `settings` (Mapping):此 `Endpoint` 的配置信息。 +* **返回** + * 来自 `werkzeug` 的 `Response` 对象,支持流式响应。 + * 不支持直接返回字符串。 + +示例代码: + +```python +import json +from typing import Mapping +from werkzeug import Request, Response +from dify_plugin import Endpoint + +class Duck(Endpoint): + def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: + """ + Invokes the endpoint with the given request. + """ + app_id = values["app_id"] + + def generator(): + yield f"{app_id}
" + + return Response(generator(), status=200, content_type="text/html") +``` + +## 注意事项 + +* Endpoint 仅在插件被调用时实例化;它们不是长期运行的服务。 +* 开发 Endpoint 时请注意安全性,避免执行危险操作。 +* Endpoint 可用于处理 Webhook 回调或为其他系统提供连接接口。 + +如果你正在学习插件开发,建议先阅读[插件开发入门](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)和[开发者速查表](/zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet)。 + +## 相关资源 + +* [插件开发基本概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin) - 了解插件开发的整体架构。 +* [Neko Cat 示例](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 扩展插件开发示例。 +* [通用规范定义](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 了解 ProviderConfig 等通用结构。 +* [开发 Slack Bot 插件示例](/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 另一个插件开发示例。 +* [插件开发入门](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - 从零开始开发插件。 +* [反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - 了解如何使用反向调用功能。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/endpoint.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-zh/0222-tool-oauth.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx similarity index 55% rename from plugin-dev-zh/0222-tool-oauth.mdx rename to zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx index 5db2b5d1..0d77da18 100644 --- a/plugin-dev-zh/0222-tool-oauth.mdx +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx @@ -2,48 +2,50 @@ title: "为工具插件添加 OAuth 支持" --- + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth)。 + ![b0e673ba3e339b31ac36dc3cd004df04787bcaa64bb6d2cac6feb7152b7b515f.png](/images/b0e673ba3e339b31ac36dc3cd004df04787bcaa64bb6d2cac6feb7152b7b515f.png) -本文档介绍如何为你的工具插件添加 [OAuth](https://oauth.net/2/) 支持。 +本指南将教你如何为工具插件构建 [OAuth](https://oauth.net/2/) 支持。 -对于需要通过第三方服务(如 Gmail 或 GitHub)访问用户数据的工具插件而言,OAuth 是一种更好的授权方式:在获得用户明确同意的情况下,允许工具插件代表用户执行操作,而无需用户手动输入 API 密钥。 +OAuth 是为需要访问第三方服务(如 Gmail 或 GitHub)用户数据的工具插件提供授权的更好方式。OAuth 允许工具在用户明确同意的情况下代表用户执行操作,而无需用户手动输入 API 密钥。 -## 介绍 +## 背景 -Dify 的 OAuth 配置涉及两个独立流程,开发者应当充分理解并根据流程进行设计。 +Dify 中的 OAuth 涉及**两个独立的流程**,开发者需要理解并为其进行设计。 -### 流程一:OAuth 客户端设置(由管理员 / 开发者完成) +### 流程 1:OAuth 客户端设置(管理员/开发者流程) - 在 Dify Cloud 上,Dify 团队会为热门工具插件创建 OAuth 应用并设置 OAuth 客户端,为用户节省自行配置的麻烦。 + 在 Dify Cloud 上,Dify 团队会为热门工具插件创建 OAuth 应用并设置 OAuth 客户端,省去用户自行配置的麻烦。 - 而对于自托管的 Dify 实例,管理员需自行完成此设置流程。 + 自托管 Dify 实例的管理员必须完成此设置流程。 -首先,Dify 实例的管理员或开发者需要在第三方服务中将 OAuth 应用注册为受信任应用,以获得将 Dify 工具供应商配置为 OAuth 客户端所需的必要凭证。 +Dify 实例的管理员或开发者首先需要在第三方服务上将 OAuth 应用注册为受信任的应用程序。由此,他们将能够获取必要的凭证,以将 Dify 工具提供者配置为 OAuth 客户端。 -下面以 Dify 的 Gmail 工具供应商为例。 +以下是为 Dify 的 Gmail 工具提供者设置 OAuth 客户端的步骤示例: - 1. 前往 [Google Cloud Console](https://console.cloud.google.com) ,创建新项目或选择现有项目。 - 2. 启用所需的 API(如 Gmail API)。 + 1. 前往 [Google Cloud Console](https://console.cloud.google.com) 创建新项目,或选择现有项目 + 2. 启用所需的 API(例如 Gmail API) - - 1. 前往 **API 和服务** \> **OAuth 权限请求页面**。 - 2. 对于公开插件,选择 **外部** 受众群体类型。 - 3. 填写应用名称、用户支持邮箱和开发者联系方式。 - 4. (可选)添加授权域名。 - 5. 选择 **目标对象** \> **测试用户**,添加测试用户以进行测试。 + + 1. 导航至 **APIs & Services** \> **OAuth consent screen** + 2. 为公共插件选择 **External** 用户类型 + 3. 填写应用名称、用户支持邮箱和开发者联系方式 + 4. 如需要,添加授权域名 + 5. 测试阶段:在 **Test users** 部分添加测试用户 - 1. 前往 **API 和服务** \> **凭证**。 - 2. 点击 **创建凭证** \> **OAuth 客户端 ID**。 - 3. 选择 **Web 应用**,点击 **创建**。 - 4. 保存生成的凭证信息,包括客户端 ID 和客户端密钥。 + 1. 前往 **APIs & Services** \> **Credentials** + 2. 点击 **Create Credentials** \> **OAuth 2.0 Client IDs** + 3. 选择 **Web application** 类型 + 4. 将生成 `client_id` 和 `client_secret`。保存这些凭证。 - 在 OAuth 客户端配置窗口中,输入客户端 ID(client_ID)和客户端密钥(client_secret),以将工具供应商设置为客户端。 + 在 OAuth 客户端配置弹窗中输入 client_id 和 client_secret,以将工具提供者设置为客户端。 - 在 Google OAuth 客户端页面,填写由 Dify 生成的重定向 URI。 + 在 Google OAuth 客户端页面上注册 Dify 生成的重定向 URI: - Dify 在 OAuth 客户端配置弹窗中显示`redirect_uri`,通常遵循以下格式: + Dify 在 OAuth 客户端配置弹窗中显示 `redirect_uri`。它通常遵循以下格式: ```bash https://{your-dify-domain}/console/api/oauth/plugin/{plugin-id}/{provider-name}/{tool-name}/callback ``` - 对于自托管的 Dify 实例,`your-dify-domain` 应与 `CONSOLE_WEB_URL` 保持一致。 + 对于自托管 Dify,`your-dify-domain` 应与 `CONSOLE_WEB_URL` 保持一致。 - 不同第三方服务的要求各异,请务必查阅目标集成服务的特定 OAuth 文档。 + 每个服务都有独特的要求,因此请务必查阅你所集成服务的具体 OAuth 文档。 -### 流程二:用户授权(由 Dify 用户完成) +### 流程 2:用户授权(Dify 用户流程) -OAuth 客户端配置完成后,Dify 用户即可授权插件访问他们的个人账户。 +配置 OAuth 客户端后,Dify 用户可以授权你的插件访问他们的个人账户。 -## 步骤 +## 实现 -### 1. 在供应商的 Manifest 文件中定义 OAuth 的参数架构 +### 1. 在提供者清单中定义 OAuth Schema -供应商的 Manifest 文件中的 `oauth_schema` 字段为插件 OAuth 定义凭证需求及授权流程产出,涉及以下两种参数架构。 +提供者清单中的 `oauth_schema` 部分告诉 Dify 你的插件 OAuth 需要哪些凭证以及 OAuth 流程将产生什么。设置 OAuth 需要两个 schema: #### client_schema -定义 OAuth 客户端设置所需的输入参数架构。 +定义 OAuth 客户端设置的输入: ```yaml gmail.yaml oauth_schema: @@ -115,15 +117,15 @@ oauth_schema: ``` - `url` 字段直接链接至第三方服务的帮助文档,有助于为管理员/开发人员解惑。 + `url` 字段直接链接到第三方服务的帮助文档。这有助于遇到困惑的管理员/开发者。 #### credentials_schema -定义用户授权流程产生的凭证参数架构(由 Dify 自动管理)。 +指定用户授权流程产生的内容(Dify 自动管理这些): ```yaml -# 同样在 oauth_schema 下 +# also under oauth_schema credentials_schema: - name: "access_token" type: "secret-input" @@ -134,22 +136,22 @@ oauth_schema: ``` - 同时包含 `oauth_schema` 和 `credentials_for_provider` 字段,为用户提供 OAuth 和 API 密钥两种认证选项。 + 同时包含 `oauth_schema` 和 `credentials_for_provider` 可提供 OAuth \+ API 密钥认证选项。 -### 2. 在工具供应商中完成所需的 OAuth 方法实现 +### 2. 在工具提供者中完成必需的 OAuth 方法 -在实现 `ToolProvider` 的位置,添加以下代码: +在实现 `ToolProvider` 的位置添加以下导入: ```python from dify_plugin.entities.oauth import ToolOAuthCredentials from dify_plugin.errors.tool import ToolProviderCredentialValidationError, ToolProviderOAuthError ``` -`ToolProvider` 类必须实现以下三个 OAuth 方法(以 `GmailProvider` 为例): +你的 `ToolProvider` 类必须实现以下三个 OAuth 方法(以 `GmailProvider` 为例): - 为避免安全隐患,在任何情况下都不应在 `ToolOAuthCredentials` 的凭证中返回 `client_secret`(客户端密钥)。 + 在任何情况下都不应在 `ToolOAuthCredentials` 的凭证中返回 `client_secret`,因为这可能导致安全问题。 @@ -157,24 +159,24 @@ from dify_plugin.errors.tool import ToolProviderCredentialValidationError, ToolP ```python _oauth_get_authorization_url expandable def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: """ - 使用 OAuth 客户端设置流程中的凭据生成授权 URL。 - 此 URL 是用户授权应用程序访问其资源的地址。 + Generate the authorization URL using credentials from OAuth Client Setup Flow. + This URL is where users grant permissions. """ - # 生成随机状态值用于 CSRF 保护(建议所有 OAuth 流程使用) + # Generate random state for CSRF protection (recommended for all OAuth flows) state = secrets.token_urlsafe(16) - # 定义 Gmail 特定的作用域范围。请求最小必要权限 - scope = "read:user read:data" # 替换为所需的权限范围 + # Define Gmail-specific scopes - request minimal necessary permissions + scope = "read:user read:data" # Replace with your required scopes - # 组装 Gmail 特定的请求参数 + # Assemble Gmail-specific payload params = { - "client_id": system_credentials["client_id"], # 来自 OAuth 客户端设置 - "redirect_uri": redirect_uri, # 由 Dify 生成,请勿修改 + "client_id": system_credentials["client_id"], # From OAuth Client Setup + "redirect_uri": redirect_uri, # Dify generates this - DON'T modify "scope": scope, - "response_type": "code", # 标准 OAuth 授权码流程 - "access_type": "offline", # 关键:获取刷新令牌(若支持) - "prompt": "consent", # 当权限范围变更时强制重新授权(若支持) - "state": state, # CSRF 保护 + "response_type": "code", # Standard OAuth authorization code flow + "access_type": "offline", # Critical: gets refresh token (if supported) + "prompt": "consent", # Forces reauth when scopes change (if supported) + "state": state, # CSRF protection } return f"{self._AUTH_URL}?{urllib.parse.urlencode(params)}" @@ -186,29 +188,29 @@ def _oauth_get_credentials( self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request ) -> ToolOAuthCredentials: """ - 将授权码交换为访问令牌和刷新令牌。 - 此方法用于为单个账户连接创建一套凭证。 + Exchange authorization code for access token and refresh token. This is called + to creates ONE credential set for one account connection """ - # 从 OAuth 回调中提取授权码 + # Extract authorization code from OAuth callback code = request.args.get("code") if not code: raise ToolProviderOAuthError("Authorization code not provided") - # 检查来自 OAuth 提供程序的授权错误 + # Check for authorization errors from OAuth provider error = request.args.get("error") if error: error_description = request.args.get("error_description", "") raise ToolProviderOAuthError(f"OAuth authorization failed: {error} - {error_description}") - # 使用 OAuth 客户端设置凭据将授权码交换为令牌 + # Exchange authorization code for tokens using OAuth Client Setup credentials - # 组装 Gmail 特定的请求载荷 + # Assemble Gmail-specific payload data = { - "client_id": system_credentials["client_id"], # 来自 OAuth 客户端设置 - "client_secret": system_credentials["client_secret"], # 来自 OAuth 客户端设置 - "code": code, # 来自用户授权 - "grant_type": "authorization_code", # 标准 OAuth 流程类型 - "redirect_uri": redirect_uri, # 必须与授权 URL 完全匹配 + "client_id": system_credentials["client_id"], # From OAuth Client Setup + "client_secret": system_credentials["client_secret"], # From OAuth Client Setup + "code": code, # From user's authorization + "grant_type": "authorization_code", # Standard OAuth flow type + "redirect_uri": redirect_uri, # Must exactly match authorization URL } headers = {"Content-Type": "application/x-www-form-urlencoded"} @@ -224,7 +226,7 @@ def _oauth_get_credentials( token_data = response.json() - # 处理响应中的 OAuth 提供商错误 + # Handle OAuth provider errors in response if "error" in token_data: error_desc = token_data.get('error_description', token_data['error']) raise ToolProviderOAuthError(f"Token exchange failed: {error_desc}") @@ -233,18 +235,18 @@ def _oauth_get_credentials( if not access_token: raise ToolProviderOAuthError("No access token received from provider") - # 构建与你的 credentials_schema 匹配的凭据字典 + # Build credentials dict matching your credentials_schema credentials = { "access_token": access_token, "token_type": token_data.get("token_type", "Bearer"), } - # 若支持刷新令牌,则需包含(对长期访问至关重要) + # Include refresh token if provided (critical for long-term access) refresh_token = token_data.get("refresh_token") if refresh_token: credentials["refresh_token"] = refresh_token - # 处理令牌过期时间。某些提供程序不提供 expires_in + # Handle token expiration - some providers don't provide expires_in expires_in = token_data.get("expires_in", 3600) # Default to 1 hour expires_at = int(time.time()) + expires_in @@ -262,19 +264,19 @@ def _oauth_refresh_credentials( self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] ) -> ToolOAuthCredentials: """ - 使用刷新令牌刷新凭证。 - 当令牌过期时,Dify 将自动调用此方法。 + Refresh the credentials using refresh token. + Dify calls this automatically when tokens expire """ refresh_token = credentials.get("refresh_token") if not refresh_token: raise ToolProviderOAuthError("No refresh token available") - # 标准 OAuth 刷新令牌流程 + # Standard OAuth refresh token flow data = { - "client_id": system_credentials["client_id"], # 来自 OAuth 客户端设置 - "client_secret": system_credentials["client_secret"], # 来自 OAuth 客户端设置 - "refresh_token": refresh_token, # 来自先前的授权 - "grant_type": "refresh_token", # OAuth 刷新流程 + "client_id": system_credentials["client_id"], # From OAuth Client Setup + "client_secret": system_credentials["client_secret"], # From OAuth Client Setup + "refresh_token": refresh_token, # From previous authorization + "grant_type": "refresh_token", # OAuth refresh flow } headers = {"Content-Type": "application/x-www-form-urlencoded"} @@ -290,7 +292,7 @@ def _oauth_refresh_credentials( token_data = response.json() - # 处理刷新错误 + # Handle refresh errors if "error" in token_data: error_desc = token_data.get('error_description', token_data['error']) raise ToolProviderOAuthError(f"Token refresh failed: {error_desc}") @@ -299,21 +301,22 @@ def _oauth_refresh_credentials( if not access_token: raise ToolProviderOAuthError("No access token received from provider") - # 构建新凭证,保留现有的刷新令牌 + # Build new credentials, preserving existing refresh token + new_credentials = { "access_token": access_token, "token_type": token_data.get("token_type", "Bearer"), - "refresh_token": refresh_token, # 保留现有的刷新令牌 + "refresh_token": refresh_token, # Keep existing refresh token } - # 处理令牌过期时间 + # Handle token expiration expires_in = token_data.get("expires_in", 3600) - # 若提供了新的刷新令牌,则进行更新 + # update refresh token if new one provided new_refresh_token = token_data.get("refresh_token") if new_refresh_token: new_credentials["refresh_token"] = new_refresh_token - # 为 Dify 的令牌管理计算新的过期时间戳 + # Calculate new expiration timestamp for Dify's token management expires_at = int(time.time()) + expires_in return ToolOAuthCredentials(credentials=new_credentials, expires_at=expires_at) @@ -328,7 +331,7 @@ def _oauth_refresh_credentials( ### 3. 在工具中访问令牌 -你可以在 `Tool` 实现中使用 OAuth 凭证进行经过身份验证的 API 调用,示例如下: +你可以在 `Tool` 实现中使用 OAuth 凭证进行经过身份验证的 API 调用,如下所示: ```python class YourTool(BuiltinTool): @@ -341,19 +344,19 @@ class YourTool(BuiltinTool): return self.create_text_message(response.text) ``` -`self.runtime.credentials` 自动提供当前用户的令牌。Dify 自动处理令牌刷新机制。 +`self.runtime.credentials` 自动提供当前用户的令牌。Dify 自动处理刷新。 -对于同时支持 OAuth 和 API 密钥认证的插件,可使用 `self.runtime.credential_type` 来区分两种认证类型。 +对于同时支持 OAuth 和 API_KEY 认证的插件,你可以使用 `self.runtime.credential_type` 来区分这两种认证类型。 ### 4. 指定正确的版本 -插件 SDK 和 Dify 的早期版本不支持 OAuth 认证。因此,需将插件 SDK 版本设置如下: +早期版本的插件 SDK 和 Dify 不支持 OAuth 认证。因此,你需要将插件 SDK 版本设置为: ``` dify_plugin>=0.4.2,<0.5.0. ``` -在 `manifest.yaml`中, 添加最低 Dify 版本要求: +在 `manifest.yaml` 中,添加最低 Dify 版本: ```yaml meta: @@ -376,5 +379,4 @@ It will be automatically generated by the script. --- -[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-zh/0222-tool-oauth.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/tool-oauth.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx new file mode 100644 index 00000000..2ab9f556 --- /dev/null +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx @@ -0,0 +1,387 @@ +--- +dimensions: + type: + primary: implementation + detail: standard + level: intermediate +standard_title: Tool Plugin +language: en +title: 工具插件 +description: 本文档提供了如何为 Dify 开发工具插件的详细说明,以 Google Search 为例演示完整的工具插件开发流程。内容包括插件初始化、模板选择、工具提供者配置文件定义、添加第三方服务凭据、工具功能代码实现、调试以及打包发布。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)。 + +工具是指可以被 Chatflow / Workflow / Agent 类型应用调用的第三方服务,提供完整的 API 实现能力来增强 Dify 应用。例如,添加在线搜索、图像生成等额外功能。 + +![Tool Plugin Example](https://assets-docs.dify.ai/2024/12/7e7bcf1f9e3acf72c6917ea9de4e4613.png) + +在本文中,**"工具插件"**指的是一个完整的项目,包含工具提供者文件、功能代码和其他结构。一个工具提供者可以包含多个工具(可以理解为单个工具内提供的额外功能),结构如下: + +``` +- Tool Provider + - Tool A + - Tool B +``` + +![Tool Plugin Structure](https://assets-docs.dify.ai/2025/02/60c4c86a317d865133aa460592eac079.png) + +本文将以 `Google Search` 为例,演示如何快速开发一个工具插件。 + +### 前置条件 + +- Dify 插件脚手架工具 +- Python 环境,版本 ≥ 3.12 + +关于如何准备插件开发脚手架工具的详细说明,请参考[初始化开发工具](/zh/develop-plugin/getting-started/cli)。如果你是首次开发插件,建议先阅读 [Dify 插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)。 + +### 创建新项目 + +运行脚手架命令行工具来创建一个新的 Dify 插件项目。 + +```bash +./dify-plugin-darwin-arm64 plugin init +``` + +如果你已将二进制文件重命名为 `dify` 并复制到 `/usr/local/bin` 路径,可以运行以下命令来创建新的插件项目: + +```bash +dify plugin init +``` + +> 在后续文本中,将使用 `dify` 作为命令行示例。如果遇到任何问题,请将 `dify` 命令替换为命令行工具的路径。 + +### 选择插件类型和模板 + +脚手架工具中的所有模板都提供完整的代码项目。在本示例中,选择 `Tool` 插件。 + +> 如果你已经熟悉插件开发且不需要依赖模板,可以参考[通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)指南来完成不同类型插件的开发。 + +![Plugin Type: Tool](https://assets-docs.dify.ai/2024/12/dd3c0f9a66454e15868eabced7b74fd6.png) + +#### 配置插件权限 + +插件还需要从 Dify 平台读取的权限。为本示例插件授予以下权限: + +- Tools +- Apps +- 启用持久化存储 Storage,分配默认大小存储 +- 允许注册 Endpoints + +> 在终端中使用方向键选择权限,使用"Tab"按钮授予权限。 + +勾选所有权限项后,按 Enter 完成插件创建。系统将自动生成插件项目代码。 + +![Plugin Permissions](https://assets-docs.dify.ai/2024/12/9cf92c2e74dce55e6e9e331d031e5a9f.png) + +### 开发工具插件 + +#### 1. 创建工具提供者文件 + +工具提供者文件是一个 yaml 格式文件,可以理解为工具插件的基本配置入口,用于向工具提供必要的授权信息。 + +进入插件模板项目的 `/provider` 路径,将 yaml 文件重命名为 `google.yaml`。这个 `yaml` 文件将包含工具提供者的信息,包括提供者的名称、图标、作者等详细信息。这些信息将在安装插件时显示。 + +**示例代码** + +```yaml +identity: # Basic information of the tool provider + author: Your-name # Author + name: google # Name, unique, cannot have the same name as other providers + label: # Label, for frontend display + en_US: Google # English label + zh_Hans: Google # Chinese label + description: # Description, for frontend display + en_US: Google # English description + zh_Hans: Google # Chinese description + icon: icon.svg # Tool icon, needs to be placed in the _assets folder + tags: # Tags, for frontend display + - search +``` + +确保文件路径在 `/tools` 目录中,完整路径如下: + +```yaml +plugins: + tools: + - 'google.yaml' +``` + +其中 `google.yaml` 需要使用其在插件项目中的绝对路径。在本示例中,它位于项目根目录。YAML 文件中的 identity 字段说明如下:`identity` 包含工具提供者的基本信息,包括作者、名称、标签、描述、图标等。 + +- 图标需要是附件资源,需要放置在项目根目录的 `_assets` 文件夹中。 +- 标签可以帮助用户通过分类快速找到插件。以下是目前支持的所有标签。 + +```python +class ToolLabelEnum(Enum): + SEARCH = 'search' + IMAGE = 'image' + VIDEOS = 'videos' + WEATHER = 'weather' + FINANCE = 'finance' + DESIGN = 'design' + TRAVEL = 'travel' + SOCIAL = 'social' + NEWS = 'news' + MEDICAL = 'medical' + PRODUCTIVITY = 'productivity' + EDUCATION = 'education' + BUSINESS = 'business' + ENTERTAINMENT = 'entertainment' + UTILITIES = 'utilities' + OTHER = 'other' +``` + +#### **2. 完善第三方服务凭据** + +为了开发方便,我们选择使用第三方服务 `SerpApi` 提供的 Google Search API。`SerpApi` 需要 API Key 才能使用,因此我们需要在 `yaml` 文件中添加 `credentials_for_provider` 字段。 + +完整代码如下: + +```yaml +identity: + author: Dify + name: google + label: + en_US: Google + zh_Hans: Google + pt_BR: Google + description: + en_US: Google + zh_Hans: GoogleSearch + pt_BR: Google + icon: icon.svg + tags: + - search +credentials_for_provider: #Add credentials_for_provider field + serpapi_api_key: + type: secret-input + required: true + label: + en_US: SerpApi API key + zh_Hans: SerpApi API key + placeholder: + en_US: Please input your SerpApi API key + zh_Hans: Please enter your SerpApi API key + help: + en_US: Get your SerpApi API key from SerpApi + zh_Hans: Get your SerpApi API key from SerpApi + url: https://serpapi.com/manage-api-key +tools: + - tools/google_search.yaml +extra: + python: + source: google.py +``` + +- `credentials_for_provider` 的子级结构需要满足[通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)的要求。 +- 你需要指定提供者包含哪些工具。本示例只包含一个 `tools/google_search.yaml` 文件。 +- 作为提供者,除了定义其基本信息外,还需要实现一些代码逻辑,因此需要指定其实现逻辑。在本示例中,我们将功能代码文件放在 `google.py` 中,但暂时不实现它,而是先编写 `google_search` 的代码。 + +#### 3. 填写工具 YAML 文件 + +一个工具插件可以有多个工具功能,每个工具功能都需要一个 `yaml` 文件进行描述,包括工具功能的基本信息、参数、输出等。 + +仍以 `GoogleSearch` 工具为例,在 `/tools` 文件夹中创建一个新的 `google_search.yaml` 文件。 + +```yaml +identity: + name: google_search + author: Dify + label: + en_US: GoogleSearch + zh_Hans: Google Search + pt_BR: GoogleSearch +description: + human: + en_US: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. + zh_Hans: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. + pt_BR: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. + llm: A tool for performing a Google SERP search and extracting snippets and webpages. Input should be a search query. +parameters: + - name: query + type: string + required: true + label: + en_US: Query string + zh_Hans: Query string + pt_BR: Query string + human_description: + en_US: used for searching + zh_Hans: used for searching web content + pt_BR: used for searching + llm_description: key words for searching + form: llm +extra: + python: + source: tools/google_search.py +``` + +- `identity` 包含工具的基本信息,包括名称、作者、标签、描述等。 +- `parameters` 参数列表 + - `name`(必填)参数名称,唯一,不能与其他参数同名。 + - `type`(必填)参数类型,目前支持 `string`、`number`、`boolean`、`select`、`secret-input` 五种类型,分别对应字符串、数字、布尔值、下拉框、加密输入框。对于敏感信息,请使用 `secret-input` 类型。 + - `label`(必填)参数标签,用于前端显示。 + - `form`(必填)表单类型,目前支持 `llm`、`form` 两种类型。 + - 在智能体应用中,`llm` 表示该参数由 LLM 自行推断,`form` 表示参数可以预先设置以使用此工具。 + - 在工作流应用中,`llm` 和 `form` 都需要由前端填写,但 `llm` 参数将用作工具节点的输入变量。 + - `required` 是否必填 + - 在 `llm` 模式下,如果参数是必填的,智能体将被要求推断此参数。 + - 在 `form` 模式下,如果参数是必填的,用户将被要求在对话开始前在前端填写此参数。 + - `options` 参数选项 + - 在 `llm` 模式下,Dify 会将所有选项传递给 LLM,LLM 可以根据这些选项进行推断。 + - 在 `form` 模式下,当 `type` 为 `select` 时,前端将显示这些选项。 + - `default` 默认值。 + - `min` 最小值,当参数类型为 `number` 时可以设置。 + - `max` 最大值,当参数类型为 `number` 时可以设置。 + - `human_description` 用于前端显示的介绍,支持多语言。 + - `placeholder` 输入字段的提示文本,当表单类型为 `form` 且参数类型为 `string`、`number`、`secret-input` 时可以设置,支持多语言。 + - `llm_description` 传递给 LLM 的介绍。为了让 LLM 更好地理解此参数,请在此处写尽可能详细的关于此参数的信息,以便 LLM 能够理解该参数。 + +#### 4. 准备工具代码 + +填写完工具的配置信息后,就可以开始编写工具功能的代码,实现工具的逻辑目的。在 `/tools` 目录中创建 `google_search.py`,内容如下: + +```python +from collections.abc import Generator +from typing import Any + +import requests + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +SERP_API_URL = "https://serpapi.com/search" + +class GoogleSearchTool(Tool): + def _parse_response(self, response: dict) -> dict: + result = {} + if "knowledge_graph" in response: + result["title"] = response["knowledge_graph"].get("title", "") + result["description"] = response["knowledge_graph"].get("description", "") + if "organic_results" in response: + result["organic_results"] = [ + { + "title": item.get("title", ""), + "link": item.get("link", ""), + "snippet": item.get("snippet", ""), + } + for item in response["organic_results"] + ] + return result + + def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: + params = { + "api_key": self.runtime.credentials["serpapi_api_key"], + "q": tool_parameters["query"], + "engine": "google", + "google_domain": "google.com", + "gl": "us", + "hl": "en", + } + + response = requests.get(url=SERP_API_URL, params=params, timeout=5) + response.raise_for_status() + valuable_res = self._parse_response(response.json()) + + yield self.create_json_message(valuable_res) +``` + +此示例表示请求 `serpapi` 并使用 `self.create_json_message` 返回格式化的 `json` 数据字符串。如果你想了解更多关于返回数据类型的信息,可以参考[远程调试插件](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)和[持久化存储 KV](/zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) 文档。 + +#### 4. 完善工具提供者代码 + +最后,你需要为提供者创建一个实现代码来实现凭据验证逻辑。如果凭据验证失败,将抛出 `ToolProviderCredentialValidationError` 异常。验证成功后,`google_search` 工具服务将被正确请求。 + +在 `/provider` 目录中创建 `google.py` 文件,内容如下: + +```python +from typing import Any + +from dify_plugin import ToolProvider +from dify_plugin.errors.tool import ToolProviderCredentialValidationError +from tools.google_search import GoogleSearchTool + +class GoogleProvider(ToolProvider): + def _validate_credentials(self, credentials: dict[str, Any]) -> None: + try: + for _ in GoogleSearchTool.from_credentials(credentials).invoke( + tool_parameters={"query": "test", "result_type": "link"}, + ): + pass + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) +``` + +### 调试插件 + +完成插件开发后,需要测试插件是否能正常工作。Dify 提供了便捷的远程调试方法,帮助你在测试环境中快速验证插件的功能。 + +前往["插件管理"](https://cloud.dify.ai/plugins)页面获取远程服务器地址和调试 Key。 + +![Remote Debug Key](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) + +返回插件项目,复制 `.env.example` 文件并重命名为 `.env`,然后填写你获取的远程服务器地址和调试 Key 信息。 + +`.env` 文件: + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_URL=debug.dify.ai:5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +运行 `python -m main` 命令启动插件。在插件页面上,你可以看到插件已安装在工作区中,团队的其他成员也可以访问该插件。 + +![](https://assets-docs.dify.ai/2024/11/0fe19a8386b1234755395018bc2e0e35.png) + +### 打包插件(可选) + +确认插件可以正常运行后,你可以使用以下命令行工具打包和命名插件。运行后,你会在当前文件夹中发现一个 `google.difypkg` 文件,这就是最终的插件包。 + +```bash +# Replace ./google with the actual path of the plugin project + +dify plugin package ./google +``` + +恭喜,你已经完成了工具类型插件的开发、调试和打包的整个流程! + +### 发布插件(可选) + +如果你想将插件发布到 Dify Marketplace,请确保你的插件符合[发布到 Dify Marketplace](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) 中的规范。通过审核后,代码将被合并到主分支并自动上架到 [Dify Marketplace](https://marketplace.dify.ai/)。 + +[发布概述](/zh/develop-plugin/publishing/marketplace-listing/release-overview) + +### 探索更多 + +#### **快速开始:** + +- [开发扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) +- [开发模型插件](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) +- [Bundle 插件:打包多个插件](/zh/develop-plugin/features-and-specs/advanced-development/bundle) + +#### **插件接口文档:** + +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - Manifest 结构和工具规范 +- [Endpoint](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 详细的 Endpoint 定义 +- [反向调用](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 反向调用 Dify 能力 +- [模型 Schema](/zh/develop-plugin/features-and-specs/plugin-types/model-schema) - 模型 +- [智能体插件](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 扩展智能体策略 + +## 下一步学习 + +- [远程调试插件](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - 学习更多高级调试技巧 +- [持久化存储](/zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) - 学习如何在插件中使用数据存储 +- [Slack Bot 插件开发示例](/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 查看更复杂的插件开发案例 +- [工具插件](/zh/develop-plugin/features-and-specs/plugin-types/tool) - 探索工具插件的高级功能 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/tool-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-zh/0222-trigger-plugin.mdx b/zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx similarity index 76% rename from plugin-dev-zh/0222-trigger-plugin.mdx rename to zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx index be402f41..cc5f741d 100644 --- a/plugin-dev-zh/0222-trigger-plugin.mdx +++ b/zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx @@ -2,83 +2,88 @@ title: "触发器插件" --- -## 触发器插件是什么? + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin)。 -Dify v1.10.0 引入了触发器(Trigger)类型的开始节点。区别于代码(Code)、工具(Tool)、知识检索(Knowledge Retrieval)等功能性节点,触发器的作用是**将第三方事件转化为 Dify 能接受的入参格式**。 +## 什么是触发器插件? + +触发器是 Dify v1.10.0 版本中引入的一种新型起始节点。与代码、工具或知识库检索等功能节点不同,触发器的目的是**将第三方事件转换为 Dify 可以识别和处理的输入格式**。 ![Trigger Plugin Intro](/images/trigger_plugin_intro.PNG) -例如,在 Gmail 中将事件的接收方配置为 Dify 后,每当你收到一封新邮件,Gmail 就会向 Dify 发送一个事件,可用于触发工作流。然而: +例如,如果你在 Gmail 中将 Dify 配置为 `new email` 事件接收器,每当收到新邮件时,Gmail 会自动向 Dify 发送一个可用于触发工作流的事件。然而: -- Gmail 的原始请求格式不是 Dify 可接受的格式; +- Gmail 的原始事件格式与 Dify 的输入格式不兼容。 -- 全世界有成千上万的平台,每个平台的格式都不尽相同。 +- 全球有数千个平台,每个平台都有其独特的事件格式。 -因此,我们需要触发器插件来定义和解析这些来自不同平台、不同格式的事件,并将它们统一为 Dify 可接受的标准入参格式。 +因此,我们需要触发器插件来定义和解析来自不同平台、各种格式的事件,并将它们统一为 Dify 可以接受的输入格式。 -## 技术原理 +## 技术概述 -Dify 触发器基于 Webhook 实现。Webhook 是互联网中广泛应用的机制,主流 SaaS 平台(如 Github、Slack、Linear 等)均支持 Webhook 并配有详细的开发文档。 +Dify 触发器基于 webhook 实现,这是一种在网络上被广泛采用的机制。许多主流 SaaS 平台(如 GitHub、Slack 和 Linear)都支持 webhook,并提供完善的开发者文档。 -Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事件接收地址后,这些 SaaS 平台会在指定事件发生时自动将其推送至目标服务器。** +Webhook 可以理解为一种基于 HTTP 的事件分发器。**一旦配置了事件接收地址,这些 SaaS 平台会在订阅的事件发生时自动将事件数据推送到目标服务器。** -为了统一处理来自不同平台的 Webhook 事件,Dify 抽象出两个核心概念:订阅(Subscription) 和事件(Event)。 +为了以统一的方式处理来自不同平台的 webhook 事件,Dify 定义了两个核心概念:**订阅(Subscription)**和**事件(Event)**。 -- **订阅**:如前所述,基于 Webhook 的事件派发有一个前提条件——**需要将 Dify 的网络地址作为目标服务器,配置在第三方平台的开发者后台中。这个配置过程在 Dify 中称为「订阅」。** +- **订阅(Subscription)**:基于 Webhook 的事件分发需要**在第三方平台的开发者控制台中将 Dify 的网络地址注册为目标服务器。在 Dify 中,这个配置过程称为*订阅*。** -- **事件**:一个平台可能会发送多种类型的事件,例如 *新邮件*、*邮件删除*、*邮件已读* 等,这些事件均会被推送至预先配置的地址。一个触发器插件可配置多个事件,一个事件对应 Dify 工作流中的一个触发器节点。 +- **事件(Event)**:一个平台可能发送多种类型的事件——例如*收到邮件*、*删除邮件*或*标记邮件为已读*——所有这些都会推送到注册的地址。触发器插件可以处理多种事件类型,每个事件对应 Dify 工作流中的一个插件触发器节点。 ## 插件开发 -触发器插件的开发方式与工具(Tool)、数据源(Data Source)、模型(Model)等插件类型一致,均可通过 `dify plugin init` 命令创建开发模板,其文件结构遵循统一的插件格式规范: +触发器插件的开发流程与其他插件类型(工具、数据源、模型等)一致。 + +你可以使用 `dify plugin init` 命令创建开发模板。生成的文件结构遵循标准的插件格式规范。 ``` ├── _assets -│   └── icon.svg +│ └── icon.svg ├── events -│   └── star -│   ├── star_created.py -│   └── star_created.yaml +│ └── star +│ ├── star_created.py +│ └── star_created.yaml ├── main.py ├── manifest.yaml ├── provider -│   ├── github.py -│   └── github.yaml +│ ├── github.py +│ └── github.yaml ├── README.md ├── PRIVACY.md └── requirements.txt ``` -- `manifest.yaml`:描述插件的基本信息。 -- `provider` 目录:包含插件供应商的描述信息、创建订阅的代码,以及接收 Webhook 请求后对事件进行分类的代码。 +- `manifest.yaml`:描述插件的基本元数据。 -- **`events` 目录:包含事件处理和筛选功能的代码,支持在节点端对事件进行本地筛选;每个目录下可创建二级目录,以便对事件进行分组。** +- `provider` 目录:包含提供者的元数据、创建订阅的代码,以及接收 webhook 请求后对事件进行分类的代码。 + +- **`events` 目录:包含事件处理和过滤的代码,支持在节点级别进行本地事件过滤。你可以创建子目录来分组相关事件。** - 在触发器插件中,最低 Dify 版本需设置为 `1.10.0`,SDK 版本需设置为大于等于 `0.6.0`。 + 对于触发器插件,Dify 最低版本必须设置为 `1.10.0`,SDK 版本必须 `>= 0.6.0`。 -下面以 GitHub 为例,介绍触发器插件的具体开发方法。 +接下来,我们将以 GitHub 为例来说明触发器插件的开发流程。 -### 订阅创建 +### 创建订阅 -在主流 SaaS 平台中,Webhook 的配置方式差异较大: +主流 SaaS 平台的 Webhook 配置方式差异很大: -- 部分平台(如 GitHub)支持通过 API 配置 Webhook。此类平台在 Dify 中完成 OAuth 鉴权后,Dify 即可自动完成 Webhook 配置。 +- 一些平台(如 GitHub)支持基于 API 的 webhook 配置。对于这些平台,一旦完成 OAuth 认证,Dify 可以自动设置 webhook。 -- 另一类平台(如 Notion)不仅不提供 Webhook API 配置功能,还要求用户手动完成部分校验工作。 +- 其他平台(如 Notion)不提供 webhook 配置 API,可能需要用户手动进行认证。 -因此,我们将订阅过程分为两个部分:Subscription Constructor 和 Subscription。 +为了适应这些差异,我们将订阅过程分为两部分:**订阅构造器(Subscription Constructor)**和**订阅(Subscription)**本身。 -对于 Notion 这类平台,订阅的创建需要用户手动将 Dify 提供的回调地址(Callback URL)复制粘贴到 Notion 后台中,以完成 Webhook 配置。此流程对应 Dify 界面中的 **粘贴 URL 以创建新订阅** 选项。 +对于像 Notion 这样的平台,创建订阅需要用户手动复制 Dify 提供的回调 URL,并将其粘贴到他们的 Notion 工作区以完成 webhook 设置。这个过程对应 Dify 界面中的**粘贴 URL 创建新订阅**选项。 -Paste URL to Create a New Subscription +粘贴 URL 创建新订阅 -若要实现通过手动复制 Callback URL 的方式创建订阅,需要修改 `github.yaml` 和 `github.py` 两个文件。 +要实现通过手动粘贴 URL 创建订阅,你需要修改两个文件:`github.yaml` 和 `github.py`。 - 由于 Github Webhook 存在加密机制,解密和校验请求需要使用密钥,因此需在 `github.yaml` 中声明 `webhook_secret`。 + 由于 GitHub webhook 使用加密机制,需要一个密钥来解密和验证传入的请求。因此,你需要在 `github.yaml` 中声明 `webhook_secret`。 ```YAML subscription_schema: @@ -97,16 +102,16 @@ Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事 - 首先,我们需要编写 `dispatch_event` 接口。所有发送到 Callback URL 的请求都会先经过该接口处理,处理后的事件将显示在界面上的 **请求日志** 中,便于调试与验证。 + 首先,我们需要实现 `dispatch_event` 接口。所有发送到回调 URL 的请求都由这个接口处理,处理后的事件将显示在**请求日志**部分,用于调试和验证。 - Manual Setup + 手动设置 - 在代码中,可通过 `subscription.properties` 获取在 `github.yaml` 中声明的 `webhook_secret`。 + 在代码中,你可以通过 `subscription.properties` 获取在 `github.yaml` 中声明的 `webhook_secret`。 - `dispatch_event` 方法需要根据请求内容判断该请求对应的事件类型。在以下示例中,事件提取由 `_dispatch_trigger_event` 方法完成。 + `dispatch_event` 方法需要根据请求内容确定事件类型。在下面的示例中,事件提取由 `_dispatch_trigger_event` 方法处理。 - 完整代码示例,请参考 [Dify GitHub 插件代码](https://github.com/langgenius/dify-plugin-sdks/tree/feat/trigger/python/examples/github_trigger)。 + 完整代码示例,请参阅 [Dify 的 GitHub 触发器插件](https://github.com/langgenius/dify-plugin-sdks/tree/feat/trigger/python/examples/github_trigger)。 ```Python @@ -132,9 +137,9 @@ Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事 ### 事件处理 -提取出事件后,需要由相应的事件实现对原始 HTTP 请求进行过滤,并将其转换为 Dify 工作流可接受的入参。 +一旦提取了事件,相应的实现必须过滤原始 HTTP 请求并将其转换为 Dify 工作流可以接受的输入格式。 -以 Issue 事件为例,可分别通过 `events/issues/issues.yaml` 和 `events/issues/issues.py` 来定义事件与实现事件。事件的输出可在 `issues.yaml` 的 `output_schema` 中定义,与工具类型插件相同,遵循 JSON Schema 规范。 +以 Issue 事件为例,你可以分别通过 `events/issues/issues.yaml` 和 `events/issues/issues.py` 定义事件及其实现。事件的输出可以在 `issues.yaml` 的 `output_schema` 部分定义,它遵循与工具插件相同的 JSON Schema 规范。 @@ -198,7 +203,7 @@ Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事 ### 事件过滤 -若希望插件能够筛选掉部分事件,例如只关注具有某个特定标签的 Issue 事件,可在事件定义中为 Issue 事件添加 `parameters`。在 `_on_event` 方法中,通过抛出 `EventIgnoreError` 异常,即可在实际运行中根据配置的参数过滤掉不符合条件的事件。 +要过滤掉某些事件——例如,只关注具有特定标签的 Issue 事件——你可以在 `issues.yaml` 的事件定义中添加 `parameters`。然后,在 `_on_event` 方法中,你可以抛出 `EventIgnoreError` 异常来过滤掉不符合配置条件的事件。 @@ -245,13 +250,13 @@ Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事 -### 通过 OAuth 或 API key 创建订阅 +### 通过 OAuth 或 API 密钥创建订阅 -若要实现通过 OAuth 或 API key 自动创建订阅,同样需要修改 `github.yaml` 和 `github.py` 两个文件。 +要启用通过 OAuth 或 API 密钥自动创建订阅,你需要修改 `github.yaml` 和 `github.py` 文件。 - 在 `github.yaml` 中,添加如下字段。 + 在 `github.yaml` 中,添加以下字段。 ```YAML subscription_constructor: @@ -292,16 +297,17 @@ Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事 python: source: provider/github.py ``` - `subscription_constructor` 是 Dify 抽象出的一个概念,用于定义如何构建订阅,包含以下字段: - - `parameters`(可选):用于定义创建订阅时所需的参数,例如想要订阅的事件类型或目标 GitHub 仓库等。 + `subscription_constructor` 是 Dify 抽象出来的一个概念,用于定义如何构造订阅。它包含以下字段: - - `credentials_schema`(可选):通过 API key 创建订阅时,必须填写该字段以声明所需的密钥,例如在 GitHub 中定义 `access_tokens`。 + - `parameters`(可选):定义创建订阅所需的参数,例如要订阅的事件类型或目标 GitHub 仓库 - - `oauth_schema`(可选):通过 OAuth 创建订阅时,必须填写该字段以启用 OAuth 鉴权。具体定义方式,可参考 [为插件添加 OAuth 支持](/plugin-dev-zh/0222-tool-oauth)。 + - `credentials_schema`(可选):声明使用 API 密钥或访问令牌创建订阅所需的凭据,例如 GitHub 的 `access_tokens`。 + + - `oauth_schema`(可选):实现通过 OAuth 创建订阅时需要。有关如何定义它的详细信息,请参阅[为你的工具插件添加 OAuth 支持](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-oauth)。 - 在 `github.py` 中创建一个 `Constructor` 类,以实现自动化订阅逻辑。 + 在 `github.py` 中,创建一个 `Constructor` 类来实现自动订阅逻辑。 ```Python class GithubSubscriptionConstructor(TriggerSubscriptionConstructor): @@ -378,13 +384,13 @@ Webhook 可理解为基于 HTTP 协议的事件派发中心。**当配置好事 --- -完成以上两个文件的配置后,你将在 Dify 界面中看到 **通过 API Key 创建** 选项。 +修改完这两个文件后,你将在 Dify 界面中看到**使用 API 密钥创建**选项。 -通过 OAuth 的订阅自动创建也可以在 `Constructor` 中实现:在 `subscription_constructor` 中添加 `oauth_schema` 字段,即可启用 OAuth 认证方式。 +通过 OAuth 自动创建订阅也可以在同一个 `Constructor` 类中实现:通过在 `subscription_constructor` 下添加 `oauth_schema` 字段,即可启用 OAuth 认证。 -![OAuth & API Key Options](/images/trigger_plugin_oauth_apikey.png) +OAuth 和 API 密钥选项 -## 探索更多 +## 深入探索 触发器插件开发中核心类的接口定义和实现方法如下。 @@ -656,5 +662,4 @@ It will be automatically generated by the script. --- -[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-zh/0222-trigger-plugin.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/advanced-development/bundle.mdx b/zh/develop-plugin/features-and-specs/advanced-development/bundle.mdx new file mode 100644 index 00000000..de4786b1 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/advanced-development/bundle.mdx @@ -0,0 +1,106 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: beginner +standard_title: Bundle +language: en +title: Bundle 插件包 +description: 本文档介绍 Bundle 插件包的概念和开发方法。Bundle 插件包可以将多个插件聚合在一起,支持三种类型(Marketplace、GitHub 和 Package)。文档详细介绍了创建 Bundle 项目、添加不同类型依赖以及打包 Bundle 项目的整个流程。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/bundle)。 + +Bundle 插件包是多个插件的集合。它允许在单个插件中打包多个插件,实现批量安装并提供更强大的服务。 + +你可以使用 Dify CLI 工具将多个插件打包成一个 Bundle。Bundle 插件包分为三种类型: + +* `Marketplace` 类型。存储插件的 ID 和版本信息。导入时,将从 Dify Marketplace 下载特定的插件包。 +* `GitHub` 类型。存储 GitHub 仓库地址、发布版本号和资源文件名。导入时,Dify 将访问对应的 GitHub 仓库下载插件包。 +* `Package` 类型。插件包直接存储在 Bundle 内部。它不存储引用来源,但这可能导致 Bundle 包体积较大。 + +### 前置条件 + +* Dify 插件脚手架工具 +* Python 环境,版本 ≥ 3.10 + +有关如何准备插件开发脚手架工具的详细说明,请参阅[初始化开发工具](/zh/develop-plugin/getting-started/cli)。 + +### 创建 Bundle 项目 + +在当前目录下,运行脚手架命令行工具创建新的插件包项目。 + +```bash +./dify-plugin-darwin-arm64 bundle init +``` + +如果你已将二进制文件重命名为 `dify` 并复制到 `/usr/local/bin` 路径,可以运行以下命令创建新的插件项目: + +```bash +dify bundle init +``` + +#### 1. 填写插件信息 + +按照提示配置插件名称、作者信息和插件描述。如果你是团队协作,也可以输入组织名称作为作者。 + +> 名称长度必须为 1-128 个字符,只能包含字母、数字、连字符和下划线。 + +![Bundle 基本信息](https://assets-docs.dify.ai/2024/12/03a1c4cdc72213f09523eb1b40832279.png) + +填写信息并按 Enter 后,将自动创建 Bundle 插件项目目录。 + +![](https://assets-docs.dify.ai/2024/12/356d1a8201fac3759bf01ee64e79a52b.png) + +#### 2. 添加依赖 + +* **Marketplace** + +执行以下命令: + +```bash +dify-plugin bundle append marketplace . --marketplace_pattern=langgenius/openai:0.0.1 +``` + +其中 `marketplace_pattern` 是插件在 marketplace 中的引用,格式为 `organization_name/plugin_name:version_number`。 + +* **GitHub** + +执行以下命令: + +```bash +dify-plugin bundle append github . --repo_pattern=langgenius/openai:0.0.1/openai.difypkg +``` + +其中 `repo_pattern` 是插件在 GitHub 上的引用,格式为 `organization_name/repository_name:release/asset_name`。 + +* **Package** + +执行以下命令: + +```bash +dify-plugin bundle append package . --package_path=./openai.difypkg +``` + +其中 `package_path` 是插件包的目录。 + +### 打包 Bundle 项目 + +运行以下命令打包 Bundle 插件: + +```bash +dify-plugin bundle package ./bundle +``` + +执行命令后,将在当前目录自动创建 `bundle.difybndl` 文件。该文件即为最终的打包结果。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/bundle.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx b/zh/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx new file mode 100644 index 00000000..c24fc8cf --- /dev/null +++ b/zh/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx @@ -0,0 +1,360 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: advanced +standard_title: Customizable Model +language: en +title: 集成自定义模型 +description: 本文档详细介绍了如何将自定义模型集成到 Dify 中,以 Xinference 模型为例。它涵盖了完整的流程,包括创建模型供应商文件、根据模型类型编写代码、实现模型调用逻辑、处理异常、调试和发布。具体详细说明了 LLM 调用、令牌计算、凭据验证和参数生成等核心方法的实现。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/customizable-model)。 + +**自定义模型**是指您自行部署或配置的 LLM。本文档以 [Xinference 模型](https://inference.readthedocs.io/en/latest/)为例,演示如何将自定义模型集成到您的**模型插件**中。 + +默认情况下,自定义模型自动包含两个参数——其**模型类型**和**模型名称**——无需在供应商 YAML 文件中进行额外定义。 + +您无需在供应商配置文件中实现 `validate_provider_credential`。在运行时,根据用户选择的模型类型或模型名称,Dify 会自动调用相应模型层的 `validate_credentials` 方法来验证凭据。 + +## 集成自定义模型插件 + +以下是集成自定义模型的步骤: + +1. **创建模型供应商文件**\ + 确定您的自定义模型将包含的模型类型。 +2. **按模型类型创建代码文件**\ + 根据模型的类型(例如 `llm` 或 `text_embedding`),创建单独的代码文件。确保每种模型类型都组织成不同的逻辑层,以便于维护和未来扩展。 +3. **开发模型调用逻辑**\ + 在每个模型类型模块中,创建一个以该模型类型命名的 Python 文件(例如 `llm.py`)。在文件中定义一个类,实现特定的模型逻辑,符合系统的模型接口规范。 +4. **调试插件**\ + 为新的供应商功能编写单元测试和集成测试,确保所有组件按预期工作。 + +*** + +### 1. **创建模型供应商文件** + +在插件的 `/provider` 目录中,创建一个 `xinference.yaml` 文件。 + +`Xinference` 系列模型支持 **LLM**、**Text Embedding** 和 **Rerank** 模型类型,因此您的 `xinference.yaml` 必须包含所有三种类型。 + +**示例:** + +```yaml +provider: xinference # Identifies the provider +label: # Display name; can set both en_US (English) and zh_Hans (Chinese). If zh_Hans is not set, en_US is used by default. + en_US: Xorbits Inference +icon_small: # Small icon; store in the _assets folder of this provider's directory. The same multi-language logic applies as with label. + en_US: icon_s_en.svg +icon_large: # Large icon + en_US: icon_l_en.svg +help: # Help information + title: + en_US: How to deploy Xinference + zh_Hans: 如何部署 Xinference + url: + en_US: https://github.com/xorbitsai/inference + +supported_model_types: # Model types Xinference supports: LLM/Text Embedding/Rerank +- llm +- text-embedding +- rerank + +configurate_methods: # Xinference is locally deployed and does not offer predefined models. Refer to its documentation to learn which model to use. Thus, we choose a customizable-model approach. +- customizable-model + +provider_credential_schema: + credential_form_schemas: +``` + +接下来,定义 `provider_credential_schema`。由于 `Xinference` 支持文本生成、嵌入和重排序模型,您可以按如下方式配置: + +```yaml +provider_credential_schema: + credential_form_schemas: + - variable: model_type + type: select + label: + en_US: Model type + zh_Hans: 模型类型 + required: true + options: + - value: text-generation + label: + en_US: Language Model + zh_Hans: 语言模型 + - value: embeddings + label: + en_US: Text Embedding + - value: reranking + label: + en_US: Rerank +``` + +Xinference 中的每个模型都需要一个 `model_name`: + +```yaml + - variable: model_name + type: text-input + label: + en_US: Model name + zh_Hans: 模型名称 + required: true + placeholder: + zh_Hans: 填写模型名称 + en_US: Input model name +``` + +由于 Xinference 必须在本地部署,用户需要提供服务器地址(server\_url)和模型 UID。例如: + +```yaml + - variable: server_url + label: + zh_Hans: 服务器 URL + en_US: Server url + type: text-input + required: true + placeholder: + zh_Hans: 在此输入 Xinference 的服务器地址,如 https://example.com/xxx + en_US: Enter the url of your Xinference, for example https://example.com/xxx + + - variable: model_uid + label: + zh_Hans: 模型 UID + en_US: Model uid + type: text-input + required: true + placeholder: + zh_Hans: 在此输入你的 Model UID + en_US: Enter the model uid +``` + +定义完这些参数后,自定义模型供应商的 YAML 配置就完成了。接下来,为此配置中定义的每个模型创建功能代码文件。 + +### 2. 开发模型代码 + +由于 Xinference 支持 llm、rerank、speech2text 和 tts,您应该在 /models 下创建相应的目录,每个目录包含其各自的功能代码。 + +以下是 llm 类型模型的示例。您需要创建一个名为 llm.py 的文件,然后定义一个类——例如 XinferenceAILargeLanguageModel——继承自 \_\_base.large\_language\_model.LargeLanguageModel。该类应包含: + +* **LLM 调用** + +调用 LLM 的核心方法,支持流式和同步响应: + +```python +def _invoke( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + model_parameters: dict, + tools: Optional[list[PromptMessageTool]] = None, + stop: Optional[list[str]] = None, + stream: bool = True, + user: Optional[str] = None +) -> Union[LLMResult, Generator]: + """ + Invoke the large language model. + + :param model: model name + :param credentials: model credentials + :param prompt_messages: prompt messages + :param model_parameters: model parameters + :param tools: tools for tool calling + :param stop: stop words + :param stream: determines if response is streamed + :param user: unique user id + :return: full response or a chunk generator + """ +``` + +您需要两个单独的函数来处理流式和同步响应。Python 将任何包含 `yield` 的函数视为返回 `Generator` 类型的生成器,因此最好将它们分开: + +```yaml +def _invoke(self, stream: bool, **kwargs) -> Union[LLMResult, Generator]: + if stream: + return self._handle_stream_response(**kwargs) + return self._handle_sync_response(**kwargs) + +def _handle_stream_response(self, **kwargs) -> Generator: + for chunk in response: + yield chunk + +def _handle_sync_response(self, **kwargs) -> LLMResult: + return LLMResult(**response) +``` + +* **预计算输入令牌** + +如果您的模型不提供令牌计数接口,只需返回 0: + +```python +def get_num_tokens( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + tools: Optional[list[PromptMessageTool]] = None +) -> int: + """ + Get the number of tokens for the given prompt messages. + """ + return 0 +``` + +或者,您可以从 `AIModel` 基类调用 `self._get_num_tokens_by_gpt2(text: str)`,它使用 GPT-2 分词器。请记住这只是一个近似值,可能与您的模型不完全匹配。 + +* **验证模型凭据** + +类似于供应商级别的凭据检查,但范围限定于单个模型: + +```python +def validate_credentials(self, model: str, credentials: dict) -> None: + """ + Validate model credentials. + """ +``` + +* **动态模型参数模式** + +与[预定义模型](/zhplugins/quick-start/develop-plugins/model-plugin/predefined-model)不同,没有 YAML 定义模型支持哪些参数。您必须动态生成参数模式。 + +例如,Xinference 支持 `max_tokens`、`temperature` 和 `top_p`。某些其他供应商(例如 `OpenLLM`)可能仅对某些模型支持 `top_k` 等参数。这意味着您需要根据每个模型的能力调整您的模式: + +```python +def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity | None: + """ + used to define customizable model schema + """ + rules = [ + ParameterRule( + name='temperature', type=ParameterType.FLOAT, + use_template='temperature', + label=I18nObject( + zh_Hans='温度', en_US='Temperature' + ) + ), + ParameterRule( + name='top_p', type=ParameterType.FLOAT, + use_template='top_p', + label=I18nObject( + zh_Hans='Top P', en_US='Top P' + ) + ), + ParameterRule( + name='max_tokens', type=ParameterType.INT, + use_template='max_tokens', + min=1, + default=512, + label=I18nObject( + zh_Hans='最大生成长度', en_US='Max Tokens' + ) + ) + ] + + # if model is A, add top_k to rules + if model == 'A': + rules.append( + ParameterRule( + name='top_k', type=ParameterType.INT, + use_template='top_k', + min=1, + default=50, + label=I18nObject( + zh_Hans='Top K', en_US='Top K' + ) + ) + ) + + """ + some NOT IMPORTANT code here + """ + + entity = AIModelEntity( + model=model, + label=I18nObject( + en_US=model + ), + fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, + model_type=model_type, + model_properties={ + ModelPropertyKey.MODE: ModelType.LLM, + }, + parameter_rules=rules + ) + + return entity +``` + +* **错误映射** + +当模型调用过程中发生错误时,将其映射到运行时识别的适当 InvokeError 类型。这使 Dify 能够以标准化的方式处理不同的错误: + +运行时错误: + +``` +• `InvokeConnectionError` +• `InvokeServerUnavailableError` +• `InvokeRateLimitError` +• `InvokeAuthorizationError` +• `InvokeBadRequestError` +``` + +```python +@property +def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + Map model invocation errors to unified error types. + The key is the error type thrown to the caller. + The value is the error type thrown by the model, which needs to be mapped to a + unified Dify error for consistent handling. + """ + # return { + # InvokeConnectionError: [requests.exceptions.ConnectionError], + # ... + # } +``` + +有关接口方法的更多详细信息,请参阅[模型文档](https://docs.dify.ai/zh-hans/plugins/schema-definition/model)。 + +要查看本指南中讨论的完整代码文件,请访问 [GitHub 仓库](https://github.com/langgenius/dify-official-plugins/tree/main/models/xinference)。 + +### 3. 调试插件 + +完成开发后,测试插件以确保其正常运行。有关更多详细信息,请参阅: + + + + +### 4. 发布插件 + +如果您想在 Dify Marketplace 上列出此插件,请参阅: + +发布到 Dify Marketplace + +## 探索更多 + +**快速开始:** + +* [开发扩展插件](/zhplugins/quick-start/develop-plugins/extension-plugin) +* [开发工具插件](/zhplugins/quick-start/develop-plugins/tool-plugin) +* [Bundle 插件:打包多个插件](/zhplugins/quick-start/develop-plugins/bundle) + +**插件端点文档:** + +* [Manifest](/zhplugins/schema-definition/manifest) 结构 +* [Endpoint](/zhplugins/schema-definition/endpoint) 定义 +* [反向调用 Dify 服务](/zhplugins/schema-definition/reverse-invocation-of-the-dify-service) +* [工具](/zhplugins/schema-definition/tool) +* [模型](/zhplugins/schema-definition/model) + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/customizable-model.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx new file mode 100644 index 00000000..f39088dc --- /dev/null +++ b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx @@ -0,0 +1,142 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: intermediate +standard_title: Reverse Invocation App +language: en +title: 应用 +description: 本文档详细介绍了插件如何在 Dify 平台内反向调用应用服务。涵盖三种接口类型:Chat 接口(用于 Chatbot/Agent/Chatflow 应用)、工作流接口和 Completion 接口,为每种接口提供入口点、调用规范和实用代码示例。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app)。 + +反向调用应用意味着插件可以访问 Dify 内应用的数据。此模块支持流式和非流式应用调用。如果你不熟悉反向调用的基本概念,请先阅读[反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation)。 + +**接口类型:** + +* 对于 `Chatbot/Agent/Chatflow` 类型的应用,它们都是基于对话的应用,因此共享相同的输入和输出参数类型。因此,它们可以统一视为 **Chat 接口。** +* 对于工作流应用,它们占用单独的**工作流接口。** +* 对于 Completion(文本生成应用)应用,它们占用单独的 **Completion 接口**。 + +请注意,插件只允许访问插件所在工作空间内的应用。 + +### 调用 Chat 接口 + +#### **入口点** + +```python + self.session.app.chat +``` + +#### **接口规范** + +```python + def invoke( + self, + app_id: str, + inputs: dict, + response_mode: Literal["streaming", "blocking"], + conversation_id: str, + files: list, + ) -> Generator[dict, None, None] | dict: + pass +``` + +当 `response_mode` 为 `streaming` 时,此接口将直接返回 `Generator[dict]`。否则,返回 `dict`。有关具体接口字段,请参阅 `ServiceApi` 的返回结果。 + +#### **使用场景** + +我们可以在 `Endpoint` 内调用 Chat 类型的应用并直接返回结果。 + +```python +import json +from typing import Mapping +from werkzeug import Request, Response +from dify_plugin import Endpoint + +class Duck(Endpoint): + def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response: + """ + Invokes the endpoint with the given request. + """ + app_id = values["app_id"] + + def generator(): + # Note: The original example incorrectly called self.session.app.workflow.invoke + # It should call self.session.app.chat.invoke for a chat app. + # Assuming a chat app is intended here based on the section title. + response = self.session.app.chat.invoke( + app_id=app_id, + inputs={}, # Provide actual inputs as needed + response_mode="streaming", + conversation_id="some-conversation-id", # Provide a conversation ID if needed + files=[] + ) + + for data in response: + yield f"{json.dumps(data)}
" + + return Response(generator(), status=200, content_type="text/html") +``` + +### 调用工作流接口 + +#### **入口点** + +```python + self.session.app.workflow +``` + +#### **接口规范** + +```python + def invoke( + self, + app_id: str, + inputs: dict, + response_mode: Literal["streaming", "blocking"], + files: list, + ) -> Generator[dict, None, None] | dict: + pass +``` + +### 调用 Completion 接口 + +#### **入口点** + +```python + self.session.app.completion +``` + +**接口规范** + +```python + def invoke( + self, + app_id: str, + inputs: dict, + response_mode: Literal["streaming", "blocking"], + files: list, + ) -> Generator[dict, None, None] | dict: + pass +``` + +## 相关资源 + +- [反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 了解反向调用的基本概念 +- [反向调用模型](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) - 学习如何调用平台内的模型能力 +- [反向调用工具](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) - 学习如何调用其他插件 +- [开发 Slack Bot 插件](/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 使用反向调用的实际应用案例 +- [开发扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 学习如何开发扩展插件 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-zh/9242-reverse-invocation-model.mdx b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx similarity index 57% rename from plugin-dev-zh/9242-reverse-invocation-model.mdx rename to zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx index f3347eec..b13e28ae 100644 --- a/plugin-dev-zh/9242-reverse-invocation-model.mdx +++ b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx @@ -5,26 +5,28 @@ dimensions: detail: advanced level: intermediate standard_title: Reverse Invocation Model -language: zh -title: Model -description: 本文档详细介绍了插件如何反向调用Dify平台中的模型服务。内容包括反向调用LLM、Summary、TextEmbedding、Rerank、TTS、Speech2Text和Moderation等模型的具体方法,每种模型调用都配有对应的入口、接口参数说明以及实际的使用示例代码,并提供了调用模型的最佳实践建议。 +language: en +title: 反向调用模型 +description: 本文档详细介绍了插件如何在 Dify 平台内反向调用模型服务。涵盖了反向调用 LLM、Summary、TextEmbedding、Rerank、TTS、Speech2Text 和 Moderation 模型的具体方法。每个模型调用都包括其入口点、接口参数说明、实际使用代码示例以及调用模型的最佳实践建议。 --- -反向调用 Model 指的是插件能够反向调用 Dify 内 LLM 的能力,包括平台内的所有模型类型与功能,例如 TTS、Rerank 等。如果你对反向调用的基本概念还不熟悉,请先阅读[反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation)。 + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model)。 -不过请注意,调用模型需要传入一个 `ModelConfig` 类型的参数,它的结构可以参考 [通用规范定义](/plugin-dev-zh/0411-general-specifications),并且对于不同类型的模型,该结构会存在细微的差别。 +反向调用模型是指插件能够调用 Dify 内部的 LLM 能力,包括平台内的所有模型类型和功能,如 TTS、Rerank 等。如果您不熟悉反向调用的基本概念,请先阅读[反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation)。 -例如对于 `LLM` 类型的模型,还需要包含 `completion_params` 与 `mode` 参数,你可以手动构建该结构,或者使用 `model-selector` 类型的参数或配置。 +但请注意,调用模型需要传递 `ModelConfig` 类型的参数。其结构可以参考[通用规范定义](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications),并且该结构对于不同类型的模型会有细微差异。 + +例如,对于 `LLM` 类型的模型,还需要包含 `completion_params` 和 `mode` 参数。您可以手动构建此结构,或使用 `model-selector` 类型的参数或配置。 ### 调用 LLM -#### **入口** +#### **入口点** ```python self.session.model.llm ``` -#### **端点** +#### **接口** ```python def invoke( @@ -38,11 +40,11 @@ description: 本文档详细介绍了插件如何反向调用Dify平台中的模 pass ``` -请注意,如果你调用的模型不具备 `tool_call` 的能力,那么此处传入的 `tools` 将不会生效。 +请注意,如果您调用的模型不具备 `tool_call` 能力,这里传递的 `tools` 将不会生效。 -#### **用例** +#### **使用示例** -如果想在 `Tool` 中调用 `OpenAI` 的 `gpt-4o-mini` 模型,请参考以下示例代码: +如果您想在 `Tool` 中调用 OpenAI 的 `gpt-4o-mini` 模型,请参考以下示例代码: ```python from collections.abc import Generator @@ -79,11 +81,11 @@ class LLMTool(Tool): yield self.create_text_message(text=chunk.delta.message.content) ``` -可以留意到代码中传入了 `tool_parameters` 中的 `query` 参数。 +请注意,代码中传入了 `tool_parameters` 中的 `query` 参数。 ### **最佳实践** -并不建议手动来构建 `LLMModelConfig`,而是允许用户可以在 UI 上选择自己想使用的模型,在这种情况下可以修改一下工具的参数列表,按照如下配置,添加一个 `model` 参数: +不建议手动构建 `LLMModelConfig`。相反,应该允许用户在 UI 上选择他们想要使用的模型。在这种情况下,您可以通过添加 `model` 参数来修改工具的参数列表,如下所示: ```yaml identity: @@ -132,7 +134,7 @@ extra: source: tools/llm.py ``` -请注意在该例子中指定了 `model` 的 `scope` 为 `llm`,那么此时用户就只能选择 `llm` 类型的参数,从而可以将上述用例的代码改成以下代码: +请注意,在此示例中,`model` 的 `scope` 被指定为 `llm`。这意味着用户只能选择 `llm` 类型的参数。因此,前面使用示例中的代码可以修改如下: ```python from collections.abc import Generator @@ -152,7 +154,7 @@ class LLMTool(Tool): content='you are a helpful assistant' ), UserPromptMessage( - content=tool_parameters.get('query') + content=tool_parameters.get('query') # Assuming 'query' is still needed, otherwise use 'prompt' from parameters ) ], stream=True @@ -166,18 +168,18 @@ class LLMTool(Tool): ### 调用 Summary -你可以请求该端点来总结一段文本,它会使用你当前 workspace 内的系统模型来总结文本。 +您可以请求此接口来总结一段文本。它将使用当前工作空间内的系统模型来总结文本。 -**入口** +**入口点** ```python self.session.model.summary ``` -**端点** +**接口** -* `text` 为需要被总结的文本。 -* `instruction` 为你想要额外添加的指令,它可以让你风格化地总结文本。 +* `text` 是要总结的文本。 +* `instruction` 是您想要添加的额外指令,允许您按照特定风格总结文本。 ```python def invoke( @@ -187,13 +189,13 @@ class LLMTool(Tool): ### 调用 TextEmbedding -**入口** +**入口点** ```python self.session.model.text_embedding ``` -**端点** +**接口** ```python def invoke( @@ -204,13 +206,13 @@ class LLMTool(Tool): ### 调用 Rerank -**入口** +**入口点** ```python self.session.model.rerank ``` -**端点** +**接口** ```python def invoke( @@ -221,13 +223,13 @@ class LLMTool(Tool): ### 调用 TTS -**入口** +**入口点** ```python self.session.model.tts ``` -**端点** +**接口** ```python def invoke( @@ -236,17 +238,17 @@ class LLMTool(Tool): pass ``` -请注意 `tts` 端点返回的 `bytes` 流是一个 `mp3` 音频字节流,每一轮迭代返回的都是一个完整的音频。如果你想做更深入的处理任务,请选择合适的库进行。 +请注意,`tts` 接口返回的 `bytes` 流是 `mp3` 音频字节流。每次迭代返回一个完整的音频片段。如果您想要进行更深入的处理任务,请选择合适的库。 ### 调用 Speech2Text -**入口** +**入口点** ```python self.session.model.speech2text ``` -**端点** +**接口** ```python def invoke( @@ -255,32 +257,32 @@ class LLMTool(Tool): pass ``` -其中 `file` 是一个 `mp3` 格式编码的音频文件。 +其中 `file` 是以 `mp3` 格式编码的音频文件。 ### 调用 Moderation -**入口** +**入口点** ```python self.session.model.moderation ``` -**端点** +**接口** ```python def invoke(self, model_config: ModerationModelConfig, text: str) -> bool: pass ``` -若该端点返回 `true` 则表示 `text` 中包含敏感内容。 +如果此接口返回 `true`,表示 `text` 包含敏感内容。 ## 相关资源 -- [反向调用 Dify 服务](/plugin-dev-zh/9241-reverse-invocation) - 了解反向调用的根本概念 -- [反向调用 App](/plugin-dev-zh/9242-reverse-invocation-app) - 了解如何调用平台内的 App -- [反向调用 Tool](/plugin-dev-zh/9242-reverse-invocation-tool) - 了解如何调用其它插件 -- [模型插件开发指南](/plugin-dev-zh/0211-getting-started-new-model) - 学习如何开发自定义模型插件 -- [模型设计规则](/plugin-dev-zh/0411-model-designing-rules) - 了解模型插件的设计原则 +- [反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 了解反向调用的基本概念 +- [反向调用应用](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - 了解如何调用平台内的应用 +- [反向调用工具](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) - 了解如何调用其他插件 +- [模型插件开发指南](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 了解如何开发自定义模型插件 +- [模型设计规则](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - 了解模型插件的设计原则 {/* Contributing Section @@ -290,5 +292,4 @@ It will be automatically generated by the script. --- -[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-zh/9242-reverse-invocation-model.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx new file mode 100644 index 00000000..91b9281a --- /dev/null +++ b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx @@ -0,0 +1,110 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: advanced +standard_title: Reverse Invocation Node +language: en +title: 节点 +description: 本文档描述了插件如何在 Dify 平台内反向调用 Chatflow/Workflow 应用节点的功能。主要涵盖两个特定节点 ParameterExtractor 和 QuestionClassifier 的调用方法。文档详细介绍了调用这两个节点的入口、接口参数和示例代码。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node)。 + +反向调用节点意味着插件可以访问 Dify Chatflow/工作流应用中某些节点的能力。 + +`Workflow` 中的 `ParameterExtractor` 和 `QuestionClassifier` 节点封装了复杂的提示词和代码逻辑,能够通过 LLM 完成难以用硬编码解决的任务。插件可以调用这两个节点。 + +### 调用参数提取器节点 + +#### **入口** + +```python + self.session.workflow_node.parameter_extractor +``` + +#### **接口** + +```python + def invoke( + self, + parameters: list[ParameterConfig], + model: ModelConfig, + query: str, + instruction: str = "", + ) -> NodeResponse + pass +``` + +其中,`parameters` 是要提取的参数列表,`model` 符合 `LLMModelConfig` 规范,`query` 是用于参数提取的源文本,`instruction` 提供 LLM 可能需要的任何附加指令。关于 `NodeResponse` 的结构,请参阅此[文档](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx#noderesponse)。 + +#### **使用场景** + +要从对话中提取人名,可以参考以下代码: + +```python +from collections.abc import Generator +from dify_plugin.entities.tool import ToolInvokeMessage +from dify_plugin import Tool +from dify_plugin.entities.workflow_node import ModelConfig, ParameterConfig, NodeResponse # Assuming NodeResponse is importable + +class ParameterExtractorTool(Tool): + def _invoke( + self, tool_parameters: dict + ) -> Generator[ToolInvokeMessage, None, None]: + response: NodeResponse = self.session.workflow_node.parameter_extractor.invoke( + parameters=[ + ParameterConfig( + name="name", + description="name of the person", + required=True, + type="string", + ) + ], + model=ModelConfig( + provider="langgenius/openai/openai", + name="gpt-4o-mini", + completion_params={}, + ), + query="My name is John Doe", + instruction="Extract the name of the person", + ) + + # Assuming NodeResponse has an 'outputs' attribute which is a dictionary + extracted_name = response.outputs.get("name", "Name not found") + yield self.create_text_message(extracted_name) +``` + +### 调用问题分类器节点 + +#### **入口** + +```python + self.session.workflow_node.question_classifier +``` + +#### **接口** + +```python + def invoke( + self, + classes: list[ClassConfig], # Assuming ClassConfig is defined/imported + model: ModelConfig, + query: str, + instruction: str = "", + ) -> NodeResponse: + pass +``` + +接口参数与 `ParameterExtractor` 一致。最终结果存储在 `NodeResponse.outputs['class_name']` 中。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx new file mode 100644 index 00000000..5135e398 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx @@ -0,0 +1,104 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: intermediate +standard_title: Reverse Invocation Tool +language: en +title: 工具 +description: 本文档详细介绍了插件如何在 Dify 平台内反向调用工具服务。涵盖三种工具调用方式:调用已安装工具(Built-in Tool)、调用工作流作为工具(Workflow as Tool)以及调用自定义工具(Custom Tool)。每种方式都包含相应的入口点和接口参数说明。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool)。 + +反向调用工具意味着插件可以调用 Dify 平台内的其他工具类型插件。如果您不熟悉反向调用的基本概念,请先阅读[反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation)。 + +考虑以下场景: + +* 一个工具类型插件实现了某个功能,但结果不如预期,需要对数据进行后处理。 +* 某个任务需要网页爬虫,而您希望灵活选择爬取服务。 +* 您需要聚合多个工具的结果,但使用工作流应用难以处理。 + +在这些情况下,您需要在插件中调用其他现有工具。这些工具可能来自市场、自建的工作流作为工具,或自定义工具。 + +这些需求可以通过调用插件的 `self.session.tool` 字段来满足。 + +### 调用已安装工具 + +允许插件调用当前工作区中安装的各种工具,包括其他工具类型插件。 + +**入口点** + +```python + self.session.tool +``` + +**接口** + +```python + def invoke_builtin_tool( + self, provider: str, tool_name: str, parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + pass +``` + +这里,`provider` 是插件 ID 加上工具提供者名称,格式如 `langgenius/google/google`。`tool_name` 是具体的工具名称,`parameters` 是传递给工具的参数。 + +### 调用工作流作为工具 + +有关工作流作为工具的更多信息,请参阅[工具插件文档](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)。 + +**入口点** + +```python + self.session.tool +``` + +**接口** + +```python + def invoke_workflow_tool( + self, provider: str, tool_name: str, parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + pass +``` + +在这种情况下,`provider` 是该工具的 ID,`tool_name` 在创建工具时指定。 + +### 调用自定义工具 + +**入口点** + +```python + self.session.tool +``` + +**接口** + +```python + def invoke_api_tool( + self, provider: str, tool_name: str, parameters: dict[str, Any] + ) -> Generator[ToolInvokeMessage, None, None]: + pass +``` + +这里,`provider` 是该工具的 ID,`tool_name` 是 OpenAPI 规范中的 `operation_id`。如果不存在,则是 Dify 自动生成的 `tool_name`,可在工具管理页面找到。 + +## 相关资源 + +- [反向调用 Dify 服务](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) - 了解反向调用的基本概念 +- [反向调用应用](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) - 了解如何调用平台内的应用 +- [反向调用模型](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) - 了解如何调用平台内的模型能力 +- [工具插件开发指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - 了解如何开发工具插件 +- [高级工具插件](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - 了解工作流作为工具等高级功能 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx new file mode 100644 index 00000000..c7132a78 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx @@ -0,0 +1,47 @@ +--- +dimensions: + type: + primary: implementation + detail: advanced + level: beginner +standard_title: Reverse Invocation +language: en +title: Dify 服务的反向调用 +description: 本文档简要介绍了 Dify 插件的反向调用能力,即插件可以调用 Dify 主平台内的指定服务。文中列出了四种可调用的模块类型:App(访问应用数据)、Model(调用平台内的模型能力)、Tool(调用平台内的其他工具插件)和 Node(调用 Chatflow/Workflow 应用内的节点)。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation)。 + +插件可以自由调用 Dify 主平台内的一些服务来增强其能力。 + +### 可调用的 Dify 模块 + +* [App](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-app) + + 插件可以访问 Dify 平台内应用的数据。 +* [Model](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-model) + + 插件可以反向调用 Dify 平台内的 LLM 能力,包括平台内所有模型类型和功能,如 TTS、Rerank 等。 +* [Tool](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-tool) + + 插件可以调用 Dify 平台内的其他工具类型插件。 +* [Node](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation-node) + + 插件可以调用 Dify 平台内特定 Chatflow/工作流应用中的节点。 + +## 相关资源 + +- [开发扩展插件](/zh/develop-plugin/dev-guides-and-walkthroughs/endpoint) - 了解如何开发与外部系统集成的插件 +- [开发 Slack Bot 插件](/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) - 使用反向调用与 Slack 平台集成的示例 +- [Bundle 类型插件](/zh/develop-plugin/features-and-specs/advanced-development/bundle) - 了解如何打包使用反向调用的多个插件 +- [使用持久化存储](/zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv) - 通过 KV 存储增强插件能力 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/advanced-development/reverse-invocation.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx b/zh/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx new file mode 100644 index 00000000..4b1ace91 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx @@ -0,0 +1,279 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: General Specs +language: en +title: 通用规范 +description: 本文将简要介绍插件开发中的常见结构。在开发过程中,强烈建议结合[插件开发基本概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin)和[开发者速查表](/zh/develop-plugin/getting-started/cli)一起阅读,以便更好地理解整体架构。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)。 + +### 路径规范 + +在 Manifest 或任何 yaml 文件中填写文件路径时,根据文件类型遵循以下两种规范: + +* 如果目标文件是多媒体文件(如图片或视频),例如填写插件的 `icon` 时,应将这些文件放在插件根目录下的 `_assets` 文件夹中。 +* 如果目标文件是普通文本文件,如 `.py` 或 `.yaml` 代码文件,应填写该文件在插件项目中的绝对路径。 + +### 通用结构 + +在定义插件时,有一些数据结构可以在工具、模型和 Endpoints 之间共享。这些共享结构在此处定义。 + +#### I18nObject + +`I18nObject` 是符合 [IETF BCP 47](https://tools.ietf.org/html/bcp47) 标准的国际化结构。目前支持四种语言: + + + 英语(美国) + + + + 简体中文 + + + + 日语 + + + + 葡萄牙语(巴西) + + +#### ProviderConfig + +`ProviderConfig` 是通用的提供者表单结构,适用于 `Tool` 和 `Endpoint` + + + 表单项名称 + + + + 遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) 标准的显示标签 + + + + 表单字段类型 - 决定字段在 UI 中的渲染方式 + + + + 可选范围规范,根据 `type` 的值而变化 + + + + 字段是否不能为空 + + + + 默认值,仅支持基本类型:`float`、`int`、`string` + + + + 可用选项,仅在 type 为 `select` 时使用 + + + + 帮助文档链接标签,遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) + + + + 帮助文档链接 + + + + 多语言占位符文本,遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) + + +#### ProviderConfigOption(object) + + + 选项的值 + + + + 选项的显示标签,遵循 [IETF BCP 47](https://tools.ietf.org/html/bcp47) + + +#### ProviderConfigType(string) + + + 将被加密的配置信息 + + + + 纯文本输入字段 + + + + 下拉选择字段 + + + + 开关/切换控件 + + + + 模型配置选择器,包括提供者名称、模型名称、模型参数等 + + + + 应用 ID 选择器 + + + + 工具配置选择器,包括工具提供者、名称、参数等 + + + + 数据集选择器(待定) + + +#### ProviderConfigScope(string) + +当 `type` 为 `model-selector` 时: + + 所有模型类型 + + + 仅大型语言模型 + + + 仅文本嵌入模型 + + + 仅重排序模型 + + + 仅文本转语音模型 + + + 仅语音转文本模型 + + + 仅内容审核模型 + + + 仅视觉模型 + + +当 `type` 为 `app-selector` 时: + + 所有应用类型 + + + 仅聊天应用 + + + 仅工作流应用 + + + 仅补全应用 + + +当 `type` 为 `tool-selector` 时: + + 所有工具类型 + + + 仅插件工具 + + + 仅 API 工具 + + + 仅工作流工具 + + +#### ModelConfig + + + 包含 plugin_id 的模型提供者名称,格式为 `langgenius/openai/openai` + + + + 具体模型名称 + + + + 模型类型枚举,参考[模型设计规则](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules#modeltype)文档 + + +#### NodeResponse + + + 最终输入到节点的变量 + + + + 节点的输出结果 + + + + 节点执行期间生成的数据 + + +#### ToolSelector + + + 工具提供者名称 + + + + 工具名称 + + + + 工具描述 + + + + 工具配置信息 + + + + 需要 LLM 推理的参数 + + + 参数名称 + + + + 参数类型 + + + + 参数是否必填 + + + + 参数描述 + + + + 默认值 + + + + 参数的可用选项 + + + +## 相关资源 + +- [插件开发基本概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin) - 全面了解 Dify 插件开发 +- [开发者速查表](/zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet) - 插件开发中常用命令和概念的快速参考 +- [工具插件开发详解](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - 了解如何定义插件信息和工具插件开发流程 +- [模型设计规则](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - 了解模型配置的标准 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/general-specifications.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx b/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx new file mode 100644 index 00000000..f8e7fd6a --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx @@ -0,0 +1,573 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Model Specs +language: en +title: 模型规范 +description: 本文档详细定义了 Dify 模型插件开发的核心概念和结构,包括模型供应商(Provider)、AI 模型实体(AIModelEntity)、模型类型(ModelType)、配置方法(ConfigurateMethod)、模型特性(ModelFeature)、参数规则(ParameterRule)、价格配置(PriceConfig)以及各种凭据模式的详细数据结构规范。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules)。 + +* 模型供应商规则基于 [Provider](#provider) 实体。 +* 模型规则基于 [AIModelEntity](#aimodelentity) 实体。 + +> 以下所有实体均基于 `Pydantic BaseModel`,可在 `entities` 模块中找到。 + +### Provider + + + 供应商标识符,例如:`openai` + + + + 供应商显示名称,i18n,可设置 `en_US`(英文)和 `zh_Hans`(中文)两种语言 + + + 中文标签,若未设置,将默认使用 `en_US` + + + + 英文标签 + + + + + 供应商描述,i18n + + + 中文描述 + + + + 英文描述 + + + + + 供应商小图标,存储在相应供应商实现目录下的 `_assets` 目录中 + + + 中文图标 + + + + 英文图标 + + + + + 供应商大图标,存储在相应供应商实现目录下的 `_assets` 目录中 + + + 中文图标 + + + + 英文图标 + + + + + 背景颜色值,例如:#FFFFFF,若为空,将显示前端默认颜色值 + + + + 帮助信息 + + + 帮助标题,i18n + + + 中文标题 + + + + 英文标题 + + + + + 帮助链接,i18n + + + 中文链接 + + + + 英文链接 + + + + + + 支持的模型类型 + + + + 配置方法 + + + + 供应商凭据规范 + + + + 模型凭据规范 + + +### AIModelEntity + + + 模型标识符,例如:`gpt-3.5-turbo` + + + + 模型显示名称,i18n,可设置 `en_US`(英文)和 `zh_Hans`(中文)两种语言 + + + 中文标签 + + + + 英文标签 + + + + + 模型类型 + + + + 支持的特性列表 + + + + 模型属性 + + + 模式(适用于模型类型 `llm`) + + + + 上下文大小(适用于模型类型 `llm` 和 `text-embedding`) + + + + 最大分块数(适用于模型类型 `text-embedding` 和 `moderation`) + + + + 最大文件上传限制,单位:MB(适用于模型类型 `speech2text`) + + + + 支持的文件扩展名格式,例如:mp3,mp4(适用于模型类型 `speech2text`) + + + + 默认语音,必填项:alloy,echo,fable,onyx,nova,shimmer(适用于模型类型 `tts`) + + + + 可用语音列表(适用于模型类型 `tts`) + + + 语音模型 + + + + 语音模型显示名称 + + + + 语音模型支持的语言 + + + + + 单次转换的字数限制,默认按段落分割(适用于模型类型 `tts`) + + + + 支持的音频文件扩展名格式,例如:mp3,wav(适用于模型类型 `tts`) + + + + 文字转音频转换支持的并发任务数(适用于模型类型 `tts`) + + + + 每个分块的最大字符数(适用于模型类型 `moderation`) + + + + + 模型调用参数规则 + + + + 价格信息 + + + + 是否已弃用。若已弃用,模型列表将不再显示该模型,但已配置的仍可继续使用。默认为 False。 + + +### ModelType + + + 文本生成模型 + + + + 文本嵌入模型 + + + + 重排序模型 + + + + 语音转文字 + + + + 文字转语音 + + + + 内容审核 + + +### ConfigurateMethod + + + 预定义模型 - 表示用户只需配置统一的供应商凭据即可使用该供应商下的预定义模型。 + + + + 自定义模型 - 用户需要为每个模型添加凭据配置。 + + + + 从远程获取 - 与 `predefined-model` 配置方法类似,只需统一的供应商凭据,但模型是使用凭据信息从供应商获取的。 + + +### ModelFeature + + + 智能体推理,通常 70B 以上的模型具有思维链能力。 + + + + 视觉,即:图像理解。 + + + + 工具调用 + + + + 多工具调用 + + + + 流式工具调用 + + +### FetchFrom + + + 预定义模型 + + + + 远程模型 + + +### LLMMode + + + 文本补全 + + + + 对话 + + +### ParameterRule + + + 模型调用的实际参数名称 + + + + 使用模板 + + +> 有关使用模板的详细信息,可参考[创建新模型供应商](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider)中的示例。 + +默认有 5 个预配置的变量内容模板: + +* `temperature` +* `top_p` +* `frequency_penalty` +* `presence_penalty` +* `max_tokens` + +可以直接在 `use_template` 中设置模板变量名,这将使用 entities.defaults.PARAMETER\_RULE\_TEMPLATE 中的默认配置,无需设置除 `name` 和 `use_template` 之外的任何参数。如果设置了额外的配置参数,它们将覆盖默认配置。可参考 `openai/llm/gpt-3.5-turbo.yaml` 中的示例。 + + + 标签,i18n + + + 中文标签 + + + + 英文标签 + + + + + 参数类型 + + + 整数 + + + + 浮点数 + + + + 字符串 + + + + 布尔值 + + + + + 帮助信息 + + + 中文帮助信息 + + + + 英文帮助信息 + + + + + 是否必填,默认为 False + + + + 默认值 + + + + 最小值,仅适用于数值类型 + + + + 最大值,仅适用于数值类型 + + + + 精度,保留的小数位数,仅适用于数值类型 + + + + 下拉选项值,仅当 `type` 为 `string` 时适用,若未设置或为 null,则不限制选项值 + + +### PriceConfig + + + 输入单价,即提示词单价 + + + + 输出单价,即返回内容单价 + + + + 价格单位,例如,若按每 1M 令牌计价,则单价对应的单位令牌数为 `0.000001` + + + + 货币单位 + + +### ProviderCredentialSchema + + + 凭据表单规范 + + +### ModelCredentialSchema + + + 模型标识符,默认变量名为 `model` + + + 模型表单项显示名称 + + + 英文 + + + + 中文 + + + + + 模型提示内容 + + + 英文 + + + + 中文 + + + + + + 凭据表单规范 + + +### CredentialFormSchema + + + 表单项变量名 + + + + 表单项标签 + + + 英文 + + + + 中文 + + + + + 表单项类型 + + + + 是否必填 + + + + 默认值 + + + + `select` 或 `radio` 特有的表单项属性,定义下拉内容 + + + + `text-input` 特有的表单项属性,表单项占位符 + + + 英文 + + + + 中文 + + + + + `text-input` 特有的表单项属性,定义最大输入长度,0 表示无限制 + + + + 当其他表单项值满足条件时显示,为空表示始终显示 + + +#### FormType + + + 文本输入组件 + + + + 密码输入组件 + + + + 单选下拉框 + + + + 单选按钮组件 + + + + 开关组件,仅支持 `true` 和 `false` + + +#### FormOption + + + 标签 + + + 英文 + + + + 中文 + + + + + 下拉选项值 + + + + 当其他表单项值满足条件时显示,为空表示始终显示 + + +#### FormShowOnObject + + + 其他表单项变量名 + + + + 其他表单项变量值 + + +## 相关资源 + +- [模型架构详解](/zh/develop-plugin/features-and-specs/plugin-types/model-schema) - 深入了解模型插件的架构规范 +- [快速集成新模型](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 学习如何应用这些规则来添加新模型 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 了解插件清单文件的配置 +- [创建新模型供应商](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 开发全新的模型供应商插件 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/model-designing-rules.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/model-schema.mdx b/zh/develop-plugin/features-and-specs/plugin-types/model-schema.mdx new file mode 100644 index 00000000..339b7271 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/model-schema.mdx @@ -0,0 +1,1263 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: intermediate +standard_title: Model Schema +language: en +title: 模型 API 接口 +description: Dify 模型插件 API 的综合指南,包括 LLM、TextEmbedding、Rerank、Speech2text 和 Text2speech 模型的实现要求,以及所有相关数据结构的详细规范。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/model-schema)。 + +## 简介 + +本文档详细介绍了实现 Dify 模型插件所需的接口和数据结构。它作为开发者将 AI 模型与 Dify 平台集成的技术参考。 + + +在深入阅读此 API 参考之前,我们建议先阅读[模型设计规则](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules)和[模型插件介绍](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules)以获得概念上的理解。 + + + + + 了解如何为不同的 AI 服务提供商实现模型提供商类 + + + 五种支持的模型类型的实现细节:LLM、Embedding、Rerank、Speech2Text 和 Text2Speech + + + 模型 API 中使用的所有数据结构的综合参考 + + + 正确的错误映射和异常处理指南 + + + +## 模型提供商 + +每个模型提供商必须继承 `__base.model_provider.ModelProvider` 基类并实现凭据验证接口。 + +### 提供商凭据验证 + + +```python Core Implementation +def validate_provider_credentials(self, credentials: dict) -> None: + """ + Validate provider credentials by making a test API call + + Parameters: + credentials: Provider credentials as defined in `provider_credential_schema` + + Raises: + CredentialsValidateFailedError: If validation fails + """ + try: + # Example implementation - validate using an LLM model instance + model_instance = self.get_model_instance(ModelType.LLM) + model_instance.validate_credentials( + model="example-model", + credentials=credentials + ) + except Exception as ex: + logger.exception(f"Credential validation failed") + raise CredentialsValidateFailedError(f"Invalid credentials: {str(ex)}") +``` + +```python Custom Model Provider +class XinferenceProvider(Provider): + def validate_provider_credentials(self, credentials: dict) -> None: + """ + For custom-only model providers, a simple implementation is sufficient + as validation happens at the model level + """ + pass +``` + + + + 在提供商的 YAML 配置中 `provider_credential_schema` 下定义的凭据信息。 + 通常包括 `api_key`、`organization_id` 等字段。 + + + +如果验证失败,您的实现必须抛出 `CredentialsValidateFailedError` 异常。这确保了在 Dify UI 中正确的错误处理。 + + + +对于预定义的模型提供商,您应该实现一个彻底的验证方法来验证凭据是否能与您的 API 一起工作。对于自定义模型提供商(每个模型都有自己的凭据),简化的实现就足够了。 + + +## 模型 + +Dify 支持五种不同的模型类型,每种都需要实现特定的接口。然而,所有模型类型都有一些共同的要求。 + +### 通用接口 + +每个模型实现,无论类型如何,都必须实现这两个基本方法: + +#### 1. 模型凭据验证 + + +```python Implementation +def validate_credentials(self, model: str, credentials: dict) -> None: + """ + Validate that the provided credentials work with the specified model + + Parameters: + model: The specific model identifier (e.g., "gpt-4") + credentials: Authentication details for the model + + Raises: + CredentialsValidateFailedError: If validation fails + """ + try: + # Make a lightweight API call to verify credentials + # Example: List available models or check account status + response = self._api_client.validate_api_key(credentials["api_key"]) + + # Verify the specific model is available if applicable + if model not in response.get("available_models", []): + raise CredentialsValidateFailedError(f"Model {model} is not available") + + except ApiException as e: + raise CredentialsValidateFailedError(str(e)) +``` + + + + 要验证的特定模型标识符(例如,"gpt-4"、"claude-3-opus") + + + + 在提供商配置中定义的凭据信息 + + +#### 2. 错误映射 + + +```python Implementation +@property +def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + Map provider-specific exceptions to standardized Dify error types + + Returns: + Dictionary mapping Dify error types to lists of provider exception types + """ + return { + InvokeConnectionError: [ + requests.exceptions.ConnectionError, + requests.exceptions.Timeout, + ConnectionRefusedError + ], + InvokeServerUnavailableError: [ + ServiceUnavailableError, + HTTPStatusError + ], + InvokeRateLimitError: [ + RateLimitExceededError, + QuotaExceededError + ], + InvokeAuthorizationError: [ + AuthenticationError, + InvalidAPIKeyError, + PermissionDeniedError + ], + InvokeBadRequestError: [ + InvalidRequestError, + ValidationError + ] + } +``` + + + + + 网络连接失败、超时 + + + 服务提供商宕机或不可用 + + + 达到速率限制或配额限制 + + + 认证或权限问题 + + + 无效的参数或请求 + + + + +您也可以在代码中直接抛出这些标准化的错误类型,而不是依赖错误映射。这种方法让您对错误消息有更多的控制。 + + +### LLM 实现 + +要实现大型语言模型提供商,请继承 `__base.large_language_model.LargeLanguageModel` 基类并实现以下方法: + +#### 1. 模型调用 + +此核心方法处理对语言模型的流式和非流式 API 调用。 + + +```python Core Implementation +def _invoke( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + model_parameters: dict, + tools: Optional[list[PromptMessageTool]] = None, + stop: Optional[list[str]] = None, + stream: bool = True, + user: Optional[str] = None +) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]: + """ + Invoke the language model + """ + # Prepare API parameters + api_params = self._prepare_api_parameters( + model, + credentials, + prompt_messages, + model_parameters, + tools, + stop + ) + + try: + # Choose between streaming and non-streaming implementation + if stream: + return self._invoke_stream(model, api_params, user) + else: + return self._invoke_sync(model, api_params, user) + + except Exception as e: + # Map errors using the error mapping property + self._handle_api_error(e) + +# Helper methods for streaming and non-streaming calls +def _invoke_stream(self, model, api_params, user): + # Implement streaming call and yield chunks + pass + +def _invoke_sync(self, model, api_params, user): + # Implement synchronous call and return complete result + pass +``` + + + + + 模型标识符(例如,"gpt-4"、"claude-3") + + + + API 的认证凭据 + + + + Dify 标准化格式的消息列表: + - 对于 `completion` 模型:包含单个 `UserPromptMessage` + - 对于 `chat` 模型:根据需要包含 `SystemPromptMessage`、`UserPromptMessage`、`AssistantPromptMessage`、`ToolPromptMessage` + + + + 模型特定参数(temperature、top_p 等),在模型的 YAML 配置中定义 + + + + 函数调用能力的工具定义 + + + + 遇到时将停止模型生成的停止序列 + + + + 是否返回流式响应 + + + + 用于 API 监控的用户标识符 + + + + + + 一个生成器,在响应块可用时逐个产出 + + + + 包含完整生成文本的完整响应对象 + + + + +我们建议为流式和非流式调用实现单独的辅助方法,以保持代码的组织性和可维护性。 + + +#### 2. 令牌计数 + + +```python Implementation +def get_num_tokens( + self, + model: str, + credentials: dict, + prompt_messages: list[PromptMessage], + tools: Optional[list[PromptMessageTool]] = None +) -> int: + """ + Calculate the number of tokens in the prompt + """ + # Convert prompt_messages to the format expected by the tokenizer + text = self._convert_messages_to_text(prompt_messages) + + try: + # Use the appropriate tokenizer for this model + tokenizer = self._get_tokenizer(model) + return len(tokenizer.encode(text)) + except Exception: + # Fall back to a generic tokenizer + return self._get_num_tokens_by_gpt2(text) +``` + + + +如果模型不提供分词器,您可以使用基类的 `_get_num_tokens_by_gpt2(text)` 方法进行合理的近似估算。 + + +#### 3. 自定义模型 Schema(可选) + + +```python Implementation +def get_customizable_model_schema( + self, + model: str, + credentials: dict +) -> Optional[AIModelEntity]: + """ + Get parameter schema for custom models + """ + # For fine-tuned models, you might return the base model's schema + if model.startswith("ft:"): + base_model = self._extract_base_model(model) + return self._get_predefined_model_schema(base_model) + + # For standard models, return None to use the predefined schema + return None +``` + + + +此方法仅对支持自定义模型的提供商是必需的。它允许自定义模型从基础模型继承参数规则。 + + +### TextEmbedding 实现 + + +文本嵌入模型将文本转换为捕获语义含义的高维向量,这对于检索、相似性搜索和分类非常有用。 + + +要实现文本嵌入提供商,请继承 `__base.text_embedding_model.TextEmbeddingModel` 基类: + +#### 1. 核心嵌入方法 + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + texts: list[str], + user: Optional[str] = None +) -> TextEmbeddingResult: + """ + Generate embedding vectors for multiple texts + """ + # Set up API client with credentials + client = self._get_client(credentials) + + # Handle batching if needed + batch_size = self._get_batch_size(model) + all_embeddings = [] + total_tokens = 0 + start_time = time.time() + + # Process in batches to avoid API limits + for i in range(0, len(texts), batch_size): + batch = texts[i:i+batch_size] + + # Make API call to the embeddings endpoint + response = client.embeddings.create( + model=model, + input=batch, + user=user + ) + + # Extract embeddings from response + batch_embeddings = [item.embedding for item in response.data] + all_embeddings.extend(batch_embeddings) + + # Track token usage + total_tokens += response.usage.total_tokens + + # Calculate usage metrics + elapsed_time = time.time() - start_time + usage = self._create_embedding_usage( + model=model, + tokens=total_tokens, + latency=elapsed_time + ) + + return TextEmbeddingResult( + model=model, + embeddings=all_embeddings, + usage=usage + ) +``` + + + + + 嵌入模型标识符 + + + + 嵌入服务的认证凭据 + + + + 要嵌入的文本输入列表 + + + + 用于 API 监控的用户标识符 + + + + + + 包含以下内容的结构化响应: + - model:用于嵌入的模型 + - embeddings:与输入文本对应的嵌入向量列表 + - usage:关于令牌使用和成本的元数据 + + + +#### 2. 令牌计数方法 + + +```python Implementation +def get_num_tokens( + self, + model: str, + credentials: dict, + texts: list[str] +) -> int: + """ + Calculate the number of tokens in the texts to be embedded + """ + # Join all texts to estimate token count + combined_text = " ".join(texts) + + try: + # Use the appropriate tokenizer for this model + tokenizer = self._get_tokenizer(model) + return len(tokenizer.encode(combined_text)) + except Exception: + # Fall back to a generic tokenizer + return self._get_num_tokens_by_gpt2(combined_text) +``` + + + +对于嵌入模型,准确的令牌计数对于成本估算很重要,但对功能不是关键的。`_get_num_tokens_by_gpt2` 方法为大多数模型提供了合理的近似值。 + + +### Rerank 实现 + + +重排序模型通过根据与查询的相关性重新排列一组候选文档来帮助提高搜索质量,通常在初始检索阶段之后进行。 + + +要实现重排序提供商,请继承 `__base.rerank_model.RerankModel` 基类: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + query: str, + docs: list[str], + score_threshold: Optional[float] = None, + top_n: Optional[int] = None, + user: Optional[str] = None +) -> RerankResult: + """ + Rerank documents based on relevance to the query + """ + # Set up API client with credentials + client = self._get_client(credentials) + + # Prepare request data + request_data = { + "query": query, + "documents": docs, + } + + # Call reranking API endpoint + response = client.rerank( + model=model, + **request_data, + user=user + ) + + # Process results + ranked_results = [] + for i, result in enumerate(response.results): + # Create RerankDocument for each result + doc = RerankDocument( + index=result.document_index, # Original index in docs list + text=docs[result.document_index], # Original text + score=result.relevance_score # Relevance score + ) + ranked_results.append(doc) + + # Sort by score in descending order + ranked_results.sort(key=lambda x: x.score, reverse=True) + + # Apply score threshold filtering if specified + if score_threshold is not None: + ranked_results = [doc for doc in ranked_results if doc.score >= score_threshold] + + # Apply top_n limit if specified + if top_n is not None and top_n > 0: + ranked_results = ranked_results[:top_n] + + return RerankResult( + model=model, + docs=ranked_results + ) +``` + + + + + 重排序模型标识符 + + + + API 的认证凭据 + + + + 搜索查询文本 + + + + 要重排序的文档文本列表 + + + + 用于过滤结果的可选最小分数阈值 + + + + 返回结果数量的可选限制 + + + + 用于 API 监控的用户标识符 + + + + + + 包含以下内容的结构化响应: + - model:用于重排序的模型 + - docs:包含索引、文本和分数的 RerankDocument 对象列表 + + + + +重排序可能计算成本较高,特别是对于大型文档集。为大型文档集合实现批处理以避免超时或过度资源消耗。 + + +### Speech2Text 实现 + + +语音转文本模型将音频文件中的口语转换为书面文本,支持转录服务、语音命令和无障碍功能等应用。 + + +要实现语音转文本提供商,请继承 `__base.speech2text_model.Speech2TextModel` 基类: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + file: IO[bytes], + user: Optional[str] = None +) -> str: + """ + Convert speech audio to text + """ + # Set up API client with credentials + client = self._get_client(credentials) + + try: + # Determine the file format + file_format = self._detect_audio_format(file) + + # Prepare the file for API submission + # Most APIs require either a file path or binary data + audio_data = file.read() + + # Call the speech-to-text API + response = client.audio.transcriptions.create( + model=model, + file=("audio.mp3", audio_data), # Adjust filename based on actual format + user=user + ) + + # Extract and return the transcribed text + return response.text + + except Exception as e: + # Map to appropriate error type + self._handle_api_error(e) + + finally: + # Reset file pointer for potential reuse + file.seek(0) +``` + +```python Helper Methods +def _detect_audio_format(self, file: IO[bytes]) -> str: + """ + Detect the audio format based on file header + """ + # Read the first few bytes to check the file signature + header = file.read(12) + file.seek(0) # Reset file pointer + + # Check for common audio format signatures + if header.startswith(b'RIFF') and header[8:12] == b'WAVE': + return 'wav' + elif header.startswith(b'ID3') or header.startswith(b'\xFF\xFB'): + return 'mp3' + elif header.startswith(b'OggS'): + return 'ogg' + elif header.startswith(b'fLaC'): + return 'flac' + else: + # Default or additional format checks + return 'mp3' # Default assumption +``` + + + + + 语音转文本模型标识符 + + + + API 的认证凭据 + + + + 包含要转录的音频的二进制文件对象 + + + + 用于 API 监控的用户标识符 + + + + + + 从音频文件转录的文本 + + + + +音频格式检测对于正确处理不同文件类型很重要。考虑实现一个辅助方法来从文件头检测格式,如示例所示。 + + + +一些语音转文本 API 有文件大小限制。如有必要,考虑为大型音频文件实现分块处理。 + + +### Text2Speech 实现 + + +文本转语音模型将书面文本转换为自然发音的语音,支持语音助手、屏幕阅读器和音频内容生成等应用。 + + +要实现文本转语音提供商,请继承 `__base.text2speech_model.Text2SpeechModel` 基类: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + content_text: str, + streaming: bool, + user: Optional[str] = None +) -> Union[bytes, Generator[bytes, None, None]]: + """ + Convert text to speech audio + """ + # Set up API client with credentials + client = self._get_client(credentials) + + # Get voice settings based on model + voice = self._get_voice_for_model(model) + + try: + # Choose implementation based on streaming preference + if streaming: + return self._stream_audio( + client=client, + model=model, + text=content_text, + voice=voice, + user=user + ) + else: + return self._generate_complete_audio( + client=client, + model=model, + text=content_text, + voice=voice, + user=user + ) + except Exception as e: + self._handle_api_error(e) +``` + +```python Helper Methods +def _stream_audio(self, client, model, text, voice, user=None): + """ + Implementation for streaming audio output + """ + # Make API request with stream=True + response = client.audio.speech.create( + model=model, + voice=voice, + input=text, + stream=True, + user=user + ) + + # Yield chunks as they arrive + for chunk in response: + if chunk: + yield chunk + +def _generate_complete_audio(self, client, model, text, voice, user=None): + """ + Implementation for complete audio file generation + """ + # Make API request for complete audio + response = client.audio.speech.create( + model=model, + voice=voice, + input=text, + user=user + ) + + # Get audio data as bytes + audio_data = response.content + return audio_data +``` + + + + + 文本转语音模型标识符 + + + + API 的认证凭据 + + + + 要转换为语音的文本内容 + + + + 是返回流式音频还是完整文件 + + + + 用于 API 监控的用户标识符 + + + + + + 一个生成器,在音频块可用时逐个产出 + + + + 作为字节的完整音频数据 + + + + +大多数文本转语音 API 要求您在指定模型的同时指定语音。考虑在 Dify 的模型标识符和提供商的语音选项之间实现映射。 + + + +长文本输入可能需要分块以获得更好的语音合成质量。考虑实现文本预处理来正确处理标点符号、数字和特殊字符。 + + + +### Moderation 实现 + + +内容审核模型分析内容中潜在的有害、不当或不安全的材料,帮助维护平台安全和内容政策。 + + +要实现内容审核提供商,请继承 `__base.moderation_model.ModerationModel` 基类: + + +```python Implementation +def _invoke( + self, + model: str, + credentials: dict, + text: str, + user: Optional[str] = None +) -> bool: + """ + Analyze text for harmful content + + Returns: + bool: False if the text is safe, True if it contains harmful content + """ + # Set up API client with credentials + client = self._get_client(credentials) + + try: + # Call moderation API + response = client.moderations.create( + model=model, + input=text, + user=user + ) + + # Check if any categories were flagged + result = response.results[0] + + # Return True if flagged in any category, False if safe + return result.flagged + + except Exception as e: + # Log the error but default to safe if there's an API issue + # This is a conservative approach - production systems might want + # different fallback behavior + logger.error(f"Moderation API error: {str(e)}") + return False +``` + +```python Detailed Implementation +def _invoke( + self, + model: str, + credentials: dict, + text: str, + user: Optional[str] = None +) -> bool: + """ + Analyze text for harmful content with detailed category checking + """ + # Set up API client with credentials + client = self._get_client(credentials) + + try: + # Call moderation API + response = client.moderations.create( + model=model, + input=text, + user=user + ) + + # Get detailed category results + result = response.results[0] + categories = result.categories + + # Check specific categories based on your application's needs + # For example, you might want to flag certain categories but not others + critical_violations = [ + categories.harassment, + categories.hate, + categories.self_harm, + categories.sexual, + categories.violence + ] + + # Flag content if any critical category is violated + return any(critical_violations) + + except Exception as e: + self._handle_api_error(e) + # Default to safe in case of error + return False +``` + + + + + 内容审核模型标识符 + + + + API 的认证凭据 + + + + 要分析的文本内容 + + + + 用于 API 监控的用户标识符 + + + + + + 表示内容安全性的布尔值: + - False:内容是安全的 + - True:内容包含有害材料 + + + + +内容审核通常用作安全机制。在实现解决方案时,请考虑漏报(让有害内容通过)与误报(阻止安全内容)的影响。 + + + +许多内容审核 API 提供详细的类别分数而不仅仅是二进制结果。如果您的应用需要,考虑扩展此实现以返回关于特定有害内容类别的更详细信息。 + + +### 实体 + +#### PromptMessageRole + +消息角色 + +```python +class PromptMessageRole(Enum): + """ + Enum class for prompt message. + """ + SYSTEM = "system" + USER = "user" + ASSISTANT = "assistant" + TOOL = "tool" +``` + +#### PromptMessageContentType + +消息内容类型,分为纯文本和图片。 + +```python +class PromptMessageContentType(Enum): + """ + Enum class for prompt message content type. + """ + TEXT = 'text' + IMAGE = 'image' +``` + +#### PromptMessageContent + +消息内容基类,仅用于参数声明,不能初始化。 + +```python +class PromptMessageContent(BaseModel): + """ + Model class for prompt message content. + """ + type: PromptMessageContentType + data: str # Content data +``` + +目前支持两种类型:文本和图片,并且可以同时支持文本和多张图片。 +您需要分别初始化 `TextPromptMessageContent` 和 `ImagePromptMessageContent`。 + +#### TextPromptMessageContent + +```python +class TextPromptMessageContent(PromptMessageContent): + """ + Model class for text prompt message content. + """ + type: PromptMessageContentType = PromptMessageContentType.TEXT +``` + +当传入文本和图片时,文本需要构造成此实体作为 `content` 列表的一部分。 + +#### ImagePromptMessageContent + +```python +class ImagePromptMessageContent(PromptMessageContent): + """ + Model class for image prompt message content. + """ + class DETAIL(Enum): + LOW = 'low' + HIGH = 'high' + + type: PromptMessageContentType = PromptMessageContentType.IMAGE + detail: DETAIL = DETAIL.LOW # Resolution +``` + +当传入文本和图片时,图片需要构造成此实体作为 `content` 列表的一部分。 +`data` 可以是 `url` 或图片的 `base64` 编码字符串。 + +#### PromptMessage + +所有角色消息体的基类,仅用于参数声明,不能初始化。 + +```python +class PromptMessage(ABC, BaseModel): + """ + Model class for prompt message. + """ + role: PromptMessageRole # Message role + content: Optional[str | list[PromptMessageContent]] = None # Supports two types: string and content list. The content list is for multimodal needs, see PromptMessageContent for details. + name: Optional[str] = None # Name, optional. +``` + +#### UserPromptMessage + +UserMessage 消息体,表示用户消息。 + +```python +class UserPromptMessage(PromptMessage): + """ + Model class for user prompt message. + """ + role: PromptMessageRole = PromptMessageRole.USER +``` + +#### AssistantPromptMessage + +表示模型响应消息,通常用于 `few-shots` 或聊天历史输入。 + +```python +class AssistantPromptMessage(PromptMessage): + """ + Model class for assistant prompt message. + """ + class ToolCall(BaseModel): + """ + Model class for assistant prompt message tool call. + """ + class ToolCallFunction(BaseModel): + """ + Model class for assistant prompt message tool call function. + """ + name: str # Tool name + arguments: str # Tool parameters + + id: str # Tool ID, only effective for OpenAI tool call, a unique ID for tool invocation, the same tool can be called multiple times + type: str # Default is function + function: ToolCallFunction # Tool call information + + role: PromptMessageRole = PromptMessageRole.ASSISTANT + tool_calls: list[ToolCall] = [] # Model's tool call results (only returned when tools are passed in and the model decides to call them) +``` + +这里的 `tool_calls` 是在向模型传入 `tools` 后模型返回的 `tool call` 列表。 + +#### SystemPromptMessage + +表示系统消息,通常用于为模型设置系统指令。 + +```python +class SystemPromptMessage(PromptMessage): + """ + Model class for system prompt message. + """ + role: PromptMessageRole = PromptMessageRole.SYSTEM +``` + +#### ToolPromptMessage + +表示工具消息,用于在工具执行后将结果传递给模型以进行下一步规划。 + +```python +class ToolPromptMessage(PromptMessage): + """ + Model class for tool prompt message. + """ + role: PromptMessageRole = PromptMessageRole.TOOL + tool_call_id: str # Tool call ID, if OpenAI tool call is not supported, you can also pass in the tool name +``` + +基类的 `content` 传入工具执行结果。 + +#### PromptMessageTool + +```python +class PromptMessageTool(BaseModel): + """ + Model class for prompt message tool. + """ + name: str # Tool name + description: str # Tool description + parameters: dict # Tool parameters dict + +``` + +*** + +#### LLMResult + +```python +class LLMResult(BaseModel): + """ + Model class for llm result. + """ + model: str # Actually used model + prompt_messages: list[PromptMessage] # Prompt message list + message: AssistantPromptMessage # Reply message + usage: LLMUsage # Tokens used and cost information + system_fingerprint: Optional[str] = None # Request fingerprint, refer to OpenAI parameter definition +``` + +#### LLMResultChunkDelta + +流式响应中每次迭代的 Delta 实体 + +```python +class LLMResultChunkDelta(BaseModel): + """ + Model class for llm result chunk delta. + """ + index: int # Sequence number + message: AssistantPromptMessage # Reply message + usage: Optional[LLMUsage] = None # Tokens used and cost information, only returned in the last message + finish_reason: Optional[str] = None # Completion reason, only returned in the last message +``` + +#### LLMResultChunk + +流式响应中的迭代实体 + +```python +class LLMResultChunk(BaseModel): + """ + Model class for llm result chunk. + """ + model: str # Actually used model + prompt_messages: list[PromptMessage] # Prompt message list + system_fingerprint: Optional[str] = None # Request fingerprint, refer to OpenAI parameter definition + delta: LLMResultChunkDelta # Changes in content for each iteration +``` + +#### LLMUsage + +```python +class LLMUsage(ModelUsage): + """ + Model class for llm usage. + """ + prompt_tokens: int # Tokens used by prompt + prompt_unit_price: Decimal # Prompt unit price + prompt_price_unit: Decimal # Prompt price unit, i.e., unit price based on how many tokens + prompt_price: Decimal # Prompt cost + completion_tokens: int # Tokens used by completion + completion_unit_price: Decimal # Completion unit price + completion_price_unit: Decimal # Completion price unit, i.e., unit price based on how many tokens + completion_price: Decimal # Completion cost + total_tokens: int # Total tokens used + total_price: Decimal # Total cost + currency: str # Currency unit + latency: float # Request time (s) +``` + +*** + +#### TextEmbeddingResult + +```python +class TextEmbeddingResult(BaseModel): + """ + Model class for text embedding result. + """ + model: str # Actually used model + embeddings: list[list[float]] # Embedding vector list, corresponding to the input texts list + usage: EmbeddingUsage # Usage information +``` + +#### EmbeddingUsage + +```python +class EmbeddingUsage(ModelUsage): + """ + Model class for embedding usage. + """ + tokens: int # Tokens used + total_tokens: int # Total tokens used + unit_price: Decimal # Unit price + price_unit: Decimal # Price unit, i.e., unit price based on how many tokens + total_price: Decimal # Total cost + currency: str # Currency unit + latency: float # Request time (s) +``` + +*** + +#### RerankResult + +```python +class RerankResult(BaseModel): + """ + Model class for rerank result. + """ + model: str # Actually used model + docs: list[RerankDocument] # List of reranked segments +``` + +#### RerankDocument + +```python +class RerankDocument(BaseModel): + """ + Model class for rerank document. + """ + index: int # Original sequence number + text: str # Segment text content + score: float # Score +``` + +## 相关资源 + +- [模型设计规则](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - 了解模型配置的标准 +- [模型插件介绍](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules) - 快速了解模型插件的基本概念 +- [快速集成新模型](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 学习如何向现有提供商添加新模型 +- [创建新模型提供商](/zh/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) - 学习如何开发全新的模型提供商 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/model-schema.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx b/zh/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx new file mode 100644 index 00000000..6a4a9e24 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx @@ -0,0 +1,52 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Multilingual README +language: en +title: 多语言 README +description: 本文介绍 Dify 插件多语言 README 的文件规范及其在 Dify Marketplace 中的显示规则。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme)。 + +你可以为插件创建多语言 README,这些 README 将根据用户的首选语言显示在 [Dify Marketplace](https://marketplace.dify.ai) 和其他位置。 + +### README **文件规范** + +| **语言** | 是否必需 | 文件名 | 路径 | **描述** | +| :------------------ | :------- | :-------------------------- | :----------------------------------------------------- | :--------------------------------------------------------------- | +| **英语** | 是 | `README.md` | 插件根目录 | / | +| **其他语言** | 否 | `README_.md` | 插件根目录下的 `readme` 文件夹中 | 目前支持日语、葡萄牙语和简体中文。 | + +以下是目录结构示例: + +```bash +... +├── main.py +├── manifest.yaml +├── readme +│ ├── README_ja_JP.md +│ ├── README_pt_BR.md +│ └── README_zh_Hans.md +├── README.md +... +``` + +### 多语言 README 在 **Marketplace 中的显示方式** + +当你的插件有用户首选语言的 README 时,Dify Marketplace 中的插件详情页将显示该语言版本的 README。 + +![](/images/plugin_details_page_en.jpeg) + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/multilingual-readme.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx b/zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx new file mode 100644 index 00000000..edfa5484 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx @@ -0,0 +1,162 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Persistent Storage KV +language: en +title: 持久化存储 +description: 了解如何使用内置的键值数据库在 Dify 插件中实现持久化存储,以在多次交互中维护状态。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv)。 + +## 概述 + +大多数插件工具和端点以无状态的单轮交互模型运行: +1. 接收请求 +2. 处理数据 +3. 返回响应 +4. 结束交互 + +然而,许多实际应用需要在多次交互中维护状态。这就是**持久化存储**变得至关重要的原因。 + + +持久化存储机制允许插件在同一工作区内持久存储数据,从而实现有状态应用和记忆功能。 + + +Dify 目前为插件提供键值(KV)存储系统,并计划根据开发者需求在未来引入更灵活、更强大的存储接口。 + +## 访问存储 + +所有存储操作都通过插件会话中可用的 `storage` 对象执行: + +```python +# Access the storage interface +storage = self.session.storage +``` + +## 存储操作 + +### 存储数据 + +使用 `set` 方法存储数据: + +```python +def set(self, key: str, val: bytes) -> None: + """ + Store data in persistent storage + + Parameters: + key: Unique identifier for your data + val: Binary data to store (bytes) + """ + pass +``` + + +值必须是 `bytes` 格式。这提供了存储各种类型数据的灵活性,包括文件。 + + +#### 示例:存储不同数据类型 + +```python +# String data (must convert to bytes) +storage.set("user_name", "John Doe".encode('utf-8')) + +# JSON data +import json +user_data = {"name": "John", "age": 30, "preferences": ["AI", "NLP"]} +storage.set("user_data", json.dumps(user_data).encode('utf-8')) + +# File data +with open("image.jpg", "rb") as f: + image_data = f.read() + storage.set("profile_image", image_data) +``` + +### 检索数据 + +使用 `get` 方法检索存储的数据: + +```python +def get(self, key: str) -> bytes: + """ + Retrieve data from persistent storage + + Parameters: + key: Unique identifier for your data + + Returns: + The stored data as bytes, or None if key doesn't exist + """ + pass +``` + +#### 示例:检索和转换数据 + +```python +# Retrieving string data +name_bytes = storage.get("user_name") +if name_bytes: + name = name_bytes.decode('utf-8') + print(f"Retrieved name: {name}") + +# Retrieving JSON data +import json +user_data_bytes = storage.get("user_data") +if user_data_bytes: + user_data = json.loads(user_data_bytes.decode('utf-8')) + print(f"User preferences: {user_data['preferences']}") +``` + +### 删除数据 + +使用 `delete` 方法删除存储的数据: + +```python +def delete(self, key: str) -> None: + """ + Delete data from persistent storage + + Parameters: + key: Unique identifier for the data to delete + """ + pass +``` + +## 最佳实践 + + + + 为键创建一致的命名方案,以避免冲突并使代码更易于维护。 + + + 在处理数据之前始终检查数据是否存在,因为键可能不存在。 + + + 在存储之前将复杂对象转换为 JSON 或其他序列化格式。 + + + 将存储操作包装在 try/except 块中,以优雅地处理潜在错误。 + + + +## 常见用例 + +- **用户偏好**:在会话之间存储用户设置和偏好 +- **对话历史**:维护先前对话的上下文 +- **API 令牌**:安全存储认证令牌 +- **缓存数据**:存储频繁访问的数据以减少 API 调用 +- **文件存储**:存储用户上传的文件或生成的内容 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/persistent-storage-kv.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx b/zh/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx new file mode 100644 index 00000000..32065a3e --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx @@ -0,0 +1,253 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Plugin info by Manifest +language: en +title: Manifest +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest)。 + +Manifest 是一个符合 YAML 规范的文件,定义了**插件**最基本的信息,包括但不限于插件名称、作者、包含的工具、模型等。关于插件的整体架构,请参阅[插件开发基本概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin)和[开发者速查表](/zh/develop-plugin/dev-guides-and-walkthroughs/cheatsheet)。 + +如果该文件的格式不正确,插件的解析和打包过程将会失败。 + +### 代码示例 + +以下是一个简单的 Manifest 文件示例。每个数据项的含义和功能将在后面解释。 + +其他插件的参考代码,请参阅 [GitHub 代码仓库](https://github.com/langgenius/dify-official-plugins/blob/main/tools/google/manifest.yaml)。 + +```yaml +version: 0.0.1 +type: "plugin" +author: "Yeuoly" +name: "neko" +label: + en_US: "Neko" +created_at: "2024-07-12T08:03:44.658609186Z" +icon: "icon.svg" +resource: + memory: 1048576 + permission: + tool: + enabled: true + model: + enabled: true + llm: true + endpoint: + enabled: true + app: + enabled: true + storage: + enabled: true + size: 1048576 +plugins: + endpoints: + - "provider/neko.yaml" +meta: + version: 0.0.1 + arch: + - "amd64" + - "arm64" + runner: + language: "python" + version: "3.10" + entrypoint: "main" +privacy: "./privacy.md" +``` + +### 结构 + + + 插件的版本。 + + + + 插件类型,目前仅支持 `plugin`,未来将支持 `bundle`。 + + + + 作者,定义为 Marketplace 中的组织名称。 + + + + 多语言名称。 + + + + 创建时间,Marketplace 要求不能晚于当前时间。 + + + + 图标路径。 + + + + 申请的资源。 + + + 最大内存使用量,主要与 SaaS 上的 AWS Lambda 资源申请相关,单位为字节。 + + + + 权限申请。 + + + 工具反向调用权限。 + + + 是否启用工具权限。 + + + + + 模型反向调用权限。 + + + 是否启用模型权限。 + + + + 是否启用大语言模型权限。 + + + + 是否启用文本嵌入模型权限。 + + + + 是否启用重排序模型权限。 + + + + 是否启用文本转语音模型权限。 + + + + 是否启用语音转文本模型权限。 + + + + 是否启用内容审核模型权限。 + + + + + 节点反向调用权限。 + + + 是否启用节点权限。 + + + + + 注册 `endpoint` 的权限。 + + + 是否启用 endpoint 权限。 + + + + + `app` 反向调用权限。 + + + 是否启用 app 权限。 + + + + + 申请持久化存储的权限。 + + + 是否启用存储权限。 + + + + 允许的最大持久化存储大小,单位为字节。 + + + + + + + 插件扩展的具体能力的 `yaml` 文件列表。使用插件包内的绝对路径。例如,如果你需要扩展一个模型,你需要定义一个类似 `openai.yaml` 的文件,在这里填写文件路径,并且该路径下的文件必须实际存在,否则打包将失败。 + + + 不允许同时扩展工具和模型。 + + + + 不允许没有任何扩展。 + + + + 不允许同时扩展模型和 Endpoints。 + + + + 目前,每种类型的扩展只支持一个 provider。 + + + + [工具](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) provider 的插件扩展。 + + + + [模型](/zh/develop-plugin/features-and-specs/plugin-types/model-designing-rules) provider 的插件扩展。 + + + + [Endpoints](/zh/develop-plugin/dev-guides-and-walkthroughs/develop-a-slack-bot-plugin) provider 的插件扩展。 + + + + [智能体策略](/zh/develop-plugin/features-and-specs/advanced-development/reverse-invocation) provider 的插件扩展。 + + + + + 插件的元数据。 + + + `manifest` 格式版本,初始版本为 `0.0.1`。 + + + + 支持的架构,目前仅支持 `amd64` 和 `arm64`。 + + + + 运行时配置。 + + + 编程语言。目前仅支持 Python。 + + + + 语言版本,目前仅支持 `3.12`。 + + + + 程序入口点,在 Python 下应为 `main`。 + + + + + + 指定插件隐私政策文件的相对路径或 URL,例如 `"./privacy.md"` 或 `"https://your-web/privacy"`。如果你计划在 Dify Marketplace 上架插件,**此字段为必填**,以提供清晰的用户数据使用和隐私声明。详细填写指南请参阅[插件隐私数据保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines)。 + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/plugin-info-by-manifest.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx b/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx new file mode 100644 index 00000000..79cf9fb8 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin.mdx @@ -0,0 +1,33 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Remote Debug a Plugin +language: en +title: 插件调试 +description: 本文档介绍如何使用 Dify 的远程调试功能来测试插件。文档详细说明了如何获取调试信息、配置环境变量文件、启动插件远程调试以及验证插件安装状态。通过这种方法,开发者可以在本地开发的同时,在 Dify 环境中实时测试插件。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)。 + +完成插件开发后,下一步是测试插件能否正常工作。Dify 提供了便捷的远程调试方法,帮助你在测试环境中快速验证插件功能。 + +前往["插件管理"](https://cloud.dify.ai/plugins)页面,获取远程服务器地址和调试 Key。 + +![远程调试插件](https://assets-docs.dify.ai/2024/12/053415ef127f1f4d6dd85dd3ae79626a.png) + +返回插件项目,复制 `.env.example` 文件并重命名为 `.env`,然后填入你获取的远程服务器地址和调试 Key 信息。 + +`.env` 文件: + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_URL=debug.dify.ai:5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +运行 `python -m main` 命令启动插件。在插件页面,你可以看到插件已安装到工作区,团队的其他成员也可以访问该插件。 + +![插件已安装到工作区](https://assets-docs.dify.ai/2024/12/ec26e5afc57bbfeb807719638f603807.png) diff --git a/zh/develop-plugin/features-and-specs/plugin-types/tool.mdx b/zh/develop-plugin/features-and-specs/plugin-types/tool.mdx new file mode 100644 index 00000000..ba603853 --- /dev/null +++ b/zh/develop-plugin/features-and-specs/plugin-types/tool.mdx @@ -0,0 +1,393 @@ +--- +dimensions: + type: + primary: reference + detail: core + level: beginner +standard_title: Tool +language: en +title: 工具返回 +description: 本文档详细介绍了 Dify 插件中工具的数据结构和使用方法。涵盖如何返回不同类型的消息(图片 URL、链接、文本、文件、JSON)、如何创建变量和流式变量消息,以及如何定义工具输出变量模式以便在工作流中引用。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/features-and-specs/plugin-types/tool)。 + +## 概述 + + +在深入了解详细的接口文档之前,请确保您对 Dify 插件的工具集成流程有基本的了解。 + + + + + 返回不同类型的消息,如文本、链接、图片和 JSON + + + 创建和操作变量以实现工作流集成 + + + 定义自定义输出变量以供工作流引用 + + + +## 数据结构 + +### 消息返回 + + +Dify 支持多种消息类型,如 `text`、`links`、`images`、`file BLOBs` 和 `JSON`。这些消息可以通过专用接口返回。 + + +默认情况下,工作流中工具的输出包含三个固定变量:`files`、`text` 和 `json`。以下方法可帮助您为这些变量填充适当的内容。 + + +虽然您可以使用 `create_image_message` 等方法返回图片,但工具也支持自定义输出变量,这使得在工作流中引用特定数据更加方便。 + + +### 消息类型 + + +```python Image URL +def create_image_message(self, image: str) -> ToolInvokeMessage: + """ + Return an image URL message + + Dify will automatically download the image from the provided URL + and display it to the user. + + Args: + image: URL to an image file + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python Link +def create_link_message(self, link: str) -> ToolInvokeMessage: + """ + Return a clickable link message + + Args: + link: URL to be displayed as a clickable link + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python Text +def create_text_message(self, text: str) -> ToolInvokeMessage: + """ + Return a text message + + Args: + text: Text content to be displayed + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python File +def create_blob_message(self, blob: bytes, meta: dict = None) -> ToolInvokeMessage: + """ + Return a file blob message + + For returning raw file data such as images, audio, video, + or documents (PPT, Word, Excel, etc.) + + Args: + blob: Raw file data in bytes + meta: File metadata dictionary. Include 'mime_type' to specify + the file type, otherwise 'octet/stream' will be used + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python JSON +def create_json_message(self, json: dict) -> ToolInvokeMessage: + """ + Return a formatted JSON message + + Useful for data transmission between workflow nodes. + In agent mode, most LLMs can read and understand JSON data. + + Args: + json: Python dictionary to be serialized as JSON + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + + + + + 将被下载并显示的图片 URL + + + + 将显示为可点击链接的 URL + + + + 要显示的文本内容 + + + + 字节格式的原始文件数据 + + + + 文件元数据,包括: + - `mime_type`:文件的 MIME 类型(例如 "image/png") + - 与文件相关的其他元数据 + + + + 要序列化为 JSON 的 Python 字典 + + + + +处理文件 blob 时,请始终在 `meta` 字典中指定 `mime_type`,以确保文件得到正确处理。例如:`{"mime_type": "image/png"}`。 + + +### 变量 + + +```python Standard Variable +from typing import Any + +def create_variable_message(self, variable_name: str, variable_value: Any) -> ToolInvokeMessage: + """ + Create a named variable for workflow integration + + For non-streaming output variables. If multiple instances with the + same name are created, the latest one overrides previous values. + + Args: + variable_name: Name of the variable to create + variable_value: Value of the variable (any Python data type) + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + +```python Streaming Variable +def create_stream_variable_message( + self, variable_name: str, variable_value: str +) -> ToolInvokeMessage: + """ + Create a streaming variable with typewriter effect + + When referenced in an answer node in a chatflow application, + the text will be output with a typewriter effect. + + Args: + variable_name: Name of the variable to create + variable_value: String value to stream (only strings supported) + + Returns: + ToolInvokeMessage: Message object for the tool response + """ + pass +``` + + + + + 要创建或更新的变量名称 + + + + 要分配给变量的值: + - 对于标准变量:任何 Python 数据类型 + - 对于流式变量:仅支持字符串数据 + + + + +流式变量方法(`create_stream_variable_message`)目前仅支持字符串数据。复杂数据类型无法通过打字机效果进行流式输出。 + + +## 自定义输出变量 + + +要在工作流应用中引用工具的输出变量,您需要定义可能输出的变量。这是通过在工具清单中使用 [JSON Schema](https://json-schema.org/) 格式完成的。 + + +### 定义输出模式 + + +```yaml Tool Manifest with Output Schema +identity: + author: example_author + name: example_tool + label: + en_US: Example Tool + zh_Hans: 示例工具 + ja_JP: ツール例 + pt_BR: Ferramenta de exemplo +description: + human: + en_US: A simple tool that returns a name + zh_Hans: 返回名称的简单工具 + ja_JP: 名前を返す簡単なツール + pt_BR: Uma ferramenta simples que retorna um nome + llm: A simple tool that returns a name variable +output_schema: + type: object + properties: + name: + type: string + description: "The name returned by the tool" + age: + type: integer + description: "The age returned by the tool" + profile: + type: object + properties: + interests: + type: array + items: + type: string + location: + type: string +``` + + + + + 定义工具输出模式的根对象 + + + + 工具输出模式必须为 "object" + + + + 所有可能输出变量的字典 + + + + 每个输出变量的定义,包括其类型和描述 + + + + +即使定义了输出模式,您仍需要在实现代码中使用 `create_variable_message()` 实际返回变量。否则,工作流将收到该变量的 `None` 值。 + + +### 实现示例 + + +```python Basic Variable Example +def run(self, inputs): + # Process inputs and generate a name + generated_name = "Alice" + + # Return the name as a variable that matches the output_schema + return self.create_variable_message("name", generated_name) +``` + +```python Complex Structure Example +def run(self, inputs): + # Generate complex structured data + user_data = { + "name": "Bob", + "age": 30, + "profile": { + "interests": ["coding", "reading", "hiking"], + "location": "San Francisco" + } + } + + # Return individual variables + self.create_variable_message("name", user_data["name"]) + self.create_variable_message("age", user_data["age"]) + self.create_variable_message("profile", user_data["profile"]) + + # Also return a text message for display + return self.create_text_message(f"User {user_data['name']} processed successfully") +``` + + + +对于复杂的工作流,您可以定义多个输出变量并全部返回。这为工作流设计者使用您的工具时提供了更大的灵活性。 + + +## 示例 + +### 完整的工具实现 + + +```python Weather Forecast Tool +import requests +from typing import Any + +class WeatherForecastTool: + def run(self, inputs: dict) -> Any: + # Get location from inputs + location = inputs.get("location", "London") + + try: + # Call weather API (example only) + weather_data = self._get_weather_data(location) + + # Create variables for workflow use + self.create_variable_message("temperature", weather_data["temperature"]) + self.create_variable_message("conditions", weather_data["conditions"]) + self.create_variable_message("forecast", weather_data["forecast"]) + + # Create a JSON message for data transmission + self.create_json_message(weather_data) + + # Create an image message for the weather map + self.create_image_message(weather_data["map_url"]) + + # Return a formatted text response + return self.create_text_message( + f"Weather in {location}: {weather_data['temperature']}°C, {weather_data['conditions']}. " + f"Forecast: {weather_data['forecast']}" + ) + + except Exception as e: + # Handle errors gracefully + return self.create_text_message(f"Error retrieving weather data: {str(e)}") + + def _get_weather_data(self, location: str) -> dict: + # Mock implementation - in a real tool, this would call a weather API + return { + "location": location, + "temperature": 22, + "conditions": "Partly Cloudy", + "forecast": "Sunny with occasional showers tomorrow", + "map_url": "https://example.com/weather-map.png" + } +``` + + + +设计工具时,请同时考虑直接输出(用户看到的内容)和变量输出(其他工作流节点可以使用的内容)。这种分离为工具的使用方式提供了灵活性。 + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/features-and-specs/plugin-types/tool.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/getting-started/cli.mdx b/zh/develop-plugin/getting-started/cli.mdx new file mode 100644 index 00000000..565c541a --- /dev/null +++ b/zh/develop-plugin/getting-started/cli.mdx @@ -0,0 +1,156 @@ +--- +dimensions: + type: + primary: conceptual + detail: architecture + level: beginner +standard_title: CLI +language: en +title: CLI +description: Dify 插件开发命令行界面 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/getting-started/cli)。 + +使用命令行界面(CLI)设置和打包你的 Dify 插件。CLI 提供了一种简化的方式来管理你的插件开发工作流,从初始化到打包。 + +本指南将指导你如何使用 CLI 进行 Dify 插件开发。 + +## 前提条件 +在开始之前,请确保已安装以下内容: +- Python 版本 ≥ 3.12 +- Dify CLI +- Homebrew(适用于 Mac 用户) + +## 创建 Dify 插件项目 + + + + ```bash + brew tap langgenius/dify + brew install dify + ``` + + + 从 [Dify GitHub 发布页面](https://github.com/langgenius/dify-plugin-daemon/releases) 获取最新的 Dify CLI + + ```bash + # Download dify-plugin-darwin-arm64 + chmod +x dify-plugin-darwin-arm64 + mv dify-plugin-darwin-arm64 dify + sudo mv dify /usr/local/bin/ + ``` + + + +现在你已成功安装 Dify CLI。你可以通过运行以下命令来验证安装: + + +```bash +dify version +``` + + +你可以使用以下命令创建一个新的 Dify 插件项目: + +```bash +dify plugin init +``` + +根据提示填写必填字段: + +```bash +Edit profile of the plugin +Plugin name (press Enter to next step): hello-world +Author (press Enter to next step): langgenius +Description (press Enter to next step): hello world example +Repository URL (Optional) (press Enter to next step): Repository URL (Optional) + Enable multilingual README: [✔] English is required by default + +Languages to generate: + English: [✔] (required) + → 简体中文 (Simplified Chinese): [✔] + 日本語 (Japanese): [✘] + Português (Portuguese - Brazil): [✘] + +Controls: + ↑/↓ Navigate • Space/Tab Toggle selection • Enter Next step +``` + +选择 `python` 并按 Enter 继续使用 Python 插件模板。 + +```bash +Select the type of plugin you want to create, and press `Enter` to continue +Before starting, here's some basic knowledge about Plugin types in Dify: + +- Tool: Tool Providers like Google Search, Stable Diffusion, etc. Used to perform specific tasks. +- Model: Model Providers like OpenAI, Anthropic, etc. Use their models to enhance AI capabilities. +- Endpoint: Similar to Service API in Dify and Ingress in Kubernetes. Extend HTTP services as endpoints with custom logi +- Agent Strategy: Implement your own agent strategies like Function Calling, ReAct, ToT, CoT, etc. + +Based on the ability you want to extend, Plugins are divided into four types: Tool, Model, Extension, and Agent Strategy + +- Tool: A tool provider that can also implement endpoints. For example, building a Discord Bot requires both Sending and +- Model: Strictly for model providers, no other extensions allowed. +- Extension: For simple HTTP services that extend functionality. +- Agent Strategy: Implement custom agent logic with a focused approach. + +We've provided templates to help you get started. Choose one of the options below: +-> tool + agent-strategy + llm + text-embedding + rerank + tts + speech2text + moderation + extension +``` + +输入默认的 dify 版本,留空则使用最新版本: + +```bash +Edit minimal Dify version requirement, leave it blank by default +Minimal Dify version (press Enter to next step): +``` + +现在你已准备就绪!CLI 将创建一个以你提供的插件名称命名的新目录,并为你的插件设置基本结构。 + +```bash +cd hello-world +``` + +## 运行插件 + +确保你在 hello-world 目录中 + +```bash +cp .env.example .env +``` + +编辑 `.env` 文件以设置插件的环境变量,例如 API 密钥或其他配置。你可以在 Dify 仪表板中找到这些变量。登录到你的 Dify 环境,点击右上角的"插件"图标,然后点击调试图标(或类似虫子的图标)。在弹出窗口中,复制"API Key"和"Host Address"。(请参考你本地对应的截图,其中显示了获取密钥和主机地址的界面) + + +```bash +INSTALL_METHOD=remote +REMOTE_INSTALL_HOST=debug-plugin.dify.dev +REMOTE_INSTALL_PORT=5003 +REMOTE_INSTALL_KEY=********-****-****-****-************ +``` + +现在你可以使用以下命令在本地运行你的插件: + +```bash +pip install -r requirements.txt +python -m main +``` + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/cli.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/getting-started/getting-started-dify-plugin.mdx b/zh/develop-plugin/getting-started/getting-started-dify-plugin.mdx new file mode 100644 index 00000000..ea7006f6 --- /dev/null +++ b/zh/develop-plugin/getting-started/getting-started-dify-plugin.mdx @@ -0,0 +1,108 @@ +--- +dimensions: + type: + primary: conceptual + detail: introduction + level: beginner +standard_title: Getting Started with Dify Plugin Development +language: en +title: Dify 插件 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/getting-started/getting-started-dify-plugin)。 + +Dify 插件是模块化组件,可为 AI 应用添加额外的功能。它们允许你将外部服务、自定义功能和专业工具集成到基于 Dify 构建的 AI 应用中。 + + + + + +通过插件,你的 AI 应用可以: +- 连接外部 API +- 处理不同类型的数据 +- 执行专业计算 +- 执行现实世界的操作 + +## 插件类型 + + + + 将 AI 模型打包并作为插件进行管理 + + 了解更多 + + + 为智能体和工作流构建专业功能 + + 了解更多 + + + 为自主智能体创建自定义推理策略 + + 了解更多 + + + 通过 HTTP Webhooks 实现与外部服务的集成 + + 了解更多 + + + +## 其他资源 + + + + 高效插件开发的工具和技术 + + + 打包并与 Dify 社区分享你的插件 + + + 技术规范和文档 + + + 与其他开发者交流并为生态系统做出贡献 + + + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/getting-started-dify-plugin.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/faq/faq.mdx b/zh/develop-plugin/publishing/faq/faq.mdx new file mode 100644 index 00000000..accd8433 --- /dev/null +++ b/zh/develop-plugin/publishing/faq/faq.mdx @@ -0,0 +1,49 @@ +--- +dimensions: + type: + primary: operational + detail: maintenance + level: beginner +todo: Developers (Contributors) should thoroughly test before releasing; debugging + should not be the user's (Dify User / Consumer) responsibility. +standard_title: Faq +language: en +title: 常见问题 +description: 本文档解答了关于 Dify 插件开发和安装的常见问题,包括如何解决插件上传失败(通过修改 author 字段)以及如何处理插件安装时的验证异常(通过设置 FORCE_VERIFYING_SIGNATURE 环境变量)。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/faq/faq)。 + +## 安装时插件上传失败怎么办? + +**错误详情**:出现错误信息 `PluginDaemonBadRequestError: plugin_unique_identifier is not valid`。 + +**解决方案**:将插件项目下 `manifest.yaml` 文件和 `/provider` 路径下 `.yaml` 文件中的 `author` 字段修改为你的 GitHub ID。 + +重新运行插件打包命令并安装新的插件包。 + +## 插件安装过程中遇到异常应该如何处理? + +**问题描述**:插件安装过程中遇到异常信息:`plugin verification has been enabled, and the plugin you want to install has a bad signature`。应该如何处理? + +**解决方案**:在 `/docker/.env` 配置文件末尾添加字段 `FORCE_VERIFYING_SIGNATURE=false`。然后,运行以下命令重启 Dify 服务: + +```bash +cd docker +docker compose down +docker compose up -d +``` + +添加此字段后,Dify 平台将允许安装所有未在 Dify Marketplace 上架(审核)的插件,这可能带来安全风险。 + +建议先在测试/沙盒环境中安装插件,确认其安全性后再安装到生产环境。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/faq/faq.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/plugin-dev-zh/0321-plugin-auto-publish-pr.mdx b/zh/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx similarity index 62% rename from plugin-dev-zh/0321-plugin-auto-publish-pr.mdx rename to zh/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx index 25d4eb6a..8ff683a3 100644 --- a/plugin-dev-zh/0321-plugin-auto-publish-pr.mdx +++ b/zh/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx @@ -5,50 +5,52 @@ dimensions: detail: deployment level: beginner standard_title: Plugin Auto Publish PR -language: zh -title: 自动发布插件 -description: 本文档介绍了如何使用GitHub Actions自动化Dify插件的发布流程,包括配置步骤、参数说明及使用方法,帮助插件开发者简化发布更新流程,无需手动 +language: en +title: 通过 PR 自动发布插件 +description: 本文档介绍如何使用 GitHub Actions 自动化 Dify 插件的发布流程,包括配置步骤、参数说明和使用方法,帮助插件开发者简化发布流程,无需手动干预。 --- + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr)。 + ### 背景 -当插件贡献者需要严肃更新 **已被其他用户使用的 Dify 插件** 时,流程通常非常繁琐:贡献者需要先修改插件源码并更新版本号,将更改推送到插件源码仓库,并在 fork 的 dify-plugin 仓库中创建新分支。随后,贡献者需要手动打包插件并上传打包文件,再创建 PR 合并到原始 dify-plugin 仓库。这个过程必须在每次插件代码变更时重复,非常耗时低效。 +更新其他人正在使用的插件可能很繁琐。传统方式需要修改代码、更新版本、推送更改、创建分支、打包文件并手动提交 PR——这是一个重复性的流程,会拖慢开发进度。 -为了简化这一流程,我们构建了基于 GitHub Actions 的自动化工作流 **Plugin Auto-PR**。借助这个工具,插件贡献者可以一键完成插件打包、分支推送以及 PR 创建。 +因此,我们创建了 **Plugin Auto-PR**,这是一个 GitHub Actions 工作流,可以自动化整个流程。现在你只需一个操作就能完成打包、推送和创建 PR,专注于构建优秀的插件。 -### 概念简介 +### 概念 #### GitHub Actions -GitHub Actions 是 GitHub 提供的内置 CI/CD 服务,可以自动化各种构建、测试和部署任务。 +GitHub Actions 可以在 GitHub 中自动化你的开发任务。 -**运行原理**:当触发条件(如 push 代码)满足时,GitHub 会自动分配虚拟机运行你的工作流。所有操作都在 GitHub 云端完成。 +**工作原理**:当触发时(例如,通过代码推送),它会在基于云的虚拟机中运行你的工作流,自动处理从构建到部署的所有事项。 ![Workflow](https://assets-docs.dify.ai/2025/04/60534de8e220f860947b32a8329a8349.png) -**免费额度**: +**限制**: -* 公共仓库:无限制 +* 公开仓库:无限制 * 私有仓库:每月 2000 分钟 #### Plugin Auto-PR -**运行原理**: +**工作原理**: -1. 当你推送代码到插件源码仓库的 main 分支时,触发工作流 -2. 工作流从 `manifest.yaml` 文件中读取插件信息 -3. 自动打包插件为 `.difypkg` 文件 -4. 将打包文件推送到你 fork 的 `dify-plugins` 仓库中 +1. 当你将代码推送到插件源代码仓库的主分支时,工作流会被触发 +2. 工作流从 `manifest.yaml` 文件读取插件信息 +3. 自动将插件打包为 `.difypkg` 文件 +4. 将打包后的文件推送到你 fork 的 `dify-plugins` 仓库 5. 创建新分支并提交更改 -6. 自动创建 PR 请求合并到上游仓库 +6. 自动创建 PR 以合并到上游仓库 -### 环境准备 +### 前提条件 -#### 仓库要求 +#### 仓库 -* 你已拥有自己的插件源码仓库(例如:`your-name/plugin-source`) -* 你已拥有自己的 fork 插件仓库(例如:`your-name/dify-plugins`) -* 你的 fork 仓库中已有插件目录结构: +* 你已经有自己的插件源代码仓库(例如,`your-name/plugin-source`) +* 你已经有自己 fork 的插件仓库(例如,`your-name/dify-plugins`) +* 你 fork 的仓库已经有插件目录结构: ``` dify-plugins/ @@ -56,58 +58,58 @@ dify-plugins/ └── plugin-name ``` -#### 权限要求 +#### 权限 -此工作流需要适当的权限才能正常运行: +此工作流需要适当的权限才能运行: -* 你需要创建一个有足够权限的 GitHub Personal Access Token (PAT) -* 该 PAT 必须有权向你的 fork 仓库推送代码 -* 该 PAT 必须有权向上游仓库创建 PR +* 你需要创建一个具有足够权限的 GitHub 个人访问令牌(PAT) +* PAT 必须有权限将代码推送到你 fork 的仓库 +* PAT 必须有权限向上游仓库创建 PR -### 参数与配置项说明 +### 参数和配置 -#### 必要参数 +#### 设置要求 -插件自动发布工作流需要你正确配置以下关键元素: +要开始自动发布,你需要两个关键组件: -**manifest.yaml 文件**:这是整个自动化流程的核心配置源。你需要确保以下字段正确无误: +**manifest.yaml 文件**:此文件驱动自动化流程: -* `name`:插件名称(将用于生成包名和分支名) -* `version`:版本号(每次更新时需要递增) -* `author`:GitHub 用户名(用于确定目标仓库路径) +* `name`:你的插件名称(影响包和分支名称) +* `version`:语义版本号(每次发布时递增) +* `author`:你的 GitHub 用户名(决定仓库路径) -**PLUGIN_ACTION Secret**:你需要在插件源码仓库中正确设置此密钥。 +**PLUGIN\_ACTION Secret**:你需要将此 secret 添加到你的插件源代码仓库: -* 值要求:必须是具有足够权限的个人访问令牌(PAT) -* 权限要求:能够推送分支到你的 fork 仓库,能够创建 PR 到上游仓库 +* 值:必须是具有足够权限的个人访问令牌(PAT) +* 权限:能够将分支推送到你 fork 的仓库并向上游仓库创建 PR #### 自动生成的参数 -工作流会**自动处理以下内容**,无需手动干预: +设置完成后,工作流会自动处理这些参数: -* GitHub 用户名:从 `manifest.yaml` 的 `author` 字段读取 -* 作者文件夹名称:与 `author` 字段保持一致 -* 插件名称:从 `manifest.yaml` 的 `name` 字段读取 -* 分支名称:`bump-{插件名}-plugin-{版本号}` -* 打包文件名:`{插件名}-{版本号}.difypkg` -* PR 标题和内容:基于插件名称和版本自动生成 +* GitHub 用户名:从 `manifest.yaml` 中的 `author` 字段读取 +* 作者文件夹名称:与 `author` 字段一致 +* 插件名称:从 `manifest.yaml` 中的 `name` 字段读取 +* 分支名称:`bump-{plugin-name}-plugin-{version}` +* 包文件名:`{plugin-name}-{version}.difypkg` +* PR 标题和内容:根据插件名称和版本自动生成 -### 安装配置步骤 +### 分步指南 - 确保你已经 fork 了官方的 `dify-plugins` 仓库,并且有自己的插件源码仓库。 + 确保你已经 fork 了官方的 `dify-plugins` 仓库,并且有自己的插件源代码仓库。 - 导航到你的插件源码仓库,点击 **Settings > Secrets and variables > Actions > New repository secret**,创建 GitHub Secret: + 导航到你的插件源代码仓库,点击 **Settings > Secrets and variables > Actions > New repository secret**,然后创建一个 GitHub Secret: - * 名称填写: `PLUGIN_ACTION` - * 值填写: 拥有目标仓库(`your-name/dify-plugins`)写入权限的 GitHub Personal Access Token (PAT) + * 名称:`PLUGIN_ACTION` + * 值:具有目标仓库(`your-name/dify-plugins`)写入权限的 GitHub 个人访问令牌(PAT) Create Secrets - 在仓库中创建 `.github/workflows/`目录,并在此目录中创建名为 `plugin-publish.yml` 的文件,再将以下内容复制到该文件中: + 在你的仓库中创建 `.github/workflows/` 目录,在此目录中创建名为 `plugin-publish.yml` 的文件,并将以下内容复制到文件中: ```yaml # .github/workflows/auto-pr.yml @@ -256,7 +258,7 @@ dify-plugins/ ``` - 确保 `manifest.yaml` 文件正确设置以下字段: + 确保以下字段正确设置: ```yaml version: 0.0.x # Version number @@ -268,41 +270,41 @@ dify-plugins/ ### 使用指南 -#### 初次使用流程 +#### 首次设置 -首次设置自动发布工作流时,需要完成以下步骤: +首次设置自动发布工作流时,请完成以下步骤: 1. 确保你已经 fork 了官方的 `dify-plugins` 仓库 -2. 确保你的插件源码仓库结构正确 -3. 在插件源码仓库中设置 `PLUGIN_ACTION Secret` +2. 确保你的插件源代码仓库结构正确 +3. 在你的插件源代码仓库中设置 `PLUGIN_ACTION Secret` 4. 创建工作流文件 `.github/workflows/plugin-publish.yml` -5. 确保 `manifest.yaml` 文件中的 `name` 和 `author` 字段正确配置 +5. 确保 `manifest.yaml` 文件中的 `name` 和 `author` 字段配置正确 -#### 后续更新流程 +#### 后续更新 -设置完成后,每次需要发布新版本时,只需: +设置完成后,发布新版本: -1. 修改插件代码 +1. 修改代码 2. 更新 `manifest.yaml` 中的 `version` 字段 ![Release](https://assets-docs.dify.ai/2025/04/9eed2b9110e91e18008b399e58198f03.png) -3. 将所有更改推送到 main 分支 -4. 等待 GitHub Actions 自动完成打包、分支创建和 PR 提交 +3. 将所有更改推送到主分支 +4. 等待 GitHub Actions 完成打包、分支创建和 PR 提交 -### 执行效果展示 +### 结果 -当你推送代码到插件源码仓库的 main 分支时,GitHub Actions 将自动执行发布流程: +当你将代码推送到插件源代码仓库的主分支时,GitHub Actions 将自动执行发布流程: -* 自动打包插件为 `{plugin-name}-{version}.difypkg` 格式 -* 自动将打包文件推送到目标仓库 -* 自动创建 PR 合并到 fork 仓库 +* 以 `{plugin-name}-{version}.difypkg` 格式打包插件 +* 将打包后的文件推送到目标仓库 +* 创建 PR 以合并到 fork 仓库 ![Outcome](https://assets-docs.dify.ai/2025/04/60d5de910c6ce2482c67ddec3320311f.png) ### 示例仓库 -你可以参考[示例仓库](https://github.com/Yevanchen/exa-in-dify),了解完整的配置细节和最佳实践。 +查看[示例仓库](https://github.com/Yevanchen/exa-in-dify)以了解配置和最佳实践。 {/* Contributing Section @@ -312,5 +314,4 @@ It will be automatically generated by the script. --- -[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/plugin-dev-zh/0321-plugin-auto-publish-pr.mdx) | [提交问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) - +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/marketplace-listing/release-by-file.mdx b/zh/develop-plugin/publishing/marketplace-listing/release-by-file.mdx new file mode 100644 index 00000000..17eb8dbd --- /dev/null +++ b/zh/develop-plugin/publishing/marketplace-listing/release-by-file.mdx @@ -0,0 +1,75 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: intermediate +standard_title: Release by File +language: en +title: 打包为本地文件并分享 +description: 本文档详细介绍了如何将 Dify 插件项目打包为本地文件并与他人分享。内容涵盖打包插件前的准备工作、使用 Dify 插件开发工具执行打包命令、如何安装生成的 .difypkg 文件,以及如何与其他用户分享插件文件。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/marketplace-listing/release-by-file)。 + +完成插件开发后,你可以将插件项目打包为本地文件并与他人分享。获取插件文件后,可以将其安装到 Dify 工作区。如果你还没有开发过插件,可以参考[插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)。 + +* **特点**: + * 不依赖在线平台,**快速灵活**地分享插件。 + * 适用于**私有插件**或**内部测试**。 +* **发布流程**: + * 将插件项目打包为本地文件。 + * 在 Dify 插件页面上传文件以安装插件。 + +本文将介绍如何将插件项目打包为本地文件,以及如何使用本地文件安装插件。 + +### 前提条件 + +* **Dify 插件开发工具**,详细说明请参考[初始化开发工具](/zh/develop-plugin/getting-started/cli)。 + +配置完成后,在终端中输入 `dify version` 命令,检查是否输出版本信息以确认已安装必要的开发工具。 + +### 打包插件 + +> 在打包插件之前,请确保插件 `manifest.yaml` 文件和 `/provider` 路径下的 `.yaml` 文件中的 `author` 字段与你的 GitHub ID 一致。有关 manifest 文件的详细信息,请参考[通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)。 + +完成插件项目开发后,请确保你已完成[远程调试测试](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)。导航到插件项目的上级目录,运行以下插件打包命令: + +```bash +dify plugin package ./your_plugin_project +``` + +运行命令后,将在当前路径生成一个扩展名为 `.difypkg` 的文件。 + +![生成插件文件](https://assets-docs.dify.ai/2024/12/98e09c04273eace8fe6e5ac976443cca.png) + +### 安装插件 + +访问 Dify 插件管理页面,点击右上角的**安装插件** → **通过本地文件**进行安装,或将插件文件拖放到页面空白区域以安装插件。 + +![安装插件文件](https://assets-docs.dify.ai/2024/12/8c31c4025a070f23455799f942b91a57.png) + +### 发布插件 + +你可以将插件文件分享给他人,或上传到互联网供他人下载。如果你想更广泛地分享你的插件,可以考虑: + +1. [发布到个人 GitHub 仓库](/zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo) - 通过 GitHub 分享插件 +2. [发布到 Dify Marketplace](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - 在官方市场发布插件 + +## 相关资源 + +- [发布插件](/zh/develop-plugin/publishing/marketplace-listing/release-overview) - 了解各种发布方式 +- [初始化开发工具](/zh/develop-plugin/getting-started/cli) - 配置插件开发环境 +- [远程调试插件](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - 了解插件调试方法 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 定义插件元数据 +- [插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin) - 从零开始开发插件 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-by-file.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/marketplace-listing/release-overview.mdx b/zh/develop-plugin/publishing/marketplace-listing/release-overview.mdx new file mode 100644 index 00000000..13e0f0fc --- /dev/null +++ b/zh/develop-plugin/publishing/marketplace-listing/release-overview.mdx @@ -0,0 +1,96 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: beginner +standard_title: Release Overview +language: en +title: 发布插件 +description: 本文档介绍了三种发布 Dify 插件的方式——官方 Marketplace、开源 GitHub 仓库和本地插件文件包。详细说明了每种方式的特点、发布流程和适用场景,并提供了具体的发布建议,以满足不同开发者的需求。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/marketplace-listing/release-overview)。 + +### 发布方式 + +为满足不同开发者的发布需求,Dify 提供以下三种插件发布方式。在发布前,请确保你已完成插件的开发和测试,并已阅读[插件开发基础概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin)和[插件开发者指南](/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)。 + +#### **1. Marketplace** + +**简介**:Dify 官方提供的插件市场,用户可以一键浏览、搜索和安装各种插件。 + +**特点**: + +* 插件上线前需经过审核,确保**安全可靠**。 +* 可以直接安装到个人或团队的**工作区**。 + +**发布流程**: + +* 将插件项目提交到 **Dify Marketplace** [代码仓库](https://github.com/langgenius/dify-plugins)。 +* 经官方审核后,插件将公开发布到市场,供其他用户安装使用。 + +详细说明请参考: + +[发布到 Dify Marketplace](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) + +#### 2. **GitHub 仓库** + +**简介**:在 **GitHub** 上开源或托管你的插件,供他人查看、下载和安装。 + +**特点**: + +* 便于**版本管理**和**开源分享**。 +* 用户可通过插件链接直接安装,无需平台审核。 + +**发布流程**: + +* 将插件代码推送到 GitHub 仓库。 +* 分享仓库链接,用户可通过链接将插件集成到其 **Dify 工作区**。 + +详细说明请参考: + +[发布到个人 GitHub 仓库](/zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo) + +#### 3. 插件文件包(本地安装) + +**简介**:将插件打包为本地文件(如 `.difypkg` 格式)并分享给他人安装。 + +**特点**: + +* 不依赖在线平台,**快速灵活**地分享插件。 +* 适用于**私有插件**或**内部测试**。 + +**发布流程**: + +* 将插件项目打包为本地文件。 +* 在 Dify 插件页面点击**上传插件**,选择本地文件即可安装插件。 + +你可以将插件项目打包为本地文件并分享给他人。在插件页面上传文件后,即可将插件安装到你的 Dify 工作区。 + +详细说明请参考: + +[打包为本地文件并分享](/zh/develop-plugin/publishing/marketplace-listing/release-by-file) + +### **发布建议** + +* **想要推广你的插件** → **推荐使用 Marketplace**,通过官方审核确保插件质量,提高曝光度。 +* **开源分享项目** → **推荐使用 GitHub**,便于版本管理和社区协作。 +* **快速分发或内部测试** → **推荐使用插件文件**,安装和分享简单高效。 + +## 相关资源 + +- [插件开发基础概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin) - 全面了解 Dify 插件开发 +- [插件开发者指南](/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - 了解插件提交的标准 +- [插件隐私数据保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines) - 了解隐私政策编写要求 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 了解插件清单文件的配置 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-overview.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx b/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx new file mode 100644 index 00000000..ec7db958 --- /dev/null +++ b/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx @@ -0,0 +1,113 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: intermediate +standard_title: Release to Dify Marketplace +language: en +title: 发布到 Dify Marketplace +description: 本指南详细介绍了将插件发布到 Dify Marketplace 的完整流程,包括提交 PR、审核流程、发布后维护以及其他关键步骤和注意事项。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace)。 + +Dify Marketplace 欢迎合作伙伴和社区开发者提交插件。您的贡献将进一步丰富 Dify 插件的可能性。本指南提供清晰的发布流程和最佳实践建议,帮助您的插件顺利发布并为社区带来价值。如果您还没有开发过插件,可以参考[插件开发:Hello World 指南](/zh/develop-plugin/dev-guides-and-walkthroughs/tool-plugin)。 + +请按照以下步骤将您的插件 Pull Request (PR) 提交到 [GitHub 仓库](https://github.com/langgenius/dify-plugins)进行审核。审核通过后,您的插件将正式上线 Dify Marketplace。 + +### 插件发布流程 + +将插件发布到 Dify Marketplace 包括以下步骤: + +1. 根据[插件开发者指南](/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)完成插件开发和测试; +2. 根据[插件隐私数据保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines)为插件编写隐私政策,并在插件[通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)中包含隐私政策的文件路径或 URL; +3. 完成插件打包; +4. Fork [Dify Plugins](https://github.com/langgenius/dify-plugins) 代码仓库; +5. 在仓库中创建您的个人或组织文件夹,并将打包好的 `.difypkg` 文件上传到您的文件夹中; +6. 按照 GitHub 中的 PR Template 格式提交 Pull Request (PR) 并等待审核; +7. 审核通过后,插件代码将被合并到 Main 分支,插件将自动上线 [Dify Marketplace](https://marketplace.dify.ai/)。 + +插件提交、审核和发布流程图: + +![上传插件的流程](https://assets-docs.dify.ai/2025/01/05df333acfaf662e99316432db23ba9f.png) + +> **注意**:上图中的贡献者协议是指[插件开发者指南](/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)。 + +*** + +### Pull Request (PR) 审核期间 + +积极回应审核者的问题和反馈: + +* **14 天**内未解决的 PR 评论将被标记为过期(可以重新打开)。 +* **30 天**内未解决的 PR 评论将被关闭(无法重新打开,需要创建新的 PR)。 + +*** + +### **Pull Request (PR) 批准后** + +**1. 持续维护** + +* 处理用户报告的问题和功能请求。 +* 当发生重大 API 变更时迁移插件: + * Dify 将提前发布变更通知和迁移说明。 + * Dify 工程师可以提供迁移支持。 + +**2. Marketplace 公测阶段的限制** + +* 避免对现有插件引入破坏性变更。 + +*** + +### 审核流程 + +**1. 审核顺序** + +* PR 按照**先到先审**的原则处理。审核将在 1 周内开始。如有延迟,审核者将通过评论通知 PR 作者。 + +**2. 审核重点** + +* 检查插件名称、描述和设置说明是否清晰且具有指导性。 +* 检查插件的[通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)是否符合格式标准并包含有效的作者联系信息。 + +**3. 插件功能和相关性** + +* 根据[插件开发指南](/zh/develop-plugin/getting-started/getting-started-dify-plugin)测试插件。 +* 确保插件在 Dify 生态系统中具有合理的用途。 + +[Dify.AI](https://dify.ai/) 保留接受或拒绝插件提交的权利。 + +*** + +### 常见问题 + +1. **如何判断插件是否具有唯一性?** + +示例:仅添加多语言版本的 Google 搜索插件应被视为对现有插件的优化。但是,如果插件实现了重大功能改进(例如优化的批处理或错误处理),则可以作为新插件提交。 + +2. **如果我的 PR 被标记为过期或关闭怎么办?** + +被标记为过期的 PR 在处理反馈后可以重新打开。已关闭的 PR(超过 30 天)需要创建新的 PR。 + +3. **在 Beta 测试阶段可以更新插件吗?** + +可以,但应避免破坏性变更。 + +## 相关资源 + +- [发布插件](/zh/develop-plugin/publishing/marketplace-listing/release-overview) - 了解各种发布方法 +- [插件开发者指南](/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - 插件提交标准 +- [插件隐私数据保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines) - 隐私政策编写要求 +- [打包为本地文件并分享](/zh/develop-plugin/publishing/marketplace-listing/release-by-file) - 插件打包方法 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 定义插件元数据 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx b/zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx new file mode 100644 index 00000000..ec5784d0 --- /dev/null +++ b/zh/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx @@ -0,0 +1,92 @@ +--- +dimensions: + type: + primary: operational + detail: deployment + level: intermediate +standard_title: Release to Individual GitHub Repo +language: en +title: 发布到个人 GitHub 仓库 +description: 本文档详细介绍了如何将 Dify 插件发布到个人 GitHub 仓库,包括准备工作、初始化本地插件仓库、连接远程仓库、上传插件文件、打包插件代码以及通过 GitHub 安装插件的完整流程。此方法允许开发者完全管理自己的插件代码和更新。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo)。 + +### 发布方式 + +为了满足开发者的各种发布需求,Dify 提供了三种插件发布方式: + +#### **1. Marketplace** + +**简介**:Dify 官方插件市场允许用户一键浏览、搜索和安装各种插件。 + +**特点**: + +* 插件通过审核后才能上架,确保**可信赖**且**高质量**。 +* 可以直接安装到个人或团队的 **Workspaces** 中。 + +**发布流程**: + +* 将插件项目提交到 **Dify Marketplace** [代码仓库](https://github.com/langgenius/dify-plugins)。 +* 经过官方审核后,插件将在市场中公开发布,供其他用户安装和使用。 + +详细说明请参考: + + + + +#### 2. **GitHub 仓库** + +**简介**:在 **GitHub** 上开源或托管插件,方便他人查看、下载和安装。 + +**特点**: + +* 便于**版本管理**和**开源分享**。 +* 用户可以通过链接直接安装插件,无需经过平台审核。 + +**发布流程**: + +* 将插件代码推送到 GitHub 仓库。 +* 分享仓库链接,用户可以通过链接将插件集成到他们的 **Dify Workspace** 中。 + +详细说明请参考: + + + + +#### 插件文件(本地安装) + +**简介**:将插件打包为本地文件(如 `.difypkg` 格式)并分享给他人安装。 + +**特点**: + +* 不依赖在线平台,可以**快速灵活**地分享插件。 +* 适用于**私有插件**或**内部测试**。 + +**发布流程**: + +* 将插件项目打包为本地文件。 +* 在 Dify 插件页面点击**上传插件**,选择本地文件即可安装插件。 + +你可以将插件项目打包为本地文件并分享给他人。在插件页面上传文件后,即可将插件安装到 Dify Workspace 中。 + +详细说明请参考: + + + + +### **发布建议** + +* **希望推广插件** → **推荐使用 Marketplace**,通过官方审核确保插件质量并增加曝光度。 +* **开源分享项目** → **推荐使用 GitHub**,便于版本管理和社区协作。 +* **快速分发或内部测试** → **推荐使用插件文件**,安装和分享简单高效。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/marketplace-listing/release-to-individual-github-repo.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx b/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx new file mode 100644 index 00000000..1d0ffcd2 --- /dev/null +++ b/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx @@ -0,0 +1,173 @@ +--- +dimensions: + type: + primary: operational + detail: setup + level: intermediate +standard_title: Contributor Covenant Code of Conduct +language: en +title: 插件开发指南 +description: 为了确保 Dify Marketplace 中所有插件的质量,并为 Dify Marketplace 用户提供一致的高质量体验,您在提交插件进行审核时必须遵守这些插件开发指南中列出的所有要求。提交插件即表示**您确认已阅读、理解并同意遵守以下所有条款**。遵循这些指南将帮助您的插件更快通过审核。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct)。 + +## 1. 插件价值和独特性 + +- **聚焦生成式 AI**:确保您的插件核心功能专注于生成式 AI 领域,并为 Dify 用户提供独特且显著的价值。这可能包括: + - 集成新的模型、工具或服务。 + - 提供独特的数据源或处理能力以增强 AI 应用。 + - 简化或自动化 Dify 平台上的 AI 相关工作流。 + - 为 AI 应用开发提供创新的支持功能。 + +- **避免功能重复**:提交的插件**不得**与 Marketplace 中现有插件重复或高度相似。每个发布的插件必须是独特且独立的,以确保用户获得最佳体验。 + +- **有意义的更新**:对于插件更新,**确保引入新功能或服务**,这些功能或服务在当前版本中尚不可用。 + +- **PR 提交建议**:我们**建议**在您的 pull request 中包含简要说明,解释为什么需要这个新插件。 + +## 2. 插件功能检查清单 + +- **唯一名称**:提前搜索插件目录,确保您的插件名称是唯一的。 + +- **品牌一致性**:插件名称必须与插件的品牌一致。 + +- **功能验证**:在提交前彻底测试插件,确认其按预期工作。详情请参阅[远程调试插件](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin)。插件必须达到生产就绪状态。 + +- **README 要求**: + - 设置说明和使用指南。 + - 连接插件所需的任何必要代码、API、凭证或信息。 + - **不要**包含无关内容或链接。 + - **不要**使用夸大的、促销性的语言或无法验证的声明。 + - **不要**包含任何形式的广告(包括自我推广或展示广告)。 + - **不要**包含误导性、攻击性或诽谤性内容。 + - **不要**在截图中暴露真实用户名或数据。 + - **不要**链接到 404 页面或返回错误的页面。 + - 避免过多的拼写或标点错误。 + +- **用户数据使用**:仅将收集的数据用于连接服务和改进插件功能。 + +- **错误清晰度**:标记必填字段并提供清晰的错误消息,帮助用户理解问题。 + +- **认证设置**:如果需要认证,包含完整的配置步骤——不要省略。 + +- **隐私政策**:根据[隐私保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines)准备隐私政策文档或在线 URL。 + +- **性能**:插件必须高效运行,不得降低 Dify 或用户系统的性能。 + +- **凭证安全**:API 密钥或其他凭证必须安全存储和传输。避免硬编码或将其暴露给未经授权的各方。 + + +## 3. 语言要求 + +- **英语为主要语言**:由于 Dify Marketplace 服务全球用户,所有面向用户的文本(插件名称、描述、字段名称、标签、帮助文本、错误消息)**必须以英语为主要语言**。 + +- **鼓励多语言支持**:鼓励支持多种语言。 + + +## 4. 禁止和限制的插件 + +- **禁止:误导或恶意行为** + 插件不得误导用户。不要创建用于垃圾邮件、网络钓鱼或发送未经请求消息的插件。试图欺骗审核流程、窃取用户数据或冒充用户将导致移除,并可能被禁止未来提交。 + +- **禁止:攻击性内容** + 插件不得包含暴力内容、仇恨言论、歧视或对全球文化、宗教或用户的不尊重。 + +- **禁止:金融交易** + 插件不得促进任何金融交易、资产转移或支付处理。这包括区块链/加密应用中的令牌或资产所有权转移。 + +- **限制:频繁缺陷的插件** + 彻底测试您的插件以避免关键错误。重复提交有缺陷的版本可能导致延迟或处罚。 + +- **限制:不必要的插件拆分** + 不要为共享相同 API 和认证的功能创建多个插件,除非每个都明确是独立的产品或服务。优先将功能集成到一个高级插件中。 + +- **限制:重复提交** + 避免重复提交本质上相同的插件。这样做可能会延迟审核或导致拒绝。 + +## 5. 插件货币化 + +- **Dify Marketplace 目前仅支持**免费**插件。 + +- **未来政策**:货币化和定价模型的政策将在未来公布。 + +## 6. 商标和知识产权 + +- **需要授权**:确保您有权使用任何提交的标志或商标。 + +- **验证权利**:如果使用第三方标志,我们可能会要求您证明您有许可——特别是如果它们明显属于知名品牌。 + +- **违规后果**:如发现未经授权使用,Dify 保留要求更改或移除插件的权利。权利人的投诉也可能导致移除。 + +- **禁止使用 Dify 标志**:您不得使用 Dify 自己的标志。 + +- **图片标准**:不要提交低质量、扭曲或裁剪不当的图片。审核团队可能要求替换。 + +- **图标限制**:图标不得包含误导性、攻击性或恶意的视觉效果。 + + + +## 7. 插件更新和版本管理 + +- **负责任的更新**:在描述中或通过外部渠道(如 GitHub Release Notes)清楚地传达破坏性更改。 + +- **鼓励维护**:定期更新以修复错误、匹配 Dify 平台变化或响应第三方服务的更新——特别是安全方面。 + +- **弃用通知**:如果停止维护插件,请提前通知用户(例如,在插件描述中说明时间表和计划),并在可能的情况下建议替代方案。 + + +## 8. 插件维护和支持 + +- **所有者责任**:插件所有者负责技术支持和维护。 + +- **需要支持渠道**:所有者必须提供**至少一个**支持渠道(GitHub 仓库或电子邮件)用于审核和发布期间的反馈。 + +- **处理未维护的插件**:如果插件缺乏维护且所有者在合理通知后不响应,Dify 可能会: + - 添加"缺乏维护"或"潜在风险"标签。 + - 限制新安装。 + - 最终取消发布该插件。 + + +## 9. 隐私和数据合规 + +- **需要披露**:您**必须声明**您的插件是否收集任何用户个人数据。请参阅[隐私保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines)。 + +- **简单数据列表**:如果收集数据,请简要列出类型(例如,用户名、电子邮件、设备 ID、位置)。无需详尽说明。 + +- **隐私政策**:您**必须提供**隐私政策链接,说明: + - 收集哪些信息。 + - 如何使用这些信息。 + - 与第三方共享哪些内容(如适用,需提供其隐私链接)。 + +- **审核重点**: + - **形式检查**:确保您声明了收集的数据。 + - **敏感数据扫描**:收集敏感数据(如健康、财务、儿童信息)的插件需要额外审查。 + - **恶意行为扫描**:插件不得在未经同意的情况下收集或上传用户数据。 + +--- + +## 10. 审核和自由裁量权 + +- **拒绝/移除权利**:如果不满足要求、隐私标准或相关政策,Dify 可能会拒绝或移除您的插件。这包括滥用审核流程或数据滥用。 + +- **及时审核**:Dify 审核团队将根据数量和复杂性,在合理时间内审核插件。 + +- **沟通**:我们可能会通过您提供的支持渠道联系您——请确保它处于活跃状态。 + +## 相关资源 + +- [插件开发基础概念](/zh/develop-plugin/getting-started/getting-started-dify-plugin) - 学习插件开发基础知识 +- [发布插件](/zh/develop-plugin/publishing/marketplace-listing/release-overview) - 插件发布流程概述 +- [插件隐私数据保护指南](/zh/develop-plugin/publishing/standards/privacy-protection-guidelines) - 隐私政策编写指南 +- [发布到 Dify Marketplace](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - 在官方市场发布插件 +- [远程调试插件](/zh/develop-plugin/features-and-specs/plugin-types/remote-debug-a-plugin) - 插件调试指南 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[Edit this page](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct.mdx) | [Report an issue](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx b/zh/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx new file mode 100644 index 00000000..b8b44bfa --- /dev/null +++ b/zh/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx @@ -0,0 +1,102 @@ +--- +dimensions: + type: + primary: operational + detail: setup + level: intermediate +standard_title: Privacy Protection Guidelines +language: en +title: 插件隐私政策指南 +description: 本文档描述了开发者在向 Dify Marketplace 提交插件时如何编写隐私政策的指南。包括如何识别和列出收集的个人数据类型(直接识别信息、间接识别信息、组合信息)、如何填写插件隐私政策、如何在 Manifest 文件中包含隐私政策声明,以及相关常见问题的解答。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/standards/privacy-protection-guidelines)。 + +当你向 Dify Marketplace 提交插件时,你需要透明地说明如何处理用户数据。以下指南重点介绍如何处理插件的隐私相关问题和用户数据处理。 + +围绕以下几点制定你的隐私政策: + +**你的插件是否收集和使用任何用户个人数据?** 如果是,请列出收集的数据类型。 + +> "个人数据"是指任何可以识别特定个人的信息——无论是单独使用还是与其他数据结合使用——例如用于定位、联系或以其他方式识别特定个人的信息。 + +#### 1. 列出收集的数据类型 + +**类型 A:** **直接标识符** + +* 姓名(例如,全名、名、姓) +* 电子邮件地址 +* 电话号码 +* 家庭住址或其他实际地址 +* 政府颁发的身份证号码(例如,社会安全号码、护照号码、驾驶执照号码) + +**类型 B:** **间接标识符** + +* 设备标识符(例如,IMEI、MAC 地址、设备 ID) +* IP 地址 +* 位置数据(例如,GPS 坐标、城市、地区) +* 在线标识符(例如,cookies、广告 ID) +* 用户名 +* 头像 +* 生物识别数据(例如,指纹、面部识别数据) +* 网页浏览历史 +* 购买历史 +* 健康信息 +* 财务信息 + +**类型 C:可以与其他数据结合以识别个人的数据:** + +* 年龄 +* 性别 +* 职业 +* 兴趣爱好 + +虽然你的插件可能不收集任何个人信息,但你也需要确保插件中使用的第三方服务可能涉及数据收集或处理。作为插件开发者,你有责任披露与插件相关的所有数据收集活动,包括第三方服务执行的活动。因此,请务必仔细阅读第三方服务的隐私政策,并验证插件收集的任何数据都在提交中声明。 + +例如,如果你正在开发的插件涉及 Slack 服务,请确保在插件的隐私政策声明中引用 [Slack 的隐私政策](https://slack.com/trust/privacy/privacy-policy),并清楚地披露数据收集做法。 + +#### **2. 提交插件的最新隐私政策** + +**隐私政策**应包含: + +* 收集哪些类型的数据。 +* 收集的数据如何使用。 +* 是否与第三方共享任何数据,如果是,请识别这些第三方并提供其隐私政策的链接。 +* 如果你不知道如何编写隐私政策,也可以查看 Dify 团队发布的插件隐私政策。 + +#### 3. 在插件 Manifest 文件中引入隐私政策声明 + +有关填写特定字段的详细说明,请参阅[通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications)文档。 + +**常见问题** + +1. **关于用户个人数据,"收集和使用"是什么意思?在任何插件中,个人数据是如何被收集和使用的常见示例有哪些?** + +"收集和使用"用户数据通常是指收集、传输、使用或共享用户数据。产品如何处理个人或敏感用户数据的常见示例包括: + +* 使用收集任何类型个人身份信息的表单。 +* 实现登录功能,即使使用第三方身份验证服务。 +* 收集可能包含个人身份信息的输入或资源信息。 +* 实现分析以跟踪用户行为、交互和使用模式。 +* 存储通信数据,如消息、聊天记录或电子邮件地址。 +* 访问来自已连接社交媒体账户的用户资料或数据。 +* 收集健康和健身数据,如活动水平、心率或医疗信息。 +* 存储搜索查询或跟踪浏览行为。 +* 处理财务信息,包括银行详情、信用评分或交易历史。 + +## 相关资源 + +- [发布概述](/zh/develop-plugin/publishing/marketplace-listing/release-overview) - 了解插件发布流程 +- [发布到 Dify Marketplace](/zh/develop-plugin/publishing/marketplace-listing/release-to-dify-marketplace) - 了解如何向官方市场提交插件 +- [插件开发者指南](/zh/develop-plugin/publishing/standards/contributor-covenant-code-of-conduct) - 了解插件提交指南 +- [通用规范](/zh/develop-plugin/features-and-specs/plugin-types/general-specifications) - 插件元数据配置 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/privacy-protection-guidelines.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/develop-plugin/publishing/standards/third-party-signature-verification.mdx b/zh/develop-plugin/publishing/standards/third-party-signature-verification.mdx new file mode 100644 index 00000000..07980637 --- /dev/null +++ b/zh/develop-plugin/publishing/standards/third-party-signature-verification.mdx @@ -0,0 +1,120 @@ +--- +dimensions: + type: + primary: operational + detail: setup + level: intermediate +standard_title: Third-Party Signature Verification +language: zh-Hans +title: 为第三方签名验证签署插件 +description: 本文档介绍如何在 Dify 社区版中启用和使用第三方签名验证功能,包括密钥对生成、插件签名和验证,以及环境配置步骤,使管理员能够安全地安装 Dify Marketplace 上没有的插件。 +--- + + ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/publishing/standards/third-party-signature-verification)。 + +--- +title: +--- + +此功能仅在 Dify 社区版中可用。Dify 云版本目前不支持第三方签名验证。 + +第三方签名验证允许 Dify 管理员在不完全禁用签名验证的情况下,安全地批准安装未在 Dify Marketplace 上列出的插件。例如,这支持以下场景: + +* Dify 管理员可以在审核通过开发者发送的插件后为其添加签名。 +* 插件开发者可以为其插件添加签名,并将其与公钥一起发布,供无法禁用签名验证的 Dify 管理员使用。 + +Dify 管理员和插件开发者都可以使用预先生成的密钥对为插件添加签名。此外,管理员可以配置 Dify 在插件安装期间使用特定公钥强制执行签名验证。 + +## 生成用于签名和验证的密钥对 + +使用以下命令生成用于添加和验证插件签名的新密钥对: + +```bash +dify signature generate -f your_key_pair +``` + +运行此命令后,将在当前目录中生成两个文件: + +* **私钥**:`your_key_pair.private.pem` +* **公钥**:`your_key_pair.public.pem` + +私钥用于签署插件,公钥用于验证插件的签名。 + +请妥善保管私钥。如果私钥泄露,攻击者可以为任何插件添加有效签名,这将危及 Dify 的安全性。 + +## 为插件添加签名并验证 + +运行以下命令为您的插件添加签名。请注意,您必须指定**要签名的插件文件**和**私钥**: + +```bash +dify signature sign your_plugin_project.difypkg -p your_key_pair.private.pem +``` + +执行命令后,将在同一目录中生成一个新的插件文件,其原始文件名中添加了 `signed`:`your_plugin_project.signed.difypkg` + +您可以使用此命令验证插件是否已正确签名。在这里,您需要指定**已签名的插件文件**和**公钥**: + +```bash +dify signature verify your_plugin_project.signed.difypkg -p your_key_pair.public.pem +``` + +如果省略公钥参数,验证将使用 Dify Marketplace 公钥。在这种情况下,对于任何未从 Dify Marketplace 下载的插件文件,签名验证都将失败。 + +## 启用第三方签名验证 + +Dify 管理员可以在安装插件之前使用预先批准的公钥强制执行签名验证。 + +### 放置公钥 + +将与签名所用私钥对应的**公钥**放置在插件守护程序可以访问的位置。 + +例如,在 `docker/volumes/plugin_daemon` 下创建一个 `public_keys` 目录,并将公钥文件复制到该目录: + +```bash +mkdir docker/volumes/plugin_daemon/public_keys +cp your_key_pair.public.pem docker/volumes/plugin_daemon/public_keys +``` + +### 环境变量配置 + +在 `plugin_daemon` 容器中,配置以下环境变量: + +* `THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED` + * 启用第三方签名验证。 + * 将此设置为 `true` 以启用该功能。 +* `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` + * 指定用于签名验证的公钥文件的路径。 + * 您可以列出多个公钥文件,用逗号分隔。 + +以下是配置这些变量的 Docker Compose 覆盖文件(`docker-compose.override.yaml`)示例: + +```yaml +services: + plugin_daemon: + environment: + FORCE_VERIFYING_SIGNATURE: true + THIRD_PARTY_SIGNATURE_VERIFICATION_ENABLED: true + THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS: /app/storage/public_keys/your_key_pair.public.pem +``` + +请注意,`docker/volumes/plugin_daemon` 被挂载到 `plugin_daemon` 容器中的 `/app/storage`。请确保 `THIRD_PARTY_SIGNATURE_VERIFICATION_PUBLIC_KEYS` 中指定的路径对应于容器内的路径。 + +要应用这些更改,请重启 Dify 服务: + +```bash +cd docker +docker compose down +docker compose up -d +``` + +重启服务后,第三方签名验证功能将在当前社区版环境中启用。 + +{/* +Contributing Section +DO NOT edit this section! +It will be automatically generated by the script. +*/} + +--- + +[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/publishing/standards/third-party-signature-verification.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml) \ No newline at end of file diff --git a/zh/use-dify/nodes/trigger/plugin-trigger.mdx b/zh/use-dify/nodes/trigger/plugin-trigger.mdx index 85309d1a..ae44f984 100644 --- a/zh/use-dify/nodes/trigger/plugin-trigger.mdx +++ b/zh/use-dify/nodes/trigger/plugin-trigger.mdx @@ -17,7 +17,7 @@ title: 插件触发器 1. 在 Workflow 画布上,单击右键并选择 **添加节点** > **开始**,然后选择可用的插件触发器,或在 [Dify 插件市场](https://marketplace.dify.ai/?language=zh-Hans&category=trigger) 中搜索更多插件。 - - 若未找到合适的触发器插件,你可以 [向社区请求](https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml)、[自行开发](/plugin-dev-zh/0222-trigger-plugin),或者改用 [Webhook 触发器](/zh/use-dify/nodes/trigger/webhook-trigger)。 + - 若未找到合适的触发器插件,你可以 [向社区请求](https://github.com/langgenius/dify-plugins/issues/new?template=plugin_request.yaml)、[自行开发](/zh/develop-plugin/dev-guides-and-walkthroughs/trigger-plugin),或者改用 [Webhook 触发器](/zh/use-dify/nodes/trigger/webhook-trigger)。 - 一个 Workflow 可同时拥有多个并行的插件触发器。当并行的分支连续包含相同节点时,可在相同部分之前添加 [变量聚合节点](/zh/use-dify/nodes/variable-aggregator) 以合并分支,而无需在每个分支中分别重复添加相同的节点。