从零开发 AIDataReport 智能数据报表工具|工程脚手架

从零开发 AIDataReport 智能数据报表工具|工程脚手架

1. 本篇要解决什么

前两篇把「为什么做」和「MVP 做什么」说清楚了。从这篇开始进入开发。

工程上第一刀不要 直接写 Text2SQL,也不要先接大模型。先把骨架立住:

  1. 有清晰的包结构,后面模块往哪放一目了然
  2. 有统一的运行时配置(环境变量 / .env
  3. 本地能一键拉起系统配置库 PostgreSQL
  4. FastAPI 能启动,并且 /health 能探活

2. 技术选型(脚手架相关,一句带过)

和 MVP 文档对齐,脚手架阶段用到的选型如下:

选型 本篇用途
语言 Python 3.12 运行时
API FastAPI + Uvicorn HTTP 入口
系统库 PostgreSQL 16(Docker Compose) 存租户/项目/配置/审计(后续篇)
配置 pydantic-settings + .env 统一读环境变量
包管理 pyproject.toml + requirements.txt 可编辑安装与依赖锁定习惯
CLI Typer(入口先挂上) 后续 init-db / config / query

记住一个关键区分:

  • 系统配置库:平台自己的库,存 Tenant / Project / Agent / 配置发布 / 审计
  • 业务只读库:实施对接的销售库等,由配置里的 DataSource 描述,账号必须只读

3. 仓库目录怎么规划

从第一天就按「能力边界」分目录,而不是按「先写一堆 scripts」。当前目标结构如下:

text 复制代码
ai-data-report/
├── configs/demo/sales/     # 销售试点 Demo 配置包(后续篇)
├── docs/                   # 系列文章
├── src/bi_agent/           # 主包(src layout)
│   ├── domain/             # 配置契约、问数请求、ExecutionPlan
│   ├── db/                 # 系统库 ORM、会话、建表
│   ├── config_service/     # 校验、YAML、发布仓储
│   ├── compiler/           # 配置驱动 SQL 编译
│   ├── reviewer/           # SQL 安全审核
│   ├── executor/           # 只读执行 Report Service
│   ├── formatter/          # JSON / Excel
│   ├── audit/              # 审计写入
│   ├── agent/              # 百炼 NL(阶段 4)
│   ├── api/routes/         # FastAPI 路由
│   ├── pipeline.py         # 端到端编排(API/CLI 共用)
│   ├── cli.py              # Typer CLI
│   ├── settings.py         # 运行时配置
│   └── main.py             # ASGI 入口
├── tests/
├── docker-compose.yml
├── .env.example
├── pyproject.toml
├── requirements.txt
└── README.md

为什么用 src/ 布局:

  • 强制「安装后再导入」,避免在仓库根目录误 import 到半成品路径
  • pytestpythonpath = ["src"]、可编辑安装 pip install -e . 配合自然

4. 声明项目与依赖

4.1 pyproject.toml(项目元数据 + 入口)

核心点:

  • 包名:bi-agent(CLI 命令同名)
  • 代码在 src/
  • 控制台脚本:bi-agent = bi_agent.cli:app
  • pytest 直接认 src

精简示意:

toml 复制代码
[project]
name = "bi-agent"
version = "0.1.0"
description = "Configurable enterprise BI Agent platform (MVP)"
requires-python = ">=3.10"
dependencies = [
  "fastapi>=0.115.0,<1.0.0",
  "uvicorn[standard]>=0.32.0,<1.0.0",
  "sqlalchemy>=2.0.36,<3.0.0",
  "psycopg[binary]>=3.2.0,<4.0.0",
  "pydantic>=2.9.0,<3.0.0",
  "pydantic-settings>=2.6.0,<3.0.0",
  "pyyaml>=6.0.2,<7.0.0",
  "sqlglot>=25.0.0,<30.0.0",
  "openpyxl>=3.1.5,<4.0.0",
  "typer>=0.12.0,<1.0.0",
  "httpx>=0.27.0,<1.0.0",
  "python-dotenv>=1.0.1,<2.0.0",
]

[project.scripts]
bi-agent = "bi_agent.cli:app"

[tool.setuptools.package-dir]
"" = "src"

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]

4.2 requirements.txt

开发时也可以直接:

bash 复制代码
pip install -r requirements.txt
pip install -e .

若可编辑安装失败,临时方案:

bash 复制代码
# Windows PowerShell
$env:PYTHONPATH="src"

5. 运行时配置:settings.py + .env

把「连哪套系统库、LIMIT 上限、超时」集中到一处,后续 Reviewer / Executor 都从这里读阈值,避免魔法数散落。

python 复制代码
# src/bi_agent/settings.py(核心结构)
from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    # 系统配置库(不是业务只读库)
    database_url: str = "postgresql+psycopg://bi_agent:bi_agent@localhost:5432/bi_agent"
    app_env: str = "dev"
    log_level: str = "INFO"

    # 查询安全阈值
    default_query_limit: int = 1000
    max_query_limit: int = 10000
    query_timeout_seconds: int = 30
    max_sql_length: int = 20000

    # 百炼:阶段 4 再填,MVP 可留空
    bailian_api_key: str = ""
    bailian_base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1"
    bailian_model: str = "qwen-plus"

@lru_cache
def get_settings() -> Settings:
    return Settings()

配套 .env.example(复制为 .env 即可本地开发):

env 复制代码
DATABASE_URL=postgresql+psycopg://bi_agent:bi_agent@localhost:5432/bi_agent
APP_ENV=dev
LOG_LEVEL=INFO
DEFAULT_QUERY_LIMIT=1000
MAX_QUERY_LIMIT=10000
QUERY_TIMEOUT_SECONDS=30
MAX_SQL_LENGTH=20000
BAILIAN_API_KEY=
BAILIAN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
BAILIAN_MODEL=qwen-plus

6. FastAPI 空壳:main + /health

6.1 应用工厂

create_app() 而不是只写一个全局 app,测试里可以反复创建、互不污染:

python 复制代码
# src/bi_agent/main.py
from fastapi import FastAPI
from bi_agent import __version__
from bi_agent.api.routes import config, health, query

def create_app() -> FastAPI:
    app = FastAPI(
        title="BI Agent",
        description="可配置的企业报表 Agent 平台(MVP)",
        version=__version__,
    )
    # 探活挂根路径;业务 API 统一 /api/v1
    app.include_router(health.router)
    app.include_router(config.router, prefix="/api/v1")
    app.include_router(query.router, prefix="/api/v1")
    return app

app = create_app()

6.2 健康检查

python 复制代码
# src/bi_agent/api/routes/health.py
from fastapi import APIRouter
from bi_agent import __version__

router = APIRouter(tags=["health"])

@router.get("/health")
def health() -> dict[str, str]:
    return {"status": "ok", "version": __version__}

包版本集中在一处:

python 复制代码
# src/bi_agent/__init__.py
__version__ = "0.1.0"

6.3 第一个测试

探活是最便宜的回归保护:

python 复制代码
# tests/test_health.py
from fastapi.testclient import TestClient
from bi_agent.main import create_app

def test_health() -> None:
    client = TestClient(create_app())
    resp = client.get("/health")
    assert resp.status_code == 200
    assert resp.json()["status"] == "ok"

7. 动手验证(本篇验收)

环境要求:Python 3.12+(推荐)。

bash 复制代码
# 1) 虚拟环境
python -m venv .venv

# Windows
.venv\Scripts\activate

# macOS / Linux
# source .venv/bin/activate

python --version   # 建议 3.12.x+

# 2) 依赖
pip install -r requirements.txt
pip install -e .

# 3) 环境变量
copy .env.example .env          # Windows
# cp .env.example .env          # macOS / Linux

# 4) 启动 API
uvicorn bi_agent.main:app --reload --app-dir src

另开终端:

bash 复制代码
curl http://127.0.0.1:8000/health

期望类似:

json 复制代码
{"status":"ok","version":"0.1.0"}

跑测试:

bash 复制代码
pytest tests/test_health.py -q

8. 小结与下篇预告

本篇完成了 AIDataReport(BI Agent)开发阶段的第一步:

  1. src/bi_agent 按能力拆模块
  2. 用 pydantic-settings 统一运行时配置
  3. 用 Docker Compose 拉起系统 PostgreSQL
  4. 用 FastAPI 应用工厂 + /health 证明进程活着

下一篇 《语义配置模型与系统库落库》 会回答:

  • 租户 → 项目 → Agent 如何建模
  • DataSource / Dataset / Join / Metric / Dimension 的配置怎么写
  • 领域模型(Pydantic)和 ORM 表如何分离
  • bi-agent init-db 如何把系统表建出来

发帖纯粹个人记录与技术交流,欢迎各位同行大佬围观、指点问题,也欢迎同好一起交流探讨,一起学习进步

相关推荐
小流苏生4 小时前
“《关于我妈说我又老又丑又穷已经没有女生会看得上我了这件事情》”
程序员
CodeSheep13 小时前
稚晖君公司人事大变动,来了!
前端·后端·程序员
潘高21 小时前
做一个鸿蒙倒班应用时,我踩过的 4 个“看起来很简单”坑
程序员
程序员cxuan1 天前
Pi + DeepSeek-v4-Flash,这用着也太爽了。
人工智能·后端·程序员
程序员cxuan1 天前
Claude Opus 5 的系统提示词被扒出来了
人工智能·后端·程序员
AskHarries1 天前
为什么产品没人用
程序员
Patrick_Wilson2 天前
代码重构中的蚕食方式是什么
程序员·架构·代码规范
Patrick_Wilson2 天前
你知道 git check 的故事吗
git·程序员·命令行
SemiTris2 天前
为什么 C/C++ 不走 Java 式的虚拟机跨平台路线?
java·程序员