返回博客

AI 入门指南

向 LLM 询问 CSV:发送 schema,而不是表

发送列名、类型和 3 行示例数据,拿回一行 pandas 代码,在完整文件上运行它。比粘贴行更便宜,而且你可以检查数字。

作者:CheapTokens Team发布于 6 分钟阅读

读取 CSV、获取其列类型和三行数据,并请求一行 pandas 代码的代码行
本页内容
  1. 为什么粘贴整张表会出错
  2. 发送表的形状,而不是表本身
  3. 脚本:提问、读取代码行、运行它
  4. 成本:粘贴全部内容 vs schema + 3 行
  5. 信任数字之前先检查它
  6. 如果不起作用

你有一个 sales.csv,包含 5,000 行数据,还有一个问题:10 月份哪个产品卖得最多?不要把文件粘贴到聊天里。把列名、列类型和三行示例数据发给模型,让它给出一行 pandas 代码,然后你自己在完整文件上运行这一行。模型从不读取你的 5,000 行数据,提示词保持很小,而你得到的数字来自可以重新运行的代码。

下面说明为什么这样做更好、提示词长什么样、一个可以复制的脚本,以及它相比粘贴全部内容的成本。

为什么粘贴整张表会出错#

这里有一个你可能熟悉的故事。有人把 200 行费用数据粘贴到聊天里,然后问总计是多少。答案回来时很自信,连分位都有。但它也是错的,而屏幕上没有任何东西告诉你这一点。

模型逐块预测文本(这些块就是 token)。对 200 个数字求和是 200 个小步骤,内部没有计算器,而一个滑错的数字看起来和正确答案一模一样。代码的行为不同:df['amount'].sum() 每次都会把所有行加起来,第二次运行也会给出相同结果。

还有第二个问题,而且和大小有关。一张表会很快吃掉 上下文窗口,而且每个问题你都要为每一行付费。对同一个文件问十个问题,就意味着把整张表的十份副本作为输入发送。

快速检查

为什么一行 pandas 代码比让模型算总计更安全?

显示答案

答案: 你的计算机会在每一行上运行代码,而且你可以重新运行并检查它

模型仍然可能写出一行错误的代码。区别在于,一行代码是可见且可重复的:你读它、运行它,并手动用几行数据核对结果。

发送表的形状,而不是表本身#

模型不需要你的数据来写代码。它需要知道表长什么样:有哪些列、这些列保存什么类型的值,以及一行是怎么写的。这就是 schema 加几行数据。

假设你的 sales.csv 有四列。这就是完整的提示词:

text
A pandas DataFrame named df has these columns and types:
date        object
product     object
units        int64
price      float64

First 3 rows (CSV):
date,product,units,price
2026-10-01,Oat latte mix,12,4.50
2026-10-01,Cocoa,7,3.20
2026-10-02,Oat latte mix,9,4.50

Question: Which product sold the most units in October 2026?

Reply with ONE line of pandas code that computes the answer from df.
No explanation, no markdown, no imports.

预期回复的形状类似 df[df['date'].str.startswith('2026-10')].groupby('product')['units'].sum().idxmax()。具体措辞每次运行都会不同,所以运行前先读那一行。

为什么是三行而不是只有列名?因为日期。类型列写的是 object,这只表示文本。示例行显示日期写成 2026-10-01,所以模型知道要匹配文本 2026-10,而不是 10/2026 或月份名称。大多数错误的 pandas 代码行都来自猜测表里从未有过的格式。

粘贴每一行与发送 schema 和三行数据的对比
同一个问题:左边的提示词随表增长,右边的提示词保持同样大小

脚本:提问、读取代码行、运行它#

下面的脚本会根据你的文件构建那个提示词,这样你就不用手动输入 schema。它通过 OpenAI Python SDK 调用 CheapTokens API:基础 URL 为 https://api.cheaptokens.dev/v1,模型 id 为 deepseek-ai/DeepSeek-V4-Flash-0731。把密钥放在环境变量里,不要放在文件中。

python
import os
import pandas as pd
from openai import OpenAI

client = OpenAI(
    base_url="https://api.cheaptokens.dev/v1",
    api_key=os.environ["CHEAPTOKENS_API_KEY"],
)

df = pd.read_csv("sales.csv")      # for .xlsx: pd.read_excel("sales.xlsx")

schema = df.dtypes.to_string()
sample = df.head(3).to_csv(index=False)
question = "Which product sold the most units in October 2026?"

prompt = f"""A pandas DataFrame named df has these columns and types:
{schema}

First 3 rows (CSV):
{sample}
Question: {question}

Reply with ONE line of pandas code that computes the answer from df.
No explanation, no markdown, no imports."""

resp = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash-0731",
    messages=[{"role": "user", "content": prompt}],
    max_tokens=500,
)

text = resp.choices[0].message.content.strip()
code = text.removeprefix("```python").removeprefix("```").removesuffix("```").strip()
print("Model's line:", code)
print("Tokens in/out:", resp.usage.prompt_tokens, resp.usage.completion_tokens)

if resp.choices[0].finish_reason != "stop" or "import" in code or "__" in code:
    raise SystemExit("Not running this one. Read the line above and decide.")

print("Answer:", eval(code, {"df": df, "pd": pd}))

最后一块是初学者会跳过的部分。eval 会在你的机器上运行模型写出的任何文本,所以脚本会拒绝包含 import 或 __ 的代码行,以及被截断的答案(finish_reason 不是 stop;参见为什么答案会在句子中间停止)。而且你仍然要先阅读打印出来的代码行。如果它涉及文件、网络或任何你没有要求的内容,就不要运行它。

第一次运行会打印三样东西:模型给出的代码行、这一次请求的 token 计数,以及答案。token 计数是下一节的计量器。

成本:粘贴全部内容 vs schema + 3 行#

为了比较,我们需要给一行数据定一个大小。假设一行像 2026-10-01,Oat latte mix,12,4.50 这样的数据大约占 20 个 token。这是一个假设:它取决于模型的分词器和你的列,而发送前计算 token 会显示你的真实数字。按每行 20 个 token 计算,5,000 行就是 5,000 × 20 = 100,000 个输入 token。schema 加三行的提示词大约 300 个 token,包含指令。两种情况下答案都很短,比如 60 个 token,所以差异完全在输入侧,也就是随你的表增长的那一侧(更多内容见输入 token 与输出 token)。

关于一张 5,000 行表的一个问题,使用 DeepSeek-V4-Flash,答案 60 个 token
  • 粘贴全部 5,000 行$0.0015
  • Schema + 3 行$0.000011

两个数字换算成美元都很小,这很诚实:便宜的模型让即使浪费的方式也变得可负担。差距在于增长。每天问 20 个问题,粘贴全部内容的提示词就要发送 20 次。表翻倍,其成本也翻倍,而 schema 提示词不会变。而且还有一堵硬墙:在 380K token 的上下文窗口下,380,000 ÷ 20 = 19,000 行是你最多能粘贴的行数,这还没有给答案留任何空间。一个 50,000 行的导出文件根本放不下。而 schema 提示词无论表多大都能放下。

代入你自己的表,看看每日成本:

成本计算器

你的表整表粘贴:每天 20 个问题

每次请求的输入 token 数: 100,000 · 每次请求的输出 token 数: 60 · 每日请求数: 20

模型每天每月
GLM-5.3-Flash$0.04$1.20
DeepSeek-V4-Flash$0.0301$0.904
MiniMax-M2.7$0.10$3.01

把 in 改成 300,看看 schema 方式。CheapTokens 上的 DeepSeek-V4-Flash 在任何时段都是一个价格,没有高峰时段附加费,而且一个余额覆盖所有模型,所以你可以把模型 id 换成 zai-org/GLM-5.3-Flash(390K 上下文),无需第二个账户。当前价格在定价页面上。

信任数字之前先检查它#

循环总是一样的。每次都这样做,错误答案就会在第四步被抓住,而不是在报告里。

排序

把循环排好序

  1. 描述表:列类型和 3 行示例数据
  2. 要求给出一行 pandas 代码,不要别的
  3. 阅读这一行,然后在完整文件上运行它
  4. 手动用几行数据核对结果
循环:表、schema 和三行数据、一行 pandas 代码、你的数字
模型只看到中间步骤;完整表从不离开你的计算机

第四步很便宜。把文件过滤到少量行(df[df['product'] == 'Cocoa'].head(10)),在脑子里或在电子表格里把它们加起来,然后比较。如果模型给出的代码行是错的,通常错得很明显:它数了行数而不是对 units 求和,或者选错了月份。

想了解更多这样的习惯,请参阅为什么 AI 会编造内容,以及减少这种情况的 4 个提示词习惯。

如果不起作用#

  • KeyError: 'Date'。模型写出的列名大小写不同。把真实的表头行粘贴到提示词里,三行示例数据已经做到了这一点,并加上“完全按照所示使用列名”。
  • 回复在代码前有一句话。你的 eval 因 SyntaxError 而失败。在提示词末尾重复“一行 pandas 代码,不要解释”,最后一条指令最重要。
  • 答案是一张表,而不是一个数字。说明你想要什么形状:“返回单个数字”或“返回按降序排序的 Series”。
  • 日期结果错误。示例行显示了真实格式。如果你的日期是 14/10/2026,模型需要看到这一点;把 pd.to_datetime(df['date'], dayfirst=True) 加到提示词里,作为你希望读取日期的方式。
  • finish_reason 是 length。回复被 max_tokens 截断了。一行代码在 500 个 token 内就能放下,所以检查提示词:模型可能在做长篇解释。

从密钥到响应的首次请求完整设置,见 CheapTokens 文档。