> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/api-can-kao/core-api-reference/character-crafting-apis/external-api.md).

# 外部 API

创建、列出、关联和删除外部 API 函数，以便你的角色能在对话中调用自定义 Python 代码。

{% hint style="danger" %}
该 API 仅适用于专业版及以上套餐。
{% endhint %}

外部 API 函数是一些小型 Python 处理器，你的角色可以在对话中将它们作为工具调用。只需创建一次函数，将它链接到一个或多个角色，模型就会根据函数名称和描述决定何时运行它。

典型流程：

1. 使用以下方式创建函数 `/functions/create/`
2. 使用以下方式将其链接到角色 `/character/update` (`status: "active"`)
3. 使用以下方式列出函数（可按角色筛选） `/functions/list/`
4. 使用以下方式将其与角色解除链接 `/character/update` (`status: "inactive"`，或使用以下方式将其完全删除 `/functions/delete/`

有关 Playground UI 演练和示例处理器（天气、体育比分、Jira），请参见 [外部 API](/api-docs/zh/convai-playground/character-customization/external-api.md).

硬性限制（支持的模型、Python 运行时、库、schema、上限）统一记录在 [外部 API 限制](/api-docs/zh/convai-playground/character-customization/external-api/external-api-limitations.md).

## 编写函数

函数运行在一个受沙箱保护的 **Python 3.11** 运行时中。请编写纯 Python，保持接口尽量精简，并返回模型可以读回对话中的 JSON 可序列化数据。

完整限制列表（允许的库、行数上限、模型支持、字符数上限）请参见 [外部 API 限制](/api-docs/zh/convai-playground/character-customization/external-api/external-api-limitations.md).

### 入口点： `handle_event`

每个函数 **必须** 定义一个名为 `handle_event` 的顶层函数，它接受一个参数。该参数是模型根据你的 `input_description`.

```python
def handle_event(inputs):
    # `inputs` 是 input_description 中定义的参数字典。
    # 在这里调用你的外部 API，并返回一个 JSON 可序列化的字典。
    return {"result": "ok"}
```

要求：

* 名称必须完全是 `handle_event`
* 它必须接受一个单独的参数（通常命名为 `inputs` 或 `data`)
* 返回一个 **JSON 可序列化** 值，几乎总是一个 `dict`
* 不要依赖跨调用的全局可变状态——每次调用都是独立的

读取一个参数并调用外部 API 的最小示例：

```python
import requests

API_KEY = "<your-api-key>"

def handle_event(inputs):
    city = inputs.get("city")
    url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}"
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    weather = response.json()
    return {
        "city": city,
        "description": weather["weather"][0]["description"],
        "temp_k": weather["main"]["temp"],
    }
```

### 输入描述 schema

`input_description` 告诉模型它可以（并且必须）传入哪些参数到 `handle_event`。在创建/更新时，它会以 **JSON 字符串**的形式发送，而不是嵌套对象。解码后的 JSON 必须匹配此 schema：

```json
{
  "type": "object",
  "properties": {
    "parameters": {
      "type": "object",
      "patternProperties": {
        "^[a-zA-Z_][a-zA-Z0-9_]*$": {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "enum": ["string", "integer", "boolean", "object", "array"]
            },
            "description": { "type": "string" }
          },
          "required": ["type", "description"]
        }
      },
      "additionalProperties": false
    },
    "required": {
      "type": "array",
      "items": { "type": "string" }
    }
  },
  "required": ["parameters", "required"]
}
```

实际含义如下：

| 字段                              | 规则                                                          |
| ------------------------------- | ----------------------------------------------------------- |
| `parameters`                    | 键为参数名称的对象。此映射之外的额外键会被拒绝（`additionalProperties: false`).     |
| 参数名称                            | 必须匹配 `^[a-zA-Z_][a-zA-Z0-9_]*$` （字母或 `_` 开头，然后是字母、数字或 `_`). |
| `parameters.<name>.type`        | 以下之一： `string`, `integer`, `布尔值`, `object`, `array`.        |
| `parameters.<name>.description` | 非空字符串，模型据此决定要传递什么值。                                         |
| `必需`                            | 必须存在的参数名称数组。这里列出的名称也应存在于 `parameters`.                      |

这些规则也在 [外部 API 限制](/api-docs/zh/convai-playground/character-customization/external-api/external-api-limitations.md#input-description).

示例 `input_description` 上进行了总结（作为对象——在发送请求体前先将其字符串化）：

```json
{
  "parameters": {
    "city": {
      "type": "string",
      "description": "要获取天气的城市名称（例如 'London'、'Tokyo'）"
    },
    "units": {
      "type": "string",
      "description": "可选的单位系统，例如 'metric' 或 'imperial'"
    }
  },
  "required": ["city"]
}
```

在 Python 中调用 create 时：

```python
input_description = json.dumps({
    "parameters": {
        "city": {
            "type": "string",
            "description": "要获取天气的城市名称"
        }
    },
    "required": ["city"]
})
```

{% hint style="info" %}
保持参数描述具体明确。模型会根据这些描述选择参数，因此像 `"a value"` 这样含糊的文本会导致错误调用。描述字符串中应尽量提供示例和单位。
{% endhint %}

***

## 创建函数

<mark style="color:绿色;">`POST`</mark> `https://api.convai.com/functions/create/`

在你的账户上创建一个新的外部 API 函数。该函数在你将其链接之前不会附加到任何角色。

#### 标头

| 名称                                              | 类型  | 说明                                          |
| ----------------------------------------------- | --- | ------------------------------------------- |
| CONVAI-API-KEY<mark style="color:红色;">\*</mark> | 字符串 | 每个用户提供的唯一 api-key。在登录 Convai 账户后，可在钥匙图标下找到。 |
| Content-Type<mark style="color:红色;">\*</mark>   | 字符串 | 必须为 `application/json`                      |

#### 请求体

| 名称                                                  | 类型  | 说明                                                                                                                                                                                                                |
| --------------------------------------------------- | --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name<mark style="color:红色;">\*</mark>               | 字符串 | 函数的显示名称。最好使用模型能够匹配的清晰动词短语（例如 `Get Weather`).                                                                                                                                                                      |
| 描述<mark style="color:红色;">\*</mark>                 | 字符串 | 角色应何时调用此函数。模型会用它进行工具选择。                                                                                                                                                                                           |
| language<mark style="color:红色;">\*</mark>           | 字符串 | 实现语言。仅支持 `python` 。                                                                                                                                                                                               |
| source\_code<mark style="color:红色;">\*</mark>       | 字符串 | 完整的 Python 3.11 源代码，包括 `handle_event`。最多 400 行。仅限标准库 + `requests` 。参见 [编写函数](#writing-functions) 和 [限制](/api-docs/zh/convai-playground/character-customization/external-api/external-api-limitations.md#runtime). |
| input\_description<mark style="color:红色;">\*</mark> | 字符串 | JSON **string** ，用于描述参数。参见 [输入描述 schema](#input-description-schema) 和 [限制](/api-docs/zh/convai-playground/character-customization/external-api/external-api-limitations.md#input-description).                    |

#### 示例载荷

```json
{
  "name": "Get Weather",
  "description": "获取给定城市的当前天气",
  "language": "python",
  "input_description": "{\"parameters\":{\"city\":{\"type\":\"string\",\"description\":\"要获取天气的城市名称\"}},\"required\":[\"city\"]}",
  "source_code": "import requests\n\nAPI_KEY = \"<openweather-api-key>\"\n\ndef handle_event(data):\n    city = data.get(\"city\")\n    url = f\"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}\"\n    response = requests.get(url)\n    weather_data = response.json()\n    return {\"weather\": weather_data[\"weather\"][0][\"description\"]}\n"
}
```

{% tabs %}
{% tab title="201：已创建" %}

```json
{
  "transactionID": "<uuid>",
  "function": {
    "function_id": "<function uuid>",
    "name": "Get Weather",
    "description": "获取给定城市的当前天气",
    "language": "python",
    "source_code": "import requests\n...",
    "base64_source_code": "<base64 encoded source>",
    "input_description": "{\"parameters\":{...},\"required\":[\"city\"]}",
    "created_at": "2026-03-18T12:34:56"
  }
}
```

{% endtab %}

{% tab title="400：错误的请求" %}

```json
{
  "ERROR": "缺少必填字段：name",
  "Reference ID": "<uuid>"
}
```

其他常见的 400 消息：

* `字段 input_description 必须是有效的 json 字符串`
* `不支持语言 pythonx`
* 无效 input\_description 引起的 schema 错误 `input_description`
* 源代码验证失败（为空、超过 400 行，或被阻止为恶意内容）
  {% endtab %}

{% tab title="401：未授权" %}

```json
{
  "ERROR": "提供的 API 密钥无效。"
}
```

{% endtab %}
{% endtabs %}

以下是一些示例代码，用于演示该端点的请求格式 -->

{% tabs %}
{% tab title="Python" %}
{% code overflow="wrap" %}

```python
import json
import requests

url = "https://api.convai.com/functions/create/"

input_description = {
    "parameters": {
        "city": {
            "type": "string",
            "description": "要获取天气的城市名称"
        }
    },
    "required": ["city"]
}

source_code = """
import requests

API_KEY = "<openweather-api-key>"

def handle_event(data):
    city = data.get("city")
    url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}"
    response = requests.get(url)
    weather_data = response.json()
    return {"weather": weather_data["weather"][0]["description"]}
""".strip()

payload = json.dumps({
    "name": "Get Weather",
    "description": "获取给定城市的当前天气",
    "language": "python",
    "input_description": json.dumps(input_description),
    "source_code": source_code
})

headers = {
    "CONVAI-API-KEY": "<your api key>",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=payload)
print(response.text)
```

{% endcode %}
{% endtab %}

{% tab title="cURL" %}
{% code overflow="wrap" %}

```shell
curl --location --request POST 'https://api.convai.com/functions/create/' \\
--header 'CONVAI-API-KEY: <your api key>' \\
--header 'Content-Type: application/json' \\
--data-raw '{
  "name": "Get Weather",
  "description": "获取给定城市的当前天气",
  "language": "python",
  "input_description": "{\"parameters\":{\"city\":{\"type\":\"string\",\"description\":\"要获取天气的城市名称\"}},\"required\":[\"city\"]}",
  "source_code": "import requests\n\nAPI_KEY = \"<openweather-api-key>\"\n\ndef handle_event(data):\n    city = data.get(\"city\")\n    url = f\"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}\"\n    response = requests.get(url)\n    weather_data = response.json()\n    return {\"weather\": weather_data[\"weather\"][0][\"description\"]}\n"
}'
```

{% endcode %}
{% endtab %}
{% endtabs %}

***

## 列出函数

<mark style="color:绿色;">`POST`</mark> `https://api.convai.com/functions/list/`

返回你账户中的外部 API 函数。传入 `character_id` 可包含该角色的每个函数链接状态（`active` 或 `inactive`).

#### 标头

| 名称                                              | 类型  | 说明                                          |
| ----------------------------------------------- | --- | ------------------------------------------- |
| CONVAI-API-KEY<mark style="color:红色;">\*</mark> | 字符串 | 每个用户提供的唯一 api-key。在登录 Convai 账户后，可在钥匙图标下找到。 |

#### 请求体

所有字段都是可选的。空请求体会列出账户中的所有函数。

| 名称            | 类型  | 说明                                                    |
| ------------- | --- | ----------------------------------------------------- |
| character\_id | 字符串 | 如果设置，每个函数都会包含 `status` 相对于此角色的`active` / `inactive`). |
| per\_page     | 整数  | 每页大小。默认值为 `-1` （返回全部）。设置为正值时，会添加分页字段。                 |
| page          | 整数  | 页码，从 `1`开始。仅在 `per_page` 不是 `-1`。默认值 `1`.             |

#### 示例载荷

```json
{
  "character_id": "<character uuid>",
  "per_page": 20,
  "page": 1
}
```

{% tabs %}
{% tab title="200：正常" %}

```json
{
  "transactionID": "<uuid>",
  "functions": [
    {
      "function_id": "<function uuid>",
      "name": "Get Weather",
      "description": "获取给定城市的当前天气",
      "language": "python",
      "created_at": "2026-03-18T12:34:56",
      "status": "active"
    }
  ],
  "total_pages": 1,
  "per_page": 20,
  "page": 1,
  "total": 1
}
```

`total_pages`, `per_page`, `page`，以及 `total` 仅在 `per_page` 为正整数时存在。
{% endtab %}

{% tab title="400：错误的请求" %}

```json
{
  "ERROR": "获取函数失败，响应为：...",
  "Reference ID": "<uuid>"
}
```

{% endtab %}

{% tab title="401：未授权" %}

```json
{
  "ERROR": "提供的 API 密钥无效。"
}
```

{% endtab %}
{% endtabs %}

以下是一些示例代码，用于演示该端点的请求格式 -->

{% tabs %}
{% tab title="Python" %}
{% code overflow="wrap" %}

```python
import json
import requests

url = "https://api.convai.com/functions/list/"

payload = json.dumps({
    "character_id": "<character uuid>",
    "per_page": 20,
    "page": 1
})
headers = {
    "CONVAI-API-KEY": "<your api key>",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=payload)
print(response.text)
```

{% endcode %}
{% endtab %}

{% tab title="cURL" %}
{% code overflow="wrap" %}

```shell
curl --location --request POST 'https://api.convai.com/functions/list/' \\
--header 'CONVAI-API-KEY: <your api key>' \\
--header 'Content-Type: application/json' \\
--data-raw '{
  "character_id": "<character uuid>",
  "per_page": 20,
  "page": 1
}'
```

{% endcode %}
{% endtab %}
{% endtabs %}

***

## 将函数链接到角色

<mark style="color:绿色;">`POST`</mark> `https://api.convai.com/character/update`

通过现有的 [角色基础 API](/api-docs/zh/api-can-kao/core-api-reference/character-crafting-apis/character-api.md) 更新端点，将一个或多个外部 API 函数附加到角色。链接后（`status: "active"`），模型就可以在对话中调用这些函数。

一个角色最多可以有 **128** 个处于激活状态的函数。你可以在一次请求中链接多个函数，并且可以混合链接和 [解除链接](#unlink-functions-from-a-character) 条目。

#### 标头

| 名称                                              | 类型  | 说明                                          |
| ----------------------------------------------- | --- | ------------------------------------------- |
| CONVAI-API-KEY<mark style="color:红色;">\*</mark> | 字符串 | 每个用户提供的唯一 api-key。在登录 Convai 账户后，可在钥匙图标下找到。 |
| Content-Type                                    | 字符串 | `application/json`                          |

#### 请求体

| 名称                                      | 类型  | 说明                                                      |
| --------------------------------------- | --- | ------------------------------------------------------- |
| charID<mark style="color:红色;">\*</mark> | 字符串 | 要更新的角色。                                                 |
| functions                               | 数组  | 函数配置列表。每个项目都需要 `id` （函数 UUID）和 `status` 设置为 `"active"`. |

#### 示例载荷

```json
{
  "charID": "<character uuid>",
  "functions": [
    {
      "id": "<function uuid>",
      "status": "active"
    }
  ]
}
```

{% tabs %}
{% tab title="200：正常" %}

```json
{
  "STATUS": "SUCCESS"
}
```

{% endtab %}

{% tab title="400：错误的请求" %}

```json
{
  "ERROR": "Function limit exceeded. A maximum of 128 functions can be connected to a character.",
  "Reference ID": "<uuid>"
}
```

无效配置也会返回此信息，例如：

* `Functions 必须是配置列表`
* `函数配置中缺少必填字段：id`
* `函数状态必须是以下之一：active, inactive`
* `发现重复的函数 ID：<id>`
  {% endtab %}

{% tab title="401：未授权" %}

```json
{
  "ERROR": "提供的 API 密钥无效。"
}
```

{% endtab %}
{% endtabs %}

以下是一些示例代码，用于演示该端点的请求格式 -->

{% tabs %}
{% tab title="Python" %}
{% code overflow="wrap" %}

```python
import json
import requests

url = "https://api.convai.com/character/update"

payload = json.dumps({
    "charID": "<character uuid>",
    "functions": [
        {"id": "<function uuid>", "status": "active"}
    ]
})
headers = {
    "CONVAI-API-KEY": "<your api key>",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=payload)
print(response.text)
```

{% endcode %}
{% endtab %}

{% tab title="cURL" %}
{% code overflow="wrap" %}

```shell
curl --location --request POST 'https://api.convai.com/character/update' \\
--header 'CONVAI-API-KEY: <your api key>' \\
--header 'Content-Type: application/json' \\
--data-raw '{
  "charID": "<character uuid>",
  "functions": [
    {"id": "<function uuid>", "status": "active"}
  ]
}'
```

{% endcode %}
{% endtab %}
{% endtabs %}

链接后，请使用 `/functions/list/` 和 `character_id` 进行确认——已链接的函数会显示 `"status": "active"`.

***

## 将函数与角色解除链接

<mark style="color:绿色;">`POST`</mark> `https://api.convai.com/character/update`

在不从你的账户中删除函数的情况下，将其与角色断开连接。与链接使用同一端点；设置 `status` 为 `"inactive"`.

。解除链接后，角色将不再能够调用该函数。该函数仍可稍后重新链接，或附加到其他角色。

#### 标头

| 名称                                              | 类型  | 说明                                          |
| ----------------------------------------------- | --- | ------------------------------------------- |
| CONVAI-API-KEY<mark style="color:红色;">\*</mark> | 字符串 | 每个用户提供的唯一 api-key。在登录 Convai 账户后，可在钥匙图标下找到。 |
| Content-Type                                    | 字符串 | `application/json`                          |

#### 请求体

| 名称                                      | 类型  | 说明                                                        |
| --------------------------------------- | --- | --------------------------------------------------------- |
| charID<mark style="color:红色;">\*</mark> | 字符串 | 要更新的角色。                                                   |
| functions                               | 数组  | 函数配置列表。每个项目都需要 `id` （函数 UUID）和 `status` 设置为 `"inactive"`. |

#### 示例载荷

```json
{
  "charID": "<character uuid>",
  "functions": [
    {
      "id": "<function uuid>",
      "status": "inactive"
    }
  ]
}
```

{% tabs %}
{% tab title="200：正常" %}

```json
{
  "STATUS": "SUCCESS"
}
```

{% endtab %}

{% tab title="400：错误的请求" %}

```json
{
  "ERROR": "函数配置中缺少必填字段：status",
  "Reference ID": "<uuid>"
}
```

{% endtab %}

{% tab title="401：未授权" %}

```json
{
  "ERROR": "提供的 API 密钥无效。"
}
```

{% endtab %}
{% endtabs %}

以下是一些示例代码，用于演示该端点的请求格式 -->

{% tabs %}
{% tab title="Python" %}
{% code overflow="wrap" %}

```python
import json
import requests

url = "https://api.convai.com/character/update"

payload = json.dumps({
    "charID": "<character uuid>",
    "functions": [
        {"id": "<function uuid>", "status": "inactive"}
    ]
})
headers = {
    "CONVAI-API-KEY": "<your api key>",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=payload)
print(response.text)
```

{% endcode %}
{% endtab %}

{% tab title="cURL" %}
{% code overflow="wrap" %}

```shell
curl --location --request POST 'https://api.convai.com/character/update' \\
--header 'CONVAI-API-KEY: <your api key>' \\
--header 'Content-Type: application/json' \\
--data-raw '{
  "charID": "<character uuid>",
  "functions": [
    {"id": "<function uuid>", "status": "inactive"}
  ]
}'
```

{% endcode %}
{% endtab %}
{% endtabs %}

使用以下方式确认： `/functions/list/` 和 `character_id` 进行确认——已解除链接的函数会显示 `"status": "inactive"`.

{% hint style="info" %}
解除链接只会移除与角色的关联。若要将函数从你的账户中完全删除（以及从所有已链接到它的角色中删除），请使用 [删除函数](#delete-a-function).
{% endhint %}

***

## 删除函数

<mark style="color:绿色;">`POST`</mark> `https://api.convai.com/functions/delete/`

删除你拥有的函数，并移除其与所有角色的关联。此操作无法撤销。

#### 标头

| 名称                                              | 类型  | 说明                                          |
| ----------------------------------------------- | --- | ------------------------------------------- |
| CONVAI-API-KEY<mark style="color:红色;">\*</mark> | 字符串 | 每个用户提供的唯一 api-key。在登录 Convai 账户后，可在钥匙图标下找到。 |
| Content-Type<mark style="color:红色;">\*</mark>   | 字符串 | 必须为 `application/json`                      |

#### 请求体

| 名称                                            | 类型  | 说明           |
| --------------------------------------------- | --- | ------------ |
| function\_id<mark style="color:红色;">\*</mark> | 字符串 | 要删除的函数的 UUID |

#### 示例载荷

```json
{
  "function_id": "<function uuid>"
}
```

{% tabs %}
{% tab title="200：正常" %}

```json
{
  "transactionID": "<uuid>",
  "status": "success"
}
```

{% endtab %}

{% tab title="403：禁止访问" %}

```json
{
  "ERROR": "你没有权限删除此函数",
  "Reference ID": "<uuid>"
}
```

{% endtab %}

{% tab title="404：未找到" %}

```json
{
  "ERROR": "未找到 id 为 <function uuid> 的函数",
  "Reference ID": "<uuid>"
}
```

{% endtab %}

{% tab title="401：未授权" %}

```json
{
  "ERROR": "提供的 API 密钥无效。"
}
```

{% endtab %}
{% endtabs %}

以下是一些示例代码，用于演示该端点的请求格式 -->

{% tabs %}
{% tab title="Python" %}
{% code overflow="wrap" %}

```python
import json
import requests

url = "https://api.convai.com/functions/delete/"

payload = json.dumps({
    "function_id": "<function uuid>"
})
headers = {
    "CONVAI-API-KEY": "<your api key>",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=payload)
print(response.text)
```

{% endcode %}
{% endtab %}

{% tab title="cURL" %}
{% code overflow="wrap" %}

```shell
curl --location --request POST 'https://api.convai.com/functions/delete/' \\
--header 'CONVAI-API-KEY: <your api key>' \\
--header 'Content-Type: application/json' \\
--data-raw '{
  "function_id": "<function uuid>"
}'
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
若要在不删除的情况下将函数与角色断开连接，请使用 [将函数与角色解除链接](#unlink-functions-from-a-character).
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/api-can-kao/core-api-reference/character-crafting-apis/external-api.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
