← 返回 产品架构 · 技术文档 接口文档

FinQuery · 企业智能数据分析平台

数据分析助手

基于 LangChain 多 Agent 设计范式构建的企业级 Excel 智能分析系统。上传表格、自然语言提问,Multi-Agent 协作完成读表、计算、可视化与报告生成。

为邦德激光股份有限公司专属设计

核心优势

数字可验证

ReAct Agent 通过 CODE 动作在真实 DataFrame 上执行 Python,OBSERVATION 回传计算结果,DONE 报告引用真实数字,杜绝 LLM 幻觉。

🤖

LangChain 多 Agent

采用 Orchestrator 编排 + Tool 工具链 + Memory 记忆 + Context 上下文传递,完整实现 LangChain Multi-Agent 架构模式。

📊

Excel 原生理解

COM-First 读取策略,自动处理合并单元格、多 Sheet、公式与中文编码,生成 Rich Schema 注入 Agent Prompt。

📈

交互式图表

内置 6 种 Plotly 图表(折线/柱状/饼图/散点/热力/瀑布),关键词自动触发;Agent 亦可用 matplotlib 自由绑图,图表嵌入聊天气泡。

LangChain 多 Agent 架构

系统完整实现了 LangChain 生态中的 Multi-Agent 设计模式:Supervisor 编排、Tool Use、Memory、State 传递与 ReAct 推理-行动循环。各模块职责清晰、可独立扩展。

┌─────────────────────────────────────────────────────────────────────┐
│                     Supervisor Agent · Orchestrator                    │
│  协调 Context / Memory / AnalysisEngine / LLM,驱动 ReAct 主循环      │
└───────────────────────────────┬─────────────────────────────────────┘
                                │
        ┌───────────────────────┼───────────────────────┐
        ▼                       ▼                       ▼
┌───────────────┐     ┌─────────────────┐     ┌─────────────────┐
│ Context Agent │     │  Memory Agent   │     │  Analysis Agent │
│ ContextManager│     │ MemoryManager   │     │ AnalysisEngine  │
│ 多文件/多Sheet │     │ 项目记忆+自动记忆│     │ 工具路由+代码执行 │
│ DataFrame状态 │     │ 关键词相关性召回 │     │ 沙箱 Python REPL │
└───────┬───────┘     └────────┬────────┘     └────────┬────────┘
        │                      │                       │
        └──────────────────────┼───────────────────────┘
                               ▼
                    ┌─────────────────────┐
                    │   LLM Agent Gateway  │
                    │  双 Provider 热切换   │
                    │  internal / external │
                    └─────────────────────┘

LangChain 概念映射

LangChain 概念本系统实现源码位置
Agent / SupervisorOrchestrator — 主编排器,驱动 ReAct 循环,协调所有子模块agents/orchestrator.py
BaseAgent 接口BaseAgent 抽象类,定义 name / description / system_prompt / tools / processagents/base_agent.py
ToolBaseTool 及 DataProfiler / Statistics / Chart / PythonExecutortools/
Agent Executorhandle_message() — 最多 8 轮 ReAct 循环,解析 ACTION 并分发agents/orchestrator.py
MemoryMemoryManager — 项目记忆(长期)+ 自动记忆(相关性召回)memory/memory_manager.py
State / ContextContextManager — 跨 Agent 传递 DataFrame、Schema、元数据context/context_manager.py
LLM Chaincall_llm() — System Prompt + Messages → ChatCompletionagents/llm_client.py
Callbacksprogress_cb — 每轮推送 step / observation 事件到 SSE 流web/routes.py
Tool RouterAnalysisEngine.run() — 关键词路由到内置工具,预计算注入 Prompttools/analysis_engine.py

Agent 组件详解

1. Orchestrator(Supervisor Agent)

系统核心编排器,等价于 LangChain 中的 Supervisor / Agent Executor。接收用户消息后:

  • 调用 AnalysisEngine 预执行关键词匹配的内置工具
  • 通过 build_rich_schema() 构建完整数据 Schema 注入 System Prompt
  • MemoryManager 召回 top-5 相关历史记忆
  • 启动 ReAct 循环(最多 8 轮),每轮调用 LLM 并解析 ACTION
  • 分析完成后自动保存 Auto Memory 摘要

2. Context Agent(ContextManager)

管理当前分析会话的数据状态,在 Agent 间传递上下文(类似 LangChain Runnable State):

  • _tables — 多文件 × 多 Sheet 的 DataFrame 字典
  • _metadata — 文件存储路径、行数列数等元信息
  • _merge_maps — 合并单元格展开记录
  • get_active_df() — 当前活跃 Sheet 的 DataFrame(注入为 df 变量)

3. Memory Agent(MemoryManager)

双层记忆架构,对标 LangChain ConversationBufferMemory + 相关性检索:

  • 项目记忆(project) — 用户手动维护的长期业务背景,始终注入 Prompt
  • 自动记忆(auto) — 每次分析完成后自动保存摘要,按关键词相关性评分召回 top-K
  • 记忆持久化至 SQLite memory_entries 表,支持 tags 标签匹配

4. LLM Gateway(双模型 Agent)

运行时可在两套 LLM Provider 间热切换,无需重启服务:

internal公司内部模型(Bodor AI · Qwen3-235B),内网直连,适合敏感数据
externalOpenRouter 外部模型(xiaomi/mimo-v2.5-pro),适合复杂推理

支持 3 次指数退避重试、请求/响应 JSONL 全链路日志、OpenRouter 专属 HTTP-Referer 头。

Tool 工具链

所有工具继承 BaseTool 抽象类(对标 LangChain BaseTool),由 AnalysisEngine 按关键词路由自动调用。

工具触发关键词能力
DataProfilerTool质量、缺失、异常、重复、诊断缺失值统计、异常值检测、重复行分析、数据概览
StatisticsTool同比、环比、趋势、相关、结构、占比YoY/MoM 计算、趋势分析、相关性矩阵、结构分布
ChartTool图表、柱状、饼图、折线、可视化Plotly 交互式图表,输出 HTML 嵌入报告
Python REPL计算、汇总、groupby、pivot、排名沙箱执行 Agent 生成的 Python 代码,暴露 df / pd / np
ExcelReader(上传时自动)COM → openpyxl → xlrd 三级回退,合并单元格自动展开

路由优先级:内置工具(快、结构化)→ Python REPL(灵活、复杂逻辑)→ LLM 叙述(解读结果)。

图表可视化

系统内置完整的图表生成能力,支持 双通道出图:内置 ChartTool 自动绘图 + Agent 代码中 matplotlib 自定义绘图。图表以 Plotly 交互式 HTML 嵌入聊天气泡,支持缩放、悬停、图例切换。

通道一:ChartTool 自动绘图(内置工具)

当用户消息包含图表关键词(图表、柱状、饼图、折线、可视化、画图、散点等),AnalysisEngine 在 Agent 循环启动前自动调用 ChartTool,根据语义智能选择图表类型:

折线图 line

趋势 / 时间序列分析。触发词:趋势、折线、trend

柱状图 bar

对比 / 排名分析。支持垂直/水平、多组并列、Top-N 筛选

饼图 pie

占比 / 结构分析。触发词:饼、占比、结构。自动限制 ≤8 类

散点图 scatter

相关性 / 分布分析。大数据集自动采样至 5000 点

热力图 heatmap

多变量相关矩阵。触发词:热力、相关矩阵

瀑布图 waterfall

增减分解 / 利润桥分析。触发词:瀑布、增减

ChartTool 智能特性

自动轴检测根据列类型和唯一值数量,自动选择 X 轴和颜色分组维度
模糊列名匹配支持大小写不敏感、子串匹配,容错用户口语化列名
内置聚合group_by + agg_func(sum / mean / count / max / min)先聚合再绘图
多组对比color 维度支持最多 12 组,超出自动合并为 Other
Top-N 筛选柱状图/饼图自动取 Top 15,饼图超过 8 类自动截断
交互式输出Plotly HTML 嵌入聊天气泡,前端通过 Plotly.js 渲染,支持悬停/缩放

通道二:Agent 代码绘图(matplotlib)

ReAct 循环中 Agent 可在 CODE 动作里使用 matplotlib 自由绘图(已预配置中文字体)。适合复杂多子图、自定义样式等 ChartTool 无法覆盖的场景。代码中的 plt.show() 输出会被捕获并展示。

图表数据流

用户提问「画一个区域预算占比饼图」
        │
        ▼
AnalysisEngine 关键词命中 _CHART_KW
        │  自动选择 chart_type = "pie"
        │  检测 group_by 列(从消息中匹配列名)
        ▼
ChartTool.execute(df, chart_type="pie", group_by="区域", top_n=8)
        │  Plotly 生成交互式 HTML
        ▼
charts[] 随 Agent 结果返回
        │
        ├─ SSE done 事件 → chat.js appendMessage(reply, charts)
        ├─ 聊天气泡内嵌 Plotly 图表(.chart-inline)
        └─ 会话历史 metadata.charts 持久化,刷新后可回放

使用示例

「各区域销售额柱状图」自动 bar 图 + 按区域 group_by 聚合
「月度收入趋势折线图」自动 line 图 + 时间轴
「各部门预算占比饼图」自动 pie 图 + Top 8 部门
「画一个价格与销量的散点图」自动 scatter 图 + 采样
「用代码画分组箱线图」Agent CODE → matplotlib 自定义绑图

ReAct 推理-行动循环

对标 LangChain ReAct Agent:每轮 LLM 输出一个 ACTION,系统执行后返回 OBSERVATION,循环直至 DONE 或达到上限。

用户提问 THINK
规划分析路径
CODE
执行 Python
OBSERVATION
回传计算结果
DONE
生成 Markdown 报告

ACTION 解析兼容性

编排器支持多种 LLM 输出格式,确保不同模型的 Tool Call 均可正确解析:

  • 标准格式ACTION: THINK|CODE|DONE
  • MiniMax 格式<CODE>...</CODE> 自动转换为标准 Python 块
  • 裸代码块 — 无 ACTION 前缀的 ```python 自动识别为 CODE
  • 多 ACTION 截断 — 违反单 ACTION 规则时自动截断,只保留第一个

沙箱执行环境

可用变量df(活跃 Sheet)、df_<sheet名>(各 Sheet)、pdnp
输出捕获stdout 重定向,DataFrame 自动转 Markdown 表格
中文字体matplotlib 预配置 CJK 字体(Noto Sans CJK / 文泉驿等)
安全限制无文件系统 / 网络访问,代码在隔离 namespace 中 exec
日志每次执行记录至 data/code_logs/ JSONL

端到端数据流

用户浏览器
  │  POST /api/chat/stream  { message, session_id, file_ids }
  ▼
FastAPI 路由层
  │  ① 创建/验证 Session,保存用户消息到 SQLite
  │  ② 生成 task_id,注册后台任务 _TASKS[task_id]
  │  ③ 立即返回 { task_id, session_id }
  ▼
后台 Agent 任务 (_run_background_agent)
  │  ④ 并行加载 Excel → ContextManager.add_file()
  │  ⑤ 加载 MemoryManager + 聊天历史(最近 6 条,去重截断)
  │  ⑥ Orchestrator.handle_message() → ReAct 循环
  │     ├─ AnalysisEngine 预计算工具结果
  │     ├─ call_llm() × N 轮
  │     ├─ execute_code_from_reply() 沙箱执行
  │     └─ progress_cb → SSE 事件推送
  │  ⑦ 保存 Assistant 消息 + metadata(agent_steps, charts)
  │  ⑧ log_conversation() → data/chat_logs/ JSONL
  ▼
SSE 事件流  GET /api/task/{task_id}/events
  │  progress → step → observation → done / error
  ▼
前端 chat.js 实时渲染 → Markdown 报告 + Plotly 图表

SSE 事件类型

type说明关键字段
progress阶段进度(加载文件、历史、启动 Agent)step, text
stepAgent 动作(THINK / CODE / DONE)action, turn, text
observation代码执行结果turn, text
done分析完成reply, charts[], session_id
error分析失败text

记忆与上下文管理

会话上下文窗口

  • 保留最近 6 条历史消息
  • 用户消息全局去重(跨轮次)
  • Assistant 回复截断至 500 字符(节省 Token)
  • 连续重复 Assistant 消息自动合并

Rich Schema 注入

  • 每个 Sheet 生成变量名 df_<safe_name>
  • 列名、类型、非空数、示例值/统计量
  • 合并单元格展开状态标注
  • 前 3 行样本数据预览
  • 大表(>50K 行)自动提示分批处理

部署架构

                    用户浏览器
                        │ HTTPS
                        ▼
              finquery.lijichen.cn :443
                        │
              Xray SNI 路由(stream proxy)
                        │
                        ▼
              Nginx :4443 (SSL Termination)
                        │ proxy_pass
                        ▼
              fenxi.service (systemd)
              Uvicorn → FastAPI :7860
                        │
          ┌─────────────┼─────────────┐
          ▼             ▼             ▼
     SQLite DB    用户文件目录    JSONL 日志
  excel_analyst.db  data/users/   llm_logs/
                                  code_logs/
                                  chat_logs/
进程管理systemd fenxi.service,异常自动重启(RestartSec=3)
SSL 证书Let's Encrypt,通过 ACME Webroot 自动续期
文件限制单文件最大 50MB,支持 .xlsx / .xls / .csv
上传限制Nginx client_max_body_size 512MB

可观测性

日志类型路径记录内容
LLM 调用日志data/llm_logs/llm_log_YYYY-MM-DD.jsonlrequest_id, model, system_prompt, messages, response, duration, status
代码执行日志data/code_logs/code_exec_YYYY-MM-DD.jsonl完整 Python 代码、stdout 输出、成功/失败、耗时
对话日志data/chat_logs/chat_YYYY-MM-DD.jsonl用户问题、agent_steps、code_executions、最终回复、总轮次
服务日志journalctl -u fenxi启动、LLM 请求、错误堆栈、任务状态

安全设计

身份认证

JWT Token(HttpOnly Cookie),bcrypt 密码哈希,24 小时过期。所有 API 通过 get_current_user 依赖注入鉴权。

数据隔离

用户级文件目录 data/users/{id}/,数据库查询均带 user_id 过滤,会话/文件/记忆严格归属校验。

代码沙箱

Agent 生成的 Python 在受限 namespace 中执行,无网络/文件系统权限,stdout 截断至 4000 字符防溢出。

技术栈

Web 框架FastAPI 0.115 + Uvicorn(全异步 ASGI)
ORMSQLAlchemy 2.0 + aiosqlite(异步 SQLite)
Agent 架构LangChain 风格 Multi-Agent(Orchestrator + Tools + Memory + ReAct)
LLM 接入httpx 异步 HTTP · OpenAI 兼容 ChatCompletion API
数据分析Pandas 2.2 · NumPy 2.2 · SciPy 1.15 · Plotly 5.24
Excel 引擎win32com (COM) → openpyxl → xlrd → pandas 四级回退
认证python-jose (JWT) + passlib (bcrypt)
前端原生 HTML/CSS/JS · Marked.js (Markdown) · MathJax · Plotly.js
部署systemd + Nginx + Xray SNI + Let's Encrypt

接口文档

所有 API 均需登录认证(Cookie: access_token),管理员接口额外校验 is_admin。Base URL: https://finquery.lijichen.cn

认证

POST/api/login

用户登录,返回 JWT Cookie。

// Request
{ "username": "admin", "password": "admin123" }

// Response 200
{ "ok": true, "username": "admin", "display_name": "管理员" }
POST/api/logout

退出登录,清除 Cookie。

// Response 200
{ "ok": true }

健康检查

GET/health

服务健康检查(无需认证)。

// Response 200
{ "status": "ok", "version": "1.0.0" }

模型设置

GET/api/settings/provider

获取当前 LLM 提供方。

// Response 200
{ "provider": "internal", "label": "公司内部模型", "model": "Qwen3-235B-A22B" }
POST/api/settings/provider

切换 LLM 提供方(运行时热切换)。

// Request
{ "provider": "external" }   // "internal" | "external"

// Response 200
{ "provider": "external", "label": "外部模型", "model": "xiaomi/mimo-v2.5-pro" }

文件管理

GET/api/files

列出当前用户的所有活跃文件。

// Response 200
[
  {
    "id": 1, "name": "预算表.xlsx", "size": 102400,
    "type": "xlsx", "sheets": ["Sheet1", "汇总"],
    "rows": 500, "cols": 12, "uploaded_at": "2026-06-17T01:00:00"
  }
]
POST/api/files/upload

上传 Excel/CSV 文件(multipart/form-data,字段名 file)。

// Response 200
{
  "id": 1, "name": "预算表.xlsx", "sheets": ["Sheet1"],
  "rows": 500, "cols": 12, "reader": "openpyxl", "merge_count": 3
}
DELETE/api/files/{file_id}

软删除文件(标记 is_active=false)。

// Response 200
{ "ok": true }

会话管理

GET/api/sessions

列出用户所有活跃会话。

// Response 200
[{ "id": 1, "title": "区域预算分析", "created_at": "...", "updated_at": "..." }]
POST/api/sessions

创建新会话。

// Request
{ "title": "新对话" }

// Response 200
{ "id": 2, "title": "新对话" }
DELETE/api/sessions/{session_id}

软删除会话。

GET/api/sessions/{session_id}/messages

获取会话全部消息(含 agent_steps、charts 等 metadata)。

// Response 200
[
  {
    "id": 1, "role": "user", "content": "各区域预算占比?",
    "metadata": {}, "created_at": "..."
  },
  {
    "id": 2, "role": "assistant", "content": "## 分析报告\n...",
    "metadata": {
      "agent_steps": [{"action": "CODE", "turn": 1, "code": "...", "observation": "..."}],
      "agent_turns": 3,
      "charts": [{"type": "pie", "title": "区域占比", "html": "..."}]
    },
    "created_at": "..."
  }
]

智能分析(核心)

POST/api/chat/stream

推荐 — 异步流式分析。立即返回 task_id,通过 SSE 接收实时进度。

// Request
{
  "message": "按区域汇总预算并计算占比",
  "session_id": 1,          // 可选,不传则自动创建
  "file_ids": [1, 2]        // 要分析的文件 ID 列表
}

// Response 200(立即返回)
{ "task_id": "uuid-...", "session_id": 1 }

// 然后连接 SSE
GET /api/task/{task_id}/events?after=0
// Content-Type: text/event-stream

data: {"type":"progress","step":"load_files","text":"文件已就绪:预算表.xlsx"}
data: {"type":"step","action":"CODE","turn":1,"text":"执行代码中…"}
data: {"type":"observation","turn":1,"text":"区域  |  预算\n华东  |  1200\n..."}
data: {"type":"step","action":"DONE","turn":2,"text":"生成报告"}
data: {"type":"done","reply":"## 分析报告\n...","charts":[...],"session_id":1}
POST/api/chat

同步分析(阻塞等待,适合简单调用或脚本集成)。

// Request — 同 /api/chat/stream

// Response 200
{
  "session_id": 1,
  "reply": "## 分析报告\n...",
  "charts": [{ "type": "pie", "title": "区域占比", "html": "<div>..." }]
}

任务状态

GET/api/task/{task_id}/events

SSE 事件流。参数 after 为已接收事件索引,支持断线重连回放。

GET/api/task/{task_id}/resume

页面刷新后恢复任务。运行中返回 status=running,已完成返回完整 result。

// Response 200
{ "task_id": "...", "status": "done", "session_id": 1, "result": { "type": "done", "reply": "...", "charts": [] } }
GET/api/task/{task_id}/status

轻量轮询端点,检查任务状态和事件数量。

// Response 200
{ "task_id": "...", "status": "running", "session_id": 1, "event_count": 5, "result": null }

管理后台(需 is_admin)

GET/api/admin/users

列出所有用户及在线状态。

POST/api/admin/users

创建新用户。

// Request
{ "username": "user1", "password": "pass123", "display_name": "张三" }

// Response 200
{ "id": 2, "username": "user1" }
PUT/api/admin/users/{user_id}/toggle

启用/禁用用户账号。

// Response 200
{ "id": 2, "is_active": false }

错误码

401未登录或 Token 过期
403无管理员权限 / 账号已禁用
404会话 / 文件 / 任务不存在
400参数错误(空消息、文件格式不支持、文件过大等)