前言
最近参加了一场名为“Python Vibe Coding 实操”的考核。这场考核很有意思,它不考你背诵算法题的能力,而是考察你在限时 60 分钟内,利用 AI 编码工具(如 Copilot, Cursor, 通义灵码等) 完成一个真实工程任务的能力。
核心指标不是“你会不会写代码”,而是你能不能把需求讲清楚、把任务拆得开、把结果验得出。
今天我就以这次考核中的“Excel 报表生成脚本”为例,分享一下我是如何通过自然语言与 AI 协作,完成从数据清洗到多 Sheet 报表输出的全过程。这不仅是一篇解题思路,更是一份AI 辅助编程的最佳实践指南。
一、需求拆解
在打开 IDE 之前,我并没有急着让 AI 写代码。根据考核要求,我先做了一份需求澄清清单。这一步至关重要,因为 AI 的理解能力取决于你 Prompt 的清晰度。
我将题目中的非结构化文本转化为了结构化的技术指标:
输入输出明确化:
输入:sales_raw.xlsx(包含脏数据:空值、重复行、负数)。
输出:report.xlsx(包含4个特定Sheet)。
清洗规则逻辑化:
删除关键列(日期、销售员、产品、数量、单价、地区)为空的行。
剔除 数量 <= 0 的行。
全字段去重(Drop Duplicates)。
统计维度具体化:
**新增计算列:**销售额 = 数量 * 单价。
**维度1:**按“销售员”汇总。
**维度2:**按“地区”汇总。
**维度3:**总览(月度总额)。
异常处理机制:
文件不存在怎么办?
文件是空的怎么办?
清洗后没数据了怎么办?
二、AI 协作实录
在明确了上述需求后,我开始使用 AI 工具(这里以 Cursor/Copilot 的逻辑为例)进行开发。以下是我与 AI 交互的关键步骤和代码生成过程。
第一步:构建项目骨架与依赖
我首先告诉 AI:“我需要创建一个 Python 项目,使用 pandas 和 openpyxl 处理 Excel。请帮我生成 requirements.txt 和一个基础的 main.py 结构,包含读取 Excel 的函数。”
AI 迅速给出了基础代码,我确认使用了 pandas 作为核心处理库。
第二步:核心清洗逻辑实现
这是最关键的一步。我没有自己手写 dropna 或 drop_duplicates,而是将刚才整理的“清洗规则逻辑化”直接发给 AI。
我的 Prompt:
“请编写一个 clean_data(df) 函数。
(1)检查必要列是否存在,不存在则报错。
(2)删除‘日期, 销售员, 产品, 数量, 单价, 地区’中任意一列为空的行。
(3)将‘数量’和‘单价’转换为数值类型,无法转换的视为异常剔除。
(4)删除‘数量’小于等于0的行。
(5)基于所有列进行去重。
(6)返回清洗后的 DataFrame。”
AI 生成的代码片段(优化后):
importpandasaspdimportnumpyasnpdefclean_data(df:pd.DataFrame)->pd.DataFrame:"""数据清洗核心逻辑"""required_cols=['日期','销售员','产品','数量','单价','地区']# 1. 检查列是否存在missing_cols=[colforcolinrequired_colsifcolnotindf.columns]ifmissing_cols:raiseValueError(f"原始数据缺少必要列:{missing_cols}")initial_len=len(df)# 2. 删除关键列空值df=df.dropna(subset=required_cols)# 3. 类型转换与异常值处理df['数量']=pd.to_numeric(df['数量'],errors='coerce')df['单价']=pd.to_numeric(df['单价'],errors='coerce')df=df.dropna(subset=['数量','单价'])# 转换失败的会变成NaN,再次删除# 4. 业务逻辑过滤:数量必须大于0df=df[df['数量']>0]# 5. 全字段去重df=df.drop_duplicates()print(f"数据清洗完成:原始{initial_len}行 -> 清洗后{len(df)}行")returndf.reset_index(drop=True)第三步:多维度统计与报表输出
接下来,我要求 AI 编写统计逻辑。这里有一个坑:计算销售额必须在清洗之后,统计之前进行。
我的 Prompt:
(1)“编写 generate_report(clean_df) 函数。
(2)计算‘销售额’列。
(3)分别按‘销售员’和‘地区’分组求和‘销售额’。
(4)计算总销售额。
(5)使用 ExcelWriter 将‘明细清洗后’、‘按销售员’、‘按地区’、‘总览’写入同一个 report.xlsx 的不同 Sheet。”
三、工程化完善
我为代码增加了健壮性检查:
importosimportsysdefmain():input_file='sales_raw.xlsx'output_file='report.xlsx'# 1. 文件存在性检查ifnotos.path.exists(input_file):print(f"[错误] 找不到输入文件:{input_file},请确保文件在当前目录下。")sys.exit(1)try:# 读取数据raw_df=pd.read_excel(input_file)# 2. 空文件检查ifraw_df.empty:print("[警告] 输入文件为空,无法生成报表。")return# 执行清洗clean_df=clean_data(raw_df)# 3. 清洗后无有效数据检查ifclean_df.empty:print("[警告] 清洗后无有效数据,请检查原始数据质量。")return# 生成报表generate_report(clean_df)print(f"[成功] 报表已生成:{output_file}")exceptExceptionase:print(f"[严重错误] 程序运行失败:{str(e)}")if__name__=='__main__':main()四、测试与验证
我设计了以下测试场景:
正常用例:提供一个包含 100 行标准数据的 Excel,验证生成的 4 个 Sheet 数据是否准确,总和是否对齐。
异常用例 A(脏数据):提供一个所有“数量”都为 -1 的文件。
预期结果: 程序提示“清洗后无有效数据”,不生成错误的报表。
异常用例 B(格式错误):提供一个缺少“单价”列的 Excel。
预期结果: 程序捕获 ValueError,提示“缺少必要列”。
五、可运行的源代码工程
importpandasaspdimportosimportsysfromdatetimeimportdatetime# ================= 配置区域 =================INPUT_FILE="sales_raw.xlsx"OUTPUT_FILE="report.xlsx"REQUIRED_COLUMNS=["日期","销售员","产品","数量","单价","地区"]defclean_data(df):""" 数据清洗逻辑: 1. 检查必要字段是否存在 2. 删除关键字段缺失的行 3. 剔除数量<=0的异常行 4. 按全字段去重 """print(">>> 开始数据清洗...")# 1. 检查列名是否匹配missing_cols=[colforcolinREQUIRED_COLUMNSifcolnotindf.columns]ifmissing_cols:raiseValueError(f"原始数据缺少必要列:{missing_cols},请检查表头。")initial_count=len(df)# 2. 删除关键列(日期、销售员、产品、数量、单价、地区)有空值的行df=df.dropna(subset=REQUIRED_COLUMNS)# 确保数量和单价是数值类型,无法转换的视为脏数据剔除df["数量"]=pd.to_numeric(df["数量"],errors="coerce")df["单价"]=pd.to_numeric(df["单价"],errors="coerce")df=df.dropna(subset=["数量","单价"])# 3. 剔除数量 <= 0 的行df=df[df["数量"]>0].copy()# 4. 全字段去重df=df.drop_duplicates().reset_index(drop=True)cleaned_count=len(df)print(f">>> 清洗完成:原始{initial_count}行 -> 有效{cleaned_count}行 (移除{initial_count-cleaned_count}行)")returndfdefgenerate_statistics(df):""" 统计维度计算: 1. 计算销售额 2. 按销售员汇总 3. 按地区汇总 4. 计算总览 """print(">>> 开始统计数据...")# 计算销售额df["销售额"]=df["数量"]*df["单价"]# 1. 按销售员汇总sales_by_person=df.groupby("销售员")["销售额"].sum().reset_index()sales_by_person.columns=["销售员","总销售额"]sales_by_person=sales_by_person.sort_values(by="总销售额",ascending=False)# 2. 按地区汇总sales_by_region=df.groupby("地区")["销售额"].sum().reset_index()sales_by_region.columns=["地区","总销售额"]sales_by_region=sales_by_region.sort_values(by="总销售额",ascending=False)# 3. 总览total_sales=df["销售额"].sum()total_volume=df["数量"].sum()overview_data={"指标":["月度总销售额","月度总销量","有效订单数"],"数值":[total_sales,total_volume,len(df)]}overview_df=pd.DataFrame(overview_data)returndf,sales_by_person,sales_by_region,overview_dfdefexport_report(clean_df,person_df,region_df,overview_df):""" 输出 report.xlsx,包含四个工作表 """print(f">>> 正在生成报表:{OUTPUT_FILE}...")withpd.ExcelWriter(OUTPUT_FILE,engine="openpyxl")aswriter:clean_df.to_excel(writer,sheet_name="明细清洗后",index=False)person_df.to_excel(writer,sheet_name="按销售员",index=False)region_df.to_excel(writer,sheet_name="按地区",index=False)overview_df.to_excel(writer,sheet_name="总览",index=False)print(">>> 报表生成成功!")defmain():print(f" Python Excel 报表生成工具启动 (时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')})")# 1. 检查输入文件是否存在ifnotos.path.exists(INPUT_FILE):print(f" 错误:找不到输入文件 '{INPUT_FILE}'。请确保文件在当前目录下。")sys.exit(1)try:# 2. 读取数据raw_df=pd.read_excel(INPUT_FILE)ifraw_df.empty:print(" 警告:输入文件是空的,无法生成报表。")sys.exit(0)# 3. 执行清洗clean_df=clean_data(raw_df)ifclean_df.empty:print(" 警告:清洗后没有剩余有效数据,请检查原始数据质量。")sys.exit(0)# 4. 执行统计clean_df,person_df,region_df,overview_df=generate_statistics(clean_df)# 5. 导出报表export_report(clean_df,person_df,region_df,overview_df)exceptValueErrorasve:print(f" 数据格式错误:{ve}")exceptExceptionase:print(f" 发生未知错误:{e}")if__name__=="__main__":main()