## 场景 01 · 发起智能体对话

从创建身份主体到实时消费智能体输出的端到端流程。

> **调用流程：** 创建身份主体（Principal） → 创建智能体（Agent） → 异步提交对话（获取 requestId） → 订阅 SSE 事件流。

## 前置条件

已开通点金租户并创建应用、已获取 API Key。

```text
Base URL: https://router.fis.aliyuncs.com/finx
```

## 鉴权说明（二要素）

| Header | 说明 | 必须 |
| --- | --- | --- |
| `Authorization: Bearer <TOKEN>` | 访问令牌（API Key） | 是 |
| `X-Principal-Id: <id>` | 身份主体 ID | 运行类接口必须 |
| `Content-Type: application/json` | JSON 请求体 | 视接口 |

### Step 1: 创建身份主体（Principal）

POST /api/principal/create — 为每个最终用户/场景创建独立身份主体

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| principalName | string | 主体名称（必填） |
| principalDescription | string | 主体描述 |

```bash
curl -X POST 'https://router.fis.aliyuncs.com/finx/api/principal/create' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"principalName": "客服机器人主体"}'
```

### Step 2: 创建智能体（Agent）

POST /api/agent/create — 创建智能体实例，返回 agentId

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| agentName | string | 智能体名称（必填） |
| agentSoul | string | System Prompt |
| defaultModelName | string | 默认模型 |

```bash
curl -X POST 'https://router.fis.aliyuncs.com/finx/api/agent/create' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"agentName": "我的智能体"}'
```

### Step 3: 提交对话（异步运行）

POST /api/agent/run/async — 立即返回 requestId，不阻塞

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| agentId | int64 | 智能体 ID（必填） |
| userInput | string | 发送给智能体的消息（必填） |
| sessionId | int64 | 会话 ID（不传则新建） |
| triggerSource | object | 触发来源，建议 api_call |

```bash
curl -X POST 'https://router.fis.aliyuncs.com/finx/api/agent/run/async' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'X-Principal-Id: <principalId>' \
  -H 'Content-Type: application/json' \
  -d '{"agentId":1001,"userInput":"你好","triggerSource":{"sourceType":"api_call"}}'
```

### Step 4: 消费 SSE 事件流

GET /api/agent/run/stream?requestId=xxx — 实时读取智能体输出

| 参数 | 说明 |
| --- | --- |
| requestId | 步骤 3 返回的异步请求 ID（必填） |
| lastEventId | 断线重连时传入上次最大事件 ID |

```bash
curl -N -X GET 'https://router.fis.aliyuncs.com/finx/api/agent/run/stream?requestId=<requestId>' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'Accept: text/event-stream'
```

SSE 数据格式：每条事件的 `event` 为 `EventType` 枚举名（如 `TEXT_DELTA`），`data` 为完整的 `AgentEvent` JSON 信封（包含 `eventType`、`data`、`timestamp`、`step`、`totalTokens`）。

```text
id: 0
event: TEXT_DELTA
data: {"eventType":"TEXT_DELTA","data":{"type":"text","text":"你好...","synthetic":false},"timestamp":"2026-05-07T10:30:01","step":1,"totalTokens":256}
```

更多事件类型和数据结构详见[数据模型 -> SSE 事件结构](/docs/quickstart/data-model.md#sse-event-types)。

> **注意事项**
> 
> API 接入必须携带 X-Principal-Id；提交对话后应尽快订阅 SSE；断线用 lastEventId 重连；所有非流式接口先判断 success 再取 data。

> 文件：`agent_conversation.py`

```python
# 公共：Base URL + Token + 鉴权头
import requests

BASE_URL = "https://router.fis.aliyuncs.com/finx"
TOKEN    = "<YOUR_API_KEY>"

def auth_headers(principal_id=None, json_body=True):
    h = {"Authorization": f"Bearer {TOKEN}"}
    if json_body:
        h["Content-Type"] = "application/json"
    if principal_id is not None:
        h["X-Principal-Id"] = str(principal_id)
    return h

def unwrap(resp):
    body = resp.json()
    if not body.get("success"):
        raise RuntimeError(body["message"])
    return body["data"]
```

```python
# 步骤 1：创建身份主体 → principalId
def create_principal(name="客服机器人主体"):
    data = unwrap(requests.post(
        f"{BASE_URL}/api/principal/create",
        headers=auth_headers(),
        json={"principalName": name},
    ))
    return data["principalId"]
```

```python
# 步骤 2：创建智能体 → agentId
def create_agent(principal_id, name="我的智能体"):
    data = unwrap(requests.post(
        f"{BASE_URL}/api/agent/create",
        headers=auth_headers(principal_id),
        json={"agentName": name},
    ))
    return data["agentId"]
```

```python
# 步骤 3：异步提交对话 → requestId
def run_async(principal_id, agent_id, user_input):
    data = unwrap(requests.post(
        f"{BASE_URL}/api/agent/run/async",
        headers=auth_headers(principal_id),
        json={
            "agentId": agent_id,
            "userInput": user_input,
            "triggerSource": {"sourceType": "api_call"},
        },
    ))
    return data["requestId"], data["sessionId"]
```

```python
# 步骤 4：SSE 消费事件流
def stream_events(principal_id, request_id):
    headers = auth_headers(principal_id, json_body=False)
    headers["Accept"] = "text/event-stream"
    with requests.get(
        f"{BASE_URL}/api/agent/run/stream",
        headers=headers,
        params={"requestId": request_id},
        stream=True, timeout=300,
    ) as resp:
        for raw in resp.iter_lines(decode_unicode=True):
            if raw and raw.startswith("data:"):
                print(raw[5:].strip())

if __name__ == "__main__":
    pid = create_principal()
    aid = create_agent(pid)
    req_id, sid = run_async(pid, aid, "你好，请做个自我介绍")
    stream_events(pid, req_id)
```
