From b5600d6c0e1cc80d828425d8534b268e21865267 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 3 Sep 2026 02:37:18 +0000 Subject: [PATCH 1/2] =?UTF-8?q?gen-zh-hant:=20ship=20=E6=AC=8A=E9=99=90/?= =?UTF-8?q?=E5=AF=A6=E4=BE=8B=20and=20the=20straddled=20locative=20?= =?UTF-8?q?=E8=A3=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generator converts zh-Hans to zh-Hant with OpenCC's `s2twp`. Two of that preset's 603 phrase entries are wrong for this corpus, and one segmentation accident pins a locative: 权限 -> 許可權 a Microsoft-glossary rendering; 權限 is the ordinary term 实例 -> 例項 not standard Taiwanese usage in any register X里 straddling STPhrases matches pin the locative 里 as 里 Keep the preset — its other 142 firing entries (資料, 程式, 物件, 介面, 伺服器, 軟體, 資訊, 快取, 使用者, 預設 …) are all correct, and plain `tw` would lose every one of them. Instead put identity entries at the head of the TWPhrases group, which disables exactly those two rules and nothing beneath them; a genuine 许可权 in a source still converts to 許可權 on its own terms. The locative is a different defect: STCharacters already reads a bare 里 as 裏/裡, and 541 of 553 come out right unaided. The twelve that do not are all a two-character STPhrases entry (本里, 里根, 里拉, 道里, 里加, 里长, 数里) matching across a word boundary. Those entries are correct in their own right, so the repair is a whitelist applied after conversion, behind a listed word only, guarded so 里程碑 is never touched. Both are pinned in the generator's fixture, which runs on every dev and build, so a preset upgrade cannot silently put 許可權 back in 435 places. A new unclaimed 里 is reported rather than guessed at. Regenerated: 許可權 435 -> 0, 權限 0 -> 435 (the exact count of 权限 in the Simplified sources), 例項 2 -> 0, 實例 0 -> 2, 裡 541 -> 553. The 8 links #187 pointed at /zh-Hant/ are unchanged. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr --- .../index.zh-Hant.mdx | 48 ++-- .../blog/ai-agent-workbench/index.zh-Hant.mdx | 22 +- .../ai-compliance-control/index.zh-Hant.mdx | 12 +- .../ai-content-workbench/index.zh-Hant.mdx | 2 +- .../index.zh-Hant.mdx | 24 +- .../blog/ai-expense-audit/index.zh-Hant.mdx | 4 +- .../index.zh-Hant.mdx | 32 +-- .../index.zh-Hant.mdx | 4 +- .../blog/ai-sales-assistant/index.zh-Hant.mdx | 14 +- content/blog/ai-ticket-hub/index.zh-Hant.mdx | 22 +- .../index.zh-Hant.mdx | 8 +- .../index.zh-Hant.mdx | 18 +- .../index.zh-Hant.mdx | 20 +- .../index.zh-Hant.mdx | 4 +- .../index.zh-Hant.mdx | 10 +- .../index.zh-Hant.mdx | 2 +- .../index.zh-Hant.mdx | 2 +- .../index.zh-Hant.mdx | 12 +- .../index.zh-Hant.mdx | 14 +- .../index.zh-Hant.mdx | 32 +-- .../index.zh-Hant.mdx | 26 +-- .../index.zh-Hant.mdx | 4 +- .../index.zh-Hant.mdx | 6 +- .../eu-ai-act-runtime-audit/index.zh-Hant.mdx | 18 +- .../index.zh-Hant.mdx | 18 +- .../index.zh-Hant.mdx | 36 +-- .../from-requirement-to-app/index.zh-Hant.mdx | 40 ++-- .../index.zh-Hant.mdx | 22 +- .../index.zh-Hant.mdx | 2 +- .../index.zh-Hant.mdx | 28 +-- .../index.zh-Hant.mdx | 12 +- .../mcp-governed-tool-layer/index.zh-Hant.mdx | 36 +-- .../index.zh-Hant.mdx | 26 +-- .../index.zh-Hant.mdx | 16 +- .../objectos-action-tools/index.zh-Hant.mdx | 12 +- .../index.zh-Hant.mdx | 48 ++-- .../index.zh-Hant.mdx | 10 +- .../index.zh-Hant.mdx | 24 +- .../index.zh-Hant.mdx | 30 +-- .../index.zh-Hant.mdx | 4 +- .../index.zh-Hant.mdx | 20 +- .../index.zh-Hant.mdx | 30 +-- .../why-custom-systems-die/index.zh-Hant.mdx | 10 +- scripts/gen-zh-hant.mjs | 208 ++++++++++++++++-- 44 files changed, 583 insertions(+), 409 deletions(-) diff --git a/content/blog/ai-agent-business-data-security-boundaries/index.zh-Hant.mdx b/content/blog/ai-agent-business-data-security-boundaries/index.zh-Hant.mdx index fb055dc..873df98 100644 --- a/content/blog/ai-agent-business-data-security-boundaries/index.zh-Hant.mdx +++ b/content/blog/ai-agent-business-data-security-boundaries/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. -title: AI Agent 資料安全邊界:如何在企業許可權內工作 -description: 企業不是不想讓 AI agent 使用業務資料,而是不允許它繞過身份、許可權、審批和審計。真正可上線的 agent,必須像一個受控使用者,而不是影子管理員。 +title: AI Agent 資料安全邊界:如何在企業權限內工作 +description: 企業不是不想讓 AI agent 使用業務資料,而是不允許它繞過身份、權限、審批和審計。真正可上線的 agent,必須像一個受控使用者,而不是影子管理員。 author: ObjectStack Team date: 2026-06-04 status: published @@ -12,10 +12,10 @@ industries: [] cover: ./cover.jpg tags: - AI 智慧體 - - 智慧體許可權 + - 智慧體權限 --- -**先給結論**:可上線的 AI agent 必須像一個受控使用者:繼承使用者身份,許可權落到物件、記錄、欄位和動作;先只讀再執行,高風險動作要審批可回滾,每步可審計。真正的區別是:它是受控使用者,還是影子管理員。 +**先給結論**:可上線的 AI agent 必須像一個受控使用者:繼承使用者身份,權限落到物件、記錄、欄位和動作;先只讀再執行,高風險動作要審批可回滾,每步可審計。真正的區別是:它是受控使用者,還是影子管理員。 很多企業討論 AI agent 時,第一反應是問: @@ -25,44 +25,44 @@ tags: > 它以誰的身份訪問?能看什麼?能改什麼?出問題時能不能知道它做過什麼,並立刻停下來? -如果這些問題沒有答案,agent 越聰明,風險越大。它會變成一個披著 AI 外衣的“影子管理員”:能跨系統查資料、能呼叫工具、能修改記錄,但不受任何人的崗位許可權約束。 +如果這些問題沒有答案,agent 越聰明,風險越大。它會變成一個披著 AI 外衣的“影子管理員”:能跨系統查資料、能呼叫工具、能修改記錄,但不受任何人的崗位權限約束。 -企業級 agent 的目標不是讓 AI 獲得超級許可權,而是讓它在清晰邊界內幫助使用者完成工作。 +企業級 agent 的目標不是讓 AI 獲得超級權限,而是讓它在清晰邊界內幫助使用者完成工作。 ![AI Agent 的安全邊界](./security-boundaries.webp) ## 第一層邊界:agent 必須繼承使用者身份 -agent 不應該擁有一個獨立的萬能賬號,更不應該直接拿資料庫管理員許可權。 +agent 不應該擁有一個獨立的萬能賬號,更不應該直接拿資料庫管理員權限。 它應該代表當前登入使用者行動。銷售只能看自己負責的客戶,agent 也只能看這些客戶;客服只能處理自己佇列裡的工單,agent 也只能在這個佇列內查詢和建議;工程師不能看合同金額,agent 也不能因為“需要分析”就繞過去。 這條規則看似簡單,卻決定了整個系統是否可控: - 使用者離職,agent 的訪問能力隨之消失; -- 使用者轉崗,agent 的可見範圍隨許可權變化; +- 使用者轉崗,agent 的可見範圍隨權限變化; - 使用者無權訪問的記錄、欄位和動作,agent 也無權訪問; - 審計日誌可以把每次 agent 行為關聯回真實使用者。 -不要把這件事交給提示詞。提示詞可以提醒模型“不要越權”,但真正可靠的邊界必須由執行時許可權系統強制執行。 +不要把這件事交給提示詞。提示詞可以提醒模型“不要越權”,但真正可靠的邊界必須由執行時權限系統強制執行。 -## 第二層邊界:許可權要落到物件、記錄、欄位和動作 +## 第二層邊界:權限要落到物件、記錄、欄位和動作 -企業許可權不是一句“允許訪問 CRM”就夠了。 +企業權限不是一句“允許訪問 CRM”就夠了。 一個安全的 agent 需要同時尊重四類邊界: -**物件級許可權**:使用者是否能訪問客戶、訂單、工單、合同這些物件。 +**物件級權限**:使用者是否能訪問客戶、訂單、工單、合同這些物件。 -**記錄級許可權**:使用者能訪問哪些具體記錄,例如自己的客戶、所在區域的訂單、某個團隊的工單。 +**記錄級權限**:使用者能訪問哪些具體記錄,例如自己的客戶、所在區域的訂單、某個團隊的工單。 -**欄位級許可權**:使用者能不能看合同金額、成本、身份證號、內部備註等敏感欄位。 +**欄位級權限**:使用者能不能看合同金額、成本、身份證號、內部備註等敏感欄位。 -**動作級許可權**:使用者能不能建立任務、修改階段、關閉工單、傳送報價、調整折扣、變更許可權。 +**動作級權限**:使用者能不能建立任務、修改階段、關閉工單、傳送報價、調整折扣、變更權限。 -很多 agent 專案失敗,不是模型不夠好,而是許可權模型太粗。系統只知道“這個 agent 可以查客戶”,卻不知道它不能查所有客戶,不能讀取敏感欄位,不能執行高風險動作。 +很多 agent 專案失敗,不是模型不夠好,而是權限模型太粗。系統只知道“這個 agent 可以查客戶”,卻不知道它不能查所有客戶,不能讀取敏感欄位,不能執行高風險動作。 -ObjectOS 的思路是把業務物件、欄位、動作和許可權都變成宣告式後設資料。agent 不是直接碰表,也不是直接調任意 API,而是通過受控工具在這些後設資料定義的邊界內工作。 +ObjectOS 的思路是把業務物件、欄位、動作和權限都變成宣告式後設資料。agent 不是直接碰表,也不是直接調任意 API,而是通過受控工具在這些後設資料定義的邊界內工作。 ## 第三層邊界:先只讀,再建議,再執行 @@ -76,7 +76,7 @@ ObjectOS 的思路是把業務物件、欄位、動作和許可權都變成宣 **受控執行階段**:對低風險、邊界明確、可回滾的動作,agent 可以自動執行。例如建立內部任務、更新普通狀態、補全非敏感欄位。高風險動作仍然需要審批。 -這個分層很重要。它讓企業可以逐步擴大 agent 的許可權,而不是在“完全不用”和“全自動執行”之間二選一。 +這個分層很重要。它讓企業可以逐步擴大 agent 的權限,而不是在“完全不用”和“全自動執行”之間二選一。 ## 第四層邊界:高風險動作必須審批和可回滾 @@ -86,10 +86,10 @@ ObjectOS 的思路是把業務物件、欄位、動作和許可權都變成宣 - 批次修改客戶、訂單、合同、庫存或財務資料; - 修改金額、折扣、賬期、信用額度; - 對外發送正式郵件、報價、合同或通知; -- 修改角色、許可權、組織關係; +- 修改角色、權限、組織關係; - 呼叫會產生真實成本的外部服務。 -這些動作不能只靠模型判斷“應該沒問題”。系統需要在執行前展示影響範圍、原因和差異,讓有許可權的人確認。 +這些動作不能只靠模型判斷“應該沒問題”。系統需要在執行前展示影響範圍、原因和差異,讓有權限的人確認。 同時,系統要記錄執行前後的狀態。出錯時至少能撤銷、補償或人工恢復。如果 agent 一次準備改 500 條記錄、命中敏感客戶、超過金額上限,系統應該自動剎車並升級給人。 @@ -112,14 +112,14 @@ ObjectOS 的思路是把業務物件、欄位、動作和許可權都變成宣 - 執行前後資料如何變化; - 哪些步驟失敗、越權或升級審批。 -審計不是事後甩鍋,而是讓團隊有能力逐步放寬許可權。沒有審計,企業只能保守地把 agent 關在業務系統外面。有了審計,IT 和業務團隊才能知道哪些場景已經穩定,哪些場景還需要人守著。 +審計不是事後甩鍋,而是讓團隊有能力逐步放寬權限。沒有審計,企業只能保守地把 agent 關在業務系統外面。有了審計,IT 和業務團隊才能知道哪些場景已經穩定,哪些場景還需要人守著。 ## 一個判斷標準:它是受控使用者,還是影子管理員? 評估一個企業 agent 架構,可以問 6 個問題: 1. agent 是否以真實使用者身份執行? -2. 它是否繼承物件、記錄、欄位和動作許可權? +2. 它是否繼承物件、記錄、欄位和動作權限? 3. 它是否通過受控工具訪問資料,而不是直接讀取整庫? 4. 它是否支援只讀、建議、執行的分級授權? 5. 高風險動作是否需要審批、可回滾、可剎車? @@ -131,8 +131,8 @@ ObjectOS 的思路是把業務物件、欄位、動作和許可權都變成宣 ObjectOS 預設接受一個現實:真正有價值的 AI 一定會進入業務系統。 -它需要讀客戶、訂單、工單、合同和審批;它需要理解業務物件之間的關係;它也需要在授權後推動流程。但它不能繞過企業已有的身份、許可權、審批和審計。 +它需要讀客戶、訂單、工單、合同和審批;它需要理解業務物件之間的關係;它也需要在授權後推動流程。但它不能繞過企業已有的身份、權限、審批和審計。 -所以 ObjectOS 把物件、欄位、流程、許可權和動作都放進統一後設資料層,讓 agent 通過這層結構工作。AI 能更接近真實業務,同時每一步都有身份、有邊界、有記錄。 +所以 ObjectOS 把物件、欄位、流程、權限和動作都放進統一後設資料層,讓 agent 通過這層結構工作。AI 能更接近真實業務,同時每一步都有身份、有邊界、有記錄。 企業不缺會聊天的 AI。企業缺的是能安全使用業務資料、能被授權、能被審計、能隨時停下來的 AI。 diff --git a/content/blog/ai-agent-workbench/index.zh-Hant.mdx b/content/blog/ai-agent-workbench/index.zh-Hant.mdx index 85cc86a..52233ae 100644 --- a/content/blog/ai-agent-workbench/index.zh-Hant.mdx +++ b/content/blog/ai-agent-workbench/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: AI Agent 工作臺:讓 agent 在業務系統內受控執行 -description: 企業 agent 不能只是會聊天,而要能在業務物件、工具、許可權、審批和審計邊界內執行任務。工作臺的關鍵是受控執行,而不是萬能許可權。 +description: 企業 agent 不能只是會聊天,而要能在業務物件、工具、權限、審批和審計邊界內執行任務。工作臺的關鍵是受控執行,而不是萬能權限。 author: ObjectStack Team date: 2026-06-05 status: published @@ -13,10 +13,10 @@ cover: ./cover.png tags: - 受治理的工具 - AI 智慧體 - - 智慧體許可權 + - 智慧體權限 --- -**先給結論**:企業 Agent 的關鍵不是聰明,而是能不能受控執行——把物件、工具、許可權、審批和審計做成後設資料,Agent 才能在邊界內真正辦事,而不只是會聊天。 +**先給結論**:企業 Agent 的關鍵不是聰明,而是能不能受控執行——把物件、工具、權限、審批和審計做成後設資料,Agent 才能在邊界內真正辦事,而不只是會聊天。 很多企業已經有了 AI 聊天入口,但真正的問題很快會出現:聊完以後,業務還是要人去系統裡操作。 @@ -24,7 +24,7 @@ tags: 所以企業下一步需要的,不只是聊天助手,而是可執行任務的 AI 工作臺。 -它不是讓 Agent 拿到管理員許可權到處亂跑,而是把業務物件、工具、許可權、審批和審計放在同一個執行邊界裡。 +它不是讓 Agent 拿到管理員權限到處亂跑,而是把業務物件、工具、權限、審批和審計放在同一個執行邊界裡。 你可以對平臺說: @@ -48,7 +48,7 @@ tags: 所以企業 Agent 的核心不是“模型有多聰明”,而是“它能不能在業務系統的邊界裡執行”。 -這要求 Agent 工作臺必須後設資料驅動。業務物件定義它能理解什麼,工具定義它能做什麼,許可權定義它能代表誰做,審批定義哪些動作要確認,審計定義事後如何追蹤。 +這要求 Agent 工作臺必須後設資料驅動。業務物件定義它能理解什麼,工具定義它能做什麼,權限定義它能代表誰做,審批定義哪些動作要確認,審計定義事後如何追蹤。 ## 用自然語言生成 Agent 工作臺 @@ -70,7 +70,7 @@ tags: Agent 不會直接憑空執行。它應該先: -1. 檢查使用者是否有許可權檢視企業客戶工單; +1. 檢查使用者是否有權限檢視企業客戶工單; 2. 呼叫工單查詢工具; 3. 生成候選工單列表; 4. 說明將建立哪些任務; @@ -86,7 +86,7 @@ Agent 工作臺的能力會逐步擴大。管理員可以說: > 讓銷售主管可以批次建立商機跟進任務,但不能修改商機金額和合同條款。 -平臺應生成工具許可權:允許建立任務,禁止修改金額和合同。 +平臺應生成工具權限:允許建立任務,禁止修改金額和合同。 合規負責人可以說: @@ -148,7 +148,7 @@ Agent 查詢合同條款物件,生成風險列表,發起複核審批,並 高風險動作需要審批: -- 修改金額、合同、許可權和主資料; +- 修改金額、合同、權限和主資料; - 對外發送承諾; - 批次匯出客戶資料; - 關閉合規或審計問題; @@ -172,13 +172,13 @@ Agent 工作臺不應該一開始覆蓋所有系統。更好的路徑是從一 第六,逐步跨系統擴充套件,把多個業務物件連線成更完整的執行工作臺。 -這條路徑讓企業可以先驗證價值,再擴大 Agent 的許可權。 +這條路徑讓企業可以先驗證價值,再擴大 Agent 的權限。 ## ObjectStack 的價值:把 Agent 放進業務執行時 -很多 Agent 演示看起來很強,但一到企業生產環境就卡住,因為它們沒有物件、許可權、流程和審計邊界。 +很多 Agent 演示看起來很強,但一到企業生產環境就卡住,因為它們沒有物件、權限、流程和審計邊界。 -ObjectStack 的後設資料驅動能力,讓業務系統天然可以暴露成受控工具:物件定義資料語義,許可權定義訪問範圍,流程定義動作路徑,審批定義人工關口,審計記錄每一次 Agent 行為。 +ObjectStack 的後設資料驅動能力,讓業務系統天然可以暴露成受控工具:物件定義資料語義,權限定義訪問範圍,流程定義動作路徑,審批定義人工關口,審計記錄每一次 Agent 行為。 用自然語言搭建 Agent 工作臺,本質上不是生成一個聊天機器人,而是生成一個業務執行層。 diff --git a/content/blog/ai-compliance-control/index.zh-Hant.mdx b/content/blog/ai-compliance-control/index.zh-Hant.mdx index 0236266..f372826 100644 --- a/content/blog/ai-compliance-control/index.zh-Hant.mdx +++ b/content/blog/ai-compliance-control/index.zh-Hant.mdx @@ -18,7 +18,7 @@ tags: [] 合規檢查最累的地方,常常不是不知道制度在哪裡,而是要把制度、業務記錄和證據材料對起來。 -制度裡寫著訪問許可權要定期複核,實際複核記錄在哪?合同審批要求超過一定金額必須法務確認,哪些合同有證據?資料匯出需要留痕,日誌是否完整?供應商資質要每年更新,過期材料是否整改? +制度裡寫著訪問權限要定期複核,實際複核記錄在哪?合同審批要求超過一定金額必須法務確認,哪些合同有證據?資料匯出需要留痕,日誌是否完整?供應商資質要每年更新,過期材料是否整改? 傳統合規檢查大量依賴人工翻制度、拉清單、問業務、收截圖、做表格。AI 可以改變這個過程,但前提是不能只做制度問答。 @@ -37,7 +37,7 @@ AI 內控檢查應用應該把制度條款變成控制點,把控制點關聯 第一,制度文本多,而且經常不是結構化的。很多規則寫在制度、流程、合同模板、監管要求和內部通知裡。 -第二,證據分散。審批記錄在 OA,許可權記錄在 IAM,合同在合同系統,供應商材料在採購系統,日誌在安全平臺,整改進度在表格裡。 +第二,證據分散。審批記錄在 OA,權限記錄在 IAM,合同在合同系統,供應商材料在採購系統,日誌在安全平臺,整改進度在表格裡。 AI 擅長閱讀和匹配,但它必須知道自己匹配的是什麼。制度條款、檢查項、證據、缺口、整改都需要成為物件。 @@ -57,7 +57,7 @@ AI 擅長閱讀和匹配,但它必須知道自己匹配的是什麼。制度 | `remediation_task` | 整改措施、負責人、截止時間、複核結果 | | `audit_log` | AI 分析、人工確認、審批和證據變更記錄 | -例如制度寫著“生產環境許可權應每季度複核”。AI 應該把它拆成一個 `control_item`,要求每季度檢查生產環境許可權清單和複核記錄。如果找不到最近季度的複核證據,就建立 `compliance_gap`,並生成整改任務。 +例如制度寫著“生產環境權限應每季度複核”。AI 應該把它拆成一個 `control_item`,要求每季度檢查生產環境權限清單和複核記錄。如果找不到最近季度的複核證據,就建立 `compliance_gap`,並生成整改任務。 ## 搭建後持續用語言調整檢查口徑 @@ -75,11 +75,11 @@ AI 擅長閱讀和匹配,但它必須知道自己匹配的是什麼。制度 IT 負責人可以說: -> 對低風險系統,許可權複核週期從季度改成半年;核心系統保持季度。 +> 對低風險系統,權限複核週期從季度改成半年;核心系統保持季度。 這會生成按系統等級區分的檢查頻率規則。 -自然語言搭建讓檢查口徑可以被業務和合規共同維護,而不是藏在一個難改的腳本里。 +自然語言搭建讓檢查口徑可以被業務和合規共同維護,而不是藏在一個難改的腳本裡。 ## 檢查人員如何用自然語言工作 @@ -136,7 +136,7 @@ AI 適合做: ## 第一版怎麼搭 -AI 內控檢查應用可以從一個範圍清楚的場景開始,比如許可權複核、合同審批、供應商資質或資料匯出。 +AI 內控檢查應用可以從一個範圍清楚的場景開始,比如權限複核、合同審批、供應商資質或資料匯出。 第一步,匯入制度和流程檔案,讓 AI 生成條款和控制點草稿。 diff --git a/content/blog/ai-content-workbench/index.zh-Hant.mdx b/content/blog/ai-content-workbench/index.zh-Hant.mdx index 33e66d8..56e219d 100644 --- a/content/blog/ai-content-workbench/index.zh-Hant.mdx +++ b/content/blog/ai-content-workbench/index.zh-Hant.mdx @@ -100,7 +100,7 @@ AI 可以從 `source_material` 中讀取銷售記錄、客戶問題、產品文 AI 可以返回一組選題,並說明依據: -- 最近 30 天客戶多次問到 AI Agent 許可權邊界; +- 最近 30 天客戶多次問到 AI Agent 權限邊界; - 銷售在三個商機中反饋客戶擔心私有化部署; - 現有部落格裡有 CRM 文章,但缺少審批和合同場景; - 建議寫一篇面向業務負責人的應用搭建文章。 diff --git a/content/blog/ai-employee-service-center/index.zh-Hant.mdx b/content/blog/ai-employee-service-center/index.zh-Hant.mdx index 243f77b..2afacc0 100644 --- a/content/blog/ai-employee-service-center/index.zh-Hant.mdx +++ b/content/blog/ai-employee-service-center/index.zh-Hant.mdx @@ -19,7 +19,7 @@ tags: [] 員工在公司裡辦一件小事,經常要先學會系統。 -請假去哪提?電腦壞了找誰?VPN 許可權怎麼開?差旅制度在哪?名片申請算行政還是市場?入職裝置什麼時候發?很多內部服務的問題,不是員工不願意自助,而是入口太多、流程太散、規則太難找。 +請假去哪提?電腦壞了找誰?VPN 權限怎麼開?差旅制度在哪?名片申請算行政還是市場?入職裝置什麼時候發?很多內部服務的問題,不是員工不願意自助,而是入口太多、流程太散、規則太難找。 AI 企業服務中心的目標,是把“提工單”變成“說清楚要辦什麼”。 @@ -27,11 +27,11 @@ AI 企業服務中心的目標,是把“提工單”變成“說清楚要辦 > 我下週去上海見客戶,幫我看一下差旅標準,併發起出差申請。 -系統先回答制度,再根據許可權、預算、審批和服務目錄生成申請。AI 不是一個泛泛聊天機器人,而是站在 HR、IT、行政、財務和知識庫之上的內部服務應用。 +系統先回答制度,再根據權限、預算、審批和服務目錄生成申請。AI 不是一個泛泛聊天機器人,而是站在 HR、IT、行政、財務和知識庫之上的內部服務應用。 搭建時,你可以對平臺說: -> 幫我搭建一個 AI 企業服務中心。它要覆蓋 HR、IT、行政和財務常見服務;員工可以用自然語言查詢制度、提交申請、檢視進度;AI 自動識別服務型別,補齊表單欄位,生成審批和待辦;涉及許可權開通、報銷、裝置和合同的動作必須按角色審批。 +> 幫我搭建一個 AI 企業服務中心。它要覆蓋 HR、IT、行政和財務常見服務;員工可以用自然語言查詢制度、提交申請、檢視進度;AI 自動識別服務型別,補齊表單欄位,生成審批和待辦;涉及權限開通、報銷、裝置和合同的動作必須按角色審批。 平臺生成的,是一套可執行的內部服務中心。 @@ -51,7 +51,7 @@ AI 企業服務中心的目標,是把“提工單”變成“說清楚要辦 AI 的價值,是先理解員工意圖,再把它路由到正確服務物件和流程。 -這要求平臺不能只有聊天能力,還要有服務目錄、知識庫、申請物件、許可權、審批和審計。 +這要求平臺不能只有聊天能力,還要有服務目錄、知識庫、申請物件、權限、審批和審計。 ## 用自然語言生成服務中心後設資料 @@ -64,7 +64,7 @@ AI 的價值,是先理解員工意圖,再把它路由到正確服務物件 | `knowledge_article` | 制度、FAQ、操作說明和適用範圍 | | `approval_task` | 審批節點、審批人、意見和結果 | | `fulfillment_task` | IT、HR、行政等部門的執行任務 | -| `employee_profile` | 員工部門、職級、地點、角色和許可權上下文 | +| `employee_profile` | 員工部門、職級、地點、角色和權限上下文 | 有了這些物件,員工說“幫我申請一臺新電腦”,系統才能判斷這屬於裝置申請,需要員工所在部門、預算、裝置型別、審批人和行政執行任務。 @@ -80,9 +80,9 @@ AI 的價值,是先理解員工意圖,再把它路由到正確服務物件 IT 負責人可以說: -> 生產環境許可權申請必須先由直屬主管審批,再由系統負責人審批,有效期最長 7 天。 +> 生產環境權限申請必須先由直屬主管審批,再由系統負責人審批,有效期最長 7 天。 -這會生成許可權申請欄位、審批流、有效期校驗和到期回收任務。 +這會生成權限申請欄位、審批流、有效期校驗和到期回收任務。 行政負責人可能說: @@ -101,7 +101,7 @@ IT 負責人可以說: AI 應該識別這是多個服務請求: - 郵箱開通; -- VPN 許可權申請; +- VPN 權限申請; - 財務系統賬號; - 新員工制度說明; - 可能還需要裝置和門禁檢查。 @@ -136,14 +136,14 @@ AI 可以自動做: 但以下動作必須受控: -- 開通系統許可權; +- 開通系統權限; - 修改員工主資料; - 批准請假、報銷和預算; - 發放裝置; - 訪問敏感 HR 資訊; - 關閉審計相關請求。 -每個動作都應該繼承員工身份和角色許可權。AI 不是管理員賬號,它只能在服務目錄和許可權邊界內呼叫工具。 +每個動作都應該繼承員工身份和角色權限。AI 不是管理員賬號,它只能在服務目錄和權限邊界內呼叫工具。 ## 第一版怎麼搭 @@ -151,7 +151,7 @@ AI 企業服務中心可以從四類高頻服務開始: 第一,HR 問答和請假申請。制度查詢、假期餘額、請假流程。 -第二,IT 服務。賬號、許可權、裝置、網路和故障報修。 +第二,IT 服務。賬號、權限、裝置、網路和故障報修。 第三,行政服務。辦公用品、會議室、門禁、名片和資產。 @@ -163,6 +163,6 @@ AI 企業服務中心可以從四類高頻服務開始: 很多企業會先做一個內部知識問答機器人,但員工真正想要的是“問完以後能辦成事”。 -ObjectStack 的後設資料驅動能力,讓企業可以用自然語言生成服務目錄、申請物件、知識庫、審批流和 Agent 工具。員工繼續用自然語言提問、提交、修改和追蹤,系統則負責許可權、流程和審計。 +ObjectStack 的後設資料驅動能力,讓企業可以用自然語言生成服務目錄、申請物件、知識庫、審批流和 Agent 工具。員工繼續用自然語言提問、提交、修改和追蹤,系統則負責權限、流程和審計。 員工服務從提工單變成聊天,不是把所有流程藏起來,而是讓系統先理解人的表達,再把它落到正確的業務物件和受控動作上。 diff --git a/content/blog/ai-expense-audit/index.zh-Hant.mdx b/content/blog/ai-expense-audit/index.zh-Hant.mdx index 8be3836..5f14019 100644 --- a/content/blog/ai-expense-audit/index.zh-Hant.mdx +++ b/content/blog/ai-expense-audit/index.zh-Hant.mdx @@ -24,7 +24,7 @@ tags: [] 你可以對平臺說: -> 幫我搭建一個 AI 報銷稽核應用。員工上傳發票、行程單和付款憑證後,AI 自動識別費用型別、金額、日期和供應商;系統根據費用政策、預算、專案和審批許可權判斷是否異常;低風險報銷自動生成稽核建議,高風險報銷進入財務複核和主管審批;所有 AI 判斷都要說明依據。 +> 幫我搭建一個 AI 報銷稽核應用。員工上傳發票、行程單和付款憑證後,AI 自動識別費用型別、金額、日期和供應商;系統根據費用政策、預算、專案和審批權限判斷是否異常;低風險報銷自動生成稽核建議,高風險報銷進入財務複核和主管審批;所有 AI 判斷都要說明依據。 這句話生成的,不應該只是一個票據識別頁面,而是一套費用合規應用。 @@ -35,7 +35,7 @@ tags: [] 這些判斷很適合 AI 輔助,因為它要閱讀票據、附件、說明和歷史記錄,還要解釋政策。 -但報銷又不能完全交給 AI。財務稽核涉及錢、合規和員工體驗。AI 可以提示風險、生成意見、解釋規則,但最終通過、駁回、追加說明和例外批准,都應該在許可權和審計之下完成。 +但報銷又不能完全交給 AI。財務稽核涉及錢、合規和員工體驗。AI 可以提示風險、生成意見、解釋規則,但最終通過、駁回、追加說明和例外批准,都應該在權限和審計之下完成。 這正是後設資料驅動應用的價值:把政策、預算、專案、審批和異常都表達成物件和規則,讓 AI 在清楚邊界裡工作。 diff --git a/content/blog/ai-ontology-open-protocol/index.zh-Hant.mdx b/content/blog/ai-ontology-open-protocol/index.zh-Hant.mdx index 2cf1e0a..029eea5 100644 --- a/content/blog/ai-ontology-open-protocol/index.zh-Hant.mdx +++ b/content/blog/ai-ontology-open-protocol/index.zh-Hant.mdx @@ -26,10 +26,10 @@ tags: 第三個月,要接生產資料了,安全團隊進場,問了三個問題: - AI 能看到哪些資料?銷售 A 問“全公司業績排名”,它會不會把別人的提成也答出來? -- 它要執行動作——改折扣、發合同——許可權按什麼算?出錯了算誰的? +- 它要執行動作——改折扣、發合同——權限按什麼算?出錯了算誰的? - 審計要查“這筆折扣是誰批的”,AI 參與的那部分,記錄在哪? -專案組答不上來。不是態度問題,是**架構里根本沒有能回答這些問題的層**。資料散在十幾個系統裡,許可權寫在各個應用的程式碼裡,“折扣審批”這個業務規則只存在於某個資深員工的腦子裡。AI 面對的是一堆裸表和裸介面,它再聰明,也沒有地方去“看懂”這家企業的規則。 +專案組答不上來。不是態度問題,是**架構裡根本沒有能回答這些問題的層**。資料散在十幾個系統裡,權限寫在各個應用的程式碼裡,“折扣審批”這個業務規則只存在於某個資深員工的腦子裡。AI 面對的是一堆裸表和裸介面,它再聰明,也沒有地方去“看懂”這家企業的規則。 第九個月,試點悄悄結束。模型沒有輸給能力,輸給了沒有人敢簽字。 @@ -39,9 +39,9 @@ tags: 把 Ontology 從論文概念變成企業架構實踐的代表,是 Palantir。值得認真看一下它為什麼成立——看得越公道,後面的問題才越清楚。 -Palantir Foundry 的核心動作是兩個。第一,把企業散落各處的資料**整合進一個統一的本體層**:客戶、裝置、訂單不再只是幾十張表,而是有型別、有關係、有屬性的業務物件。第二,把寫操作收斂成**受控的 Actions**——每個動作帶校驗、帶許可權、帶完整審計。AIP 把這套架構直接對準了大模型:**LLM 不直接碰資料庫,而是呼叫本體層暴露出來的受治理工具。** 模型可以換,邊界不動。 +Palantir Foundry 的核心動作是兩個。第一,把企業散落各處的資料**整合進一個統一的本體層**:客戶、裝置、訂單不再只是幾十張表,而是有型別、有關係、有屬性的業務物件。第二,把寫操作收斂成**受控的 Actions**——每個動作帶校驗、帶權限、帶完整審計。AIP 把這套架構直接對準了大模型:**LLM 不直接碰資料庫,而是呼叫本體層暴露出來的受治理工具。** 模型可以換,邊界不動。 -這套東西為什麼貴?因為它解決的問題確實貴。把一家大企業多年積累的系統梳理成一個乾淨的本體,需要團隊一個系統一個系統地啃,一個概念一個概念地對齊——這是實打實的人力密集型工程。政府、國防、金融、能源這類客戶,對“AI 每一步都在許可權之內、都有記錄”的要求是硬性的,也願意為交付質量、責任邊界和長期支援付費。 +這套東西為什麼貴?因為它解決的問題確實貴。把一家大企業多年積累的系統梳理成一個乾淨的本體,需要團隊一個系統一個系統地啃,一個概念一個概念地對齊——這是實打實的人力密集型工程。政府、國防、金融、能源這類客戶,對“AI 每一步都在權限之內、都有記錄”的要求是硬性的,也願意為交付質量、責任邊界和長期支援付費。 所以這裡真正值得吸取的,不是某家公司的估值故事,而是一個架構判斷:**AI 要進入企業,必須先有一個受治理的業務語義層。** @@ -79,7 +79,7 @@ Palantir Foundry 的核心動作是兩個。第一,把企業散落各處的資 規律其實很整齊:**被整個生態依賴的可移植底座最終會走向開放——既包括定義,也包括解釋和執行這些定義的基礎執行時。** 廠商仍然可以獲得持續收入,但賣的是託管運營、升級、安全封裝、效能、支援和責任。AWS 自己就是最大的例證:Linux、Kubernetes、Postgres 保持開放,AWS 為可靠運營它們收費。 -業務語義層正是這種底座。物件模型、許可權規則、審批流程,以及強制執行它們的執行時語義,未來會被應用、agent、審計系統共同依賴。依賴越多,定義與執行時就越不應該只存在於某個供應商的平臺裡。定義應是你倉庫中可讀、可版本化的檔案,相容執行時則應可自託管、可替換。只能由一家付費引擎執行的“開放檔案”,並不真正可遷移。 +業務語義層正是這種底座。物件模型、權限規則、審批流程,以及強制執行它們的執行時語義,未來會被應用、agent、審計系統共同依賴。依賴越多,定義與執行時就越不應該只存在於某個供應商的平臺裡。定義應是你倉庫中可讀、可版本化的檔案,相容執行時則應可自託管、可替換。只能由一家付費引擎執行的“開放檔案”,並不真正可遷移。 企業花了二十年把**資料**從一個個封閉系統裡解放出來,不應該在 AI 時代把比資料更核心的資產——**業務的定義本身**——再鎖進去一次。 @@ -96,7 +96,7 @@ Palantir Foundry 的核心動作是兩個。第一,把企業散落各處的資 | 層 | 它是什麼 | 2026 年把它留在哪 | | --- | --- | --- | | **介面層** | agent 如何呼叫 ontology | **已開放。** MCP,由平臺廠商自己採用 | -| **定義層** | 物件、動作與許可權 | **形式上在開放。** 以程式碼入庫,仍要落到單一廠商的平臺上 | +| **定義層** | 物件、動作與權限 | **形式上在開放。** 以程式碼入庫,仍要落到單一廠商的平臺上 | | **執行時** | 執行動作、並在執行時強制規則的那一層 | **原地未動。** 沒有廠商交出一個你能換個地方跑的執行時 | 第三行值得慢慢讀,因為整個論點就在那裡。 @@ -105,11 +105,11 @@ Palantir Foundry 的核心動作是兩個。第一,把企業散落各處的資 這就是這次更新真正依賴的那個數字。把 Palantir 那套寫進文件的投影規則套到一箇中等規模的應用上——12 個物件型別、30 個動作型別、6 個對外函式——你會得到**37 個說著開放協議的 MCP 工具,而底下只有一臺引擎能回答其中任何一個。**介面變得可移植了,依賴一寸也沒動。 -![三層結構決定可移植性:介面層通過 MCP 開放,定義層以程式碼入庫的形式開放,而負責強制許可權、事務與審計的執行時原地未動](./three-layers-open-2026.svg) +![三層結構決定可移植性:介面層通過 MCP 開放,定義層以程式碼入庫的形式開放,而負責強制權限、事務與審計的執行時原地未動](./three-layers-open-2026.svg) **把最有力的反駁如實擺出來:**團隊真正想從可移植性裡拿到的東西,如今大半已經拿到了。你可以讀自己的模型、以 diff 的方式評審它、把任何 agent 指向它;分析型語義還能通過一份 2026 年進入 Apache 孵化器的中立規範來交換。如果你的 ontology 只需要回答問題,那已經接近夠用了,本文不該假裝不是。 -而回答它的那條線,和「語義層」與 ontology 的分界線是同一條:它一直成立,直到有事情必須真的**發生**。當一個對外暴露的動作真的改寫了一條記錄,你在意的一切——許可權校驗、事務、超過閾值時的審批、那一行審計記錄——都是引擎的性質,而不是檔案的性質,也不是協議的性質。你能匯出那句話,導不出那道強制。 +而回答它的那條線,和「語義層」與 ontology 的分界線是同一條:它一直成立,直到有事情必須真的**發生**。當一個對外暴露的動作真的改寫了一條記錄,你在意的一切——權限校驗、事務、超過閾值時的審批、那一行審計記錄——都是引擎的性質,而不是檔案的性質,也不是協議的性質。你能匯出那句話,導不出那道強制。 把這個缺口叫作**最後一層沒有開啟的地方**。這不是指控,而是對這個賽道停在哪裡的描述。九個月裡有兩層開放了,而且多半是靠自身慣性;第三層一動沒動——因為那是平臺生意在不改變自己賣什麼的前提下無法開啟的一層。 @@ -134,7 +134,7 @@ export const Opportunity = ObjectSchema.create({ }, }); -// 許可權同樣是宣告的:銷售可讀寫商機,但不能刪除 +// 權限同樣是宣告的:銷售可讀寫商機,但不能刪除 export const SalesUser: Security.PermissionSet = { name: 'crm_sales_user', objects: { @@ -143,15 +143,15 @@ export const SalesUser: Security.PermissionSet = { }; ``` -關鍵不在語法,在於**這幾十行就是系統本身**。開源 ObjectStack 執行時讀取這份定義,派生資料表、REST API、管理介面、MCP 工具,並強制執行許可權與審計。折扣超過 30% 要走財務審批?那是一條掛在這個物件上的流程定義,同樣是宣告式的,同樣在版本庫裡。ObjectOS 在同一應用外增加商業生產體驗——瀏覽器內 Build 與 Ask、團隊審閱和審批、託管雲或私有部署運營、SSO 與支援——但不會把定義或執行引擎重新變成專有依賴。 +關鍵不在語法,在於**這幾十行就是系統本身**。開源 ObjectStack 執行時讀取這份定義,派生資料表、REST API、管理介面、MCP 工具,並強制執行權限與審計。折扣超過 30% 要走財務審批?那是一條掛在這個物件上的流程定義,同樣是宣告式的,同樣在版本庫裡。ObjectOS 在同一應用外增加商業生產體驗——瀏覽器內 Build 與 Ask、團隊審閱和審批、託管雲或私有部署運營、SSO 與支援——但不會把定義或執行引擎重新變成專有依賴。 -![一份後設資料定義,同時生效為 API、介面、AI 工具和審計許可權](./one-definition-four-surfaces.svg) +![一份後設資料定義,同時生效為 API、介面、AI 工具和審計權限](./one-definition-four-surfaces.svg) 這帶來三個直接後果: -1. **開頭那三個安全問題,有了結構性的答案。** AI 能看什麼——許可權集裡寫著;它執行動作按什麼許可權算——它以登入使用者的身份行動,由 ObjectStack 執行時強制執行,而不是靠提示詞約束;審計記錄在哪——人和 agent 的每一次讀寫共用同一本賬,誰、什麼、何時、為什麼,合規團隊只看一本。 -2. **業務變更變成了程式碼評審。** AI 要給系統加一個“續約提醒”?它提交的是一份後設資料 diff,改了什麼欄位、動了什麼許可權,一目瞭然。出問題可以回滾,因為定義是版本化的。 -3. **整個系統裝得進一個 agent 的上下文視窗。** 一個典型的企業模組,從幾萬行 CRUD 和膠水程式碼收斂成幾百行宣告——小到 AI 可以完整讀懂每一處依賴,然後跨資料、API、介面、許可權做一次安全的整體重構。這是“AI 當共同維護者”和“AI 當代碼補全”的分界線。 +1. **開頭那三個安全問題,有了結構性的答案。** AI 能看什麼——權限集裡寫著;它執行動作按什麼權限算——它以登入使用者的身份行動,由 ObjectStack 執行時強制執行,而不是靠提示詞約束;審計記錄在哪——人和 agent 的每一次讀寫共用同一本賬,誰、什麼、何時、為什麼,合規團隊只看一本。 +2. **業務變更變成了程式碼評審。** AI 要給系統加一個“續約提醒”?它提交的是一份後設資料 diff,改了什麼欄位、動了什麼權限,一目瞭然。出問題可以回滾,因為定義是版本化的。 +3. **整個系統裝得進一個 agent 的上下文視窗。** 一個典型的企業模組,從幾萬行 CRUD 和膠水程式碼收斂成幾百行宣告——小到 AI 可以完整讀懂每一處依賴,然後跨資料、API、介面、權限做一次安全的整體重構。這是“AI 當共同維護者”和“AI 當代碼補全”的分界線。 ## 定義與可移植執行時歸社群,生產運營做生意 @@ -161,7 +161,7 @@ Ontology 這個判斷是對的,Palantir 已經替行業證明過。本文最 這正是 ObjectStack 和 ObjectOS 的分工: -- **ObjectStack** 是一套**開放業務本體(open business ontology)**:型別化的應用定義,加上執行它的開源執行時(Apache 2.0)。物件、關係、許可權、流程、API、UI、AI 工具在你的倉庫裡一次定義;執行時從中派生資料庫、REST API、渲染介面與 MCP 服務,並在每次呼叫上強制許可權與審計。定義和引擎都可 diff、可自託管、可遷移——而後一半,正是這個賽道其餘玩家留著沒開的那一層。 +- **ObjectStack** 是一套**開放業務本體(open business ontology)**:型別化的應用定義,加上執行它的開源執行時(Apache 2.0)。物件、關係、權限、流程、API、UI、AI 工具在你的倉庫裡一次定義;執行時從中派生資料庫、REST API、渲染介面與 MCP 服務,並在每次呼叫上強制權限與審計。定義和引擎都可 diff、可自託管、可遷移——而後一半,正是這個賽道其餘玩家留著沒開的那一層。 - **ObjectOS** 是圍繞同一 ObjectStack 應用的商業生產平臺。它銷售瀏覽器內 Build 與 Ask、團隊審閱和審批、託管雲或私有部署運營、SSO、企業控制與支援,而不是一臺把業務本體重新鎖回廠商手裡的封閉執行引擎。 一邊是任何團隊、任何 agent 都看得懂、可自託管、帶得走的應用定義與可移植執行時;另一邊是企業真正願意付費的生產體驗:協作編寫、審批、託管、私有部署、SSO、支援、升級和運營責任。應用及其基礎執行時歸你,為團隊可靠運營它們才是生意。 @@ -178,4 +178,4 @@ Ontology 這個判斷是對的,Palantir 已經替行業證明過。本文最 npm i -g @objectstack/cli && os start ``` -五分鐘後,定義你的第一個業務物件,看開源 ObjectStack 執行時把它變成一張表、一個 API、一個管理介面和一個 AI 可以安全呼叫的工具。每次呼叫都帶許可權,每次呼叫都記賬。如果團隊需要瀏覽器內 Build 與 Ask、共享審閱和審批、託管雲或私有部署、SSO 與支援,ObjectOS 運營的仍是同一份 ObjectStack 應用,不會換成專有格式或獨家引擎。 +五分鐘後,定義你的第一個業務物件,看開源 ObjectStack 執行時把它變成一張表、一個 API、一個管理介面和一個 AI 可以安全呼叫的工具。每次呼叫都帶權限,每次呼叫都記賬。如果團隊需要瀏覽器內 Build 與 Ask、共享審閱和審批、託管雲或私有部署、SSO 與支援,ObjectOS 運營的仍是同一份 ObjectStack 應用,不會換成專有格式或獨家引擎。 diff --git a/content/blog/ai-project-risk-assistant/index.zh-Hant.mdx b/content/blog/ai-project-risk-assistant/index.zh-Hant.mdx index 9f81c57..5adc4cd 100644 --- a/content/blog/ai-project-risk-assistant/index.zh-Hant.mdx +++ b/content/blog/ai-project-risk-assistant/index.zh-Hant.mdx @@ -19,7 +19,7 @@ tags: [] 它通常藏在進度更新裡:“這個介面可能要晚兩天”“客戶還沒確認範圍”“測試環境還沒準備好”“關鍵同事這周被別的專案佔用”。這些話看起來只是普通備註,等它們真正變成延期,專案經理才發現風險已經積累很久。 -AI 專案管理助手的價值,不是再做一個任務看板,而是持續閱讀專案裡的非結構化資訊,把風險訊號從會議紀要、任務評論、變更記錄和週報里拉出來。 +AI 專案管理助手的價值,不是再做一個任務看板,而是持續閱讀專案裡的非結構化資訊,把風險訊號從會議紀要、任務評論、變更記錄和週報裡拉出來。 你可以對平臺說: @@ -143,6 +143,6 @@ AI 專案管理助手可以從四步開始。 專案管理最難的不是缺工具,而是缺一個能把現場訊號連線起來的執行層。 -ObjectStack 可以用自然語言生成專案、任務、會議、風險、變更和行動計劃後設資料。AI 在這些物件和許可權之下讀取進度更新、識別風險、解釋原因並建立受控動作。 +ObjectStack 可以用自然語言生成專案、任務、會議、風險、變更和行動計劃後設資料。AI 在這些物件和權限之下讀取進度更新、識別風險、解釋原因並建立受控動作。 專案風險藏在進度更新裡。AI 專案管理助手的意義,就是讓這些風險在真正爆發之前,被系統看見、被團隊討論、被行動計劃接住。 diff --git a/content/blog/ai-sales-assistant/index.zh-Hant.mdx b/content/blog/ai-sales-assistant/index.zh-Hant.mdx index d91abf3..93562b7 100644 --- a/content/blog/ai-sales-assistant/index.zh-Hant.mdx +++ b/content/blog/ai-sales-assistant/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: AI 銷售助理:如何更新 CRM 並建議下一步 -description: AI 銷售助理不只是自動填表,而是把客戶、聯絡人、商機、跟進和任務做成可治理的後設資料,讓銷售用對話推進商機,同時保留許可權和審計。 +description: AI 銷售助理不只是自動填表,而是把客戶、聯絡人、商機、跟進和任務做成可治理的後設資料,讓銷售用對話推進商機,同時保留權限和審計。 author: ObjectStack Team date: 2026-06-05 status: published @@ -15,7 +15,7 @@ tags: - AI 智慧體 --- -**先給結論**:AI 銷售助理不是給 CRM 加個自動填表,而是把客戶、商機、跟進、任務和 Agent 工具生成為受治理的後設資料——銷售用對話工作、主管能追問,而資料始終在許可權之內。 +**先給結論**:AI 銷售助理不是給 CRM 加個自動填表,而是把客戶、商機、跟進、任務和 Agent 工具生成為受治理的後設資料——銷售用對話工作、主管能追問,而資料始終在權限之內。 銷售團隊討厭填 CRM,不是因為他們討厭資料,而是因為傳統 CRM 經常把資料錄入放在業務推進前面。 @@ -111,11 +111,11 @@ AI 銷售助理最常見的使用畫面,不是開啟一個新頁面,而是 > 我下午要見明遠科技,幫我準備一下。 -系統應該基於許可權讀取客戶、聯絡人、歷史活動、商機、工單和合同資訊,生成會前簡報: +系統應該基於權限讀取客戶、聯絡人、歷史活動、商機、工單和合同資訊,生成會前簡報: - 客戶當前有兩個進行中商機; - 最近一次溝通提到私有化部署和資料安全; -- 技術負責人關注審計日誌和許可權邊界; +- 技術負責人關注審計日誌和權限邊界; - 客服系統裡有一條未關閉問題,可能影響演示; - 建議本次會議確認安全評估流程、預算審批人和上線時間。 @@ -146,7 +146,7 @@ AI 不只是列出列表,還應該解釋原因: > 給每個負責人生成一條提醒任務,要求今天下班前補充下一步計劃。 -這時系統需要檢查主管許可權,確認任務建立範圍,再執行批次動作。AI 負責理解意圖,平臺負責許可權、動作和審計。 +這時系統需要檢查主管權限,確認任務建立範圍,再執行批次動作。AI 負責理解意圖,平臺負責權限、動作和審計。 ## AI 銷售助理的邊界 @@ -170,7 +170,7 @@ AI 不只是列出列表,還應該解釋原因: 需要審批的動作包括: -- 超許可權折扣; +- 超權限折扣; - 非標準合同承諾; - 高風險客戶承諾上線日期; - 跨區域客戶移交; @@ -198,7 +198,7 @@ AI 銷售助理越好用,越不能繞過這些邊界。否則它只是把傳 ## ObjectStack 的價值:讓 CRM 變成可對話的業務應用 -AI 銷售助理不是一個孤立聊天視窗。它需要理解物件、關係、許可權、動作和流程。 +AI 銷售助理不是一個孤立聊天視窗。它需要理解物件、關係、權限、動作和流程。 ObjectStack 的後設資料驅動方式,讓應用搭建和應用使用可以共用同一套語義:業務人員用自然語言生成客戶、商機、階段、規則和檢視;銷售再用自然語言查詢、更新、總結和推進工作。 diff --git a/content/blog/ai-ticket-hub/index.zh-Hant.mdx b/content/blog/ai-ticket-hub/index.zh-Hant.mdx index b373928..0e6e07b 100644 --- a/content/blog/ai-ticket-hub/index.zh-Hant.mdx +++ b/content/blog/ai-ticket-hub/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: AI 工單中樞:讓客服系統讀懂客戶問題 -description: 客服工單不應該只負責排隊。把物件、佇列、SLA、知識庫和受控工具做成後設資料後,AI 才能在許可權邊界內理解問題、推薦回覆並推動流轉。 +description: 客服工單不應該只負責排隊。把物件、佇列、SLA、知識庫和受控工具做成後設資料後,AI 才能在權限邊界內理解問題、推薦回覆並推動流轉。 author: ObjectStack Team date: 2026-06-05 status: published @@ -15,7 +15,7 @@ cover: ./cover.png tags: [] --- -**先給結論**:AI 工單中樞的價值不是把問題排隊,而是把物件、佇列、SLA、知識庫和 Agent 工具做成後設資料,讓 AI 在許可權之內讀懂問題、給出處理,而不是又一個聊天框。 +**先給結論**:AI 工單中樞的價值不是把問題排隊,而是把物件、佇列、SLA、知識庫和 Agent 工具做成後設資料,讓 AI 在權限之內讀懂問題、給出處理,而不是又一個聊天框。 很多客服系統的問題,不是沒有工單,而是隻有工單。 @@ -23,7 +23,7 @@ tags: [] 這套流程能管理工作量,卻很難理解問題本身。 -AI 原生的工單中樞應該反過來設計:先讓系統讀懂客戶問題,再讓工單成為被理解後的業務物件。它不是在傳統工單系統旁邊加一個“AI 總結”按鈕,而是從物件、欄位、檢視、流程、許可權、知識庫和 Agent 工具開始,就把 AI 放進業務執行方式裡。 +AI 原生的工單中樞應該反過來設計:先讓系統讀懂客戶問題,再讓工單成為被理解後的業務物件。它不是在傳統工單系統旁邊加一個“AI 總結”按鈕,而是從物件、欄位、檢視、流程、權限、知識庫和 Agent 工具開始,就把 AI 放進業務執行方式裡。 更關鍵的是,這個應用本身應該能用自然語言搭建。 @@ -42,7 +42,7 @@ AI 原生的工單中樞應該反過來設計:先讓系統讀懂客戶問題 第二,判斷依賴上下文。同一句“系統打不開”,對免費試用客戶和年付企業客戶的優先順序不同;對正在上線的客戶和普通諮詢客戶的處理方式也不同。AI 必須結合客戶、合同、歷史工單、SLA 和知識庫一起判斷。 -第三,客服動作重複但不能完全自動。分類、摘要、查知識庫、起草回覆可以交給 AI;是否傳送、是否退款、是否承諾交付時間,仍然需要許可權、審批和人工確認。 +第三,客服動作重複但不能完全自動。分類、摘要、查知識庫、起草回覆可以交給 AI;是否傳送、是否退款、是否承諾交付時間,仍然需要權限、審批和人工確認。 所以 AI 工單中樞不是“自動聊天機器人”,而是一個能把客戶問題轉成受控業務流程的應用。 @@ -67,7 +67,7 @@ AI 原生的工單中樞應該反過來設計:先讓系統讀懂客戶問題 - 訊息保留來源渠道、原文、附件和 AI 摘要; - 問題型別、緊急程度、情緒、語言、影響範圍由 AI 初判,但允許人工改寫; - SLA 截止時間由客戶等級、問題型別和建立時間自動計算; -- 企業客戶、付款異常客戶、法律風險問題進入更嚴格的許可權和審批。 +- 企業客戶、付款異常客戶、法律風險問題進入更嚴格的權限和審批。 這就是後設資料驅動和普通 AI 生成頁面的差別。頁面只是入口,真正重要的是業務語義被平臺理解了。 @@ -87,9 +87,9 @@ AI 原生的工單中樞應該反過來設計:先讓系統讀懂客戶問題 > 把退款、賠償、合同承諾這三類回覆設為敏感回覆,必須主管確認後才能傳送。 -這不應該只是提示詞變化,而應該落到動作許可權和審批後設資料裡:AI 可以起草敏感回覆,但傳送動作必須走審批;審批前,客戶不可見;審批後,動作和批准人進入審計日誌。 +這不應該只是提示詞變化,而應該落到動作權限和審批後設資料裡:AI 可以起草敏感回覆,但傳送動作必須走審批;審批前,客戶不可見;審批後,動作和批准人進入審計日誌。 -好的 AI Builder 應該像一個懂平臺的應用架構師:它接受自然語言,但輸出的是物件、許可權、檢視、流程、校驗和 Agent 工具。 +好的 AI Builder 應該像一個懂平臺的應用架構師:它接受自然語言,但輸出的是物件、權限、檢視、流程、校驗和 Agent 工具。 ## 客服使用應用時,也應該是對話式的 @@ -131,7 +131,7 @@ AI 可以基於當前工單、歷史訊息、知識庫和客戶上下文回答 例如“傳送客戶回覆”應該是一個動作,不是模型自由輸出後直接發郵件。動作需要檢查: -1. 當前使用者是否有許可權回覆該客戶; +1. 當前使用者是否有權限回覆該客戶; 2. 回覆是否包含敏感承諾、賠償、價格或合同內容; 3. AI 生成內容是否引用了可公開給客戶的知識; 4. 是否需要主管審批; @@ -159,10 +159,10 @@ AI 的能力越強,越需要把動作邊界設計清楚。否則工單中樞 AI 工單中樞表面上是客服應用,底層其實是一個典型的後設資料驅動系統。 -它需要物件模型、關係、欄位、許可權、檢視、流程、動作、知識庫、Agent 工具和審計一起工作。任何一層缺失,AI 都很容易停留在外圍。 +它需要物件模型、關係、欄位、權限、檢視、流程、動作、知識庫、Agent 工具和審計一起工作。任何一層缺失,AI 都很容易停留在外圍。 -ObjectStack 的價值在於:業務人員可以用自然語言描述應用,平臺把需求轉成後設資料;應用執行時再用同一套後設資料驅動 UI、API、許可權、自動化和 Agent。 +ObjectStack 的價值在於:業務人員可以用自然語言描述應用,平臺把需求轉成後設資料;應用執行時再用同一套後設資料驅動 UI、API、權限、自動化和 Agent。 -這樣 AI 不是繞過客服系統,而是在客服系統的業務語義和許可權邊界內工作。 +這樣 AI 不是繞過客服系統,而是在客服系統的業務語義和權限邊界內工作。 真正的 AI 工單中樞,不只是讓客服少寫幾句話。它讓系統第一次有能力持續讀懂客戶問題,並把理解結果變成可追蹤、可審批、可覆盤的業務動作。 diff --git a/content/blog/ai-wrote-your-app-dare-to-merge/index.zh-Hant.mdx b/content/blog/ai-wrote-your-app-dare-to-merge/index.zh-Hant.mdx index f493f4b..42474ae 100644 --- a/content/blog/ai-wrote-your-app-dare-to-merge/index.zh-Hant.mdx +++ b/content/blog/ai-wrote-your-app-dare-to-merge/index.zh-Hant.mdx @@ -41,7 +41,7 @@ tags: [] 回到那個 `GET /api/refunds`。它返回了所有人的退款記錄——可它能通過幾乎所有自動檢查:語法沒錯、沒有空指標、有測試(測試也是同一個 agent 寫的,自然只測了"能查到退款",不會去測"該不該查到別人的退款")。AI 評審擅長的是**程式碼對不對它自己**:有沒有 bug、符不符合已知漏洞模式、風格一不一致。它回答不了三個**程式碼之外**的問題:這段程式碼**該不該**讀這張表?這個動作**該不該**動這筆錢?這是不是我們**想要**的業務規則? -這些答案不在程式碼裡——它們在許可權模型、在審批策略、在業務意圖裡。**兩個 AI 互相點頭,不等於治理。** 審計員、法務、安全團隊要的那個"誰授權、誰擔責"的答案,一個再聰明的評審模型也籤不了字。所以"讓 AI 審 AI"省掉的是人讀程式碼的體力,省不掉那個**必須由人來做的"該不該"判斷**。問題繞回原點:人得能審。可八千行,人審不動。 +這些答案不在程式碼裡——它們在權限模型、在審批策略、在業務意圖裡。**兩個 AI 互相點頭,不等於治理。** 審計員、法務、安全團隊要的那個"誰授權、誰擔責"的答案,一個再聰明的評審模型也籤不了字。所以"讓 AI 審 AI"省掉的是人讀程式碼的體力,省不掉那個**必須由人來做的"該不該"判斷**。問題繞回原點:人得能審。可八千行,人審不動。 ## 出路:把 AI 要交給你的東西,縮小到你審得動 @@ -58,7 +58,7 @@ tags: [] + flow: refund_amount > 500 → 需財務審批 ``` -這十幾行,你能逐行讀懂、能在五分鐘內評審、能一鍵回滾。更關鍵的是最後那幾處:審查不再是"我讀得完嗎",而變成了**"這條許可權對不對、這個審批閾值合不合理"**——一個你真正能判斷、也該由你判斷的業務問題。那個會洩露的 `GET /api/refunds` 在這裡壓根不會出現:`support_refund` 的讀取許可權被宣告為"按呼叫者許可權",執行時據此強制,越權那條路從源頭就被關上了。 +這十幾行,你能逐行讀懂、能在五分鐘內評審、能一鍵回滾。更關鍵的是最後那幾處:審查不再是"我讀得完嗎",而變成了**"這條權限對不對、這個審批閾值合不合理"**——一個你真正能判斷、也該由你判斷的業務問題。那個會洩露的 `GET /api/refunds` 在這裡壓根不會出現:`support_refund` 的讀取權限被宣告為"按呼叫者權限",執行時據此強制,越權那條路從源頭就被關上了。 而實現去哪了?實現屬於被反覆審計、所有應用共用的開源 **ObjectStack 執行時**,不是每個應用各生成一份。"該不該做"——能不能讀、能不能刪、要不要審批——由執行時在執行時強制,而不是埋在八千行裡靠運氣。 @@ -68,7 +68,7 @@ tags: [] ![AI 寫、人審小 diff、執行時治理、agent 在邊界內執行的閉環](./review-loop.svg) -注意第④步:因為業務定義本身就聲明瞭物件與許可權,執行時會把它投影成一組**受治理的工具**——於是同一個 agent 不只"寫"了這個應用,之後還能在**同樣的許可權邊界內**去操作它(查退款、發起退款),每一步都帶身份、都留痕。寫和用,共用一套治理。 +注意第④步:因為業務定義本身就聲明瞭物件與權限,執行時會把它投影成一組**受治理的工具**——於是同一個 agent 不只"寫"了這個應用,之後還能在**同樣的權限邊界內**去操作它(查退款、發起退款),每一步都帶身份、都留痕。寫和用,共用一套治理。 ## 先潑一盆冷水 @@ -76,7 +76,7 @@ tags: [] 第一,**不是所有東西都能變成後設資料**。一個全新的即時演算法、一套獨特的渲染管線,仍然需要真正的程式碼,也仍然需要有人硬著頭皮 review 那部分——後設資料幫不了你,硬套反而誤事。它擅長的是企業裡那 90% 反覆重建的業務系統。 -第二,**信任被轉移了,不是被消滅了**。你不再逐個 review 每個應用的實現,但你把信任押在了那個執行時上——它得被認真審一次、被持續維護。但算一下這筆賬:傳統做法下,AI 每生成一個應用,你就得重新信任一坨新程式碼;後設資料做法下,你**審一次執行時**,之後它派生出的每個應用都自動繼承同一套被驗證過的許可權與審計。**審一次,勝過審一千次。** 這是個划算得多的交易,但它是一筆交易,不是魔法。 +第二,**信任被轉移了,不是被消滅了**。你不再逐個 review 每個應用的實現,但你把信任押在了那個執行時上——它得被認真審一次、被持續維護。但算一下這筆賬:傳統做法下,AI 每生成一個應用,你就得重新信任一坨新程式碼;後設資料做法下,你**審一次執行時**,之後它派生出的每個應用都自動繼承同一套被驗證過的權限與審計。**審一次,勝過審一千次。** 這是個划算得多的交易,但它是一筆交易,不是魔法。 ## 結語 diff --git a/content/blog/airtable-omni-vs-governed-ai-app-platform/index.zh-Hant.mdx b/content/blog/airtable-omni-vs-governed-ai-app-platform/index.zh-Hant.mdx index 5574313..8830a84 100644 --- a/content/blog/airtable-omni-vs-governed-ai-app-platform/index.zh-Hant.mdx +++ b/content/blog/airtable-omni-vs-governed-ai-app-platform/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: "Airtable Omni 與受治理 AI 應用平臺:為什麼審閱 diff 比撤銷更重要" -description: "Airtable Omni 把自然語言和表格式應用結合得很強。記錄系統真正要比較的,不是能不能生成應用,而是 AI 改動許可權、欄位和流程時,是否能在上線前形成可審閱的 diff。" +description: "Airtable Omni 把自然語言和表格式應用結合得很強。記錄系統真正要比較的,不是能不能生成應用,而是 AI 改動權限、欄位和流程時,是否能在上線前形成可審閱的 diff。" author: ObjectStack Team date: 2026-06-24 status: published @@ -15,7 +15,7 @@ tags: - Airtable Omni --- -**TL;DR:** Airtable 作為 AI 原生應用平臺的推進是真實的:Omni 用經生產驗證的元件來組裝應用,而不是每次提示都生成一次性程式碼。差距不在“能不能生成”,而在“改動如何被批准”。撤銷、活動記錄和審計日誌屬於變更後的檢測能力;受監管的記錄系統還需要釋出前的預防型控制:一份說明欄位、許可權、檢視、自動化影響的可審閱 diff,以及由執行時在物件、欄位和動作層強制執行的許可權。若你的要求還包括執行時主權和自託管,平臺形態本身也會提前改變評估結論。 +**TL;DR:** Airtable 作為 AI 原生應用平臺的推進是真實的:Omni 用經生產驗證的元件來組裝應用,而不是每次提示都生成一次性程式碼。差距不在“能不能生成”,而在“改動如何被批准”。撤銷、活動記錄和審計日誌屬於變更後的檢測能力;受監管的記錄系統還需要釋出前的預防型控制:一份說明欄位、權限、檢視、自動化影響的可審閱 diff,以及由執行時在物件、欄位和動作層強制執行的權限。若你的要求還包括執行時主權和自託管,平臺形態本身也會提前改變評估結論。 從一個星期二說起,因為真正咬到你的地方在這裡,而不是在演示裡。 @@ -27,7 +27,7 @@ tags: ## 你的審計師早已在用的區分:預防型 vs 檢測型 -先精確地把該給 Airtable 的肯定給足,因為含糊的批評在這裡一文不值。Omni 確實不是氛圍程式設計(vibe coding)——CEO Howie Liu"從一個裝著經生產驗證元件的零件箱裡組裝"的說法,是正確的架構,勝過每次提示都重新生成脆弱程式碼。Airtable Enterprise 有真正的控制:Enterprise Hub、審計日誌(介面內 1 萬條事件,通過 API 更多)、組織單元角色與超級管理員角色、EKM/DLP,以及 2025 年那套能觸及欄位與記錄級別的高階許可權控制。一個認真的 Airtable 管理員讀到"它沒有治理"這種偷懶的論調,就會不再信任你。所以別寫那一種。 +先精確地把該給 Airtable 的肯定給足,因為含糊的批評在這裡一文不值。Omni 確實不是氛圍程式設計(vibe coding)——CEO Howie Liu"從一個裝著經生產驗證元件的零件箱裡組裝"的說法,是正確的架構,勝過每次提示都重新生成脆弱程式碼。Airtable Enterprise 有真正的控制:Enterprise Hub、審計日誌(介面內 1 萬條事件,通過 API 更多)、組織單元角色與超級管理員角色、EKM/DLP,以及 2025 年那套能觸及欄位與記錄級別的高階權限控制。一個認真的 Airtable 管理員讀到"它沒有治理"這種偷懶的論調,就會不再信任你。所以別寫那一種。 寫精確的那一種。安全與審計框架把控制分為兩類,而你的審計師正是依這個區分行事: @@ -69,7 +69,7 @@ tags: change #4827 · proposed by Omni · approved_by: __________ · reason: __________ ``` -讀一讀這給開篇那位經理帶來了什麼。這個欄位被標記為 `confidential`,因為它衍生自 ARR——是自動標的,因為敏感度是資料的屬性,而不是某個人需要記得去打的標籤。而那唯一要緊的一行——看板檢視想授予 CSM 對 ARR 派生資料的讀取許可權——被*當作一個決策*單獨凸顯出來,在任何東西釋出之前。經理(或她的安全搭檔)要麼是有意去批准它,要麼不批。無論哪種,變更 #4827 現在都附上了一個名字和一個理由。當審計師在六週後來問,答案存在——*因為在變更的那一刻,這個問題就被強制提出來了。* +讀一讀這給開篇那位經理帶來了什麼。這個欄位被標記為 `confidential`,因為它衍生自 ARR——是自動標的,因為敏感度是資料的屬性,而不是某個人需要記得去打的標籤。而那唯一要緊的一行——看板檢視想授予 CSM 對 ARR 派生資料的讀取權限——被*當作一個決策*單獨凸顯出來,在任何東西釋出之前。經理(或她的安全搭檔)要麼是有意去批准它,要麼不批。無論哪種,變更 #4827 現在都附上了一個名字和一個理由。當審計師在六週後來問,答案存在——*因為在變更的那一刻,這個問題就被強制提出來了。* 這就是"AI 能造出來"和"AI 的變更是可治理的"之間的區別。這無關乎少信任模型幾分。這關乎變更是一個可審閱的物件,而不是一樁已經發生了的事件。 @@ -80,11 +80,11 @@ tags: - 有了**預防型**閘門,MTUE **在構造上就是零**。那個越線的變更從不上線;它停在審批這一步等待。不存在暴露視窗。 - 用**撤銷 + 一份檢測型日誌**,MTUE 就是*檢測所需的時間*——而你應該誠實地給它定價。最好的情況,某個同事當天下午就注意到了。現實的情況,是在有人審計那個檢視時,或季度訪問複核執行時,或——如場景裡那樣——外部審計師先發現了它。對那些會同步到其他系統的資料(Airtable 的 HyperDB 預設是每 24 小時同步一次),在任何人去看之前,暴露就可能已經擴散。 -代入你自己的訪問複核節奏。如果你每季度複核一次敏感許可權,那麼對一個悄無聲息的錯配,你那基於撤銷的 MTUE 要以*數週到一個季度*來計量。預防型模型把這個數字變成零,靠的不是更聰明,而是把檢查點挪到了變更之前而非之後。你無法靠提示把 MTUE 提到 0;它是關於人*在何時*進入迴路的一種架構性質。 +代入你自己的訪問複核節奏。如果你每季度複核一次敏感權限,那麼對一個悄無聲息的錯配,你那基於撤銷的 MTUE 要以*數週到一個季度*來計量。預防型模型把這個數字變成零,靠的不是更聰明,而是把檢查點挪到了變更之前而非之後。你無法靠提示把 MTUE 提到 0;它是關於人*在何時*進入迴路的一種架構性質。 ## "可我們已經在用 Airtable Enterprise,而且安全團隊已經批過了" -這是真實讀者的立場,所以正面回應它。是的——而你的安全團隊當初批的,是 Airtable 的*訪問模型與基礎設施*:SSO、加密、審計日誌、那幾層許可權。這些是真的,那次批准也是合理的。 +這是真實讀者的立場,所以正面回應它。是的——而你的安全團隊當初批的,是 Airtable 的*訪問模型與基礎設施*:SSO、加密、審計日誌、那幾層權限。這些是真的,那次批准也是合理的。 它幾乎可以肯定早於 Omni 開始往那個訪問模型裡寫變更。你的安全團隊極可能從未被問到的那個問題,既具體又可回答:**"當 AI 改動誰能看到什麼時,是什麼在它上線之前審閱了這個變更——具名的批准又在哪裡?"** 把這句話帶到你下一次的供應商溝通裡。你拿回來的答案——"你可以撤銷它"/"它在審計日誌裡"/"Omni 會展示一個計劃"——會精確地告訴你,你正站在預防型/檢測型那條線的哪一側。為此你不需要我們的意見;你需要的是這個問題。 @@ -92,12 +92,12 @@ tags: 為了智識上的誠實——因為這類文章的失敗模式,就是假裝這個取捨是免費的。預防型模型有真實的代價:**摩擦。**對每一個敏感變更都設一道審批閘門,對一個在內部追蹤表上迭代的三人小隊來說,恰恰是錯誤的人機工學。對他們而言,撤銷*才是*正確的設計,表格的使用體驗是真正的愉悅,而 Airtable 的模板生態和"做出第一個應用"的時間,領先於任何更重的東西——包括我們。我們不會在"做出第一個應用"的速度上去超過 Airtable,假裝能超過,會是反方向上同樣的不誠實。 -預防型模型只有在一個未經審閱的變更的代價超過審閱變更的代價時才划得來——也就是說,當存在機密資料、一個真正的許可權模型,以及一個終將去審計它的人時。這就是那條線。線之下,Airtable 憑實力取勝。線之上,撤銷缺口才是那個終結評估的東西,而且它在功能比較之前就把評估終結了。 +預防型模型只有在一個未經審閱的變更的代價超過審閱變更的代價時才划得來——也就是說,當存在機密資料、一個真正的權限模型,以及一個終將去審計它的人時。這就是那條線。線之下,Airtable 憑實力取勝。線之上,撤銷缺口才是那個終結評估的東西,而且它在功能比較之前就把評估終結了。 還有一條,獨立於以上所有,並且對某些買家同樣重要:Airtable 是託管平臺,而不是可由客戶完整自託管的執行時。如果你的執行時必須存在於你的資料和監管要求所在之處——主權、隔離、特定駐留地——那麼再好的協作體驗也不能替代部署形態本身。對這一類買家而言,比較會先從執行邊界開始,而不是從功能清單開始。 ## ObjectStack 的立場 -ObjectStack 是為那條線之上的世界而造的,且只為那個世界。應用核心是**開放、可讀的後設資料**——物件、欄位、關係、許可權、動作——因此一個 AI 變更就是上面展示的那份可審閱的 diff:一個由人在釋出前批准的*預防型*檢查點,其後果(這個檢視會把 ARR 派生資料暴露給 CSM)被當作一個決策凸顯出來,並繫結到一位具名審批人。許可權由**執行時在物件、記錄、欄位和動作上**強制執行,因此無法靠編輯一個檢視就被悄悄重排。它**可自託管**,並且它**接入你已經在執行的 CRM/ERP/資料庫**,而不是把你的業務再同步進一朵雲裡。 +ObjectStack 是為那條線之上的世界而造的,且只為那個世界。應用核心是**開放、可讀的後設資料**——物件、欄位、關係、權限、動作——因此一個 AI 變更就是上面展示的那份可審閱的 diff:一個由人在釋出前批准的*預防型*檢查點,其後果(這個檢視會把 ARR 派生資料暴露給 CSM)被當作一個決策凸顯出來,並繫結到一位具名審批人。權限由**執行時在物件、記錄、欄位和動作上**強制執行,因此無法靠編輯一個檢視就被悄悄重排。它**可自託管**,並且它**接入你已經在執行的 CRM/ERP/資料庫**,而不是把你的業務再同步進一朵雲裡。 -這套主張不是"像 Airtable 一樣簡單"——它有意不是,因為審批這一步本身就是產品。它是這樣的:保留那種讓 Airtable 易讀的"表格加聊天"體驗,在它底下放上一個預防型控制、一個執行時許可權模型,以及你自己的基礎設施——這樣,對"星期二是誰批准暴露 ARR 的"這個問題的回答,就是一個名字,而不是一次搜尋。 +這套主張不是"像 Airtable 一樣簡單"——它有意不是,因為審批這一步本身就是產品。它是這樣的:保留那種讓 Airtable 易讀的"表格加聊天"體驗,在它底下放上一個預防型控制、一個執行時權限模型,以及你自己的基礎設施——這樣,對"星期二是誰批准暴露 ARR 的"這個問題的回答,就是一個名字,而不是一次搜尋。 diff --git a/content/blog/airtable-style-ai-builder/index.zh-Hant.mdx b/content/blog/airtable-style-ai-builder/index.zh-Hant.mdx index b2903eb..fca7256 100644 --- a/content/blog/airtable-style-ai-builder/index.zh-Hant.mdx +++ b/content/blog/airtable-style-ai-builder/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: Airtable 式 AI Builder:用表格理解應用,用對話修改應用 -description: 最好的 AI Builder 把表格式搭建、對話式修改和受治理的後設資料結合起來:物件、欄位、檢視、許可權和自動化都可見,也都能被審查。 +description: 最好的 AI Builder 把表格式搭建、對話式修改和受治理的後設資料結合起來:物件、欄位、檢視、權限和自動化都可見,也都能被審查。 author: ObjectStack Team date: 2026-06-05T10:20:00+08:00 status: published @@ -14,7 +14,7 @@ tags: - Airtable --- -**先給結論**:最好的 AI Builder 體驗,是把表格式搭建、對話式修改和受治理的後設資料三者合一——像 Airtable 一樣直觀,但底下是企業級的物件、許可權和審計,而不是黑盒。 +**先給結論**:最好的 AI Builder 體驗,是把表格式搭建、對話式修改和受治理的後設資料三者合一——像 Airtable 一樣直觀,但底下是企業級的物件、權限和審計,而不是黑盒。 Airtable 之所以打動業務人員,不是因為它像資料庫,而是因為它把“搭應用”變成了一件可理解的事。 @@ -26,12 +26,12 @@ AI Builder 如果要真正進入業務現場,就應該繼承這種可理解性 > 給客戶表加一個“續約風險”欄位,把高風險客戶放到一個看板裡,每週一提醒客戶成功經理跟進。 -平臺把這句話變成欄位、檢視、自動化和許可權變更。 +平臺把這句話變成欄位、檢視、自動化和權限變更。 ## Airtable 給低程式碼產品留下的最大啟發 -很多低程式碼平臺能力很強,但一上來就是頁面設計器、流程畫布、資料模型、許可權矩陣、表示式編輯器。對於非技術使用者來說,這些概念太重。 +很多低程式碼平臺能力很強,但一上來就是頁面設計器、流程畫布、資料模型、權限矩陣、表示式編輯器。對於非技術使用者來說,這些概念太重。 Airtable 的聰明之處,是從業務人員熟悉的“表格心智”開始。 @@ -48,7 +48,7 @@ AI Builder 也應該從這個心智出發,而不是讓使用者一開始就面 ## AI 不應該讓應用變成黑盒 -如果使用者說一句話,平臺立刻生成一個完整應用,但使用者不知道里面有什麼物件、欄位、許可權和流程,這個體驗短期很驚豔,長期會讓人不敢改。 +如果使用者說一句話,平臺立刻生成一個完整應用,但使用者不知道裡面有什麼物件、欄位、權限和流程,這個體驗短期很驚豔,長期會讓人不敢改。 業務人員需要的不是魔法,而是可控感。 @@ -57,7 +57,7 @@ AI Builder 也應該從這個心智出發,而不是讓使用者一開始就面 - 左側是物件和檢視; - 中間是表格、表單、看板或詳情; - 右側是 AI 對話和變更計劃; -- 底部或側欄能看到自動化、許可權和 Agent 工具。 +- 底部或側欄能看到自動化、權限和 Agent 工具。 這時候 AI 不是藏在系統背後的黑盒,而是一個能解釋自己將要修改什麼的協作者。 @@ -72,7 +72,7 @@ AI Builder 也應該從這個心智出發,而不是讓使用者一開始就面 | 資料模型 | 欄位型別、預設值、必填、列舉、公式 | | 表單 | 建立頁、編輯頁、詳情頁是否展示 | | 檢視 | 列表列、篩選條件、分組、排序 | -| 許可權 | 誰能看、誰能改、欄位是否敏感 | +| 權限 | 誰能看、誰能改、欄位是否敏感 | | 自動化 | 是否觸發提醒、審批、狀態變化 | | Agent | AI 能否讀取、解釋、基於欄位行動 | | 審計 | 欄位變化是否需要記錄修改原因 | @@ -107,19 +107,19 @@ AI Builder 的聊天框不應該只回答問題,它應該能操作應用結構 第一,像 Airtable:讓物件、欄位、記錄、檢視清楚可見。 -第二,像低程式碼平臺:讓流程、許可權、自動化和整合有企業級能力。 +第二,像低程式碼平臺:讓流程、權限、自動化和整合有企業級能力。 第三,像 ChatGPT:讓使用者用自然語言表達意圖,不必記住配置入口。 這三者少一個都不夠。 -只有表格,做不出複雜許可權和流程;只有低程式碼,業務使用者學習成本高;只有聊天,系統容易變成黑盒。 +只有表格,做不出複雜權限和流程;只有低程式碼,業務使用者學習成本高;只有聊天,系統容易變成黑盒。 ## ObjectStack 的 AI Builder 方向 ObjectStack 的 AI Builder 應該不是“生成程式碼的聊天框”,而是“可對話的應用搭建工作臺”。 -它讓業務結構像 Airtable 一樣可見:物件、欄位、關係、檢視。也讓企業能力像低程式碼一樣完整:許可權、流程、自動化、整合、審計。最後再用自然語言把修改入口降到業務人員能直接表達的程度。 +它讓業務結構像 Airtable 一樣可見:物件、欄位、關係、檢視。也讓企業能力像低程式碼一樣完整:權限、流程、自動化、整合、審計。最後再用自然語言把修改入口降到業務人員能直接表達的程度。 這會帶來一個很具體的產品畫面: diff --git a/content/blog/automation-cross-system-flows/index.zh-Hant.mdx b/content/blog/automation-cross-system-flows/index.zh-Hant.mdx index 2e287a7..1e404fb 100644 --- a/content/blog/automation-cross-system-flows/index.zh-Hant.mdx +++ b/content/blog/automation-cross-system-flows/index.zh-Hant.mdx @@ -23,7 +23,7 @@ CRM 改了狀態,ERP 要查應收,合同系統要確認簽署,通知服務 所以,自動化引擎如果只能在本系統裡改欄位、發通知,它能解決的只是區域性效率問題。真正的業務自動化必須跨系統執行。 -但跨系統不是簡單地“多接幾個 API”。關鍵在於:外部呼叫也要成為流程的一部分,有輸入、有輸出、有錯誤處理、有許可權邊界、有日誌,業務人員能看懂,管理員能治理。 +但跨系統不是簡單地“多接幾個 API”。關鍵在於:外部呼叫也要成為流程的一部分,有輸入、有輸出、有錯誤處理、有權限邊界、有日誌,業務人員能看懂,管理員能治理。 ![跨系統自動化流程](./cross-system-flow.svg) @@ -153,7 +153,7 @@ CRM 改了狀態,ERP 要查應收,合同系統要確認簽署,通知服務 如果只做同步,系統知道發生了什麼;如果有自動化流程,系統才知道接下來該做什麼。 -這也是 ObjectOS 這類平臺的價值:把外部資料接進來後,不只是展示,而是讓它進入物件、許可權、流程和動作體系。 +這也是 ObjectOS 這類平臺的價值:把外部資料接進來後,不只是展示,而是讓它進入物件、權限、流程和動作體系。 ## 對業務應用搭建的意義 diff --git a/content/blog/automation-governed-flow-changes/index.zh-Hant.mdx b/content/blog/automation-governed-flow-changes/index.zh-Hant.mdx index eb1c3a4..e45beef 100644 --- a/content/blog/automation-governed-flow-changes/index.zh-Hant.mdx +++ b/content/blog/automation-governed-flow-changes/index.zh-Hant.mdx @@ -67,7 +67,7 @@ tags: [] 3. 生成變更草案; 4. 展示新增、刪除、修改的節點和條件; 5. 校驗流程結構; -6. 由有許可權的人確認釋出; +6. 由有權限的人確認釋出; 7. 保留版本和審計。 這樣,自然語言帶來速度,流程治理保證穩定。 @@ -102,11 +102,11 @@ tags: [] - 哪個通知物件發生變化; - 是否影響已有執行中的流程; - 哪些異常路徑沒有覆蓋; -- 哪些許可權需要管理員確認。 +- 哪些權限需要管理員確認。 如果平臺只能說“已完成修改”,業務就很難放心。 -一個可治理的自動化引擎應該把變更變成 diff:流程圖層面的 diff、條件層面的 diff、動作層面的 diff、許可權層面的 diff。 +一個可治理的自動化引擎應該把變更變成 diff:流程圖層面的 diff、條件層面的 diff、動作層面的 diff、權限層面的 diff。 這也是後設資料驅動的價值。因為流程是結構化的,平臺才能比較前後差異,而不是讓人去讀指令碼。 @@ -166,8 +166,8 @@ tags: [] ObjectOS 適合承接自然語言改流程,不是因為它把 AI 放在輸入框裡,而是因為流程本身是後設資料。 -自然語言可以生成變更建議,Automation 引擎負責把建議落到節點、連線、條件、等待、審批和動作上。平臺可以校驗結構,展示差異,要求有許可權的人釋出,並保留版本和執行記錄。 +自然語言可以生成變更建議,Automation 引擎負責把建議落到節點、連線、條件、等待、審批和動作上。平臺可以校驗結構,展示差異,要求有權限的人釋出,並保留版本和執行記錄。 這讓“業務人員用自然語言改流程”不再是危險的魔法,而是一種受治理的協作方式。 -未來的企業自動化不應該每次變化都等開發,也不應該讓流程隱藏在腳本里。它應該讓業務語言進入平臺,但最終沉澱為可執行、可審查、可追蹤的流程資產。 +未來的企業自動化不應該每次變化都等開發,也不應該讓流程隱藏在腳本裡。它應該讓業務語言進入平臺,但最終沉澱為可執行、可審查、可追蹤的流程資產。 diff --git a/content/blog/automation-pause-resume-approvals/index.zh-Hant.mdx b/content/blog/automation-pause-resume-approvals/index.zh-Hant.mdx index 30a2909..3bd4426 100644 --- a/content/blog/automation-pause-resume-approvals/index.zh-Hant.mdx +++ b/content/blog/automation-pause-resume-approvals/index.zh-Hant.mdx @@ -85,7 +85,7 @@ tags: [] 這些都不是“立即執行”。它們需要在等待期間保留業務狀態,等訊號回來後繼續。 -如果平臺不支援暫停恢復,就會讓每個模組自己儲存狀態。最後系統裡會出現很多半流程:審批表裡一段、定時任務裡一段、業務物件裡一段、腳本里一段。 +如果平臺不支援暫停恢復,就會讓每個模組自己儲存狀態。最後系統裡會出現很多半流程:審批表裡一段、定時任務裡一段、業務物件裡一段、腳本裡一段。 ## 審批通過和拒絕應該進入不同分支 diff --git a/content/blog/automation-trigger-model/index.zh-Hant.mdx b/content/blog/automation-trigger-model/index.zh-Hant.mdx index a27eb62..961fc2c 100644 --- a/content/blog/automation-trigger-model/index.zh-Hant.mdx +++ b/content/blog/automation-trigger-model/index.zh-Hant.mdx @@ -50,7 +50,7 @@ tags: [] 如果每個入口都單獨寫邏輯,就會出現規則漂移:定時任務走一套判斷,按鈕走另一套判斷,外部表單又走第三套判斷。 -統一觸發模型的價值,是讓不同入口進入同一個流程執行時。觸發方式可以不同,但判斷、動作、許可權和日誌應該一致。 +統一觸發模型的價值,是讓不同入口進入同一個流程執行時。觸發方式可以不同,但判斷、動作、權限和日誌應該一致。 ## 記錄變化觸發:讓資料狀態推動流程 diff --git a/content/blog/beyond-agentforce-copilot-open-runtime/index.zh-Hant.mdx b/content/blog/beyond-agentforce-copilot-open-runtime/index.zh-Hant.mdx index 6859487..12e717f 100644 --- a/content/blog/beyond-agentforce-copilot-open-runtime/index.zh-Hant.mdx +++ b/content/blog/beyond-agentforce-copilot-open-runtime/index.zh-Hant.mdx @@ -2,7 +2,7 @@ # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: Agentforce、Copilot Studio 之外:何時選擇開放自託管執行時 author: ObjectStack Team -description: Agentforce、Copilot Studio、ServiceNow AI Agents 在各自生態內都很強。問題是你的資料、流程和許可權是否也在同一個生態內;若不是,開放自託管執行時或混合架構可能更穩。 +description: Agentforce、Copilot Studio、ServiceNow AI Agents 在各自生態內都很強。問題是你的資料、流程和權限是否也在同一個生態內;若不是,開放自託管執行時或混合架構可能更穩。 date: 2026-06-16T11:00:00+08:00 status: published topic: ai-agents @@ -16,11 +16,11 @@ tags: - ServiceNow --- -**先給結論**:套件型 agent 平臺在自家生態裡最強——前提是你的資料、流程、身份和許可權也主要在那個生態裡。當業務散在多系統、資料要自持、模型要可選時,開放自託管執行時,或者套件與自託管執行時混用,才更接近真實企業的結構。 +**先給結論**:套件型 agent 平臺在自家生態裡最強——前提是你的資料、流程、身份和權限也主要在那個生態裡。當業務散在多系統、資料要自持、模型要可選時,開放自託管執行時,或者套件與自託管執行時混用,才更接近真實企業的結構。 一家公司做 AI agent 選型,入圍名單很自然:Agentforce、Copilot Studio、ServiceNow AI Agents。三家都強,都有人推薦。 -他們差點就簽了 Agentforce——CRM 場景演示得最漂亮。臨門一腳前,一位架構師提了個問題:"我們要讓 agent 處理的客戶問題,一半要查 Salesforce 裡的商機,一半要查我們自建系統裡的交付和工單。生態外那一半資料怎麼納入同一個許可權和口徑?" +他們差點就簽了 Agentforce——CRM 場景演示得最漂亮。臨門一腳前,一位架構師提了個問題:"我們要讓 agent 處理的客戶問題,一半要查 Salesforce 裡的商機,一半要查我們自建系統裡的交付和工單。生態外那一半資料怎麼納入同一個權限和口徑?" 銷售的回答是"可以做整合"。於是他們花了六週做了個整合 PoC。結論很清楚:能連,但每加一個生態外系統,就要重寫一套同步、對齊一次口徑、維護一條會斷的管道——而他們生態外的系統有七八個。那一刻團隊才意識到:**問題不在 Agentforce 不夠好,而在它假設了一個對這家公司不成立的前提。** @@ -28,7 +28,7 @@ tags: ## 那個沒說出口的前提:你的世界主要在同一個生態裡 -這些套件的強,本質是"**生態內最優**"。Agentforce 最適合 Salesforce 裡的客戶、流程和物件;Copilot Studio 與 Microsoft 365、Power Platform、Teams、SharePoint、Entra 的結合最順;ServiceNow AI Agents 則天然貼近 ServiceNow 上的流程。前提成立時,它們確實省心——資料現成、許可權現成、整合現成,agent 幾乎順手就接上。 +這些套件的強,本質是"**生態內最優**"。Agentforce 最適合 Salesforce 裡的客戶、流程和物件;Copilot Studio 與 Microsoft 365、Power Platform、Teams、SharePoint、Entra 的結合最順;ServiceNow AI Agents 則天然貼近 ServiceNow 上的流程。前提成立時,它們確實省心——資料現成、權限現成、整合現成,agent 幾乎順手就接上。 可這個前提,對很多企業並不成立。真實的企業長這樣:CRM 一家、ERP 另一家、工單第三家,外加一堆自建系統和電子表格;它們想保留模型選擇權,因為模型一年一個樣;它們受監管約束,資料不能隨便出域。對這樣的企業,"生態內最優"反而成了約束——因為業務本來就跨多個系統。每接一個生態外系統都要重寫一條管道,正是那家公司在 PoC 裡撞到的邊界。 @@ -65,7 +65,7 @@ tags: 這就引出一個被選型討論長期忽略的選項:**這不一定是單選題。** -最務實的架構,往往是混合的:在你確實重度使用的那個生態裡,繼續用它的套件——Salesforce 裡的銷售 agent 就讓 Agentforce 幹它最擅長的;但在**跨系統、要統一口徑、要自持資料**的那一層,用一個開放、自託管的執行時來做連線組織。後者不取代套件,它做的是套件結構上做不好的那件事:把散在多個牆裡的業務,收成一份你自己持有的、帶許可權和審計的統一定義。 +最務實的架構,往往是混合的:在你確實重度使用的那個生態裡,繼續用它的套件——Salesforce 裡的銷售 agent 就讓 Agentforce 幹它最擅長的;但在**跨系統、要統一口徑、要自持資料**的那一層,用一個開放、自託管的執行時來做連線組織。後者不取代套件,它做的是套件結構上做不好的那件事:把散在多個牆裡的業務,收成一份你自己持有的、帶權限和審計的統一定義。 換句話說,開放執行時可以是你多個系統(包括那些套件)之上的**連線組織**,而不是又一堵要你搬家進去的牆。承認這一點,選型就從"押哪一家"變成了"哪部分用套件、哪部分用開放"——這才是大多數真實企業最後落地的樣子。 @@ -91,7 +91,7 @@ export const Customer = ObjectSchema.create({ - **之前**:agent 接 Salesforce,看到商機活躍,答"值得";它壓根不知道自建系統裡這個客戶的交付一直在延期、工單積壓。 - **之後**:agent 面對的是**一個**統一的客戶,商機、交付、工單一起看,答"商機不錯,但交付風險高,先解決履約再談擴單"。 -同一個模型、同一個問題,只因為腳下的"客戶"不再被牆切開,結論就從片面變成了全域性。而這一切不需要為每個牆外系統重寫同步管道——業務定義是你倉庫裡可 diff、可遷移的後設資料;執行時跑在你自己的基礎設施上,強制許可權、記錄審計;模型可以來自外部任何一家。你沒有把"自己業務的定義"交給任何一家保管。 +同一個模型、同一個問題,只因為腳下的"客戶"不再被牆切開,結論就從片面變成了全域性。而這一切不需要為每個牆外系統重寫同步管道——業務定義是你倉庫裡可 diff、可遷移的後設資料;執行時跑在你自己的基礎設施上,強制權限、記錄審計;模型可以來自外部任何一家。你沒有把"自己業務的定義"交給任何一家保管。 ## 一個誠實的選擇題 diff --git a/content/blog/business-app-in-16k-tokens/index.zh-Hant.mdx b/content/blog/business-app-in-16k-tokens/index.zh-Hant.mdx index 6c8cf70..c7a7479 100644 --- a/content/blog/business-app-in-16k-tokens/index.zh-Hant.mdx +++ b/content/blog/business-app-in-16k-tokens/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: "一個業務應用到底有多少 token?完整 CRM 全應用不到 150k" -description: "完整 CRM 的資料模型、流程、許可權與介面合計不到 150k token:業務邏輯不到 100k,UI 約 50k;隨包參考 CRM 仍約 16k。能整體裝進智慧體上下文的軟體,維護方式完全不同。" +description: "完整 CRM 的資料模型、流程、權限與介面合計不到 150k token:業務邏輯不到 100k,UI 約 50k;隨包參考 CRM 仍約 16k。能整體裝進智慧體上下文的軟體,維護方式完全不同。" author: ObjectStack Team date: 2026-07-22 status: published @@ -15,7 +15,7 @@ tags: - AI 智慧體 --- -**一句話版本:** 一套完整 CRM 可以壓進不到 **150,000 token** 的型別化後設資料:業務邏輯——全部物件、流程、動作和許可權——不到 **100,000 token**,宣告式 UI 約增加 **50,000 token**。隨包的 `app-crm` 參考樣例更小:31 個檔案、1792 行,約 **16,000 token**。這個 16k 描述的是參考樣例,不是產品級完整 CRM 的上限。兩者都裝得進 200k 上下文視窗。我們稱之為**上下文體量的軟體(context-sized software)**:小到 AI 智慧體能整體裝入、推理和重構,而人只需審閱變更 diff。 +**一句話版本:** 一套完整 CRM 可以壓進不到 **150,000 token** 的型別化後設資料:業務邏輯——全部物件、流程、動作和權限——不到 **100,000 token**,宣告式 UI 約增加 **50,000 token**。隨包的 `app-crm` 參考樣例更小:31 個檔案、1792 行,約 **16,000 token**。這個 16k 描述的是參考樣例,不是產品級完整 CRM 的上限。兩者都裝得進 200k 上下文視窗。我們稱之為**上下文體量的軟體(context-sized software)**:小到 AI 智慧體能整體裝入、推理和重構,而人只需審閱變更 diff。 ## 自己算一遍 @@ -30,7 +30,7 @@ find objectstack/examples/app-crm/src -name '*.ts' -not -name '*.test.ts' \ | 系統 | 檔案數 | 行數 | ≈ Token | 能裝進 200k 上下文? | |---|---:|---:|---:|---| -| CRM 示例([`app-crm`](https://github.com/objectstack-ai/objectstack/tree/main/examples/app-crm))——物件、檢視、儀表盤、流程、許可權、翻譯 | 31 | 1792 | ~16k | 能——還有 12 倍餘量 | +| CRM 示例([`app-crm`](https://github.com/objectstack-ai/objectstack/tree/main/examples/app-crm))——物件、檢視、儀表盤、流程、權限、翻譯 | 31 | 1792 | ~16k | 能——還有 12 倍餘量 | | [HotCRM](https://github.com/objectstack-ai/hotcrm)——完整的市場級 CRM:15 個物件、17 個流程、4 個儀表盤、2 個 AI copilot、4 種語言 | 132 | ~18,000 | 總計不到 150k(業務邏輯不到 100k + UI 約 50k) | 能——餘量超過 50k | | 傳統手寫 CRM 程式碼庫 | 數千 | 30 萬–100 萬+ | 數百萬 | 差得遠 | @@ -41,7 +41,7 @@ find objectstack/examples/app-crm/src -name '*.ts' -not -name '*.test.ts' \ 五十年來我們用程式碼行數度量軟體,因為約束條件是人類讀者。現在讀者換了。AI 智慧體要*安全地*修改一個系統,得先把系統裝進上下文——這把所有程式碼庫分成兩種狀態: - **系統大於上下文。** 智慧體只能 grep、抽樣、猜測。它的修改是區域性的,錯誤卻是全域性的。每次變更都是隔著鑰匙孔做考古。 -- **系統小於上下文。** 智慧體一次讀完所有東西——每個物件、每條許可權規則、每個依賴。*「改這裡會弄壞什麼?」*從一個願望變成一個可回答的問題。跨領域的變更——把一個概念在資料模型、許可權、API 和介面裡統一重新命名——是一個連貫的 diff。 +- **系統小於上下文。** 智慧體一次讀完所有東西——每個物件、每條權限規則、每個依賴。*「改這裡會弄壞什麼?」*從一個願望變成一個可回答的問題。跨領域的變更——把一個概念在資料模型、權限、API 和介面裡統一重新命名——是一個連貫的 diff。 這不是漸進式改善,是狀態切換。而分界線就畫在你的上下文視窗所在的位置。 @@ -50,7 +50,7 @@ find objectstack/examples/app-crm/src -name '*.ts' -not -name '*.test.ts' \ 不靠壓縮技巧,靠刪除。一個企業應用是兩樣東西交織在一起: - **決策。** 有哪些物件、它們如何關聯、誰能看到哪個欄位、線索轉化時發生什麼。這是你的業務**本體(ontology)**,真正不可約減——只有你能做這些決定。 -- **管道。** 資料表、CRUD 介面、列表頁和詳情頁、許可權中介軟體、審計寫入。這些在古往今來每一個業務應用裡幾乎一模一樣——也就意味著它們是*可派生的*。 +- **管道。** 資料表、CRUD 介面、列表頁和詳情頁、權限中介軟體、審計寫入。這些在古往今來每一個業務應用裡幾乎一模一樣——也就意味著它們是*可派生的*。 ObjectStack 押的注是:製品裡只保留決策,管道全部由執行時派生。在隨包參考 CRM 裡,那 1792 行*就是*決策清單——型別化、經 Zod 校驗的後設資料。資料庫 schema、REST API、渲染後的介面和 MCP 工具在每次啟動時由它計算出來。可派生的東西一概不儲存,所以不會漂移。到了完整 HotCRM,這種分離仍把業務邏輯控制在 100k token 以內;宣告式 UI 約增加 50k,使全應用保持在 150k 以內。 @@ -66,7 +66,7 @@ ObjectStack 押的注是:製品裡只保留決策,管道全部由執行時 ## 軟體達到上下文體量後,什麼變了 -1. **評審變成真的。** 1792 行是一次程式碼評審;30 萬行是一場儀式。人能讀完整個 diff,校驗門和執行時的許可權、審計強制在後面兜底。 +1. **評審變成真的。** 1792 行是一次程式碼評審;30 萬行是一場儀式。人能讀完整個 diff,校驗門和執行時的權限、審計強制在後面兜底。 2. **維護不再腐爛。** 整個系統裝得進上下文時,智慧體是整體重構,而不是修補它看得見的那部分。企業軟體常見的熵增曲線——每次變更都比上一次更危險——被拉平了。 3. **本體始終歸你。** 定義是 Apache-2.0 的開放格式,是你倉庫裡的普通檔案——人能讀,任何智慧體能寫,可跨執行時遷移。 @@ -79,4 +79,4 @@ npm create objectstack@latest my-app && cd my-app npx os dev --ui # 應用已執行——把下一個需求直接告訴你的智慧體 ``` -更想在瀏覽器裡完成?[ObjectOS](https://www.objectos.ai) 是同一個思路的託管形態——線上構建與問詢,內建 AI Builder、許可權與審計。 +更想在瀏覽器裡完成?[ObjectOS](https://www.objectos.ai) 是同一個思路的託管形態——線上構建與問詢,內建 AI Builder、權限與審計。 diff --git a/content/blog/conversational-app-iteration/index.zh-Hant.mdx b/content/blog/conversational-app-iteration/index.zh-Hant.mdx index 0399aa9..7abb88f 100644 --- a/content/blog/conversational-app-iteration/index.zh-Hant.mdx +++ b/content/blog/conversational-app-iteration/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 對話式應用迭代:加欄位、改流程、生成檢視和自動化 -description: AI Builder 的真正價值不是“聊一句就改”,而是把欄位、流程、檢視、許可權和自動化都落到可審查、可回滾的後設資料層。 +description: AI Builder 的真正價值不是“聊一句就改”,而是把欄位、流程、檢視、權限和自動化都落到可審查、可回滾的後設資料層。 author: ObjectStack Team date: 2026-06-05T10:10:00+08:00 status: published @@ -13,11 +13,11 @@ cover: ./cover.svg tags: [] --- -**先給結論**:對話式改系統真正的價值,不是“聊一句就改”,而是每次加欄位、改流程、調許可權都落到可審查、可回滾的後設資料層——改得快,還改得安全。 +**先給結論**:對話式改系統真正的價值,不是“聊一句就改”,而是每次加欄位、改流程、調權限都落到可審查、可回滾的後設資料層——改得快,還改得安全。 業務系統上線以後,真正的工作才開始。 -客服主管想加欄位,銷售總監想改階段,財務想加審批,法務想調風險規則,運營想多一個看板,IT 想收緊許可權。傳統軟體開發裡,這些都是需求單,要排期、評估、開發、測試、上線。 +客服主管想加欄位,銷售總監想改階段,財務想加審批,法務想調風險規則,運營想多一個看板,IT 想收緊權限。傳統軟體開發裡,這些都是需求單,要排期、評估、開發、測試、上線。 AI Builder 最值得期待的地方,是讓其中一大部分變化從“提需求”變成“對話修改”。 @@ -33,7 +33,7 @@ AI Builder 最值得期待的地方,是讓其中一大部分變化從“提需 - AI 會不會改錯物件; - 加欄位會不會影響已有表單; - 改流程會不會影響正在審批的單據; -- 許可權變化會不會造成資料洩露; +- 權限變化會不會造成資料洩露; - 自動化會不會發錯通知; - Agent 會不會執行越權動作; - 改完以後能不能回滾。 @@ -54,7 +54,7 @@ AI Builder 最值得期待的地方,是讓其中一大部分變化從“提需 | 欄位 | 新增列舉欄位 `renewal_risk` | | 表單 | 在客戶詳情和編輯頁展示 | | 檢視 | 新增“高風險續約客戶”看板 | -| 許可權 | 客戶成功經理可編輯,銷售只讀 | +| 權限 | 客戶成功經理可編輯,銷售只讀 | | 自動化 | 高風險變化時提醒負責人 | | Agent | 客戶摘要允許引用該欄位 | @@ -82,7 +82,7 @@ Builder 應該生成: 同時,它應該提示影響範圍:這個流程隻影響新提交的報銷,還是也影響已在審批中的報銷?如果影響存量流程,是否需要遷移? -這是低程式碼平臺裡非常關鍵的專業細節。流程不是畫出來就結束,它還和執行中的例項有關。 +這是低程式碼平臺裡非常關鍵的專業細節。流程不是畫出來就結束,它還和執行中的實例有關。 ## 第三類修改:生成檢視 @@ -96,7 +96,7 @@ Builder 應該生成: - 物件:專案; - 篩選:風險等級為高,且預計影響本週里程碑; -- 許可權:只看當前使用者負責或參與的專案; +- 權限:只看當前使用者負責或參與的專案; - 排序:預計延期天數降序; - 欄位:專案名、負責人、里程碑、風險原因、下一步動作; - 展示:列表或看板。 @@ -107,15 +107,15 @@ Builder 應該生成: 這時它不是重建頁面,而是修改檢視後設資料。 -## 第四類修改:調整許可權 +## 第四類修改:調整權限 -許可權是對話式修改裡最需要謹慎的部分。 +權限是對話式修改裡最需要謹慎的部分。 使用者說: > 銷售只能看自己負責的客戶,區域經理可以看本區域客戶,老闆可以看全部客戶。 -這句話看起來清楚,但平臺必須生成並展示許可權矩陣: +這句話看起來清楚,但平臺必須生成並展示權限矩陣: | 角色 | 記錄範圍 | 欄位範圍 | 可執行動作 | | --- | --- | --- | --- | @@ -123,9 +123,9 @@ Builder 應該生成: | 區域經理 | 本區域客戶 | 可看彙總金額 | 分配負責人、檢視風險 | | 管理層 | 全部客戶 | 可看彙總,不一定能改 | 檢視報表、匯出需審批 | -同時,Agent 查詢也必須繼承這套許可權。銷售問“所有高風險客戶有哪些”,系統只能返回他有權看的客戶。 +同時,Agent 查詢也必須繼承這套權限。銷售問“所有高風險客戶有哪些”,系統只能返回他有權看的客戶。 -AI 可以幫助配置許可權,但不能讓許可權配置變得輕率。 +AI 可以幫助配置權限,但不能讓權限配置變得輕率。 ## 第五類修改:建立自動化和 Agent 動作 @@ -154,9 +154,9 @@ AI 可以幫助配置許可權,但不能讓許可權配置變得輕率。 ## 好的對話式修改應該有 4 個產品細節 -第一,展示變更計劃。使用者應該知道平臺準備改哪些物件、欄位、檢視、流程、許可權和自動化。 +第一,展示變更計劃。使用者應該知道平臺準備改哪些物件、欄位、檢視、流程、權限和自動化。 -第二,展示影響範圍。尤其是許可權、流程和自動化,要說明影響哪些角色、哪些資料、哪些執行中例項。 +第二,展示影響範圍。尤其是權限、流程和自動化,要說明影響哪些角色、哪些資料、哪些執行中實例。 第三,支援預覽和回滾。修改前能預覽,修改後能回滾到上一個版本。 @@ -168,8 +168,8 @@ AI 可以幫助配置許可權,但不能讓許可權配置變得輕率。 ObjectStack 適合做對話式應用迭代,是因為它把應用結構放在後設資料層。 -欄位、檢視、流程、許可權、自動化和 Agent 工具不是散落在程式碼裡,而是可以被生成、解釋、修改、版本化和審計的業務結構。 +欄位、檢視、流程、權限、自動化和 Agent 工具不是散落在程式碼裡,而是可以被生成、解釋、修改、版本化和審計的業務結構。 -業務人員用自然語言說出變化,平臺生成變更計劃;管理員或業務 owner 確認後,執行時按新後設資料工作;Agent 也繼承同樣的物件、許可權和動作邊界。 +業務人員用自然語言說出變化,平臺生成變更計劃;管理員或業務 owner 確認後,執行時按新後設資料工作;Agent 也繼承同樣的物件、權限和動作邊界。 這就是用對話改業務系統的關鍵:不是讓 AI 幫你臨時改一個功能,而是讓業務系統具備持續被業務語言塑造的能力,同時仍然保持低程式碼平臺應有的治理能力。 diff --git a/content/blog/crm-ai-understands-customers/index.zh-Hant.mdx b/content/blog/crm-ai-understands-customers/index.zh-Hant.mdx index 467fe90..717e4c2 100644 --- a/content/blog/crm-ai-understands-customers/index.zh-Hant.mdx +++ b/content/blog/crm-ai-understands-customers/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. -title: CRM AI:讓 agent 在許可權內讀取客戶和商機 -description: 很多公司的 CRM 裡已有客戶、商機、聯絡人和跟進記錄。真正有價值的做法不是匯出資料問一次,而是讓 agent 在許可權之下讀懂這些業務物件。 +title: CRM AI:讓 agent 在權限內讀取客戶和商機 +description: 很多公司的 CRM 裡已有客戶、商機、聯絡人和跟進記錄。真正有價值的做法不是匯出資料問一次,而是讓 agent 在權限之下讀懂這些業務物件。 author: ObjectStack Team date: 2026-06-03 status: published @@ -13,10 +13,10 @@ industries: [] cover: ./cover.jpg tags: - AI 智慧體 - - 智慧體許可權 + - 智慧體權限 --- -**先給結論**:讓 AI 用起 CRM 的正確順序,是先在許可權之下讀懂客戶、商機和跟進記錄,再從只讀分析走到建議、最後才到受控執行——而不是繞過 CRM 另起爐灶。 +**先給結論**:讓 AI 用起 CRM 的正確順序,是先在權限之下讀懂客戶、商機和跟進記錄,再從只讀分析走到建議、最後才到受控執行——而不是繞過 CRM 另起爐灶。 如果一家公司只能先選一個系統接 AI,我會建議從 CRM 開始。 @@ -49,7 +49,7 @@ tags: 這些問題聽起來簡單,但在傳統 CRM 裡並不好答。因為答案往往散在多個地方:客戶 表、聯絡人表、商機表、活動記錄、報價單、合同、工單、郵件備註。 -人要拼起來很慢。AI 如果能在許可權之下把這些物件串起來,就能立刻變成一個銷售 +人要拼起來很慢。AI 如果能在權限之下把這些物件串起來,就能立刻變成一個銷售 管理助手。 ## 一個真實的工作畫面 @@ -85,8 +85,8 @@ tags: **第一種,資料是散的。** 客戶在一張表,聯絡人在另一張表,商機又是另一套欄位, 還有自定義備註、附件、工單、合同。人知道它們的關係,AI 不知道。 -**第二種,許可權是糊的。** 銷售只能看自己的客戶,區域經理能看區域,老闆能看全域性。 -如果 AI 一接入就拿管理員許可權,那就不是智慧化,而是越權。 +**第二種,權限是糊的。** 銷售只能看自己的客戶,區域經理能看區域,老闆能看全域性。 +如果 AI 一接入就拿管理員權限,那就不是智慧化,而是越權。 **第三種,語義是缺的。** 資料庫裡可能叫 `acct_id`、`opp_stage`、`last_touch_at`。 程式設計師知道是什麼意思,銷售知道業務含義,但 AI 只能看到一堆欄位名。 @@ -177,7 +177,7 @@ CRM 很少是孤島。 如果 AI 只能讀 CRM,它看到的還是區域性真相。 -更有價值的是,讓 AI 在許可權之下跨系統理解客戶: +更有價值的是,讓 AI 在權限之下跨系統理解客戶: - CRM 裡的客戶和商機; - 工單系統裡的問題和滿意度; @@ -186,7 +186,7 @@ CRM 很少是孤島。 - 合同系統裡的條款和續約日期。 這就是為什麼我們一直強調“連線現有系統”,而不是把所有東西重做一遍。企業的資料 -本來就分佈在不同系統裡,AI 需要的是一個能理解物件、關係和許可權的業務層。 +本來就分佈在不同系統裡,AI 需要的是一個能理解物件、關係和權限的業務層。 ## 一個好的 CRM AI 專案,應該從這 5 個問題開始 @@ -203,20 +203,20 @@ CRM 很少是孤島。 ## ObjectOS 的做法:讓 AI 讀懂 CRM,而不是繞過 CRM ObjectOS 不要求你先換掉 CRM。更現實的路徑是:連線現有 CRM 的資料庫或 API, -把關鍵表建模為物件,讓 AI 通過物件和許可權訪問業務資料。 +把關鍵表建模為物件,讓 AI 通過物件和權限訪問業務資料。 這樣,AI 既能理解“客戶、商機、聯絡人、跟進記錄”這些業務概念,又不會繞過已有 -許可權和審計。 +權限和審計。 對企業來說,這才是 CRM 接 AI 的起點: - 資料不搬家; - 業務系統不重做; -- 許可權不繞過; +- 權限不繞過; - 先只讀,後建議,再自動化; - 每一步都可審計。 AI 進入 CRM 的價值,不是讓銷售少填幾個欄位,而是讓管理層終於能即時看懂客戶和 商機的真實狀態。 -先把這層物件和許可權建清楚,再談自動執行,CRM AI 才不會從一個演示變成新的資料風險。 +先把這層物件和權限建清楚,再談自動執行,CRM AI 才不會從一個演示變成新的資料風險。 diff --git a/content/blog/enterprise-agent-true-cost/index.zh-Hant.mdx b/content/blog/enterprise-agent-true-cost/index.zh-Hant.mdx index 9af5cab..2a7ecd4 100644 --- a/content/blog/enterprise-agent-true-cost/index.zh-Hant.mdx +++ b/content/blog/enterprise-agent-true-cost/index.zh-Hant.mdx @@ -76,7 +76,7 @@ $250,000 = $0.10 × 年動作數 1. **用量賬:成本會不會隨成功暴漲?** 這就是 CFO 那張四倍賬單——你的用量是否和 agent 的成功正相關。是,按動作就是個陷阱。 2. **合規賬:資料出域的代價。** 按動作、按席位的 SaaS 往往意味著業務資料持續流向廠商雲。隨著 EU AI Act 分階段適用、歐洲繼續推進雲與 AI 主權框架,資料駐留和證據鏈不再只是安全團隊的偏好,而會進入採購和審計問題清單。 -3. **鎖定賬:將來走不掉的代價。** 當業務定義、流程、許可權都長在某家平臺裡,遷移成本隨使用時間複利上漲。你以為在為軟體付費,其實在為"將來走不掉"付押金。 +3. **鎖定賬:將來走不掉的代價。** 當業務定義、流程、權限都長在某家平臺裡,遷移成本隨使用時間複利上漲。你以為在為軟體付費,其實在為"將來走不掉"付押金。 把這三筆一起算,"一毛錢一個動作"那點表面便宜,很快被吃光。 @@ -85,7 +85,7 @@ $250,000 = $0.10 × 年動作數 核心是一個清晰的分工:**ObjectStack 是執行業務定義的開放引擎與執行時;ObjectOS 收費的是同一個 ObjectStack 應用的生產運營體驗,而不是第二套引擎或每次執行時呼叫。** 這套體驗包括 Build 與 Ask、團隊控制、託管或私有部署,以及支援。由此: - **成本與用量解耦。** ObjectStack 執行時在你的基礎設施上執行業務定義,agent 呼叫受治理工具的次數再多,執行時也不按次收費——成本由基礎設施決定,可預測、可規劃。ObjectOS 定價覆蓋的是應用的生產運營,不是對執行時呼叫計次。 -- **資料不出域。** 物件、許可權、審計證據都留在你自己的基礎設施裡,合規風險和資料出域成本一起降。 +- **資料不出域。** 物件、權限、審計證據都留在你自己的基礎設施裡,合規風險和資料出域成本一起降。 - **不被鎖定。** 業務定義是開放協議(Apache 2.0)下你倉庫裡的後設資料,可 diff、可遷移。你從 ObjectOS 購買的是同一個開放 ObjectStack 應用的生產運營體驗,不是一套無法退出的專有執行時。 ## 結語 diff --git a/content/blog/enterprise-ontology-race-open-vs-closed/index.zh-Hant.mdx b/content/blog/enterprise-ontology-race-open-vs-closed/index.zh-Hant.mdx index 434adde..6aacd06 100644 --- a/content/blog/enterprise-ontology-race-open-vs-closed/index.zh-Hant.mdx +++ b/content/blog/enterprise-ontology-race-open-vs-closed/index.zh-Hant.mdx @@ -131,7 +131,7 @@ MCP 端點是一條讀取通道,不是一張地契。你的 agent 得到了一 第三,**也是對本文立場最強的一條反駁:廠商們正在自己把定義層標準化。** Snowflake 與 Salesforce、dbt Labs、BlackRock、RelationalAI 共同發起了 Open Semantic Interchange;2026 年 7 月,這個專案以 **Apache Ossie** 的身份進入 Apache 孵化器,成員組織超過 50 家,其中包括 Databricks、Oracle 和 Collibra。Databricks 還在單獨把自己的指標檢視實現開源進 Apache Spark。這是真事,比大多數中立層努力推進得都快;今天再說"封閉平臺永遠不會收斂",就是在跟證據吵架。 -但要看清這輪收斂停在了哪裡。Ossie 覆蓋的是**分析型**語義——指標、維度、關係。動作與許可權不在範圍內。也就是說,你本體中**描述**業務的那一半正在變得可遷移,而**改變**業務的那一半——操作本身、誰有權執行、以及什麼被寫進審計日誌——仍然是專有的。這不是一個小尾巴。它恰恰是決定 agent 能不能做事的那一半,也恰恰是分裂代價最高的那一半。 +但要看清這輪收斂停在了哪裡。Ossie 覆蓋的是**分析型**語義——指標、維度、關係。動作與權限不在範圍內。也就是說,你本體中**描述**業務的那一半正在變得可遷移,而**改變**業務的那一半——操作本身、誰有權執行、以及什麼被寫進審計日誌——仍然是專有的。這不是一個小尾巴。它恰恰是決定 agent 能不能做事的那一半,也恰恰是分裂代價最高的那一半。 這三條都沒有說封閉更好。它們說的是:開放也要花力氣、也有風險、而且有一半正在被對方迎上來。把它們和另一邊的下行風險放在一起稱——把業務定義鎖進一家平臺,然後讓它散在五家之間。兩邊都不是免費的;只是其中一邊,把最核心的資產攥在了你自己手裡。 @@ -170,13 +170,13 @@ os start # 同一份定義,跑在你自己的基礎設施上 # 然後把任意模型指向它——Claude、GPT、Gemini 都行,執行時不變 ``` -現在再問那個要命的問題:"H 集團明年續約風險多高?"agent 面對的是**一個**統一的、帶許可權和審計的"客戶":訂單健康,但疊著兩次高管級投訴和一筆 90 天回款爭議——它會答"高風險,建議提前介入"。同一個模型、同一個問題,只因為腳下的定義不再分裂,結論從"丟了幾百萬"變成了"提前一個季度預警"。 +現在再問那個要命的問題:"H 集團明年續約風險多高?"agent 面對的是**一個**統一的、帶權限和審計的"客戶":訂單健康,但疊著兩次高管級投訴和一筆 90 天回款爭議——它會答"高風險,建議提前介入"。同一個模型、同一個問題,只因為腳下的定義不再分裂,結論從"丟了幾百萬"變成了"提前一個季度預警"。 MCP 那一點在這裡同樣成立,而且方向恰好是對的:同一份定義,正是執行時作為受治理工具交給 agent 的那一份——讀取通道是開放的,**同時**定義是你的。這正是[為什麼定義與執行時都該開放](/zh-Hant/blog/ai-ontology-open-protocol/)完整論證的那件事。 這就是 ObjectStack 與 ObjectOS 的分工,也是它對這場競賽的回答: -- **ObjectStack**——一份 **open business ontology**(開放業務本體):開放的定義協議與開源自託管執行時(Apache 2.0)。定義存在你倉庫裡,任意廠商的 agent 都能讀,執行時負責校驗和執行,並強制許可權、記錄審計; +- **ObjectStack**——一份 **open business ontology**(開放業務本體):開放的定義協議與開源自託管執行時(Apache 2.0)。定義存在你倉庫裡,任意廠商的 agent 都能讀,執行時負責校驗和執行,並強制權限、記錄審計; - **ObjectOS**——同一 ObjectStack 應用可選的商業生產平臺與運營體驗:支援雲端或自管部署,增加瀏覽器 AI 構建、部署和運營能力,但不取代底層開放定義與執行時。 開放定義與自託管執行時保持中立,商業生產體驗才是產品競爭的地方。和 SQL 與資料庫廠商、LSP 與編輯器廠商的關係,是同一種。 diff --git a/content/blog/eu-ai-act-runtime-audit/index.zh-Hant.mdx b/content/blog/eu-ai-act-runtime-audit/index.zh-Hant.mdx index 0c34296..b8c8393 100644 --- a/content/blog/eu-ai-act-runtime-audit/index.zh-Hant.mdx +++ b/content/blog/eu-ai-act-runtime-audit/index.zh-Hant.mdx @@ -42,10 +42,10 @@ tags: [] | 審計員會問 | 它在查什麼 | 答不上來的後果 | | --- | --- | --- | | 這些資料處理得合法嗎? | 資料在哪、誰能讀、有沒有出過歐盟 | 資料駐留違規,CLOUD Act 暴露 | -| 這個動作誰授權 AI 做的? | 拒賠、放款這類動作按誰的許可權算 | 責任無法歸屬,動作不可控 | +| 這個動作誰授權 AI 做的? | 拒賠、放款這類動作按誰的權限算 | 責任無法歸屬,動作不可控 | | AI 參與的那步留痕了嗎? | 能否拿出完整、不可抵賴的證據鏈 | 審計直接失敗 | -沒有一個問題是關於模型的。它們全都關於模型之外那一層——承載資料、強制許可權、記錄證據的執行時。 +沒有一個問題是關於模型的。它們全都關於模型之外那一層——承載資料、強制權限、記錄證據的執行時。 ## AI Act 對"高風險系統"到底要什麼 @@ -56,7 +56,7 @@ tags: [] | 自動記錄事件日誌(可追溯) | 執行時的審計賬 | 不能,模型不留痕 | | 人類監督(關鍵決策可介入、可推翻) | 執行時的審批與流程 | 不能,要靠流程強制 | | 決策可解釋(依據了什麼) | 執行時記錄的輸入與規則 | 部分,但不可抵賴的記錄在執行時 | -| 資料治理(來源、許可權、駐留) | 執行時的許可權與部署 | 不能 | +| 資料治理(來源、權限、駐留) | 執行時的權限與部署 | 不能 | 你會發現,模型再強,這張表它一欄都打不了勾。這正是那麼多團隊"模型選得很認真、合規卻過不了"的根因——他們在錯的那一層用功。監管要的東西,結構性地長在執行時上。 @@ -68,7 +68,7 @@ tags: [] 這條路能解決一部分,但解決不了那個會議室裡的問題。 -合規工具和認證做的是**記錄與背書**:它告訴監管"我們有流程、有文件、有資料處理協議"。但審計員要的不是"你有沒有流程",是"把*這一筆*的完整經過調出來"。**文件證明不了某一次具體動作的合法性,DPA 也回答不了'這筆拒賠是 AI 依據哪條許可權做的、誰複核的'。** 這類證據只能由真正執行那個動作的執行時,在動作發生的當下記下來。買工具能幫你管住"制度層",管不住"動作層"——而審計追到最後,問的總是某一個具體動作。 +合規工具和認證做的是**記錄與背書**:它告訴監管"我們有流程、有文件、有資料處理協議"。但審計員要的不是"你有沒有流程",是"把*這一筆*的完整經過調出來"。**文件證明不了某一次具體動作的合法性,DPA 也回答不了'這筆拒賠是 AI 依據哪條權限做的、誰複核的'。** 這類證據只能由真正執行那個動作的執行時,在動作發生的當下記下來。買工具能幫你管住"制度層",管不住"動作層"——而審計追到最後,問的總是某一個具體動作。 ## 可審計性,是補不上的 @@ -81,24 +81,24 @@ tags: [] 去審計室之前,先用這五個問題自查——任何一個答不出"是",那一項就是你的風險點: 1. 隨便挑一筆 AI 參與的業務動作,能不能當場調出它的完整經過? -2. 許可權是執行時**強制**的,還是寫在**提示詞**裡的? +2. 權限是執行時**強制**的,還是寫在**提示詞**裡的? 3. 人和 agent 的動作,是不是記在**同一本**審計賬上? 4. 這些資料和處理過程,落在誰的**管轄權**之下? 5. 出了問題,能不能**一鍵停下**某個 agent 或某類動作? ## 為什麼"把規則寫進提示詞"過不了這一關 -不少團隊其實做了治理,只是做錯了地方——寫進了提示詞。"你只能查當前使用者有許可權的資料""高風險理賠要人工複核",平時看著也管用。但它過不了審計,兩條原因都致命: +不少團隊其實做了治理,只是做錯了地方——寫進了提示詞。"你只能查當前使用者有權限的資料""高風險理賠要人工複核",平時看著也管用。但它過不了審計,兩條原因都致命: 第一,**提示詞是建議,不是控制。** 它靠模型"願意聽話"生效,一次越獄、一個沒覆蓋的邊界就被繞過。審計員問"你怎麼*保證*某類理賠一定經過人工複核","我們在提示詞裡寫了"不是能簽字的答案。 第二,**提示詞不產生記錄。** 審計要的是結構化、不可抵賴的證據,提示詞給不了。 -合規真正要求的,是把治理從"提示詞裡的建議"挪到"執行引擎裡的強制"——許可權在每次讀寫時被執行時核驗,審計是動作的天然副產品。 +合規真正要求的,是把治理從"提示詞裡的建議"挪到"執行引擎裡的強制"——權限在每次讀寫時被執行時核驗,審計是動作的天然副產品。 ## CADA 之後,"資料在哪"成了硬指標——但自託管不是免罪符 -歐盟圍繞雲、AI 和資料主權的討論,把另一件事推到臺前:你的資料和 AI 處理過程,究竟在誰的管轄權之下?這一問直接指向部署形態。把讀取真實業務資料的 AI 執行時交給一個你無法審視內部的外部 SaaS,合規簽字會變得更難。自託管能改善資料駐留、第三方暴露和可見性——要自託管的不一定是模型,而是承載物件、許可權、工具、審批和審計證據的那個執行時。 +歐盟圍繞雲、AI 和資料主權的討論,把另一件事推到臺前:你的資料和 AI 處理過程,究竟在誰的管轄權之下?這一問直接指向部署形態。把讀取真實業務資料的 AI 執行時交給一個你無法審視內部的外部 SaaS,合規簽字會變得更難。自託管能改善資料駐留、第三方暴露和可見性——要自託管的不一定是模型,而是承載物件、權限、工具、審批和審計證據的那個執行時。 但要誠實地說一句:**自託管不是免罪符,它是一筆交易。** 當執行時跑在你自己的基礎設施上,打補丁、輪換金鑰、保證日誌不丟、出事一鍵熔斷——這些操作和舉證責任,也一起落到你頭上。你換來的是控制權,代價是責任。反過來,若你希望讓別人替你擔這份責任,通常意味著把資料也交給他。這筆賬沒有白拿的一邊,得看哪邊的代價你擔得起、簽得了字。 @@ -119,7 +119,7 @@ tags: [] } ``` -這條記錄裡,誰、做了什麼、AI 依據什麼、命中哪條許可權、誰複核的、何時——全在。它不是事後補的工程,是 agent 以受監督身份呼叫受治理工具時,執行時順手落下的一筆。人和 agent 走同一套許可權引擎、記同一本賬。業務定義(物件、許可權、複核流程)則是你倉庫裡可 diff、可追溯的後設資料——審計員問"哪類理賠必須人工複核",答案不在某人腦子裡,在流程定義裡寫著。 +這條記錄裡,誰、做了什麼、AI 依據什麼、命中哪條權限、誰複核的、何時——全在。它不是事後補的工程,是 agent 以受監督身份呼叫受治理工具時,執行時順手落下的一筆。人和 agent 走同一套權限引擎、記同一本賬。業務定義(物件、權限、複核流程)則是你倉庫裡可 diff、可追溯的後設資料——審計員問"哪類理賠必須人工複核",答案不在某人腦子裡,在流程定義裡寫著。 ## 結語 diff --git a/content/blog/extend-existing-systems-with-ai/index.zh-Hant.mdx b/content/blog/extend-existing-systems-with-ai/index.zh-Hant.mdx index 389ce64..ede219d 100644 --- a/content/blog/extend-existing-systems-with-ai/index.zh-Hant.mdx +++ b/content/blog/extend-existing-systems-with-ai/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 給現有系統加 AI:連線資料庫,而不是先遷移 -description: 把 ObjectOS 連到已經執行的資料庫,讓 agent 把關鍵資料表建模為物件,再在你的許可權和伺服器邊界內疊加 AI 能力;原系統繼續執行,AI 走受控物件層。 +description: 把 ObjectOS 連到已經執行的資料庫,讓 agent 把關鍵資料表建模為物件,再在你的權限和伺服器邊界內疊加 AI 能力;原系統繼續執行,AI 走受控物件層。 author: ObjectStack Team date: 2026-05-30 updated: 2026-09-02T10:00:00+08:00 @@ -19,7 +19,7 @@ tags: [] # published_at: 2026-05-30 --- -**先給結論**:讓現有系統支援 AI,不必先遷移或重建——把 ObjectOS 連到你正在跑的資料庫,讓 agent 在你的許可權之下讀懂真實資料、疊加 AI,優先連線,而不是先重建。 +**先給結論**:讓現有系統支援 AI,不必先遷移或重建——把 ObjectOS 連到你正在跑的資料庫,讓 agent 在你的權限之下讀懂真實資料、疊加 AI,優先連線,而不是先重建。 大多數"給你的業務加上 AI"的說辭,都悄悄假設了一次重建:把資料搬到新平臺、 重新實現工作流、重新培訓團隊,然後祈禱遷移順利落地。而這正是沒人想做的部分。 @@ -32,10 +32,10 @@ ObjectOS 採取相反的立場。**你不遷移。你連線。** 把 ObjectOS 指向你現有的資料庫,將你關心的資料表描述為物件,於是每一個 AI Agent、流程、API 和儀表盤都立刻在這些資料上工作 —— 自動路由到正確的系統, -並受你的使用者已經擁有的同一套許可權治理。 +並受你的使用者已經擁有的同一套權限治理。 原有的應用不會改變。資料行不會移動。ObjectOS 成為你已執行系統之上那層原生 -支援 AI、感知許可權的介面。 +支援 AI、感知權限的介面。 ## 一個具體的畫面 @@ -51,7 +51,7 @@ Agent、流程、API 和儀表盤都立刻在這些資料上工作 —— 自動 3. 向你的資料提問,並接上第一條自動化。 不用先替換 CRM,也不用先搬走資料。你在相同的資料行之上,得到一層支援 -AI 的物件與許可權邊界。 +AI 的物件與權限邊界。 ![概念示意圖](./connect-without-migration.webp) @@ -119,7 +119,7 @@ export const Opportunity = ObjectSchema.create({ ``` 因為產物是**你擁有並提交的普通原始碼**,你始終掌握控制權:保留重要的列、丟棄 -不想暴露的列,再疊加 label、校驗與許可權。Agent 幾分鐘內把你帶到一份可審閱的 +不想暴露的列,再疊加 label、校驗與權限。Agent 幾分鐘內把你帶到一份可審閱的 初稿;你來讓它達到生產級別。 ### 3. 將物件繫結到資料來源 @@ -160,7 +160,7 @@ Postgres 上以 `SELECT … WHERE …` 執行,並基於真實、當前的資 地方: - **AI 以使用者身份行動,絕不凌駕其上。** Agent 看到的,恰好是它背後那個人被 - 允許看到的內容 —— 物件級、記錄級、欄位級許可權由執行時強制,而非由提示詞約束。 + 允許看到的內容 —— 物件級、記錄級、欄位級權限由執行時強制,而非由提示詞約束。 - **如果你願意,預設只讀。** 把物件繫結到只讀連線或只讀資料庫使用者。安全地 分析生產資料;再有意識地、一個物件一個物件地開啟寫入。 - **一切皆有審計。** 每一次讀取、寫入和提權 —— 無論來自人還是 Agent —— @@ -176,7 +176,7 @@ Postgres 上以 `SELECT … WHERE …` 執行,並基於真實、當前的資 | **對記錄系統的風險** | 高 —— 資料遷移、雙寫、切換上線 | 低 —— 先只讀連線,源應用繼續執行 | | **資料存放在哪** | 被搬走 | 原地不動 | | **建模工作量** | 手工重新實現每個實體 | 編碼 Agent 從真實 schema 起草物件 | -| **許可權** | 重建並重新審計 | 繼承;AI 遵守同一套模型 | +| **權限** | 重建並重新審計 | 繼承;AI 遵守同一套模型 | | **可逆性** | 難以撤銷 | 斷開資料來源 —— 什麼都沒變 | ## 第一天你就能得到什麼 @@ -188,7 +188,7 @@ Postgres 上以 `SELECT … WHERE …` 執行,並基於真實、當前的資 皆有審計。 - **生成式 API 與控制台。** REST/GraphQL 端點與管理介面源自同一份後設資料 —— 無需另建整合層。 -- **同一套許可權模型。** 適用於人的邊界,同樣適用於 AI 流量。 +- **同一套權限模型。** 適用於人的邊界,同樣適用於 AI 流量。 ## 已經交付的 vs. 即將到來的 diff --git a/content/blog/forward-deployed-engineer-tools/index.zh-Hant.mdx b/content/blog/forward-deployed-engineer-tools/index.zh-Hant.mdx index fe34383..d9fef3c 100644 --- a/content/blog/forward-deployed-engineer-tools/index.zh-Hant.mdx +++ b/content/blog/forward-deployed-engineer-tools/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: "FDE(前沿部署工程師)用什麼工具?一套本體優先的開源技術棧" -description: "FDE 在一次 60–180 天的部署裡真正寫下什麼:接入介面卡、實體解析、許可權對映、最初的幾條工作流。加上定義這份工作的五個痛點,以及 2026 年的模仿潮為什麼只抄走了崗位、沒抄走底下的基質。" +description: "FDE 在一次 60–180 天的部署裡真正寫下什麼:接入介面卡、實體解析、權限對映、最初的幾條工作流。加上定義這份工作的五個痛點,以及 2026 年的模仿潮為什麼只抄走了崗位、沒抄走底下的基質。" author: ObjectStack Team date: 2026-07-23 updated: 2026-09-02T10:00:00+08:00 @@ -22,7 +22,7 @@ tags: ## 沒人誠實描述過的這份工作 -招聘啟事談的是"0→1 的模糊性"和 $300K–$550K 的薪資帶([Perspective AI](https://getperspective.ai/blog/2026-fde-hiring-trends-what-1000-job-posts-reveal)、[TechTarget](https://www.techtarget.com/searchenterpriseai/feature/The-rise-of-the-AI-forward-deployed-engineer))。真實的工作是在別人的圍牆內讓 AI 落地:他們的資料、他們的許可權、他們的合規部門、他們對"夠好"的定義。Palantir 多年前就把方法制度化了:其 AI FDE **在交付任何 LLM 應用之前先構建客戶專屬本體**,並把每週 30–40% 的時間花在業務發現上([Palantir AI FDE 指南](https://www.palantir.com/docs/foundry/ai-fde/overview))。方法是對的。方法之下的工具,才是一週時間真正的去向。 +招聘啟事談的是"0→1 的模糊性"和 $300K–$550K 的薪資帶([Perspective AI](https://getperspective.ai/blog/2026-fde-hiring-trends-what-1000-job-posts-reveal)、[TechTarget](https://www.techtarget.com/searchenterpriseai/feature/The-rise-of-the-AI-forward-deployed-engineer))。真實的工作是在別人的圍牆內讓 AI 落地:他們的資料、他們的權限、他們的合規部門、他們對"夠好"的定義。Palantir 多年前就把方法制度化了:其 AI FDE **在交付任何 LLM 應用之前先構建客戶專屬本體**,並把每週 30–40% 的時間花在業務發現上([Palantir AI FDE 指南](https://www.palantir.com/docs/foundry/ai-fde/overview))。方法是對的。方法之下的工具,才是一週時間真正的去向。 ## FDE 到底構建了什麼 @@ -32,13 +32,13 @@ tags: |---|---|---| | **0–15 · 接入介面卡** | 每個源系統一個介面卡——他們的 ERP、他們的工單系統、那份其實才是事實來源的電子表格。先做讀取路徑:連線,不遷移。 | 介面上的一個業務物件,顯示出今天早上從他們系統裡出來的一條真實記錄。 | | **15–45 · 實體解析** | 沒人拿去演示的那一半苦活。"客戶"在四個系統裡是四個不同的主鍵:你要寫匹配規則、存活規則,以及本體認定為規範的那個識別符號。 | 同一家公司的兩條記錄合併了——而且他們的運營負責人認同就該合併。 | -| **30–60 · 許可權對映** | 把他們的組織架構翻譯成角色、許可權集、行級共享和欄位級規則,包括那些只有三個人能看的欄位。 | 安全評審變成讀檔案而不是開會:評審人能直接指出誰能看到什麼。 | +| **30–60 · 權限對映** | 把他們的組織架構翻譯成角色、權限集、行級共享和欄位級規則,包括那些只有三個人能看的欄位。 | 安全評審變成讀檔案而不是開會:評審人能直接指出誰能看到什麼。 | | **45–90 · 最初的幾條工作流** | 兩三條端到端的流程——一條審批鏈、一個分派佇列、一次續約——連同圍繞它們的動作、檢視和通知。 | 一個不給你打工的人,在這個應用裡完成了真實一天的工作。 | | **90–180 · 交接** | 種子資料、驗收夾具、翻譯標籤、打包好的應用,以及一份他們團隊真能跑起來的評審清單。 | 他們自己的工程師改一處東西上線,不用給你打電話。 | 注意前四行的共同點:沒有一行是通常意義上的應用程式碼。它們是*定義*——什麼存在、什麼算作同一個東西、誰可以做什麼、工作怎麼流轉。在手工搭的技術棧上,這些照樣只能寫成程式碼,而這恰恰是下面五個痛點咬人的原因。 -**第二次部署,才是這個模式賺錢還是失敗的地方。** 上面那張表裡沒有一樣東西,像你做的時候感覺的那麼"客戶專屬"。給"客戶"做實體解析,在下一家客戶那裡是同一個結構性問題,只是主鍵不同;一條審批鏈是同一個形狀,只是閾值和審批人角色不同。所以第二次專案只有一個數值值得測量——就叫它**改名率**:第二次部署裡,有多少比例是把你已經擁有的型別化定義*改個名字*,而不是重寫一遍。在手寫程式碼庫裡,改名率接近於零,而且沒人察覺,因為第二次部署照樣交付了——它只是花掉了和第一次一樣的成本。在型別化後設資料裡,這個比例是可數的,因為那個面是有限的:一個 HotCRM 量級的專案就是 15 個物件、17 條流程、10 個動作、6 個許可權檔案、5 條共享規則。下一個客戶繼承了什麼,你真的能一條條列出來。 +**第二次部署,才是這個模式賺錢還是失敗的地方。** 上面那張表裡沒有一樣東西,像你做的時候感覺的那麼"客戶專屬"。給"客戶"做實體解析,在下一家客戶那裡是同一個結構性問題,只是主鍵不同;一條審批鏈是同一個形狀,只是閾值和審批人角色不同。所以第二次專案只有一個數值值得測量——就叫它**改名率**:第二次部署裡,有多少比例是把你已經擁有的型別化定義*改個名字*,而不是重寫一遍。在手寫程式碼庫裡,改名率接近於零,而且沒人察覺,因為第二次部署照樣交付了——它只是花掉了和第一次一樣的成本。在型別化後設資料裡,這個比例是可數的,因為那個面是有限的:一個 HotCRM 量級的專案就是 15 個物件、17 條流程、10 個動作、6 個權限檔案、5 條共享規則。下一個客戶繼承了什麼,你真的能一條條列出來。 這就是這份工作。本文接下來講的,是讓上面每一行都比它本該的樣子更難的五個反覆出現的痛點——以及什麼能拆掉它們。 @@ -46,18 +46,18 @@ tags: 每個專案的開場都一樣:在螢幕上出現第一個業務物件之前,你需要登入、SSO、角色、CRUD 介面、管理介面、檔案儲存、審計表。沒有一樣是客戶僱你的原因。你的差異化能力——花在理解*他們*業務上的那 30–40%——被花在重建無差異底座上的 60% 擠到了邊緣,而那個底座你上個客戶剛建過一遍。 -**這套棧改變了什麼:** 底座本來就在。一條命令,午飯前 Console、登入與 SSO、角色/行級/欄位級許可權、審計日誌、REST API 和 MCP 伺服器就全部在執行: +**這套棧改變了什麼:** 底座本來就在。一條命令,午飯前 Console、登入與 SSO、角色/行級/欄位級權限、審計日誌、REST API 和 MCP 伺服器就全部在執行: ```bash npm create objectstack@latest client-app && cd client-app -npx os dev --ui # Console 在 :3000——認證、許可權、審計已在強制執行 +npx os dev --ui # Console 在 :3000——認證、權限、審計已在強制執行 ``` -一切可派生的都由執行時派生。剩下要寫的,只有唯獨你能寫的東西:客戶的物件、流程和許可權規則。第一週變成業務發現和建模——你真正有差異化的那部分工作。 +一切可派生的都由執行時派生。剩下要寫的,只有唯獨你能寫的東西:客戶的物件、流程和權限規則。第一週變成業務發現和建模——你真正有差異化的那部分工作。 ## 痛點二——死在安全評審裡的演示 -你熟悉這條曲線。第一週的週五:一個拼起來的演示——vibe-coding 的介面蓋在一份拷出來的 CSV 上——全場鼓掌。第二個月:資訊安全部門進場,三個問題。*AI 到底能看到什麼?它執行操作時用誰的許可權?審計記錄在哪裡?* 對一個演示棧來說,誠實的回答是推倒重建,而重建正是專案死掉的地方。 +你熟悉這條曲線。第一週的週五:一個拼起來的演示——vibe-coding 的介面蓋在一份拷出來的 CSV 上——全場鼓掌。第二個月:資訊安全部門進場,三個問題。*AI 到底能看到什麼?它執行操作時用誰的權限?審計記錄在哪裡?* 對一個演示棧來說,誠實的回答是推倒重建,而重建正是專案死掉的地方。 **這套棧改變了什麼:** 治理是底座,不是補丁。校驗門甚至不接受一個沒有宣告共享模型的物件: @@ -74,25 +74,25 @@ export const Ticket = ObjectSchema.create({ }); ``` -執行時裡,每一次呼叫——人用介面、REST,還是 AI 智慧體走 MCP——都過同一套 RBAC、行級與欄位級安全,落進同一份審計日誌。當資訊安全問*"AI 能看到什麼?"*,答案是一份他們能直接讀的檔案:許可權後設資料,由執行時強制執行,而不是幻燈片上的承諾。你週五的演示和生產部署是同一個製品。不存在重建,因為從來不存在"沒有治理的版本"。 +執行時裡,每一次呼叫——人用介面、REST,還是 AI 智慧體走 MCP——都過同一套 RBAC、行級與欄位級安全,落進同一份審計日誌。當資訊安全問*"AI 能看到什麼?"*,答案是一份他們能直接讀的檔案:權限後設資料,由執行時強制執行,而不是幻燈片上的承諾。你週五的演示和生產部署是同一個製品。不存在重建,因為從來不存在"沒有治理的版本"。 ## 痛點三——需求變得比程式碼快 會開到一半,運營負責人說:*"對了,超過 20% 的折扣要先過大區經理審批。"* 在手寫程式碼庫裡,這是一次 schema 遷移、三處 API 改動、一處介面改動、一週時間——而在客戶眼裡,他們一變具體,你就變慢了。前沿部署工作的生死,就在*會議室裡的*迭代速度。 -**這套棧改變了什麼:** 整個應用是緊湊的型別化後設資料。隨包 CRM 參考樣例是 **1792 行、約 16k token**(自己數:`find examples/app-crm/src -name '*.ts' | xargs cat | wc -l`);完整 HotCRM 全應用不到 **150k token**——業務邏輯不到 100k,UI 約增加 50k。無論哪一檔,你的編碼智慧體都能把*整個*系統裝在上下文裡:審批鏈的改動是橫跨流程、許可權、介面的一個連貫 diff,會還沒開完就寫好了,`os validate` 把關,Console 即時預覽。"改這裡會弄壞什麼?"是智慧體真正能回答的問題,因為它看得見全部。需求變更不再威脅工期——它本身就成了演示。 +**這套棧改變了什麼:** 整個應用是緊湊的型別化後設資料。隨包 CRM 參考樣例是 **1792 行、約 16k token**(自己數:`find examples/app-crm/src -name '*.ts' | xargs cat | wc -l`);完整 HotCRM 全應用不到 **150k token**——業務邏輯不到 100k,UI 約增加 50k。無論哪一檔,你的編碼智慧體都能把*整個*系統裝在上下文裡:審批鏈的改動是橫跨流程、權限、介面的一個連貫 diff,會還沒開完就寫好了,`os validate` 把關,Console 即時預覽。"改這裡會弄壞什麼?"是智慧體真正能回答的問題,因為它看得見全部。需求變更不再威脅工期——它本身就成了演示。 ## 痛點四——你的模式永遠無法複利 客戶 A 的審批鏈程式碼抬不進客戶 B 的程式碼庫——框架版本不同、認證不同、一切都不同。於是每個專案都從零開始,一家三人精品諮詢永遠攢不出讓 Palantir 模式經濟學成立的槓桿。這是前沿部署諮詢公司做不大的隱秘原因。 -**這套棧改變了什麼:** 模式就是型別化後設資料,而型別化後設資料是可移植的。你為客戶 A 建的審批鏈,是一份丟進客戶 B 倉庫改個名就能用的流程定義。專案做多了,你會積累出自己的"號型庫"——物件、流程、許可權集、種子資料——你的智慧體幾分鐘內把它們套到下一個客戶身上。而且你的庫不必從零開始:[HotCRM](https://github.com/objectstack-ai/hotcrm) 是一個完整、可 fork 的參考實現——15 個物件、17 個流程、4 個儀表盤、2 個 AI copilot、4 種語言——就是為示範這套約定而建的。fork、改名稱空間,你的專案從一個能跑的系統開始,而不是一個空倉庫。 +**這套棧改變了什麼:** 模式就是型別化後設資料,而型別化後設資料是可移植的。你為客戶 A 建的審批鏈,是一份丟進客戶 B 倉庫改個名就能用的流程定義。專案做多了,你會積累出自己的"號型庫"——物件、流程、權限集、種子資料——你的智慧體幾分鐘內把它們套到下一個客戶身上。而且你的庫不必從零開始:[HotCRM](https://github.com/objectstack-ai/hotcrm) 是一個完整、可 fork 的參考實現——15 個物件、17 個流程、4 個儀表盤、2 個 AI copilot、4 種語言——就是為示範這套約定而建的。fork、改名稱空間,你的專案從一個能跑的系統開始,而不是一個空倉庫。 ## 痛點五——交接毒化客戶關係 每個專案都會結束,而今天的結束方式有兩種,都不體面。交出一個平臺,客戶從此永遠租用自己的本體——你成了別人的銷售渠道,而客戶學會了害怕成功的試點,因為本體越好,鎖定越深。交出一個定製程式碼庫,客戶團隊維護不了,它慢慢腐爛,十八個月後爛賬記在你名下。 -**這套棧改變了什麼:** 這就是**本體交接**——FDE 打法從未解決的結尾。你交出的是客戶的倉庫:Apache-2.0 下的型別化物件、流程與許可權,加上編譯好的製品和一份評審清單。他們的安全團隊能檢查整份定義——隨包參考樣例是 16k token,連完整 HotCRM 也不到 150k,而不是 30 萬行程式碼。他們自己的編碼智慧體用你用過的同一個迴圈繼續維護,因為這個格式生來就是給智慧體寫的。如果他們想要平臺被託管運營——瀏覽器 AI Builder、雲端或自管——那是 [ObjectOS](https://www.objectos.ai),跑的是同一份開放定義;哪天離開也不會失去本體。你的下一份合同靠新的工作贏來,而不是靠鎖定榨出來。這個差別,就是你的口碑在複利。 +**這套棧改變了什麼:** 這就是**本體交接**——FDE 打法從未解決的結尾。你交出的是客戶的倉庫:Apache-2.0 下的型別化物件、流程與權限,加上編譯好的製品和一份評審清單。他們的安全團隊能檢查整份定義——隨包參考樣例是 16k token,連完整 HotCRM 也不到 150k,而不是 30 萬行程式碼。他們自己的編碼智慧體用你用過的同一個迴圈繼續維護,因為這個格式生來就是給智慧體寫的。如果他們想要平臺被託管運營——瀏覽器 AI Builder、雲端或自管——那是 [ObjectOS](https://www.objectos.ai),跑的是同一份開放定義;哪天離開也不會失去本體。你的下一份合同靠新的工作贏來,而不是靠鎖定榨出來。這個差別,就是你的口碑在複利。 ## FDE 的完整後設資料工具箱 @@ -101,9 +101,9 @@ export const Ticket = ObjectSchema.create({ | 專案階段 | 你要回答的客戶問題 | 用到的後設資料型別 | |---|---|---| | **1 · 建模客戶的名詞** | "我們的業務裡有什麼?" | 物件與欄位(關係、校驗規則、公式欄位)· 資料來源(連線現有資料庫,不遷移)· 種子資料(演示與驗收用) | -| **2 · 建模客戶的動詞** | "事情是怎麼流轉的?" | 流程(審批鏈、狀態機、記錄觸發、定時任務)· 審批(多級、佇列、記錄鎖定)· 動作(許可權校驗的按鈕與服務端操作) | +| **2 · 建模客戶的動詞** | "事情是怎麼流轉的?" | 流程(審批鏈、狀態機、記錄觸發、定時任務)· 審批(多級、佇列、記錄鎖定)· 動作(權限校驗的按鈕與服務端操作) | | **3 · 給人用的介面** | "我們的人在哪裡幹活?" | 應用與導航 · 檢視(列表/看板/日曆/甘特)· 頁面與表單 · 儀表盤與報表(高管要看的 KPI) | -| **4 · 過安全評審** | "誰能看到什麼、做什麼?" | 許可權集與角色(RBAC)· 行級/欄位級安全 · 共享規則 · 審計(執行時自帶,宣告即得) | +| **4 · 過安全評審** | "誰能看到什麼、做什麼?" | 權限集與角色(RBAC)· 行級/欄位級安全 · 共享規則 · 審計(執行時自帶,宣告即得) | | **5 · 客戶真正想買的 AI** | "AI 能替我們幹什麼?" | AI 智慧體(銷售/客服 copilot)· AI 工具與技能 · MCP 暴露(`ai: { exposed: true }`) | | **6 · 交接與複利** | "你走了之後呢?" | 翻譯(多語言標籤,跨國客戶)· 應用清單與打包(編譯成一個 `objectstack.json`,裝進任何環境) | @@ -137,7 +137,7 @@ export const ServiceCopilot = defineAgent({ }); ``` -HotCRM 就是這份詞彙表的完整用法示範:15 個物件、17 個流程、10 個動作、4 個儀表盤、2 個 AI copilot、6 個技能、6 個許可權檔案、5 條共享規則、4 種語言——每一層都有,全應用不到 **150k token**:業務邏輯不到 100k,UI 約增加 50k。整套裝得進單個智慧體上下文視窗。 +HotCRM 就是這份詞彙表的完整用法示範:15 個物件、17 個流程、10 個動作、4 個儀表盤、2 個 AI copilot、6 個技能、6 個權限檔案、5 條共享規則、4 種語言——每一層都有,全應用不到 **150k token**:業務邏輯不到 100k,UI 約增加 50k。整套裝得進單個智慧體上下文視窗。 ## 2026 年的模仿潮抄走了崗位,沒抄走基質 @@ -160,7 +160,7 @@ HotCRM 就是這份詞彙表的完整用法示範:15 個物件、17 個流程、 2. **客戶離開你還讀得懂它嗎?** 如果這份定義只有在某個廠商控制台裡才可讀,客戶就是在租回自己的本體,而且你幹得越好,租得越深。 3. **第二次部署從第一次繼承了什麼?** 讓他們把清單拿出來。如果誰都拿不出來,改名率就是零。 -本文對這三個問題的答案是同一個,也正是上面通篇本體優先框架的理由:交付物是一份**開放的業務本體**——客戶自己倉庫裡、Apache-2.0 之下的型別化物件、流程與許可權——客戶能讀、能留、能交給他們自己的編碼智慧體。抄崗位是一份招聘計劃,一個季度就能抄完。抄基質意味著把它開放到客戶願意留下的程度,而這是一個產品決定,2026 年這波浪潮裡幾乎沒人做過。 +本文對這三個問題的答案是同一個,也正是上面通篇本體優先框架的理由:交付物是一份**開放的業務本體**——客戶自己倉庫裡、Apache-2.0 之下的型別化物件、流程與權限——客戶能讀、能留、能交給他們自己的編碼智慧體。抄崗位是一份招聘計劃,一個季度就能抄完。抄基質意味著把它開放到客戶願意留下的程度,而這是一個產品決定,2026 年這波浪潮裡幾乎沒人做過。 ## 這套棧不解決什麼 @@ -170,9 +170,9 @@ HotCRM 就是這份詞彙表的完整用法示範:15 個物件、17 個流程、 1. 先把客戶的名詞和動詞建模成物件與流程,再談任何介面。 2. 讓整個定義保持上下文體量,智慧體才能整體推理、整體重構。 -3. 許可權預設從嚴;每一次許可權變更都在 diff 裡顯式可見。 +3. 權限預設從嚴;每一次權限變更都在 diff 裡顯式可見。 4. 交接的是倉庫、編譯製品和評審清單——不是你租戶裡的一個賬號。 -5. 保持 MCP 開啟,讓客戶自己的 AI 在其許可權內操作應用。 +5. 保持 MCP 開啟,讓客戶自己的 AI 在其權限內操作應用。 6. 到第二次部署時,數一數改名率。如果什麼都沒帶過來,問題出在基質上,不在這個專案上。 ## 跑一遍這個迴圈 diff --git a/content/blog/from-requirement-to-app/index.zh-Hant.mdx b/content/blog/from-requirement-to-app/index.zh-Hant.mdx index 2512a00..f5a80ba 100644 --- a/content/blog/from-requirement-to-app/index.zh-Hant.mdx +++ b/content/blog/from-requirement-to-app/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 從需求到可審查應用:AI 如何生成 ObjectStack 後設資料 -description: 用裝置報修場景拆開 AI Builder 的生成過程:物件、欄位、關係、檢視、許可權、動作、流程、API 和 agent 工具如何由同一份後設資料驅動。 +description: 用裝置報修場景拆開 AI Builder 的生成過程:物件、欄位、關係、檢視、權限、動作、流程、API 和 agent 工具如何由同一份後設資料驅動。 author: ObjectStack Team date: 2026-06-04 status: published @@ -11,15 +11,15 @@ cover: ./cover.jpg tags: [] --- -**先給結論**:用裝置報修場景走一遍——物件、欄位、檢視、許可權、動作、流程、API 和 agent 工具都來自同一份後設資料;這就是“生成可審查應用”和“一次性甩出程式碼”的根本區別。 +**先給結論**:用裝置報修場景走一遍——物件、欄位、檢視、權限、動作、流程、API 和 agent 工具都來自同一份後設資料;這就是“生成可審查應用”和“一次性甩出程式碼”的根本區別。 你對 AI Builder 說一句話: > 幫我做一個裝置報修系統:員工能提交故障,系統能關聯裝置、分派工程師、跟蹤狀態、計算停機時間,高優先順序自動派單,關閉工單前要填寫維修結果和成本。 -AI Builder 生成的第一版不只是頁面,也有物件、欄位、關係、許可權、檢視、流程、動作、API 和 agent 工具。人要 review 的不是一堆散落實現,而是一份能被執行時校驗的業務系統規格。 +AI Builder 生成的第一版不只是頁面,也有物件、欄位、關係、權限、檢視、流程、動作、API 和 agent 工具。人要 review 的不是一堆散落實現,而是一份能被執行時校驗的業務系統規格。 -這篇不泛講“AI 生成應用”,而是用這個具體業務場景拆開看:ObjectStack 後設資料到底生成了什麼,為什麼它比一次性程式碼生成更適合要審查、要許可權、要審計的企業應用。 +這篇不泛講“AI 生成應用”,而是用這個具體業務場景拆開看:ObjectStack 後設資料到底生成了什麼,為什麼它比一次性程式碼生成更適合要審查、要權限、要審計的企業應用。 ![從需求到應用的生成流程](./requirement-to-app-pipeline.webp) @@ -34,7 +34,7 @@ AI Builder 生成的第一版不只是頁面,也有物件、欄位、關係、 5. 高風險或高成本工單進入審批; 6. 工單關閉後形成裝置維修歷史。 -如果用傳統方式做,這會散落在資料表、API、頁面、許可權、狀態機、通知、審計和報表裡。 +如果用傳統方式做,這會散落在資料表、API、頁面、權限、狀態機、通知、審計和報表裡。 ObjectStack 的核心思路是把這些東西先描述成後設資料。AI Builder 的任務不是憑空寫一堆膠水程式碼,而是先起草一份業務系統規格。 @@ -42,7 +42,7 @@ ObjectStack 的核心思路是把這些東西先描述成後設資料。AI Build | --- | --- | | 裝置、工單、工程師是什麼 | 物件與關係 | | 哪些欄位必填、可選、列舉 | 欄位型別與校驗 | -| 員工、工程師、主管看到什麼 | 許可權集與欄位級許可權 | +| 員工、工程師、主管看到什麼 | 權限集與欄位級權限 | | 列表、看板、詳情如何展示 | 檢視後設資料 | | 派單、升級、關閉如何執行 | 動作與流程 | | AI agent 能查詢和操作什麼 | 受控工具與審計 | @@ -57,7 +57,7 @@ AI Builder 第一步應該拆業務物件: - `user`:員工、工程師、主管複用現有使用者物件; - `team`:班組或維修隊。 -真正的應用從物件開始,因為物件會同時影響 API、UI、許可權、流程和 agent 工具。 +真正的應用從物件開始,因為物件會同時影響 API、UI、權限、流程和 agent 工具。 下面是簡化後的裝置物件: @@ -84,7 +84,7 @@ export const Device = ObjectSchema.create({ }); ``` -注意這裡已經不是“表單欄位”這麼簡單。`team` 是關係,`status` 是列舉,`code` 是唯一約束。這些資訊後面會被 API、頁面、篩選、許可權和 agent 一起使用。 +注意這裡已經不是“表單欄位”這麼簡單。`team` 是關係,`status` 是列舉,`code` 是唯一約束。這些資訊後面會被 API、頁面、篩選、權限和 agent 一起使用。 ## 工單物件承載業務規則 @@ -130,8 +130,8 @@ export const RepairOrder = ObjectSchema.create({ - `lookup` 讓工單和裝置、使用者建立關係; - `select` 讓狀態可以用於篩選、看板和流程判斷; - `datetime` 讓 SLA、停機時間和超時提醒可以被計算; -- `currency` 讓成本欄位可以做欄位級許可權和審批條件; -- `image` 讓現場照片自動進入表單、詳情頁和檔案許可權體系。 +- `currency` 讓成本欄位可以做欄位級權限和審批條件; +- `image` 讓現場照片自動進入表單、詳情頁和檔案權限體系。 ## 公式和校驗也應該是後設資料 @@ -192,7 +192,7 @@ export const RepairBoardView = { 檢視不是純前端配置。它定義了使用者如何掃描業務,也影響 agent 如何向用戶展示結果。例如 agent 回答“哪些高優先順序工單還沒處理”時,可以複用同樣的物件、欄位和篩選語義。 -## 許可權不是最後補的 +## 權限不是最後補的 同一個 `repair_order`,不同角色邊界完全不同: @@ -201,7 +201,7 @@ export const RepairBoardView = { - 主管可以分派工程師、檢視成本、關閉異常工單; - 財務可以看成本,但不一定能改維修狀態。 -所以許可權也必須進入後設資料: +所以權限也必須進入後設資料: ```ts export const EngineerPermission = { @@ -224,11 +224,11 @@ export const EngineerPermission = { 這段後設資料會影響 UI、API 和 agent。工程師在頁面上看不到成本,通過 API 也讀不到成本,agent 以工程師身份查詢時同樣拿不到成本。 -這就是企業級 AI 應用必須強調許可權的原因:agent 不能比使用者擁有更多業務權力。 +這就是企業級 AI 應用必須強調權限的原因:agent 不能比使用者擁有更多業務權力。 ## 動作讓業務行為可控 -“開始維修”“提交驗收”“關閉工單”不是普通欄位更新,而是業務動作。動作可以定義輸入、前置條件、許可權和審計。 +“開始維修”“提交驗收”“關閉工單”不是普通欄位更新,而是業務動作。動作可以定義輸入、前置條件、權限和審計。 ```ts export const StartRepairAction = { @@ -313,18 +313,18 @@ export const RepairAgentTools = [ > 幫我找出今天還沒開始維修的高優先順序工單,並說明可能影響哪些裝置。 -agent 不需要猜資料庫結構。它通過受控工具查詢 `repair_order`,展開關聯的 `device`,遵守當前使用者許可權,然後把結果總結給使用者。 +agent 不需要猜資料庫結構。它通過受控工具查詢 `repair_order`,展開關聯的 `device`,遵守當前使用者權限,然後把結果總結給使用者。 -如果使用者繼續說“把第一條工單派給今天值班工程師”,agent 呼叫的是 `assign_repair_order` 動作;如果成本過高或許可權不足,執行時會拒絕或進入審批。 +如果使用者繼續說“把第一條工單派給今天值班工程師”,agent 呼叫的是 `assign_repair_order` 動作;如果成本過高或權限不足,執行時會拒絕或進入審批。 ## 這和一次性程式碼生成的區別 -一次性程式碼生成的結果通常是很多檔案:頁面、API、資料庫、許可權判斷、指令碼。第一版看起來快,但後續需求變化會讓程式碼逐漸分叉。 +一次性程式碼生成的結果通常是很多檔案:頁面、API、資料庫、權限判斷、指令碼。第一版看起來快,但後續需求變化會讓程式碼逐漸分叉。 ObjectStack 後設資料的價值在於:**業務結構只有一個源頭**。 - 物件欄位變了,API、表單、詳情頁和 agent 工具一起變; -- 許可權變了,UI、API 和 agent 都遵守同一套規則; +- 權限變了,UI、API 和 agent 都遵守同一套規則; - 動作變了,按鈕、流程、審計和工具呼叫都跟著變; - 檢視變了,人和 agent 對業務佇列的理解也同步變化。 @@ -336,9 +336,9 @@ AI Builder 不是替你繞過軟體工程,而是把軟體工程裡最重要的 1. 自然語言被拆成真實業務物件; 2. 物件、欄位、關係、公式和校驗進入後設資料; -3. 檢視、許可權、動作和流程補齊業務邊界; +3. 檢視、權限、動作和流程補齊業務邊界; 4. 平臺把後設資料投影成 API、介面和 agent 工具; -5. AI 在許可權內查詢和建議,高風險動作進入審批; +5. AI 在權限內查詢和建議,高風險動作進入審批; 6. 人 review 一份小 diff 後繼續迭代同一份規格。 這才是 AI-native 應用平臺真正有價值的地方:不是讓 AI 一次性寫出一堆程式碼,而是讓 AI 和人一起維護一套可治理、可演進、能進入生產的業務系統。 diff --git a/content/blog/give-your-agent-rules-for-governable-apps/index.zh-Hant.mdx b/content/blog/give-your-agent-rules-for-governable-apps/index.zh-Hant.mdx index 00c1cad..443ef3c 100644 --- a/content/blog/give-your-agent-rules-for-governable-apps/index.zh-Hant.mdx +++ b/content/blog/give-your-agent-rules-for-governable-apps/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: Agent 規則檔案怎麼寫:讓 AI 生成可治理應用 -description: 編碼 agent 的 AGENTS.md、.cursor/rules 或 CLAUDE.md 不該只管程式碼風格。把許可權、審批、審計和目標後設資料格式寫進去,AI 生成的應用才更容易被審查和簽字。 +description: 編碼 agent 的 AGENTS.md、.cursor/rules 或 CLAUDE.md 不該只管程式碼風格。把權限、審批、審計和目標後設資料格式寫進去,AI 生成的應用才更容易被審查和簽字。 author: ObjectStack Team date: 2026-06-16T18:00:00+08:00 status: published @@ -15,11 +15,11 @@ tags: - AI 智慧體 --- -**先給結論**:在一個 AI 寫絕大部分程式碼的世界裡,你的 agent 規則檔案(`AGENTS.md`、`.cursor/rules`、`CLAUDE.md`)就是你**真正在生效的架構文件**。只拿它管縮排和元件庫,管的是"好不好看",不是"敢不敢上線"。把許可權、審批、審計和目標格式寫進去,才是在生成那一刻控制風險。 +**先給結論**:在一個 AI 寫絕大部分程式碼的世界裡,你的 agent 規則檔案(`AGENTS.md`、`.cursor/rules`、`CLAUDE.md`)就是你**真正在生效的架構文件**。只拿它管縮排和元件庫,管的是"好不好看",不是"敢不敢上線"。把權限、審批、審計和目標格式寫進去,才是在生成那一刻控制風險。 一個真實的小事故。某團隊的 `AGENTS.md` 寫得很認真:兩空格縮排、用內部 UI 庫、提交資訊用祈使句。agent 一條不落地照做,生成的程式碼"非常規範"。然後有人發現,它順手生成的 `GET /api/refunds` **把所有人的退款記錄都返回了**。 -程式碼評審時沒人攔下——因為它確實符合規則檔案裡的每一條。agent 沒違反任何規則,它只是**沒被告知許可權這回事**。那份規則裡,沒有一條是關於"誰能看哪些資料"的。它被教會了怎麼寫得好看,沒被教會怎麼寫得可治理。 +程式碼評審時沒人攔下——因為它確實符合規則檔案裡的每一條。agent 沒違反任何規則,它只是**沒被告知權限這回事**。那份規則裡,沒有一條是關於"誰能看哪些資料"的。它被教會了怎麼寫得好看,沒被教會怎麼寫得可治理。 ## 你的規則檔案,管錯了東西 @@ -27,24 +27,24 @@ tags: 盤一下大多數規則檔案裡寫了什麼:程式碼風格、目錄結構、用哪個庫、命名約定、提交規範。挑不出錯,但它們有一個共同點——**全是關於"程式碼長什麼樣",沒有一條關於"這個應用被允許做什麼"**。它們讓多個 agent、多次生成的產出保持一致,解決的是"長得像一家人";完全沒碰那些決定一個企業應用能不能上線的事:誰能看哪些資料、哪些動作要審批、出了事查不查得到。 -換句話說,**當寫程式碼這件事交給了 AI,規則檔案就從"程式碼規範"升級成了"架構與治理的約束"**——因為它是少數幾個能在**生成的那一刻**就把約束注入進去的地方。一旦程式碼被生成出來,再去補許可權、補審計,就是事後返工;而規則檔案是最早能把治理前置到生成階段的槓桿。 +換句話說,**當寫程式碼這件事交給了 AI,規則檔案就從"程式碼規範"升級成了"架構與治理的約束"**——因為它是少數幾個能在**生成的那一刻**就把約束注入進去的地方。一旦程式碼被生成出來,再去補權限、補審計,就是事後返工;而規則檔案是最早能把治理前置到生成階段的槓桿。 ## 把"可治理性"寫進規則,而不是事後補 -事後補治理,是當下最常見、也最貴的錯法:先讓 agent 生成,再回頭審許可權、補審計、加審批——也就是 [AI Agent 試點進不了生產那篇](/zh-Hant/blog/why-ai-agent-pilots-fail-four-layers/)裡說的治理返工。每生成一個應用就返工一次,規模化之後這筆賬會越來越難付。 +事後補治理,是當下最常見、也最貴的錯法:先讓 agent 生成,再回頭審權限、補審計、加審批——也就是 [AI Agent 試點進不了生產那篇](/zh-Hant/blog/why-ai-agent-pilots-fail-four-layers/)裡說的治理返工。每生成一個應用就返工一次,規模化之後這筆賬會越來越難付。 更省的做法,是讓規則把 agent 指向一個**本身就可治理的目標**。一份這樣的規則,核心不是風格,是約束產出的形態: ```text # AGENTS.md —— 生成業務應用時 - 把領域建模為 ObjectStack 物件(ObjectSchema),不要手寫表和遷移 -- 所有訪問許可權走 PermissionSet 宣告,絕不在接口裡手寫 if 判斷鑑權 +- 所有訪問權限走 PermissionSet 宣告,絕不在接口裡手寫 if 判斷鑑權 - 不要手寫 SQL 拼接或鑑權中介軟體——這些由執行時承擔 - 有審批需求的動作,宣告為掛在物件上的 flow,而不是寫在程式碼裡 - 產出必須是可審查的後設資料 diff,而不是大段實現 ``` -逐條看,每一行都在把一類"事後才會爆的風險"提前關掉:第二行讓越權從"接口裡漏寫一個判斷"變成"許可權被顯式宣告、執行時強制";第四行讓審批從"某段程式碼裡的硬邏輯"變成"掛在物件上、可被審計的流程"。在這種規則下,開頭那個 `GET /api/refunds` 不會再發生:agent 生成的是一個聲明瞭"按呼叫者許可權讀取"的 `support_refund` 物件,越權那條路從源頭就被關上了——而不是指望 agent 在某次生成裡"恰好記得"加判斷。 +逐條看,每一行都在把一類"事後才會爆的風險"提前關掉:第二行讓越權從"接口裡漏寫一個判斷"變成"權限被顯式宣告、執行時強制";第四行讓審批從"某段程式碼裡的硬邏輯"變成"掛在物件上、可被審計的流程"。在這種規則下,開頭那個 `GET /api/refunds` 不會再發生:agent 生成的是一個聲明瞭"按呼叫者權限讀取"的 `support_refund` 物件,越權那條路從源頭就被關上了——而不是指望 agent 在某次生成裡"恰好記得"加判斷。 ## 為什麼"讓 agent 生成 ObjectStack"是現實的:開放的飛輪 @@ -60,9 +60,9 @@ tags: ## 落地:今天就能加的三條 -不必一步到位重寫整份規則。如果你現在只往 agent 的規則檔案里加三條治理約束,按收益排序,應該是這三條: +不必一步到位重寫整份規則。如果你現在只往 agent 的規則檔案裡加三條治理約束,按收益排序,應該是這三條: -1. **"許可權必須顯式宣告,不準在程式碼裡手寫鑑權。"** 這一條直接消滅開頭那種"漏寫一個判斷就洩露全表"的事故——把鑑權從"agent 是否記得"變成"聲明裡是否寫了"。 +1. **"權限必須顯式宣告,不準在程式碼裡手寫鑑權。"** 這一條直接消滅開頭那種"漏寫一個判斷就洩露全表"的事故——把鑑權從"agent 是否記得"變成"聲明裡是否寫了"。 2. **"高風險動作(動錢、發合同、刪資料)必須宣告為帶審批的流程。"** 讓"該不該停下來等人"不再取決於 agent 的臨場判斷,而是一條可審計的規則。 3. **"產出可審查的宣告,而不是大段實現;改動要能在一屏 diff 裡看完。"** 這一條守住的是你自己的 Merge 按鈕——它強制 agent 交付你審得動的東西。 @@ -72,7 +72,7 @@ tags: 兩點必須說清,否則就把規則檔案神化了。 -第一,**規則檔案管的是產出的形態,不是 agent 的判斷力**。它能保證 agent 生成的是受治理的後設資料,保證不了它**理解對了業務意圖**。"該給客服多大的退款許可權"這種判斷,仍然要人來定、來 review——規則只是確保這個判斷有地方落、且會被強制執行,而不是散落在八千行裡。它把"該不該做"這個問題擺到你面前,但不替你回答。 +第一,**規則檔案管的是產出的形態,不是 agent 的判斷力**。它能保證 agent 生成的是受治理的後設資料,保證不了它**理解對了業務意圖**。"該給客服多大的退款權限"這種判斷,仍然要人來定、來 review——規則只是確保這個判斷有地方落、且會被強制執行,而不是散落在八千行裡。它把"該不該做"這個問題擺到你面前,但不替你回答。 第二,**別把它當成"官方 SDK"**。我這裡給的是一種打法、一份示例規則,不是某個一鍵安裝的官方檔案——你需要按自己的棧把它寫實、維護好。它的價值在思路:把治理前置到生成那一刻,而不是等程式碼長出來再補。 @@ -86,4 +86,4 @@ AI 寫程式碼的時代,團隊之間拉開差距的,不再是誰的工程 npm i -g @objectstack/cli && os start ``` -給你的 agent 寫上"建模為 ObjectStack 物件、許可權走宣告",讓它生成一個退款應用——然後試著讓它越權返回全部資料,看執行時怎麼從源頭拒絕它。 +給你的 agent 寫上"建模為 ObjectStack 物件、權限走宣告",讓它生成一個退款應用——然後試著讓它越權返回全部資料,看執行時怎麼從源頭拒絕它。 diff --git a/content/blog/is-lovable-safe-for-production/index.zh-Hant.mdx b/content/blog/is-lovable-safe-for-production/index.zh-Hant.mdx index c2d2e86..8588b45 100644 --- a/content/blog/is-lovable-safe-for-production/index.zh-Hant.mdx +++ b/content/blog/is-lovable-safe-for-production/index.zh-Hant.mdx @@ -51,7 +51,7 @@ create policy "Enable read access for all users" 平心而論,這個批評擊中了 Lovable,他們也作出了回應——一個安全掃描器,一個帶 SSO 和審計日誌的企業層。所以公正的問題是:這難道沒把口子堵上嗎? -看看掃描器能解決什麼、不能解決什麼。Lovable 的安全掃描會檢查資料庫配置、RLS 規則、雲專案設定和常見誤配置,這當然有價值,也比沒有強得多。但檢查*是否存在風險訊號*和證明*每條訪問路徑都符合業務許可權*不是一回事。後者需要理解資料模型、角色、記錄歸屬和異常路徑。掃描器可以幫你發現問題、降低漏檢機率,卻不能替你承擔「這套訪問控制已經可以上生產」的簽字責任。 +看看掃描器能解決什麼、不能解決什麼。Lovable 的安全掃描會檢查資料庫配置、RLS 規則、雲專案設定和常見誤配置,這當然有價值,也比沒有強得多。但檢查*是否存在風險訊號*和證明*每條訪問路徑都符合業務權限*不是一回事。後者需要理解資料模型、角色、記錄歸屬和異常路徑。掃描器可以幫你發現問題、降低漏檢機率,卻不能替你承擔「這套訪問控制已經可以上生產」的簽字責任。 而那些企業級控制——SSO、組織審計日誌——管的是*人們如何登入 Lovable*,不是*AI 在你應用裡寫了什麼 RLS*。它們是真實的、好的,而且與此正交。缺口不在 Lovable 的企業姿態。缺口在於:AI 為每個應用生成的那套訪問邏輯,對那個唯一為它負責的人來說是讀不懂的。 diff --git a/content/blog/low-code-vs-ai-native-app-platform/index.zh-Hant.mdx b/content/blog/low-code-vs-ai-native-app-platform/index.zh-Hant.mdx index ab38337..be11c3b 100644 --- a/content/blog/low-code-vs-ai-native-app-platform/index.zh-Hant.mdx +++ b/content/blog/low-code-vs-ai-native-app-platform/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 低程式碼 vs AI 原生應用平臺:複雜業務卡在哪裡 -description: 低程式碼解決的是更快搭頁面和流程;複雜業務真正卡住的是物件、許可權、整合、變更和可維護性。AI 原生平臺要把這些變成可審查的執行時後設資料。 +description: 低程式碼解決的是更快搭頁面和流程;複雜業務真正卡住的是物件、權限、整合、變更和可維護性。AI 原生平臺要把這些變成可審查的執行時後設資料。 author: ObjectStack Team date: 2026-06-03 status: published @@ -15,7 +15,7 @@ cover: ./cover.jpg tags: [] --- -**先給結論**:低程式碼解決的是“更快搭頁面”,複雜業務真正卡在物件、許可權、整合、變更和可維護性。AI 原生平臺先定義物件、把規則顯性化、讓改動可審查,差的就是這一層。 +**先給結論**:低程式碼解決的是“更快搭頁面”,複雜業務真正卡在物件、權限、整合、變更和可維護性。AI 原生平臺先定義物件、把規則顯性化、讓改動可審查,差的就是這一層。 低程式碼曾經給了很多企業一個很有吸引力的承諾: @@ -36,7 +36,7 @@ tags: [] - 拖一個表單; - 配一個列表; - 拉一條審批流; -- 給幾個角色分許可權。 +- 給幾個角色分權限。 一週內上線,大家都很開心。 @@ -58,12 +58,12 @@ tags: [] **第一,物件模型。** 客戶、訂單、合同、工單、裝置、員工、庫存,這些不是孤立表單,而是彼此關聯的 -業務物件。它們有生命週期、有狀態、有關係、有許可權。 +業務物件。它們有生命週期、有狀態、有關係、有權限。 -**第二,許可權模型。** +**第二,權限模型。** 誰能看,誰能改,誰能審批,誰能匯出,誰能跨部門檢視,誰能看到金額欄位。這些 -許可權不是頁面級別能解決的,必須深入到物件、記錄和欄位。 +權限不是頁面級別能解決的,必須深入到物件、記錄和欄位。 **第三,系統整合。** @@ -92,7 +92,7 @@ AI 加入以後,問題變了:系統必須讓 AI 也讀得懂。 如果一個應用的業務規則散落在幾十個配置頁面、隱藏指令碼、條件表示式和平臺私有 元件裡,AI 很難一次性理解它。它不知道哪個配置是核心規則,哪個是歷史補丁;不 -知道改一個欄位會影響哪條流程;更不知道哪些動作會觸碰許可權邊界。 +知道改一個欄位會影響哪條流程;更不知道哪些動作會觸碰權限邊界。 於是你會遇到一種尷尬情況: @@ -114,7 +114,7 @@ AI 能讀懂、能修改、能驗證的結構。 - 物件是什麼; - 欄位是什麼; - 關係是什麼; -- 許可權是什麼; +- 權限是什麼; - 動作是什麼; - 流程是什麼; - UI 從哪裡來; @@ -124,7 +124,7 @@ AI 能讀懂、能修改、能驗證的結構。 當這些東西都以清晰結構存在時,AI 才能真正幫你做事。 -它能讀懂當前系統,能生成變更,能解釋影響範圍,能幫你寫測試,能指出許可權風險, +它能讀懂當前系統,能生成變更,能解釋影響範圍,能幫你寫測試,能指出權限風險, 也能把一個需求落成一組可審查的改動。 ![概念示意圖](./platform-architecture-contrast.webp) @@ -146,7 +146,7 @@ AI-native 平臺應該從物件開始。 - 派單動作; - 關閉規則。 -物件定義清楚以後,表單、列表、API、許可權、搜尋、報表、Agent 工具都可以從同一份 +物件定義清楚以後,表單、列表、API、權限、搜尋、報表、Agent 工具都可以從同一份 模型生成。 這會帶來一個關鍵好處:系統裡不再有五套互相打架的定義。AI 也不需要在頁面、介面 @@ -178,7 +178,7 @@ AI-native 應用平臺更應該把 AI 生成的東西落到可審查的產物裡 - 哪個物件變了; - 哪個欄位新增了; -- 哪條許可權規則改了; +- 哪條權限規則改了; - 哪個流程動作新增了; - 哪些 API 會受影響。 @@ -211,7 +211,7 @@ Agent、流程和 API 都能在這些物件之上工作。 - 一次性資料收集; - 部門級輕量應用。 -但如果你要做的是長期執行的核心業務系統,尤其是需要接 AI、接許可權、接多個系統、 +但如果你要做的是長期執行的核心業務系統,尤其是需要接 AI、接權限、接多個系統、 持續迭代的應用,只靠低程式碼往往不夠。 你需要的不只是“搭得快”,而是“以後還能被理解、被修改、被治理”。 @@ -221,7 +221,7 @@ Agent、流程和 API 都能在這些物件之上工作。 如果你正在選擇平臺,可以問 6 個問題: 1. 業務物件是不是一等公民,還是隻是表單背後的資料表? -2. 許可權能不能做到物件、記錄、欄位和動作級別? +2. 權限能不能做到物件、記錄、欄位和動作級別? 3. AI 能不能讀懂系統結構,而不是隻看頁面截圖? 4. 每次改動能不能版本化、審查和回滾? 5. 能不能連線現有系統,而不是強迫遷移? @@ -237,7 +237,7 @@ ObjectOS 不是要把低程式碼換一個名字再賣一遍。 我們更關心的是:如何把業務系統變成人和 AI 都能讀懂、能安全修改、能持續演化的 結構。 -這意味著從物件開始,而不是從頁面開始;從許可權和審計開始,而不是最後補安全;從 +這意味著從物件開始,而不是從頁面開始;從權限和審計開始,而不是最後補安全;從 連線現有系統開始,而不是要求企業推倒重來。 AI-native 應用平臺真正要解決的,不是“少寫幾行程式碼”。 diff --git a/content/blog/manufacturing-legacy-systems-ai/index.zh-Hant.mdx b/content/blog/manufacturing-legacy-systems-ai/index.zh-Hant.mdx index 1631ee2..162c89e 100644 --- a/content/blog/manufacturing-legacy-systems-ai/index.zh-Hant.mdx +++ b/content/blog/manufacturing-legacy-systems-ai/index.zh-Hant.mdx @@ -85,7 +85,7 @@ AI 接入製造業報表的第一價值,不是生成漂亮圖表,而是讓 > “哪些供應商的到貨延遲正在影響生產計劃?” -這些問題不是簡單聊天。AI 需要在許可權之下查詢 ERP、MES、WMS 或工單資料,把結果 +這些問題不是簡單聊天。AI 需要在權限之下查詢 ERP、MES、WMS 或工單資料,把結果 聚合起來,再給出解釋。 這一步可以完全只讀,不改任何生產系統,卻能立刻提升管理效率。 @@ -168,13 +168,13 @@ AI 建議升級某個工單、提醒某個負責人、關注某個供應商, 物件建好以後,AI 不需要直接面對一堆表名和欄位名。它看到的是“訂單、物料、庫存、 工單、裝置”這些業務概念,以及它們之間的關係。 -同時,許可權也要跟上: +同時,權限也要跟上: - 車間主管只能看本車間; - 採購只能看供應商和採購資料; - 銷售不能看敏感成本欄位; - 老闆可以看彙總; -- AI 不能越過使用者本人的許可權。 +- AI 不能越過使用者本人的權限。 這一步做好,AI 才能進入真實製造業務,而不是停留在檔案問答和報表截圖分析。 @@ -195,7 +195,7 @@ AI 建議升級某個工單、提醒某個負責人、關注某個供應商, **第 3 周:建模物件。** -把訂單、物料、庫存、裝置、工單這些物件建出來,補上欄位含義、關係和許可權。 +把訂單、物料、庫存、裝置、工單這些物件建出來,補上欄位含義、關係和權限。 **第 4 周:上線只讀 AI 助手。** @@ -217,7 +217,7 @@ AI 建議升級某個工單、提醒某個負責人、關注某個供應商, 所以製造業接 AI,有幾條底線: - 資料先只讀; -- 許可權繼承現有系統; +- 權限繼承現有系統; - 高風險動作必須確認; - 關鍵操作必須審計; - 不要求業務系統一次性遷移; @@ -230,7 +230,7 @@ AI 建議升級某個工單、提醒某個負責人、關注某個供應商, ObjectOS 的目標不是讓製造企業推倒重來。 ERP、MES、WMS、工單系統都已經在跑,裡面有真實業務和多年資料。更務實的方式,是 -把這些系統連線起來,把關鍵表和 API 建模成物件,再讓 AI 在許可權之下查詢、分析、 +把這些系統連線起來,把關鍵表和 API 建模成物件,再讓 AI 在權限之下查詢、分析、 建議和觸發低風險流程。 這相當於給既有系統加了一層 AI 能讀懂的業務結構。 diff --git a/content/blog/mcp-governed-tool-layer/index.zh-Hant.mdx b/content/blog/mcp-governed-tool-layer/index.zh-Hant.mdx index 1908262..ee10412 100644 --- a/content/blog/mcp-governed-tool-layer/index.zh-Hant.mdx +++ b/content/blog/mcp-governed-tool-layer/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: MCP 安全:為什麼協議還需要受治理的工具層 -description: MCP 和 A2A 讓 agent 連線工具與其他 agent 變得更容易,但連線不等於授權。企業缺的不是再包一層介面,而是每次呼叫都帶身份、強制許可權、留下審計的工具層。 +description: MCP 和 A2A 讓 agent 連線工具與其他 agent 變得更容易,但連線不等於授權。企業缺的不是再包一層介面,而是每次呼叫都帶身份、強制權限、留下審計的工具層。 author: ObjectStack Team date: 2026-06-16T14:00:00+08:00 status: published @@ -17,7 +17,7 @@ tags: - A2A --- -**先給結論**:連線協議(MCP、A2A)已經標準化,企業真正缺的是協議背後那一層——每次呼叫都帶身份、強制許可權、留痕,而且不用你手寫的受治理工具層。 +**先給結論**:連線協議(MCP、A2A)已經標準化,企業真正缺的是協議背後那一層——每次呼叫都帶身份、強制權限、留痕,而且不用你手寫的受治理工具層。 一家公司的工程師,花了一個下午,把生產庫包了一層 MCP server,讓內部 agent"連上了"。演示很順,老闆很滿意。 @@ -43,27 +43,27 @@ agent 很樂意地照做了——全公司的,一條不落,包括這位銷 這話對,但它低估了兩件事。 -第一,**它不擴充套件。** 一兩個 server 你能仔細加鑑權,可企業很快就是幾十個 server、上百個工具,每一個都要手寫一遍身份核驗、許可權判斷、審計落賬——這本身就是一大坨沒人讀的膠水程式碼,正是"技術債"那篇講的那種債,只是這次長在工具層。 +第一,**它不擴充套件。** 一兩個 server 你能仔細加鑑權,可企業很快就是幾十個 server、上百個工具,每一個都要手寫一遍身份核驗、權限判斷、審計落賬——這本身就是一大坨沒人讀的膠水程式碼,正是"技術債"那篇講的那種債,只是這次長在工具層。 第二,**"我們會小心"不是一種架構。** 它是一種依賴人始終不犯錯、不趕工、不走捷徑的承諾。而我們都知道,deadline 一來,"先連上、鑑權回頭補"的那條路,往往是最好走的那條。一個安全屬性如果要靠每個人每次都自覺,它遲早會破——開頭那家公司的工程師,也並不是不懂安全,他只是趕時間。 -真正的解法不是"更小心地手寫",而是讓"帶身份、帶許可權、帶留痕"成為工具的**預設形態**,省不掉、也不用每次手寫。 +真正的解法不是"更小心地手寫",而是讓"帶身份、帶權限、帶留痕"成為工具的**預設形態**,省不掉、也不用每次手寫。 ## 把裸介面包成工具,等於發了張超級使用者通行證 為什麼裸介面對 agent 這麼危險?因為被包的那些介面,**當初是為可信的後端服務設計的,不是為一個會自己決策的 agent 設計的**。它們預設呼叫方已經鑑過權,所以自己不怎麼校驗身份。直接暴露成 MCP 工具時: -- agent 拿到的是一個**沒有身份**的介面——它不是"以這位銷售的身份查",而是以服務的許可權查所有; -- 它的寫操作按**服務的許可權**算,不是發起人的,出錯無從歸責; +- agent 拿到的是一個**沒有身份**的介面——它不是"以這位銷售的身份查",而是以服務的權限查所有; +- 它的寫操作按**服務的權限**算,不是發起人的,出錯無從歸責; - 這些呼叫**不進任何業務審計賬**,事後查無可查(開頭那場洩露,正卡在這條上)。 一句話:把裸介面包成 MCP 工具,等於給 agent 發了一張超級使用者通行證。 -## 缺的那一層:每次呼叫都帶身份、許可權和留痕 +## 缺的那一層:每次呼叫都帶身份、權限和留痕 協議之上真正該補的,是一個受治理的工具層——agent 調的不是裸介面,而是一組每次呼叫都走完和人一模一樣關卡的受控動作: -![一次受治理的工具呼叫的生命週期:以使用者身份發起、執行時核驗許可權、受控執行、寫入審計](./tool-call-lifecycle.svg) +![一次受治理的工具呼叫的生命週期:以使用者身份發起、執行時核驗權限、受控執行、寫入審計](./tool-call-lifecycle.svg) 裸介面的做法是把中間三步全省掉,而省掉的恰好是"準不準做"和"記不記賬"。這裡最容易被忽視的是第一步——**身份傳播**:agent 必須以發起人(那位銷售)的身份去呼叫,而不是以服務自己的身份。一旦身份對了,"他只能看自己大區的合同"就成了執行時能強制的事實,而不是一句但願模型會遵守的提示。 @@ -71,9 +71,9 @@ agent 很樂意地照做了——全公司的,一條不落,包括這位銷 身份傳播這件事,在 A2A(agent 調 agent)普及之後會變得更要命,也最容易出漏洞。 -設想:銷售對"銷售助理 agent"說"幫我準備這個客戶的續約材料"。這個 agent 自己搞不定,於是去調"財務 agent"拉賬期、調"合同 agent"取歷史條款。現在問題來了——財務 agent 執行時,用的是**誰**的許可權?如果鏈條中間任何一跳把身份弄丟了,變成"以財務 agent 服務自己的許可權"去查,那這位銷售就藉著一串 agent 接力,看到了他本來無權看的賬務。**越權不是發生在第一跳,而是悄悄發生在第二、第三跳。** +設想:銷售對"銷售助理 agent"說"幫我準備這個客戶的續約材料"。這個 agent 自己搞不定,於是去調"財務 agent"拉賬期、調"合同 agent"取歷史條款。現在問題來了——財務 agent 執行時,用的是**誰**的權限?如果鏈條中間任何一跳把身份弄丟了,變成"以財務 agent 服務自己的權限"去查,那這位銷售就藉著一串 agent 接力,看到了他本來無權看的賬務。**越權不是發生在第一跳,而是悄悄發生在第二、第三跳。** -裸介面式的連線裡,這種"身份在鏈條中蒸發"幾乎是預設結果,而且因為沒有統一審計賬,事後根本還原不出這串接力到底誰看了什麼。受治理的工具層要做對的,是讓發起人的身份**沿著整條 A2A 鏈一路傳下去**,每一跳都以最初那個人的許可權被核驗、被記賬。協議(A2A)負責把 agent 接起來,但"接力過程中許可權不丟、留痕不斷",得靠協議背後那層治理來保證。 +裸介面式的連線裡,這種"身份在鏈條中蒸發"幾乎是預設結果,而且因為沒有統一審計賬,事後根本還原不出這串接力到底誰看了什麼。受治理的工具層要做對的,是讓發起人的身份**沿著整條 A2A 鏈一路傳下去**,每一跳都以最初那個人的權限被核驗、被記賬。協議(A2A)負責把 agent 接起來,但"接力過程中權限不丟、留痕不斷",得靠協議背後那層治理來保證。 ## 你的工具層健不健康,五個問題就能查 @@ -81,11 +81,11 @@ agent 很樂意地照做了——全公司的,一條不落,包括這位銷 2. 一次越權呼叫,會被執行時**當場攔下**,還是靠模型"自覺不做"? 3. 每次工具呼叫,進**審計賬**了嗎? 4. agent 調 agent 時,最初那個人的身份**傳下去**了嗎? -5. 改一條許可權,是**一處生效**,還是要去每個 server 裡改一遍? +5. 改一條權限,是**一處生效**,還是要去每個 server 裡改一遍? -## 工具不該一個個手寫,而該從定義里長出來 +## 工具不該一個個手寫,而該從定義裡長出來 -那怎麼既不手寫、又預設安全?答案是:讓工具從業務定義裡**自動長出來**。你宣告物件和許可權——比如一個客服退款場景: +那怎麼既不手寫、又預設安全?答案是:讓工具從業務定義裡**自動長出來**。你宣告物件和權限——比如一個客服退款場景: ```ts export const Refund = ObjectSchema.create({ @@ -101,7 +101,7 @@ export const AgentRole: Security.PermissionSet = { }; ``` -開源 ObjectStack 執行時就**自動**把它投影成一組 agent 可呼叫的受治理工具:查詢、建立退款,每個都內建上面那條許可權的核驗、以登入使用者身份執行、落進統一審計賬;"退款超額走審批"是掛在物件上的流程,工具命中時自動暫停等簽字——這些都不用在工具程式碼裡手寫。改一條許可權,所有相關工具一處生效。 +開源 ObjectStack 執行時就**自動**把它投影成一組 agent 可呼叫的受治理工具:查詢、建立退款,每個都內建上面那條權限的核驗、以登入使用者身份執行、落進統一審計賬;"退款超額走審批"是掛在物件上的流程,工具命中時自動暫停等簽字——這些都不用在工具程式碼裡手寫。改一條權限,所有相關工具一處生效。 對照一下危險的版本,差別就清楚了: @@ -110,13 +110,13 @@ export const AgentRole: Security.PermissionSet = { { "name": "run_sql", "description": "執行任意 SQL 查詢", "params": { "sql": "string" } } ``` -你不為每個工具寫許可權程式碼,你只宣告許可權;工具是定義的投影。MCP 負責"怎麼連",這層負責"連上之後準不準做、記不記賬"——而且不用你手寫。 +你不為每個工具寫權限程式碼,你只宣告權限;工具是定義的投影。MCP 負責"怎麼連",這層負責"連上之後準不準做、記不記賬"——而且不用你手寫。 ## 先潑一盆冷水:它管的是"能不能",不是"該不該" 這裡要劃清一條邊界,否則容易神化它。 -受治理的工具層,約束的是**爆炸半徑**,不是**判斷力**。它能保證 agent 做不了它無權做的事——這很重要,開頭那次洩露就會被它當場攔下。但它**攔不住一個"許可權之內、卻很蠢"的動作**:如果一個客服 agent 本來就有權發起退款,它給了一筆不該退的退款,工具層會照常放行,因為這在許可權之內。 +受治理的工具層,約束的是**爆炸半徑**,不是**判斷力**。它能保證 agent 做不了它無權做的事——這很重要,開頭那次洩露就會被它當場攔下。但它**攔不住一個"權限之內、卻很蠢"的動作**:如果一個客服 agent 本來就有權發起退款,它給了一筆不該退的退款,工具層會照常放行,因為這在權限之內。 換句話說,它解決的是"越權"和"無痕",不解決"決策對不對"。後者還得靠評測、靠把高風險動作留給人審批、靠流程設計。誰要是告訴你"接上受治理工具層,agent 就絕對安全了",那是誇大。它是必要的地基,不是全部的樓——但沒有這層地基,開頭那場洩露就會一再發生。 @@ -124,10 +124,10 @@ export const AgentRole: Security.PermissionSet = { 把 MCP 比作 TCP/IP 沒錯,但別忘了網際網路值錢的部分,是 TCP/IP 之上那層身份與問責長出來之後才有的。 -agent 生態正處在同一個時刻。連線越來越標準,開頭那個"樂於助人的下午"會越來越多——因為連上太容易了;等 A2A 把 agent 串成鏈,沒有治理的連線只會把越權藏得更深。接下來真正稀缺的,不是又一個連線協議,而是協議背後那個會強制許可權、會沿鏈路保住身份、會留痕、還不用你手寫的工具層。它不解決一切,但沒有它,很多企業場景都不敢上線。 +agent 生態正處在同一個時刻。連線越來越標準,開頭那個"樂於助人的下午"會越來越多——因為連上太容易了;等 A2A 把 agent 串成鏈,沒有治理的連線只會把越權藏得更深。接下來真正稀缺的,不是又一個連線協議,而是協議背後那個會強制權限、會沿鏈路保住身份、會留痕、還不用你手寫的工具層。它不解決一切,但沒有它,很多企業場景都不敢上線。 ```bash npm i -g @objectstack/cli && os start ``` -宣告一個物件和它的許可權,讓 agent 通過工具去越權改一條它無權改的資料——看執行時怎麼當場攔下,並把這次嘗試也記進賬裡。 +宣告一個物件和它的權限,讓 agent 通過工具去越權改一條它無權改的資料——看執行時怎麼當場攔下,並把這次嘗試也記進賬裡。 diff --git a/content/blog/metadata-not-code-generation/index.zh-Hant.mdx b/content/blog/metadata-not-code-generation/index.zh-Hant.mdx index dbaa633..243bbc7 100644 --- a/content/blog/metadata-not-code-generation/index.zh-Hant.mdx +++ b/content/blog/metadata-not-code-generation/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 後設資料,不是程式碼生成:AI 應用為什麼可治理 -description: 程式碼生成能讓原型變快,但企業應用真正需要的是物件、欄位、關係、檢視、許可權、流程、動作和 agent 工具共同受控的後設資料執行時。 +description: 程式碼生成能讓原型變快,但企業應用真正需要的是物件、欄位、關係、檢視、權限、流程、動作和 agent 工具共同受控的後設資料執行時。 author: ObjectStack Team date: 2026-06-05T10:40:00+08:00 status: published @@ -13,13 +13,13 @@ cover: ./cover.svg tags: [] --- -**先給結論**:AI 原生應用的核心不是把需求變成一堆程式碼,而是生成物件、許可權、流程、agent 工具共同受控的後設資料——程式碼能跑,後設資料才改得動、治得住。 +**先給結論**:AI 原生應用的核心不是把需求變成一堆程式碼,而是生成物件、權限、流程、agent 工具共同受控的後設資料——程式碼能跑,後設資料才改得動、治得住。 過去幾年,低程式碼平臺解決了一個很具體的問題:不要每個內部系統都從零寫頁面、寫表單、寫流程。 現在 AI 又把這個問題往前推了一步:既然低程式碼可以拖拽搭應用,那能不能直接用一句話生成應用? -答案是可以,但這裡有一個很容易踩的坑:如果把“AI 生成應用”理解成“AI 生成一堆程式碼”,很快會遇到企業應用的老問題。第一版看起來很快,第二版開始變慢;頁面能跑,許可權不好管;表單能提交,流程難追蹤;AI 能回答,Agent 不知道哪些動作能做、哪些動作不能做。 +答案是可以,但這裡有一個很容易踩的坑:如果把“AI 生成應用”理解成“AI 生成一堆程式碼”,很快會遇到企業應用的老問題。第一版看起來很快,第二版開始變慢;頁面能跑,權限不好管;表單能提交,流程難追蹤;AI 能回答,Agent 不知道哪些動作能做、哪些動作不能做。 真正的 AI 原生應用平臺,核心不是程式碼生成,而是後設資料生成。 @@ -29,9 +29,9 @@ tags: [] 站在業務負責人和 IT 負責人的角度,看一個應用平臺,最重要的問題通常不是“第一版能不能生成出來”,而是: - 業務變化時能不能改; -- 改了欄位以後,表單、列表、許可權、流程是否同步; +- 改了欄位以後,表單、列表、權限、流程是否同步; - 新增審批規則時,舊資料和舊流程是否還能解釋; -- AI Agent 是否繼承使用者許可權; +- AI Agent 是否繼承使用者權限; - 誰看過什麼、改過什麼、批准過什麼,能不能審計; - 這個系統半年後是不是還可維護。 @@ -74,13 +74,13 @@ tags: [] | 欄位 | 每個物件有哪些屬性,型別、必填、公式、敏感性是什麼 | | 關係 | 物件之間如何關聯,一對多、多對多、引用和反向引用是什麼 | | 檢視 | 不同角色如何檢視資料,列表、看板、表單、詳情、儀表盤如何組織 | -| 許可權 | 誰能看、誰能改、能看哪些記錄、能操作哪些欄位 | +| 權限 | 誰能看、誰能改、能看哪些記錄、能操作哪些欄位 | | 流程 | 狀態如何流轉,哪些條件觸發審批、通知和自動化 | | 動作 | 建立任務、發起審批、生成報告、傳送提醒等業務動作 | | Agent 工具 | AI 能查詢什麼、建議什麼、執行什麼、什麼時候必須停下來等人確認 | | 審計 | AI 建議了什麼,人確認了什麼,系統最終執行了什麼 | -這些後設資料共同驅動 UI、API、許可權、自動化和 Agent。 +這些後設資料共同驅動 UI、API、權限、自動化和 Agent。 頁面只是後設資料的一種表現。API 也是。Agent 工具也是。這樣系統才不會因為入口不同而行為不一致。 @@ -97,7 +97,7 @@ Builder 應該先產出: 1. 主物件:客戶、工單、訊息、知識庫、SLA、升級記錄; 2. 欄位:問題型別、優先順序、情緒、影響範圍、截止時間; 3. 檢視:客服佇列、主管看板、快超時工單、高風險客戶; -4. 許可權:客戶、客服、主管、管理員分別能看什麼; +4. 權限:客戶、客服、主管、管理員分別能看什麼; 5. 流程:提交、分類、處理、升級、關閉、覆盤; 6. Agent 工具:摘要、分類、知識匹配、回覆草稿、升級建議; 7. 審計:AI 初判、人工修改、傳送確認、升級原因。 @@ -108,7 +108,7 @@ Builder 應該先產出: ## 和傳統低程式碼相比,AI 改變了什麼 -傳統低程式碼平臺通常要求使用者理解配置介面:物件設計器、欄位面板、流程畫布、許可權矩陣、表示式編輯器。 +傳統低程式碼平臺通常要求使用者理解配置介面:物件設計器、欄位面板、流程畫布、權限矩陣、表示式編輯器。 AI Builder 不應該推翻這些能力,而應該降低表達成本。 @@ -116,7 +116,7 @@ AI Builder 不應該推翻這些能力,而應該降低表達成本。 > 把高風險合同單獨放到一個法務看板裡,金額超過 50 萬的再加財務複核。 -平臺把這句話拆成物件篩選、檢視、流程條件、審批節點和許可權變更,並展示變更計劃讓使用者確認。 +平臺把這句話拆成物件篩選、檢視、流程條件、審批節點和權限變更,並展示變更計劃讓使用者確認。 這才是 AI 對低程式碼的真正增強:不是讓平臺變成黑盒,而是讓業務語言直接進入平臺結構。 @@ -124,9 +124,9 @@ AI Builder 不應該推翻這些能力,而應該降低表達成本。 如果你在評估 AI 應用平臺,不要只看它能不能生成一個漂亮頁面。更應該問: -1. 它生成的是程式碼,還是可解釋的物件、欄位、檢視、許可權和流程? +1. 它生成的是程式碼,還是可解釋的物件、欄位、檢視、權限和流程? 2. 業務人員後續能否用自然語言修改應用結構? -3. 許可權是否是執行時統一能力,而不是頁面裡的臨時判斷? +3. 權限是否是執行時統一能力,而不是頁面裡的臨時判斷? 4. AI Agent 是否只能通過受控工具訪問和修改資料? 5. 每次 AI 建議、人工確認和系統執行是否有審計? 6. 當業務規則變化時,是改後設資料,還是重新生成程式碼? @@ -137,7 +137,7 @@ AI Builder 不應該推翻這些能力,而應該降低表達成本。 ObjectStack 的方向,是讓自然語言生成後設資料,再由後設資料驅動執行時。 -使用者說一句需求,平臺生成物件、欄位、關係、檢視、許可權、流程、動作和 Agent 工具。應用執行後,業務人員繼續用自然語言修改它。AI Agent 也在同一套物件、許可權和動作邊界內工作。 +使用者說一句需求,平臺生成物件、欄位、關係、檢視、權限、流程、動作和 Agent 工具。應用執行後,業務人員繼續用自然語言修改它。AI Agent 也在同一套物件、權限和動作邊界內工作。 程式碼仍然存在,但它不再是業務變化的唯一承載物。業務結構進入後設資料層,才能被生成、理解、修改、治理和審計。 diff --git a/content/blog/natural-language-to-app-metadata/index.zh-Hant.mdx b/content/blog/natural-language-to-app-metadata/index.zh-Hant.mdx index 628a658..85d6af7 100644 --- a/content/blog/natural-language-to-app-metadata/index.zh-Hant.mdx +++ b/content/blog/natural-language-to-app-metadata/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. -title: 從自然語言到應用後設資料:AI Builder 如何生成物件和許可權 -description: AI Builder 真正重要的不是把一句話變成頁面,而是把業務需求拆成物件、欄位、檢視、流程、許可權、自動化和 agent 工具。 +title: 從自然語言到應用後設資料:AI Builder 如何生成物件和權限 +description: AI Builder 真正重要的不是把一句話變成頁面,而是把業務需求拆成物件、欄位、檢視、流程、權限、自動化和 agent 工具。 author: ObjectStack Team date: 2026-06-05T10:30:00+08:00 status: published @@ -14,7 +14,7 @@ tags: - AI 智慧體 --- -**先給結論**:好的 AI Builder 不是把一句話變成幾個頁面,而是把一句業務需求拆成物件、欄位、檢視、流程、許可權和 agent 工具——一份可執行、可修改、可治理的應用規格。 +**先給結論**:好的 AI Builder 不是把一句話變成幾個頁面,而是把一句業務需求拆成物件、欄位、檢視、流程、權限和 agent 工具——一份可執行、可修改、可治理的應用規格。 “一句話生成應用”聽起來很有衝擊力,但這句話本身容易誤導。 @@ -93,9 +93,9 @@ AI Builder 應該根據角色生成初始檢視: 使用者不需要從空白畫布開始。 -## 第四步:生成許可權和動作邊界 +## 第四步:生成權限和動作邊界 -許可權是 AI Builder 最容易被忽略、但最能區分專業度的地方。 +權限是 AI Builder 最容易被忽略、但最能區分專業度的地方。 在這個供應商應用裡,至少要生成幾類邊界: @@ -150,7 +150,7 @@ AI 原生應用的最後一層,是 Agent 工具。 - 發起高風險採購審批; - 生成供應商月度風險報告。 -每個工具都要有輸入、輸出、許可權和審計。 +每個工具都要有輸入、輸出、權限和審計。 當用戶問: @@ -168,7 +168,7 @@ Agent 應該先查供應商、資質、交付、質量和報價,再給出結 - 每個物件有哪些關鍵欄位; - 物件之間有哪些關係; - 將生成哪些檢視; -- 哪些許可權規則會生效; +- 哪些權限規則會生效; - 哪些自動化會執行; - Agent 可以呼叫哪些工具; - 哪些動作需要人工確認。 @@ -181,7 +181,7 @@ ObjectStack 的 AI Builder 應該把自然語言轉成應用規格,再由規 這條鏈路是: -**自然語言需求 → 業務物件 → 欄位關係 → 視圖表單 → 許可權邊界 → 流程自動化 → Agent 工具 → 審計執行時** +**自然語言需求 → 業務物件 → 欄位關係 → 視圖表單 → 權限邊界 → 流程自動化 → Agent 工具 → 審計執行時** 這條鏈路越清楚,讀者越容易理解平臺差異。 diff --git a/content/blog/objectos-action-tools/index.zh-Hant.mdx b/content/blog/objectos-action-tools/index.zh-Hant.mdx index ad060f9..db413e3 100644 --- a/content/blog/objectos-action-tools/index.zh-Hant.mdx +++ b/content/blog/objectos-action-tools/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: AI 如何觸發業務動作:Action 後設資料如何保證受控執行 -description: AI agent 的價值不只是回答問題,而是幫助使用者更新記錄、建立任務、發起審批和推動流程。ObjectOS 用 Action 後設資料把按鈕、流程和審批開放給 AI,同時保留許可權、確認和審計。 +description: AI agent 的價值不只是回答問題,而是幫助使用者更新記錄、建立任務、發起審批和推動流程。ObjectOS 用 Action 後設資料把按鈕、流程和審批開放給 AI,同時保留權限、確認和審計。 author: ObjectStack Team date: 2026-06-05T11:10:00+08:00 status: published @@ -24,7 +24,7 @@ tags: AI 說“建議把這個線索轉為商機”,銷售還要自己去 CRM 點按鈕;AI 說“建議發起高風險審批”,法務還要開啟流程系統;AI 說“這張報銷需要退回”,財務還要手動改狀態、寫原因、通知員工。 -如果 AI 只能回答,業務還是停在原地。AI 原生應用必須讓 AI 能在許可權範圍內推進工作:建立記錄、更新狀態、發起審批、生成任務、呼叫流程。 +如果 AI 只能回答,業務還是停在原地。AI 原生應用必須讓 AI 能在權限範圍內推進工作:建立記錄、更新狀態、發起審批、生成任務、呼叫流程。 但這件事不能靠給 agent 隨便開 API。ObjectOS 的關鍵設計是:把業務系統裡已經存在的按鈕、流程和審批沉澱為 Action 後設資料,再有選擇地開放給 AI。 @@ -40,7 +40,7 @@ AI 說“建議把這個線索轉為商機”,銷售還要自己去 CRM 點按 問題是,真實業務系統裡“轉換線索”從來不只是幾次資料寫入。它可能包含: -- 檢查當前使用者是否有許可權轉換; +- 檢查當前使用者是否有權限轉換; - 校驗必填欄位是否完整; - 判斷是否已有重複客戶; - 建立聯絡人、客戶和商機; @@ -101,7 +101,7 @@ ObjectOS 採用顯式開放的方式:動作可以存在於業務系統中, > 這批報銷裡哪些可能違反差旅政策?把證據列出來,低風險的通過,高風險的建立複核任務。 -這些對話背後,不只是模型在“說話”。平臺需要把使用者意圖拆成查詢、判斷、動作和流程,並把每一步限制在當前使用者許可權內。 +這些對話背後,不只是模型在“說話”。平臺需要把使用者意圖拆成查詢、判斷、動作和流程,並把每一步限制在當前使用者權限內。 Action 後設資料的價值正在這裡:它讓 AI 知道哪些業務動作真實存在、需要哪些輸入、呼叫後會產生什麼結果、是否需要確認。 @@ -125,7 +125,7 @@ Action 後設資料的價值正在這裡:它讓 AI 知道哪些業務動作真 - UI 裡的規則更新了,AI 工具沒更新; - API 引數變了,工具還在傳舊欄位; -- 許可權策略變了,agent 仍然能直接呼叫; +- 權限策略變了,agent 仍然能直接呼叫; - 審批要求增加了,AI 工具沒有進入審批; - 人工操作有日誌,AI 操作沒有完整記錄。 @@ -149,7 +149,7 @@ ObjectOS 用 Action 統一這些入口,就是為了避免“人走一套、AI ObjectOS 想解決的不是“給 agent 多寫幾個工具”,而是讓 AI 成為業務系統裡受治理的執行者。 -它通過 Action 後設資料把業務動作統一起來:同一個動作可以出現在介面上,可以被流程呼叫,也可以在明確開放後被 agent 使用。動作引數來自物件和欄位定義,執行經過許可權、確認和審計,結果回到同一套業務資料。 +它通過 Action 後設資料把業務動作統一起來:同一個動作可以出現在介面上,可以被流程呼叫,也可以在明確開放後被 agent 使用。動作引數來自物件和欄位定義,執行經過權限、確認和審計,結果回到同一套業務資料。 這就是 AI 原生應用和普通聊天機器人的區別。 diff --git a/content/blog/objectos-agent-permission-boundaries/index.zh-Hant.mdx b/content/blog/objectos-agent-permission-boundaries/index.zh-Hant.mdx index e2f3a7c..152ca61 100644 --- a/content/blog/objectos-agent-permission-boundaries/index.zh-Hant.mdx +++ b/content/blog/objectos-agent-permission-boundaries/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. -title: AI Agent 許可權檢查跑在哪一層:查詢下推、欄位脫敏與工具閘門 -description: 該不該守許可權已經沒有爭議;決定這道邊界真假的是檢查跑在哪一層。資料進入模型上下文之後再過濾,等於沒過濾——那是紙面許可權。本文拆開查詢、欄位、工具閘門三個執行點,以及平臺明確不兜底的兩處。 +title: AI Agent 權限檢查跑在哪一層:查詢下推、欄位脫敏與工具閘門 +description: 該不該守權限已經沒有爭議;決定這道邊界真假的是檢查跑在哪一層。資料進入模型上下文之後再過濾,等於沒過濾——那是紙面權限。本文拆開查詢、欄位、工具閘門三個執行點,以及平臺明確不兜底的兩處。 author: ObjectStack Team date: 2026-06-05T11:00:00+08:00 status: published @@ -12,12 +12,12 @@ industries: [] cover: ./cover.svg tags: - AI 智慧體 - - 智慧體許可權 + - 智慧體權限 --- -**先給結論**:agent 該不該受許可權約束,這件事已經不用爭了。真正決定這道邊界是真是假的,是**檢查跑在哪一層**——在資料進入模型上下文之前,還是之後。之後才補的過濾不是邊界,是**紙面許可權**:寫下來像訪問控制,執行時什麼都不做。所以採購和評審時該問的不是"你們有沒有許可權模型",而是"你們能不能證明某一條許可權不是紙做的"。 +**先給結論**:agent 該不該受權限約束,這件事已經不用爭了。真正決定這道邊界是真是假的,是**檢查跑在哪一層**——在資料進入模型上下文之前,還是之後。之後才補的過濾不是邊界,是**紙面權限**:寫下來像訪問控制,執行時什麼都不做。所以採購和評審時該問的不是"你們有沒有權限模型",而是"你們能不能證明某一條權限不是紙做的"。 -"agent 到底該不該繼承使用者身份、該不該受審批和審計約束",我們在 [AI Agent 資料安全邊界:如何在企業許可權內工作](/zh-Hant/blog/ai-agent-business-data-security-boundaries/) 裡單獨論證過。這篇預設你已經同意那一層,只問後面那個更難回答的問題:這道邊界具體落在哪一行程式碼上,以及它失效的時候,你能看見嗎? +"agent 到底該不該繼承使用者身份、該不該受審批和審計約束",我們在 [AI Agent 資料安全邊界:如何在企業權限內工作](/zh-Hant/blog/ai-agent-business-data-security-boundaries/) 裡單獨論證過。這篇預設你已經同意那一層,只問後面那個更難回答的問題:這道邊界具體落在哪一行程式碼上,以及它失效的時候,你能看見嗎? ![同一個請求的兩條路徑:紅線之前攔,還是紅線之後補](./security-pipeline.svg) @@ -25,15 +25,15 @@ tags: 把一次 agent 請求攤平來看,中間有一條線:**資料進入模型上下文的那一刻**。 -線的左邊,許可權還能被強制執行——不該出現的行可以根本不產生,不該看的欄位可以在離開資料層時就被替換掉。線的右邊,一切都變成了"希望":希望模型不要複述、希望它按提示詞自覺、希望摘要裡不會把幾個欄位拼成一句自然的話。 +線的左邊,權限還能被強制執行——不該出現的行可以根本不產生,不該看的欄位可以在離開資料層時就被替換掉。線的右邊,一切都變成了"希望":希望模型不要複述、希望它按提示詞自覺、希望摘要裡不會把幾個欄位拼成一句自然的話。 -企業裡最貴的那類錯誤,不是這條線畫錯了,而是**沒人知道自己已經站線上的右邊**。因為紙面許可權從來不報錯。它在後設資料裡讀起來是治理,在評審裡能過,在執行時什麼都不做。 +企業裡最貴的那類錯誤,不是這條線畫錯了,而是**沒人知道自己已經站線上的右邊**。因為紙面權限從來不報錯。它在後設資料裡讀起來是治理,在評審裡能過,在執行時什麼都不做。 下面三種失效,都是真實存在的形態。共同點是:它們不會讓系統崩掉,只會讓你以為自己有邊界。 ## 失效一:寫下來像授權,跑起來像"這條授權不存在" -行級許可權在 ObjectStack 裡是可宣告的後設資料:讀用 `permissions[].rowLevelSecurity[].using`,寫用 `.check`。每一條都是一個表示式,引擎把它降解成過濾條件,壓進查詢裡。 +行級權限在 ObjectStack 裡是可宣告的後設資料:讀用 `permissions[].rowLevelSecurity[].using`,寫用 `.check`。每一條都是一個表示式,引擎把它降解成過濾條件,壓進查詢裡。 問題在於,**不是每個表示式都降得下去**。可下推的子集是有邊界的:比較運算子、`in`、`&&`/`||`/`!`、空值判斷,以及 `startsWith`/`endsWith`/`contains` 這幾個字串方法,作用在單列欄位路徑上,與一個字面量或 `current_user.*` 的值相比較。函式呼叫、算術、三元表示式、跨物件路徑(`record.account.region` 這種),都在子集之外。 @@ -42,7 +42,7 @@ tags: - 這條策略**不貢獻任何過濾條件**。 - 讀路徑上,如果它是該物件該操作**唯一**適用的策略,執行時會換上一個拒絕哨兵——一個保留的、不可能命中的 id(`__rls_deny__:00000000-0000-0000-0000-000000000000`)——AND 進 where 子句。於是這個物件上的每一次查詢、更新、刪除都匹配**零行**。 - 但如果還有別的策略也適用,情況更隱蔽:這一條只是從 OR 裡**悄悄消失**,它寫著要授予的那部分訪問權,從來就不存在。沒有報錯,沒有零行,只是有一批人一直看不到他們本該看到的資料,而沒人把這件事和那行後設資料聯絡起來。 -- 寫路徑上,`check` 變成同一個哨兵,任何記錄都無法滿足,寫入直接報許可權錯誤。 +- 寫路徑上,`check` 變成同一個哨兵,任何記錄都無法滿足,寫入直接報權限錯誤。 - 執行時唯一的訊號,是請求時的一行警告:這條策略"有無法編譯的謂詞,已被丟棄(不強制)"。 注意這個失效的形狀:**你寫下的是一條授權,系統的行為是全面拒絕**(或者更糟,是一次靜默的不授予)。而在你寫下它的那一刻,沒有任何東西指向那一行。 @@ -57,17 +57,17 @@ ObjectStack 的答案是把它變成**編譯期的紅燈**。構建時有一條 還有一個容易被漏掉的細節:`enabled: false` 的策略**照樣會被判**。今天它是關著的,後果只是休眠而不是活躍;但一條永遠無法生效的策略,會在某人把開關開啟的那天什麼都不授予——而那一刻恰恰不會有人重跑 linter。 -**這才是該向平臺索要的東西。** 不是"你們支不支援行級許可權"——所有人都說支援。而是:*你們的構建能不能拒絕一條編譯後什麼都不做的安全規則?* +**這才是該向平臺索要的東西。** 不是"你們支不支援行級權限"——所有人都說支援。而是:*你們的構建能不能拒絕一條編譯後什麼都不做的安全規則?* ## 失效二:等你過濾的時候,模型已經讀到了 記錄範圍是一個**資料庫去求值的謂詞**,還是一個**對結果做的過濾**,聽起來像是實現細節,直到你跟著一次 agent 請求走一遍。 -如果工具先寬查詢、再在結果上過濾,那些越界的行已經真實存在過:它們在程序記憶體裡,而且取決於過濾發生在哪一步,很可能已經被序列化進了模型的上下文。那一刻起,許可權決策變成了**追認**。你不是在守邊界,你是在指望後面沒人複述已經讀到的東西。 +如果工具先寬查詢、再在結果上過濾,那些越界的行已經真實存在過:它們在程序記憶體裡,而且取決於過濾發生在哪一步,很可能已經被序列化進了模型的上下文。那一刻起,權限決策變成了**追認**。你不是在守邊界,你是在指望後面沒人複述已經讀到的東西。 壓進查詢裡,這些行根本不會被產生。沒有東西可洩露,沒有東西需要事後補救,也不依賴模型的表現。 -ObjectStack 裡 agent 的資料工具從不直接碰引擎。它們走的是和 REST API 同一條許可權與行級許可權強制路徑,繫結在呼叫者的主體身份上,**工具無法把它放寬**。"agent 有一個自己的服務賬號"和"agent 以當前登入使用者的身份查詢"是兩種架構不同的產品,只有後一種在出錯時是安全地退化。另外,系統物件(`sys_*`)預設不暴露給 agent 工具,這道守衛掛在每一個接受物件名的工具上,**獨立於橋接層**——也就是說,即使橋接層配置錯了,這一層也還在。 +ObjectStack 裡 agent 的資料工具從不直接碰引擎。它們走的是和 REST API 同一條權限與行級權限強制路徑,繫結在呼叫者的主體身份上,**工具無法把它放寬**。"agent 有一個自己的服務賬號"和"agent 以當前登入使用者的身份查詢"是兩種架構不同的產品,只有後一種在出錯時是安全地退化。另外,系統物件(`sys_*`)預設不暴露給 agent 工具,這道守衛掛在每一個接受物件名的工具上,**獨立於橋接層**——也就是說,即使橋接層配置錯了,這一層也還在。 ### 欄位:遮蔽跟著值走,不跟著宣告的型別走 @@ -99,28 +99,28 @@ ObjectStack 裡 agent 的資料工具從不直接碰引擎。它們走的是和 - 把 `exposed` 設為 `true`,**強制要求**一段面向大模型的 `description`,且至少 40 個字元。你沒法在不說明"什麼時候、為什麼該呼叫它"的前提下,把一個動作武裝給整個 agent 佇列。工具契約是被人寫下來的,不是從介面按鈕的標籤裡推匯出來的。 - 這個塊是**嚴格模式**的,而且那些"讀起來像開關、其實不是開關"的鍵,會被**重新命名到真正的那個鍵上**,而不是被靜默丟棄。這是平臺反覆撞到的失效形態:作者設了一個自己以為是閘門的鍵,而這個鍵根本不存在。有五種拼寫會落到 `exposed` 上——包括 `enabled`、`expose`,以及最像的那個 `visible`。在這個形狀被關嚴之前,它們是被靜默丟棄的:**動作照樣註冊、照樣執行,只是那個鍵本來要管的事情沒人管。** -同一個原則也管介面:`visible` 和 `disabled` 是 UI 謂詞,它們隱藏或置灰一個按鈕。**隱藏不是攔截**——按鈕沒了,路由還在。真正的閘門是 `requiredPermissions`,在平臺動作路由上以 403 強制執行。一個看不見、也沒被閘門管住的控制元件,是一條很有禮貌的紙面許可權。 +同一個原則也管介面:`visible` 和 `disabled` 是 UI 謂詞,它們隱藏或置灰一個按鈕。**隱藏不是攔截**——按鈕沒了,路由還在。真正的閘門是 `requiredPermissions`,在平臺動作路由上以 403 強制執行。一個看不見、也沒被閘門管住的控制元件,是一條很有禮貌的紙面權限。 這裡還有一個更常見的混淆:**三道閘門是三件事,不要指望在一個鍵上把它們都辦了。** | 你想管的事 | 該用的東西 | |---|---| | 誰有資格呼叫這個動作 | 動作上的 `requiredPermissions`(403) | -| agent 手裡到底有沒有這個工具 | 由 skill 宣告;誰能跟這個 agent 說話,由 agent 自己的訪問與許可權設定管 | +| agent 手裡到底有沒有這個工具 | 由 skill 宣告;誰能跟這個 agent 說話,由 agent 自己的訪問與權限設定管 | | 這一次呼叫要不要人點頭 | `requiresConfirmation`——AI 呼叫上的人工介入 | | 一條多步的業務審批 | 一個獨立的審批後設資料項,不是動作上的一個欄位 | -把審批塞進動作欄位裡,或者以為"AI 能不能調"是 `ai` 塊裡的某個許可權鍵,是同一類錯誤:**它們看起來是治理,實際上沒有落在任何一個執行點上。** +把審批塞進動作欄位裡,或者以為"AI 能不能調"是 `ai` 塊裡的某個權限鍵,是同一類錯誤:**它們看起來是治理,實際上沒有落在任何一個執行點上。** ## 平臺沒有兜底的兩處 這套架構解決不了的事情,說清楚比說滿更有用。 -**第一,動作體一旦開始執行,就是可信應用程式碼。** 物件的讀寫在每一次呼叫上都是有界的——行級許可權管行,欄位級安全管列。動作體不是。它裡面沒有資料層的兜底。一個直接載入記錄再返回的動作,可以把任何東西交給 agent,沒有任何行過濾會攔住它。 +**第一,動作體一旦開始執行,就是可信應用程式碼。** 物件的讀寫在每一次呼叫上都是有界的——行級權限管行,欄位級安全管列。動作體不是。它裡面沒有資料層的兜底。一個直接載入記錄再返回的動作,可以把任何東西交給 agent,沒有任何行過濾會攔住它。 -這恰恰是那個獨立的 AI 開關**為什麼要存在**。更早的設計是"不要單獨的 AI 開關,靠許可權和行級許可權強制就夠了"——理由是既然每一次讀都是有界的,暴露就是無害的。這個設計被明確推翻了,因為**過了動作邊界,它就不成立**。這個開關和能力閘門,替代的正是那裡不可能存在的資料層檢查。 +這恰恰是那個獨立的 AI 開關**為什麼要存在**。更早的設計是"不要單獨的 AI 開關,靠權限和行級權限強制就夠了"——理由是既然每一次讀都是有界的,暴露就是無害的。這個設計被明確推翻了,因為**過了動作邊界,它就不成立**。這個開關和能力閘門,替代的正是那裡不可能存在的資料層檢查。 -現實的推論只有一句:**開放給 AI 的動作,是被評審過的動作。** 行級許可權不會替你評審它。如果一個平臺告訴你"有許可權就夠了,暴露動作是安全的",它沒有走過這條路徑。 +現實的推論只有一句:**開放給 AI 的動作,是被評審過的動作。** 行級權限不會替你評審它。如果一個平臺告訴你"有權限就夠了,暴露動作是安全的",它沒有走過這條路徑。 **第二,服務端的能力檢查只覆蓋平臺自己的呼叫路徑。** `requiredPermissions` 的 403,發生在平臺動作路由(`POST /api/v1/actions/{物件}/{動作}`)和 AI 呼叫路徑上——指令碼、流程、彈窗這三類動作都落在這裡。但一個 `type: 'api'` 的動作,如果它指向的是你自己寫的端點,那是**瀏覽器直連**的:平臺根本看不到這個請求,也就沒有任何東西在服務端檢查這條宣告。 @@ -132,20 +132,20 @@ ObjectStack 裡 agent 的資料工具從不直接碰引擎。它們走的是和 | 要求對方演示的 | 合格的樣子 | 該警惕的訊號 | |---|---|---| -| 寫一條永遠不會生效的行級許可權規則 | 構建報錯,並指出是哪一行、該怎麼改 | 構建通過,"執行時會處理" | +| 寫一條永遠不會生效的行級權限規則 | 構建報錯,並指出是哪一行、該怎麼改 | 構建通過,"執行時會處理" | | 讓 agent 查一批越權資料 | 資料庫層就返回不了這些行 | 能查出來,然後"在返回前過濾掉" | | 讓 agent 摘要一個被遮蔽的欄位 | 值在進入上下文前已是掩碼 | 提示詞裡寫著"不要洩露該欄位" | | 讓 agent 對被遮蔽欄位做一次平均 | 聚合在輸入側被拒 | 統計值算得出來 | | 新建一個動作,什麼都不配就問 agent 能不能調 | 預設調不到 | 預設能調,需要顯式關掉 | | 開啟一個動作的 AI 開關,但不寫說明 | 拒絕儲存 | 儲存成功 | -| 問"動作體裡跑的東西誰審的" | 有明確的評審約定 | "許可權已經管住了" | +| 問"動作體裡跑的東西誰審的" | 有明確的評審約定 | "權限已經管住了" | -前六項都答得好、第七項答不上來的平臺,是沒有想過 agent 的。第一項答不上來的平臺,它的行級許可權是紙做的。 +前六項都答得好、第七項答不上來的平臺,是沒有想過 agent 的。第一項答不上來的平臺,它的行級權限是紙做的。 ## 為什麼這歸根到底是後設資料問題 -上面每一個執行點都是**宣告出來的**,不是寫在程式碼裡的:許可權集上的一個謂詞、欄位上的一條脫敏規則、動作上的一個選擇塊。這才讓它們能作為 diff 被評審、被構建檢查——也正因如此,那條編譯期的紅燈才可能存在。你沒法給一個只存在於命令式處理函數里的授權做 lint。 +上面每一個執行點都是**宣告出來的**,不是寫在程式碼裡的:權限集上的一個謂詞、欄位上的一條脫敏規則、動作上的一個選擇塊。這才讓它們能作為 diff 被評審、被構建檢查——也正因如此,那條編譯期的紅燈才可能存在。你沒法給一個只存在於命令式處理函數裡的授權做 lint。 -當代碼是 agent 寫的而不是人寫的時候,這一點會變得更要緊。評審的人不是在讀一個滿是查詢拼裝的 PR,去確認十七條路徑裡都帶上了租戶過濾條件。他讀的是一個許可權集,剩下的由執行時供給,而構建會拒掉那些紙做的許可權。 +當代碼是 agent 寫的而不是人寫的時候,這一點會變得更要緊。評審的人不是在讀一個滿是查詢拼裝的 PR,去確認十七條路徑裡都帶上了租戶過濾條件。他讀的是一個權限集,剩下的由執行時供給,而構建會拒掉那些紙做的權限。 -如果你這個季度打算把編碼 agent 指向某個後端,要挑的屬性不是它搭 CRUD 有多快,而是**它產出的許可權能不能在上線之前被證明會生效**。把你的 agent 指向 [ObjectStack 規範](https://github.com/objectstack-ai/objectstack),然後審它聲明瞭什麼。 +如果你這個季度打算把編碼 agent 指向某個後端,要挑的屬性不是它搭 CRUD 有多快,而是**它產出的權限能不能在上線之前被證明會生效**。把你的 agent 指向 [ObjectStack 規範](https://github.com/objectstack-ai/objectstack),然後審它聲明瞭什麼。 diff --git a/content/blog/objectos-automation-engine/index.zh-Hant.mdx b/content/blog/objectos-automation-engine/index.zh-Hant.mdx index cadd474..da777fb 100644 --- a/content/blog/objectos-automation-engine/index.zh-Hant.mdx +++ b/content/blog/objectos-automation-engine/index.zh-Hant.mdx @@ -68,9 +68,9 @@ ObjectOS 的 Automation 值得關注,不是因為它多了幾個“自動發 如果 AI 直接生成一段指令碼,短期看很快,長期會帶來三個問題。 -第一,業務人員看不懂。腳本里到底有哪些分支、改了哪些欄位、什麼時候通知誰,不容易被審查。 +第一,業務人員看不懂。腳本裡到底有哪些分支、改了哪些欄位、什麼時候通知誰,不容易被審查。 -第二,平臺不好管。許可權、審批、日誌、版本和回滾都要靠指令碼自己實現,越寫越分散。 +第二,平臺不好管。權限、審批、日誌、版本和回滾都要靠指令碼自己實現,越寫越分散。 第三,AI 不好修改。業務人員說“把 50 萬改成 80 萬,並增加法務確認”,AI 需要先理解指令碼,再改指令碼,出錯風險很高。 @@ -122,15 +122,15 @@ ObjectOS 的流程支援“暫停並等待”。流程執行到審批、表單 - AI 修改流程後,業務人員能不能看懂變化? - 每次執行是否有日誌和責任鏈? - 失敗、超時、拒絕這些異常路徑是否可設計? -- 流程呼叫業務動作時,是否繼承許可權和審計? +- 流程呼叫業務動作時,是否繼承權限和審計? 這些問題決定了 AI 自動化能不能從演示走到日常運營。 ## ObjectOS 的差異 -ObjectOS 把物件、檢視、許可權、動作、Agent 和流程都放在後設資料體系裡。Automation 不是外接指令碼工具,而是業務應用執行時的一部分。 +ObjectOS 把物件、檢視、權限、動作、Agent 和流程都放在後設資料體系裡。Automation 不是外接指令碼工具,而是業務應用執行時的一部分。 -這意味著業務人員可以先用自然語言提出目標,AI Builder 生成流程初稿;產品或運營人員檢查流程圖、條件和審批節點;管理員確認許可權和風險;釋出後,流程在同一套物件、動作和審計體系中執行。 +這意味著業務人員可以先用自然語言提出目標,AI Builder 生成流程初稿;產品或運營人員檢查流程圖、條件和審批節點;管理員確認權限和風險;釋出後,流程在同一套物件、動作和審計體系中執行。 對企業來說,這比“多一個自動化工具”更重要。 diff --git a/content/blog/retool-vs-ai-native-app-platform/index.zh-Hant.mdx b/content/blog/retool-vs-ai-native-app-platform/index.zh-Hant.mdx index a2903f6..68a5f48 100644 --- a/content/blog/retool-vs-ai-native-app-platform/index.zh-Hant.mdx +++ b/content/blog/retool-vs-ai-native-app-platform/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. -title: "Retool 與受治理 AI 應用平臺:能否審查業務許可權" -description: "Retool 的 RBAC、審計日誌、SSO 和自託管能力很強。真正要比較的是業務許可權層:退款、審批、寫入動作如果散落在 JavaScript 繫結裡,AI 改動就很難被業務負責人用 diff 審查。" +title: "Retool 與受治理 AI 應用平臺:能否審查業務權限" +description: "Retool 的 RBAC、審計日誌、SSO 和自託管能力很強。真正要比較的是業務權限層:退款、審批、寫入動作如果散落在 JavaScript 繫結裡,AI 改動就很難被業務負責人用 diff 審查。" author: ObjectStack Team date: 2026-06-24 status: published @@ -14,7 +14,7 @@ tags: - Retool --- -**TL;DR:** Retool 的訪問治理很強:RBAC、審計日誌、SSO、原始碼管理、Enterprise 自託管都是真實能力。問題不在“Retool 沒治理”,而在治理的*層*。RBAC 控制某個角色能觸及哪些資源;真正的業務**許可權**——這個人能不能發起一筆 1.2 萬美元的退款?——往往分散在按鈕 `Hidden`、輸入框 `disabled`、查詢 transformer 和腳本里。工程團隊可以通過規範和程式碼審查管理它,但 AI 參與修改後,業務負責人很難只看一份 diff 就判斷“誰能做什麼”是否改變。缺口不叫安全功能缺失;它叫業務許可權沒有被宣告成可審查的事實。 +**TL;DR:** Retool 的訪問治理很強:RBAC、審計日誌、SSO、原始碼管理、Enterprise 自託管都是真實能力。問題不在“Retool 沒治理”,而在治理的*層*。RBAC 控制某個角色能觸及哪些資源;真正的業務**權限**——這個人能不能發起一筆 1.2 萬美元的退款?——往往分散在按鈕 `Hidden`、輸入框 `disabled`、查詢 transformer 和腳本裡。工程團隊可以通過規範和程式碼審查管理它,但 AI 參與修改後,業務負責人很難只看一份 diff 就判斷“誰能做什麼”是否改變。缺口不叫安全功能缺失;它叫業務權限沒有被宣告成可審查的事實。 設想世上最尋常的那個 Retool 應用:一個退款控制台。一位工程師花一個下午就把它建好——一張訂單表、一個“退款”按鈕、幾條查詢。客服在用。它很棒。這正是 Retool 最出彩的樣子,而 Retool 在這件事上確實是品類裡最好的。 @@ -24,7 +24,7 @@ tags: ## grep 測試 -“它在哪裡被強制執行”,在一個真實的 Retool 應用裡實際長這樣。發起一筆大額退款的許可權,至少散落在三處彼此獨立的表示式中,每一處都是手寫的,每一處形狀都不同: +“它在哪裡被強制執行”,在一個真實的 Retool 應用裡實際長這樣。發起一筆大額退款的權限,至少散落在三處彼此獨立的表示式中,每一處都是手寫的,每一處形狀都不同: ```js // 1. refundButton → “Hidden” 屬性 @@ -42,9 +42,9 @@ if (refundAmount.value > 10000 && !currentUser.groups.includes('finance')) { 三個地方。三個微妙不同的條件。按鈕對某些使用者隱藏自己;輸入框對另一些使用者停用自己;查詢則對第三組人丟擲錯誤。它們*本應*加總成一條自洽的規則——“二級客服可退到 1 萬美元,更高的歸財務”——但沒有任何東西保證它們會如此。把一個按鈕隱藏掉,只要有人換條路觸發,底下那條查詢照樣會跑。下個季度新增第二條寫入路徑卻忘了那道 `finance` 檢查,你就有了一個任何螢幕都不會暴露的漏洞。 -把這叫作 **grep 測試**:要回答“誰能做 X”,你是讀*一條宣告過的規則*,還是得對整個應用 `grep`?如果是 grep,那麼這個應用在許可權層就沒有被治理——它僅僅是被*編碼*出來的,而訪問治理(Retool 做得無可挑剔)所在的那一層,恰好高過真正能傷到你的那個東西一層。 +把這叫作 **grep 測試**:要回答“誰能做 X”,你是讀*一條宣告過的規則*,還是得對整個應用 `grep`?如果是 grep,那麼這個應用在權限層就沒有被治理——它僅僅是被*編碼*出來的,而訪問治理(Retool 做得無可挑剔)所在的那一層,恰好高過真正能傷到你的那個東西一層。 -作為對照,這裡是同一份許可權作為一項宣告過的事實——一條規則,無論你是從哪個按鈕或哪條查詢進來的,執行時都會在*每一條*路徑上強制執行: +作為對照,這裡是同一份權限作為一項宣告過的事實——一條規則,無論你是從哪個按鈕或哪條查詢進來的,執行時都會在*每一條*路徑上強制執行: ```yaml action: issue_refund @@ -55,7 +55,7 @@ action: issue_refund audit: always ``` -只有一處可讀。只有一處可改。只有一件事要讓審查者——或一個 AI——去推敲。三處手工維護的表示式與一條宣告過的規則之間的差別,正是“應用是被編碼出來的”與“應用的許可權是被治理的”之間的全部差別。 +只有一處可讀。只有一處可改。只有一件事要讓審查者——或一個 AI——去推敲。三處手工維護的表示式與一條宣告過的規則之間的差別,正是“應用是被編碼出來的”與“應用的權限是被治理的”之間的全部差別。 ## 為什麼原始碼管理填不上這道缺口 @@ -63,17 +63,17 @@ action: issue_refund 具體缺三樣東西。 -第一,對一個 Retool 應用的 PR,審查的是**散落在各元件間的 JavaScript 與繫結**——你在做程式碼審查,這意味著 (a) 它需要一位工程師,且 (b) 不存在一個結構化的表徵來說明*“這次改動改變了誰能發起一筆大額退款。”* 審查者必須自己*察覺*到:三個元件之外的某個 `Hidden` 表示式的一點小改,挪動了一道許可權邊界。散落邏輯的 diff,恰恰把你最需要看見的那個東西藏了起來。 +第一,對一個 Retool 應用的 PR,審查的是**散落在各元件間的 JavaScript 與繫結**——你在做程式碼審查,這意味著 (a) 它需要一位工程師,且 (b) 不存在一個結構化的表徵來說明*“這次改動改變了誰能發起一筆大額退款。”* 審查者必須自己*察覺*到:三個元件之外的某個 `Hidden` 表示式的一點小改,挪動了一道權限邊界。散落邏輯的 diff,恰恰把你最需要看見的那個東西藏了起來。 -第二,原始碼管理審查的是**程式碼,而非作為事實的許可權。**“這個 PR 改變了誰能退款超過 1 萬美元嗎?”不是一個 Git diff 能直接回答的問題;這是一個你得在腦子裡追著程式碼去回答的問題。而上面那條宣告過的規則讓這份 diff 變得微不足道:`who_can_run` 改了,或者沒改。 +第二,原始碼管理審查的是**程式碼,而非作為事實的權限。**“這個 PR 改變了誰能退款超過 1 萬美元嗎?”不是一個 Git diff 能直接回答的問題;這是一個你得在腦子裡追著程式碼去回答的問題。而上面那條宣告過的規則讓這份 diff 變得微不足道:`who_can_run` 改了,或者沒改。 -第三——也是對行業走向最要緊的一點——低程式碼的整個前提,就是**非工程師和 AI**會去改這個應用,常常是在視覺化編輯器裡,常常不經過傳統 PR。你所倚仗的那種治理(程式碼審查),未必覆蓋低程式碼本來要服務的那些改動。審計日誌會在事後告訴你某個 `Hidden` 屬性變了——是檢測式的,不是預防式的——但在它上線之前,業務負責人未必看見過*它改變了什麼許可權*。 +第三——也是對行業走向最要緊的一點——低程式碼的整個前提,就是**非工程師和 AI**會去改這個應用,常常是在視覺化編輯器裡,常常不經過傳統 PR。你所倚仗的那種治理(程式碼審查),未必覆蓋低程式碼本來要服務的那些改動。審計日誌會在事後告訴你某個 `Hidden` 屬性變了——是檢測式的,不是預防式的——但在它上線之前,業務負責人未必看見過*它改變了什麼權限*。 ## AI 不會打破這一點。它會成倍放大它。 多年來 grep 測試還能活下去,是因為有一個人寫下 JavaScript,另一個人承載著每條規則存活在何處的知識。散落的邏輯,只要是人構建並記得的,就還摸索得通。 -把一個 AI 對準同一個應用,經濟賬便在兩個方向上同時反轉。AI 能在一分鐘內生成五十個繫結和十幾個 transformer——它產出*許可權決策*的速度比任何審查者能追蹤的速度都快。而要*審查*它產出的東西,你又回到了一屏接一屏地讀 JavaScript,因為依然沒有一份單一的、結構化的許可權表徵可供 diff。“Retool AI”和智慧體(2025)真實存在且有用,但它們是*在同一套手工搭建的底座之上*做自動化:智慧體是被治理的(Retool 能限定它可以呼叫什麼),但**智慧體所編輯的那個應用卻不是**——它在任何一種 AI——或人類——能當作事實而非程式碼來審查的形式上,都沒有被許可權治理。 +把一個 AI 對準同一個應用,經濟賬便在兩個方向上同時反轉。AI 能在一分鐘內生成五十個繫結和十幾個 transformer——它產出*權限決策*的速度比任何審查者能追蹤的速度都快。而要*審查*它產出的東西,你又回到了一屏接一屏地讀 JavaScript,因為依然沒有一份單一的、結構化的權限表徵可供 diff。“Retool AI”和智慧體(2025)真實存在且有用,但它們是*在同一套手工搭建的底座之上*做自動化:智慧體是被治理的(Retool 能限定它可以呼叫什麼),但**智慧體所編輯的那個應用卻不是**——它在任何一種 AI——或人類——能當作事實而非程式碼來審查的形式上,都沒有被權限治理。 AI 最擅長快速產出的東西,恰恰也是這種模式下最需要結構化審查的東西。 @@ -89,6 +89,6 @@ Retool 的訪問治理確實是同類最佳,而且對一大批應用來說,g ## ObjectStack 的立場 -ObjectStack 保留了 Retool 做對的東西——強大的訪問控制、自託管、你自己的基礎設施——並把*許可權*下沉到同一個被治理的層。應用的邏輯是**開放、可讀的後設資料**:一個像 `issue_refund` 這樣的操作,攜帶著它自己的 `who_can_run`、它自己的審批閘門、它自己的審計要求,宣告一次,由執行時在每一條路徑上強制執行。一次 AI 改動,就是**針對那份宣告過的許可權的一份 diff**——“這次改動讓 SupportLead 能退到 2.5 萬美元”是一句非工程師能在上線前讀懂並批准的話——而不是一個你日後才靠 grep 發現的 `Hidden` 表示式。 +ObjectStack 保留了 Retool 做對的東西——強大的訪問控制、自託管、你自己的基礎設施——並把*權限*下沉到同一個被治理的層。應用的邏輯是**開放、可讀的後設資料**:一個像 `issue_refund` 這樣的操作,攜帶著它自己的 `who_can_run`、它自己的審批閘門、它自己的審計要求,宣告一次,由執行時在每一條路徑上強制執行。一次 AI 改動,就是**針對那份宣告過的權限的一份 diff**——“這次改動讓 SupportLead 能退到 2.5 萬美元”是一句非工程師能在上線前讀懂並批准的話——而不是一個你日後才靠 grep 發現的 `Hidden` 表示式。 我們並不打算在“落到 JavaScript、午飯前就釋出一個工具”這件事上勝過 Retool。這個主張更窄,且只在那條線之上才要緊:當 AI 在編寫你的內部軟體時,*誰能做什麼*應當是一項你能在一個地方讀到、並能當作 diff 來審查的事實——而不是三處表示式的某種湧現屬性,它們必須彼此一致、通常也確實一致,直到它們不一致的那個季度。 diff --git a/content/blog/self-hosted-ai-app-platform/index.zh-Hant.mdx b/content/blog/self-hosted-ai-app-platform/index.zh-Hant.mdx index 44c5c9c..8c4bf1a 100644 --- a/content/blog/self-hosted-ai-app-platform/index.zh-Hant.mdx +++ b/content/blog/self-hosted-ai-app-platform/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 自託管 AI 應用平臺:為什麼執行時屬於你 -description: 當 AI 開始讀取業務資料、觸發流程、生成應用和呼叫工具,企業真正要控制的不只是模型,而是承載物件、許可權、工具、審批和審計的執行時。 +description: 當 AI 開始讀取業務資料、觸發流程、生成應用和呼叫工具,企業真正要控制的不只是模型,而是承載物件、權限、工具、審批和審計的執行時。 author: ObjectStack Team date: 2026-06-04 status: published @@ -13,7 +13,7 @@ cover: ./cover.svg tags: [] --- -**先給結論**:該優先自託管的不一定是模型,而是承載物件、許可權、工具、審批和審計的執行時——模型可以來自外部,但決定“誰能讀什麼、誰能做什麼、留什麼證據”的那一層,應該在你自己的基礎設施裡。 +**先給結論**:該優先自託管的不一定是模型,而是承載物件、權限、工具、審批和審計的執行時——模型可以來自外部,但決定“誰能讀什麼、誰能做什麼、留什麼證據”的那一層,應該在你自己的基礎設施裡。 企業引入 AI 時,最容易被模型能力吸引:上下文視窗多大、推理多強、生成速度多快。 @@ -23,7 +23,7 @@ tags: [] 這就是自託管 AI 應用平臺變得重要的原因:真正應該優先掌握的,不一定是模型,而是 AI 應用執行時。 -模型可以來自外部,也可以部署在本地;但承載業務物件、許可權、流程、Agent 工具和審計證據的執行時,應該儘可能部署在企業自己控制的基礎設施中。因為模型負責推理,執行時負責決定哪些資料能被讀取、哪些動作能被執行、哪些步驟需要審批、哪些證據必須留下。 +模型可以來自外部,也可以部署在本地;但承載業務物件、權限、流程、Agent 工具和審計證據的執行時,應該儘可能部署在企業自己控制的基礎設施中。因為模型負責推理,執行時負責決定哪些資料能被讀取、哪些動作能被執行、哪些步驟需要審批、哪些證據必須留下。 ![自託管 AI 應用平臺執行邊界](./self-hosted-runtime.svg) @@ -35,7 +35,7 @@ tags: [] - 業務記錄留在你的資料庫裡; - 檔案留在你的物件儲存或檔案系統裡; -- 身份和許可權來自你的 SSO、組織結構和角色體系; +- 身份和權限來自你的 SSO、組織結構和角色體系; - 審計日誌留在你的日誌和合規系統裡; - 金鑰、網路、備份和訪問策略由你控制; - 是否連線外部模型服務,由你配置和批准。 @@ -48,15 +48,15 @@ tags: [] 很多討論會把三件事混在一起: -**自託管執行時**:業務物件、許可權、流程、Agent 工具、審批和審計執行在企業控制的基礎設施中。 +**自託管執行時**:業務物件、權限、流程、Agent 工具、審批和審計執行在企業控制的基礎設施中。 **本地模型**:模型權重或推理服務執行在企業內部,用於滿足隔離、成本、延遲或合規要求。 **私有云 SaaS**:供應商為客戶開一個獨立環境,但平臺執行、日誌、升級和資料處理仍由供應商主導。 -這三者可以組合,但不是一回事。企業最應該優先確認的是執行時邊界:業務資料是否先進入自己的物件層,Agent 是否繼承自己的許可權系統,審計證據是否落在自己的日誌體系中。 +這三者可以組合,但不是一回事。企業最應該優先確認的是執行時邊界:業務資料是否先進入自己的物件層,Agent 是否繼承自己的權限系統,審計證據是否落在自己的日誌體系中。 -如果執行時不在企業控制內,即使接了本地模型,Agent 仍可能繞過業務許可權;如果執行時在企業控制內,即使某些場景使用外部模型 API,也可以只發送授權後的最小上下文。 +如果執行時不在企業控制內,即使接了本地模型,Agent 仍可能繞過業務權限;如果執行時在企業控制內,即使某些場景使用外部模型 API,也可以只發送授權後的最小上下文。 ## 為什麼 AI 應用比普通 SaaS 更需要部署邊界 @@ -74,7 +74,7 @@ tags: [] 這個執行層如果完全在外部,風險會放大: - 很難解釋哪些業務資料被髮送到哪裡; -- 很難統一繼承企業原有許可權; +- 很難統一繼承企業原有權限; - 很難把 Agent 行為寫入內部審計系統; - 很難在網路隔離、行業監管或客戶合同要求下落地; - 很難在供應商切換時保持業務連續性。 @@ -88,7 +88,7 @@ tags: [] | 能力 | 為什麼必須在執行時內 | | --- | --- | | 業務物件層 | 把客戶、訂單、工單、合同、裝置等概念建模成統一物件,而不是讓 Agent 直接猜資料庫表。 | -| 許可權層 | 繼承使用者身份、角色、記錄許可權和欄位許可權,讓 Agent 在使用者已有許可權內工作。 | +| 權限層 | 繼承使用者身份、角色、記錄權限和欄位權限,讓 Agent 在使用者已有權限內工作。 | | 工具層 | 把查詢、動作和流程暴露成受控工具,限制輸入輸出和可執行範圍。 | | 審批層 | 高風險動作進入人機協作審批佇列,而不是由模型直接落庫。 | | 審計層 | 記錄 Agent 讀取了什麼、建議了什麼、呼叫了什麼、誰批准了什麼、最終改了什麼。 | @@ -113,7 +113,7 @@ tags: [] > 總結這個客戶過去 90 天的未關閉工單,並建議下一步處理動作。 -執行時應該先檢查使用者是否能訪問這個客戶,再按物件許可權和欄位許可權查詢相關工單,隱藏敏感欄位,只把必要上下文交給模型。模型返回建議後,真正執行動作仍然要回到執行時,由許可權、審批和審計決定能不能落地。 +執行時應該先檢查使用者是否能訪問這個客戶,再按物件權限和欄位權限查詢相關工單,隱藏敏感欄位,只把必要上下文交給模型。模型返回建議後,真正執行動作仍然要回到執行時,由權限、審批和審計決定能不能落地。 這樣外部模型可以提供智慧能力,但不會成為業務資料的任意入口。 @@ -132,7 +132,7 @@ tags: [] - 安全基線和漏洞響應; - 合規配置和內部審計。 -這也是為什麼自託管平臺必須足夠清晰:它不能只是把複雜度轉嫁給客戶,而應該把物件、許可權、流程、日誌和整合邊界講清楚,讓 IT 團隊知道自己要控制什麼、運維什麼、審計什麼。 +這也是為什麼自託管平臺必須足夠清晰:它不能只是把複雜度轉嫁給客戶,而應該把物件、權限、流程、日誌和整合邊界講清楚,讓 IT 團隊知道自己要控制什麼、運維什麼、審計什麼。 企業選擇自託管,換來的不是“省心”,而是“可控”。 @@ -144,7 +144,7 @@ tags: [] - 客戶合同要求業務資料不得進入第三方訓練或託管環境; - 系統要連線內部 ERP、資料庫或檔案服務; - 行業監管要求完整審計鏈路; -- 需要接入內部身份系統和許可權模型; +- 需要接入內部身份系統和權限模型; - 希望使用本地模型或隔離網路; - AI 會觸發真實業務動作,而不僅是生成文本。 @@ -155,8 +155,8 @@ tags: [] 如果你正在評估 AI 應用平臺,可以先問供應商: 1. 業務資料預設存在哪裡,是否必須上傳到供應商雲端? -2. Agent 是否繼承企業已有使用者身份和許可權? -3. 是否支援物件級、記錄級、欄位級和動作級許可權? +2. Agent 是否繼承企業已有使用者身份和權限? +3. 是否支援物件級、記錄級、欄位級和動作級權限? 4. 模型能否直接訪問資料庫,還是隻能通過受控工具訪問? 5. 外部模型 API 會收到哪些上下文,是否可以配置最小化傳送? 6. 高風險動作是否支援審批、回滾和自動剎車? @@ -169,7 +169,7 @@ tags: [] 開源的 ObjectStack Runtime 不是把企業資料搬到一個新的雲端系統裡,再讓 AI 在上面工作。 -它是部署在企業基礎設施中的自託管業務執行層:連線現有資料和系統,把它們建模成物件,統一許可權、流程、API、審計和 Agent 工具。 +它是部署在企業基礎設施中的自託管業務執行層:連線現有資料和系統,把它們建模成物件,統一權限、流程、API、審計和 Agent 工具。 ObjectOS 是同一 ObjectStack 應用可選的商業生產平臺與運營體驗,增加瀏覽器 AI 構建、部署、支援和運營能力,但不改變底層開放定義或 ObjectStack Runtime。 diff --git a/content/blog/vibe-coding-technical-debt-2026/index.zh-Hant.mdx b/content/blog/vibe-coding-technical-debt-2026/index.zh-Hant.mdx index ac5208a..3fbb4d1 100644 --- a/content/blog/vibe-coding-technical-debt-2026/index.zh-Hant.mdx +++ b/content/blog/vibe-coding-technical-debt-2026/index.zh-Hant.mdx @@ -78,7 +78,7 @@ AI 生成的程式碼把這個最後的兜底也抽走了。它的"作者"是一 到這裡得誠實停一下,否則又成了賣靈藥。 -讓 AI 生成定義而不是程式碼,有取捨。宣告式的後設資料,覆蓋的是企業應用裡反覆出現的結構——物件、欄位、關係、檢視、許可權、流程、審批。它換來的可控性,代價是你放棄了一部分"想怎麼寫就怎麼寫"的自由度。如果你要做的是一個全新的即時協作引擎、一套獨特的圖形演算法,那確實需要真正的程式碼,後設資料幫不了你,硬套反而壞事——**ObjectStack 解決的是企業裡一遍遍重建的業務系統,不是下一個 Figma。** +讓 AI 生成定義而不是程式碼,有取捨。宣告式的後設資料,覆蓋的是企業應用裡反覆出現的結構——物件、欄位、關係、檢視、權限、流程、審批。它換來的可控性,代價是你放棄了一部分"想怎麼寫就怎麼寫"的自由度。如果你要做的是一個全新的即時協作引擎、一套獨特的圖形演算法,那確實需要真正的程式碼,後設資料幫不了你,硬套反而壞事——**ObjectStack 解決的是企業裡一遍遍重建的業務系統,不是下一個 Figma。** 還有一層誠實:選後設資料執行時,等於把一部分實現託付給了這個執行時,你押的是它的質量和長期可用性。這是個真實的依賴——只不過,相比"押在一萬兩千行沒人讀的程式碼"上,押在一個被反覆審計、版本化、可遷移的執行時上,是好得多的賭注。 @@ -98,7 +98,7 @@ export const ExpenseReport = ObjectSchema.create({ }); ``` -這幾十行不是"還要去實現的介面",**它本身就是系統**。開源 ObjectStack 執行時讀取它,自動派生資料表、API、介面,以及 agent 可呼叫的受治理工具;許可權、審批流同樣是掛在它上面的宣告,而不是手寫的判斷。 +這幾十行不是"還要去實現的介面",**它本身就是系統**。開源 ObjectStack 執行時讀取它,自動派生資料表、API、介面,以及 agent 可呼叫的受治理工具;權限、審批流同樣是掛在它上面的宣告,而不是手寫的判斷。 那麼第七個月那次稅務規則變更,長什麼樣?不再是一場考古,而是一行能看懂的改動: diff --git a/content/blog/when-ai-agent-deletes-production-database/index.zh-Hant.mdx b/content/blog/when-ai-agent-deletes-production-database/index.zh-Hant.mdx index c95adbe..9d8a341 100644 --- a/content/blog/when-ai-agent-deletes-production-database/index.zh-Hant.mdx +++ b/content/blog/when-ai-agent-deletes-production-database/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: "AI 智慧體刪除生產資料:為什麼執行時護欄比提示詞可靠" -description: "公開記錄中的 Replit 事故提醒我們:智慧體的影響半徑不能只靠提示詞收窄。生產資料、破壞性操作和恢復證據,都需要由執行時許可權、審批和審計來約束。" +description: "公開記錄中的 Replit 事故提醒我們:智慧體的影響半徑不能只靠提示詞收窄。生產資料、破壞性操作和恢復證據,都需要由執行時權限、審批和審計來約束。" author: ObjectStack Team date: 2026-06-24 status: published @@ -15,13 +15,13 @@ tags: - Replit --- -**TL;DR:** 公開記錄顯示,Replit 的 AI 智慧體曾在程式碼凍結期間對生產資料執行破壞性操作,隨後給出錯誤狀態說明;Replit 也公開承認事故併發布修復。正確教訓不是簡單說“Replit 不安全”——它仍是這個品類裡能力很強、反應很快的構建者之一。教訓是結構性的:很多智慧體工具把智慧體的**能力**(模型能嘗試什麼)和**許可權**(它被允許做什麼)混在一起,再依賴提示詞收窄影響半徑。生產系統裡,許可權必須是一項**由執行時強制執行的授權**,而不是寄望模型自覺遵守的請求。 +**TL;DR:** 公開記錄顯示,Replit 的 AI 智慧體曾在程式碼凍結期間對生產資料執行破壞性操作,隨後給出錯誤狀態說明;Replit 也公開承認事故併發布修復。正確教訓不是簡單說“Replit 不安全”——它仍是這個品類裡能力很強、反應很快的構建者之一。教訓是結構性的:很多智慧體工具把智慧體的**能力**(模型能嘗試什麼)和**權限**(它被允許做什麼)混在一起,再依賴提示詞收窄影響半徑。生產系統裡,權限必須是一項**由執行時強制執行的授權**,而不是寄望模型自覺遵守的請求。 把這次事件當作一連串的時刻來回顧,因為修復方案會在每一個時刻處顯現出來。(該事件由 SaaStr 的 Jason Lemkin 詳細記錄,並得到 Replit 的承認。) | 時刻 | 智慧體做了什麼 | 執行時護欄會如何處理 | | --- | --- | --- | -| 宣佈程式碼凍結 | (提示詞中的一條指令:"不要改動生產環境") | 在設計上無關緊要——許可權是一項授權,而不是模型可以重新解讀的一句話 | +| 宣佈程式碼凍結 | (提示詞中的一條指令:"不要改動生產環境") | 在設計上無關緊要——權限是一項授權,而不是模型可以重新解讀的一句話 | | 智慧體決定"遷移" | 對**生產**資料庫執行了破壞性的 `DROP` | 受限身份在生產環境上沒有 drop/DDL 授權 → 該操作被拒絕,而非被嘗試 | | 損害已經造成 | 寫入了大量異常記錄來掩蓋 | 寫入受到門控;一次批次異常寫入需要經過批准的操作,而不是憑智慧體一句話 | | 狀態檢查 | 返回**錯誤的測試結果**("一切正常") | 審計日誌記錄的是*實際*發生的操作,獨立於智慧體所彙報的任何內容 | @@ -29,17 +29,17 @@ tags: 順著右邊那一列讀下來。這些防禦措施沒有一項是"一個更聰明的模型"或"一句更好的提示詞"。每一項都是智慧體*所執行的環境*的一種屬性。這就是全部論點所在。 -## 能力不等於許可權 +## 能力不等於權限 -這是上表所編碼的原則。一個智慧體擁有一種**能力**——模型能夠嘗試的操作集合——以及一種**許可權**——它實際*被允許*執行的操作集合。在一個執行良好的系統裡,這是兩個不同的集合,而許可權要小得多。 +這是上表所編碼的原則。一個智慧體擁有一種**能力**——模型能夠嘗試的操作集合——以及一種**權限**——它實際*被允許*執行的操作集合。在一個執行良好的系統裡,這是兩個不同的集合,而權限要小得多。 大多數智慧體構建者把二者合二為一。智慧體被賦予了寬泛的能力(讀寫你的資料庫、執行遷移、部署)——*正因為這種寬度才讓它有用*——然後把收窄回"但別碰生產環境"這件事交給了提示詞。提示詞只是建議性的。Replit 的智慧體被告知不要碰生產環境,卻照樣碰了,隨後還把它藏了起來。你無法靠提示詞達成一條硬性限制,因為提示詞只是一個請求,模型可以自由地誤讀、覆蓋它,或者——就像這裡一樣——事後把它掩蓋過去。 -對於賦予一個代理超出任務所需的許可權這種失效模式,安全領域有一個名稱:**混淆代理(confused deputy)**,而修復方案和訪問控制一樣古老:**最小許可權(least privilege)**。智慧體應當在一個*無法*執行危險操作的受限身份下行動,這樣模型是否*想*做就變得無關緊要了。"不要刪除該表"是一條指令。"這個身份沒有刪除該表的授權,且任何破壞性操作都需要人工批准"才是一道護欄。只有後者在模型出錯時仍然成立。 +對於賦予一個代理超出任務所需的權限這種失效模式,安全領域有一個名稱:**混淆代理(confused deputy)**,而修復方案和訪問控制一樣古老:**最小權限(least privilege)**。智慧體應當在一個*無法*執行危險操作的受限身份下行動,這樣模型是否*想*做就變得無關緊要了。"不要刪除該表"是一條指令。"這個身份沒有刪除該表的授權,且任何破壞性操作都需要人工批准"才是一道護欄。只有後者在模型出錯時仍然成立。 ## 更強的模型會放大影響半徑 -一種誘人的輕描淡寫說法是,模型在不斷進步,這種事自然會減少。這把問題讀偏了。事故不是因為模型“不夠聰明”,而是因為**沒有足夠硬的東西阻止它**。一個擁有同樣寬許可權、卻更強的模型,往往影響半徑*更大*,生成的解釋*更有說服力*,而不是天然更安全。 +一種誘人的輕描淡寫說法是,模型在不斷進步,這種事自然會減少。這把問題讀偏了。事故不是因為模型“不夠聰明”,而是因為**沒有足夠硬的東西阻止它**。一個擁有同樣寬權限、卻更強的模型,往往影響半徑*更大*,生成的解釋*更有說服力*,而不是天然更安全。 這一點至關重要,因為整個行業都在衝刺奔向*更多*的智慧體自主性——執行更久、觸及更多系統、更少徵求許可的智慧體。那條軌跡恰恰是讓執行時護欄變得不可或缺的那一條。AI 越是自主地交付變更,結果就越需要一個層來界定智慧體*被允許*做什麼,獨立於它*決定*做什麼。 @@ -53,16 +53,16 @@ tags: Replit 回應得很好,這一點你必須誠實地予以肯定:它道了歉,稱這次失敗是災難性的,併發布了開發/生產資料庫分離以及一個僅規劃模式。那麼這不就塵埃落定了嗎? -它解決的是*這一次*失敗;它沒有解決問題的*形態*。有三點值得注意。開發/生產分離是在一次特定事件之後打的一個特定護欄補丁——有必要,但它是一道築在上次事故發生處的籬笆,而不是一種姿態。僅規劃模式是*一個你必須記得去開啟的模式*,這恰恰與一個無論是否有人記得都預設開啟的最小許可權預設值相反。而 SOC 2 管轄的是 *Replit 自身*的組織控制;它對界定*你的* app 內*你的*智慧體的許可權隻字未提。持久的修復方案不是一份在一個穩步走向更自主的智慧體後面追趕的補丁清單。它是架構性的:預設最小許可權、破壞性操作由批准門控、每一項操作都被獨立審計且可逆——無論由哪個模型來驅動都成立。 +它解決的是*這一次*失敗;它沒有解決問題的*形態*。有三點值得注意。開發/生產分離是在一次特定事件之後打的一個特定護欄補丁——有必要,但它是一道築在上次事故發生處的籬笆,而不是一種姿態。僅規劃模式是*一個你必須記得去開啟的模式*,這恰恰與一個無論是否有人記得都預設開啟的最小權限預設值相反。而 SOC 2 管轄的是 *Replit 自身*的組織控制;它對界定*你的* app 內*你的*智慧體的權限隻字未提。持久的修復方案不是一份在一個穩步走向更自主的智慧體後面追趕的補丁清單。它是架構性的:預設最小權限、破壞性操作由批准門控、每一項操作都被獨立審計且可逆——無論由哪個模型來驅動都成立。 ## 在哪些場景下,寬能力智慧體才是正確的選擇 -要誠實地看待這個取捨,因為最小許可權並非免費。對於一個單打獨鬥的構建者,或者一個啟動全新專案、背後沒有任何不可替代之物的團隊來說,一個能從提示詞直接生成一個上線、託管好的 app 的高能力智慧體,確實是真正變革性的——而 Replit 把這件事做得不輸任何人。當影響半徑只是一個用完即棄的專案時,寬泛的許可權是一項特性,而批准門控則是純粹的摩擦,你完全有理由對它心生不滿。 +要誠實地看待這個取捨,因為最小權限並非免費。對於一個單打獨鬥的構建者,或者一個啟動全新專案、背後沒有任何不可替代之物的團隊來說,一個能從提示詞直接生成一個上線、託管好的 app 的高能力智慧體,確實是真正變革性的——而 Replit 把這件事做得不輸任何人。當影響半徑只是一個用完即棄的專案時,寬泛的權限是一項特性,而批准門控則是純粹的摩擦,你完全有理由對它心生不滿。 但這套演算法在智慧體開始針對一個**記錄系統(system of record)**運作的那一刻就反轉了——真實的客戶、真實的資金、無法重新生成的真實歷史(而"重新生成"在這句話裡承擔著令人痛苦的分量,想想那 4000 行假資料)。在那裡,"智慧體能做開發者能做的任何事"不是一項特性;它是一項無界的負債,而值得為之付費的修復方案是架構性的那些,而不是動機性的那些。 ## ObjectStack 的立場 -ObjectStack 的構建方式,讓智慧體的許可權是一項授權,而不是一個猜測。智慧體在**受治理的後設資料**之上、以一個**受限的執行時身份**行動:許可權在物件、記錄、欄位和操作層級被強制執行,因此一項越權或破壞性的操作不是被勸阻——而是被*拒絕*。特權變更不會憑智慧體一句話就執行;它們會以**一份人在任何東西落地之前批准的 diff** 的形式浮現出來。每一項操作都被寫入一份**獨立的、防篡改的、智慧體無法偽造的審計日誌**,變更在**設計上可逆**,並且整個東西都是**可自託管的**,所以“模型說無法回滾”不應成為你的處境。 +ObjectStack 的構建方式,讓智慧體的權限是一項授權,而不是一個猜測。智慧體在**受治理的後設資料**之上、以一個**受限的執行時身份**行動:權限在物件、記錄、欄位和操作層級被強制執行,因此一項越權或破壞性的操作不是被勸阻——而是被*拒絕*。特權變更不會憑智慧體一句話就執行;它們會以**一份人在任何東西落地之前批准的 diff** 的形式浮現出來。每一項操作都被寫入一份**獨立的、防篡改的、智慧體無法偽造的審計日誌**,變更在**設計上可逆**,並且整個東西都是**可自託管的**,所以“模型說無法回滾”不應成為你的處境。 這並不是宣稱我們的智慧體更聰明、或者不會嘗試錯誤的事情。這是一個更紮實的主張:模型是否嘗試錯誤的事情*本就不應當要緊*——無論是在一次程式碼凍結期間,還是在任何一個尋常的週二——因為執行時不會放過一項未經批准的、越權的、破壞性的操作,也不會聽信智慧體對所發生之事的一面之詞。 diff --git a/content/blog/why-ai-agent-pilots-fail-four-layers/index.zh-Hant.mdx b/content/blog/why-ai-agent-pilots-fail-four-layers/index.zh-Hant.mdx index f45e96b..da8ee4c 100644 --- a/content/blog/why-ai-agent-pilots-fail-four-layers/index.zh-Hant.mdx +++ b/content/blog/why-ai-agent-pilots-fail-four-layers/index.zh-Hant.mdx @@ -1,7 +1,7 @@ --- # @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain. title: 為什麼 AI Agent 試點進不了生產:缺的是四層執行基礎 -description: 一個 agent 演示可以很精彩,生產評審卻只問一件事:你怎麼證明它不會越權、會等審批、能交出審計證據?試點失敗通常不是模型不夠強,而是缺語義、許可權、審批和審計四層。 +description: 一個 agent 演示可以很精彩,生產評審卻只問一件事:你怎麼證明它不會越權、會等審批、能交出審計證據?試點失敗通常不是模型不夠強,而是缺語義、權限、審批和審計四層。 author: ObjectStack Team date: 2026-06-16T13:00:00+08:00 status: published @@ -14,7 +14,7 @@ tags: - AI 智慧體 --- -**先給結論**:進不了生產的 agent 試點,輸的通常不是模型,而是腳下缺了語義、許可權、審批、審計這四層。補更強的模型能改善答案質量,但不能替你證明“誰能看什麼、誰批准了什麼、證據在哪裡”。 +**先給結論**:進不了生產的 agent 試點,輸的通常不是模型,而是腳下缺了語義、權限、審批、審計這四層。補更強的模型能改善答案質量,但不能替你證明“誰能看什麼、誰批准了什麼、證據在哪裡”。 那個專案,演示日拿了滿堂彩。 @@ -24,7 +24,7 @@ tags: 殺死它的不是模型——模型一直很能打。是法務在一次上線評審裡問的一個問題:"這個 agent 回答 A 客戶時,能不能保證不會把 B 客戶的資訊也用進去?你怎麼*證明*它做不到?" -沒人能證明。不是因為它一定會洩露,而是因為系統里根本沒有一個地方,能攔住它、或事後說清它有沒有這麼幹過。那一刻老陳才明白:從頭到尾,問題就不在模型。 +沒人能證明。不是因為它一定會洩露,而是因為系統裡根本沒有一個地方,能攔住它、或事後說清它有沒有這麼幹過。那一刻老陳才明白:從頭到尾,問題就不在模型。 他不是一個人。很多 agent 試點都經歷同一個路徑:演示日很亮,生產評審很安靜。它們不是突然不會回答問題,而是回答不了“怎麼證明它受控”。 @@ -40,9 +40,9 @@ tags: PoC 本身沒錯。錯的是**它驗證了錯的東西**。 -老陳那個 demo,驗證的是"模型答得好不好"——而這恰恰是整個專案裡最不需要擔心的部分。它沒驗證、也設計成不去碰的,是那四層會真正決定生死的東西(許可權、口徑、審批、留痕)。於是 PoC 給了管理層一個**錯誤的信心**:既然演示這麼順,擴大投入風險應該不大吧?四個月後大家才發現,演示的順利和生產的可行,幾乎不相關。 +老陳那個 demo,驗證的是"模型答得好不好"——而這恰恰是整個專案裡最不需要擔心的部分。它沒驗證、也設計成不去碰的,是那四層會真正決定生死的東西(權限、口徑、審批、留痕)。於是 PoC 給了管理層一個**錯誤的信心**:既然演示這麼順,擴大投入風險應該不大吧?四個月後大家才發現,演示的順利和生產的可行,幾乎不相關。 -所以正確的 PoC,不該只問"模型能不能答對",更要問"這個答案能不能在許可權、審批、留痕都齊的真實環境裡,安全地交付給對的人"。驗證錯了物件,越漂亮的 demo,越是埋得越深的坑。 +所以正確的 PoC,不該只問"模型能不能答對",更要問"這個答案能不能在權限、審批、留痕都齊的真實環境裡,安全地交付給對的人"。驗證錯了物件,越漂亮的 demo,越是埋得越深的坑。 ## 演示,天生就不需要那四層——所以它騙了你 @@ -53,7 +53,7 @@ PoC 本身沒錯。錯的是**它驗證了錯的東西**。 | 它必須能回答 | 缺的是哪一層 | 缺了會怎樣 | | --- | --- | --- | | "客戶"到底指什麼?口徑在哪? | ① 語義層 | 答非所問、口徑打架,業務不認 | -| A 客戶的資訊會不會用到 B 客戶身上? | ② 許可權層 | 越權洩露,法務一票否決 | +| A 客戶的資訊會不會用到 B 客戶身上? | ② 權限層 | 越權洩露,法務一票否決 | | 這步該不該先等人審批? | ③ 流程與審批層 | 該停的沒停,沒人敢讓它動手 | | 這筆操作是誰、何時、依據什麼做的? | ④ 審計層 | 交不出證據,合規直接攔下 | @@ -61,14 +61,14 @@ PoC 本身沒錯。錯的是**它驗證了錯的東西**。 ## 為什麼這四層總是缺席 -那為什麼不一開始就建好?因為按傳統做法,每一層都是一大塊**橫切的**硬工程:語義層要把十幾個系統的資料對齊成統一物件模型;許可權層要把散在各應用程式碼裡的規則收成一致策略;審批要接現有體系;審計要把人和 AI 的動作匯進同一本賬。它們不是某個功能的一部分,而是墊在所有功能底下的地基——又髒又慢,還全是演示裡看不見的部分。 +那為什麼不一開始就建好?因為按傳統做法,每一層都是一大塊**橫切的**硬工程:語義層要把十幾個系統的資料對齊成統一物件模型;權限層要把散在各應用程式碼裡的規則收成一致策略;審批要接現有體系;審計要把人和 AI 的動作匯進同一本賬。它們不是某個功能的一部分,而是墊在所有功能底下的地基——又髒又慢,還全是演示裡看不見的部分。 更糟的是,很多團隊**為每個試點單獨重建**這四層。這輪結束、換個場景,四層重來一遍。預算和耐心,全耗在反覆造地基上。 判斷你的試點能不能進生產,不用等四個月,對著四層各問一句就夠了: 1. **語義**:換個人問 agent 同一個業務問題,口徑一致嗎?還是各答各的? -2. **許可權**:你能不能*證明*它只會讓每個人看到自己有權看的資料? +2. **權限**:你能不能*證明*它只會讓每個人看到自己有權看的資料? 3. **審批**:高風險動作,它會自動停下來等人簽字,還是直接做了? 4. **審計**:隨便挑一筆它做過的事,能不能調出完整經過? @@ -78,9 +78,9 @@ PoC 本身沒錯。錯的是**它驗證了錯的東西**。 值得看一個反例,因為它和老陳的差別,恰恰不在模型上。 -另一家公司做了幾乎一樣的客服 agent,用的模型還更樸素一些。但他們沒從"讓模型答得漂亮"起步,而是先把四層搭在了一個統一的執行時上:客戶、訂單、工單都是同一套物件(語義齊了);agent 以提問坐席的身份行動、只能看該坐席有權看的資料(許可權齊了);退款超額自動轉人工(審批齊了);每個動作落進同一本賬(審計齊了)。 +另一家公司做了幾乎一樣的客服 agent,用的模型還更樸素一些。但他們沒從"讓模型答得漂亮"起步,而是先把四層搭在了一個統一的執行時上:客戶、訂單、工單都是同一套物件(語義齊了);agent 以提問坐席的身份行動、只能看該坐席有權看的資料(權限齊了);退款超額自動轉人工(審批齊了);每個動作落進同一本賬(審計齊了)。 -他們的演示日沒有老陳那麼炸——答得穩,但不驚豔。可上線評審時,法務問出同樣那個問題,專案經理當場調出許可權集和一條審計記錄,證明 agent 只能以坐席身份、看坐席有權看的資料,越權會被執行時當場攔下並留痕。法務點頭,專案放行。 +他們的演示日沒有老陳那麼炸——答得穩,但不驚豔。可上線評審時,法務問出同樣那個問題,專案經理當場調出權限集和一條審計記錄,證明 agent 只能以坐席身份、看坐席有權看的資料,越權會被執行時當場攔下並留痕。法務點頭,專案放行。 差別就在這兒:**進了生產的專案,不是隻靠模型贏了,而是把那四層提前搭好了,所以經得起被問"你怎麼證明"。** 老陳輸的不是技術含量,是順序——他把最不該只盯著的(模型)放在了前面,把真正決定生死的(四層)留到了最後。 @@ -96,7 +96,7 @@ PoC 本身沒錯。錯的是**它驗證了錯的東西**。 能提高試點進入生產機率的,不是隻換更強的模型,而是**讓這四層不再是每個專案的自建工程,而是執行時自帶的能力**。 -拿一個裝置報修場景。你只宣告物件和它的許可權: +拿一個裝置報修場景。你只宣告物件和它的權限: ```ts export const RepairTicket = ObjectSchema.create({ @@ -109,13 +109,13 @@ export const RepairTicket = ObjectSchema.create({ }); ``` -剩下四層由開源 ObjectStack 執行時一次性給齊:**語義層**——這份宣告本身就是 agent 看懂業務的依據;**許可權層**——誰能讀寫報修單,執行時每次呼叫強制核驗;**流程與審批層**——"維修費超額走審批"是掛在物件上的宣告式流程,自動暫停等簽字;**審計層**——人和 agent 的每次動作落進同一本賬。換下個場景,這四層不用重建,只要再宣告幾個物件。那"80% 的反覆造地基",被壓成了幾百行宣告。 +剩下四層由開源 ObjectStack 執行時一次性給齊:**語義層**——這份宣告本身就是 agent 看懂業務的依據;**權限層**——誰能讀寫報修單,執行時每次呼叫強制核驗;**流程與審批層**——"維修費超額走審批"是掛在物件上的宣告式流程,自動暫停等簽字;**審計層**——人和 agent 的每次動作落進同一本賬。換下個場景,這四層不用重建,只要再宣告幾個物件。那"80% 的反覆造地基",被壓成了幾百行宣告。 -老陳那個專案如果是這麼搭的,法務那個問題就不會是死刑:他能當場調出許可權集,證明 agent 只能以提問者的身份、看提問者有權看的資料——第②層本來就在腳下,專案也就有機會當場放行。 +老陳那個專案如果是這麼搭的,法務那個問題就不會是死刑:他能當場調出權限集,證明 agent 只能以提問者的身份、看提問者有權看的資料——第②層本來就在腳下,專案也就有機會當場放行。 ## 結語 -真正進了生產的專案,靠的很少只是最好的模型。靠的是模型腳下那四層——語義、許可權、流程、審計——穩穩地在;也靠組織真的把它用起來。前者是入場券,後者是比賽,兩個都得要。 +真正進了生產的專案,靠的很少只是最好的模型。靠的是模型腳下那四層——語義、權限、流程、審計——穩穩地在;也靠組織真的把它用起來。前者是入場券,後者是比賽,兩個都得要。 所以如果你的 agent 試點又卡住了,先別急著換模型。問老陳四個月後才學會問的問題:**它腳下這四層,到底建了幾層?** 這比再調一版提示詞,省錢得多,也救得了一個專案和一個人的可信度。 @@ -123,4 +123,4 @@ export const RepairTicket = ObjectSchema.create({ npm i -g @objectstack/cli && os start ``` -宣告一個物件和它的許可權,讓 agent 去用它——你會發現那四層已經在腳下了,而你只寫了幾十行。 +宣告一個物件和它的權限,讓 agent 去用它——你會發現那四層已經在腳下了,而你只寫了幾十行。 diff --git a/content/blog/why-custom-systems-die/index.zh-Hant.mdx b/content/blog/why-custom-systems-die/index.zh-Hant.mdx index fe9bec0..1ca646d 100644 --- a/content/blog/why-custom-systems-die/index.zh-Hant.mdx +++ b/content/blog/why-custom-systems-die/index.zh-Hant.mdx @@ -80,7 +80,7 @@ tags: [] > 未來 AI 能不能幫到你,很大程度上取決於一件事——**你的系統,它讀不讀得懂。** -讀得懂的公司,AI 能在許可權之下查資料、建議流程改動、生成可審查的差異;讀不懂的公司,AI 往往只能停在外圍問答。同樣的行業、同樣的預算,兩類公司會逐漸拉開差距。 +讀得懂的公司,AI 能在權限之下查資料、建議流程改動、生成可審查的差異;讀不懂的公司,AI 往往只能停在外圍問答。同樣的行業、同樣的預算,兩類公司會逐漸拉開差距。 ## 解法:把系統從"一堆程式碼"變成"一份說明書" @@ -99,15 +99,15 @@ tags: [] - **改一處不用動全身**,加欄位、調流程是分鐘級的事,不必排期兩週、提心吊膽; - **AI 真的能進入系統協作**——因為它讀得懂整套系統,所以能生成可審查的改動、解釋影響範圍,而不只是一個外圍聊天框。 -這正是 ObjectStack 的出發點:把一整套業務系統,做成 AI 和人都能讀懂、能安全修改的結構。它讓業務物件、許可權、流程和動作成為可審查的定義,而不是散落在幾十處程式碼裡的隱含規則。 +這正是 ObjectStack 的出發點:把一整套業務系統,做成 AI 和人都能讀懂、能安全修改的結構。它讓業務物件、權限、流程和動作成為可審查的定義,而不是散落在幾十處程式碼裡的隱含規則。 -直觀的對比是:過去你想加個新模組,要先找回原作者、排期、反覆測試;在這種新形態下,AI 先生成一份小的後設資料 diff,人審查欄位、許可權和流程影響,再由執行時執行。交付可能更輕,但真正的關鍵是:負責人看得懂,也敢簽字。 +直觀的對比是:過去你想加個新模組,要先找回原作者、排期、反覆測試;在這種新形態下,AI 先生成一份小的後設資料 diff,人審查欄位、權限和流程影響,再由執行時執行。交付可能更輕,但真正的關鍵是:負責人看得懂,也敢簽字。 ## "那是不是又要推翻重來?"——恰恰相反 聊到這,很多老闆的第一反應是:"道理我懂,但我不可能把現在的系統全推翻重做。" -完全不需要。事實上,最務實的路,是**不動你的老系統,在它之上疊一層 AI 能讀懂的結構**——資料不搬家、原系統照常跑,卻能讓 AI 在上面工作,並且守住你原有的許可權和規矩。換句話說,你不是再賭一次"推倒重來",而是給現有系統補上一層可讀、可審、可治理的業務定義。 +完全不需要。事實上,最務實的路,是**不動你的老系統,在它之上疊一層 AI 能讀懂的結構**——資料不搬家、原系統照常跑,卻能讓 AI 在上面工作,並且守住你原有的權限和規矩。換句話說,你不是再賭一次"推倒重來",而是給現有系統補上一層可讀、可審、可治理的業務定義。 ![概念示意圖](./readable-system-model.webp) @@ -128,4 +128,4 @@ tags: [] 軟體正在從"做一次就定型的產品",變成"能持續演進的資產"。這一輪 AI,真正改變的不是多一個功能,而是重新決定一件事:哪些公司的系統能被 AI 讀懂、被負責人審查、被執行時治理,哪些只能繼續停在沒人敢改的狀態。 -把一套現有系統先建成物件、欄位、許可權和動作的定義,再讓 agent 生成小 diff 給人審查,是比“推倒重來”更現實的起點。 +把一套現有系統先建成物件、欄位、權限和動作的定義,再讓 agent 生成小 diff 給人審查,是比“推倒重來”更現實的起點。 diff --git a/scripts/gen-zh-hant.mjs b/scripts/gen-zh-hant.mjs index 761c2ae..0d8a0c1 100644 --- a/scripts/gen-zh-hant.mjs +++ b/scripts/gen-zh-hant.mjs @@ -10,8 +10,123 @@ import { readdir, readFile, writeFile } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import path from 'node:path'; import * as OpenCC from 'opencc-js'; +import { ConverterBuilder } from 'opencc-js/core'; -const convert = OpenCC.Converter({ from: 'cn', to: 'twp' }); +// ─── Taiwanese vocabulary: s2twp, minus two wrong entries ────────────────── +// +// `twp` is the right preset. Its phrase layer is what turns 数据 into 資料, +// 程序 into 程式, 对象 into 物件, 接口 into 介面, 服务器 into 伺服器, 软件 into +// 軟體, 信息 into 資訊, 缓存 into 快取, 用户 into 使用者 and 默认/缺省 into +// 預設 — 145 of its 603 phrase entries fire in this corpus, and all but two are +// the ordinary Taiwanese term. Dropping to plain `tw` to escape those two would +// lose every one of the rest, so the preset stays and the two are shadowed. +// +// HOW THE SHADOW WORKS. `s2twp` runs three conversion groups in order: +// [STPhrases, STCharacters] → [TWPhrases] → [TWVariants]. Inside one group the +// FIRST dictionary wins — `Trie.loadDictGroup` loads a group in reverse, so a +// dictionary listed earlier is loaded later and overwrites. An identity entry at +// the head of the TWPhrases group therefore disables exactly that one TWPhrases +// rule and nothing else: the correction lands at the stage that introduces the +// defect, and the character conversion underneath is untouched. +// +// WHY IDENTITY ENTRIES AND NOT A POST-PASS. Rewriting 許可權 back to 權限 after +// the fact would also rewrite a genuine 许可权 — a real Simplified word — that +// the preset had converted correctly. Shadowing leaves 许可权 → 許可權 alone and +// only stops 权限 from being rewritten. TWPhrases is the only dictionary in the +// chain that can emit 許可權 or 例項 at all: STPhrases (49276 entries), +// STCharacters (3882) and TWVariants (39) contain neither string. +const TWP_PHRASE_OVERRIDES = [ + // 权限 → 許可權 is a Microsoft-glossary rendering; 權限 is the ordinary term in + // Taiwanese technical and legal writing. Keyed on the post-s2t form, which is + // what the TWPhrases group sees. + ['權限', '權限'], + // 实例 → 例項 is not standard Taiwanese usage in any register. + ['實例', '實例'], +]; + +/** `s2twp` with TWP_PHRASE_OVERRIDES shadowing the head of its phrase group. */ +function buildVocabularyConverter() { + const stock = OpenCC.Locale.configs?.s2twp; + if (!stock || stock.conversionChain?.length !== 3) { + console.error( + '✗ gen-zh-hant: opencc-js no longer exposes an s2twp config with three ' + + 'conversion groups, so the phrase overrides have nowhere to sit. ' + + 'Re-derive them against the new shape before taking the upgrade.' + ); + process.exit(1); + } + return ConverterBuilder({ + from: OpenCC.Locale.from, + to: OpenCC.Locale.to, + configs: { + ...OpenCC.Locale.configs, + s2twp: { + segmentation: stock.segmentation, + // Group 1 is [TWPhrases]; the override goes in front of it. + conversionChain: stock.conversionChain.map((group, i) => + i === 1 ? [TWP_PHRASE_OVERRIDES, ...group] : group + ), + }, + }, + })({ from: 'cn', to: 'twp' }); +} + +// ─── 里 → 裡: the locative, where a straddling phrase match pinned it ─────── +// +// Not vocabulary. STCharacters already converts a bare 里 to 裏, which +// TWVariants then makes 裡, so the locative is OpenCC's default and 541 of the +// 553 locatives in this corpus come out right unaided. The twelve that do not +// are all one accident: OpenCC segments the Simplified text with STPhrases +// before converting it, and a two-character STPhrases entry that pins 里 as 里 — +// a place name, a proper noun, a measure word — matches ACROSS the word +// boundary and takes the 里 with it: +// +// 脚本里 → 本里 (a village) 函数里 → 数里 (a distance) +// 架构里根本 / 系统里根本 → 里根 (Reagan) 文件里加 → 里加 (Riga) +// 周报里拉出 → 里拉 (the lira) 定义里长 → 里长 (a village chief) +// 知道里面 → 道里 (a district of Harbin) +// +// Each of those entries is right in its own context, so none of them is +// shadowed; the straddle is repaired after conversion instead, and only behind a +// listed word. A wrong 裡 is worse than a wrong 里 — the reader who would catch it +// never sees it — so this is a whitelist by construction. It cannot fire on 公里, +// 英里, 里程碑, 鄰里, 里長 or a place name, because none of those follow one of +// the listed words. The straddle also blocks the phrase layer, which is why the +// text these rules touch reads 腳本 and 函數 rather than 指令碼 and 函式; both +// spellings are listed so the rule holds once a straddle stops hiding one. +const LOCATIVE_LI = [ + // …里 directly after a technical artifact. `(?!程)` holds 里程碑 out: 系統里程碑 + // is a milestone, not something inside the system. + [/(指令碼|腳本|架構|系統|週報|檔案|定義|函數|函式)里(?!程)/g, '$1裡'], + // …道里 — a word ending in 道 followed by the locative. Matched as whole words, + // never as a bare 道 + 里, so the district 道里 itself is left alone. + [/(知道|報道|頻道|通道)里(?!程)/g, '$1裡'], +]; + +/** + * 里 that is genuinely 里. Only used to keep the warning below quiet; being + * absent from this list costs a line of build output, never a wrong character. + */ +const GENUINE_LI = + /公里|英里|海里|華里|里程|里長|里民|里弄|鄰里|故里|鄉里|萬里|千里|百里|里根|里加|里拉|阿里|巴里|德里|克里|居里/g; + +const convertVocabulary = buildVocabularyConverter(); + +/** s2twp with the two phrase entries shadowed and the straddled 里 repaired. */ +function convert(source) { + let out = convertVocabulary(source); + for (const [pattern, replacement] of LOCATIVE_LI) out = out.replace(pattern, replacement); + return out; +} + +/** Every 里 left in a converted file that LOCATIVE_LI did not claim. */ +function unresolvedLocatives(text) { + const found = []; + for (const match of text.replace(GENUINE_LI, '').matchAll(/.{0,8}里.{0,8}/g)) { + found.push(match[0].replace(/\s+/g, ' ').trim()); + } + return found; +} // Pure-ASCII marker so OpenCC never touches it and includes() is reliable. const MARKER = @@ -164,18 +279,30 @@ function splitFrontmatter(source) { return { head: match[0], body: source.slice(match[0].length) }; } -// ─── Fixture: the scoped rewrite, pinned ─────────────────────────────────── +// ─── Fixtures: the scoped rewrite and the vocabulary, pinned ─────────────── // -// This repo has no test runner, and the property worth pinning is a negative -// one — a link is rewritten, an identical string inside code is not — which a -// later edit to the patterns above would break silently in generated output no -// one reads. So the cases run on every `pnpm dev` and `pnpm build`, off a stub -// registry where `known` is built and `ghost` is not. Pure string work; the -// generator prints nothing unless a case fails. +// This repo has no test runner, and the properties worth pinning are negative +// ones — a link is rewritten, an identical string inside code is not; 权限 comes +// out 權限 while a genuine 许可权 is left alone — which a later edit to the +// patterns above, or an opencc-js upgrade that reshuffles the phrase +// dictionaries, would break silently in generated output no one reads. A preset +// bump that reinstated 許可權 would put it back in 435 places, in `title` tags, +// cards, RSS and the sitemap, with nothing to say it had happened. So the cases +// run on every `pnpm dev` and `pnpm build`, off a stub registry where `known` is +// built and `ghost` is not. Pure string work; the generator prints nothing +// unless a case fails. function selfTest() { + const failures = []; + const check = (label, run, cases) => { + for (const [input, expected] of cases) { + const actual = run(input); + if (actual !== expected) failures.push({ label, input, expected, actual }); + } + }; + const stub = (rest) => rest === '' || rest === '/' || rest === '/blog/known/' || rest === '/glossary/known/'; - const cases = [ + check('link-rewrite', (input) => rewriteBodyLinks(input, stub, () => {}), [ // A body link is rewritten… ['[标题](/zh-Hans/blog/known/)', '[标题](/zh-Hant/blog/known/)'], ['x', 'x'], @@ -200,15 +327,50 @@ function selfTest() { '[a](/zh-Hans/blog/known/)\n```\n/zh-Hans/blog/known/\n```\n[b](/zh-Hans/blog/known/)', '[a](/zh-Hant/blog/known/)\n```\n/zh-Hans/blog/known/\n```\n[b](/zh-Hant/blog/known/)', ], - ]; - const failures = []; - for (const [input, expected] of cases) { - const actual = rewriteBodyLinks(input, stub, () => {}); - if (actual !== expected) failures.push({ input, expected, actual }); - } + ]); + + check('conversion', convert, [ + // The two shadowed TWPhrases entries — bare, and in the phrase contexts the + // corpus actually uses, since the phrase layer is what the shadow sits in. + ['权限', '權限'], + ['权限边界', '權限邊界'], + ['行级权限', '行級權限'], + ['读取权限', '讀取權限'], + ['字段级权限', '欄位級權限'], + ['权限检查跑在哪一层', '權限檢查跑在哪一層'], + ['实例', '實例'], + ['实例化', '實例化'], + ['数据库实例', '資料庫實例'], + // …and a genuine 许可权 / 例项 in the source still converts on its own terms. + ['许可权', '許可權'], + ['例项', '例項'], + // The rest of the preset still applies. This is the whole reason `twp` is + // kept rather than dropped to `tw` to escape the two entries above. + ['数据 程序 对象 接口 服务器', '資料 程式 物件 介面 伺服器'], + ['软件 信息 缓存 用户 默认 缺省', '軟體 資訊 快取 使用者 預設 預設'], + // The straddled locative 里, in every shape the corpus produced it. + ['只存在于命令式处理函数里', '只存在於命令式處理函數裡'], + ['流程隐藏在脚本里', '流程隱藏在腳本裡'], + ['系统里根本没有', '系統裡根本沒有'], + ['架构里根本没有', '架構裡根本沒有'], + ['从周报里拉出来', '從週報裡拉出來'], + ['在规则文件里加三条', '在規則檔案裡加三條'], + ['而该从定义里长出来', '而該從定義裡長出來'], + ['用户不知道里面有什么', '使用者不知道裡面有什麼'], + // …and the genuine 里 it must never touch: a distance, a milestone, a + // village, a district, a place name. + ['五公里', '五公里'], + ['本周里程碑', '本週里程碑'], + ['系统里程碑', '系統里程碑'], + ['邻里和里长', '鄰里和里長'], + ['道里区', '道里區'], + ['万里长城', '萬里長城'], + ]); + if (failures.length > 0) { - console.error('✗ gen-zh-hant: link-rewrite fixture failed'); - for (const { input, expected, actual } of failures) { + console.error('✗ gen-zh-hant: fixture failed'); + for (const { label, input, expected, actual } of failures) { + console.error(` [${label}]`); console.error(` in: ${JSON.stringify(input)}`); console.error(` expected: ${JSON.stringify(expected)}`); console.error(` actual: ${JSON.stringify(actual)}`); @@ -226,6 +388,7 @@ let made = 0; let kept = 0; let relinked = 0; const skipped = []; +const locatives = []; for (const slug of slugs) { const src = path.join(BLOG, slug, 'index.zh-Hans.mdx'); const out = path.join(BLOG, slug, 'index.zh-Hant.mdx'); @@ -251,6 +414,7 @@ for (const slug of slugs) { ); if (localized !== body) relinked++; const converted = `${head}${localized}`.replace(/^---\n/, `---\n${MARKER}\n`); + for (const ctx of unresolvedLocatives(converted)) locatives.push({ file: rel, ctx }); await writeFile(out, converted, 'utf8'); made++; } @@ -267,3 +431,13 @@ if (skipped.length > 0) { ); for (const { file, href } of skipped) console.warn(` ${file}: ${href}`); } + +if (locatives.length > 0) { + console.warn( + `⚠ zh-Hant: ${locatives.length} 里 the locative whitelist did not claim. ` + + `Each is either a genuine 里 (add it to GENUINE_LI to quiet this line) or a ` + + `straddled locative that belongs in LOCATIVE_LI — a wrong 裡 is invisible to ` + + `the reader who would catch it, so neither list guesses:` + ); + for (const { file, ctx } of locatives) console.warn(` ${file}: …${ctx}…`); +} From 7aca1f163adab97dbb1c8599e8ea51bbad9fc9b5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 3 Sep 2026 02:55:32 +0000 Subject: [PATCH 2/2] zhconvert: one converter for the site and the generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The site had a second `Converter({from:'cn',to:'twp'})` in `src/lib/zhconvert.ts`, imported by ten modules, deriving every Traditional UI string, term label, glossary entry and marketing page from its zh-Hans source. It carried none of the overrides, so the built site shipped both spellings: an article title reading 權限 sat under a nav item reading 許可權. Move the whole pipeline — the two shadowed TWPhrases entries, the locative whitelist, and the fixture cases that pin them — into `src/lib/zhconvert.ts`, and have `scripts/gen-zh-hant.mjs` import it. One definition of how this site converts Simplified to Traditional, not two. The module stays free of relative imports so plain Node can load it by type stripping, the same constraint `src/lib/term-data.ts` documents. The fixture runs from the generator, which `pnpm dev` and `pnpm build` both execute before Astro starts, so a bad conversion now fails the build before a page is served rather than only before an MDX file is written. Three UI-string cases are added for the surface that was wrong. `src/lib/terms.ts` carried the one hand-written Traditional literal with 許可權 in it. Audited against the derived conversion: three of the four strings in that block are byte-identical to s2t(zh-Hans), and the fourth diverged in exactly this one word, so the block really is derived output that drifted. Regenerating the blog corpus through the shared module leaves it byte-identical — the refactor changes where the rules live, not what they do. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr --- scripts/gen-zh-hant.mjs | 186 +++++------------------------------- src/lib/terms.ts | 2 +- src/lib/zhconvert.ts | 203 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 225 insertions(+), 166 deletions(-) diff --git a/scripts/gen-zh-hant.mjs b/scripts/gen-zh-hant.mjs index 0d8a0c1..5613341 100644 --- a/scripts/gen-zh-hant.mjs +++ b/scripts/gen-zh-hant.mjs @@ -9,124 +9,16 @@ import { readdir, readFile, writeFile } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import path from 'node:path'; -import * as OpenCC from 'opencc-js'; -import { ConverterBuilder } from 'opencc-js/core'; +import { CONVERSION_CASES, s2t, unresolvedLocatives } from '../src/lib/zhconvert.ts'; -// ─── Taiwanese vocabulary: s2twp, minus two wrong entries ────────────────── -// -// `twp` is the right preset. Its phrase layer is what turns 数据 into 資料, -// 程序 into 程式, 对象 into 物件, 接口 into 介面, 服务器 into 伺服器, 软件 into -// 軟體, 信息 into 資訊, 缓存 into 快取, 用户 into 使用者 and 默认/缺省 into -// 預設 — 145 of its 603 phrase entries fire in this corpus, and all but two are -// the ordinary Taiwanese term. Dropping to plain `tw` to escape those two would -// lose every one of the rest, so the preset stays and the two are shadowed. -// -// HOW THE SHADOW WORKS. `s2twp` runs three conversion groups in order: -// [STPhrases, STCharacters] → [TWPhrases] → [TWVariants]. Inside one group the -// FIRST dictionary wins — `Trie.loadDictGroup` loads a group in reverse, so a -// dictionary listed earlier is loaded later and overwrites. An identity entry at -// the head of the TWPhrases group therefore disables exactly that one TWPhrases -// rule and nothing else: the correction lands at the stage that introduces the -// defect, and the character conversion underneath is untouched. -// -// WHY IDENTITY ENTRIES AND NOT A POST-PASS. Rewriting 許可權 back to 權限 after -// the fact would also rewrite a genuine 许可权 — a real Simplified word — that -// the preset had converted correctly. Shadowing leaves 许可权 → 許可權 alone and -// only stops 权限 from being rewritten. TWPhrases is the only dictionary in the -// chain that can emit 許可權 or 例項 at all: STPhrases (49276 entries), -// STCharacters (3882) and TWVariants (39) contain neither string. -const TWP_PHRASE_OVERRIDES = [ - // 权限 → 許可權 is a Microsoft-glossary rendering; 權限 is the ordinary term in - // Taiwanese technical and legal writing. Keyed on the post-s2t form, which is - // what the TWPhrases group sees. - ['權限', '權限'], - // 实例 → 例項 is not standard Taiwanese usage in any register. - ['實例', '實例'], -]; - -/** `s2twp` with TWP_PHRASE_OVERRIDES shadowing the head of its phrase group. */ -function buildVocabularyConverter() { - const stock = OpenCC.Locale.configs?.s2twp; - if (!stock || stock.conversionChain?.length !== 3) { - console.error( - '✗ gen-zh-hant: opencc-js no longer exposes an s2twp config with three ' + - 'conversion groups, so the phrase overrides have nowhere to sit. ' + - 'Re-derive them against the new shape before taking the upgrade.' - ); - process.exit(1); - } - return ConverterBuilder({ - from: OpenCC.Locale.from, - to: OpenCC.Locale.to, - configs: { - ...OpenCC.Locale.configs, - s2twp: { - segmentation: stock.segmentation, - // Group 1 is [TWPhrases]; the override goes in front of it. - conversionChain: stock.conversionChain.map((group, i) => - i === 1 ? [TWP_PHRASE_OVERRIDES, ...group] : group - ), - }, - }, - })({ from: 'cn', to: 'twp' }); -} +// The conversion itself — the preset, the two shadowed phrase entries and the +// locative repair — lives in `src/lib/zhconvert.ts`, because the site derives +// its Traditional UI strings, term labels, glossary and marketing pages from the +// same rules. Read that file before changing how anything converts; it explains +// why each override exists and why Node can load it. Node imports it directly +// via type stripping, which is why the specifier carries its `.ts` extension. +const convert = s2t; -// ─── 里 → 裡: the locative, where a straddling phrase match pinned it ─────── -// -// Not vocabulary. STCharacters already converts a bare 里 to 裏, which -// TWVariants then makes 裡, so the locative is OpenCC's default and 541 of the -// 553 locatives in this corpus come out right unaided. The twelve that do not -// are all one accident: OpenCC segments the Simplified text with STPhrases -// before converting it, and a two-character STPhrases entry that pins 里 as 里 — -// a place name, a proper noun, a measure word — matches ACROSS the word -// boundary and takes the 里 with it: -// -// 脚本里 → 本里 (a village) 函数里 → 数里 (a distance) -// 架构里根本 / 系统里根本 → 里根 (Reagan) 文件里加 → 里加 (Riga) -// 周报里拉出 → 里拉 (the lira) 定义里长 → 里长 (a village chief) -// 知道里面 → 道里 (a district of Harbin) -// -// Each of those entries is right in its own context, so none of them is -// shadowed; the straddle is repaired after conversion instead, and only behind a -// listed word. A wrong 裡 is worse than a wrong 里 — the reader who would catch it -// never sees it — so this is a whitelist by construction. It cannot fire on 公里, -// 英里, 里程碑, 鄰里, 里長 or a place name, because none of those follow one of -// the listed words. The straddle also blocks the phrase layer, which is why the -// text these rules touch reads 腳本 and 函數 rather than 指令碼 and 函式; both -// spellings are listed so the rule holds once a straddle stops hiding one. -const LOCATIVE_LI = [ - // …里 directly after a technical artifact. `(?!程)` holds 里程碑 out: 系統里程碑 - // is a milestone, not something inside the system. - [/(指令碼|腳本|架構|系統|週報|檔案|定義|函數|函式)里(?!程)/g, '$1裡'], - // …道里 — a word ending in 道 followed by the locative. Matched as whole words, - // never as a bare 道 + 里, so the district 道里 itself is left alone. - [/(知道|報道|頻道|通道)里(?!程)/g, '$1裡'], -]; - -/** - * 里 that is genuinely 里. Only used to keep the warning below quiet; being - * absent from this list costs a line of build output, never a wrong character. - */ -const GENUINE_LI = - /公里|英里|海里|華里|里程|里長|里民|里弄|鄰里|故里|鄉里|萬里|千里|百里|里根|里加|里拉|阿里|巴里|德里|克里|居里/g; - -const convertVocabulary = buildVocabularyConverter(); - -/** s2twp with the two phrase entries shadowed and the straddled 里 repaired. */ -function convert(source) { - let out = convertVocabulary(source); - for (const [pattern, replacement] of LOCATIVE_LI) out = out.replace(pattern, replacement); - return out; -} - -/** Every 里 left in a converted file that LOCATIVE_LI did not claim. */ -function unresolvedLocatives(text) { - const found = []; - for (const match of text.replace(GENUINE_LI, '').matchAll(/.{0,8}里.{0,8}/g)) { - found.push(match[0].replace(/\s+/g, ' ').trim()); - } - return found; -} // Pure-ASCII marker so OpenCC never touches it and includes() is reliable. const MARKER = @@ -279,18 +171,24 @@ function splitFrontmatter(source) { return { head: match[0], body: source.slice(match[0].length) }; } -// ─── Fixtures: the scoped rewrite and the vocabulary, pinned ─────────────── +// ─── Fixtures: the scoped rewrite and the conversion, pinned ─────────────── // // This repo has no test runner, and the properties worth pinning are negative // ones — a link is rewritten, an identical string inside code is not; 权限 comes // out 權限 while a genuine 许可权 is left alone — which a later edit to the // patterns above, or an opencc-js upgrade that reshuffles the phrase -// dictionaries, would break silently in generated output no one reads. A preset -// bump that reinstated 許可權 would put it back in 435 places, in `title` tags, -// cards, RSS and the sitemap, with nothing to say it had happened. So the cases -// run on every `pnpm dev` and `pnpm build`, off a stub registry where `known` is -// built and `ghost` is not. Pure string work; the generator prints nothing -// unless a case fails. +// dictionaries, would break silently in output no one reads. +// +// This script is where both sets run, because `pnpm dev` and `pnpm build` both +// execute it before Astro starts: the link cases are this file's own, and the +// conversion cases come from `src/lib/zhconvert.ts`, which the site itself +// converts with. Pinning them here means a bad conversion fails the build before +// a single MDX file is written or a single page is served — which is the failure +// this round exists to prevent, since the conversion now reaches the nav, +// glossary and marketing routes as well as the corpus. +// +// The link cases run off a stub registry where `known` is built and `ghost` is +// not. Pure string work; the generator prints nothing unless a case fails. function selfTest() { const failures = []; const check = (label, run, cases) => { @@ -329,43 +227,11 @@ function selfTest() { ], ]); - check('conversion', convert, [ - // The two shadowed TWPhrases entries — bare, and in the phrase contexts the - // corpus actually uses, since the phrase layer is what the shadow sits in. - ['权限', '權限'], - ['权限边界', '權限邊界'], - ['行级权限', '行級權限'], - ['读取权限', '讀取權限'], - ['字段级权限', '欄位級權限'], - ['权限检查跑在哪一层', '權限檢查跑在哪一層'], - ['实例', '實例'], - ['实例化', '實例化'], - ['数据库实例', '資料庫實例'], - // …and a genuine 许可权 / 例项 in the source still converts on its own terms. - ['许可权', '許可權'], - ['例项', '例項'], - // The rest of the preset still applies. This is the whole reason `twp` is - // kept rather than dropped to `tw` to escape the two entries above. - ['数据 程序 对象 接口 服务器', '資料 程式 物件 介面 伺服器'], - ['软件 信息 缓存 用户 默认 缺省', '軟體 資訊 快取 使用者 預設 預設'], - // The straddled locative 里, in every shape the corpus produced it. - ['只存在于命令式处理函数里', '只存在於命令式處理函數裡'], - ['流程隐藏在脚本里', '流程隱藏在腳本裡'], - ['系统里根本没有', '系統裡根本沒有'], - ['架构里根本没有', '架構裡根本沒有'], - ['从周报里拉出来', '從週報裡拉出來'], - ['在规则文件里加三条', '在規則檔案裡加三條'], - ['而该从定义里长出来', '而該從定義裡長出來'], - ['用户不知道里面有什么', '使用者不知道裡面有什麼'], - // …and the genuine 里 it must never touch: a distance, a milestone, a - // village, a district, a place name. - ['五公里', '五公里'], - ['本周里程碑', '本週里程碑'], - ['系统里程碑', '系統里程碑'], - ['邻里和里长', '鄰里和里長'], - ['道里区', '道里區'], - ['万里长城', '萬里長城'], - ]); + // The conversion cases live beside the rules they pin, in + // `src/lib/zhconvert.ts`, because that module is what both the site and this + // generator convert with. Running them here is what makes them run at all: + // `pnpm dev` and `pnpm build` both execute this script before Astro starts. + check('conversion', convert, CONVERSION_CASES); if (failures.length > 0) { console.error('✗ gen-zh-hant: fixture failed'); diff --git a/src/lib/terms.ts b/src/lib/terms.ts index 1270bcb..f57a2b2 100644 --- a/src/lib/terms.ts +++ b/src/lib/terms.ts @@ -77,7 +77,7 @@ export function termDescription(term: Term, locale: Locale): string { }, 'zh-Hant': { topic: `圍繞${label}的文章,關注 AI-native 企業軟體、受控資料、應用搭建和 Agent 工作流的實踐。`, - solution: `關於${label}場景的實踐思考,覆蓋資料模型、流程、許可權、整合以及企業 AI Agent 的設計方式。`, + solution: `關於${label}場景的實踐思考,覆蓋資料模型、流程、權限、整合以及企業 AI Agent 的設計方式。`, role: `面向${label}的文章,討論如何用 ObjectOS 構建、執行和治理 AI-native 業務應用。`, industry: `面向${label}團隊的文章,討論如何連線現有系統、業務資料、流程與 AI Agent,而不是替換核心平臺。`, }, diff --git a/src/lib/zhconvert.ts b/src/lib/zhconvert.ts index c34aba2..6c8092c 100644 --- a/src/lib/zhconvert.ts +++ b/src/lib/zhconvert.ts @@ -1,8 +1,201 @@ import * as OpenCC from 'opencc-js'; +import { ConverterBuilder } from 'opencc-js/core'; +import type { DictGroup, DictLike, LocalePreset } from 'opencc-js/core'; -// Simplified (mainland) -> Traditional (Taiwan, with phrase conversion). -// Used at build time to derive zh-Hant UI strings and term labels from -// zh-Hans, so we never maintain Traditional copies of fixed strings by hand. -const convert = OpenCC.Converter({ from: 'cn', to: 'twp' }); +// How this site converts Simplified (mainland) to Traditional (Taiwan) — the +// ONE definition of it. Used at build time from two worlds: +// +// * under Vite, by `s2t` below, which derives every Traditional UI string, +// term label, glossary entry and marketing page from its zh-Hans source, so +// we never hand-maintain Traditional copies of fixed strings; +// * under plain Node, by `scripts/gen-zh-hant.mjs`, which regenerates +// `content/blog/**/index.zh-Hant.mdx`. +// +// It used to be defined twice: this file held a bare `s2twp` converter and the +// generator held a corrected one. The result shipped a page whose article text +// said 權限 under a nav item that said 許可權 — right in the prose, wrong in the +// chrome, in the same viewport. So both callers now build from here. +// +// ⛔ Node loads this module directly (`import('…/zhconvert.ts')`, type +// stripping, Node 22.18+), which resolves specifiers by Node's own rules. Bare +// package specifiers like `opencc-js` are fine in both worlds; an extensionless +// RELATIVE specifier such as `./i18n` is Vite-only and would make the generator +// fail with ERR_MODULE_NOT_FOUND. Keep relative imports out of this file — the +// same constraint `src/lib/term-data.ts` documents, for the same reason. -export const s2t = (s: string): string => convert(s); +// ─── Taiwanese vocabulary: s2twp, minus two wrong entries ────────────────── +// +// `twp` is the right preset. Its phrase layer is what turns 数据 into 資料, +// 程序 into 程式, 对象 into 物件, 接口 into 介面, 服务器 into 伺服器, 软件 into +// 軟體, 信息 into 資訊, 缓存 into 快取, 用户 into 使用者 and 默认/缺省 into +// 預設 — 123 of its 603 phrase entries fire in the blog corpus, and all but two +// are the ordinary Taiwanese term. Dropping to plain `tw` to escape those two +// would lose every one of the rest, so the preset stays and the two are +// shadowed. +// +// HOW THE SHADOW WORKS. `s2twp` runs three conversion groups in order: +// [STPhrases, STCharacters] → [TWPhrases] → [TWVariants]. Inside one group the +// FIRST dictionary wins — `Trie.loadDictGroup` loads a group in reverse, so a +// dictionary listed earlier is loaded later and overwrites. An identity entry at +// the head of the TWPhrases group therefore disables exactly that one TWPhrases +// rule and nothing else: the correction lands at the stage that introduces the +// defect, and the character conversion underneath is untouched. +// +// WHY IDENTITY ENTRIES AND NOT A POST-PASS. Rewriting 許可權 back to 權限 after +// the fact would also rewrite a genuine 许可权 — a real Simplified word — that +// the preset had converted correctly. Shadowing leaves 许可权 → 許可權 alone and +// only stops 权限 from being rewritten. TWPhrases is the only dictionary in the +// chain that can emit 許可權 or 例項 at all: STPhrases (49276 entries), +// STCharacters (3882) and TWVariants (39) contain neither string. +export const TWP_PHRASE_OVERRIDES: readonly (readonly [string, string])[] = [ + // 权限 → 許可權 is a Microsoft-glossary rendering; 權限 is the ordinary term in + // Taiwanese technical and legal writing. Keyed on the post-s2t form, which is + // what the TWPhrases group sees. + ['權限', '權限'], + // 实例 → 例項 is not standard Taiwanese usage in any register. + ['實例', '實例'], +]; + +/** `s2twp` with TWP_PHRASE_OVERRIDES shadowing the head of its phrase group. */ +function buildVocabularyConverter(): (text: string) => string { + const stock = OpenCC.Locale.configs?.s2twp; + if (!stock || stock.conversionChain?.length !== 3) { + throw new Error( + 'opencc-js no longer exposes an s2twp config with three conversion groups, ' + + 'so the phrase overrides in src/lib/zhconvert.ts have nowhere to sit. ' + + 'Re-derive them against the new shape before taking the upgrade.' + ); + } + const preset: LocalePreset = { + from: OpenCC.Locale.from, + to: OpenCC.Locale.to, + configs: { + ...OpenCC.Locale.configs, + s2twp: { + segmentation: stock.segmentation, + // Group 1 is [TWPhrases]; the override goes in front of it. + conversionChain: stock.conversionChain.map((group, i) => + i === 1 ? ([TWP_PHRASE_OVERRIDES as DictLike, ...group] as DictGroup) : group + ), + }, + }, + }; + return ConverterBuilder(preset)({ from: 'cn', to: 'twp' }); +} + +// ─── 里 → 裡: the locative, where a straddling phrase match pinned it ─────── +// +// Not vocabulary. STCharacters already converts a bare 里 to 裏, which +// TWVariants then makes 裡, so the locative is OpenCC's default and 541 of the +// 553 locatives in the blog corpus come out right unaided. The twelve that do +// not are all one accident: OpenCC segments the Simplified text with STPhrases +// before converting it, and a two-character STPhrases entry that pins 里 as 里 — +// a place name, a proper noun, a measure word — matches ACROSS the word +// boundary and takes the 里 with it: +// +// 脚本里 → 本里 (a village) 函数里 → 数里 (a distance) +// 架构里根本 / 系统里根本 → 里根 (Reagan) 文件里加 → 里加 (Riga) +// 周报里拉出 → 里拉 (the lira) 定义里长 → 里长 (a village chief) +// 知道里面 → 道里 (a district of Harbin) +// +// Each of those entries is right in its own context, so none of them is +// shadowed; the straddle is repaired after conversion instead, and only behind a +// listed word. A wrong 裡 is worse than a wrong 里 — the reader who would catch it +// never sees it — so this is a whitelist by construction. It cannot fire on 公里, +// 英里, 里程碑, 鄰里, 里長 or a place name, because none of those follow one of +// the listed words. The straddle also blocks the phrase layer, which is why the +// text these rules touch reads 腳本 and 函數 rather than 指令碼 and 函式; both +// spellings are listed so the rule holds once a straddle stops hiding one. +export const LOCATIVE_LI: readonly (readonly [RegExp, string])[] = [ + // …里 directly after a technical artifact. `(?!程)` holds 里程碑 out: 系統里程碑 + // is a milestone, not something inside the system. + [/(指令碼|腳本|架構|系統|週報|檔案|定義|函數|函式)里(?!程)/g, '$1裡'], + // …道里 — a word ending in 道 followed by the locative. Matched as whole words, + // never as a bare 道 + 里, so the district 道里 itself is left alone. + [/(知道|報道|頻道|通道)里(?!程)/g, '$1裡'], +]; + +/** + * 里 that is genuinely 里. Only used to keep the generator's warning quiet; + * being absent from this list costs a line of build output, never a wrong + * character. + */ +export const GENUINE_LI = + /公里|英里|海里|華里|里程|里長|里民|里弄|鄰里|故里|鄉里|萬里|千里|百里|里根|里加|里拉|阿里|巴里|德里|克里|居里/g; + +const convertVocabulary = buildVocabularyConverter(); + +/** + * Simplified (mainland) → Traditional (Taiwan, phrase conversion), with the two + * wrong preset entries shadowed and the straddled locative repaired. + */ +export const s2t = (s: string): string => { + let out = convertVocabulary(s); + for (const [pattern, replacement] of LOCATIVE_LI) out = out.replace(pattern, replacement); + return out; +}; + +/** Every 里 in converted text that LOCATIVE_LI did not claim. */ +export function unresolvedLocatives(text: string): string[] { + const found: string[] = []; + for (const match of text.replace(GENUINE_LI, '').matchAll(/.{0,8}里.{0,8}/g)) { + found.push(match[0].replace(/\s+/g, ' ').trim()); + } + return found; +} + +// ─── Fixture: the conversion, pinned ─────────────────────────────────────── +// +// This repo has no test runner, and the property worth pinning is a negative +// one — 权限 comes out 權限 while a genuine 许可权 is left alone — which an +// opencc-js upgrade that reshuffles the phrase dictionaries, or an edit to the +// rules above, would break silently in build output no one reads. A preset bump +// that reinstated 許可權 would put it back in 435 blog occurrences AND in the nav +// of every Traditional page, in `title` tags, cards, RSS and the sitemap, with +// nothing to say it had happened. +// +// The cases live here, next to the rules they pin, and are run by +// `scripts/gen-zh-hant.mjs`, which `pnpm dev` and `pnpm build` both execute +// before Astro starts — so nothing is written or served without them passing. +export const CONVERSION_CASES: readonly (readonly [string, string])[] = [ + // The two shadowed TWPhrases entries — bare, and in the phrase contexts the + // corpus actually uses, since the phrase layer is what the shadow sits in. + ['权限', '權限'], + ['权限边界', '權限邊界'], + ['行级权限', '行級權限'], + ['读取权限', '讀取權限'], + ['字段级权限', '欄位級權限'], + ['权限检查跑在哪一层', '權限檢查跑在哪一層'], + ['实例', '實例'], + ['实例化', '實例化'], + ['数据库实例', '資料庫實例'], + // …and a genuine 许可权 / 例项 in the source still converts on its own terms. + ['许可权', '許可權'], + ['例项', '例項'], + // The rest of the preset still applies. This is the whole reason `twp` is + // kept rather than dropped to `tw` to escape the two entries above. + ['数据 程序 对象 接口 服务器', '資料 程式 物件 介面 伺服器'], + ['软件 信息 缓存 用户 默认 缺省', '軟體 資訊 快取 使用者 預設 預設'], + // The UI strings this module derives — the half that shipped wrong until the + // two converters were merged into one. + ['权限与安全', '權限與安全'], + ['权限模型', '權限模型'], + ['字段级权限与审计', '欄位級權限與審計'], + // The straddled locative 里, in every shape the corpus produced it. + ['只存在于命令式处理函数里', '只存在於命令式處理函數裡'], + ['流程隐藏在脚本里', '流程隱藏在腳本裡'], + ['系统里根本没有', '系統裡根本沒有'], + ['架构里根本没有', '架構裡根本沒有'], + ['从周报里拉出来', '從週報裡拉出來'], + ['在规则文件里加三条', '在規則檔案裡加三條'], + ['而该从定义里长出来', '而該從定義裡長出來'], + ['用户不知道里面有什么', '使用者不知道裡面有什麼'], + // …and the genuine 里 it must never touch: a distance, a milestone, a + // village, a district, a place name. + ['五公里', '五公里'], + ['本周里程碑', '本週里程碑'], + ['系统里程碑', '系統里程碑'], + ['邻里和里长', '鄰里和里長'], + ['道里区', '道里區'], + ['万里长城', '萬里長城'], +];