资讯详情

Nightingale AI Agent 查询 PostgreSQL 数据源实战指南:元数据 API、时序查询与只读安全机制

📅 2026/9/15 9:53:01 | 华诺云谱 👁 阅读
Nightingale AI Agent 查询 PostgreSQL 数据源实战指南:元数据 API、时序查询与只读安全机制
Nightingale AI Agent 查询 PostgreSQL 数据源实战指南元数据 API、时序查询与只读安全机制【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingaleNightingale夜莺监控平台内置了面向 AI Agent 的query-datasource技能其中pgsql是支撑 PostgreSQL 指标查询的核心插件类型。本文以 pgsql.md 为骨架结合 postgresql.go 等源码实现完整讲解如何通过 HTTP API 列出数据库/表/表结构、执行带时间变量的时序 SQL 查询并深入剖析只读校验与时间变量替换的底层原理帮助读者在夜莺平台上正确、安全地编写 PostgreSQL 查询。一、技能定位query-datasource 中的 pgsql 类型在夜莺的 AI Agent 技能体系中query-datasource技能用于从各种数据源查询监控指标、日志与时序数据。其技能描述文件 SKILL.md 中明确列出plugin_typepgsql查询语言SQL典型用途指标查询Metric queriesSKILL.md 将支持的数据源按plugin_type分为三类Prometheus 系的 PromQLprometheus、日志系的 ES DSL / LogQL / LogsQLelasticsearch、loki、opensearch、victorialogs以及 SQL 系的指标查询ck、mysql、pgsql、tdengine、doris。其中PostgreSQL 与 MySQL、ClickHouse、Doris 共享同一套元数据查询端点/api/n9e/db-databases、/api/n9e/db-tables、/api/n9e/db-desc-table这是理解 pgsql 用法的关键背景。在源码侧pgsql 插件通过datasource.RegisterDatasource(PostgreSQLType, new(PostgreSQL))注册PostgreSQLType pgsql见 datasource/postgresql/postgresql.go即 API 中cate字段的合法值之一。二、前置准备登录获取 Token 与查询数据源列表按 SKILL.md 规定的执行流程所有 pgsql 查询前必须先完成两步Step 1登录获取访问令牌POST /api/n9e/auth/login Content-Type: application/json Body: {username:username,password:password}从响应中提取dat.access_token后续所有请求携带Authorization: Bearer token。Step 2查询可用数据源确定 datasource_idPOST /api/n9e/datasource/list Authorization: Bearer token Content-Type: application/json Body: {}响应中的每个数据源包含id、name、plugin_type。只有plugin_type为pgsql的数据源才能使用本文的接口所有 pgsql 查询都需要datasource_id务必先通过该接口确认。三、元数据查询数据库列表、表列表与表结构SQL 系数据源含 pgsql共用三个元数据端点请求体统一使用{cate: pgsql, datasource_id: 1, query: [...]}结构。3.1 查询数据库列表POST /api/n9e/db-databases Authorization: Bearer token Content-Type: application/json Body: {cate: pgsql, datasource_id: 1, query: []}底层实现上router_datasource_db.go 通过dscache.DsCache.Get(f.Cate, f.DatasourceId)取出插件实例调用其ShowDatabases接口。pgsql 插件将该调用委托给连接层postgres.go实际执行SELECT datname FROM pg_database WHERE datistemplate false AND datname LIKE ?即排除模板库后返回全部数据库名。3.2 查询指定数据库下的表列表POST /api/n9e/db-tables Authorization: Bearer token Content-Type: application/json Body: {cate: pgsql, datasource_id: 1, query: [database_name]}query数组的第一个元素是数据库名字符串路由层只接受一个入参见 router_datasource_db.go。连接层执行的 SQL 为SELECT schemaname, tablename FROM pg_tables WHERE schemaname ! information_schema AND schemaname ! pg_catalog AND tablename LIKE ?返回结果会被 pgsql 插件加工为schema.table的格式如public.metrics因为 PostgreSQL 的表名需带 schema 前缀才有唯一语义见 postgresql.go。3.3 查询表结构POST /api/n9e/db-desc-table Authorization: Bearer token Content-Type: application/json Body: {cate: pgsql, datasource_id: 1, query: [{database: mydb, table: metrics}]}query数组的第一个元素是对象含database与table两个字段。table 可携带 schema如table: public.metrics插件内部会按.拆分 schema 与表名缺省 schema 时使用public见 postgresql.go 与 postgres.go。底层查询information_schema.columns返回列名、数据类型、是否可空、默认值等ColumnProperty信息可用于让 Agent 理解目标表的字段结构辅助生成正确的 SQL。四、时序查询POST /api/n9e/ds-query4.1 请求格式所有非 Prometheus 数据源含 pgsql共用统一时序查询端点POST /api/n9e/ds-query Authorization: Bearer token Content-Type: application/json请求体示例来自原文档{ cate: pgsql, datasource_id: 1, query: [ { sql: SELECT date_trunc(minute, created_at) AS ts, COUNT(*) AS value FROM events WHERE created_at to_timestamp($from) AND created_at to_timestamp($to) GROUP BY ts ORDER BY ts, keys: { valueKey: value, labelKey: , timeKey: ts } } ] }请求体结构对应源码中的QueryParammodels/ts.go字段类型说明catestring数据源类型此处固定为pgsqldatasource_idint64数据源 ID来自/api/n9e/datasource/listqueryarray查询对象数组可一次提交多条 SQL 并发执行4.2 单条查询参数QueryParampgsql 插件把query数组中的每个元素解码为查询参数见 postgresql.go字段类型必填说明sqlstring是SQL 查询语句支持$from、$to时间变量keys.valueKeystring否数值列名时序查询必填多列用空格分隔keys.labelKeystring否标签/分组列名多列用空格分隔keys.timeKeystring否时间列名其中keys结构定义在 datasource/datasource.go源码注释明确多个用空格分隔。4.3 底层执行链路/api/n9e/ds-query路由注册于 router.go处理器为Router.QueryDatarouter_query.go解析请求为models.QueryParam并做数据源权限校验CheckDsPerm分享 token 场景可跳过QueryDataConcurrently对query数组中的每条 SQL 启动 goroutine 并发查询router_query.gopgsql 插件QueryDatapostgresql.go完成 SQL 预处理后调用连接层QueryTimeseries执行查询结果按.Metric排序后统一包在{dat: data}结构中返回。值得注意的是QueryData中若 SQL 包含$__前缀宏如$__timeFilter会先经过macros.Macro宏替换同时若database未显式指定插件会用正则从from database.schema.table形式的 SQL 中解析数据库名并自动切换连接见 postgresql.go。连接层还会对database.schema.table形式的三段式表名自动补双引号dbname.scheme.table以兼容 PostgreSQL 大小写敏感标识符的语义。4.4 响应结构时序查询返回[]models.DataResp每个元素包含ref、metric由labelKey构成的标签与values时间戳-数值点序列SKILL.md 建议将结果以 Markdown 表格形式呈现给用户。五、常用 SQL 示例以下示例均来自原文档可直接套用需求SQL按分钟聚合计数SELECT date_trunc(minute, created_at) AS ts, COUNT(*) AS value FROM events WHERE created_at to_timestamp($from) AND created_at to_timestamp($to) GROUP BY ts ORDER BY ts按字段分组统计SELECT status, COUNT(*) AS value FROM events WHERE created_at to_timestamp($from) AND created_at to_timestamp($to) GROUP BY status计算分位数SELECT date_trunc(minute, created_at) AS ts, percentile_cont(0.95) WITHIN GROUP (ORDER BY response_time) AS value FROM requests WHERE created_at to_timestamp($from) AND created_at to_timestamp($to) GROUP BY ts ORDER BY ts补充要点分组统计示例需配合keys.labelKey status使用分组值会作为时序曲线的标签维度分位数示例展示了 PostgreSQL 窗口聚合函数percentile_cont在监控场景的典型用法如统计 95 分位响应时间若timeKey缺失pgsql 插件仍会返回数据但无法被正确组装为带时间轴的时序曲线因此时序查询务必同时给出valueKey与timeKey。六、注意事项与安全机制原文档列出三条注意事项这里结合源码做纵深展开6.1 只读约束Read-only禁止 CREATE、INSERT、UPDATE、DELETE、ALTER、DROP 等写操作。这不仅是文档约定更是服务端强制的安全边界。夜莺在 dskit/sqlbase/readonly.go 实现了ValidateReadOnly校验器起始关键字白名单仅允许SELECT、WITH、SHOW、DESC、DESCRIBE、EXPLAIN开头多语句拦截拒绝SELECT 1; DROP TABLE x这类堆叠语句写关键字全句扫描INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE|GRANT|REVOKE|...出现即拒绝写语句模式匹配拦截REPLACE INTO、LOAD DATA、MERGE INTO、COPY ... FROM/TO等复合写语句CTE 内嵌写拦截WITH t AS (DELETE FROM foo RETURNING *) ...这类以 WITH 开头但内部含写的语句会被全句扫描兜住SELECT ... INTO拦截该写法在 PG 系数据库是建表写操作靠写关键字扫描拦下可执行注释拦截/*!50000 INTO OUTFILE ... */这类 MySQL 系可执行注释同样被禁止。对应测试见 dskit/sqlbase/readonly_test.go覆盖了普通读查询放行与各种写绕过手法的拒绝场景。因此 Agent 编写 SQL 时应严格遵循只读原则所有查询以SELECT开头。6.2 时间变量$from和$to是 Unix 时间戳秒必须用to_timestamp()转换。夜莺在执行查询前会自动将$from/$to替换为查询时间范围对应的 Unix 秒级时间戳SKILL.md 第 3 条注意事项确认了系统自动替换。由于 PostgreSQL 的时间列通常是timestamp类型直接与秒级整数比较会类型不匹配因此文档中的示例统一使用to_timestamp($from)/to_timestamp($to)将时间戳转换为timestamptz。区间建议采用左闭右开写法 $from AND $to避免相邻桶数据重复。6.3 时间聚合用date_trunc(minute, col)做时间分桶。date_trunc是 PostgreSQL 内置的日期截断函数minute粒度可根据需求替换为second、hour、day等。GROUP BY ts配合ORDER BY ts保证输出按时间有序与timeKey指定的时间列一一对应。七、总结在夜莺 AI Agent 体系中pgsql数据源查询的完整链路为登录获取 Token →datasource/list确认数据源 ID → 用db-databases/db-tables/db-desc-table探查库表结构 → 用ds-query提交带$from/$to与keys的时序 SQL → 以表格形式返回结果。整个过程中服务端通过ValidateReadOnly严格保证只读、通过连接层自动处理数据库切换与标识符引用Agent 只需关注 SQL 本身的正确性与时间变量转换。想深入了解实现细节的读者可继续阅读 datasource/postgresql/postgresql.go、dskit/postgres/postgres.go 以及 center/router/router_query.go。【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。