← 全部文章
應用搭建 開發者 已釋出 · · 作者 ObjectStack Team

從需求到可審查應用:AI 如何生成 ObjectStack 後設資料

用裝置報修場景拆開 AI Builder 的生成過程:物件、欄位、關係、檢視、許可權、動作、流程、API 和 agent 工具如何由同一份後設資料驅動。

從需求到可審查應用:AI 如何生成 ObjectStack 後設資料
  • AI Builder
  • 應用搭建
  • 後設資料
  • 物件建模

先給結論:用裝置報修場景走一遍——物件、欄位、檢視、許可權、動作、流程、API 和 agent 工具都來自同一份後設資料;這就是“生成可審查應用”和“一次性甩出程式碼”的根本區別。

你對 AI Builder 說一句話:

幫我做一個裝置報修系統:員工能提交故障,系統能關聯裝置、分派工程師、跟蹤狀態、計算停機時間,高優先順序自動派單,關閉工單前要填寫維修結果和成本。

AI Builder 生成的第一版不只是頁面,也有物件、欄位、關係、許可權、檢視、流程、動作、API 和 agent 工具。人要 review 的不是一堆散落實現,而是一份能被執行時校驗的業務系統規格。

這篇不泛講“AI 生成應用”,而是用這個具體業務場景拆開看:ObjectStack 後設資料到底生成了什麼,為什麼它比一次性程式碼生成更適合要審查、要許可權、要審計的企業應用。

從需求到應用的生成流程

業務場景先說清楚

裝置報修看起來簡單,實際包含一條完整業務鏈:

  1. 一線員工發現裝置異常,提交報修;
  2. 系統根據裝置、位置、優先順序和班組分派工程師;
  3. 工程師接單、到場、維修、補充照片和備註;
  4. 主管檢視超時、停機時間和成本;
  5. 高風險或高成本工單進入審批;
  6. 工單關閉後形成裝置維修歷史。

如果用傳統方式做,這會散落在資料表、API、頁面、許可權、狀態機、通知、審計和報表裡。

ObjectStack 的核心思路是把這些東西先描述成後設資料。AI Builder 的任務不是憑空寫一堆膠水程式碼,而是先起草一份業務系統規格。

業務問題後設資料能力
裝置、工單、工程師是什麼物件與關係
哪些欄位必填、可選、列舉欄位型別與校驗
員工、工程師、主管看到什麼許可權集與欄位級許可權
列表、看板、詳情如何展示檢視後設資料
派單、升級、關閉如何執行動作與流程
AI agent 能查詢和操作什麼受控工具與審計

先建物件,而不是先畫頁面

AI Builder 第一步應該拆業務物件:

  • device:裝置臺賬;
  • repair_order:報修工單;
  • repair_comment:維修備註和現場記錄;
  • user:員工、工程師、主管複用現有使用者物件;
  • team:班組或維修隊。

真正的應用從物件開始,因為物件會同時影響 API、UI、許可權、流程和 agent 工具。

下面是簡化後的裝置物件:

import { ObjectSchema, Field } from '@objectstack/spec/data';

export const Device = ObjectSchema.create({
  name: 'device',
  label: '裝置',
  fields: {
    name: Field.text({ label: '裝置名稱', required: true }),
    code: Field.text({ label: '裝置編號', required: true, unique: true }),
    location: Field.text({ label: '所在位置' }),
    team: Field.lookup('team', { label: '負責班組' }),
    status: Field.select({
      label: '裝置狀態',
      options: [
        { label: '執行中', value: 'running', default: true },
        { label: '維修中', value: 'maintenance' },
        { label: '停用', value: 'disabled' },
      ],
    }),
  },
});

注意這裡已經不是“表單欄位”這麼簡單。team 是關係,status 是列舉,code 是唯一約束。這些資訊後面會被 API、頁面、篩選、許可權和 agent 一起使用。

工單物件承載業務規則

報修工單是業務主物件。它不僅記錄文本,還要表達狀態、優先順序、關係、時間和成本。

export const RepairOrder = ObjectSchema.create({
  name: 'repair_order',
  label: '報修工單',
  fields: {
    title: Field.text({ label: '故障描述', required: true }),
    device: Field.lookup('device', { label: '裝置', required: true }),
    reporter: Field.lookup('user', { label: '報修人', required: true }),
    assignee: Field.lookup('user', { label: '工程師' }),
    priority: Field.select({
      label: '優先順序',
      options: [
        { label: '低', value: 'low' },
        { label: '中', value: 'medium', default: true },
        { label: '高', value: 'high' },
      ],
    }),
    status: Field.select({
      label: '狀態',
      options: [
        { label: '待派單', value: 'pending', default: true },
        { label: '維修中', value: 'in_repair' },
        { label: '待驗收', value: 'waiting_acceptance' },
        { label: '已關閉', value: 'closed' },
      ],
    }),
    reported_at: Field.datetime({ label: '報修時間', required: true }),
    started_at: Field.datetime({ label: '開始維修時間' }),
    closed_at: Field.datetime({ label: '關閉時間' }),
    cost: Field.currency({ label: '維修成本' }),
    photos: Field.image({ label: '現場照片', multiple: true }),
  },
});

這些欄位會帶來幾種派生能力:

  • lookup 讓工單和裝置、使用者建立關係;
  • select 讓狀態可以用於篩選、看板和流程判斷;
  • datetime 讓 SLA、停機時間和超時提醒可以被計算;
  • currency 讓成本欄位可以做欄位級許可權和審批條件;
  • image 讓現場照片自動進入表單、詳情頁和檔案許可權體系。

公式和校驗也應該是後設資料

裝置報修常見的指標是停機時間。它不一定需要落庫,可以用公式欄位表達:

import { cel } from '@objectstack/spec';

downtime_hours: Field.formula({
  label: '停機時長',
  expression: cel`
    closed_at == null || reported_at == null
      ? null
      : hours_between(reported_at, closed_at)
  `,
});

關閉工單前,也可以要求填寫維修結果:

resolution: Field.textarea({
  label: '維修結果',
  requiredWhen: cel`status == "closed"`,
});

這類規則如果寫在頁面裡,API、agent 和批次操作可能繞過去。寫成後設資料後,校驗會成為執行時的一部分。

檢視後設資料決定使用者看到什麼

企業應用不是隻有一張列表。報修系統至少需要三類檢視:

  • 員工看“我提交的工單”;
  • 工程師看“分派給我的工單”;
  • 主管看“全部工單、超時工單、高成本工單”。

這些可以由檢視後設資料描述:

export const EngineerQueueView = {
  object: 'repair_order',
  label: '我的維修佇列',
  type: 'list',
  filter: cel`assignee == $currentUser && status != "closed"`,
  columns: ['title', 'device', 'priority', 'status', 'reported_at'],
  sort: [{ field: 'priority', direction: 'desc' }, { field: 'reported_at', direction: 'asc' }],
};

export const RepairBoardView = {
  object: 'repair_order',
  label: '維修看板',
  type: 'kanban',
  groupBy: 'status',
  cardFields: ['title', 'device', 'assignee', 'priority'],
};

檢視不是純前端配置。它定義了使用者如何掃描業務,也影響 agent 如何向用戶展示結果。例如 agent 回答“哪些高優先順序工單還沒處理”時,可以複用同樣的物件、欄位和篩選語義。

許可權不是最後補的

同一個 repair_order,不同角色邊界完全不同:

  • 報修人只能建立和檢視自己的工單;
  • 工程師可以更新維修狀態和備註,但不能看維修成本;
  • 主管可以分派工程師、檢視成本、關閉異常工單;
  • 財務可以看成本,但不一定能改維修狀態。

所以許可權也必須進入後設資料:

export const EngineerPermission = {
  role: 'maintenance_engineer',
  object: 'repair_order',
  readable: cel`assignee == $currentUser`,
  editable: cel`assignee == $currentUser && status != "closed"`,
  fields: {
    cost: { readable: false, editable: false },
    resolution: { readable: true, editable: true },
    photos: { readable: true, editable: true },
  },
  actions: {
    start_repair: true,
    submit_acceptance: true,
    close_order: false,
  },
};

這段後設資料會影響 UI、API 和 agent。工程師在頁面上看不到成本,通過 API 也讀不到成本,agent 以工程師身份查詢時同樣拿不到成本。

這就是企業級 AI 應用必須強調許可權的原因:agent 不能比使用者擁有更多業務權力。

動作讓業務行為可控

“開始維修”“提交驗收”“關閉工單”不是普通欄位更新,而是業務動作。動作可以定義輸入、前置條件、許可權和審計。

export const StartRepairAction = {
  name: 'start_repair',
  label: '開始維修',
  object: 'repair_order',
  availableWhen: cel`status == "pending" && assignee == $currentUser`,
  input: {
    started_at: Field.datetime({ label: '開始時間', default: 'now' }),
  },
  changes: {
    status: 'in_repair',
    started_at: '$input.started_at',
  },
  audit: true,
};

當動作被後設資料化,三件事會變得清楚:

  • 誰能看到這個按鈕;
  • 呼叫動作前要滿足什麼條件;
  • 執行後哪些欄位會變化,審計如何記錄。

agent 呼叫的也應該是這種動作,而不是直接發一個任意 PATCH 請求。

流程把自動化和審批連起來

高優先順序自動派單可以寫成流程:

export const AutoAssignHighPriorityRepair = {
  name: 'auto_assign_high_priority_repair',
  trigger: {
    object: 'repair_order',
    event: 'afterInsert',
    when: cel`priority == "high" && assignee == null`,
  },
  steps: [
    { action: 'find_on_duty_engineer', output: 'engineer' },
    { action: 'assign_repair_order', input: { assignee: '$engineer.id' } },
    { action: 'notify_user', input: { user: '$engineer.id' } },
  ],
};

高成本關閉則應該進入審批:

export const HighCostCloseApproval = {
  object: 'repair_order',
  action: 'close_order',
  when: cel`cost > 5000`,
  approvers: ['maintenance_manager'],
  reason: '高成本維修需要主管審批',
};

這樣 AI 可以建議流程,也可以觸發低風險動作;但高風險動作仍然被審批和審計攔住。

API 和 agent 工具來自同一份後設資料

物件定義完成後,平臺可以投影出 API:

curl -X POST /api/v1/data/repair_order \
  -d '{ "title": "3 號機床異響", "device": "dev_012", "priority": "high" }'

也可以投影出 agent 工具:

export const RepairAgentTools = [
  tool.queryRecords('repair_order'),
  tool.getRecord('repair_order'),
  tool.runAction('repair_order', 'start_repair'),
  tool.runAction('repair_order', 'submit_acceptance'),
];

於是使用者可以問:

幫我找出今天還沒開始維修的高優先順序工單,並說明可能影響哪些裝置。

agent 不需要猜資料庫結構。它通過受控工具查詢 repair_order,展開關聯的 device,遵守當前使用者許可權,然後把結果總結給使用者。

如果使用者繼續說“把第一條工單派給今天值班工程師”,agent 呼叫的是 assign_repair_order 動作;如果成本過高或許可權不足,執行時會拒絕或進入審批。

這和一次性程式碼生成的區別

一次性程式碼生成的結果通常是很多檔案:頁面、API、資料庫、許可權判斷、指令碼。第一版看起來快,但後續需求變化會讓程式碼逐漸分叉。

ObjectStack 後設資料的價值在於:業務結構只有一個源頭

  • 物件欄位變了,API、表單、詳情頁和 agent 工具一起變;
  • 許可權變了,UI、API 和 agent 都遵守同一套規則;
  • 動作變了,按鈕、流程、審計和工具呼叫都跟著變;
  • 檢視變了,人和 agent 對業務佇列的理解也同步變化。

AI Builder 不是替你繞過軟體工程,而是把軟體工程裡最重要的結構先起草出來,讓人可以稽核,讓平臺可以執行,讓後續變化繼續落在同一份規格上。

從一句話到應用,真正發生了什麼

用裝置報修這個場景看,中間發生的是:

  1. 自然語言被拆成真實業務物件;
  2. 物件、欄位、關係、公式和校驗進入後設資料;
  3. 檢視、許可權、動作和流程補齊業務邊界;
  4. 平臺把後設資料投影成 API、介面和 agent 工具;
  5. AI 在許可權內查詢和建議,高風險動作進入審批;
  6. 人 review 一份小 diff 後繼續迭代同一份規格。

這才是 AI-native 應用平臺真正有價值的地方:不是讓 AI 一次性寫出一堆程式碼,而是讓 AI 和人一起維護一套可治理、可演進、能進入生產的業務系統。