从OpenAI API获取数据填充Pandas DataFrame时部分字段为空的解决方法
从OpenAI API获取数据填充Pandas DataFrame时部分字段为空的解决方法
看起来你遇到的问题挺典型的——循环调用OpenAI API补全信息时,部分字段(比如沃尔玛的CEO相关内容)会返回空值,但单独请求却能拿到有效数据对吧?我来帮你分析下可能的原因,再给你具体的解决办法:
问题根源分析
- 提示词约束不够明确:你原来的prompt只要求按指定键返回JSON,但没明确说"哪怕信息不确定也不能留空,必须填'未知'这类占位符",GPT模型有时候会偷懒,遇到拿不准的信息直接返回空字符串。
- 请求频率过高导致响应质量下降:循环里连续发请求,间隔太短的话,OpenAI的模型可能会简化响应,或者返回不完整的结果(尤其是配额紧张的时候)。
- 缺少校验和重试机制:没检查返回结果的字段是否为空,也没在拿到空值时重新请求,导致空数据直接被存入DataFrame。
具体解决步骤(附代码修改)
1. 优化提示词,明确强制填充规则
把你的提示词改得更严苛,明确要求所有字段必须有值,未知信息用"未知"代替,绝对不能留空:
user_prompt = f""" 请严格按照以下指定的JSON格式,返回{company_name}的相关信息: 必须包含所有以下键:{', '.join(json_format)} **注意:任何信息无法获取或不确定时,必须填充为"未知",绝对不能留空字符串!** 返回的内容只能是合法的单个JSON对象,不能有多余的文字或格式。 """
2. 增加重试机制 + 请求间隔
封装API请求逻辑成函数,加入重试机制——如果返回的字段有空值,自动重新请求;同时在循环和重试中加入时间间隔,避免请求太密集:
完整修改后的代码
import time import json import openai import pandas as pd # 初始化OpenAI客户端(记得替换成你的API密钥) client = openai.OpenAI(api_key="your-api-key-here") sample_df = pd.DataFrame({ 'Rank': [1, 2, 3], 'Company': ['Walmart', 'Amazon', 'State Grid'], 'Revenue': ['$648,125', '$574,785', '$545,947.5'], 'Profit': ['6%', '11.8%', '3%'], 'Assets': ['$15,511', '$30,425', '$9,204.3'], 'Market Value': ['32.8%', '-', '12.4%'] }) json_format = ["Company", "Country of Origin", "Industry", "CEO name", "Bachelor Degree", "University Attended for Bachelor Degree", "MBA", "University for MBA"] def get_company_info(company_name, max_retries=3): retry_count = 0 while retry_count < max_retries: try: # 明确约束的提示词 user_prompt = f""" 请严格按照以下指定的JSON格式,返回{company_name}的相关信息: 必须包含所有以下键:{', '.join(json_format)} **注意:任何信息无法获取或不确定时,必须填充为"未知",绝对不能留空字符串!** 返回的内容只能是合法的单个JSON对象,不能有多余的文字或格式。 """ completion = client.chat.completions.create( model="gpt-3.5-turbo-0125", response_format={"type": "json_object"}, messages=[ {"role": "system", "content": "你是专业的企业信息查询助手,必须严格按照要求返回合法JSON,所有字段不能为空,未知信息填'未知'。"}, {"role": "user", "content": user_prompt} ] ) json_data = json.loads(completion.choices[0].message.content) # 检查所有字段是否都不为空 all_filled = all(json_data.get(key, "") != "" for key in json_format) if all_filled: return json_data else: print(f"{company_name}存在空字段,正在重试第{retry_count+1}次...") retry_count += 1 time.sleep(2) except Exception as e: print(f"请求{company_name}时出错:{str(e)},正在重试...") retry_count += 1 time.sleep(2) # 多次重试失败后,用"未知"填充所有字段 fallback_data = {key: "未知" for key in json_format} fallback_data["Company"] = company_name return fallback_data # 初始化结果DataFrame df_json = pd.DataFrame(columns=json_format) # 循环处理每个公司 for _, row in sample_df.iterrows(): company_name = row['Company'] print(f"正在获取{company_name}的信息...") company_info = get_company_info(company_name) new_row = pd.DataFrame([company_info]) df_json = pd.concat([df_json, new_row], ignore_index=True) # 增加请求间隔,避免过于密集 time.sleep(1) print(df_json.head())
额外优化建议
- 如果你对数据准确性要求高,可以换成
gpt-4模型,它的信息覆盖度和响应质量比gpt-3.5-turbo更高,只是成本会稍高。 - 可以考虑使用OpenAI的批量API处理请求,比循环单条请求更高效,也能避免频率限制带来的问题(需要按官方要求准备批量请求文件)。
- 定期检查你的OpenAI API配额,如果接近上限,也会导致响应质量下降,甚至返回不完整数据。
备注:内容来源于stack exchange,提问作者Faizul Zuraimi




