第五章:实战项目 — Text2SQL
本节课通过Text2SQL实战项目,用三大框架分别实现”自然语言查数据库”,在真实场景中感受框架差异与选型要点。
5.1 项目概述
目标:用户输入自然语言问题(如”哪个音乐类型的歌曲最长?”),Agent 自动查询数据库并返回结果。
使用数据库:Chinook SQLite(示例音乐商店数据库,11 张表)
技术栈:
- Python 3.11+
- SQLite
- LangChain / LangGraph / DeepAgents
数据库 Schema 概览:
1 | Album ← Artist |
安装依赖:
1 | pip install langchain langgraph deepagents langchain-openai langchain-community |
下载数据库:
1 | import requests, pathlib |
5.2 LangChain 实现
1 | """ |
LangChain 实现的问题:
| 问题 | 原因 |
|---|---|
| 无法强制先查看表结构 | 完全依赖 LLM 自主决定调用哪些工具 |
| 无法自动检查 SQL 正确性 | 没有”检查”步骤,直接执行 |
| 无人工审批 | AgentExecutor 不支持 interrupt |
| 错误恢复有限 | 只能靠 handle_parsing_errors |
| 无状态持久化 | 对话结束后状态丢失 |
5.3 LangGraph 实现
1 | """ |
执行流程图:
flowchart TD
START([START]) --> LT["list_tables<br/>强制列出所有表"]
LT --> CGS["call_get_schema<br/>LLM 决定查看哪些表"]
CGS --> GS["get_schema<br/>获取表结构"]
GS --> GQ["generate_query<br/>生成 SQL"]
GQ --> SC{有工具调用?}
SC -->|否| END([END])
SC -->|是| CQ["check_query<br/>检查 SQL 正确性"]
CQ --> RQ["run_query<br/>执行 SQL"]
RQ --> GQ
style START fill:#e8f5e9
style END fill:#ffebee
style LT fill:#e3f2fd
style CGS fill:#e3f2fd
style GS fill:#fff9c4
style GQ fill:#e3f2fd
style CQ fill:#f3e5f5
style RQ fill:#fff9c4
5.4 DeepAgents 实现
1 | """ |
DeepAgents 自动做的事情(你不需要写代码):
flowchart TD A[用户提问] --> B[write_todos 自动规划] B --> C[待办列表] C --> D1["✅ 1. 列出数据库表"] C --> D2["✅ 2. 查看 Genre 和 Track 表结构"] C --> D3["✅ 3. 编写 SQL 查询"] C --> D4["✅ 4. 检查 SQL 正确性"] C --> D5["✅ 5. 执行查询"] C --> D6["✅ 6. 解释结果"] D1 --> E[上下文管理 自动] D2 --> E D3 --> E D4 --> E D5 --> E D6 --> F[智能决策 自动] E --> E1[大的工具结果自动卸载] E --> E2[对话过长时自动摘要] F --> F1[自主决定调用哪些工具] F --> F2[出错时自动修正重试] F --> F3[虚拟文件系统保存中间结果] style B fill:#e3f2fd style E fill:#fff9c4 style F fill:#e8f5e9
5.5 三框架实现对比
| 维度 | LangChain | LangGraph | DeepAgents |
|---|---|---|---|
| 代码行数 | ~50 行 | ~120 行 | ~60 行 |
| 工具定义 | 使用 SQLDatabaseToolkit | 使用 SQLDatabaseToolkit | 自定义工具函数 |
| 流程控制 | 无(LLM 完全自主) | 精确(每个节点定义) | 半自主(提示词引导) |
| SQL 检查 | 无 | 有(check_query 节点) | 有(check_sql_query 工具) |
| 人工审批 | 不支持 | 支持(interrupt) | 支持(interrupt_on) |
| 错误处理 | 有限(handle_parsing_errors) | 节点级别 | 工具级别 + 自动重试 |
| 状态持久化 | 无 | 有(Checkpointer) | 有(继承自 LangGraph) |
| 上下文管理 | 无 | 无 | 有(自动压缩 + 卸载) |
| 规划能力 | 无 | 无 | 有(write_todos) |
| 子任务委派 | 无 | 手动实现 | 有(内置 task 工具) |
5.6 Skill 版本:从教程到可加载能力
上面的 5.4 节是”在代码中手动写工具和提示词”的传统方式。DeepAgents 的 Skills 系统 让你可以将整个 Text2SQL 工作流封装为一个可复用的技能包,Agent 按需加载即可获得完整能力。
两种方式对比
| 维度 | 传统方式(5.4 节) | Skill 方式 |
|---|---|---|
| 工具定义 | 在代码中逐个定义 | 打包在 tools.py 中 |
| 工作流指引 | 写在 system_prompt 里 | 写在 SKILL.md 里 |
| SQL 模式参考 | 无(靠 LLM 自行判断) | patterns.md 提供模式库 |
| 示例查询 | 无 | examples/ 目录提供场景示例 |
| 加载方式 | 手动传 tools 参数 | skills=["/skills/text2sql/"] |
| 复用性 | 每次重写 | 一次打包,到处加载 |
| 渐进式披露 | 全量加载 | 启动时只读 frontmatter,匹配后才加载完整内容 |
Skill 目录结构
1 | skills/text2sql/ |
使用 Skill 创建 Text2SQL Agent
1 | from deepagents import create_deep_agent |
渐进式披露的运行机制
flowchart TD
A["🚀 Agent 启动"] --> B["读取 SKILL.md frontmatter<br/>(name + description)"]
B --> C["只消耗 ~50 tokens"]
C --> D["👤 用户提问"]
D --> E{"技能 description 匹配?"}
E -->|是| F["加载完整 SKILL.md + patterns.md"]
E -->|否| G["不加载,节省 tokens"]
F --> H["Agent 按工作流执行<br/>1. 列表 → 2. Schema → 3. SQL → 4. 检查 → 5. 执行"]
H --> I["返回结果"]
style B fill:#e3f2fd
style E fill:#fff9c4
style F fill:#e8f5e9
style G fill:#ffebee
完整 Skill 包 位于
skills/text2sql/目录,可直接在 DeepAgents 项目中使用。