需用pandas.json_normalize()精准展平嵌套JSON:顶层为列表时直接调用;深层键下须指定record_path和meta(嵌套字段用列表表示);不规则结构宜手写递归函数flatten_dict;禁用max_level防稀疏列,高基数子列表应分步处理后merge。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

你需要在Dify工作流中把含数万条记录、嵌套深度达5层的JSON(比如全量用户行为日志)转成扁平化表格结构,供后续LLM节点批量摘要或条件节点做字段判断——直接传给json_normalize()会因record_path错配或max_level误设导致列爆炸、内存超限甚至节点中断。
确认输入已解析为Python对象而非字符串
打开Python节点,检查上游是否为HTTP节点或文件读取节点。若上游是HTTP节点,【必须启用“Parse JSON”选项】,否则input接收到的是原始字符串,后续所有json.loads(input)都会报JSONDecodeError。
插入调试语句:print(type(input), input.keys() if hasattr(input, 'keys') else 'not a dict')。如果输出
用pandas.json_normalize()精准控制展平路径
方法一:顶层为列表(如API返回[{"id":1,"user":{"name":"A"}},...])
直接调用:output = pd.json_normalize(input, sep='_')
方法二:数据藏在深层键下(如{"data":{"items":[{"id":1},{"id":2}]}})
必须指定record_path:output = pd.json_normalize(input, record_path=['data', 'items'], meta=['timestamp', ['data', 'total']], sep='_')
注意meta中嵌套字段要用列表表示,写成['data','total']而非'data.total',否则会报KeyError。
手动递归展平不规则嵌套结构
当JSON中同一层级混用dict和list(如"profile": {"age":30} 和 "tags": ["a","b"]),或需完全自定义列名时,手写函数更可控。
第一步:定义递归函数,用sep="_"拼接键名,避免点号引发pandas语法歧义
第二步:遇到list时,对每个元素单独递归,并保留外层前缀(如"permissions_0_role"、"permissions_1_scope")
第三步:所有缺失键统一赋None,防止pd.DataFrame()构造时报All arrays must be of the same length
这一步操作起来很简单,直接把下面代码粘贴进Python节点即可:
def flatten_dict(d, parent_key='', sep='_'): result = {} for k, v in d.items(): new_key = f"{parent_key}{sep}{k}" if parent_key else k if isinstance(v, dict): result.update(flatten_dict(v, new_key, sep=sep)) elif isinstance(v, list): for i, item in enumerate(v): item_key = f"{new_key}_{i}" if isinstance(item, dict): result.update(flatten_dict(item, item_key, sep=sep)) else: result[item_key] = item else: result[new_key] = v return result
output = [flatten_dict(item) for item in input.get('records', [])]
规避max_level陷阱与稀疏列生成
不要设max_level=3或更高——它只影响字典展开深度,对list内部的dict完全无效,反而会生成skills_0_name、skills_1_name等大量带编号的稀疏列。
真正要防的是高基数子列表(如一个订单含500行明细)。此时应分步处理:先用json_normalize(meta=['order_id','date'])提取主表,再对子列表单独normalize,最后用pd.merge()关联。
例如子项在input['order']['items']中,就单独跑一次:items_df = pd.json_normalize(input['order'], record_path=['items'], meta=['order_id'], sep='_')


















