DataPilot MCP Server
Provides tools to inspect dataset schema, profile, preview, and execute read-only SQL queries on uploaded CSV/Excel files.
README
DataPilot
DataPilot 是一个使用 Python 构建的智能数据分析 Agent 原型。用户上传 CSV 或 Excel 文件后,可以查看数据结构与质量报告、执行只读 DuckDB SQL、用自然语言进行 Text-to-SQL 查询,以及让 LangGraph 把复杂问题拆成多个步骤并生成分析报告和一张 PNG 图表。
当前项目重点展示可验证的分层设计、MCP 工具复用、受控 SQL、LangGraph 工作流和 SQLite Checkpoint。它是一个本地单机原型,不是面向生产环境的完整数据平台。
已完成能力
- 读取
.csv和.xlsx,Excel 默认使用第一个工作表; - 确定性识别 Excel 标题行、多行表头、合并单元格、空行空列和明确汇总行;
- 使用 Pandas 识别字段类型、缺失值、重复行及基础统计;
- 将 DataFrame 注册到进程内 DuckDB,并返回唯一
dataset_id; - 只允许一条
SELECT或WITH ... SELECT,结果最多返回 1000 行; - 提供 FastAPI 数据集、查询和 Agent API;
- 提供无需 React 的本地浏览器界面,自动完成上传、提问和结果展示;
- 通过 MCP Server 暴露 Schema、Profile、Preview 和只读 SQL 工具;
- 使用 Pydantic Structured Outputs 生成 DuckDB SQL;
- 使用 LangGraph 执行单步骤 Text-to-SQL,并最多修复 SQL 两次;
- 使用父 Planning Graph 将问题拆成 1~4 个独立步骤;
- 从第一个适合绘图的成功步骤生成一张 bar 或 line PNG;
- 使用
AsyncSqliteSaver持久化父图 Checkpoint; - 通过
thread_id查询最新状态和最多 50 条历史摘要; - 使用 Mock LLM 完成无网络的全量 pytest 和端到端验收。
技术栈
- Python 3.11+
- FastAPI、Pydantic
- Pandas、DuckDB
- MCP Python SDK
- LangChain、LangGraph
- DeepSeek Chat Completions API
- Matplotlib
- AsyncSqliteSaver、SQLite
- pytest
技术架构
flowchart TD
Client["HTTP / MCP 客户端"] --> API["FastAPI API 层"]
API --> DatasetService["DatasetService"]
API --> QueryService["QueryService"]
API --> AgentServices["Graph Services"]
DatasetService --> Loader["DatasetLoader"]
Loader --> ExcelDetector["ExcelStructureDetector"]
DatasetService --> Profiler["DatasetProfiler"]
DatasetService --> DuckDB["DuckDBService"]
QueryService --> DuckDB
AgentServices --> PlanningGraph["Planning Graph"]
PlanningGraph --> TextToSQLGraph["Text-to-SQL 子图"]
TextToSQLGraph --> MCPClient["DataPilotMCPClient"]
MCPClient --> MCPServer["MCP Server"]
MCPServer --> DatasetService
MCPServer --> QueryService
PlanningGraph --> ChartService["ChartService"]
PlanningGraph --> SQLite["AsyncSqliteSaver"]
各层职责:
- API 层:HTTP 参数校验、依赖获取和业务异常到状态码的转换;
- Service 层:组织上传、Profile、查询和 Graph 调用;
- Loader/Profiler/DuckDB/Chart:确定性底层能力,不调用 LLM;
- ExcelStructureDetector:识别工作表结构并生成分析用标准化副本,不修改原文件;
- MCP 层:把已有 Service 暴露成工具,不复制业务逻辑;
- Text-to-SQL 子图:Schema、SQL 生成、查询、修复和回答;
- Planning 父图:规划步骤、逐步调用子图、保存结果、生成图表和报告;
- Checkpointer:按
thread_id保存父图各 super-step 的状态快照。
项目结构
app/
├── api/ # FastAPI 路由
├── graph/ # 单步骤 Text-to-SQL 子图
├── llm/ # LLM 协议和 DeepSeek 客户端
├── models/ # Pydantic 请求、响应和领域模型
├── planning/ # 多步骤 Planning 父图
├── services/ # 数据、SQL、图表和 Graph Service
├── web/ # 本地 HTML、CSS、JavaScript 交互页面
├── main.py # 应用组合根与 lifespan
├── mcp_client.py # MCP 工具调用封装
└── mcp_server.py # MCP 工具定义
tests/ # 单元、API、工作流和项目验收测试
sample_data/ # 可复现演示数据
Excel 结构识别
上传 .xlsx 后,DatasetLoader 仍然只读取第一个工作表,但不再直接把第一行固定当作
表头。它先调用 ExcelStructureDetector,按照确定性规则完成:
- 跳过表头前只有标题内容的行;
- 将最多 3 行的合并式表头组合成唯一字段名;
- 只展开数据区真实存在的纵向合并单元格,例如分组或类别标签;
- 删除全空数据行、全空数据列和标签明确为“合计、总计、小计、汇总、平均”的汇总行;
- 清理字段和文本两侧空格,为重复或空白字段生成稳定名称;
- 返回工作表名、标题、表头位置、清理计数、置信度和 warnings。
原始 Excel 文件不会被修改。CSV 继续沿用原有读取方式。结构结果位于上传响应的
summary.excel_structure;置信度为 low 时应先核对 Preview。当前规则不会猜测字段的
业务含义,也不会在多个工作表或同一工作表的多个独立表格之间自动选择。
app/graph/ 和 app/planning/ 不是重复目录:前者处理一个自然语言查询,后者负责把
复杂请求拆成多个子查询。TextToSQLService 是保留并经过测试的线性基线;当前 HTTP
Agent 接口使用的是 TextToSQLGraphService。
LangGraph 工作流
单步骤 Text-to-SQL 子图
flowchart LR
Start["START"] --> Schema["load_schema"]
Schema -->|成功| Generate["generate_sql"]
Schema -->|失败| Failed["mark_failed"]
Generate --> Execute["execute_sql"]
Execute -->|成功| Answer["generate_answer"]
Execute -->|失败且未超过 2 次| Repair["repair_sql"]
Repair --> Execute
Execute -->|修复耗尽| Failed
Answer --> End["END"]
Failed --> End
Schema 获取和 SQL 执行必须经过 MCP。LLM 只负责生成结构化 SQL、修复 SQL 和组织自然 语言回答,最终 SQL 仍由 DuckDB 查询层执行安全校验。
多步骤 Planning 父图
flowchart LR
Start["START"] --> Schema["load_schema"]
Schema --> Plan["create_plan"]
Plan --> Select["select_next_step"]
Select --> Child["execute_current_step"]
Child --> Store["store_step_result"]
Store -->|仍有步骤| Select
Store -->|全部完成| Chart["generate_chart"]
Chart --> Report["synthesize_report"]
Report --> End["END"]
Planner 最多生成 4 个互相独立的自然语言步骤。单个步骤失败不会阻止后续步骤;至少一个
步骤成功时,整体仍可为 completed。图表失败只写入 chart_error,不会改变步骤状态。
Checkpoint
父图使用 AsyncSqliteSaver,默认数据库为:
.datapilot/checkpoints/checkpoints.sqlite
历史固定按最新到最旧返回,最多 50 条。服务重启后可以读取旧 State 和 History,但 不会自动 Resume,也不会重新注册旧 DuckDB 数据集。
MCP 工具
MCP Streamable HTTP 服务挂载在:
http://127.0.0.1:8000/mcp
| 工具 | 输入 | 输出 | 职责 |
|---|---|---|---|
get_dataset_schema |
dataset_id |
字段和 DuckDB 类型 | 查询 Schema |
get_dataset_profile |
dataset_id |
数据质量 Profile | 查询确定性质量报告 |
preview_dataset |
dataset_id, limit |
最多 5 行 | 预览数据 |
execute_readonly_sql |
dataset_id, sql |
最多 1000 行 | 执行受控只读 SQL |
MCP 工具只调用 DatasetService 和 QueryService,不重新实现文件读取、Profile 或 SQL。
安装与配置
python -m pip install -e ".[dev]"
环境变量示例见 .env.example:
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-v4-flash
CHECKPOINT_DB_PATH=.datapilot/checkpoints/checkpoints.sqlite
LANGGRAPH_STRICT_MSGPACK=true
DEEPSEEK_API_KEY:DeepSeek 控制台生成的密钥;未配置时 Agent API 返回 503;DEEPSEEK_BASE_URL:默认使用 DeepSeek 官方兼容地址;DEEPSEEK_MODEL:默认使用deepseek-v4-flash,可改为账户可用的模型;CHECKPOINT_DB_PATH:服务端配置,客户端不能修改;相对路径按启动目录解析;LANGGRAPH_STRICT_MSGPACK:限制 checkpoint 反序列化类型;项目未启用 pickle fallback。
项目不会自动读取 .env 文件。在 VSCode 的 CMD 终端中,应分两行执行:
set "DEEPSEEK_API_KEY=你的新密钥"
python -m uvicorn app.main:app --reload
PowerShell 使用:
$env:DEEPSEEK_API_KEY="你的新密钥"
python -m uvicorn app.main:app --reload
密钥必须在启动 Uvicorn 前设置。重启终端后需要重新设置,且不要把真实密钥写入
README、.env.example、截图或 Git。
DeepSeekLLMClient 使用官方 OpenAI 兼容的 Chat Completions 接口。普通回答读取
message.content;SQL 和 AnalysisPlan 等结构化结果使用 JSON Output,再由 Pydantic
执行严格模型校验。项目不再使用 OpenAI Responses API。
启动服务:
uvicorn app.main:app --reload
OpenAPI 文档:http://127.0.0.1:8000/docs
本地操作页面:http://127.0.0.1:8000/
本地操作页面
启动 DataPilot 后,直接在浏览器打开:
http://127.0.0.1:8000/
页面支持:
- 点击选择或拖入 CSV/XLSX 文件;
- 自动保存上传响应中的
dataset_id,无需手动复制; - 显示文件名称、行列数、缺失值、重复行和质量警告;
- 展示结构识别后的前 5 行数据;
- 使用“直接查询”调用单步骤 Text-to-SQL;
- 使用“综合分析”调用多步骤 Planning Graph;
- 展示自然语言回答、SQL、查询结果、分析步骤和生成的 PNG 图表;
- 在同一浏览器标签页刷新时恢复当前数据集。
浏览器只保存 dataset_id,数据仍由当前 FastAPI 进程管理。服务重启后旧
dataset_id 会失效,需要重新上传文件。页面不加载外部前端资源,也不改变现有 API、
MCP 或 Agent 的调用边界。
API
| 方法 | 路径 | 作用 |
|---|---|---|
| GET | /health |
健康检查 |
| GET | / |
本地上传和自然语言分析页面 |
| POST | /api/datasets/upload |
上传 CSV/XLSX |
| GET | /api/datasets/{dataset_id} |
概况和 Profile |
| GET | /api/datasets/{dataset_id}/schema |
DuckDB Schema |
| GET | /api/datasets/{dataset_id}/preview |
最多 5 行预览 |
| POST | /api/query |
手动只读 SQL |
| POST | /api/agent/query |
单步骤 Text-to-SQL |
| POST | /api/agent/analyze |
多步骤分析、报告和图表 |
| GET | /api/agent/analyze/{thread_id}/state |
最新状态摘要 |
| GET | /api/agent/analyze/{thread_id}/history |
Checkpoint 历史摘要 |
完整演示流程
项目提供 sample_data/sales_demo.csv:
region,product,sales,profit,sale_date
华东,A,120,20,2026-01-01
华南,B,90,-5,2026-01-02
华东,C,80,10,2026-01-03
华北,D,60,8,2026-01-04
以下命令中的 dataset_xxx 和 analysis_xxx 需要替换为上一步响应中的真实值。
1. 上传数据
curl -X POST http://127.0.0.1:8000/api/datasets/upload \
-F "file=@sample_data/sales_demo.csv"
2. 查看 Profile、Schema 和 Preview
curl http://127.0.0.1:8000/api/datasets/dataset_xxx
curl http://127.0.0.1:8000/api/datasets/dataset_xxx/schema
curl http://127.0.0.1:8000/api/datasets/dataset_xxx/preview
3. 手动 SQL
curl -X POST http://127.0.0.1:8000/api/query \
-H "Content-Type: application/json" \
-d '{
"dataset_id": "dataset_xxx",
"sql": "SELECT region, SUM(sales) AS total_sales FROM dataset_xxx GROUP BY region ORDER BY total_sales DESC"
}'
4. 单步骤 Agent
curl -X POST http://127.0.0.1:8000/api/agent/query \
-H "Content-Type: application/json" \
-d '{
"dataset_id": "dataset_xxx",
"question": "各地区总销售额分别是多少?"
}'
5. 多步骤分析和图表
curl -X POST http://127.0.0.1:8000/api/agent/analyze \
-H "Content-Type: application/json" \
-d '{
"dataset_id": "dataset_xxx",
"question": "分析各地区销售表现,并找出利润最低的商品。"
}'
响应包含:
thread_id;- 规划摘要和每个步骤结果;
- 综合报告;
chart或chart_error;- 成功、失败步骤数量和整体状态。
PNG 文件路径位于 chart.file_path。当前没有图表下载 API。
6. State 和 History
curl http://127.0.0.1:8000/api/agent/analyze/analysis_xxx/state
curl http://127.0.0.1:8000/api/agent/analyze/analysis_xxx/history
7. 重启后查询旧 thread
停止并重新启动 Uvicorn,保持 CHECKPOINT_DB_PATH 不变,再次调用上面的 State 和
History 接口即可读取旧 checkpoint。旧 dataset_id 不会恢复,因为 DatasetService
和 DuckDB 注册仍保存在内存中。
测试与验收
python -m compileall app tests
pytest -q
python -m pip check
当前验收结果:
134 passed
No broken requirements found.
tests/test_project_acceptance.py 使用确定性的 Mock LLM 和模拟销售数据完整验证:上传、
Profile、手动 SQL、单步骤 Agent、多步骤分析、PNG、State、History 和应用重启后读取旧
thread。测试不会发送真实网络请求,也不会写入默认 checkpoint 数据库。
当前限制
- 数据集元数据和 DuckDB 注册只在当前进程内,服务重启后不会恢复;
- Excel 当前只分析第一个工作表和其中一个主要表格;低置信度结构需要人工核对 Preview;
- Checkpoint 持久化不等于 Resume,目前不能从中断节点继续;
- SQL 安全采用保守的词法规则,不是完整 SQL AST 沙箱;
- SQLite 适合单机原型,不适合高并发、多实例和高可用部署;
- 没有用户认证、权限隔离、配额、上传大小限制和审计日志;
- 本地页面面向单用户开发演示,不包含登录、会话共享或生产级文件访问控制;
- 没有结构化日志、请求关联 ID、指标或分布式追踪;
- Planner 步骤互相独立,不能消费前一步查询结果;
- 每次分析最多生成一张确定性 bar/line 图;
- 没有图表下载接口、历史清理或 checkpoint 删除;
- 没有 Resume、Interrupt、人工审批、异步 Worker、Redis 或 PostgreSQL;
- DeepSeek API 的延迟、费用、余额和模型可用性取决于外部服务。
更详细的验收结论见 ACCEPTANCE_REPORT.md,分阶段开发记录见 WORKLOG.md。
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。