---
title: "給 Custom App 的預建能力：SDK 全景"
category: "app-development"
canonical: "https://www.ai-go.app/zh-TW/docs/guide/app-sdk"
locale: "zh-TW"
last_updated: "2026-08-10"
source: "AI GO 開發者文件（https://www.ai-go.app）"
---

# 給 Custom App 的預建能力：SDK 全景

這是本手冊最重要的一章。

當您在 AI GO 上開發應用程式時，有一大類工作**不需要做**——資料庫連線、租戶隔離、權限檢查、ERP 業務邏輯、簽核流程、向量檢索、外部 API 的安全出口、金鑰保管、加解密。平台把這些預先建好，以 SDK 的形式交到您手上。

SDK 分兩側：**伺服器端的 `ctx` 物件**（在 Action 中使用）與**前端的六支 TypeScript SDK**。

---

## 伺服器端：`ctx` 物件

每個 Action 都是一個接收 `ctx` 的函式：

```python
def execute(ctx):
    ...
```

`ctx` 上掛著平台的全部能力。

### 執行脈絡屬性

| 屬性 | 內容 |
|---|---|
| `ctx.params` | 呼叫端傳入的參數 |
| `ctx.app_id` | 執行中的應用程式識別碼 |
| `ctx.tenant_id` | 所屬組織識別碼 |
| `ctx.action_name` | 當前執行的 Action 名稱 |
| `ctx.env` | 執行環境（`online` / `dev`） |
| `ctx.user_id` | 觸發者的使用者識別碼 |
| `ctx.user_roles` | 觸發者的角色名稱清單（唯讀快照） |
| `ctx.user_permissions` | 觸發者的權限標籤清單（唯讀快照） |

**判斷授權請用 `user_permissions` 而不是 `user_roles`**——角色名稱可以被改名，權限標籤是穩定的識別。

---

## `ctx.db` — 資料存取

存取兩類資料：ERP 內建表與自建表。

| 方法 | 用途 |
|---|---|
| `query(table, filters, order_by, limit, offset)` | 查詢 ERP 表 |
| `insert(table, data)` | 新增 ERP 表記錄 |
| `update(table, row_id, data)` | 更新 ERP 表記錄 |
| `remove(table, row_id)` | 刪除 ERP 表記錄 |
| `list_tables()` | 列出組織的自建表 |
| `query_table(name, filters, ...)` | 查詢自建表 |
| `insert_row(name, data)` | 新增自建表記錄 |
| `update_row(name, row_id, data)` | 更新自建表記錄 |
| `delete_row(name, row_id)` | 刪除自建表記錄 |

**典型場景**：任何需要讀寫企業資料的地方。查詢支援完整的過濾、排序、分頁——不是只有「取全部」。

```python
orders = ctx.db.query('sale_orders',
    filters=[
        {'column': 'state', 'op': 'eq', 'value': 'sale'},
        {'column': 'amount_total', 'op': 'gte', 'value': 10000},
    ],
    order_by=[{'column': 'created_at', 'direction': 'desc'}],
    limit=50)
```

**授權**：讀取需 `db.read` / `data_table.read`，寫入需 `db.write` / `data_table.write`。ERP 表另外受引用宣告約束——沒宣告的表與欄位存取不到。

---

## `ctx.erp` — 觸發業務引擎

這是最容易被低估的模組。它不是「寫一筆資料」，而是**觸發平台預建的完整業務流程**。

| 方法 | 觸發什麼 |
|---|---|
| `confirm_sale_order(id)` | 確認銷售訂單（連動出貨與開票準備） |
| `confirm_purchase_order(id)` | 確認採購訂單 |
| `create_invoice(order_id)` | 從銷售訂單開立銷項發票。**`order_id` 可傳清單**——多張訂單合併開一張發票 |
| `create_bill(order_id)` | 從採購訂單建立進項帳單。同樣支援清單合併 |
| `validate_picking(id)` | 驗證揀貨單（連動庫存移動與存貨計價） |
| `post_move(id)` | 過帳會計傳票 |
| `confirm_payment(id)` | 確認收付款（連動自動沖銷） |
| `reconcile_payment(id)` | 補跑已過帳付款的沖銷引擎 |
| `confirm_payroll_run(id)` | 確認薪資結算批次（連動應付薪資傳票） |
| `cancel_payroll_run(id)` | 撤銷薪資批次（自動產生沖銷分錄） |

**典型場景**：您做了一個「業務快速結單」的應用。使用者按下按鈕後，訂單確認、發票開立、庫存扣減、會計傳票——全部由一次 `ctx.erp` 呼叫連鎖完成，您不需要知道會計科目怎麼帶、稅率怎麼算。

合併開票值得特別說明：傳入訂單 id 清單時，會把清單內所有訂單的明細彙總進**同一張**發票（要求同客戶、同組織）。這解掉了「月結客戶要合併開票」這個常見需求。

**授權**：各方法對應獨立的 scope（如 `erp.sale_order.confirm`），全部屬於高風險等級。

---

## `ctx.approval` — 簽核

| 方法 | 用途 |
|---|---|
| `list_pending()` | 取得**觸發者本人**的待簽核清單 |
| `get_record_status(res_model, res_id)` | 查某筆記錄的簽核狀態與各關卡明細 |
| `approve(request_line_id, comment)` | 以觸發者身分核准一層 |
| `reject(request_line_id, comment)` | 以觸發者身分駁回 |
| `cancel(request_id, reason)` | 取消簽核申請（限申請人本人、限進行中） |

**典型場景**：在您的部門工具裡做一個「我的待辦」面板，讓主管不必登入主控台就能完成簽核。

**重要語意**：這些方法**綁使用者身分**。`approve` 會驗證觸發者是否為該關卡的合格審核人，不是就拒絕。最後一關通過時會自動執行被攔截的原操作。

**授權**：讀取需 `approval.read`（低風險），決定需 `approval.decide`（高風險）。

---

## `ctx.knowledge` — 企業知識檢索

| 方法 | 用途 |
|---|---|
| `search(query, top_k, score_threshold)` | 向量檢索，回傳片段與相關度分數 |
| `get_content(file_id)` | 取單一知識檔案的完整解析文字 |

**典型場景**：做一個內部問答助理。檢索企業規章與產品文件取得脈絡，再用您自己的模型金鑰產生回答。

**設計要點**：這是**純檢索、不生成**——不呼叫任何語言模型，回傳原文片段。生成留給您自己的邏輯與金鑰，成本與模型選擇由您掌控。檢索結果自動套用檔案級存取政策（見第 6 章）。

**授權**：`knowledge.read`，高風險等級。

---

## `ctx.http` — 呼叫外部 API

| 方法 | 用途 |
|---|---|
| `call(service, path, method, body, headers, params)` | 透過已授權的外部服務呼叫 API |
| `fetch(url, ...)` | 抓取任意公開網址（仍受安全限制） |

**典型場景**：串接物流查詢、簡訊網關、發票加值中心、您公司既有的內部系統。

**兩個容易踩到的地方**：

1. **第三個位置參數是 `method`（字串），不是 body**。要送 body 請用具名參數。
2. **`call` 不拋例外**，回傳 `{status, headers, data}`——請務必檢查 `status`。失敗時 `data` 會帶 `error_type`、`error` 與 `fix`（一句可直接轉述給使用者的修復指引）。

```python
resp = ctx.http.call('logistics', '/track', method='POST',
                     body={'no': ctx.params['tracking_no']})
if resp['status'] != 200:
    return ctx.response.json({'error': resp['data'].get('fix')})
```

**授權**：`http`，高風險等級，且外部網域須經白名單授權。

---

## `ctx.messaging` — 通訊中心

| 方法 | 用途 |
|---|---|
| `list_channels()` / `add_channel()` / `update_channel()` / `remove_channel()` | 管理通訊渠道 |
| `inject_inbound()` | 注入外部進來的訊息 |
| `save_ai_outbound()` | 儲存 AI 產生的回覆 |
| `get_ai_config()` | 讀取 AI 回覆設定 |

**典型場景**：在您的應用裡做一個客服對話介面，把外部渠道（如通訊軟體）的訊息接進來，與 CRM 客戶資料綁定，讓營運同仁在同一個畫面內回覆。

**授權**：讀取需 `messaging.read`（低風險），寫入需 `messaging.write`，渠道管理需 `messaging.channel`（均為高風險）。

---

## `ctx.secrets` — 金鑰保管

| 方法 | 用途 |
|---|---|
| `get(key_name)` | 取得金鑰值 |
| `list_keys()` | 列出可用的金鑰名稱 |

**典型場景**：您的應用需要呼叫第三方服務或自己的模型 API。金鑰存放在 App Secrets 中，**不會出現在原始碼裡，也不會傳到前端**。

**授權**：`secret.read`，高風險等級。

---

## `ctx.crypto` — 加解密與簽章

| 方法 | 用途 |
|---|---|
| `hash(algorithm, data)` | 雜湊（sha256 等） |
| `hmac_sign(key_name, data)` | HMAC 簽章（金鑰名而非金鑰值） |
| `base64_encode(data)` / `base64_decode(data)` | Base64 編解碼 |
| `aes_encrypt(key_name, plaintext)` | AES-256 加密 |
| `aes_decrypt(key_name, ciphertext, iv)` | AES-256 解密 |

**典型場景**：驗證 Webhook 來源的簽章、產生對外 API 需要的簽名、加密儲存敏感欄位。

注意 `hmac_sign` 與 AES 方法接受的是**金鑰名稱**而不是金鑰值——實際的金鑰值永遠不經過您的程式碼。

**授權**：`crypto`，低風險等級。

---

## `ctx.mcp` — 外部工具協定

| 方法 | 用途 |
|---|---|
| `execute(task, wait=True)` | 同步執行 MCP 任務 |
| `trigger(task)` | 非同步觸發，回傳任務識別碼 |
| `get_status(task_id)` | 查詢非同步任務狀態 |

**授權**：`mcp`，高風險等級。

---

## `ctx.response` 與 `ctx.csv` — 回應控制

| 方法 | 用途 |
|---|---|
| `ctx.response.json(data)` | 回傳 JSON |
| `ctx.response.file(content, filename, mime)` | 回傳檔案下載 |
| `ctx.csv.export(rows, columns, filename)` | 一行匯出 CSV |

這兩個模組在執行環境本地處理，不需要 scope 授權。

---

## 前端 SDK

前端有六支平台提供的 TypeScript SDK，放在 `src/` 底下，開箱即用。

### `src/db.ts` — ERP 表存取

在前端直接查詢與寫入已引用的 ERP 表，語意與 `ctx.db` 對應。適合列表頁、詳情頁這類直接的資料呈現。

### `src/api.ts` — 自建表存取

存取組織的自建表。同樣支援過濾、排序、分頁。

### `src/action.ts` — 呼叫伺服器端 Action

前端呼叫 Action 的官方管道。凡是需要金鑰、需要高權限、或不該讓使用者看到邏輯的操作，都應該放進 Action 再由這裡呼叫。

```ts
import { callAction } from './action';

const result = await callAction('confirm_orders', { ids: selectedIds });
```

### `src/approval.ts` — 簽核（Internal 專屬）

取得待簽核清單、查詢簽核狀態、執行核准與駁回。可以直接組出簽核面板。

### `src/user.ts` — 使用者脈絡（Internal 專屬）

取得當前使用者的角色與權限標籤，用來決定介面上顯示什麼：

```ts
import { getUser } from './user';

const user = await getUser();
if (user.permissions.includes('accounting.write')) {
  // 顯示過帳按鈕
}
```

**注意**：前端的權限判斷是**體驗優化**，不是安全邊界。真正的授權在伺服器端執行——前端藏起來的按鈕，直接呼叫 API 一樣會被擋。

### `src/auth.ts` — 登入註冊（External 專屬）

External App 的使用者註冊、登入、登出與密碼修改流程。

---

## 授權模型一覽

每個 SDK 方法都對應一個 **scope**（能力群）。應用程式必須宣告需要哪些 scope，由管理員核可後才生效。

| 風險等級 | Scope | 核可方式 |
|---|---|---|
| **低風險** | `db.read`、`data_table.read`、`messaging.read`、`approval.read`、`crypto` | 管理員核可 |
| **高風險** | `db.write`、`data_table.write`、`erp.*`、`approval.decide`、`approval.cancel`、`knowledge.read`、`messaging.write`、`messaging.channel`、`http`、`mcp`、`secret.read` | 管理員核可 **＋ 擁有者當場密碼再驗證** |

Scope 是**能力群**的開關；細粒度的邊界另有其他機制——ERP 表看引用宣告、外部服務看網域白名單、金鑰看可用清單。兩層疊加。

每一次 SDK 呼叫都會留下稽核紀錄。詳見第 10 章。