十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

融合RAG与Text-to-SQL:Digital Librarian AI Agent企业知识库实践

融合RAG与Text-to-SQL:Digital Librarian AI Agent企业知识库实践 “你问大模型‘上季度华东区卖了多少’它可能流畅地给出一个数字但那个数字很有可能是编的你再问它‘公司对加班有什么制度文档’它能答出来一段但更可能是从网上拼来的。为什么因为大模型并不知道你的真实数据存放在哪里。IBM 在讨论 AI Agent 落地时提出了一个非常形象的比喻——Digital Librarian数字图书馆员。这个角色要做的事情和真正的图书馆员几乎一样先理解读者的问题再去目录中查找资料在哪个区域走到对应书架把书取下来翻到关键章节最后把整理好的答案交给读者。只不过数字图书馆员手里的“书”是企业数据库里的表格、文档知识库里的文本切片以及那些散落在系统各处的元数据。”这篇文章不打算停留在概念层面。我会先拆解 Digital Librarian AI Agent 的架构逻辑和它解决的问题然后给出一套完整可运行的 Python 最小实现用 SQLite 充当结构化数据源用一个迷你向量存储充当文档知识库让 Agent 根据用户问题自动判断该查 SQL、该查向量库、还是两边都查最后汇总成自然语言答案。读完你会发现只有 RAG 不够只有 Text-to-SQL 也不够真正值钱的是把两者统一起来的“图书馆员”调度层。如果你正在做企业知识库、智能问答、数据中台或者 Agent 应用这篇文章值得收藏它会帮你少走很多弯路。1. Digital Librarian AI Agent 到底解决什么问题1.1 企业落地 AI 的真实瓶颈是“数据找不到”先说一个大背景。很多团队做 AI 应用最先想到的是把 PDF、Word、Wiki 扔进向量数据库然后接一个大模型做 RAG。跑通 demo 很快一上生产就发现效果不稳定。原因很常见企业里除了文档还有大量结构化数据销量、订单、员工信息、库存、工单、财务流水这些数据普遍躺在关系型数据库里。大模型既不知道表结构也没有能力直接读库更不会把“上半年退款率”翻译成一条正确的 SQL。于是企业里出现了一种割裂状态文档类问题交给 RAG数据类问题交给 BI 报表两类系统各自为政。用户问一句“为什么华东区这个季度业绩下滑客户反馈里有什么线索”系统就懵了。前半句要查 SQL 销售明细后半句要检索文档和客户反馈向量这不是单个模型的“知识”问题而是数据访问路径的设计问题。1.2 数字图书馆员是一个“调度角色”不只是一个模型Digital Librarian 的核心判断是大模型不需要记住所有数据它只需要知道“数据在哪里”和“怎么取”。这就像图书馆员不必背下每本书的内容但必须知道分类号、馆藏位置和借阅流程。AI Agent 也一样它应该具备三个能力第一理解用户意图判断问题背后涉及的是一张表、一篇文档还是两者都要。第二访问数据资产目录知道有哪些表、哪些字段、哪些知识库集合、它们之间什么关系。第三调用工具完成实际检索SQL 查询、向量检索、API 调用都属于这一类检索之后再做归纳总结。IBM 用 Digital Librarian 这个名字点出的关键是企业真正需要的不是一个“更聪明的模型”而是一个“更聪明的数据导航系统”。模型负责读、写、总结Agent 框架负责规划路径、调用工具、校验结果。这条思路对齐了当前 AI Agent 的主流方法论把 LLM 当作大脑把外部工具和数据源当作手脚。1.3 它和传统 RAG、Text-to-SQL 的差异传统 RAG 做的事情是“找相似段落”适合开放性问题比如“介绍一下某某项目的背景”。Text-to-SQL 做的事情是“把自然语言翻译成 SQL”适合精确计算问题比如“某部门平均薪资是多少”。但现实问题经常是混合的。Digital Librarian 可以理解为“RAG Text-to-SQL 路由规划”的组合体。它不是用一个 SQL 生成模型包打天下也不指望向量检索回答统计问题而是先用路由层判断问题类型再交给正确的工具最后统一汇总。这也是我在后续代码里要重点演示的部分。2. SQL 与向量数据库两种数据世界的分工与融合2.1 两类数据源的“不对称”特征SQL 数据库和向量数据库不是替代关系它们解决的是不同性质的问题。SQL 数据库擅长存储强结构、强关系的数据比如订单表、员工表、库存表。每条记录有明确字段可以用精确条件过滤可以用 GROUP BY 做聚合可以用 JOIN 连接多张表。它的特点是确定性高同一个查询只要数据不变结果一定不变。向量数据库则擅长存储非结构化数据比如文档段落、工单描述、客户反馈、代码片段。它把文本转换成高维向量用余弦相似度或内积距离衡量语义相近程度。它的特点是模糊匹配能力强容忍同义改写适合“找内容相似的东西”这种开放场景。难点在于用户在提问时不会区分结构化还是非结构化。你不能要求用户说“请帮我写一条 SQL 查销售额”用户只会说“最近业绩怎么样”。而“最近业绩怎么样”这个问题的答案可能来自 SQL 销售表也可能来自销售负责人的月度总结文档更可能两者都要看。2.2 两类数据库能力对比对比维度SQL 数据库向量数据库数据形式结构化表/行/列文本切片向量化典型操作SELECT、JOIN、GROUP BY、聚合相似度检索、Top-K 召回擅长问题“华东区 Q4 销售额是多少”“哪些员工反馈提到了加班”结果确定性高可复现概率性依赖模型和切分主要风险表结构不熟、SQL 写错召回不准、语义偏移典型代表MySQL、PostgreSQL、SQLite、SQL ServerMilvus、Chroma、Pinecone、Weaviate从这张表能看出SQL 和向量数据库各有不可替代的能力。一个合格的 Digital Librarian必须能够在两者之间自由切换并且知道什么时候该一起用。2.3 连接的价值既能回答“是多少”又能回答“是什么”“是多少”和“是什么”是两种认知模式。前者需要精确计算比如库存量、退款率、工资总额后者需要语义理解比如制度文档的核心观点、客户反馈的共性问题。过去这两个问题要分别去 BI 系统和知识库系统里找答案现在通过 Agent 可以把两次检索变成一个问答流程。更重要的是这种连接能把因果关系串起来。比如销售数据异常下滑SQL 告诉你下滑发生在哪个区域向量检索告诉你该区域客户反馈里集中出现了“物流慢”“质量瑕疵”等关键词。两个结果拼在一起决策者得到的不再是一个数字或一段文本而是一条可以继续追问的线索链。这就是 Digital Librarian 连接的真正价值。3. Digital Librarian AI Agent 的核心架构3.1 四个核心模块要理解 Digital Librarian不需要一开始就陷入复杂的 Agent 框架可以先把它拆成四个模块。第一个是意图与路由模块。它接收用户问题输出“本次任务需要访问哪类数据源”。路由结果可以只有三种SQL、VECTOR、BOTH。意图判断可以用 LLM也可以用轻量规则或小分类模型关键是速度和准确率的平衡。第二个是数据资产目录模块。它记录企业有哪些表、每个表有哪些字段、字段含义是什么、文档切片存在哪个集合、集合的元数据怎么组织。LLM 在做工具调用时需要把这份目录作为上下文否则它不知道有哪些表可用。第三个是工具执行模块。它封装真实的 SQL 连接、向量检索、HTTP 请求等能力让 Agent 可以安全地调用底层数据源。工具层要做参数校验、超时控制、结果截断。第四个是答案生成模块。它把 SQL 查询结果、向量召回片段、原始问题组装成提示词交给 LLM 生成最终回答。必要时还要标注信息来源防止用户把 Agent 的总结误当成数据库中的原始事实。3.2 查询路由是灵魂如果你只能记住一个设计要点那就是查询路由。很多 Agent 项目最后效果差不是因为模型不够聪明而是因为路由做得很粗糙把所有问题都丢进向量库或者把所有问题都尝试转成 SQL。好的路由策略通常有三个层级。第一层判断是否需要实时数据如果用户问的是知识型问题且知识库已经覆盖则直接走向量检索。第二层判断是否需要计算与聚合如果涉及指标、汇总、比较则走 SQL。第三层判断是否属于复合问题如果一条问题里既包含事实查询又包含指标计算则需要同时执行两类工具然后合并结果。我这里说的“路由”不一定是硬编码规则。实践中完全可以让 LLM 根据工具描述自行选择函数调用这也正是主流 Agent 框架的做法。但底层思路是一致的先在思维层面把问题归类再去调用对应工具。3.3 与 RAG、Text-to-SQL 的关系总结RAG 负责把非结构化文本变成可检索的知识Text-to-SQL 负责把自然语言变成可执行的结构化查询Digital Librarian Agent 则把它们组合成一个完整问答系统。如果把它们比作一个团队RAG 是资料员Text-to-SQL 是数据分析师Digital Librarian 是带队的组长。组长不一定要亲自写 SQL但必须知道什么时候该让谁上场。接下来进入可操作的部分我用一个最小实现来演示这套架构。4. 环境准备与数据集设计4.1 运行环境说明本文示例使用 Python 3.10 及以上版本核心依赖使用标准库 sqlite3不依赖第三方数据库服务。向量存储部分我会自己写一个极简实现用于教学演示生产环境应替换为 Milvus、Chroma、Weaviate 等真实向量数据库。额外说明真实项目中的文本向量化建议使用 bge-m3、text-embedding-3-small 等嵌入模型本文为了不引入过重依赖会在代码里用一个哈希词袋策略生成伪向量目的是演示检索链路而不是证明某种向量化方法是有效的。依赖项版本说明Python3.10SQLitePython 内置numpy可选用于余弦计算也可用纯 Python 替代openai仅在进阶 LLM 路由示例中使用可按需安装4.2 SQLite 建表和构造数据先创建一张员工表、一张销售表写入少量测试数据。实际项目里表会更多更复杂但演示用这个规模足够了。-- 文件路径data/schema.sql CREATE TABLE employees ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, department TEXT NOT NULL, salary REAL, hire_date TEXT ); CREATE TABLE sales ( id INTEGER PRIMARY KEY, product TEXT NOT NULL, region TEXT NOT NULL, amount REAL, sale_date TEXT ); INSERT INTO employees (name, department, salary, hire_date) VALUES (张三, 研发部, 25000, 2021-03-15), (李四, 市场部, 18000, 2020-07-01), (王五, 研发部, 28000, 2022-11-20), (赵六, 市场部, 16000, 2023-02-10); INSERT INTO sales (product, region, amount, sale_date) VALUES (AI平台, 华东, 120000, 2024-10-15), (数据服务, 华北, 80000, 2024-11-02), (AI平台, 华南, 95000, 2024-11-20), (数据服务, 华东, 65000, 2024-12-05), (AI平台, 华北, 140000, 2024-12-18);在命令行中执行sqlite3 data/business.db data/schema.sql如果本机没有安装 sqlite3 命令行工具也可以直接在 Python 中执行 SQLimport sqlite3 conn sqlite3.connect(data/business.db) with open(data/schema.sql, r, encodingutf-8) as f: conn.executescript(f.read()) conn.commit() conn.close()4.3 准备知识库文档模拟一个企业知识库里面存放几段标准化制度文档和团队总结。这些文本在真实项目里会以切片形式存入向量数据库这里我们作为 Python 列表维护。# 文件路径data/knowledge_docs.py KNOWLEDGE_DOCS [ { title: 考勤管理制度, category: 制度, content: 公司实行弹性工作制核心工作时间为上午10点到下午4点。员工每日需完成打卡加班超过2小时需提前审批。 }, { title: 项目复盘华东区 Q4 业绩, category: 复盘, content: 华东区Q4整体销售额环比下降12%主要原因是新客户交付周期延长同时物流成本上升压缩了利润空间。销售团队反馈大客户对新方案的接受度仍然较高。 }, { title: 信息安全规范, category: 制度, content: 涉及客户数据的查询必须经过审批生产数据库禁止执行未经验证的 UPDATE 和 DELETE 操作所有数据导出需要脱敏。 }, { title: 市场部总结, category: 复盘, content: 市场部在Q4开展了两次线下活动华东区线索量增长15%但线索转化为成单的周期平均延长了5天需要与销售团队联合优化跟进流程。 } ]这些文档会在后面的 MiniVectorStore 中完成“伪向量化”并参与检索。5. 完整示例一个可运行的迷你 Digital Librarian5.1 极简向量存储实现为了不引入第三方向量数据库我用哈希词袋方式生成固定维度的稀疏向量并用余弦相似度做检索。这个类只用于教学演示目的是让检索流程跑通。# 文件路径digital_librarian/vector_store.py import math import re from typing import Dict, List, Tuple class MiniVectorStore: 教学用极简向量存储生产环境请替换为 Milvus/Chroma 等 DIM 64 def __init__(self) - None: self.items: List[Dict] [] def _hash_vector(self, text: str) - List[float]: vec [0.0] * self.DIM tokens re.findall(r[\u4e00-\u9fa5a-zA-Z0-9], text.lower()) for token in tokens: idx hash(token) % self.DIM vec[idx] 1.0 norm math.sqrt(sum(v * v for v in vec)) if norm 0: return vec return [v / norm for v in vec] def add(self, title: str, category: str, content: str) - None: combined f{title} {content} self.items.append({ title: title, category: category, content: content, vector: self._hash_vector(combined), }) def search(self, query: str, top_k: int 3) - List[Tuple[float, Dict]]: qv self._hash_vector(query) scored [] for item in self.items: score sum(a * b for a, b in zip(qv, item[vector])) scored.append((score, item)) scored.sort(keylambda x: x[0], reverseTrue) return [(score, item) for score, item in scored[:top_k] if score 0]这段代码的关键是_hash_vector。它把文本分词后映射到 64 维空间同一个词会落在同一个维度上因此两段文本如果包含相近词汇向量内积会更高。真实项目里应该用语义模型生成向量但分布式思路一致先向量化再算相似度再取 Top-K。5.2 Digital Librarian 核心类下面是核心类。它包含 SQL 查询、向量检索、意图路由、答案生成四个能力。为了保持示例简单我使用规则做路由下一节再演示 LLM 路由。# 文件路径digital_librarian/agent.py import sqlite3 from typing import List, Dict from digital_librarian.vector_store import MiniVectorStore class DigitalLibrarian: def __init__(self, db_path: str, vector_store: MiniVectorStore): self.conn sqlite3.connect(db_path) self.conn.row_factory sqlite3.Row self.vs vector_store def query_sql(self, sql: str) - List[Dict]: 执行 SQL 查询并返回字典列表封装连接与异常 cursor self.conn.execute(sql) rows cursor.fetchall() return [dict(row) for row in rows] def query_vector(self, query: str, top_k: int 2) - List[Dict]: 在迷你向量库中检索相似文档片段 hits self.vs.search(query, top_ktop_k) return [ { score: round(score, 4), title: item[title], category: item[category], content: item[content], } for score, item in hits ] def decide_plan(self, question: str) - str: 规则路由根据关键词判断应该访问哪类数据源 sql_markers [多少, 金额, 平均, 合计, 统计, 哪个部门, 环比, 同比, 人数, 销售额] vector_markers [制度, 文档, 反馈, 介绍, 总结, 规范, 包含, 内容] hit_sql any(m in question for m in sql_markers) hit_vec any(m in question for m in vector_markers) if hit_sql and hit_vec: return BOTH if hit_sql: return SQL if hit_vec: return VECTOR return UNKNOWN def run(self, question: str) - Dict: plan self.decide_plan(question) result {question: question, plan: plan, sql_rows: [], docs: []} if plan in (SQL, BOTH): # 这里使用白名单 SQL生产环境应避免让 Agent 随意拼接 SQL result[sql_rows] self._answer_sql_question(question) if plan in (VECTOR, BOTH): result[docs] self.query_vector(question, top_k2) return result def _answer_sql_question(self, question: str) - List[Dict]: 根据问题返回固定 SQL 查询结果演示 Agent 调用 SQL 工具的方式 if 平均 in question and 薪资 in question: return self.query_sql( SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department ) if Q4 in question or 第四季度 in question: return self.query_sql( SELECT region, SUM(amount) AS total_amount FROM sales WHERE sale_date 2024-10-01 AND sale_date 2025-01-01 GROUP BY region ) return []路由规则中我刻意让_answer_sql_question使用预置 SQL 白名单而不是动态拼接 SQL。这是一个重要的安全边界真实生产环境不能让 LLM 直接生成任意 SQL 并执行至少要加只读约束、表名白名单和 SQL 语法校验。5.3 主程序入口最后写一个简单入口加载知识库文档、初始化 Agent并用几个不同性质的问题测试。# 文件路径main.py from digital_librarian.agent import DigitalLibrarian from digital_librarian.vector_store import MiniVectorStore from data.knowledge_docs import KNOWLEDGE_DOCS def main() - None: vs MiniVectorStore() for doc in KNOWLEDGE_DOCS: vs.add( titledoc[title], categorydoc[category], contentdoc[content], ) agent DigitalLibrarian(data/business.db, vs) questions [ 研发部和市场部的平均薪资是多少, 公司对加班有什么制度要求, 为什么华东区Q4业绩下滑客户反馈中有哪些线索, ] for q in questions: result agent.run(q) print( * 60) print(问题, result[question]) print(路由, result[plan]) if result[sql_rows]: print(SQL 查询结果, result[sql_rows]) if result[docs]: print(文档检索结果) for doc in result[docs]: print(f - {doc[title]}相似度 {doc[score]}{doc[content][:40]}...) if __name__ __main__: main()运行方式python main.py这个主程序把三个问题分别路由到 SQL、VECTOR、BOTH正好覆盖 Digital Librarian 最核心的三种工作场景。6. 进阶用 LLM 做路由与 SQL 生成6.1 从规则路由升级到 LLM 路由规则路由的好处是稳定、可解释但覆盖不了所有表达方式。比如用户问“哪个团队人最多”规则里可能没有“哪个团队”就无法路由到 SQL。更泛化的做法是用 LLM 做路由让它根据工具描述决定调用顺序。下面是一段示例代码使用 OpenAI 兼容接口。实际项目里请根据所选大模型厂商的 SDK 调整细节。# 文件路径examples/llm_router.py 示例使用 LLM 判断问题类型。 注意需要配置真实的大模型 API Key 与模型名称。 def llm_route(question: str) - str: from openai import OpenAI client OpenAI() # 默认读取 OPENAI_API_KEY 环境变量 prompt f 你是一个企业数据问答系统的路由层。请判断用户问题需要访问哪类数据源。 可用数据源 1. SQL_DB关系型数据库包含员工表、销售表适合计算、统计、聚合类问题。 2. VECTOR_DB文档知识库包含制度文档、项目复盘、团队总结适合检索内容、了解背景。 输出必须是以下三个单词之一SQL_DB、VECTOR_DB、BOTH 用户问题{question} resp client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个严谨的路由器只输出一个单词不要解释。}, {role: user, content: prompt}, ], temperature0, ) return resp.choices[0].message.content.strip()在真实 Agent 框架中这一步通常会体现为“函数调用”LLM 决定调用query_sql还是query_vector。思路是一致的让模型先选择工具再执行工具而不是把工具结果强行塞给模型猜测。6.2 LLM 生成 SQL 的注意点很多人会把路由和 SQL 生成混在一起做。这里要特别提醒LLM 生成 SQL 虽然方便但风险很高。表名写错、字段名幻觉、聚合条件不完整都会导致答案错误。更严重的是如果 LLM 生成的 SQL 没有做安全限制可能执行危险的写操作。我建议的安全方案是三层限制第一数据库账号使用只读权限从权限层杜绝写入。第二提供给 LLM 的表结构信息要经过脱敏只暴露它完成任务所必需的字段。第三生成的 SQL 需要经过白名单校验和 JOIN 深度限制比如禁止多表 JOIN 超过 3 张禁止没有 WHERE 条件的 UPDATE 或 DELETE。如果条件允许可以加一个“预览确认”环节让用户看到 SQL 后再执行。6.3 一个可参考的 Agent 工具函数写法实际上当我们讨论 Digital Librarian 时重点是“Agent 如何调度工具”而不是“Agent 本身有多少知识”。在 LangChain 或自研框架中工具函数通常带有一个描述字符串帮助 LLM 理解什么时候该调用。下面是简化版# 文件路径examples/tool_spec.py TOOLS [ { name: query_sql, description: 执行只读 SQL 查询。适合销售统计、薪资统计、人数统计等精确计算问题。, parameters: [sql 语句], }, { name: query_vector, description: 从文档知识库中检索与问题语义相似的片段。适合制度、总结、反馈等文本类问题。, parameters: [查询文本, top_k], }, ]当 LLM 看到一个用户问题时它会根据工具描述选择调用query_sql或query_vector或者先调用一个再调用另一个。这比硬编码关键词路由更灵活。7. 运行结果与效果验证7.1 运行输出示例如果一切正常运行python main.py后输出大致如下 问题 研发部和市场部的平均薪资是多少 路由 SQL SQL 查询结果 [{department: 研发部, avg_salary: 26500.0}, {department: 市场部, avg_salary: 17000.0}] 问题 公司对加班有什么制度要求 路由 VECTOR 文档检索结果 - 考勤管理制度相似度 0.1768公司实行弹性工作制核心工作时间为上午10点到下午4点。员工每日需完成打卡加班超过2小时需提前审批... 问题 为什么华东区Q4业绩下滑客户反馈中有哪些线索 路由 BOTH SQL 查询结果 [{region: 华东, total_amount: 185000.0}, {region: 华北, total_amount: 220000.0}, {region: 华南, total_amount: 95000.0}] 文档检索结果 - 项目复盘华东区 Q4 业绩相似度 0.2236华东区Q4整体销售额环比下降12%主要原因是新客户交付周期延长... - 市场部总结相似度 0.1414市场部在Q4开展了两次线下活动华东区线索量增长15%...7.2 如何判断实现是否正确判断标准有三条。第一条路由结果是否符合问题性质统计问题走 SQL文本问题走向量库复合问题走 BOTH。第二条SQL 查询结果是否与数据一致可以手动执行同样的 SQL 进行比对。第三条向量检索是否召回了最相关的文档如果相似度排序不符合直觉可以适当调整文档切分方式。如果输出为空先看路由结果是否是 UNKNOWN。如果是说明规则没有覆盖当前问题关键词这时需要补充路由规则或者切换为 LLM 路由。8. 常见问题与排查思路下面这份排查清单是 Agent 数据问答项目里最常见的坑建议收藏备用。问题现象可能原因排查方式解决方案问题的 SQL 结果为空路由没进入 SQL 分支或 SQL 条件不匹配打印 plan 和实际执行的 SQL补充路由关键词检查 SQL WHERE 条件向量检索结果不相关文档切分太粗或向量化策略太弱查看召回的 title 和 score 排序改善文本切分换用正式嵌入模型LLM 生成的 SQL 表名不存在模型不知道真实表结构检查提交给 LLM 的 schema 提示词为 LLM 提供准确的表名、字段注释复合问题只返回了一半答案路由判断为单一数据源没有走 BOTH查看 plan 字段增加复合问题识别或强制并行查询Agent 响应速度很慢SQL 查询慢或向量库召回数据过多分析执行计划检查 Top-K 大小给 SQL 加索引限制向量召回数量相同问题反复触发外部调用没有缓存设计查看请求日志增加问题哈希缓存相同问题直接复用答案生产库被 UPDATE/DELETELLM 生成的 SQL 未限制写操作审查数据库账号权限使用只读账号禁止写入语句通过 Agent 执行重点关注最后一行。AI Agent 一旦接入数据库安全边界就不是可选项了。我在实际项目中见过因为 Agent 生成的 SQL 缺少 WHERE 条件导致全表更新的事件那类问题一旦发生影响面不可控。正确的做法是一开始就把只读权限和 SQL 校验写进工具层。9. 生产环境最佳实践与工程建议9.1 安全边界Agent 不写库写库走审批无论你用的是 LangChain、自研 Agent还是类似 Spring AI 这类 Java 框架在接入关系型数据库时都建议遵循三个原则最小权限、只读优先、审批放行。默认数据库账号只给 SELECT 权限所有写操作必须单独走审批流程。文本类知识库也一样Agent 只能读取公开的文档集合涉及机密文档时需要按权限过滤。9.2 元数据与表结构管理Digital Librarian 的检索能力很大程度上依赖元数据质量。SQL 侧你需要维护一份表清单包含表名、字段名、字段类型、字段注释、示例值、表间关系。向量库侧你需要维护文档集合的命名规范、切分粒度、标签体系。把这些元数据交给 LLM 作为上下文它才知道该查什么。我给团队的一个常用做法是把元数据写成 YAML代码启动时加载并注入 Prompt。# 文件路径config/schema_meta.yaml tables: - name: employees comment: 员工信息表 fields: - name: department comment: 所属部门 - name: salary comment: 月薪 - name: sales comment: 销售流水表 fields: - name: region comment: 销售区域 - name: amount comment: 销售金额 - name: sale_date comment: 销售日期 vector_collections: - name: policy_docs comment: 制度文档集合 - name: review_docs comment: 项目复盘与总结集合这份元数据文件的价值是让 LLM 在生成 SQL 时获得真实可用的表结构减少幻觉。9.3 日志与审计任何涉及数据库访问的 Agent 都必须记录审计日志。建议至少记录用户问题原文、路由结果、生成的 SQL、SQL 执行结果摘要、向量检索 Top-K 结果、耗时、模型生成答案的引用来源。日志不仅用于排查问题也是后续评估 Agent 效果的数据基础。9.4 性能与缓存设计SQL 和向量检索都属于外部 I/O不能每次都让 LLM 从头规划。工程上最常见的优化方式有两类。一类是语义缓存对用户问题和检索结果做归一化如果命中缓存直接返回减少模型调用和数据库查询。另一类是结果缓存对同一份 SQL 结果设置 TTL比如销售统计结果缓存 10 分钟制度文档检索结果缓存 1 小时。这能显著降低热点问题带来的压力。9.5 用评测集持续改进Agent 类应用最怕“好像能跑又好像不行”。建议从一开始就维护一个评测集包含三类问题纯 SQL 问题、纯向量问题、复合问题。每次修改 Prompt、路由规则或模型版本后跑一遍评测集记录准确率。这套机制虽然朴素但比“感觉比上次好”可靠得多。10. 总结与下一步学习方向Digital Librarian AI Agent 的本质不是“一个能回答问题的模型”而是一套连接 LLM、SQL 数据库和向量数据库的调度系统。它把企业数据访问拆成了意图路由、工具调用、结果汇总三个环节让每个环节都能被单独优化也让数据权限和安全边界有了清晰的落点。读完这篇文章建议你按下面的顺序实践第一步把文中的最小示例跑通理解 SQL 和向量检索各自能解决什么问题。第二步为你的业务数据编写 schema 元数据把规则路由切换成 LLM 路由。第三步接入真实向量数据库和真实 SQL 库补上只读权限、日志审计和安全校验。最后用一组覆盖业务问题的评测集持续迭代。下一步值得深入的方向有三个一是函数调用与 ReAct 框架的具体实现二是查询结果的校验机制三是多轮对话中的状态管理。当你不再纠结“RAG 还是 Text-to-SQL”的时候你其实已经开始用 Agent 的视角思考问题了。
返回列表