Feat/assistant app (#2086)
Co-authored-by: chenhe <guchenhe@gmail.com> Co-authored-by: Pascal M <11357019+perzeuss@users.noreply.github.com>
This commit is contained in:
266
api/core/tools/docs/zh_Hans/advanced_scale_out.md
Normal file
266
api/core/tools/docs/zh_Hans/advanced_scale_out.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# 高级接入Tool
|
||||
|
||||
在开始高级接入之前,请确保你已经阅读过[快速接入](./tool_scale_out.md),并对Dify的工具接入流程有了基本的了解。
|
||||
|
||||
## 工具接口
|
||||
|
||||
我们在`Tool`类中定义了一系列快捷方法,用于帮助开发者快速构较为复杂的工具
|
||||
|
||||
### 消息返回
|
||||
|
||||
Dify支持`文本` `链接` `图片` `文件BLOB` 等多种消息类型,你可以通过以下几个接口返回不同类型的消息给LLM和用户。
|
||||
|
||||
注意,在下面的接口中的部分参数将在后面的章节中介绍。
|
||||
|
||||
#### 图片URL
|
||||
只需要传递图片的URL即可,Dify会自动下载图片并返回给用户。
|
||||
|
||||
```python
|
||||
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
|
||||
"""
|
||||
```
|
||||
|
||||
#### 链接
|
||||
如果你需要返回一个链接,可以使用以下接口。
|
||||
|
||||
```python
|
||||
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
|
||||
"""
|
||||
```
|
||||
|
||||
#### 文本
|
||||
如果你需要返回一个文本消息,可以使用以下接口。
|
||||
|
||||
```python
|
||||
def create_text_message(self, text: str, save_as: str = '') -> ToolInvokeMessage:
|
||||
"""
|
||||
create a text message
|
||||
|
||||
:param text: the text of the message
|
||||
:return: the text message
|
||||
"""
|
||||
```
|
||||
|
||||
#### 文件BLOB
|
||||
如果你需要返回文件的原始数据,如图片、音频、视频、PPT、Word、Excel等,可以使用以下接口。
|
||||
|
||||
- `blob` 文件的原始数据,bytes类型
|
||||
- `meta` 文件的元数据,如果你知道该文件的类型,最好传递一个`mime_type`,否则Dify将使用`octet/stream`作为默认类型
|
||||
|
||||
```python
|
||||
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
|
||||
"""
|
||||
```
|
||||
|
||||
### 快捷工具
|
||||
|
||||
在大模型应用中,我们有两种常见的需求:
|
||||
- 先将很长的文本进行提前总结,然后再将总结内容传递给LLM,以防止原文本过长导致LLM无法处理
|
||||
- 工具获取到的内容是一个链接,需要爬取网页信息后再返回给LLM
|
||||
|
||||
为了帮助开发者快速实现这两种需求,我们提供了以下两个快捷工具。
|
||||
|
||||
#### 文本总结工具
|
||||
|
||||
该工具需要传入user_id和需要进行总结的文本,返回一个总结后的文本,Dify会使用当前工作空间的默认模型对长文本进行总结。
|
||||
|
||||
```python
|
||||
def summary(self, user_id: str, content: str) -> str:
|
||||
"""
|
||||
summary the content
|
||||
|
||||
:param user_id: the user id
|
||||
:param content: the content
|
||||
:return: the summary
|
||||
"""
|
||||
```
|
||||
|
||||
#### 网页爬取工具
|
||||
|
||||
该工具需要传入需要爬取的网页链接和一个user_agent(可为空),返回一个包含该网页信息的字符串,其中`user_agent`是可选参数,可以用来识别工具,如果不传递,Dify将使用默认的`user_agent`。
|
||||
|
||||
```python
|
||||
def get_url(self, url: str, user_agent: str = None) -> str:
|
||||
"""
|
||||
get url
|
||||
""" the crawled result
|
||||
```
|
||||
|
||||
### 变量池
|
||||
|
||||
我们在`Tool`中引入了一个变量池,用于存储工具运行过程中产生的变量、文件等,这些变量可以在工具运行过程中被其他工具使用。
|
||||
|
||||
下面,我们以`DallE3`和`Vectorizer.AI`为例,介绍如何使用变量池。
|
||||
|
||||
- `DallE3`是一个图片生成工具,它可以根据文本生成图片,在这里,我们将让`DallE3`生成一个咖啡厅的Logo
|
||||
- `Vectorizer.AI`是一个矢量图转换工具,它可以将图片转换为矢量图,使得图片可以无限放大而不失真,在这里,我们将`DallE3`生成的PNG图标转换为矢量图,从而可以真正被设计师使用。
|
||||
|
||||
#### DallE3
|
||||
首先我们使用DallE3,在创建完图片以后,我们将图片保存到变量池中,代码如下
|
||||
|
||||
```python
|
||||
from typing import Any, Dict, List, Union
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
from base64 import b64decode
|
||||
|
||||
from openai import OpenAI
|
||||
|
||||
class DallE3Tool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_paramters: Dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
"""
|
||||
client = OpenAI(
|
||||
api_key=self.runtime.credentials['openai_api_key'],
|
||||
)
|
||||
|
||||
# prompt
|
||||
prompt = tool_paramters.get('prompt', '')
|
||||
if not prompt:
|
||||
return self.create_text_message('Please input prompt')
|
||||
|
||||
# call openapi dalle3
|
||||
response = client.images.generate(
|
||||
prompt=prompt, model='dall-e-3',
|
||||
size='1024x1024', n=1, style='vivid', quality='standard',
|
||||
response_format='b64_json'
|
||||
)
|
||||
|
||||
result = []
|
||||
for image in response.data:
|
||||
# 将所有图片通过save_as参数保存到变量池中,变量名为self.VARIABLE_KEY.IMAGE.value,如果如果后续有新的图片生成,那么将会覆盖之前的图片
|
||||
result.append(self.create_blob_message(blob=b64decode(image.b64_json),
|
||||
meta={ 'mime_type': 'image/png' },
|
||||
save_as=self.VARIABLE_KEY.IMAGE.value))
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
我们可以注意到这里我们使用了`self.VARIABLE_KEY.IMAGE.value`作为图片的变量名,为了便于开发者们的工具能够互相配合,我们定义了这个`KEY`,大家可以自由使用,也可以不使用这个`KEY`,传递一个自定义的KEY也是可以的。
|
||||
|
||||
#### Vectorizer.AI
|
||||
接下来我们使用Vectorizer.AI,将DallE3生成的PNG图标转换为矢量图,我们先来过一遍我们在这里定义的函数,代码如下
|
||||
|
||||
```python
|
||||
from core.tools.tool.builtin_tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParamter
|
||||
from core.tools.errors import ToolProviderCredentialValidationError
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
from httpx import post
|
||||
from base64 import b64decode
|
||||
|
||||
class VectorizerTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_paramters: Dict[str, Any]) \
|
||||
-> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
|
||||
"""
|
||||
工具调用,图片变量名需要从这里传递进来,从而我们就可以从变量池中获取到图片
|
||||
"""
|
||||
|
||||
|
||||
def get_runtime_parameters(self) -> List[ToolParamter]:
|
||||
"""
|
||||
重写工具参数列表,我们可以根据当前变量池里的实际情况来动态生成参数列表,从而LLM可以根据参数列表来生成表单
|
||||
"""
|
||||
|
||||
|
||||
def is_tool_avaliable(self) -> bool:
|
||||
"""
|
||||
当前工具是否可用,如果当前变量池中没有图片,那么我们就不需要展示这个工具,这里返回False即可
|
||||
"""
|
||||
```
|
||||
|
||||
接下来我们来实现这三个函数
|
||||
|
||||
```python
|
||||
from core.tools.tool.builtin_tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParamter
|
||||
from core.tools.errors import ToolProviderCredentialValidationError
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
from httpx import post
|
||||
from base64 import b64decode
|
||||
|
||||
class VectorizerTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_paramters: Dict[str, Any]) \
|
||||
-> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
"""
|
||||
api_key_name = self.runtime.credentials.get('api_key_name', None)
|
||||
api_key_value = self.runtime.credentials.get('api_key_value', None)
|
||||
|
||||
if not api_key_name or not api_key_value:
|
||||
raise ToolProviderCredentialValidationError('Please input api key name and value')
|
||||
|
||||
# 获取image_id,image_id的定义可以在get_runtime_parameters中找到
|
||||
image_id = tool_paramters.get('image_id', '')
|
||||
if not image_id:
|
||||
return self.create_text_message('Please input image id')
|
||||
|
||||
# 从变量池中获取到之前DallE生成的图片
|
||||
image_binary = self.get_variable_file(self.VARIABLE_KEY.IMAGE)
|
||||
if not image_binary:
|
||||
return self.create_text_message('Image not found, please request user to generate image firstly.')
|
||||
|
||||
# 生成矢量图
|
||||
response = post(
|
||||
'https://vectorizer.ai/api/v1/vectorize',
|
||||
files={ 'image': image_binary },
|
||||
data={ 'mode': 'test' },
|
||||
auth=(api_key_name, api_key_value),
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(response.text)
|
||||
|
||||
return [
|
||||
self.create_text_message('the vectorized svg is saved as an image.'),
|
||||
self.create_blob_message(blob=response.content,
|
||||
meta={'mime_type': 'image/svg+xml'})
|
||||
]
|
||||
|
||||
def get_runtime_parameters(self) -> List[ToolParamter]:
|
||||
"""
|
||||
override the runtime parameters
|
||||
"""
|
||||
# 这里,我们重写了工具参数列表,定义了image_id,并设置了它的选项列表为当前变量池中的所有图片,这里的配置与yaml中的配置是一致的
|
||||
return [
|
||||
ToolParamter.get_simple_instance(
|
||||
name='image_id',
|
||||
llm_description=f'the image id that you want to vectorize, \
|
||||
and the image id should be specified in \
|
||||
{[i.name for i in self.list_default_image_variables()]}',
|
||||
type=ToolParamter.ToolParameterType.SELECT,
|
||||
required=True,
|
||||
options=[i.name for i in self.list_default_image_variables()]
|
||||
)
|
||||
]
|
||||
|
||||
def is_tool_avaliable(self) -> bool:
|
||||
# 只有当变量池中有图片时,LLM才需要使用这个工具
|
||||
return len(self.list_default_image_variables()) > 0
|
||||
```
|
||||
|
||||
可以注意到的是,我们这里其实并没有使用到`image_id`,我们已经假设了调用这个工具的时候一定有一张图片在默认的变量池中,所以直接使用了`image_binary = self.get_variable_file(self.VARIABLE_KEY.IMAGE)`来获取图片,在模型能力较弱的情况下,我们建议开发者们也这样做,可以有效提升容错率,避免模型传递错误的参数。
|
||||
BIN
api/core/tools/docs/zh_Hans/images/index/image-1.png
Normal file
BIN
api/core/tools/docs/zh_Hans/images/index/image-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
BIN
api/core/tools/docs/zh_Hans/images/index/image-2.png
Normal file
BIN
api/core/tools/docs/zh_Hans/images/index/image-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 407 KiB |
BIN
api/core/tools/docs/zh_Hans/images/index/image.png
Normal file
BIN
api/core/tools/docs/zh_Hans/images/index/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 266 KiB |
212
api/core/tools/docs/zh_Hans/tool_scale_out.md
Normal file
212
api/core/tools/docs/zh_Hans/tool_scale_out.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# 快速接入Tool
|
||||
|
||||
这里我们以GoogleSearch为例,介绍如何快速接入一个工具。
|
||||
|
||||
## 1. 准备工具供应商yaml
|
||||
|
||||
### 介绍
|
||||
这个yaml将包含工具供应商的信息,包括供应商名称、图标、作者等详细信息,以帮助前端灵活展示。
|
||||
|
||||
### 示例
|
||||
|
||||
我们需要在 `core/tools/provider/builtin`下创建一个`google`模块(文件夹),并创建`google.yaml`,名称必须与模块名称一致。
|
||||
|
||||
后续,我们关于这个工具的所有操作都将在这个模块下进行。
|
||||
|
||||
```yaml
|
||||
identity: # 工具供应商的基本信息
|
||||
author: Dify # 作者
|
||||
name: google # 名称,唯一,不允许和其他供应商重名
|
||||
label: # 标签,用于前端展示
|
||||
en_US: Google # 英文标签
|
||||
zh_Hans: Google # 中文标签
|
||||
description: # 描述,用于前端展示
|
||||
en_US: Google # 英文描述
|
||||
zh_Hans: Google # 中文描述
|
||||
icon: icon.svg # 图标,需要放置在当前模块的_assets文件夹下
|
||||
|
||||
```
|
||||
- `identity` 字段是必须的,它包含了工具供应商的基本信息,包括作者、名称、标签、描述、图标等
|
||||
- 图标需要放置在当前模块的`_assets`文件夹下,可以参考[这里](../../provider/builtin/google/_assets/icon.svg)。
|
||||
|
||||
## 2. 准备供应商凭据
|
||||
|
||||
Google作为一个第三方工具,使用了SerpApi提供的API,而SerpApi需要一个API Key才能使用,那么就意味着这个工具需要一个凭据才可以使用,而像`wikipedia`这样的工具,就不需要填写凭据字段,可以参考[这里](../../provider/builtin/wikipedia/wikipedia.yaml)。
|
||||
|
||||
配置好凭据字段后效果如下:
|
||||
```yaml
|
||||
identity:
|
||||
author: Dify
|
||||
name: google
|
||||
label:
|
||||
en_US: Google
|
||||
zh_Hans: Google
|
||||
description:
|
||||
en_US: Google
|
||||
zh_Hans: Google
|
||||
icon: icon.svg
|
||||
credentails_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 # 凭据字段帮助链接
|
||||
|
||||
```
|
||||
|
||||
- `type`:凭据字段类型,目前支持`secret-input`、`text-input`、`select` 三种类型,分别对应密码输入框、文本输入框、下拉框,如果为`secret-input`,则会在前端隐藏输入内容,并且后端会对输入内容进行加密。
|
||||
|
||||
## 3. 准备工具yaml
|
||||
一个供应商底下可以有多个工具,每个工具都需要一个yaml文件来描述,这个文件包含了工具的基本信息、参数、输出等。
|
||||
|
||||
仍然以GoogleSearch为例,我们需要在`google`模块下创建一个`tools`模块,并创建`tools/google_search.yaml`,内容如下。
|
||||
|
||||
```yaml
|
||||
identity: # 工具的基本信息
|
||||
name: google_search # 工具名称,唯一,不允许和其他工具重名
|
||||
author: Dify # 作者
|
||||
label: # 标签,用于前端展示
|
||||
en_US: GoogleSearch # 英文标签
|
||||
zh_Hans: 谷歌搜索 # 中文标签
|
||||
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 搜索并提取片段和网页的工具。输入应该是一个搜索查询。
|
||||
llm: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query. # 传递给LLM的介绍,为了使得LLM更好理解这个工具,我们建议在这里写上关于这个工具尽可能详细的信息,让LLM能够理解并使用这个工具
|
||||
parameters: # 参数列表
|
||||
- name: query # 参数名称
|
||||
type: string # 参数类型
|
||||
required: true # 是否必填
|
||||
label: # 参数标签
|
||||
en_US: Query string # 英文标签
|
||||
zh_Hans: 查询语句 # 中文标签
|
||||
human_description: # 用于前端展示的介绍,支持多语言
|
||||
en_US: used for searching
|
||||
zh_Hans: 用于搜索网页内容
|
||||
llm_description: key words for searching # 传递给LLM的介绍,同上,为了使得LLM更好理解这个参数,我们建议在这里写上关于这个参数尽可能详细的信息,让LLM能够理解这个参数
|
||||
form: llm # 表单类型,llm表示这个参数需要由Agent自行推理出来,前端将不会展示这个参数
|
||||
- name: result_type
|
||||
type: select # 参数类型
|
||||
required: true
|
||||
options: # 下拉框选项
|
||||
- value: text
|
||||
label:
|
||||
en_US: text
|
||||
zh_Hans: 文本
|
||||
- value: link
|
||||
label:
|
||||
en_US: link
|
||||
zh_Hans: 链接
|
||||
default: link
|
||||
label:
|
||||
en_US: Result type
|
||||
zh_Hans: 结果类型
|
||||
human_description:
|
||||
en_US: used for selecting the result type, text or link
|
||||
zh_Hans: 用于选择结果类型,使用文本还是链接进行展示
|
||||
form: form # 表单类型,form表示这个参数需要由用户在对话开始前在前端填写
|
||||
|
||||
```
|
||||
|
||||
- `identity` 字段是必须的,它包含了工具的基本信息,包括名称、作者、标签、描述等
|
||||
- `parameters` 参数列表
|
||||
- `name` 参数名称,唯一,不允许和其他参数重名
|
||||
- `type` 参数类型,目前支持`string`、`number`、`boolean`、`select` 四种类型,分别对应字符串、数字、布尔值、下拉框
|
||||
- `required` 是否必填
|
||||
- 在`llm`模式下,如果参数为必填,则会要求Agent必须要推理出这个参数
|
||||
- 在`form`模式下,如果参数为必填,则会要求用户在对话开始前在前端填写这个参数
|
||||
- `options` 参数选项
|
||||
- 在`llm`模式下,Dify会将所有选项传递给LLM,LLM可以根据这些选项进行推理
|
||||
- 在`form`模式下,`type`为`select`时,前端会展示这些选项
|
||||
- `default` 默认值
|
||||
- `label` 参数标签,用于前端展示
|
||||
- `human_description` 用于前端展示的介绍,支持多语言
|
||||
- `llm_description` 传递给LLM的介绍,为了使得LLM更好理解这个参数,我们建议在这里写上关于这个参数尽可能详细的信息,让LLM能够理解这个参数
|
||||
- `form` 表单类型,目前支持`llm`、`form`两种类型,分别对应Agent自行推理和前端填写
|
||||
|
||||
## 4. 准备工具代码
|
||||
当完成工具的配置以后,我们就可以开始编写工具代码了,主要用于实现工具的逻辑。
|
||||
|
||||
在`google/tools`模块下创建`google_search.py`,内容如下。
|
||||
|
||||
```python
|
||||
from core.tools.tool.builtin_tool import BuiltinTool
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
class GoogleSearchTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_paramters: Dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
"""
|
||||
query = tool_paramters['query']
|
||||
result_type = tool_paramters['result_type']
|
||||
api_key = self.runtime.credentials['serpapi_api_key']
|
||||
# TODO: search with serpapi
|
||||
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)
|
||||
```
|
||||
|
||||
### 参数
|
||||
工具的整体逻辑都在`_invoke`方法中,这个方法接收两个参数:`user_id`和`tool_paramters`,分别表示用户ID和工具参数
|
||||
|
||||
### 返回数据
|
||||
在工具返回时,你可以选择返回一个消息或者多个消息,这里我们返回一个消息,使用`create_text_message`和`create_link_message`可以创建一个文本消息或者一个链接消息。
|
||||
|
||||
## 5. 准备供应商代码
|
||||
最后,我们需要在供应商模块下创建一个供应商类,用于实现供应商的凭据验证逻辑,如果凭据验证失败,将会抛出`ToolProviderCredentialValidationError`异常。
|
||||
|
||||
在`google`模块下创建`google.py`,内容如下。
|
||||
|
||||
```python
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage, ToolProviderType
|
||||
from core.tools.tool.tool import Tool
|
||||
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
|
||||
from core.tools.errors import ToolProviderCredentialValidationError
|
||||
|
||||
from core.tools.provider.builtin.google.tools.google_search import GoogleSearchTool
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
class GoogleProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: Dict[str, Any]) -> None:
|
||||
try:
|
||||
# 1. 此处需要使用GoogleSearchTool()实例化一个GoogleSearchTool,它会自动加载GoogleSearchTool的yaml配置,但是此时它内部没有凭据信息
|
||||
# 2. 随后需要使用fork_tool_runtime方法,将当前的凭据信息传递给GoogleSearchTool
|
||||
# 3. 最后invoke即可,参数需要根据GoogleSearchTool的yaml中配置的参数规则进行传递
|
||||
GoogleSearchTool().fork_tool_runtime(
|
||||
meta={
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_paramters={
|
||||
"query": "test",
|
||||
"result_type": "link"
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
```
|
||||
|
||||
## 完成
|
||||
当上述步骤完成以后,我们就可以在前端看到这个工具了,并且可以在Agent中使用这个工具。
|
||||
|
||||
当然,因为google_search需要一个凭据,在使用之前,还需要在前端配置它的凭据。
|
||||
|
||||

|
||||
Reference in New Issue
Block a user