> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aibase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 同步与异步任务模式

> 理解 AIBase 开放平台的 SYNC（同步）与 ASYNC（异步）执行机制及任务轮询规范。

AIBase 开放平台的统一任务提交入口（`POST /v1/openapi/tasks`）支持 **SYNC（同步）** 和 **ASYNC（异步）** 两种执行模式。不同业务 API 因计算复杂度、大模型调用链路耗时的差异，分别采用对应的执行模式。

<CardGroup cols={2}>
  <Card title="SYNC · 同步模式" icon="bolt">
    **提交即返回结果**。适用于轻量、单步或毫秒级完成的高频服务（如“AI 对话问题挖掘”）。
  </Card>

  <Card title="ASYNC · 异步模式" icon="clock">
    **提交返回任务 ID，异步轮询**。适用于涉及多家大模型多轮交互、深度分析的任务（如“GEO 排名”、“品牌得分”等）。
  </Card>
</CardGroup>

***

## 两种模式对比

| 维度          | SYNC · 同步执行                               | ASYNC · 异步执行                                               |
| ----------- | ----------------------------------------- | ---------------------------------------------------------- |
| **典型接口**    | `geo.questions_corr_recommend`（AI 对话问题挖掘） | `geo.ranking`、`geo.rank_monitor`、`geo.brand`、`geo.checker` |
| **执行耗时**    | 毫秒级至秒级                                    | 数秒至数十秒（取决于并发大模型数量与响应）                                      |
| **提交接口返回**  | 直接返回业务 `data.result`                      | 返回 `data.taskId` 与 `data.requestId`                        |
| **调用方后续动作** | 直接解析业务结果，结束调用                             | 间隔 10 秒调用任务查询接口，直至终态                                       |
| **结果获取端点**  | `POST /v1/openapi/tasks`                  | `GET /v1/openapi/tasks/{taskId}`                           |

***

## 统一路由与执行流程

无论调用何种业务，客户端始终发起相同的统一入口请求，服务端根据请求体中的 `apiCode` 自动判断并调度执行模式：

```mermaid theme={null}
flowchart TD
    Start([客户端发起请求]) --> Submit[POST /v1/openapi/tasks]
    Submit --> Route[读取 apiCode 并路由至业务模块]
    Route --> Check{判断执行模式}

    Check -->|SYNC · 同步| ExecSync[执行业务逻辑]
    ExecSync --> ReturnSync([直接返回业务 result])

    Check -->|ASYNC · 异步| CreateTask[创建异步任务]
    CreateTask --> ReturnTask[返回 requestId + taskId]
    ReturnTask --> Wait[客户端等待 10 秒]
    Wait --> Poll[GET /v1/openapi/tasks/{taskId}]
    Poll --> StatusCheck{检查 status}

    StatusCheck -->|status = 1 PENDING| Wait
    StatusCheck -->|status = 2 SUCCESS| Success([获取 data.result 完成])
    StatusCheck -->|status = 3 / 4 / 5| Terminate([失败/超时/取消 结束])
```

***

## ASYNC 异步模式接入步骤

### 第一步：提交异步任务

向统一入口发起 `POST` 请求：

```http theme={null}
POST https://api.aibase.cn/v1/openapi/tasks
AIBase-API-Key: AIBase_xxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "apiCode": "geo.ranking",
  "data": {
    "keyword": "性价比高的智能手机推荐",
    "brandKeyword": ["小米", "华为"],
    "platforms": ["deepseek", "baidu"]
  }
}
```

接口接收后立即创建后台任务并返回：

```json theme={null}
{
  "code": 200,
  "msg": "成功",
  "data": {
    "requestId": "599b2f8f39078d",
    "taskId": "task_d77143abc87642d4842ff588197faa89"
  },
  "timeStamp": 1789550182642
}
```

<Important>
  异步模式下，提交接口响应中**不包含业务结果**。请务必保存 `taskId`（用于后续轮询）和 `requestId`（用于日志追踪）。
</Important>

### 第二步：轮询查询任务状态

拿到 `taskId` 后，调用通用的异步任务查询接口：

```http theme={null}
GET https://api.aibase.cn/v1/openapi/tasks/task_d77143abc87642d4842ff588197faa89
AIBase-API-Key: AIBase_xxxxxxxxxxxxxxxx
```

响应示例（成功完成状态）：

```json theme={null}
{
  "code": 200,
  "msg": "成功",
  "data": {
    "taskId": "task_d77143abc87642d4842ff588197faa89",
    "status": 2,
    "statusDesc": "成功",
    "result": {
      "keyword": "性价比高的智能手机推荐",
      "data": []
    }
  },
  "timeStamp": 1789551724519
}
```

***

## 任务状态枚举说明

任务查询返回的 `data.status` 为 `Integer` 类型，定义如下：

| status | 标识            | 说明       | 开发者动作                       |
| :----- | :------------ | :------- | :-------------------------- |
| `1`    | **PENDING**   | 任务排队或执行中 | 等待 10 秒后继续下一次查询             |
| `2`    | **SUCCESS**   | 任务执行成功   | 停止轮询，从 `data.result` 读取业务结果 |
| `3`    | **FAILED**    | 任务执行失败   | 停止轮询，记录日志或进入降级逻辑            |
| `4`    | **TIMEOUT**   | 任务执行超时   | 停止轮询，提示超时或适度重试              |
| `5`    | **CANCELLED** | 任务已被取消   | 停止轮询                        |

<Tip>
  **推荐轮询频率：** 建议轮询间隔为 **10 秒**，避免过高频率请求造成网络与限流压力。任务最大轮询时长可根据业务设置（通常建议 120 \~ 300 秒超时上限）。
</Tip>

***

## 多语言异步轮询示例

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    import time
    import requests

    API_KEY = os.environ.get("AIBASE_API_KEY", "AIBase_xxxxxxxxxxxxxxxx")
    HEADERS = {
        "AIBase-API-Key": API_KEY,
        "Content-Type": "application/json"
    }

    # 1. 提交异步任务
    submit_resp = requests.post(
        "https://api.aibase.cn/v1/openapi/tasks",
        headers=HEADERS,
        json={
            "apiCode": "geo.ranking",
            "data": {
                "keyword": "性价比高的智能手机推荐",
                "brandKeyword": ["小米", "华为"],
                "platforms": ["deepseek", "baidu"]
            }
        },
        timeout=30
    )
    submit_data = submit_resp.json()
    if submit_data.get("code") != 200:
        raise RuntimeError(f"任务提交失败: {submit_data}")

    task_id = submit_data["data"]["taskId"]
    print(f"任务已提交，taskId: {task_id}")

    # 2. 轮询任务状态（间隔 10 秒）
    max_retries = 30  # 最多轮询 30 次（约 5 分钟）
    for i in range(max_retries):
        time.sleep(10)
        query_resp = requests.get(
            f"https://api.aibase.cn/v1/openapi/tasks/{task_id}",
            headers=HEADERS,
            timeout=30
        )
        query_data = query_resp.json()
        status = query_data.get("data", {}).get("status")

        if status == 2:  # SUCCESS
            print("任务成功完成！")
            result = query_data["data"]["result"]
            print("业务结果:", result)
            break
        elif status == 1:  # PENDING
            print(f"[{i+1}/{max_retries}] 任务仍在执行中，等待下一次查询...")
        else:  # 3 FAILED, 4 TIMEOUT, 5 CANCELLED
            desc = query_data.get("data", {}).get("statusDesc", "未知状态")
            raise RuntimeError(f"任务异常终止，状态: {status} ({desc})")
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    import { setTimeout } from "node:timers/promises";

    const apiKey = process.env.AIBASE_API_KEY || "AIBase_xxxxxxxxxxxxxxxx";
    const headers = {
      "AIBase-API-Key": apiKey,
      "Content-Type": "application/json",
    };

    // 1. 提交异步任务
    const submitRes = await fetch("https://api.aibase.cn/v1/openapi/tasks", {
      method: "POST",
      headers,
      body: JSON.stringify({
        apiCode: "geo.ranking",
        data: {
          keyword: "性价比高的智能手机推荐",
          brandKeyword: ["小米", "华为"],
          platforms: ["deepseek", "baidu"],
        },
      }),
    });
    const submitData = await submitRes.json();
    if (submitData.code !== 200) {
      throw new Error(`提交失败: ${JSON.stringify(submitData)}`);
    }

    const taskId = submitData.data.taskId;
    console.log("任务已创建，taskId:", taskId);

    // 2. 轮询状态（间隔 10 秒）
    const maxRetries = 30;
    for (let i = 0; i < maxRetries; i++) {
      await setTimeout(10000);
      const queryRes = await fetch(`https://api.aibase.cn/v1/openapi/tasks/${taskId}`, {
        headers,
      });
      const queryData = await queryRes.json();
      const status = queryData.data?.status;

      if (status === 2) {
        console.log("任务成功！结果:", queryData.data.result);
        break;
      } else if (status === 1) {
        console.log(`[${i + 1}/${maxRetries}] 任务处理中，继续等待...`);
      } else {
        throw new Error(`任务失败或终止，status: ${status}`);
      }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.time.Duration;

    public class AIBaseAsyncDemo {
        public static void main(String[] args) throws Exception {
            String apiKey = System.getenv().getOrDefault("AIBASE_API_KEY", "AIBase_xxxxxxxxxxxxxxxx");
            HttpClient client = HttpClient.newHttpClient();

            // 1. 提交任务
            String submitJson = """
                {
                  "apiCode": "geo.ranking",
                  "data": {
                    "keyword": "性价比高的智能手机推荐",
                    "brandKeyword": ["小米", "华为"],
                    "platforms": ["deepseek", "baidu"]
                  }
                }
                """;
            HttpRequest submitReq = HttpRequest.newBuilder()
                .uri(URI.create("https://api.aibase.cn/v1/openapi/tasks"))
                .header("AIBase-API-Key", apiKey)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(submitJson))
                .build();

            HttpResponse<String> submitResp = client.send(submitReq, HttpResponse.BodyHandlers.ofString());
            // 需引入 JSON 库解析返回的 taskId，此处以变量伪代码示意
            String taskId = "task_d77143abc87642d4842ff588197faa89"; 

            // 2. 轮询查询（间隔 10 秒）
            for (int i = 0; i < 30; i++) {
                Thread.sleep(10000);
                HttpRequest queryReq = HttpRequest.newBuilder()
                    .uri(URI.create("https://api.aibase.cn/v1/openapi/tasks/" + taskId))
                    .header("AIBase-API-Key", apiKey)
                    .GET()
                    .build();
                HttpResponse<String> queryResp = client.send(queryReq, HttpResponse.BodyHandlers.ofString());
                // 判断返回体中的 status：
                // status == 2 -> 获取 data.result，跳出循环
                // status == 1 -> 继续等待
                // status >= 3 -> 异常终止
            }
        }
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # 1. 提交任务获取 taskId
    curl --location 'https://api.aibase.cn/v1/openapi/tasks' \
      --header 'AIBase-API-Key: AIBase_xxxxxxxxxxxxxxxx' \
      --header 'Content-Type: application/json' \
      --data '{
        "apiCode": "geo.ranking",
        "data": {
          "keyword": "性价比高的智能手机推荐",
          "brandKeyword": ["小米", "华为"],
          "platforms": ["deepseek", "baidu"]
        }
      }'

    # 2. 间隔 10 秒轮询查询
    curl --location 'https://api.aibase.cn/v1/openapi/tasks/task_d77143abc87642d4842ff588197faa89' \
      --header 'AIBase-API-Key: AIBase_xxxxxxxxxxxxxxxx'
    ```
  </Tab>
</Tabs>

***

## 最佳实践与注意事项

1. **切勿在第一步尝试读取结果**：异步模式在提交端点中仅返回 `requestId` 和 `taskId`，绝不可假设 `data.result` 在提交接口中存在。
2. **保持 10 秒合理轮询间隔**：过于频繁的轮询（如 1 秒一次）不仅无法加快大模型计算，还会消耗 API 限流配额或引发 HTTP 429 报错。
3. **设置合理的超时上限**：建议客户端为轮询流程设置 3 \~ 5 分钟的兜底超时控制，防止因网络单点中断导致进程永久阻塞。
4. **日志追踪双标识**：排查异步流程时，请在日志中同时保存首次提交的 `requestId` 和生成的 `taskId`。
