我手动创建的一个自定义工具,创建完成后这些信息存到了哪里?另外能否通过API方式创建自定义工具呢? #3961

Closed
opened 2026-02-21 18:04:09 -05:00 by yindo · 2 comments
Owner

Originally created by @wangyao123456a on GitHub (Jun 3, 2024).

Self Checks

  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • Please do not modify this template :) and fill in all the required fields.

Dify version

0.3.21

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

1

✔️ Expected Behavior

1

Actual Behavior

1

Originally created by @wangyao123456a on GitHub (Jun 3, 2024). ### Self Checks - [X] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [X] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [X] I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)). - [X] Please do not modify this template :) and fill in all the required fields. ### Dify version 0.3.21 ### Cloud or Self Hosted Self Hosted (Docker) ### Steps to reproduce 1 ### ✔️ Expected Behavior 1 ### ❌ Actual Behavior 1
yindo added the 🙋‍♂️ question label 2026-02-21 18:04:09 -05:00
yindo closed this issue 2026-02-21 18:04:09 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Jun 3, 2024):

Hello @wangyao123456a! I'm here to help you with any issues or questions you have about Dify. I'm a bot designed to assist with bug reports, answer questions, and guide you on how to become a contributor. Let me know how I can assist you today!

手动创建的自定义工具的信息存储在相应的管理服务中,例如 ApiToolManageServiceBuiltinToolManageServiceWorkflowToolManageService。具体来说,对于基于API的工具,其模式信息(包括URL、方法、参数和其他元数据)存储在 ApiToolBundle 类中。数据库中的 ApiToolProvider 表存储了API提供者的详细信息,如名称、图标、模式、用户ID、租户ID、描述、工具、凭证、隐私政策和自定义免责声明。

是的,可以通过API方式创建自定义工具。例如,ToolApiProviderAddApi 类提供了一个端点来创建API工具提供者:

class ToolApiProviderAddApi(Resource):
    @setup_required
    @login_required
    @account_initialization_required
    def post(self):
        if not current_user.is_admin_or_owner:
            raise Forbidden()
        
        user_id = current_user.id
        tenant_id = current_user.current_tenant_id

        parser = reqparse.RequestParser()
        parser.add_argument('credentials', type=dict, required=True, nullable=False, location='json')
        parser.add_argument('schema_type', type=str, required=True, nullable=False, location='json')
        parser.add_argument('schema', type=str, required=True, nullable=False, location='json')
        parser.add_argument('provider', type=str, required=True, nullable=False, location='json')
        parser.add_argument('icon', type=dict, required=True, nullable=False, location='json')
        parser.add_argument('privacy_policy', type=str, required=False, nullable=True, location='json')
        parser.add_argument('labels', type=list[str], required=False, nullable=True, location='json', default=[])
        parser.add_argument('custom_disclaimer', type=str, required=False, nullable=True, location='json')

        args = parser.parse_args()

        return ApiToolManageService.create_api_tool_provider(
            user_id,
            tenant_id,
            args['provider'],
            args['icon'],
            args['credentials'],
            args['schema_type'],
            args['schema'],
            args.get('privacy_policy', ''),
            args.get('custom_disclaimer', ''),
            args.get('labels', []),
        )

ApiToolBundle 类用于存储API工具的模式信息,例如URL、方法、参数等:

from typing import Optional
from pydantic import BaseModel
from core.tools.entities.tool_entities import ToolParameter

class ApiToolBundle(BaseModel):
    """
    This class is used to store the schema information of an api based tool. such as the url, the method, the parameters, etc.
    """
    server_url: str
    method: str
    summary: Optional[str] = None
    operation_id: str = None
    parameters: Optional[list[ToolParameter]] = None
    author: str
    icon: Optional[str] = None
    openapi: dict

数据库中的 ApiToolProvider 表存储了API提供者的详细信息:

class ApiToolProvider(db.Model):
    """
    The table stores the api providers.
    """
    __tablename__ = 'tool_api_providers'
    __table_args__ = (
        db.PrimaryKeyConstraint('id', name='tool_api_provider_pkey'),
        db.UniqueConstraint('name', 'tenant_id', name='unique_api_tool_provider')
    )

    id = db.Column(StringUUID, server_default=db.text('uuid_generate_v4()'))
    name = db.Column(db.String(40), nullable=False)
    icon = db.Column(db.String(255), nullable=False)
    schema = db.Column(db.Text, nullable=False)
    schema_type_str = db.Column(db.String(40), nullable=False)
    user_id = db.Column(StringUUID, nullable=False)
    tenant_id = db.Column(StringUUID, nullable=False)
    description = db.Column(db.Text, nullable=False)
    tools_str = db.Column(db.Text, nullable=False)
    credentials_str = db.Column(db.Text, nullable=False)
    privacy_policy = db.Column(db.String(255), nullable=True)
    custom_disclaimer = db.Column(db.String(255), nullable=True)
    created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
    updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))

    @property
    def schema_type(self) -> ApiProviderSchemaType:
        return ApiProviderSchemaType.value_of(self.schema_type_str)
    
    @property
    def tools(self) -> list[ApiToolBundle]:
        return [ApiToolBundle(**tool) for tool in json.loads(self.tools_str)]
    
    @property
    def credentials(self) -> dict:
        return json.loads(self.credentials_str)
    
    @property
    def user(self) -> Account:
        return db.session.query(Account).filter(Account.id == self.user_id).first()
    
    @property
    def tenant(self) -> Tenant:
        return db.session.query(Tenant).filter(Tenant.id == self.tenant_id).first()

[1][2][3]

To continue talking to Dosu, mention @dosu.

@dosubot[bot] commented on GitHub (Jun 3, 2024): <!-- Greeting --> Hello @wangyao123456a! I'm here to help you with any issues or questions you have about Dify. I'm a bot designed to assist with bug reports, answer questions, and guide you on how to become a contributor. Let me know how I can assist you today! <!-- Answer --> 手动创建的自定义工具的信息存储在相应的管理服务中,例如 `ApiToolManageService`、`BuiltinToolManageService` 和 `WorkflowToolManageService`。具体来说,对于基于API的工具,其模式信息(包括URL、方法、参数和其他元数据)存储在 `ApiToolBundle` 类中。数据库中的 `ApiToolProvider` 表存储了API提供者的详细信息,如名称、图标、模式、用户ID、租户ID、描述、工具、凭证、隐私政策和自定义免责声明。 是的,可以通过API方式创建自定义工具。例如,`ToolApiProviderAddApi` 类提供了一个端点来创建API工具提供者: ```python class ToolApiProviderAddApi(Resource): @setup_required @login_required @account_initialization_required def post(self): if not current_user.is_admin_or_owner: raise Forbidden() user_id = current_user.id tenant_id = current_user.current_tenant_id parser = reqparse.RequestParser() parser.add_argument('credentials', type=dict, required=True, nullable=False, location='json') parser.add_argument('schema_type', type=str, required=True, nullable=False, location='json') parser.add_argument('schema', type=str, required=True, nullable=False, location='json') parser.add_argument('provider', type=str, required=True, nullable=False, location='json') parser.add_argument('icon', type=dict, required=True, nullable=False, location='json') parser.add_argument('privacy_policy', type=str, required=False, nullable=True, location='json') parser.add_argument('labels', type=list[str], required=False, nullable=True, location='json', default=[]) parser.add_argument('custom_disclaimer', type=str, required=False, nullable=True, location='json') args = parser.parse_args() return ApiToolManageService.create_api_tool_provider( user_id, tenant_id, args['provider'], args['icon'], args['credentials'], args['schema_type'], args['schema'], args.get('privacy_policy', ''), args.get('custom_disclaimer', ''), args.get('labels', []), ) ``` `ApiToolBundle` 类用于存储API工具的模式信息,例如URL、方法、参数等: ```python from typing import Optional from pydantic import BaseModel from core.tools.entities.tool_entities import ToolParameter class ApiToolBundle(BaseModel): """ This class is used to store the schema information of an api based tool. such as the url, the method, the parameters, etc. """ server_url: str method: str summary: Optional[str] = None operation_id: str = None parameters: Optional[list[ToolParameter]] = None author: str icon: Optional[str] = None openapi: dict ``` 数据库中的 `ApiToolProvider` 表存储了API提供者的详细信息: ```python class ApiToolProvider(db.Model): """ The table stores the api providers. """ __tablename__ = 'tool_api_providers' __table_args__ = ( db.PrimaryKeyConstraint('id', name='tool_api_provider_pkey'), db.UniqueConstraint('name', 'tenant_id', name='unique_api_tool_provider') ) id = db.Column(StringUUID, server_default=db.text('uuid_generate_v4()')) name = db.Column(db.String(40), nullable=False) icon = db.Column(db.String(255), nullable=False) schema = db.Column(db.Text, nullable=False) schema_type_str = db.Column(db.String(40), nullable=False) user_id = db.Column(StringUUID, nullable=False) tenant_id = db.Column(StringUUID, nullable=False) description = db.Column(db.Text, nullable=False) tools_str = db.Column(db.Text, nullable=False) credentials_str = db.Column(db.Text, nullable=False) privacy_policy = db.Column(db.String(255), nullable=True) custom_disclaimer = db.Column(db.String(255), nullable=True) created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) @property def schema_type(self) -> ApiProviderSchemaType: return ApiProviderSchemaType.value_of(self.schema_type_str) @property def tools(self) -> list[ApiToolBundle]: return [ApiToolBundle(**tool) for tool in json.loads(self.tools_str)] @property def credentials(self) -> dict: return json.loads(self.credentials_str) @property def user(self) -> Account: return db.session.query(Account).filter(Account.id == self.user_id).first() @property def tenant(self) -> Tenant: return db.session.query(Tenant).filter(Tenant.id == self.tenant_id).first() ``` <sup>[[1]](https://github.com/langgenius/dify/blob/main/api/controllers/console/workspace/tool_providers.py)</sup><sup>[[2]](https://github.com/langgenius/dify/blob/main/api/core/tools/entities/tool_bundle.py)</sup><sup>[[3]](https://github.com/langgenius/dify/blob/main/api/models/tools.py)</sup> <!-- Dosu Comment Footer --> *To continue talking to [Dosu](https://dosu.dev), mention @dosu.*
Author
Owner

@crazywoola commented on GitHub (Jun 3, 2024):

Close due to #1542

@crazywoola commented on GitHub (Jun 3, 2024): Close due to #1542
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#3961