Dify中的工具

news2024/9/23 1:20:51

Dify中的工具分为内置工具(硬编码)和第三方工具(OpenAPI Swagger/ChatGPT Plugin)。工具可被Workflow(工作流)和Agent使用,当然Workflow也可被发布为工具,这样Workflow(工作流)中又可以使用Workflow(工具)。

一.Dify内置工具

下面以Google为例介绍。从前端看只要输入SerpApi API key即可,接下来重点分析后端实现。

源码位置:dify-0.6.9/api/core/tools/provider/builtin/google

1.准备工具供应商 yaml

源码位置:dify-0.6.9/api/core/tools/provider/builtin/google/google.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  # 图标文件名,图标文件需要放在当前模块的_assets目录下

2.准备供应商凭据

源码位置:dify-0.6.9/api/core/tools/provider/builtin/google/google.yaml

Google使用了SerpApi提供的API,而SerpApi需要一个API Key才能使用,即该工具需要一个凭证才能使用,也是前端需要输入SerpApi API key的原因。

credentials_for_provider:  # 凭据字段
  serpapi_api_key:  # 凭据字段的唯一标识
    type: secret-input  # 凭据字段的类型
    required: true  # 是否必填
    label:  # 标签用于前端展示
      en_US: SerpApi API key  # 英文标签
      zh_Hans: SerpApi API key  # 简体中文标签
      pt_BR: SerpApi API key  # 葡萄牙语标签
    placeholder:  # 提示用于前端展示
      en_US: Please input your SerpApi API key  # 英文提示
      zh_Hans: 请输入你的 SerpApi API key  # 简体中文提示
      pt_BR: Please input your SerpApi API key  # 葡萄牙语提示
    help:  # 凭据字段帮助文本
      en_US: Get your SerpApi API key from SerpApi  # 英文帮助文本
      zh_Hans: 从 SerpApi 获取您的 SerpApi API key  # 简体中文帮助文本
      pt_BR: Get your SerpApi API key from SerpApi  # 葡萄牙语帮助文本
    url: https://serpapi.com/manage-api-key  # 凭据字段帮助链接

type:凭据字段类型,目前支持secret-input、text-input、select 三种类型,分别对应密码输入框、文本输入框、下拉框,如果为secret-input,则会在前端隐藏输入内容,并且后端会对输入内容进行加密。

3.准备工具 yaml

源码位置:dify-0.6.9\api\core\tools\provider\builtin\google\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 的介绍,为了使得LLM更好理解这个工具,我们建议在这里写上关于这个工具尽可能详细的信息,让 LLM 能够理解并使用这个工具
  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的介绍,同上,为了使得LLM更好理解这个参数,我们建议在这里写上关于这个参数尽可能详细的信息,让LLM能够理解这个参数
    llm_description: key words for searching
    form: llm  # 参数的表单类型,llm表示这个参数需要由Agent自行推理出来,前端将不会展示这个参数
  - name: result_type  # 参数名称
    type: select  # 参数类型
    required: true  # 是否必填
    options:  # 参数的选项
      - value: text
        label:
          en_US: text
          zh_Hans: 文本
          pt_BR: texto
      - value: link
        label:
          en_US: link
          zh_Hans: 链接
          pt_BR: link
    default: link  # 默认值为链接
    label:
      en_US: Result type
      zh_Hans: 结果类型
      pt_BR: Result type
    human_description:
      en_US: used for selecting the result type, text or link
      zh_Hans: 用于选择结果类型,使用文本还是链接进行展示
      pt_BR: used for selecting the result type, text or link
    form: form  # 参数的表单类型,form表示这个参数需要由用户在对话开始前在前端填写
  • identity 字段是必须的,它包含了工具的基本信息,包括名称、作者、标签、描述等

  • parameters 参数列表

    • name 参数名称,唯一,不允许和其他参数重名

    • type 参数类型,目前支持stringnumberbooleanselect 四种类型,分别对应字符串、数字、布尔值、下拉框

    • required 是否必填

      • llm模式下,如果参数为必填,则会要求 Agent 必须要推理出这个参数

      • form模式下,如果参数为必填,则会要求用户在对话开始前在前端填写这个参数

    • options 参数选项

      • llm模式下,Dify 会将所有选项传递给 LLM,LLM 可以根据这些选项进行推理

      • form模式下,typeselect时,前端会展示这些选项

    • default 默认值

    • label 参数标签,用于前端展示

    • human_description 用于前端展示的介绍,支持多语言

    • llm_description 传递给 LLM 的介绍,为了使得 LLM 更好理解这个参数,我们建议在这里写上关于这个参数尽可能详细的信息,让 LLM 能够理解这个参数

    • form 表单类型,目前支持llmform两种类型,分别对应 Agent 自行推理和前端填写

4.准备工具代码

源码位置:dify-0.6.9\api\core\tools\provider\builtin\google\tools\google_search.py

class GoogleSearchTool(BuiltinTool):
    def _invoke(self, 
                user_id: str,  # 表示用户ID
               tool_parameters: dict[str, Any],  # 表示工具参数
        ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:  # 表示工具调用消息
        """
            invoke tools
        """
        query = tool_parameters['query']  # 表示查询
        result_type = tool_parameters['result_type']  # 表示结果类型
        api_key = self.runtime.credentials['serpapi_api_key']  # 表示API密钥
        result = SerpAPI(api_key).run(query, result_type=result_type)  # 表示运行查询
        if result_type == 'text':  # 表示结果类型为文本
            return self.create_text_message(text=result)  # 返回文本消息
        return self.create_link_message(link=result)  # 返回链接消息

5.准备供应商代码

源码位置:dify-0.6.9\api\core\tools\provider\builtin\google\google.py

class GoogleSearchTool(BuiltinTool):
    def _invoke(self, 
                user_id: str,  # 表示用户ID
               tool_parameters: dict[str, Any],  # 表示工具参数
        ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:  # 表示工具调用消息
        """
            invoke tools
        """
        query = tool_parameters['query']  # 表示查询
        result_type = tool_parameters['result_type']  # 表示结果类型
        api_key = self.runtime.credentials['serpapi_api_key']  # 表示API密钥
        result = SerpAPI(api_key).run(query, result_type=result_type)  # 表示运行查询
        if result_type == 'text':  # 表示结果类型为文本
            return self.create_text_message(text=result)  # 返回文本消息
        return self.create_link_message(link=result)  # 返回链接消息

二.工具接口中的消息返回

1.返回消息类型

源码位置:dify-0.6.9\api\core\tools\tool\tool.py

Dify支持文本 链接 图片 文件BLOB 等多种消息类型,可通过以下几个接口返回不同类型的消息给 LLM 和用户。

def create_image_message(self, image: str, save_as: str = '') -> ToolInvokeMessage:
    """
        create an image message

        :param image: the url of the image
        :return: the image message
    """
    return ToolInvokeMessage(type=ToolInvokeMessage.MessageType.IMAGE, 
                             message=image, 
                             save_as=save_as)

def create_file_var_message(self, file_var: FileVar) -> ToolInvokeMessage:
    return ToolInvokeMessage(type=ToolInvokeMessage.MessageType.FILE_VAR,
                             message='',
                             meta={
                                 'file_var': file_var
                             },
                             save_as='')

def create_link_message(self, link: str, save_as: str = '') -> ToolInvokeMessage:
    """
        create a link message

        :param link: the url of the link
        :return: the link message
    """
    return ToolInvokeMessage(type=ToolInvokeMessage.MessageType.LINK, 
                             message=link, 
                             save_as=save_as)

def create_text_message(self, text: str, save_as: str = '') -> ToolInvokeMessage:
    """
        create a text message

        :param text: the text
        :return: the text message
    """
    return ToolInvokeMessage(type=ToolInvokeMessage.MessageType.TEXT, 
                             message=text,
                             save_as=save_as
                             )

def create_blob_message(self, blob: bytes, meta: dict = None, save_as: str = '') -> ToolInvokeMessage:
    """
        create a blob message

        :param blob: the blob
        :return: the blob message
    """
    return ToolInvokeMessage(type=ToolInvokeMessage.MessageType.BLOB, 
                             message=blob, meta=meta,
                             save_as=save_as
                             )

如果要返回文件的原始数据,如图片、音频、视频、PPT、Word、Excel 等,可以使用文件 BLOB。

  • blob 文件的原始数据,bytes 类型。

  • meta 文件的元数据,如果知道该文件的类型,最好传递一个mime_type,否则Dify将使用octet/stream作为默认类型。比如:

# b64decode函数的作用是将一个Base64编码的字符串解码为原始的字节数据
self.create_blob_message(blob=b64decode(image.b64_json), meta={ 'mime_type': 'image/png' }, save_as=self.VARIABLE_KEY.IMAGE.value)

self.create_blob_message(blob=response.content, meta={'mime_type': 'image/svg+xml'})

application/octet-stream 是一种通用的二进制数据的 MIME 类型。“Octet” 是一个八位字节,“stream” 指的是数据流。这种类型通常用于表示未知的、二进制的数据。当下载或上传文件时,如果服务器或客户端不能确定文件的具体类型,就可能会使用 application/octet-stream。例如,当下载一个 .exe 文件或者 .zip 文件时,HTTP 响应的 Content-Type 头部字段可能就会被设置为 application/octet-stream

2.总结和爬虫

还有2个常用的文本总结工具和网络爬虫工具如下:

源码位置:dify-0.6.9\api\core\tools\tool\builtin_tool.py

def summary(self, user_id: str, content: str) -> str:
    max_tokens = self.get_max_tokens()

    if self.get_prompt_tokens(prompt_messages=[
        UserPromptMessage(content=content)
    ]) < max_tokens * 0.6:
        return content
    
    def get_prompt_tokens(content: str) -> int:
        return self.get_prompt_tokens(prompt_messages=[
            SystemPromptMessage(content=_SUMMARY_PROMPT),
            UserPromptMessage(content=content)
        ])
    
    def summarize(content: str) -> str:
        summary = self.invoke_model(user_id=user_id, prompt_messages=[
            SystemPromptMessage(content=_SUMMARY_PROMPT),
            UserPromptMessage(content=content)
        ], stop=[])

        return summary.message.content

    lines = content.split('\n')
    new_lines = []
    # split long line into multiple lines
    for i in range(len(lines)):
        line = lines[i]
        if not line.strip():
            continue
        if len(line) < max_tokens * 0.5:
            new_lines.append(line)
        elif get_prompt_tokens(line) > max_tokens * 0.7:
            while get_prompt_tokens(line) > max_tokens * 0.7:
                new_lines.append(line[:int(max_tokens * 0.5)])
                line = line[int(max_tokens * 0.5):]
            new_lines.append(line)
        else:
            new_lines.append(line)

    # merge lines into messages with max tokens
    messages: list[str] = []
    for i in new_lines:
        if len(messages) == 0:
            messages.append(i)
        else:
            if len(messages[-1]) + len(i) < max_tokens * 0.5:
                messages[-1] += i
            if get_prompt_tokens(messages[-1] + i) > max_tokens * 0.7:
                messages.append(i)
            else:
                messages[-1] += i

    summaries = []
    for i in range(len(messages)):
        message = messages[i]
        summary = summarize(message)
        summaries.append(summary)

    result = '\n'.join(summaries)

    if self.get_prompt_tokens(prompt_messages=[
        UserPromptMessage(content=result)
    ]) > max_tokens * 0.7:
        return self.summary(user_id=user_id, content=result)
    
    return result

def get_url(self, url: str, user_agent: str = None) -> str:
    """
        get url
    """
    return get_url(url, user_agent=user_agent)

3.变量池

简单理解变量池用于存储工具运行过程中产生的变量、文件等,这些变量可以在工具运行过程中被其它工具使用。以DallE3Vectorizer.AI为例,介绍如何使用变量池。

  • DallE3是一个图片生成工具,它可以根据文本生成图片,将让DallE3生成一个咖啡厅的 Logo。

  • Vectorizer.AI是一个矢量图转换工具,它可以将图片转换为矢量图,将DallE3生成的PNG图标转换为矢量图,从而可真正被设计师使用。

# DallE 消息返回
self.create_blob_message(blob=b64decode(image.b64_json), meta={ 'mime_type': 'image/png' }, save_as=self.VARIABLE_KEY.IMAGE.value)

# 从变量池中获取到之前 DallE 生成的图片
image_binary = self.get_variable_file(self.VARIABLE_KEY.IMAGE)

三.Dify第三方工具

创建自定义工具,目前支持 OpenAPI Swagger 和 ChatGPT Plugin 规范。可将 OpenAPI schema 内容直接粘贴或从 URL 内导入。工具目前支持两种鉴权方式:无鉴权 和 API Key。

1.天气(JSON)

{
      "openapi": "3.1.0",
      "info": {
        "title": "Get weather data",
        "description": "Retrieves current weather data for a location.",
        "version": "v1.0.0"
      },
      "servers": [
        {
          "url": "https://weather.example.com"
        }
      ],
      "paths": {
        "/location": {
          "get": {
            "description": "Get temperature for a specific location",
            "operationId": "GetCurrentWeather",
            "parameters": [
              {
                "name": "location",
                "in": "query",
                "description": "The city and state to retrieve the weather for",
                "required": true,
                "schema": {
                  "type": "string"
                }
              }
            ],
            "deprecated": false
          }
        }
      },
      "components": {
        "schemas": {}
      }
}

2.宠物商店(YAML)

# Taken from https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore.yaml

    openapi: "3.0.0"
    info:
      version: 1.0.0
      title: Swagger Petstore
      license:
        name: MIT
    servers:
      - url: https://petstore.swagger.io/v1
    paths:
      /pets:
        get:
          summary: List all pets
          operationId: listPets
          tags:
            - pets
          parameters:
            - name: limit
              in: query
              description: How many items to return at one time (max 100)
              required: false
              schema:
                type: integer
                maximum: 100
                format: int32
          responses:
            '200':
              description: A paged array of pets
              headers:
                x-next:
                  description: A link to the next page of responses
                  schema:
                    type: string
              content:
                application/json:    
                  schema:
                    $ref: "#/components/schemas/Pets"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
        post:
          summary: Create a pet
          operationId: createPets
          tags:
            - pets
          responses:
            '201':
              description: Null response
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
      /pets/{petId}:
        get:
          summary: Info for a specific pet
          operationId: showPetById
          tags:
            - pets
          parameters:
            - name: petId
              in: path
              required: true
              description: The id of the pet to retrieve
              schema:
                type: string
          responses:
            '200':
              description: Expected response to a valid request
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Pet"
            default:
              description: unexpected error
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Error"
    components:
      schemas:
        Pet:
          type: object
          required:
            - id
            - name
          properties:
            id:
              type: integer
              format: int64
            name:
              type: string
            tag:
              type: string
        Pets:
          type: array
          maxItems: 100
          items:
            $ref: "#/components/schemas/Pet"
        Error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: integer
              format: int32
            message:
              type: string

3.空模板(JSON)

{
      "openapi": "3.1.0",
      "info": {
        "title": "Untitled",
        "description": "Your OpenAPI specification",
        "version": "v1.0.0"
      },
      "servers": [
        {
          "url": ""
        }
      ],
      "paths": {},
      "components": {
        "schemas": {}
      }
}

四.Cloudflare Workers

一个函数调用工具可以部署到Cloudflare Workers,并使用OpenAPI模式。其中,Cloudflare Workers是Cloudflare提供的一种在边缘网络运行JavaScript函数的服务。简单理解这是一个用于为dify应用创建工具的Cloudflare Worker。

# 克隆代码
git clone https://github.com/crazywoola/dify-tools-worker

# 开发模式
cp .wrangler.toml.example .wrangler.toml
npm install
npm run dev
# You will get a url like this: http://localhost:8787

# 部署模式
npm run deploy 
# You will get a url like this: https://difytoolsworker.yourname.workers.dev

填写URL从URL中导入,如下所示:

参考文献

[1] Tools:https://github.com/langgenius/dify/blob/main/api/core/tools/README_CN.md

[2] 快速接入Tool:https://github.com/langgenius/dify/blob/main/api/core/tools/docs/zh_Hans/tool_scale_out.md

[3] 高级接入Tool:https://github.com/langgenius/dify/blob/main/api/core/tools/docs/zh_Hans/advanced_scale_out.md

[4] OpenAPI Specification:https://swagger.io/specification/

[5] https://github.com/crazywoola/dify-tools-worker

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1915748.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macOS系统下载navicat安装包

链接: https://pan.baidu.com/s/1SqTIXNL-B8ZMJxIBu1DfIw?pwdc1z8 提取码: c1z8 安装后效果

【Android组件】封装加载弹框

&#x1f4d6;封装加载弹框 ✅1. 构造LoadingDialog✅2. 调用LoadingDialog 效果&#xff1a; ✅1. 构造LoadingDialog 构造LoadingDialog类涉及到设计模式中的建造者模式&#xff0c;进行链式调用&#xff0c;注重的是构建的过程&#xff0c;设置需要的属性。 步骤一&#x…

流模型flow

流模型 Flow 超详解&#xff0c;基于 Flow 的生成式模型&#xff0c;从思路到基础到公式推导到模型理解与应用&#xff08;Flow-based Generative Model&#xff09;_generative flows-CSDN博客

做一个专业的声音分析系统,需要对声音那些评判标准进行计算

为了构建一个专业的声音分析系统&#xff0c;需要对以下评判标准进行计算。每个标准需要相应的算法和技术指标来实现。下面是一些关键的评判标准和如何计算这些标准的具体方法&#xff1a; 1. 音质 清晰度 信噪比&#xff08;SNR&#xff09;&#xff1a;计算音频信号中的信…

Linux udp编程

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

Milvus 核心概念(1) ---- 数据一致性的等级及使用场景

目录 背景 Milvus的数据一致性 设置数据一致性等级 等级类型 PACELC定理 level 详细解释 Strong Bounded staleness Session Eventually 总结 背景 分布式上的可扩展性是个比较重要的concept。Chroma 核心之前写过了,他的最大优势在于轻量级且好用。Milvus相对Ch…

C++ //练习 14.44 编写一个简单的桌面计算器使其能处理二元运算。

C Primer&#xff08;第5版&#xff09; 练习 14.44 练习 14.44 编写一个简单的桌面计算器使其能处理二元运算。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /**********************************************************…

轻松理解c++17的string_view

文章目录 轻松理解c17的string_view设计初衷常见用法构造 std::string_view常用操作作为函数参数 注意事项总结 轻松理解c17的string_view std::string_view 是 C17 引入的一个轻量级、不拥有&#xff08;non-owning&#xff09;的字符串视图类。它的设计初衷是提供一种高效、…

今天小编强烈推荐几款国产APP!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 今天小编强烈推荐几款国产APP,算得上是国产之光。如果能帮助到大家&#xff0c;别忘了给小编点点赞加关注哟&#xff01;更多精彩还在后面。 一、…

第二证券:转股溢价率是什么意思?高好还是低好?

转股溢价率是指可转债在商场上的交易价格相对于其转股价值的溢价份额&#xff0c;能够用来衡量投资者为取得将债券转换为股票权力而付出的额定金额&#xff0c;是可转债的重要指标。 转股溢价率的核算公式为&#xff1a;溢价率&#xff1d;&#xff08;转债价格-转股价值&…

C++ 重载运算符 addition (+), subtraction (-) and multiplication (*)

C 重载运算符 addition , subtraction - and multiplication * 1. Operator Overloading (运算符重载)2. Developing an Operator Overloading Example2.1. Adding an Addition Operator (添加加法运算符)2.2. Overloading Restrictions (重载限制)2.3. 重载运算符 - 和 * Refe…

数字统计

import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别// 注意 while 处理多个 caseint a in.nextInt();i…

拯救中国足球,要不尝试一下DDD事件风暴?

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 张逸老师写了新文章《领域建模的常见问题及解决方案》&#xff0c;我来谈一谈对这篇文章的感想。 &#xff08;1&#xff09;文章一开始&#xff0c;张逸老师大大地赞扬了事件风暴&am…

Linux系统中磁盘管理LVM与挂载

Linux系统中磁盘管理LVM与挂载 本文以属于Linux系统基本概念&#xff0c;如果以查找教程教程&#xff0c;解决问题为主&#xff0c;只需要查看本文后半部分。如需要系统性学习请查看本文前半部分。 本文操作极容易导致主机无法自动重启&#xff0c;请慎重操作。操作前务必要进…

JlmPack在军民两用工业软件生态平台的使用

随着信息技术的飞速发展&#xff0c;军民两用工业软件生态平台在国防建设和民用产业中的应用日益广泛。JlmPack作为一款拥有完全自主加权概率模型下的编码算法发明专利的纯国产压缩工具库&#xff0c;其高效、安全、可控的特性在军民两用工业软件生态平台中拥有巨大的应用潜力。…

闲话银行家舍入法,以及在程序中如何实现

前言 相信对于四舍五入的舍入法&#xff0c;大家都耳熟能详&#xff0c;但对于银行家舍入法&#xff0c;可能就会比较少接触了&#xff01; 可是在金融界&#xff0c;银行家舍入法可是大名鼎鼎的主角之一&#xff0c;主要应用于金融领域和涉及货币计算的场合。 那么&#xf…

Clion中怎么切换不同的程序运行

如下图&#xff0c;比如这个文件夹下面有那么多的项目&#xff1a; 那么我想切换不同的项目运行怎么办呢&#xff1f;如果想通过下图的Edit Configurations来设置是不行的&#xff1a; 解决办法&#xff1a; 如下图&#xff0c;选中项目的CMakeLists.txt&#xff0c;右键再点击…

16. Revit API: Family、FamilySymbol、FamilyInstance

前言 前面写着一直絮絮叨叨&#xff0c;感觉不好。想找些表情包来&#xff0c;写得好玩点&#xff0c;但找不到合适的&#xff0c;或者说耗时费力又不满意&#xff0c;而自个儿又做不来表情包&#xff0c;就算了。 其次呢&#xff0c;之前会把部分类成员给抄表列出来&#xf…

电脑缺少dll文件是怎么回事?教你5种有效的解决方法

当您的计算机显示DLL文件已经遗失时&#xff0c;您应如何应对呢&#xff1f;实际上&#xff0c;针对此类DLL文件的处置过程相对来说较为简易。今日&#xff0c;我们在此为大家详细介绍此领域的相关知识&#xff0c;让大家轻松解决电脑中因丢失DLL文件而产生的问题。 一、关于DL…

关于消息队列MQ的举例 | 同步调用与异步调用的区别

为什么要有一个消息代理&#xff1f; 举例&#xff1a; 消息发送者和消息接收者直接连接&#xff0c;就好像外卖员直接把外卖送到顾客的手上。 但如果顾客此刻正在处理自己的事情&#xff0c;不方便拿外卖。 那么外卖员就需要把外卖放在外卖柜上&#xff0c;顾客方便的时候直接…