SQL Lab · Execute Gate + Agent Diagnose

SQL 执行门禁与 Agent 诊断方案

用户执行 SQL 时,先经 Druid SQL Parser 本地解析与权限判定,再真正打库; 后台在解析通过后会按方言改写 SQL(如补 LIMIT)再打库,需区分 submittedSql 与 executedSql。 本地解析失败与可诊断执行失败走诊断 SSE;Agent 对用户无多轮对话。

30 秒看懂整体

提交 SQL 执行接口 Parser 解析 方言改写 权限判定 执行 executedSql 前端分流 诊断 SSE(可选)

双 SQL:sql=用户提交, executedSql=改写后实际打库(如补 LIMIT)。 PARSE_ERROR / 可诊断 EXEC_ERROR 走诊断; PERMISSION_DENIED 直接展示。

STEP 01

有哪些参与方

前端、执行网关、本地门禁(解析 + 权限)、数据库、诊断 Agent。先分清「谁拦截、谁执行、谁建议」。

架构关系图 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
BOUNDARY

职责边界对照

用一张表看清「谁负责拦截、谁真正打库、谁给建议」,避免把语法校验、权限与 Agent 混在一起。

参与方 负责什么 不负责什么 关键产出
前端 提交 SQL;按状态分流展示结果 / 错误 / Agent 面板 本地权限判定、直接连库 UI 展示;诊断请求组装
执行接口 编排解析 → 改写 → 鉴权 → 执行;回传双 SQL 生成修复 SQL、解释业务语义 status + payload
Druid Parser 本地语法解析,产出 Parsed SQL Object 权限判断、真正执行 AST / 操作对象结构
权限判定 抽取表/列/操作,与用户权限比对 语法纠错、SQL 改写建议 ALLOW / DENY + 明细
诊断 Agent 单次诊断;仅用 Builtin(校验 + 只读元数据) 绕过门禁、多轮追问、执行写 SQL 问题说明 + 修复 SQL
STEP 02

SQL 执行主流程

从提交到前端分流:解析 → 方言改写 → 权限 → 用 executedSql 打库。解析/执行失败可诊断;权限失败直接展示。

主流程图 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
STEP 03 · SUBFLOW

权限判定子流程

这是主流程中最复杂的门禁阶段:从解析对象抽取出「对什么对象做了什么操作」,再逐条与用户权限匹配。

权限子流程 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
STEP 04 · SUBFLOW

Agent 诊断子流程

当本地解析失败,或执行失败且前端判定为可诊断错误时,把错误信息与 SQL 上下文喂给 Agent,产出问题说明、建议与修正 SQL。

Agent 诊断子流程 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移

建议前端提供「一键填入修正 SQL」;再次执行仍走完整主流程(解析 → 权限 → 执行),保证安全边界不被 Agent 绕过。

STEP 06

一次执行的消息时序

用时序图核对「谁在什么时候跟谁说话」,以及解析失败、权限失败、执行失败与 Agent 介入时机。

时序图 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
STEP 05 · AGENT

Agent 如何设计(单次诊断)

对用户一次请求一次响应;内部允许工具循环。能力为 Builtin 内置工具(语法校验 + 只读元数据)。

能力分层 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
单次诊断内部流程 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
PROMPT

提示词工程

System 定角色与硬约束;User 模板注入本次错误上下文。完整文件见 prompts/

System Prompt 下载
加载中…
User Prompt 模板 下载
加载中…

关键输出契约:errorCategoryproblemSummaryrootCausesuggestionsfixedSqlconfidenceassumptionsusedCapabilities。接口完整交互见下方「接口格式」或 docs/io-contract.md

CAPABILITY

能力层详解

诊断 Agent 使用本系统 Builtin 内置工具: 语法校验与只读元数据查询;修复要点写入 System Prompt。

Builtin 内置工具

全部走当前用户权限模型;只读元数据,不执行业务写 SQL。

下载完整目录

入口预处理(非工具)

  • /sql/diagnose/stream 入口根据 status/code/message 做错误归类,注入 Prompt。
  • 不注册为 Agent 可调用工具,避免「为调用而调用」。

工具清单(输入 → 输出)

工具名 作用 输入 输出
validate_sql_syntax Druid Parser 本地再解析(收口) sql, dialect ok / parseError
get_table_schema 只读表结构(列/类型/键) table, connectionId schema(权限内)
list_tables 只读可见表列表 connectionId, keyword? tables[]

硬约束:与执行门禁同源 Parser、同源权限; Agent「认为可解析」与「再次提交可过解析」一致;元数据不泄露无权对象。

推荐调用策略

最短路径;最后一律 validate_sql_syntax 收口。format/diff 交给前端。

PARSE_ERROR(语法)
预处理归类 提示词内语法要点 生成 fixedSql validate_sql_syntax
EXEC_ERROR · 对象 / 语义类(diagnosable)
预处理归类 get_table_schema / list_tables 生成 fixedSql validate_sql_syntax
PERMISSION_DENIED / 不可诊断 EXEC_ERROR
不进入 Agent 前端直接展示错误
能力调用时序 · Mermaid
100%
下载 .mmd
渲染中…
点击放大 · 滚轮缩放 · 拖拽平移
CONTRACT

前端状态约定

执行接口用统一 status 驱动 UI;可诊断错误再走诊断 SSE。

SUCCESS 展示结果

执行成功。展示 result。不调用诊断。

PARSE_ERROR 诊断 SSE

diagnosable=true。把错误上下文交给 POST /sql/diagnose/stream

PERMISSION_DENIED 直接报错

展示 permissionGaps。不打库、不调诊断。

EXEC_ERROR 条件诊断

diagnosable=true 走 SSE;否则只展示 error

API

两个接口的交互格式

POST /sql/execute:解析 → 改写 → 鉴权 → 打库; POST /sql/diagnose/stream:SSE + 终态 result(含双 SQL 上下文)。 完整说明见 docs/io-contract.md

1. 执行接口 POST /sql/execute

同步 JSON。解析 → 方言改写 → 权限 → 用 executedSql 打库。

下载完整契约

双 SQL

  • sql:用户提交(编辑器内容)
  • executedSql:改写后实际打库;PARSE_ERROR 时为 null
  • rewrite:改写规则说明(如 default_select_limit)

请求

POST /sql/execute
Content-Type: application/json

{
  "sql": "SELECT * FROM user",
  "dialect": "mysql",
  "connectionId": "lab-conn-001"
}

SUCCESS 响应(含改写)

{
  "requestId": "exec-7f3a",
  "status": "SUCCESS",
  "sql": "SELECT * FROM user",
  "executedSql": "SELECT * FROM user LIMIT 10",
  "rewrite": {
    "applied": true,
    "rules": ["default_select_limit"],
    "detail": "未指定 LIMIT,按实验室策略追加 LIMIT 10"
  },
  "diagnosable": false,
  "parsedSummary": { "action": "SELECT", "tables": ["user"], "columns": ["*"] },
  "result": { "columns": ["id", "name"], "rows": [[1, "alice"]], "rowCount": 1 },
  "error": null,
  "permissionGaps": null
}

前端建议展示「实际执行 SQL」。诊断时务必带上 sql + executedSql + rewrite; Agent 的 fixedSql 写回提交态(不含自动 LIMIT)。

2. 诊断接口 POST /sql/diagnose/stream(SSE)

过程用事件;终态用一条完整 event: result,方便前端固定面板渲染。

请求

POST /sql/diagnose/stream
Content-Type: application/json
Accept: text/event-stream

{
  "requestId": "exec-7f3d",
  "status": "EXEC_ERROR",
  "sql": "SELECT nam FROM user",
  "executedSql": "SELECT nam FROM user LIMIT 10",
  "rewrite": {
    "applied": true,
    "rules": ["default_select_limit"],
    "detail": "未指定 LIMIT,按实验室策略追加 LIMIT 10"
  },
  "dialect": "mysql",
  "connectionId": "lab-conn-001",
  "diagnosable": true,
  "error": {
    "code": "42S22",
    "message": "Unknown column 'nam' in 'field list'"
  }
}

SSE 事件

event用途前端怎么用
meta流开始记录 requestId
phase阶段:classify / tool / generate / validate进度条
toolBuiltin 调用 start/end工具日志
message可选文本增量过程说明
result完整诊断 JSON唯一结构化面板数据源
error失败错误态(无残缺 result)
done流结束关连接 / 结束 loading

成功流(节选)

event: meta
data: {"requestId":"diag-9c01","status":"PARSE_ERROR"}

event: phase
data: {"phase":"generate"}

event: tool
data: {"name":"validate_sql_syntax","state":"end","ok":true}

event: result
data: {"errorCategory":"SYNTAX","problemSummary":"SELECT 关键字拼写错误…","rootCause":"…","suggestions":["将 SELEC 改为 SELECT"],"fixedSql":"SELECT id FROM users","confidence":0.92,"assumptions":[],"usedCapabilities":["builtin:validate_sql_syntax"]}

event: done
data: {"ok":true}

result 固定字段

{
  "errorCategory": "SYNTAX",
  "problemSummary": "…",
  "rootCause": "…",
  "suggestions": ["…"],
  "fixedSql": "SELECT id FROM users",
  "confidence": 0.92,
  "assumptions": [],
  "usedCapabilities": ["builtin:validate_sql_syntax"]
}

原则:过程可流式;终态 JSON 必须完整。fixedSql 为提交态,再执行仍会改写。不要把自动 LIMIT 当作用户错误。