Agent 查数据库先问口径再动手:NVIDIA 开源语义层 Auto Ontology,连续两天登顶 GitHub Python 趋势榜

11 月 5 日和 6 日,GitHub 趋势榜 Python 分类的第一名被同一个新项目连续占住:NVIDIA 开源的 auto-ontology,单日进账约 2000 星。它不是又一个向量数据库,也不是又一套 RAG 脚手架,官方 README 给它的定义只有一句------为企业数据构建语义化的图状推理层,让 Agent 在写 SQL 之前先搞清楚每个业务词在这家公司到底指什么。这个方向为什么突然被星标砸中?因为 Agent 做数据分析的最大事故从来不是查得慢,而是口径错了还答得理直气壮。

它解决的不是检索问题,是口径问题

用过 text-to-SQL 演示的人都会有一种错觉:把数据库 schema 贴给模型,问一句自然语言,SQL 就出来了,很漂亮。但只要你把它接进真实的公司数据,同一个问题「上季度营收是多少」很可能在三个系统里得到三个数字,而且每一个数字都有完整的 SQL 作证。

根因不在模型不够聪明,在于模型拿到的是表名和字段名,不是业务定义。营收到底是 extendedprice 直接求和,还是要扣掉退货,还是只统计已付款订单?这些定义散落在 wiki、老员工的记忆里和历代报表的注释里,没有任何一份 schema 会写出来。模型不知道,就只能猜,猜完还显得很有把握。

目前大家应对这件事的路线大体有三条:直接 NL2SQL 拼提示词、用 RAG 把 schema 和文档切片喂给模型、或者建一层语义层统一定义。三条路的实际差别可以摆在一起看。

路线 口径一致性 回答可解释性 答不了时会不会拒答 主要代价
直接 NL2SQL 无保障,每次现场编 只有 SQL 文本 不会,硬答 提示词反复调
RAG 检索 schema 与文档 取决于文档质量 弱,靠拼上下文 不会 文档维护繁重
语义层路线 认证后统一 SQL 与血缘一起返回 先验 answerability 建层加人工认证

auto-ontology 走第三条。值得说清楚的是它并不打算替代企业已经有的语义模型,官方措辞是 complement,从现有元数据自动生成本体草稿,把人工认证过的定义通过 MCP、CLI 和 API 暴露给任意 agent harness。定位是补层,不是推倒重来。

本体里只装三类东西

这个项目的本体设计得相当克制,全部定义只有三类。第一类是 term,也就是业务术语,比如 Customer、Invoice Line,每个 term 带一段自然语言描述、一组同义词,以及它映射到哪些表的哪些列。Agent 听到「发票行」和「invoice line」能认出是同一个东西,靠的就是这层同义词和映射。

第二类是 SQL attribute,挂在 term 下面的、经过人工审核的 SQL 表达式,比如毛利率怎么算、滚动三十天总额怎么算。Agent 回答时复用这些表达式,而不是每次现场新写一段,这样同一个指标在任何一次回答里都是同一套算法,口径一致性就是从这里来的。

第三类是 relationship,描述表与表怎么 join,包括桥接表。它不完全依赖外键声明,还会从数据内容本身推断关系,这对那些年久失修、外键残缺的老库特别重要,因为很多真实系统的关联关系从来就没在 DDL 里声明过。

给一个规模直觉:官方用微软的示例销售库 Wide World Importers 跑了一次完整编译,产出三十一个 term。所有定义落在 Postgres 里,对应的 embedding 存在 pgvector 里供检索用,Web UI 里还有一张可点击探索的语义图,选中 Order 能看到它的描述、关联术语、映射列和 SQL attribute。

三类定义在一次提问里是同时工作的:问题里的业务词先靠 term 的同义词表收敛到唯一概念,指标算法靠 SQL attribute 直接取认证过的版本,表与表之间的路由靠 relationship 给出 join 路径。embedding 只负责把候选项捞回来,真正决定答案长什么样的是认证过的定义本身。这个分工很关键:检索是概率性的,定义是确定性的,把确定性的部分从模型手里拿走,幻觉的空间就被压缩到只剩意图理解这一小段,「为什么这样算」也变成可以点开检查的东西,而不是埋在生成概率里。

生成、认证、回答三段流水线

auto-ontology 的工作流分成三个阶段,理解这三段就理解了整个项目。生成阶段由 ingestion 服务完成,动作有四步:读取数据源,把 schema、列的统计画像和采样值抽进 catalog;逐表命名实体并把 term 映射到列;推断表间 join 和桥接表,同时从查询历史里建议候选 SQL attribute;最后把 term、relationship、SQL attribute 写进 Postgres,embedding 写进 pgvector。

认证阶段是人的工作,也是整个设计里最不妥协的一环。机器生成的只是草稿,人用真实问题在 Chat 界面里测试,或者通过 MCP 调 check_answerable 和 ask_question 来测,发现 term 描述不准、SQL attribute 算错,就在 UI 或 API 里修,修到对了就打上认证标记。没认证的草稿,Agent 用起来会打折扣。

回答阶段是 Agent 的运行时:先对问题做意图分类和实体抽取,再用 embedding 检索候选的 term、列和 SQL attribute,然后拿这些候选项对照认证过的定义和血缘做校验,通过之后才生成并执行 SQL,收尾时把答案连同 SQL 和产生它的步骤一起返回。注意校验在生成之前,顺序不能反。这五步每步都可以单独观测,出问题时能定位到具体环节,而不是面对一个黑箱干瞪眼。「这题能不能答」在这里是一个显式判断,不是等 SQL 生成失败才被动的报错。

还有一个学习回路把整条链路闭环:被认证过的修正和实际使用情况会折回本体,共享上下文随着每一次提问变好。这意味着本体不是一次性交付物,而是越用越准的资产,前期认证投入决定后期回答质量的上限。

一次真实问答拆开看

官方 quickstart 里给了一个完整例子,值得逐步拆开。底层数据是 Wide World Importers 销售库,提问是:USB food flash drive - sushi roll 这个商品,2015 年 6 月在宾夕法尼亚州的营收是多少。

返回结果长这样:答案是 588.80 美元,来自三条发票行;同时附上生成的 SQL 和推理步骤。SQL 是真实的五表关联:

sql 复制代码
SELECT SUM(il.extendedprice) AS revenue, COUNT(*) AS invoice_lines
FROM sales.invoicelines il
JOIN sales.invoices i             ON il.invoiceid = i.invoiceid
JOIN warehouse.stockitems si      ON il.stockitemid = si.stockitemid
JOIN sales.customers c            ON i.customerid = c.customerid
JOIN application.cities ct        ON c.deliverycityid = ct.cityid
JOIN application.stateprovinces sp ON ct.stateprovinceid = sp.stateprovinceid
WHERE si.stockitemname = 'USB food flash drive - sushi roll'
  AND sp.stateprovincename = 'Pennsylvania'
  AND i.invoicedate >= '2015-06-01' AND i.invoicedate < '2015-07-01'

步骤里写着它怎么走的:revenue 被解析到 Invoice Line 这个 term 下认证过的 SQL attribute,商品和州被解析到对应 term,然后沿 relationship 走出发票行到发票到客户到城市到州的 join 链,过滤值先对着数据校验过,然后才执行。每一步都留下了血缘,可以拿回去对源。

比正例更值钱的是官方给的反例。这个库里根本没有广告投放数据,所以当你问「这个商品的广告支出回报率是多少」时,check_answerable 先验返回 coverage 0.5,没有任何 term 覆盖「广告支出」,Agent 会直接明说算不了,并反问你是要看六月营收,还是广告数据在另一个需要接入的源里。它不会编一个数给你,这就是口径层和闷头生成 SQL 的分水岭。

把正反两个例子放在一起看,auto-ontology 真正解决的是信任问题而不是速度问题。一个能随时给出血缘、并且敢于说「这题数据不够」的系统,业务方才敢把它接进正式报表链路。README 里有句话说得很直白:营收指标回答得再快,数字是错的就一文不值,可靠性是 agentic analytics 的入场券。反过来看市面上大多数 NL2SQL 演示,它们没有 coverage 这个概念,任何问题都必定产出一段 SQL,因为流水线里根本没有「不答」这个出口。把拒答做成一等公民,是这套系统和演示级方案最本质的差别。从工程角度看,answerability 先验还能省钱:不该答的问题在模型生成 SQL 之前就被拦下,token 成本和数据库的无效查询一起省掉。

部署形态与组件清单

这是一个全栈项目,五个组件各司其职。前端是 Next.js 16,底下是 React 19、TypeScript 和 Tailwind CSS 4,认证用 Better Auth,ORM 用 Prisma,跑在 3000 端口。后端是 FastAPI 加 LangChain,负责 Chat、NL-to-SQL、catalog 和数据源 API,跑在 3001。独立的 ingestion worker 跑在 3002,负责灌表格数据和写 embedding。

组件 技术栈 职责 默认端口
前端 Next.js 16、React 19、Better Auth、Prisma Web UI、认证、API 网关 3000
后端 FastAPI、LangChain Chat 与 NL-to-SQL、catalog、数据源 API 3001
ingestion worker FastAPI 灌入表格数据、写 embedding 3002
Postgres 加 pgvector 关系库 应用元数据、catalog、本体、向量 5432
HashiCorp Vault 可选 连接凭据的安全存储 无

模型侧全部通过环境变量 triplet 配置,每个角色一组 ENDPOINT、API_KEY、MODEL。默认指向 NVIDIA 托管的 NIM 目录 integrate.api.nvidia.com,LLM 用 nemotron-3.5-lightning-30b-a3b,embedding 用 nemotron-3-embed-1b,rerank 用 llama-nemotron-rerank-vl-1b-v2。REASONING、NON_REASONING、EMBED、RERANK 四个角色可以只覆盖个别字段,没设的部分回落到 DEFAULT_MODELS,再老的 NVIDIA_API_KEY 也兼容。

官方自己点名了一个容易踩的坑:EMBED 模型在 ingest 和 query 两侧必须保持同一个。灌数据时用了一个 embedding 模型,查询时换成另一个,向量空间对不上,检索质量直接塌掉,而且这种坏法不报错,只是答案悄悄变差。

部署给两条路,本地用 Docker Compose,要求是 Compose v2 加 uv;生产用 Helm chart 上 Kubernetes。还有一个文档里明确记录的小坑:UI 重启后如果左边导航不见了,是浏览器拿着过期的会话 cookie,清掉 localhost:3000 的站点数据重新登录就好。

这个组件拆分方式本身就值得抄作业:认证和 API 网关收在前端层,模型编排收在 FastAPI 层,重负载的灌库和 embedding 写入隔离在独立 worker 里,聊天流量和灌库流量互不阻塞。各数据源的连接凭据不进环境变量文件,交给可选的 Vault 托管,轮换和审计都有现成机制。对一个要接生产库的系统来说,这些不是锦上添花,而是能不能过安全评审的硬条件。五个组件全是常见技术栈,没有自研黑盒,二次开发和线上排查的门槛都压得很低,团队里普通后端就能接住。

MCP 接入:server 手里没有任何凭据

auto-ontology 的 MCP server 放在仓库的 mcp 子目录,是个独立组件,用 uvx 直接从 GitHub 子目录安装,不用 clone 主仓。它的架构非常克制:本身只是部署实例公网 API 的一个 HTTP client,向下转发到 Next.js 层,再进 FastAPI 和 Postgres。

设计里最该细看的是凭据策略。这个 server 不持有数据库凭据,不持有模型配置,也不持有任何自己的凭据。认证和权限校验本来就活在 Next.js 那层,server 直接继承,什么都不重新实现。官方对此的概括是:一个 session 能做的,恰好就是登录的那个人能做的,viewer 角色的登录者通过 Agent 也只能拿到 viewer 该看的答案。

OAuth 流程也省了常规麻烦。Auto-Ontology 自己充当授权服务器,MCP server 上没有 client id、client secret 和 redirect URI 需要配置,客户端会自己向 Auto-Ontology 自动注册。注册和授权记录存在 Auto-Ontology 的数据库里,重启不会让任何人掉登录;权限在每次调用时按账号实时取,所以改角色、封禁用户、删除授权全部立即生效,不存在 token 快照里的过期权限。

客户端接入只需要一行 URL,注意 /mcp 后缀是 endpoint 而不是服务根路径,改完配置要重启客户端,因为多数客户端只在启动时读 MCP 配置。Cursor 里会把它显示为需要登录的服务。

json 复制代码
{
  "mcpServers": {
    "auto-ontology": {
      "url": "https://auto-ontology-mcp.example/mcp"
    }
  }
}

这个设计对正在搭内部 Agent 平台的团队有直接参考价值:把权限收敛到业务系统既有的认证层,让 Agent 基础设施变成无凭据的薄转发层,审计面会小很多,出事时的爆炸半径也小很多,安全评审时也少一份要单独解释的组件。

上手路径与几条边界

想本地跑起来,路径是固定的:clone 仓库后复制 .env.example 为 .env,填好从 build.nvidia.com 申请的 nvapi key、AUTH_SECRET 和若干密码,先起 Postgres,再用姊妹仓 auto-ontology-eval 里的 seed 脚本灌入 Wide World Importers 示例库,然后整体构建启动。核心命令如下:

bash 复制代码
git clone https://github.com/NVIDIA/auto-ontology.git && cd auto-ontology
cp .env.example .env
docker compose up -d --wait postgres
docker compose up -d --build

起来之后打开 localhost:3000,用 .env 里设置的管理员账号登录,到 Settings 的 Semantic Compilation 把它打开,ingestion 会在启动时跑,编译完成后界面会报告 ready,然后就能在 Chat 里提问。想认真评估准确率的,可以用官方的 ontology-sql-eval 仓库跑 BIRD 这类 text-to-SQL 基准。

接入自己的库时,建议的顺序是先把只读副本接进来跑生成,让三十来个 term 的草稿先出来,再安排熟悉业务的人做认证,认证一批上线一批,不要等全部认证完才让 Agent 用。学习回路会把认证修正折回本体,早期用得越多,后期答得越稳。如果第一批 term 的命名和你们内部口径对不上,优先改描述和同义词,而不是急着改 SQL attribute,名字对了,后面的指标才有地方挂。

边界也要说清楚。第一条是项目治理:Apache 2.0 开源,但官方明确目前不接受外部 PR,只收 issue,仓库 2026 年 4 月底才创建,到现在零个 release、一个 tag,这是典型的早期形态,生产采用要把维护风险算进去。

第二条是模型耦合:整条链路默认依赖 NVIDIA NIM,要么用托管目录要么自托管 NIM,不是模型无关的设计,切换别家模型需要自己动手改配置层。第三条是最根本的:答案质量的上限由你在本体认证上的投入决定,机器生成草稿而人不认证,等于把幻觉制度化。语义层本身不是新发明,但把它做成开源、自带 MCP、两天冲上趋势榜,说明 Agent 工程的重点正在从「让模型敢答」转向「让系统知道什么时候不该答」。

相关推荐
段一凡-华北理工大学9 小时前
工业智能体:从Codex/Claude到项目实战~系列文章05:从“AI助手“到“工业智能体“:能力跃迁与落地范式
人工智能·python·claude·codex·工业智能体·高炉炼铁智能化
岁月宁静10 小时前
什么是 Agent:从"会聊天"到"会做事"
人工智能·python
岁月宁静11 小时前
AI 应用开发工程师简历怎么写:HR 初筛、技术复筛、面试追问,三道关卡各看什么?
人工智能·python·面试
老金带你玩AI11 小时前
全球股市跌麻了:AI在进化,牛马在买单
人工智能
我qq不是4515165213 小时前
WorkBuddy下载体验
人工智能·经验分享·ai·workbuddy
IT_陈寒14 小时前
Redis雪崩把我坑惨了,这是5年经验的教训
前端·人工智能·后端
心祭丫丫14 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
高晶14 小时前
Android 任务管理器开发实战指南
程序员