跳到主要内容

PandasAI — 这是什么 / 全景图 / 主线 / 阅读地图

30 秒导读: PandasAI 让你用大白话向一张表(或一个数据库)提问——"哪个国家收入最高?"、"画一张按月的销量图"。它把你的问题交给大模型,大模型生成一段 Python 代码,这段代码里所有取数都必须走一个叫 execute_sql_query 的函数;PandasAI 校验、清洗这段代码后执行(默认在本地 DuckDB 上跑 SQL),最后把结果包装成数字 / 字符串 / 表格 / 图四种响应之一还给你。

本章只做路由与直觉:让你先知道"这是什么、大概怎么转、精华在哪、接下来该读哪一章",不深入任何单个机制的实现。


1. 这是什么(零基础也能懂)

一句话定义: PandasAI 是一个把"自然语言问数据"翻译成"生成并执行代码"的 Python 库——你问,它让 LLM 写代码,它执行代码给你答案。

解决什么问题 / 给谁用: 假设你手里有一个 CSV 或一张数据库表,你想知道"销量最高的三个地区是哪些",但你不想手写 df.groupby(...).sum().sort_values(...),也不想拼 SQL。PandasAI 让你直接用中文/英文问,它替你把代码写出来并跑掉。既服务不会写代码的业务人,也帮会写代码的人省事。

它能做什么:

  • 对一个或多个 dataframe 用自然语言提问、追问(多轮对话)。
  • 从 CSV / Excel 读数据,或连接远程 SQL 数据源(Postgres、MySQL 等)。
  • 把数据集保存为带 schema 的数据集(语义层),甚至跨表建"视图"。
  • 返回四类结果:一个数字、一段文字、一张表、或一张图。

用起来什么样:

最小用法就是"读数据 + .chat()"。下面这段演示两条最常见入口。

# 示意,取自 README 与 pandasai/__init__.py 的公开 API
import pandasai as pai
from pandasai_litellm.litellm import LiteLLM

pai.config.set({"llm": LiteLLM(model="gpt-4.1-mini", api_key="...")}) # 配一个 LLM

df = pai.read_csv("data/companies.csv") # ① 读成 PandasAI 的 DataFrame
df.chat("Which are the top 5 companies by revenue?") # ② 直接用大白话问

# 或者一步到位,一次问一个或多个 df:
pai.chat("Which country has the highest revenue?", df)
  • pai.read_csv / pai.read_excel 把普通数据读成 PandasAI 的 DataFrame(pandasai/__init__.py:294 read_csv)。
  • DataFrame.chat(...) 是最常用的入口,内部懒创建一个 Agent 来处理这次提问(pandasai/dataframe/base.py:100 chat)。
  • pai.chat(query, *dataframes) 是模块级快捷方式,同样是新建 Agent.chat()(pandasai/__init__.py:219 chat)。
  • pai.create(...) 把一个 df 连同列 schema、转换、分组等存成数据集(语义层),pai.load(...) 再把它读回来(pandasai/__init__.py:46 create:259 load)。

一句话直觉/类比: 把 PandasAI 当成一个**"会写 SQL 的实习生"**——你说人话,它写查询代码,但你给它立了一条铁规矩:取数只能用 execute_sql_query,不许自己直接乱翻 pandas。这条规矩是全库安全性与可控性的地基。

本节不出现底层代码细节。记住三个动词就够了:问(chat)→ 生成代码 → 执行取数


2. 顶层全景(它大概怎么转)

2.1 主线一张图

下面这张图从用户问题一路走到响应。从上往下读即可,虚线是"出错时的回环"。

用户问题 "top 5 by revenue?"


┌───────────────────────────────┐
│ Agent 主循环 (agent/base.py) │ ← 三大支柱之一:主循环
└───────────────────────────────┘

① 组 prompt(把表结构 + 允许的 SQL 函数 + 输出格式喂给 LLM)


┌───────────────────────────────┐
│ LLM 生成 Python 代码 │
│ (代码里取数只允许调 │
│ execute_sql_query(...) ) │ ← 支柱三:代码即 SQL
└───────────────────────────────┘

② 校验:AST 扫一遍,没调 execute_sql_query 就打回 ┄┄┄┄┄┐
│ ┆
③ 清洗:表名白名单、剥掉危险重定义、改图路径等 ┆(重试:
│ ┆ 拿报错重新
▼ ┆ 生成代码)
┌───────────────────────────────┐ ┆
│ 执行代码 │ ┆
│ execute_sql_query → SQL 跑在: │ ┆
│ · 本地 DuckDB(CSV/parquet) │ ┆
│ · 或远程连接器(Postgres…) │ ┆
└───────────────────────────────┘ ┄┄执行报错┄┄┄┄┄┄┄┄┄┄┄┄┘

④ 解析 result = {"type":.., "value":..}


┌───────────────────────────────┐
│ 4 种响应:number / string / │
│ dataframe / plot │
└───────────────────────────────┘

怎么读这张图: 主干是"问题 → 生成 → 校验/清洗 → 执行 → 解析"这条直线;右侧虚线是容错回环——校验或执行出错时,把错误塞回 prompt 让 LLM 重写,最多重试 max_retries 次(pandasai/agent/base.py:171 generate_code_with_retries:197 execute_with_retries)。

2.2 三大支柱

PandasAI 的复杂度集中在三处,记住这三根柱子,后面每一章都能对号入座:

  1. Agent 主循环 —— 把"生成代码 → 校验清洗 → 执行 → 重试 → 解析响应"串起来的中央流程(见 01-agent-loop.md)。
  2. 语义层(Semantic Layer) —— 用 schema 描述数据集/视图/转换,再用 sqlglot 编译成 SQL(见 04-semantic-layer.md)。
  3. 代码即 SQL 的安全执行 —— 强制 LLM 只能通过 execute_sql_query 取数,加上 AST 校验、代码清洗、可选沙箱(见 02-code-as-sql.md)。

2.3 部件一句话职责

部件干什么文件
公开 APIchat/read_csv/read_excel/create/load/follow_up 等入口pandasai/__init__.py
DataFrame继承 pandas.DataFrame,挂上 schema,提供 .chat() 入口pandasai/dataframe/base.py:31
Agent主循环:生成→执行→重试→解析;并提供 execute_sql_querypandasai/agent/base.py:34
CodeGenerator调 LLM 生成代码,再做校验 + 清洗pandasai/core/code_generation/base.py:10
CodeRequirementValidator用 AST 检查代码是否真的调了 execute_sql_querypandasai/core/code_generation/code_validation.py:7
prompt 构造把表结构、允许的 SQL 函数、输出格式拼成给 LLM 的提示pandasai/core/prompts/(get_chat_prompt_for_sql)
execute_sql_query代码里唯一取数入口;分发到 DuckDB 或远程连接器pandasai/agent/base.py:137 _execute_sql_query
DuckDBConnectionManager本地把 df 注册进 DuckDB 并跑 SQLpandasai/data_loader/duck_db_connection_manager.py
语义层 schema描述数据集/视图/列/转换pandasai/data_loader/semantic_layer_schema.py
query builders把 schema 编译成 SQL(用 sqlglot)pandasai/query_builders/base_query_builder.py:12
ResponseParser{type,value} 变成 4 种响应对象pandasai/core/response/parser.py:15

2.4 主线走一遍(高层,不进代码)

df.chat("Which country has the highest revenue?") 为例:

  1. DataFrame.chat 懒创建一个 Agent,把这张 df 交给它(pandasai/dataframe/base.py:116)。
  2. Agent.chat 清空上一轮记忆,进入 _process_query(pandasai/agent/base.py:92:271)。
  3. generate_codeget_chat_prompt_for_sql 组 prompt,把表结构 + 可用 SQL 函数 + 期望输出格式喂给 LLM,拿回一段 Python 代码(:111)。
  4. 代码经 AST 校验(必须调 execute_sql_query)+ 清洗,执行时把 execute_sql_query 注入运行环境(:123 execute_code:127-130)。
  5. 代码里的 execute_sql_query(...) 落到 _execute_sql_query:本地数据就注册进 DuckDB 跑 SQL,远程数据集就交给它自己的执行器(:137)。
  6. 代码最后产出 result = {"type":.., "value":..},ResponseParsertype 包成 number/string/dataframe/plot(pandasai/core/response/parser.py:20)。

3. 巧妙之处(速览)

这是读完这套文档你该带走的"精华"。每条只点直觉,细节留给对应章节。

  • 强制 LLM 走 SQL,而非直接操作 pandas。 生成的代码里,取数只准execute_sql_query;库会用 AST 遍历函数调用,发现没调它就直接抛 ExecuteSQLQueryNotUsed 把代码打回重写(pandasai/core/code_generation/code_validation.py:41 validate,:62 检查)。这把"LLM 能干什么"收窄成"写 SQL",极大压缩了出错面和攻击面。→ 细看 02-code-as-sql.md

  • schema → SQL 用 sqlglot 编译。 语义层不是自己拼字符串,而是用 sqlglot(SQL 解析/生成库)构造并 parse_one 校验查询,还能按数据源方言(DuckDB / Postgres…)输出正确 SQL(pandasai/query_builders/base_query_builder.py:3 导入,:19 parse_one 校验)。→ 细看 04-semantic-layer.md

  • 多层安全 + 容错。 三道闸:AST 校验(必须用 execute_sql_query)→ 代码清洗(表名白名单、剥掉危险重定义、改图路径)→ 可选 Sandbox 隔离执行(pandasai/agent/base.py:132)。任一步或执行出错,都把报错回填 prompt 让 LLM 重试(:296 _regenerate_code_after_error)。→ 细看 01-agent-loop.md02-code-as-sql.md

  • 喂给 LLM 的是"表结构 + 允许的 SQL 函数 + 严格输出格式",不是原始数据。 prompt 模板把每张表的 schema、可用 SQL 函数、以及"最后必须声明 result 字典"的要求拼进去(pandasai/core/prompts/templates/generate_python_code_with_sql.tmpl:1)。这既省 token,又把输出约束成可解析的结构。→ 细看 03-prompts.md

  • 响应被收敛成 4 种类型。 LLM 必须把答案写成 {"type": one of number/string/dataframe/plot, "value": ...},解析器逐类型校验值的合法性(数字必须是数、图必须是路径或 base64 等),不合规则报 InvalidOutputValueMismatch(pandasai/core/response/parser.py:32 _validate_response)。


4. 阅读地图(建议顺序)

先读本章建立全局直觉,然后按"主循环 → 安全执行 → prompt → 语义层"由主干到细节推进:

顺序章节一句话什么时候读
0index.md(本章)是什么、全景、主线、路由先读,建立心智模型
101-agent-loop.mdAgent 主循环:一问一答怎么跑完,重试逻辑如何回环想搞懂"一次 chat 的完整生命周期"
202-code-as-sql.md代码即 SQL:强制 execute_sql_query、AST 校验、清洗、沙箱执行想搞懂"为什么安全、代码怎么被约束和跑起来"
303-prompts.mdPrompt 工程:喂给 LLM 的到底是什么(表结构、SQL 函数、输出契约)想搞懂"LLM 凭什么写对代码"
404-semantic-layer.md语义层与 SQL 编译:数据集、视图、转换如何用 sqlglot 变成 SQL想搞懂"数据集/视图/转换是怎么落到 SQL 的"

推荐路径: 只想用 → 读本章 §1、§2 即可。想改代码/排错 → 顺序 1→2。想理解"自然语言到底怎么变 SQL" → 加读 3、4。


5. 代码地图(导航索引)

主题文件路径符号名
公开入口 chatpandasai/__init__.pychat
公开入口 读 CSVpandasai/__init__.pyread_csv
公开入口 建数据集pandasai/__init__.pycreate
公开入口 载数据集pandasai/__init__.pyload
DataFrame.chat 入口pandasai/dataframe/base.pyDataFrame.chat
默认 schema 生成pandasai/dataframe/base.pyDataFrame.get_default_schema
Agent 类pandasai/agent/base.pyAgent
处理一次查询pandasai/agent/base.pyAgent._process_query
生成代码(带重试)pandasai/agent/base.pyAgent.generate_code_with_retries
执行代码(带重试)pandasai/agent/base.pyAgent.execute_with_retries
SQL 取数分发pandasai/agent/base.pyAgent._execute_sql_query
出错后重生成pandasai/agent/base.pyAgent._regenerate_code_after_error
代码生成器pandasai/core/code_generation/base.pyCodeGenerator.generate_code
强制用 SQL 的校验pandasai/core/code_generation/code_validation.pyCodeRequirementValidator.validate
组 SQL 提示pandasai/core/prompts/__init__.pyget_chat_prompt_for_sql
主 prompt 模板pandasai/core/prompts/templates/generate_python_code_with_sql.tmpl
响应解析(4 类型)pandasai/core/response/parser.pyResponseParser.parse
本地 DuckDB 执行pandasai/data_loader/duck_db_connection_manager.pyDuckDBConnectionManager
语义层 schemapandasai/data_loader/semantic_layer_schema.pySemanticLayerSchema
schema → SQL 编译pandasai/query_builders/base_query_builder.pyBaseQueryBuilder