# AI Agent 企业经营数据分析系统 **Repository Path**: north-dream-testing/Business-Operation-Data-Analysis ## Basic Information - **Project Name**: AI Agent 企业经营数据分析系统 - **Description**: 面向企业经营场景的文本到sql数据分析 Agent。业务人员用自然语言向数据提问,系统智能生成只读 SQL、在真实数据库执行,并流式返回分析结论与可视化图表。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-24 - **Last Updated**: 2026-09-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 企业经营数据分析 - 智能 SQL 查询助手 > 面向企业经营场景的 Text-to-SQL 数据分析 Agent。业务人员用自然语言向数据提问,系统智能生成只读 SQL、在真实数据库执行,并流式返回分析结论与可视化图表。 [English README](./README.md) --- ## 目录 - [项目简介](#项目简介) - [核心特性](#核心特性) - [技术架构](#技术架构) - [技术栈](#技术栈) - [快速开始](#快速开始) - [Docker 一键部署(推荐)](#docker-一键部署推荐) - [本地开发部署](#本地开发部署) - [配置说明](#配置说明) - [界面预览](#界面预览) - [功能详解](#功能详解) - [三种对话模式](#三种对话模式) - [数据接入](#数据接入) - [人工审批(HITL)](#人工审批hitl) - [图表可视化](#图表可视化) - [分层知识库](#分层知识库) - [API 文档](#api-文档) - [项目结构](#项目结构) - [CI/CD](#cicd) - [常见问题](#常见问题) - [致谢](#致谢) - [许可证](#许可证) --- ## 项目简介 **企业经营数据分析** 是一款基于大语言模型的企业级数据分析工具。它解决了传统数据分析中"业务人员不懂 SQL、数据分析师响应慢"的核心痛点: - **业务人员**:用自然语言描述分析需求,系统自动生成并执行 SQL,返回结构化结果和可视化图表 - **数据分析师**:通过人工审批机制把控 SQL 质量,通过知识库沉淀业务口径,提升团队整体效率 - **管理者**:通过对话历史追溯分析过程,通过 Token 用量统计管控成本 系统基于 LangGraph 构建 Agent 编排引擎,支持会话持久化、中断恢复和主备模型自动降级,确保生产环境的稳定性和可靠性。 --- ## 核心特性 | 特性 | 说明 | |------|------| | **Agent 智能编排** | 基于 LangGraph 的 LLM-Tool 循环状态机,PostgreSQL Checkpointer 实现会话持久化与中断恢复 | | **Text-to-SQL** | Schema 内省序列化为 XML 注入 System Prompt,LLM Function Calling 生成 SQL,流式解析增量输出 | | **SQL 安全防护** | sqlglot AST 白名单校验,仅放行 SELECT 语句;Prompt 软约束 + 代码硬约束双层防御 | | **人工审批(HITL)** | 三级审批策略(无需审批 / 仅最终结果 / 每次都审批),支持人工修改 SQL 后二次校验执行 | | **图表可视化** | LLM 传递分析意图,工具重执行 SQL 获取真实数据生成图表,杜绝数据幻觉 | | **分层知识库** | 全局 SQL 方言规则 + 数据集 Schema 指纹绑定,业务口径确定性注入,跨业务零泄漏 | | **多源数据接入** | 支持 CSV/TSV/JSON/Parquet/Excel 文件上传,以及 PostgreSQL/MySQL 外部数据库直连 | | **流式实时输出** | SSE 事件流驱动打字机效果,工具执行状态与图表实时渲染 | | **对话历史管理** | 本地持久化存储,支持多会话切换,最多保留 50 条对话记录 | | **主备模型降级** | 主模型请求失败时自动切换备用模型,保障服务可用性 | --- ## 技术架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 用户浏览器 (Next.js) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ 设置面板 │ │ 聊天窗口 │ │ 输入组件 │ │ 图表渲染组件 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ └─────────────────────────────┬───────────────────────────────────┘ │ SSE 流式响应 ┌─────────────────────────────▼───────────────────────────────────┐ │ FastAPI 后端 (:8000) │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ LangGraph Agent │ │ │ │ ┌─────────┐ ┌──────────┐ ┌─────────────────────┐ │ │ │ │ │ LLM 节点 │───▶│ 条件路由 │───▶│ Tool 节点 │ │ │ │ │ │(Prompt │ │(tool_use?│ │ ┌─────────────────┐ │ │ │ │ │ │ 渲染+FC) │◀───│ yes/no) │ │ │QueryExecutor │ │ │ │ │ │ └─────────┘ └────────── │ │ sqlglot+HITL │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ │ │ChartGenerator │ │ │ │ │ │ │ │ 重执行SQL+校验 │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ └─────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────┘ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │ │ 知识库匹配器 │ │ 连接器服务 │ │ 配置/加密/限流 │ │ │ │ Schema指纹匹配 │ │ DuckDB/PG/MySQL│ │ Fernet加密/令牌桶 │ │ │ └──────────────┘ └──────────────┘ └──────────────────────┘ │ └─────────────────────────────┬───────────────────────────────────┘ │ ┌─────────────────────────────▼───────────────────────────────────┐ │ PostgreSQL 16 (元数据) DuckDB (内存分析引擎) │ │ ├─ api_keys (API 密钥管理) ├─ 文件上传表 (动态创建) │ │ ├─ connections (连接管理) └─ SQL 执行 (只读) │ │ ├─ schema_catalog (Schema缓存) │ │ ├─ query_history (查询历史) │ │ ├─ usage_events (用量统计) │ │ └─ checkpoint (LangGraph 会话状态) │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 技术栈 | 层级 | 技术 | |------|------| | **Agent 编排** | LangGraph + langgraph-checkpoint-postgres | | **后端框架** | FastAPI + uvicorn | | **LLM 接口** | AsyncOpenAI(兼容 DeepSeek / OpenAI 等) | | **本地分析引擎** | DuckDB(内存模式) | | **元数据存储** | PostgreSQL 16 + psycopg pool | | **SQL 安全** | sqlglot(AST 白名单校验) | | **凭证加密** | cryptography(Fernet 对称加密) | | **模板引擎** | Jinja2 | | **配置管理** | pydantic-settings v2 | | **日志** | loguru | | **前端框架** | Next.js 16 + React 19 + TypeScript | | **样式方案** | Tailwind CSS 4(暗色主题) | | **图表渲染** | ECharts 6 | | **Markdown** | react-markdown + remark-gfm | | **包管理** | uv(后端)+ npm(前端) | | **容器化** | Docker + docker-compose | | **CI/CD** | GitHub Actions → Google Cloud Run | | **代码质量** | ruff + mypy | --- ## 快速开始 ### Docker 一键部署(推荐) **前置要求**:Docker Desktop 20.10+、docker-compose v2+ ```bash # 1. 克隆项目 git clone cd text-to-sql-agent # 2. 配置环境变量 cp .env.example .env # 编辑 .env,填入以下必要配置: # - DB__PASSWORD:PostgreSQL 数据库密码 # - FERNET_KEY:凭证加密密钥(执行 python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" 生成) # - OPENAI_API_KEY:LLM API 密钥(支持 DeepSeek / OpenAI 等兼容接口) # - OPENAI_BASE_URL:LLM API 地址(默认 https://api.deepseek.com/v1) # 3. 启动服务 docker compose -f docker-compose.prod.yml up -d # 4. 初始化数据库(首次部署) docker compose -f docker-compose.prod.yml run --rm init-db # 5. 访问应用 # 前端:http://localhost:3000 # 后端 API:http://localhost:8000 # 健康检查:http://localhost:8000/v1/api/health ``` **服务组成**: | 服务 | 端口 | 说明 | |------|------|------| | frontend | 3000 | Next.js 前端应用 | | backend | 8000 | FastAPI 后端服务 | | postgres | 5432 | PostgreSQL 16 数据库 | | init-db | - | 数据库初始化(一次性任务) | ### 本地开发部署 **前置要求**:Python 3.12+、Node.js 20+、PostgreSQL 16+ ```bash # 1. 后端 uv sync cp .env.example .env # 配置数据库和 LLM uv run python server.py # 启动后端 http://localhost:8000 # 2. 前端 cd frontend npm install npm run dev # 启动前端 http://localhost:3000 ``` --- ## 配置说明 ### 环境变量(.env) ```bash # ─── PostgreSQL 数据库 ─── DB__HOST=localhost DB__PORT=5432 DB__DATABASE=text_to_sql DB__USER=postgres DB__PASSWORD=your_password # 必填 DB__SCHEMA_NAME=public DB__POOL_MIN_SIZE=0 DB__POOL_MAX_SIZE=5 # ─── 凭证加密 ─── FERNET_KEY=your_fernet_key # 生产环境必填 # ─── 运行环境 ─── ENVIRONMENT=development # development | production # ─── CORS 跨域 ─── CORS_ORIGINS=* # 逗号分隔,* 表示允许所有 # ─── LLM 配置(OpenAI 兼容接口)─── OPENAI_API_KEY=your_api_key # 必填 OPENAI_BASE_URL=https://api.deepseek.com/v1 # ─── LangSmith 追踪(可选)─── LANGSMITH_TRACING=false LANGSMITH_ENDPOINT=https://api.smith.langchain.com LANGSMITH_API_KEY= LANGSMITH_PROJECT= ``` > **注意**:嵌套配置使用 `__` 作为分隔符(如 `DB__HOST` 映射到 `db.host`),这是 pydantic-settings 的标准约定。 --- ## 界面预览 ### 主界面 系统采用暗色主题设计,左侧为设置面板,右侧为对话区域。 ![主界面](docs/screenshots/01_main_page.png) > 初始状态下,需先配置接口密钥才能使用全部功能。 ### 数据源配置 配置接口密钥后,侧边栏展开数据来源配置区域,支持两种数据接入方式: **文件上传** — 拖拽或点击上传数据文件: ![文件上传](docs/screenshots/03_file_upload.png) **数据库连接** — 配置外部数据库连接信息: ![数据库连接](docs/screenshots/04_db_connection.png) ### 数据表结构 连接数据源后,Schema 查看器展示所有数据表及其字段结构: ![Schema 查看器](docs/screenshots/05_schema_viewer.png) ### 智能对话 支持三种对话模式,底部工具栏可快速切换: ![对话界面](docs/screenshots/06_chat_interface.png) > **注意**:查询结果、图表可视化、人工审批和对话历史等功能需要配置有效的 LLM API 密钥后才能使用。配置完成后,系统会流式返回 SQL 执行结果、自动生成可视化图表,并在审批策略开启时展示人工确认面板。 --- ## 功能详解 ### 三种对话模式 | 模式 | 触发方式 | 说明 | |------|----------|------| | **生成查询** | 默认模式 | 输入自然语言问题,系统自动生成 SQL、执行查询、返回分析结论和图表 | | **解释 SQL** | 点击"解释 SQL"按钮 | 粘贴已有 SQL 语句,系统逐句解释每个子句、函数、JOIN 的业务含义 | | **优化 SQL** | 点击"优化 SQL"按钮 | 粘贴已有 SQL 语句,系统分析性能瓶颈,提供优化版本和索引建议 | ### 数据接入 #### 文件上传 支持以下文件格式,上传后自动创建 DuckDB 内存表: | 格式 | 扩展名 | 处理方式 | |------|--------|----------| | CSV | `.csv` | 编码自动归一化(UTF-8 / GB18030 / GBK → UTF-8) | | TSV | `.tsv` | 制表符分隔,编码自动归一化 | | JSON | `.json` | 自动推断 JSON 结构 | | NDJSON | `.jsonl` / `.ndjson` | 逐行 JSON 解析 | | Parquet | `.parquet` | 列式存储直接读取 | | Excel | `.xlsx` / `.xls` | 每个 Sheet 独立建表 | #### 数据库连接 支持连接外部 PostgreSQL 和 MySQL 数据库: - 凭证使用 Fernet 对称加密存储,明文不落库 - 连接信息包含:主机地址、端口、数据库名、用户名、密码 - PostgreSQL 额外支持指定 Schema - 连接建立后自动内省 Schema 并缓存 ### 人工审批(HITL) 系统提供三级审批策略,在 SQL 安全性和操作便捷性之间取得平衡: | 策略 | 行为 | 适用场景 | |------|------|----------| | **无需审批** | 所有 SQL 直接执行 | 开发测试环境、可信数据源 | | **仅最终结果** | 仅 `purpose=final` 的查询需审批 | 生产环境常规使用 | | **每次都审批** | 所有查询(含中间探索)都需审批 | 高安全要求场景 | **审批流程**: 1. LLM 生成 SQL 时附带 `explanation`(查询说明)和 `purpose`(用途标签) 2. 触发中断 → 前端展示审批面板 3. 用户可选择: - **执行原始 SQL**:直接通过审批 - **修改后执行**:编辑 SQL 并填写修改原因,修改后二次校验只读性 4. 审批通过后恢复 Agent 执行 ### 图表可视化 系统支持五种图表类型,LLM 仅传递分析意图,工具重执行 SQL 获取真实数据: | 图表类型 | 适用场景 | 特殊处理 | |----------|----------|----------| | **柱状图** (bar) | 分类数据对比 | — | | **折线图** (line) | 时间序列趋势 | — | | **面积图** (area) | 累积量/趋势 | — | | **饼图** (pie) | 占比分析 | 超过 10 个分片自动合并为"其他" | | **散点图** (scatter) | 两数值变量相关性 | — | - 单次最多展示 200 行数据,超出自动截断 - 自动适配暗色主题配色 ### 分层知识库 系统采用两层知识库架构,实现业务知识的精准注入: ``` ┌─────────────────────────────────────────┐ │ 全局层 (Global) │ │ sql_dialect.yaml │ │ · 引号规范 · 除法防零 · 周口径 · LIMIT │ │ → 无条件注入所有 Prompt │ └─────────────────┬───────────────────────┘ │ Schema 指纹匹配 ┌─────────────────▼───────────────────────┐ │ 数据集层 (Datasets) │ │ manifest.yaml │ │ · required_columns (必需字段) │ │ · optional_columns (可选字段) │ │ · min_coverage (最低覆盖率 0.8) │ │ │ │ L1 口径层 → 匹配成功完整注入 │ │ · 指标公式 · SQL 模板 · 别名 · 陷阱 │ │ │ │ L2 FAQ 层 → 预留向量检索接口 │ └─────────────────────────────────────────┘ ``` **核心原则**:未匹配的数据源不会注入任何业务知识,确保跨业务场景零泄漏。 --- ## API 文档 所有 API 端点统一前缀 `/v1/api`,通过 `X-API-Key` 请求头认证。 ### 对话接口 | 方法 | 端点 | 说明 | |------|------|------| | POST | `/stream/{user_id}/{thread_id}` | 发起对话(SSE 流式响应) | | POST | `/stream/{user_id}/{thread_id}/resume` | HITL 审批后恢复执行(SSE) | **对话请求体**: ```json { "message": "显示上个月销售额最高的前10个产品", "mode": "generate", "interrupt_policy": "final", "model_settings": { "primary_model": "deepseek-chat", "secondary_model": "deepseek-chat" } } ``` **SSE 事件类型**: | 事件 | 说明 | |------|------| | `text` | 文本增量(打字机效果) | | `tool-input` | 工具调用输入增量 | | `tool-output` | 工具执行结果 | | `block-start` / `block-end` | 内容块标记 | | `__interrupt__` | HITL 审批中断 | | `complete` | 对话完成 | | `error` | 错误信息 | ### 数据管理 | 方法 | 端点 | 说明 | |------|------|------| | POST | `/data/upload` | 上传数据文件(支持多文件) | | GET | `/data/tables` | 列出所有数据表 | | DELETE | `/data/tables/{name}` | 删除指定表 | | DELETE | `/data/tables` | 清空所有表 | ### 数据库连接 | 方法 | 端点 | 说明 | |------|------|------| | POST | `/connections` | 创建数据库连接 | | GET | `/connections` | 列出所有连接 | | POST | `/connections/{id}/test` | 测试连接 | | DELETE | `/connections/{id}` | 删除连接(软删除) | | GET | `/connections/{id}/catalog` | 获取 Schema 缓存 | | POST | `/connections/{id}/catalog/refresh` | 刷新 Schema 缓存 | | GET | `/connections/{id}/history` | 查询历史(分页) | | POST | `/connections/{id}/history/{qid}/save` | 收藏查询 | ### 系统管理 | 方法 | 端点 | 说明 | |------|------|------| | GET | `/health` | 健康检查 | | POST | `/keys` | 创建 API Key | | GET | `/keys` | 列出 API Keys | | DELETE | `/keys/{id}` | 撤销 API Key | | GET | `/usage` | Token 用量(按天分组) | | GET | `/usage/summary` | 当月用量汇总 | --- ## 项目结构 ``` text-to-sql-agent/ ├── server.py # FastAPI 应用入口 ├── run_server.py # 启动脚本(含 Windows 兼容) ├── pyproject.toml # Python 项目配置(uv 管理) ├── Makefile # 构建/运行/代码质量快捷命令 ├── Dockerfile # 后端 Docker 镜像(多阶段构建) ├── docker-compose.prod.yml # 生产环境 Docker Compose 编排 ├── .env.example # 环境变量模板 │ ├── src/app/ │ ├── api/ │ │ ├── dependencies.py # 依赖注入(API Key 认证、图/工具/知识库获取) │ │ ├── lifespan.py # FastAPI 生命周期管理 │ │ ├── rate_limit.py # 令牌桶限流中间件(60 RPM) │ │ └── routers/ │ │ ├── chat.py # 对话流式接口 + HITL resume │ │ ├── data.py # 文件上传(CSV/Excel/Parquet 等) │ │ ├── connections.py # 外部数据库连接管理(CRUD) │ │ ├── catalog.py # Schema 缓存/刷新 │ │ ├── history.py # 查询历史 │ │ ├── keys.py # API Key 管理 │ │ ├── usage.py # Token 用量统计 │ │ └── health.py # 健康检查 │ │ │ ├── graphs/chat/ # LangGraph Agent 编排 │ │ ├── graph.py # 图定义(create_chat_graph) │ │ ├── state.py # 状态定义(ChatGraphState) │ │ ├── edges.py # 条件边(is_tool_call 路由) │ │ └── nodes/ │ │ ├── llm.py # LLM 节点(流式解析、主备降级) │ │ └── tool.py # Tool 节点(工具调度) │ │ │ ├── tools/ │ │ ├── handler.py # ToolHandler(工具注册/调度) │ │ ├── db.py # QueryExecutorTool(SQL 执行 + HITL) │ │ └── chart.py # ChartGeneratorTool(图表生成) │ │ │ ├── connectors/ # 数据库连接器 │ │ ├── base.py # 抽象基类 │ │ ├── duckdb_connector.py # DuckDB(文件上传分析) │ │ ├── postgres.py # PostgreSQL(asyncpg) │ │ ├── mysql.py # MySQL(aiomysql) │ │ └── service.py # ConnectionService(加密/内省/缓存) │ │ │ ├── knowledge/ │ │ └── matcher.py # KnowledgeMatcher(Schema 指纹匹配) │ │ │ ├── config/ │ │ ├── settings.py # pydantic-settings 配置 │ │ ├── database.py # PostgreSQL 连接配置模型 │ │ └── paths.py # 路径配置 │ │ │ ├── crypto/ │ │ └── fernet.py # Fernet 对称加密/解密 │ │ │ ├── db/ │ │ ├── pool.py # PostgreSQL 连接池 │ │ └── query_store.py # SQL DDL 文件加载器 │ │ │ ── utils/ │ └── prompts_utils.py # Jinja2 Prompt 模板加载 │ ├── prompts/ │ └── system.jinja2 # System Prompt 模板(三种模式) │ ├── queries/ddl/ # PostgreSQL DDL 脚本 │ ├── create_schema.sql │ ├── create_api_keys.sql │ ├── create_connections.sql │ ├── create_schema_catalog.sql │ ├── create_query_history.sql │ ├── create_usage_events.sql │ ── create_indexes.sql │ ├── knowledge_base/ # 分层知识库 │ ├── global/ │ │ └── sql_dialect.yaml # 全局 SQL 方言规则 │ └── datasets/ │ ── banyuan_delivery/ # 示例数据集 │ ├── manifest.yaml # Schema 指纹 + 知识文件登记 │ ── metrics/ # L1 指标口径定义 │ ├── scripts/ │ └── initialize_db.py # 数据库初始化脚本 │ ├── frontend/ # Next.js 前端应用 │ ├── Dockerfile │ ├── next.config.ts │ └── src/ │ ├── app/ │ │ ├── layout.tsx # 根布局(字体、元数据) │ │ └── page.tsx # 主页面(侧边栏 + 聊天区) │ ├── components/ │ │ ├── SetupPanel.tsx # 设置面板(API Key + 数据来源) │ │ ├── ApiKeyInput.tsx # API Key 输入组件 │ │ ├── CsvUpload.tsx # 文件上传(拖拽 + 点击) │ │ ├── ConnectionForm.tsx # 数据库连接表单 │ │ ├── SchemaViewer.tsx # Schema 浏览器 │ │ ├── ChatWindow.tsx # 聊天窗口(SSE + HITL + 历史) │ │ ├── ChatInput.tsx # 输入框(模式切换 + 审批策略) │ │ ├── MessageBubble.tsx # 消息气泡(Markdown + SQL + 表格) │ │ └── ChartBlock.tsx # ECharts 图表渲染 │ └── lib/ │ ├── api.ts # API 调用封装 │ ├── sse.ts # SSE 流式解析器 │ └── types.ts # TypeScript 类型定义 │ └── .github/workflows/ ├── ci.yaml # CI:lint + format + mypy └── cd.yaml # CD:构建镜像 → 部署 Cloud Run ``` --- ## CI/CD ### 持续集成(CI) 推送或 PR 到 `main` 分支时自动触发: ``` uv sync → ruff check → ruff format --check → uv lock --check → mypy ``` ### 持续部署(CD) CI 通过后自动或手动触发: ``` Google Cloud 认证 → 构建 Docker 镜像 → 推送 Artifact Registry → 部署 Cloud Run → Smoke Test(curl /health/liveness) ``` 密钥通过 Google Secret Manager 安全注入。 --- ## 常见问题 ### Q: 支持哪些 LLM 服务商? 系统使用 OpenAI 兼容接口,理论上支持所有提供 OpenAI 格式 API 的服务商,包括 DeepSeek、OpenAI、Azure OpenAI、本地部署的 vLLM / Ollama 等。通过配置 `OPENAI_BASE_URL` 和 `OPENAI_API_KEY` 切换。 ### Q: 如何添加新的业务知识? 在 `knowledge_base/datasets/` 下创建新数据集目录,编写 `manifest.yaml` 定义 Schema 指纹,在 `metrics/` 下添加指标口径定义文件(YAML 格式)。详见 [知识库架构规范](knowledge_base/README.md)。 ### Q: SQL 执行安全如何保障? 系统采用双层防护: 1. **Prompt 层**:System Prompt 明确要求只生成 SELECT 语句 2. **代码层**:sqlglot AST 解析,白名单仅允许 SELECT,拒绝所有 DDL/DML 操作 ### Q: 如何备份和恢复数据? PostgreSQL 数据通过 Docker Volume 持久化在 `pgdata` 卷中。可使用 `pg_dump` / `pg_restore` 进行备份恢复: ```bash # 备份 docker exec text-to-sql-agent-postgres-1 pg_dump -U postgres text_to_sql > backup.sql # 恢复 docker exec -i text-to-sql-agent-postgres-1 psql -U postgres text_to_sql < backup.sql ``` ### Q: 前端构建耗时较长怎么办? Windows Docker Desktop 环境下前端构建(`npm ci`)可能需要 20-30 分钟,这是已知性能问题。Linux/macOS 环境下通常只需 2-3 分钟。建议使用 Linux 环境进行开发部署。 ---