Skip to Content
核心概念AI 可以怎麼回答

AI 找不到資料時可以怎麼回答

以前 AI 助理讀自訂表格讀不到資料時,會直接說「這筆資料不存在」。這句話常常是錯的:一列資料看不到,可能是被 row policy 濾掉、可能是欄位被隱藏、可能是 SCP channel 範圍不含它、可能是這張表沒有被納入這個聊天室的洞察系統,也可能是有人的寫入還在等核准、還沒落地。

「我看不到」和「它不存在」是兩件不同的事,而使用者以前收到的是自信的那一句。所以現在只要讀到零列,就會附帶一個判定,而 AI 只有在判定允許時才可以否認它存在。

absence 物件

當讀取結果 total == 0,AI 的資料列查詢工具會附上一個 absence 物件,帶三種判定之一:

判定代表什麼AI 可以怎麼說
not_found檢視沒有被收窄,也沒有任何未落地的寫入可以解釋這次找不到可以說沒有這筆資料
not_visible檢視被收窄,或探測無法完成不存在這件事未被證明:AI 既不能否認、也不能斷言它存在
held有一筆帶著這段文字的寫入被登記,但還沒落地說明那筆請求的狀態,而不是說資料不存在

absence 物件是說「這筆資料不存在」的唯一依據。沒有它,誠實的回答是:在我能看到的範圍裡找不到。

held 判定,以及使用者接下來該做什麼

held 只在「已提出但不在表裡」的暫存變更狀態上成立:pendingapplyingapply_faileddiscardedapplied 刻意排除,因為那一列已經落地,讀得到。

每種狀態的下一步不同,AI 被要求要說清楚是哪一種:

  • pending / applying:還在等核准。沒有東西壞掉,就是需要有人去審。
  • apply_failed:核准已經過了,但接著被這張表的某條規則拒絕。判定會附上 reason,引用被拒絕的那筆寫入;正確的做法是修正 reason 指出的資料再重送。重新核准沒有用,因為核准早就完成了。
  • discarded:那筆請求已被取消或駁回,沒有什麼在等。

探測不會洩漏資料

暫留探測回答的是「是不是有人未落地的寫入造成這次找不到」,這代表它要讀暫存變更,因此有兩層閘門。

「有哪些暫存列存在」交給與核准清單相同的查詢:管理者看得到這張表的紀錄,其他人只看得到自己提出的請求,加上目標資料列本來就通過他 row 層 ACL 的紀錄。

「哪些內容可以讀」是第二層、也更窄的閘門。探測回報的每個欄位都是從 payload 推導出來的,所以「可以列出但不能讀」的紀錄會被跳過,而跳過就會把這次掃描標記為不完整。

只有真的跑完的探測才能斷言「不存在」

任何沒有真的掃描的離開路徑都會把掃描標記為不完整,而不完整的掃描會把判定強制成 not_visible。這涵蓋:查詢裡沒有可用的比對字串、缺少主體、達到暫存掃描的列數上限、payload 太大走不完、caller 不能讀的 payload,以及探測本身失敗。

這個偏誤是刻意的:少報一個暫留是比較小的錯,而暫留永遠不會被憑空製造出來。

哪些參數會餵給探測

探測要比對的字串來自一組固定的參數。在 custom_tables_find_recordssearch_text,當成子字串比對值收集。在 custom_tables_query_recordsfiltersany_of——而且只有這兩個。比較新的那幾個讀取參數一個都不會貢獻:全域 q 文字搜尋與 computed_filters 述語對探測是不存在的。

所以,只用 q 收窄的 query_records 呼叫沒有可用的比對字串,掃描會被標記為不完整,判定被強制成 not_visible。它永遠不可能回 not_found,也永遠不會浮出一筆帶著那段文字的 held 寫入——即使那筆寫入真的存在。如果這次讀取的目的是判定一筆資料存不存在,就把那個字串放進 filterseqcontains 條件,或改用 find_records,讓探測真的跑起來。q 是用來找到資料列的,不是用來證明資料列不存在的。

為什麼一筆資料會「看起來不存在」

AI 自己的說明現在把這些列為原因,你在處理使用者「系統把我的資料弄丟了」的回報時也值得知道:

  • 所在聊天室從未被授權這張表,或該房的授權列收窄了這個房間能看到的範圍——自 2026-07-28 起,agent session 解析部門表只看所在聊天室的授權(釘選天花板),所以你在 REST 上讀得到的資料列,在這個房間裡可能是隱形的,管理者也一樣;見 effective permissions
  • row policy 把那一列濾掉,包含每次請求才解析的 $me$today$now
  • 使用者用來過濾的欄位被 column ACL 隱藏
  • SCP channel 範圍 在這個聊天室不含那一列
  • 這張表沒有被納入這個聊天室的洞察系統
  • 寫入確實存在,但還沒落地:等核准中、正在套用、被規則拒絕,或已被丟棄

只有最後一項是暫留,其他都是可見性問題,而可見性正是 not_visible 的用途。

被拒絕或被截斷的一輪是看得見的,不是空白

「找不到」有一個孿生的失敗模式:模型根本什麼都沒產出的那一輪。在 backend PR #1181 之前,provider 的拒絕或 token 上限截斷會被存成一則空的、成功的 assistant 訊息——succeed 為 true、沒有錯誤碼、沒有文字——Custom Tables 房間的使用者體驗到的,就是助理單純沒有回話。畫面上沒有東西可以反應,存下來的那一輪也沒有東西可以除錯。

現在這樣的一輪會存下一則看得見的婉拒,帶著 succeed = falseerror_code

成因error_code客戶讀到什麼
模型拒絕——Anthropic refusal、OpenAI content_filter、Gemini/Vertex 的 safetyprohibited_contentblocklistspiirecitationimage_safetymodel_refusal「抱歉,這個請求我無法回覆。」/Sorry, I can't respond to that request.
回覆被截斷——max_tokenslengthmodel_context_window_exceededmodel_output_truncated「回覆在產生時被截斷,請縮小問題範圍後再試一次。」/The reply was cut off while being generated; please narrow the question and try again.

在對話紀錄裡讀到這種訊息時,有三個性質很重要:

  • 文字是伺服器撰寫、決定性的。provider 的任何字串都不會送到客戶眼前,而這則婉拒是普通的 assistant 內容——它會渲染、會進 thread、也會被計入,和其他回覆一樣。
  • 語言由該輪對話文字的 CJK 偵測決定,不是由通道型別、也不是由房間語系決定。
  • 這道防護只在答案為空時才啟動。模型拒絕但仍然產出文字時,內容不會被動;而空答案的停止原因若不在上述兩份清單內,仍然維持 succeed = true,只會留下一筆 log。

使用者要求的 JSON 區塊不再被剝掉

同一類空白輪還有第二個成因。Chat 後處理會刪掉外洩的 tool-call JSON,讓原始 tool call 永遠不會送到客戶眼前——而它過去會刪掉每一個json 標記的圍欄區塊,包含使用者明確要求的那一個。在一個「就是要你回一個 JSON object」的房間裡,答案被剝掉,取而代之被存下來的是一則空的 assistant 訊息。

自 backend PR #1178 起,只有當 json 區塊的內容看起來像外洩的 tool call 時才會被刪除:內容含有 "tool""tool_calls",或同時含有 "name""arguments""parameters"。其他任何東西——陣列、一般 object、業務 payload——都會原樣保留,連 fence 一起。這是對原始內容做子字串比對,所以一個真正的答案若剛好同時帶著 nameparameters 欄位,仍然會被移除;替房間指定固定輸出形狀時,請避開這組 key 名稱。另外要注意:Final Answer Contract 在使用者要求恰好一個 JSON object 時,要的是沒有 fence 的裸物件——這條規則講的是仍然會走到後處理的「有 fence」情況。

AI 實際上能對一張表提出哪些問題——運算子、上限,以及沿路會撞到的拒絕——見 Agent 工具箱

小型查找、分析與異動確認(v5.10.0)

custom_tables_find_recordsmatches 現在包含 {id, label, data},另有 totaldata 使用可見的顯示欄名,補齊人員/附件顯示資料並移除隱藏欄位,因此小型文字查找可直接回答,不必再呼叫 analyst。條件查詢、計數、彙總、比較與跨表問題仍交給 analyst。

Analyst 對清單或單一值查找使用一次伺服器端篩選/排序查詢;彙總與衍生指標仍需驗證。對使用者的回答採業務名稱與人員顯示名稱,並說明列權限造成的可見範圍限制;只有明確要求時才顯示 ID。Schema 提示也會依欄位型別說明輸入格式、限制與唯讀計算欄位。

異動確認採人員與資料的業務名稱,只詢問一次,並可接受有上下文的自然語言同意。遭拒或參數錯誤不等於寫入成功;把遭拒的值改放其他欄位,需要使用者另行提出要求。批次工具只宣告目前 grant 允許的 action kinds。

Last updated on