對接現有系統

保留在跑的系統:即時讀取、同步進來,或者對它執行動作。

大部分業務早就跑在某個資料庫、ERP 或工單系統裡,沒有人會去重寫它。把它納入同一份定義有三條路:聯邦接入,資料留在原處,每次讀取都是即時的;單向同步,由作業把資料單向複製成一個普通物件,成員能讀、不能改;通過宣告的動作改動源系統,寫入發往源頭,下一次拉取再把變化帶回來。本頁講怎麼選——寫給做決定的人,也寫給編寫繫結的 Agent。

ObjectOS product surface connecting business data, applications, and AI agents
AI 編寫中繼資料 物件、權限、流程、工具
人 審閱 diff 業務權限、資料訪問、審批
執行環境 執行策略 UI、API、審計、MCP、動作
3 條路
聯邦接入、即時讀取;單向同步;或通過宣告的動作改動源系統
403
通過資料 API 編輯、新建或刪除同步行,一律得到這個答覆——拉取是它唯一的寫入方
1 條執行記錄
每次拉取在 sys_sync_run 上留一條:讀取、新建、更新、拒收的行數,以及到達的位置

完整的繫結

對映決定什麼落到哪裡,作業決定什麼時候。

這是同步的一半,取自在當前版本腳手架上實際執行的配置:一個現有 SQLite 資料庫裡的聯邦表,每 20 秒複製進一個標記為 synced 的本地物件。第一次執行複製了 25 行;源頭改了一行、新增一行之後,下一次執行從上一次提交的位置讀了 4 行,更新 3 行、新建 1 行。源鍵對映到 id,水位欄位只增不減。

// 副本:一個普通物件,對成員只讀。
export const OrderCopy = ObjectSchema.create({
  name: 'app_order_copy',
  managedBy: 'synced',
  sharingModel: 'public_read',  // 拉取來的行沒有個人所有者
  fields: { order_no: Field.text(), status: Field.text(), /* … */ },
});

// 什麼落到哪裡:從聯邦物件分視窗讀取。
export const OrdersPull = defineMapping({
  name: 'orders_pull',
  targetObject: 'app_order_copy',
  mode: 'upsert',
  upsertKey: ['order_no'],
  fieldMapping: [{ source: 'id', target: 'order_no' }, /* … */],
  datasourceSource: {
    object: 'app_legacy_order',  // external.columnMap: { order_no: 'id' }
    watermark: { field: 'updated_at', start: '2020-01-01T00:00:00.000Z' },
  },
});

// 什麼時候:每次執行都從上次提交的位置接著讀。
export const OrdersPullJob = defineJob({
  name: 'orders_pull_job',
  schedule: { type: 'interval', intervalMs: 20000 },
  pull: { mapping: 'orders_pull' },
});

三條路

即時讀、複製進來,還是執行動作

要問的不是買哪個聯結器,而是複製會不會出錯。當複製會出錯時用聯邦:資料是按請求現算的、不允許落地的,或者變化快到同步跟不上。當複製只是更方便時就同步進來:報表、和自己的物件關聯、對資料提問、源系統又慢又脆弱。需要改動源系統裡的東西時,用動作。

資料留在原處

聯邦接入

把源資料庫或 OData 服務宣告為外部資料來源,把它的表繫結成物件。資料留在源頭,每次讀取都即時轉發過去。預設只讀。

資料被複製

單向同步

由作業把對映的來源——REST 或 OpenAPI 聯結器,或者一個聯邦物件——拉進一個標記為 managedBy: 'synced' 的普通物件。成員像讀任何物件一樣讀它,但不能編輯。每次執行都留下記錄。

改動源系統

通過動作寫回

一個宣告的動作通過聯結器、用聯結器自己的憑據呼叫源系統。本地副本不被編輯,下一次拉取把變化帶回來。沒有雙向同步。

指南

舊系統現代化,一次一個領域 

支柱指南:記錄系統留在原處,新的流程、介面和 Agent 在它周圍逐步長出來。

聯邦接入

資料留在原處,即時讀取

聯邦讀取一個平台並不擁有的成熟資料庫,走的是和原生物件相同的查詢引擎、REST 介面和權限檢查。ObjectStack 從不對它執行 DDL。

能接什麼

內建 SQL 驅動接 Postgres、MySQL 和 SQLite,Oracle 與 SQL Server 僅用於聯邦;內建 OData 驅動接 SAP S/4HANA、Dynamics 365 等 OData v4 與 v2 服務。

預設只讀

寫入需要兩處同時開啟:資料來源上的 allowWrites 和物件上的 writable。任何一處關閉,新增、修改、刪除都會被拒絕,返回 403 EXTERNAL_WRITE_FORBIDDEN。

報表直接彙總遠端表

基於聯邦物件的儀表盤和報表,會通過驅動自己的表解析,彙總到正確的遠端表和列上。

設計上的邊界

不支援跨資料來源關聯。經外掛驅動(包括 OData)讀取時,命中行數超過行數上限——預設 1,000,最多 10,000——的讀取會被拒絕,而不是隻返回一部分;按父記錄權限限定範圍的讀取也會被拒絕。源系統宕機時返回 503,絕不返回空列表。

單向同步

把資料複製成成員能讀、不能改的物件

同步宣告在目標上。一個 upsert 模式的對映說明資料從哪來、拉來的行如何匹配已存的行;一個 pull 指向該對映的作業說明什麼時候拉。複製進來之後它就是普通物件:每種查詢運算、報表和權限規則都適用,讀取不會碰到源頭。

兩種來源

connectorSource 讀取 REST 或 OpenAPI 聯結器,每次執行讀一個響應。datasourceSource 按水位欄位分視窗讀取聯邦物件,每次執行都從上一次提交的位置接著讀。

除了拉取,誰都不能寫

同步物件不開放新建、匯入、編輯或刪除。通過資料 API 編輯、新建或刪除都會被拒絕,返回 403——管理員也一樣——userActions 也打不開寫操作。CSV 匯出仍然可用。

每次執行都有記錄

每次拉取在 sys_sync_run 留一行:對映、驅動它的作業執行、讀取/新建/更新/拒收的行數、從哪裡開始讀、提交到哪個位置,以及結束狀態。記錄保留 30 天,持有各對映讀取位置的那一行除外。

權限從零配置

源系統的權限不會隨資料一起過來。拉取來的行沒有個人所有者,所以物件的共享模型和授權要在本地編寫;os validate 建議用 public_read,或者用 private 加一條授予讀取權限的共享規則。

寫回

通過宣告的動作改動源系統,下一次拉取把變化帶回來

對源資料的改動在源頭完成。執行改動的動作是宣告式中繼資料:在原始碼裡,它以 diff 的形式交到人手上;在 ObjectOS Cloud 上,對已上線且已有記錄的應用所做的變更會存為草稿,由人來發布。它和其他動作走同一個動作入口,並用聯結器自己的憑據呼叫源系統——Agent 從不拿到資料庫賬號。

宣告的動作呼叫源系統

一個 type 為 flow 的動作啟動流程,流程裡的 connector_action 節點把改動發往源系統。實測:動作向源系統發出了 PATCH /tickets/T-2,此時本地那一行仍是 open。

下一次拉取完成對賬

到了下一次定時拉取,作業重新讀取源頭,本地那一行變成了 closed。副本只在拉取寫入時才改變,源頭始終是記錄系統。

沒有雙向同步

不自動寫回、不做衝突合併、不在副本上疊加編輯層。被拒絕的編輯會明確告訴使用者:請通過宣告的動作改動源頭。

開發中

尚未包含在當前版本中

基於同一個同步核心開發。各項依據公開的設計記錄 ADR-0153 描述,兩項 Enterprise 能力依據 objectstack#31763 上的版本劃分。

開發中

標記源頭的刪除

源頭已經沒有的行會被標記為「源頭已刪除」,行回來時標記清除;拉取從不物理刪除任何行。deletePolicy 和 deletedField 兩個鍵已經宣告,目前還不改變任何行為。

開發中

每一行的來源資訊

每個同步行上的平台列:寫入它的對映、它在源頭的鍵、最近一次被拉取寫入的時間,以及對應的執行。_sync_ 字首已經為它們預留。

開發中

聯結器拉取的分頁

宣告分頁約定——頁碼、游標或偏移——讓聯結器拉取讀完每一頁,而不是隻讀一個響應。

開發中

Studio 同步嚮導

在資料來源頁面建立同步物件、對映和拉取作業,並設定共享模型、頻率,檢視執行歷史;目前拉取作業在程式碼裡宣告。

開發中

資料倉儲驅動

Snowflake 和 BigQuery 作為外掛驅動包,讓資料倉儲的表用自己的方言成為拉取來源。

開發中

同步指南

一份指南和配套的 Agent 技能,講清三條路的選擇規則、寫回的答案,以及對映與作業的寫法。

開發中 · Enterprise

記錄級血緣

逐條記錄地說明每條資料從哪來、又流向了哪裡。

開發中 · Enterprise

基於標籤的訪問控制

由資料上的標籤決定訪問,並對資料的使用目的加以限制。

決策表

聯邦還是同步,逐項對比

問題聯邦接入單向同步
即時還是複製?即時:每次讀取都發往源系統按作業的頻率複製;每次執行從上次提交的位置接著讀
關聯與報表報表直接彙總遠端表;不支援跨資料來源關聯資料在平台自己的資料庫裡,篩選、彙總和報表都在本地執行
大批次讀取經外掛驅動(包括 OData)讀取時,超過行數上限(預設 1,000,最多 10,000)會被拒絕內建 SQL 來源分視窗讀取,沒有行數上限
Agent 對資料提問每個問題都是一次即時查詢,受源系統速度與上限約束問題查詢本地副本,不觸碰源系統
權限在 ObjectStack 裡設定在物件上,和任何物件一樣在本地從零配置:源系統的權限不會隨資料過來
寫回預設關閉;資料來源和物件兩處都開啟才能寫成員不能編輯副本;宣告的動作改動源頭,下一次拉取把變化帶回來
源系統宕機時讀取返回 503,絕不返回空列表副本照常可用;下一次執行補上

評審清單

讓 Agent 寫繫結之前,先決定

  • 複製會不會出錯——現算的、不能落地的、要求即時的,就用聯邦。
  • 誰能讀副本:編寫它的共享模型和授權,源頭什麼都不會帶過來。
  • 哪一列對映到 id,哪個水位欄位只增不減。
  • 哪些動作可以改動源頭,誰可以執行它們。
  • 拉取作業在哪個部署上執行,並且該部署開啟了包內定時任務。

FAQ

常見問題

這是雙向同步嗎?

不是。同步是單向的:拉取是同步物件唯一的寫入方。對源頭的改動通過呼叫源系統的宣告式動作完成,下一次拉取把變化帶回來。沒有衝突合併,也沒有編輯疊加層。

源系統的權限會隨資料一起過來嗎?

不會。同步物件的權限在本地從零配置。它的行沒有個人所有者,按所有者限定的共享模型會讓所有成員都看不到:請編寫 public_read,或者 private 加一條授予讀取權限的共享規則,再把物件授權給應當看到它的角色。

副本里的值錯了,能直接改嗎?

不能通過資料 API 改:編輯、新建或刪除同步行都會被拒絕,返回 403 PERMISSION_DENIED,管理員也一樣,提示資訊會讓你通過宣告的動作改動源頭。本地編輯會被下一次拉取悄無聲息地保留或覆蓋,這正是這類物件拒絕它的原因。

ObjectStack 會在資料落地前做轉換或關聯嗎?

不會。這裡不做資料管道與加工:跨來源的關聯、清洗和彙總是資料倉儲或 ETL 廠商的工作,它們是合作伙伴,ObjectStack 把結果同步進來。對映裡的逐欄位 transform 一次只轉換一個值,不會長成管道。

拉取作業需要什麼才能執行?

一個只有一個來源、upsert 模式且帶 upsertKey 的對映,目標是宣告為 managedBy: 'synced' 的物件;再加一個 pull 指向它、在程式碼裡宣告的作業。os validate 會拒絕指向不存在的對映或沒有來源的對映的 pull。部署只有在設定 OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true 之後才執行包內宣告的作業,預設關閉。

ObjectOS 在其中是什麼角色?

聯邦接入、單向同步和聯結器動作都屬於開源的 ObjectStack 執行環境,Apache-2.0。為了執行它,ObjectStack 倉庫提供 ObjectOS Community —— ghcr.io/objectstack-ai/objectstack 映像、os start 和 Console,免費且自託管 —— 而 ObjectOS Cloud 是託管版本,ObjectOS Enterprise 是自管理、需許可的版本。ObjectOS 有三個版本:ObjectOS Community,開源、可免費自託管;ObjectOS Cloud,託管在瀏覽器中、無需安裝;ObjectOS Enterprise,自管部署在你自己的基礎設施上。你的本體是普通的 ObjectStack 中繼資料。從 ObjectOS Cloud 或 ObjectOS Enterprise 匯出本體、在開源的 ObjectStack 執行環境上執行,目前尚在計劃中。

下一步

繼續完善你的評估材料。