Agent 資料庫操作實作課:讓 Agent 查得到庫、改得了庫,卻釀不了災

Agent 資料庫操作實作課:讓 Agent 查得到庫、改得了庫,卻釀不了災

前言

幾乎每一個實用的 Agent 最後都會撞上同一道牆:資料不在文件裡,而在資料庫裡。訂單狀態、庫存水位、客戶分級、帳務明細,全都以表格的形式躺在關聯式資料庫中。讓 Agent 讀得到這些資料,價值立刻顯現;但讓 Agent 直接連上生產資料庫,風險也立刻顯現。一個語意不清的請求、一次欄位誤判、一句被資料夾帶的指令,都可能把一句查詢變成一次寫入,把一次寫入變成一場事故。

這篇文章講清楚兩條路線:讀取怎麼做得準,寫入怎麼做得安全。如圖一,讀取是一條五步的管線;如圖二,安全不是一句提示詞,而是一層一層疊上去的結構性限制。先把這兩張圖想清楚,再動手接資料庫。

一、先分清楚:讀取與寫入是兩種不同的權力

許多資料庫 Agent 事故的根源,是把讀取與寫入混在同一個工具裡。模型拿到一個可以執行任意 SQL 的連線,就等於同時拿到了查詢權與修改權。提示詞寫著「只做查詢」,資料庫卻沒有這樣承諾。提示詞是建議,權限才是契約。

實作的第一個決定,應該是把兩種權力拆成兩個工具、兩組帳號、兩條路徑。讀取工具走唯讀帳號、指向唯讀副本或報表庫;寫入工具走另一組帳號,而且預設不上線,先以審核佇列的形式存在。這個拆分做完之後,後面所有的護欄才有地方可以掛上去。如果你的 Agent 今天只有一個資料庫工具,而且它什麼 SQL 都能跑,那麼無論提示詞寫得多嚴格,你的起點都還不安全。

二、讀取路線:Text-to-SQL 其實是五步,不是一步

把自然語言翻成 SQL,聽起來像一次生成,實務上卻是五個步驟串起來的管線。第一步是意圖釐清:使用者問「上週賣最好的商品」,模型要先確認時間範圍、銷售的定義、是否含退貨,而不是直接猜一個版本去跑。第二步是 Schema 連結:從幾十甚至幾百張表裡,找出真正相關的表與欄位。這個步驟在大型資料庫裡最容易失敗,因為模型根本沒有看過完整的 Schema。

第三步才是 SQL 生成:根據選定的表與欄位寫出查詢,明確列出欄位名稱,避免使用 SELECT 星號。第四步是驗證與修復:先在語法層檢查,再以小規模試跑確認結果合理,錯了就根據錯誤訊息修正,最多重試幾次就停手。第五步是結果詮釋:把原始資料列轉成使用者聽得懂的回答,並附上查詢條件,讓人可以追溯數字從哪裡來。

這條管線為什麼重要,可以從評測數字看出來。Spider 基準考的是在已知 Schema 下寫出正確 SQL;難度更高的 BIRD 基準,則加入雜訊、複雜問題與大型真實資料庫,考驗的是在不完美的資訊下仍然寫對。而更新的 Spider 2.0 更進一步,考的不是單一查詢,而是 Agent 能不能在陌生的資料環境裡翻文件、跑查詢、看結果、再修正,也就是把 Text-to-SQL 放進真正的 Agent 迴路裡。基準越來越難,透露的訊息很一致:單次生成的準確率不夠,管線與自我修正才是關鍵。

三、Schema 是瓶頸:不要把整座資料庫塞進提示詞

大型資料庫的 Schema 動輒上千個欄位,全部塞進提示詞既貴又會稀釋注意力,模型反而更容易選錯表。實務上有三種做法,依資料庫規模選用。第一種是人工整理的資料字典:為每一張常用表寫一句話說明,註明業務含義、常見查詢與容易誤解的欄位,例如訂單金額是否含稅、狀態碼各自代表什麼。這些說明比原始 DDL 更能幫助模型選對表。

第二種是按需擷取:模型先用關鍵字搜尋表名與欄位說明,只把相關的子集放進提示詞,查詢過程中需要更多資訊時再逐段索取。這種做法類似檢索增強生成,只是檢索的對象從文件換成了 Schema。第三種是預先建立檢視表與彙總表:把常用的跨表連接、指標計算先做成檢視表,讓 Agent 查的是一張語意清楚的寬表,而不是五張需要自己拼起來的原始表。檢視表不只是效能優化,更是把業務知識固化成模型看得懂的介面。

一個實用的經驗法則是:Agent 第一次查錯表,通常不是模型不夠聰明,而是 Schema 缺少業務語意。與其換更大的模型,不如先補資料字典與檢視表,成本更低,效果更穩定。

四、寫入路線:分級授權,而不是一次放行

讀取可以自動化,寫入必須分級。建議把寫入操作分成四級。第一級是無副作用的寫入,例如寫入審核日誌、快取、草稿狀態,這類操作可以由 Agent 自主執行,但仍要留下完整紀錄。第二級是可逆的寫入,例如更新非關鍵欄位、新增備註,執行前要先出示將要執行的語句與影響列數,取得一次性的確認後才執行。

第三級是不可逆或影響金流的寫入,例如退款、扣庫存、變更合約狀態,必須走人類把關閘門:Agent 提出變更提案,附上前後對照與回滾方案,人類同意後才由系統以受控的方式執行,絕對不要讓模型直接持有生產寫入連線。第四級是結構變更,例如建表、改欄位、刪表,這類操作根本不應該出現在 Agent 的工具清單裡,應該永遠留在人工變更流程與遷移腳本裡。

這個分級的重點在於:授權的單位不是 Agent 本身,而是每一次操作。同一位 Agent,查報表時可以全自動,碰到退款時就必須停下來等候放行。權力跟著操作走,而不是跟著身分走,事故的半徑才會被限縮。

五、安全五層:讓危險的 SQL 到不了資料庫

如圖二,安全設計要疊五層,每一層擋住不同類型的失誤。第一層是資料庫權限:給 Agent 專用的唯讀帳號,只授與 SELECT 權限,不授與寫入、建表、管理權限。這一層由資料庫引擎本身強制執行,提示詞再怎麼被繞過也無法逾越。第二層是連線隔離:讀取走唯讀副本,連物理上都不連到主庫。副本是目前最徹底的防線,因為在副本上寫入根本無從寫起。

第三層是 SQL 解析與檢查:在執行之前,先以真正的 SQL 解析器檢查語句類型,只放行 SELECT,擋下 INSERT、UPDATE、DELETE、DROP、TRUNCATE 等關鍵字,並且強制加上 LIMIT、限制回傳列數、設定語句逾時。注意不要用正規表示式做這件事,註解與字串裡的關鍵字很容易騙過它,解析器才是正確的工具。第四層是結果控管:遮罩敏感欄位、限制單次回傳的資料量、把原始資料列彙總後再交給模型,避免模型把整張客戶資料表讀進上下文。第五層是稽核日誌:每一條由 Agent 產生的 SQL、執行結果、同意紀錄都要留存,出事時才能重建現場,也才能回頭改善管線。

LangChain 官方文件對 SQL Agent 的提醒,與這個分層完全一致:不要只靠客戶端逾時,因為客戶端逾時不一定能取消資料庫端正在跑的語句;資源限制要在角色或工作階段層級設定,並且要監控慢查詢。換句話說,安全要落在資料庫與中介層,而不是落在模型的自律上。

六、最小可跑骨架:先讓讀取迴路轉起來

下面是一段 Python 風格的最小骨架,重點不在框架,而在結構:Schema 工具、唯讀執行工具、驗證邏輯,三者分開,模型永遠不直接碰連線字串。

import re

DENY = re.compile(r"\b(INSERT|UPDATE|DELETE|DROP|ALTER|TRUNCATE|CREATE)\b", re.I)

def run_readonly_sql(sql: str, max_rows: int = 100):
    # 第一關:語句類型檢查,只放行 SELECT
    if DENY.search(sql):
        raise ValueError("只允許唯讀查詢")
    # 第二關:強制限制回傳列數,避免整表灌進上下文
    if "limit" not in sql.lower():
        sql = sql.rstrip(";") + f" LIMIT {max_rows}"
    # 第三關:以唯讀帳號執行,並設定語句逾時
    return db.execute(sql, timeout_seconds=30)

# Agent 的工具清單只有兩項:查 Schema、跑唯讀 SQL
tools = [get_schema, run_readonly_sql]

骨架跑通之後,真正決定成敗的是四個實作要點。第一,查詢失敗要分級:語法錯誤可以自動修正重試,查到空結果要先懷疑條件寫錯,而不是直接回答沒有資料,涉及敏感表的請求要立刻停下來。第二,回傳列數要封頂:先回傳彙總與前幾列,需要細節時再分頁索取,不要把整張表倒進提示詞。第三,數字要可追溯:回答裡附上查詢條件與資料範圍,讓使用者可以驗證,而不是只能相信。第四,寫入提案要與執行分開:Agent 可以產出寫入語句與影響評估,但執行必須由另一條受控路徑完成,兩者之間隔著人類同意或佇列審核。

七、評測與上線檢查:先用自己的問題考它

上線之前,先準備一組黃金問題,涵蓋三種類型:常見問題、邊界問題、惡意或誤導問題。常見問題考準確率,邊界問題考時間範圍、空值、狀態碼這類容易誤解的語意,惡意問題則考護欄,例如要求刪除測試資料、要求列出全部客戶個資、要求繞過限制。每一題都要有預期的正確答案或預期的拒絕行為,跑出通過率之後再談導入。

成本也要用每問題來算,而不是每 Token。一次查詢的成本,來自 Schema 擷取、SQL 生成、驗證重試、結果詮釋四段的 Token 總和。省錢的槓桿很直接:資料字典寫得越好,Schema 擷取越精準;檢視表做得越完整,生成難度越低;重試次數設上限,避免模型在同一個錯誤上反覆燒錢。

結論

讓 Agent 操作資料庫,不是要給它一把萬能鑰匙,而是要給它一組權責分明的工具。讀取走五步管線:釐清意圖、連結 Schema、生成 SQL、驗證修復、詮釋結果;寫入走四級授權:從可自主的日誌寫入,到必須經人類同意的金流變更,再到永遠不開放的結構變更;安全疊五層:權限、副本、解析檢查、結果控管、稽核日誌。這個順序做對,Agent 才能既查得到資料,又釀不了災。上線檢查清單只有一句話:先讓唯讀迴路在副本上跑穩,再談任何寫入。

資料來源

- LangChain 官方文件:Build a SQL agent(唯讀檢查、LIMIT 與逾時設計):https://docs.langchain.com/oss/javascript/langchain/sql-agent
- LangChain 官方參考文件:SQL Agent Toolkit 安全提醒(最小權限、伺服器端限制):https://reference.langchain.com/python/langchain-community/agent_toolkits
- Spider 2.0 基準論文(企業級 Text-to-SQL 工作流程,arXiv):https://arxiv.org/abs/2411.07763
- BIRD 基準與企業 Text-to-SQL 經驗(史丹佛合作研究整理):https://www.ust.com/en/insights/text-to-sql-enterprise-natural-language-analytics
- 唯讀設計:讓 AI 探索資料庫而不承擔寫入風險:https://dev.to/vivekdraxlr/read-only-by-design-letting-ai-explore-your-database-without-the-risk-of-writes-2pmm
- 保護生產 SQL 資料庫免於 AI 查詢 Agent 風險(唯讀副本與確定性護欄):https://rietta.com/blog/ai-sql-database-data-protection-read-replica/

Uploaded Image Uploaded Image

沒有留言:

張貼留言