惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
Malwarebytes
Malwarebytes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
F
Future of Privacy Forum
C
Cisco Blogs
T
The Exploit Database - CXSecurity.com
A
Arctic Wolf
S
Securelist
K
Kaspersky official blog
S
Schneier on Security
T
ThreatConnect
T
Tenable Blog
Spread Privacy
Spread Privacy
T
True Tiger Recordings
AWS News Blog
AWS News Blog
F
Fox-IT International blog
量子位
T
Threatpost
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
宝玉的分享
宝玉的分享
腾讯CDC
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
U
Unit 42
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
The Register - Security
The Register - Security
MyScale Blog
MyScale Blog
小众软件
小众软件
A
About on SuperTechFans
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
博客园 - 三生石上(FineUI控件)
美团技术团队
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog

博客园 - 沐子馨

告别简单向量搜索:RAG 中的高级查询构建与优化策略 深入理解 RAG 中的混合搜索策略 告别基础检索:掌握 RAG 中的句子窗口与递归路由策略 构建多模态检索系统:Milvus 部署、Schema 设计与混合检索实践 向量数据库原理与实战:从核心机制到 FAISS 应用 多模态向量嵌入:从文本到图像的语义统一与 RAG 应用 构建高效 RAG 的基石:深度解析 Embedding 模型原理与优化 All-in-RAG:解锁大模型“开卷考试”的终极能力 - 沐子馨 AI Agent 是如何思考的?一文读懂推理与决策引擎 终端革命:AI Agent 正在重新定义命令行 给企业装上“AI 大脑”:AgentSpace 如何从“手动检索”跨越到“智能决策”? Agentic 框架快速概览 AI 智能体交互如何带领它走出对话框,从屏幕像素迈向真实物理世界 高级提示词技巧如何带领大模型走出“一本正经胡说八道”的误区? 当 AI 学会“开疆拓土”:探索与发现模式如何从源头打破静态知识的桎梏,在陌生领域催生新洞见? 拒绝 AI “手忙脚乱”:优先级模式如何为智能体打造毫秒级的“任务调度官”? - 沐子馨 构建生产级可信 Agent:评估与监控中的自动化审计与闭环优化机制 当 AI 学会“三思后言”:安全护栏如何从源头掐灭偏见、幻觉与恶意攻击? - 沐子馨 拒绝“张口就来”:推理技术如何让 AI 像人类一样拆解复杂难题? 当家方知柴米贵:资源感知优化如何让 AI 智能体告别“算力浪费”? 开启多智能体互联时代:A2A 协议与 AI 协作网络的底层逻辑 为智能体装上“实时百科全书”:RAG 如何打破 AI 的知识边界? 构建负责任的AI:人类监督、干预与反馈闭环机制 当工具失效、网络中断:AI智能体的应急与自修复指南 赋予AI“北极星”:如何让智能体自主设定并追踪目标 打破“M×N”集成魔咒:MCP如何重塑AI应用架构 赋予模型“生命力”:大语言模型如何通过学习实现持续适应 赋予模型“长期记忆”:大语言模型的记忆管理机制 AI的“社会性”:深入理解多智能体协作机制 理解AI智能体的规划机制 理解大模型的工具使用 智能体的元认知:反思模式与自我优化机制 智能体并行化模式:提升复杂工作流性能的关键技术 超越线性执行:使用LLM实现智能体路由模式 解构复杂任务:深入理解提示词链(Prompt Chaining) 别再被 AI 术语唬住了!一文理清你需要了解的所有概念 不止是多写几句:谷歌如何用69页白皮书重塑提示工程 [转]长PDF文档的总结与评估策略 Context 工程:如何把正确的上下文喂给 AI 前端如何写出优秀的 AI Agent Skills - 沐子馨 mac安装python后command not found: pip keep-alive 原理剖析 如何优雅地在 React 中使用TypeScript,看这一篇就够了! react useContext React Context 详细介绍(状态共享、数据传递) 以用户为中心的性能指标【译】 element下拉框远程搜索debounce防抖控制 vue-router打开新窗口 propmise: allSettled()与all()的区别 使用 new Date() 在chrome、安卓和 IOS 中表现不同
告别黑盒:手把手实现一个可解释、可调试的 Text2SQL 代理系统
沐子馨 · 2026-05-24 · via 博客园 - 沐子馨

本篇聚焦于结构化数据领域中一个常见的应用。在数据世界中,除了向量数据库能够处理的非结构化数据,关系型数据库(如 MySQL, PostgreSQL, SQLite)同样是存储和管理结构化数据的重点。文本到SQL(Text-to-SQL)1 正是为了打破人与结构化数据之间的语言障碍而生。它利用大语言模型(LLM)将用户的自然语言问题,直接翻译成可以在数据库上执行的SQL查询语句。

一、业务挑战

  • “幻觉”问题:LLM 可能会“想象”出数据库中不存在的表或字段,导致生成的SQL语句无效。
  • 对数据库结构理解不足:LLM 需要准确理解表的结构、字段的含义以及表与表之间的关联关系,才能生成正确的 JOINWHERE 子句。
  • 处理用户输入的模糊性:用户的提问可能存在拼写错误或不规范的表达(例如,“上个月的销售冠军是谁?”),模型需要具备一定的容错和推理能力。

二、优化策略

  1. 提供精确的数据库模式:这是最基础也是最关键的一步。我们需要向LLM提供数据库中相关表的 CREATE TABLE 语句。这就像是给了LLM一张地图,让它了解数据库的结构,包括表名、列名、数据类型和外键关系。

  2. 提供少量高质量的示例:在提示(Prompt)中加入一些“问题-SQL”的示例对,可以极大地提升LLM生成查询的准确性。这相当于给了LLM几个范例,让它学习如何根据相似的问题构建查询。

  3. 利用RAG增强上下文:这是更进一步的策略。我们可以像RAGFlow一样,为数据库构建一个专门的“知识库”2,其中不仅包含表的DDL(数据定义语言),还可以包含:

    • 表和字段的详细描述:用自然语言解释每个表是做什么的,每个字段代表什么业务含义。
    • 同义词和业务术语:例如,将用户的“花费”映射到数据库的 cost 字段。
    • 复杂的查询示例:提供一些包含 JOINGROUP BY 或子查询的复杂问答对。 当用户提问时,系统首先从这个知识库中检索最相关的信息(如相关的表结构、字段描述、相似的Q&A),然后将这些信息和用户的问题一起组合成一个内容更丰富的提示,交给LLM生成最终的SQL查询。这种方式极大地降低了“幻觉”的风险,提高了查询的准确度。
  4. **错误修正与反思 (Error Correction and Reflection)**:在生成SQL后,系统会尝试执行它。如果数据库返回错误,可以将错误信息反馈给LLM,让它“反思”并修正SQL语句,然后重试。这个迭代过程可以显著提高查询的成功率。

三、实现一个简单的Text2SQL框架

本节基于RAGFlow方案实现了一个简单的Text2SQL框架。该框架使用Milvus向量数据库作为知识库,BGE-M3模型进行语义检索,DeepSeek作为大语言模型,专门针对SQLite数据库进行了优化。

Text2SQL框架工作流程

3.1 知识库模块 (knowledge_base.py)

知识库模块是整个框架的核心,负责存储和检索SQL相关的知识信息。

class SimpleKnowledgeBase:
    """知识库"""
    
    def __init__(self, milvus_uri: str = "http://localhost:19530"):
        self.milvus_uri = milvus_uri
        self.client = MilvusClient(uri=milvus_uri)
        self.embedding_function = BGEM3EmbeddingFunction(use_fp16=False, device="cpu")
        self.collection_name = "text2sql_kb"
        self._setup_collection()

设计思想:

  1. 统一知识管理:将DDL定义、Q-SQL示例和表描述三种类型的知识统一存储在一个Milvus集合中,通过 type 字段区分。

  2. 语义检索能力:使用BGE-M3模型进行向量化,支持中英文混合的语义相似度搜索。

def _setup_collection(self):
    """设置集合"""
    # 定义字段
    fields = [
        FieldSchema(name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=True, max_length=100),
        FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=4096),
        FieldSchema(name="type", dtype=DataType.VARCHAR, max_length=32),  # ddl, qsql, description
        FieldSchema(name="dense_vector", dtype=DataType.FLOAT_VECTOR, dim=self.embedding_function.dim["dense"])
    ]

数据加载策略:

def load_data(self):
    """加载所有知识库数据"""
    # 加载DDL数据 - 表结构定义
    # 加载Q->SQL数据 - 问答示例
    # 加载描述数据 - 表和字段的业务描述

框架支持三种类型的知识:

  • DDL知识3:表的结构定义,包括字段类型、约束等
  • Q-SQL知识4:历史问答对,为新问题提供参考模式
  • 描述知识5:表和字段的业务含义,帮助理解数据语义

检索机制:

def search(self, query: str, top_k: int = 5) -> List[Dict[str, Any]]:
    """搜索相关内容"""
    query_embeddings = self.embedding_function([query])
    
    search_results = self.client.search(
        collection_name=self.collection_name,
        data=query_embeddings["dense"],
        anns_field="dense_vector",
        search_params={"metric_type": "IP"},  # 内积相似度
        limit=top_k,
        output_fields=["content", "type"]
    )

3.2 SQL生成模块 (sql_generator.py)

SQL生成模块负责将自然语言问题转换为SQL查询语句,并具备错误修复能力。

class SimpleSQLGenerator:
    """简化的SQL生成器"""
    
    def __init__(self, api_key: str = None):
        self.llm = ChatDeepSeek(
            model="deepseek-chat",
            temperature=0,  # 确保结果的确定性
            api_key=api_key or os.getenv("DEEPSEEK_API_KEY")
        )

SQL生成策略:

def generate_sql(self, user_query: str, knowledge_results: List[Dict[str, Any]]) -> str:
    """生成SQL语句"""
    # 构建上下文
    context = self._build_context(knowledge_results)
    
    # 构建提示
    prompt = f"""你是一个SQL专家。请根据以下信息将用户问题转换为SQL查询语句。

数据库信息:
{context}

用户问题:{user_query}

要求:
1. 只返回SQL语句,不要包含任何解释
2. 确保SQL语法正确
3. 使用上下文中提供的表名和字段名
4. 如果需要JOIN,请根据表结构进行合理关联

SQL语句:"""

关键设计原则:

  1. 上下文驱动:通过知识库检索结果构建丰富的上下文信息
  2. 结构化提示:明确的任务要求和格式约束
  3. 确定性输出:设置temperature=0确保相同输入产生相同输出

错误修复机制:

def fix_sql(self, original_sql: str, error_message: str, knowledge_results: List[Dict[str, Any]]) -> str:
    """修复SQL语句"""
    context = self._build_context(knowledge_results)
    
    prompt = f"""请修复以下SQL语句的错误。

数据库信息:
{context}

原始SQL:
{original_sql}

错误信息:
{error_message}

请返回修复后的SQL语句(只返回SQL,不要解释):"""

上下文构建策略:

def _build_context(self, knowledge_results: List[Dict[str, Any]]) -> str:
    """构建上下文信息"""
    # 按类型分组
    ddl_info = []        # 表结构信息
    qsql_examples = []   # 查询示例
    descriptions = []    # 表描述信息
    
    # 分层次组织信息:结构 → 描述 → 示例
    if ddl_info:
        context += "=== 表结构信息 ===\n"
    if descriptions:
        context += "=== 表和字段描述 ===\n"
    if qsql_examples:
        context += "=== 查询示例 ===\n"

3.3 代理模块 (text2sql_agent.py)

代理模块是整个框架的控制中心,协调知识库检索、SQL生成和执行的完整流程。

class SimpleText2SQLAgent:
    """Text2SQL代理"""
    
    def __init__(self, milvus_uri: str = "http://localhost:19530", api_key: str = None):
        self.knowledge_base = SimpleKnowledgeBase(milvus_uri)
        self.sql_generator = SimpleSQLGenerator(api_key)
        
        # 配置参数
        self.max_retry_count = 3      # 最大重试次数
        self.top_k_retrieval = 5      # 检索数量
        self.max_result_rows = 100    # 结果行数限制

主要查询流程:

def query(self, user_question: str) -> Dict[str, Any]:
    """执行Text2SQL查询"""
    # 1. 从知识库检索相关信息
    knowledge_results = self.knowledge_base.search(user_question, self.top_k_retrieval)
    
    # 2. 生成SQL语句
    sql = self.sql_generator.generate_sql(user_question, knowledge_results)
    
    # 3. 执行SQL(带重试机制)
    retry_count = 0
    while retry_count < self.max_retry_count:
        success, result = self._execute_sql(sql)
        
        if success:
            return {"success": True, "sql": sql, "results": result}
        else:
            # 尝试修复SQL
            sql = self.sql_generator.fix_sql(sql, result, knowledge_results)
            retry_count += 1

安全执行策略:

def _execute_sql(self, sql: str) -> Tuple[bool, Any]:
    """执行SQL语句"""
    # 添加LIMIT限制,防止大量数据返回
    if sql.strip().upper().startswith('SELECT') and 'LIMIT' not in sql.upper():
        sql = f"{sql.rstrip(';')} LIMIT {self.max_result_rows}"
    
    # 结构化结果返回
    if sql.strip().upper().startswith('SELECT'):
        columns = [desc[0] for desc in cursor.description]
        rows = cursor.fetchall()
        
        results = []
        for row in rows:
            result_row = {}
            for i, value in enumerate(row):
                result_row[columns[i]] = value
            results.append(result_row)
        
        return True, {"columns": columns, "rows": results, "count": len(results)}

3.4 完整流程模拟

以查询"年龄大于30的用户有哪些"为例,演示框架三个核心模块的完整协作过程:

3.4.1 模拟数据

假设数据库中的users表包含以下用户数据:

ID姓名邮箱年龄城市
1 张三 zhangsan@email.com 25 北京
2 李四 lisi@email.com 32 上海
3 王五 wangwu@email.com 28 广州
4 赵六 zhaoliu@email.com 35 深圳
5 陈七 chenqi@email.com 29 杭州

3.4.2 Step 1: 知识库检索

用户输入:"年龄大于30的用户有哪些"

检索过程:

  1. BGE-M3模型将查询文本转换为768维向量
  2. Milvus在知识库中进行语义相似度搜索
  3. 返回最相关的5条知识,按相似度排序

检索结果:

DDL知识 (相似度: 0.85)

  • 表名:users
  • 结构:包含id、name、email、age、city字段
  • 约束:id为主键,email唯一

Q-SQL示例 (相似度: 0.82)

  • 问题:"查询年龄超过25岁的用户"
  • SQL:SELECT * FROM users WHERE age > 25

    这是检索到的相似示例,最终SQL会基于用户实际问题调整为age > 30

表描述 (相似度: 0.78)

  • age字段:用户年龄,整数类型
  • name字段:用户姓名,文本类型

3.4.3 Step 2: SQL生成

上下文构建: 系统将检索到的知识整理成结构化的上下文信息:

表结构信息

  • 表名:users
  • DDL定义:完整的CREATE TABLE语句
  • 字段约束:主键、唯一性等

表和字段描述

  • age字段:用户年龄,INTEGER类型
  • name字段:用户姓名,TEXT类型

查询示例

  • 相似问题:查询年龄超过25岁的用户
  • 参考SQL:SELECT * FROM users WHERE age > 25

SQL生成过程:

  1. DeepSeek分析用户问题的意图:查询满足年龄条件的用户
  2. 识别关键信息:年龄字段(age)、比较操作(大于)、阈值(30)
  3. 参考示例模式:从WHERE age > 25学习到WHERE age > 数值的模式
  4. 模式应用:将用户的实际数值30替换示例中的25
  5. 生成目标SQL:SELECT * FROM users WHERE age > 30

3.4.4 Step 3: SQL执行与结果处理

安全处理:

  • 原始SQL:SELECT * FROM users WHERE age > 30
  • 自动添加限制:SELECT * FROM users WHERE age > 30 LIMIT 100

数据库执行: SQLite引擎逐行检查users表中的数据:

用户年龄检查结果
张三 25 > 30? ❌ 不符合
李四 32 > 30? ✅ 符合
王五 28 > 30? ❌ 不符合
赵六 35 > 30? ✅ 符合
陈七 29 > 30? ❌ 不符合

结果处理:

  • 筛选出2条符合条件的记录
  • 转换为结构化JSON格式
  • 包含字段名称和数据类型信息

最终输出:

{
    "success": true,
    "error": null,
    "sql": "SELECT * FROM users WHERE age > 30 LIMIT 100",
    "results": {
        "columns": ["id", "name", "email", "age", "city"],
        "rows": [
            {"id": 2, "name": "李四", "email": "lisi@email.com", "age": 32, "city": "上海"},
            {"id": 4, "name": "赵六", "email": "zhaoliu@email.com", "age": 35, "city": "深圳"}
        ],
        "count": 2
    },
    "retry_count": 0
}

通过这个语义理解 → 结构化查询 → 数据过滤 → 结果输出的完整流程,框架成功将用户的自然语言问题转换为精确的数据库查询结果。

3.5 代码运行

如果你想测试这个Text2SQL框架,可以通过以下方式进行:

快速体验:运行演示程序

python code/C4/03_text2sql_demo.py

3.6 为什么不直接使用封装好的框架?

因为淋过雨,所以想为你撑把伞🤪

市面上确实有很多成熟的Text2SQL框架,但这些高度封装的工具往往存在黑盒问题——当查询结果不符合预期时,很难定位是检索环节、SQL生成环节还是执行环节出了问题。正如上一节LangChain示例中遇到的查询异常,我们很难深入到框架内部进行精确调试和优化。这一点在索引优化那节中也提到过。

参考文献

DDL(Data Definition Language)是数据定义语言,用于定义数据库结构,如CREATE TABLE语句。