解决方案 —— 对于反序列化出现问题,出现多重转义符号的json文件解析

背景

最近年后受到导师推荐来一个做算法的公司实习,公司最近新推出了产品,可以提供稳定模型服务等,我作为小小实习生,为了研究 deepseek 模型的prefix caching的实现,收到的任务就是研究一下提示词的前缀和如果进行前缀缓存命中率

问题描述

遇到的数据经过一点点省略后如下:

{"request_body":"{\\\"model\\\":\\\"deepseek/deepseek_v3\\\",\\\"messages\\\":[{\\\"role\\\":\\\"system\\\",\\\"content\\\":\\\"You ...

问题分析以及尝试过的解决方案

requestbody里的数据,经过了错误的多重转义。

  1. 试图和ai交互来解决这些问题,结果4o,cloude3,deepseekr1全废(2025.2.11)

有可能是因为在输入的时候,作为string读入或者别的,ai去理解这些带转义符的字符串也会受到阻碍,甚至有些ai在读入这些字符串的时候会查错转义字符的数量

  1. 自己自作聪明写了类似的解决方案:
def parse_request_body(text):
    for i in range(20,0,-1):
        pattern = "\\" * i + '"'
        text = text.replace(pattern,'"')
        pattern = "\\" * i + 'n'
        text = text.replace(pattern,'\n')

事后来分析,思路整体上没什么问题,不管是由于几次错误转义导致的问题,都能差不多还原回来,唯一的问题是可能要枚举处理所有特殊情况,比如unicode,比如制表符。

本以为此时找到了一个相对不错的方案,只要没有用户瞎输入类似于\\",或者\n这种子串,应该都不会破坏本来的输入还原回来。

遇到的问题

本以为还不错的解决方案,没想到碰到高手了:
人家本来在message里的较多的转义符,就是不想被翻译成"的,不然反倒会影响json的解析,也就是说本来json里就该有这些//

我还傻乎乎的在这转换,结果出来的都没办法解析。

真正的高手方案

正苦恼,没办法通过简单的替换来解决(其实按照正确的顺序,一层一层的解,是有机会替换回去的),结果看到了一个解决方案

import json
import request_part as reqs

print("Parsing %d requests...", len(reqs.request))
for i in range(len(reqs.request)):
    # 解析 JSON 字符串
    data = json.loads(reqs.request[i])

    # 提取 "messages" 字段的内容
    req_body = json.loads(data['request_body'])

而request_part文件,就是把json文件读入后,把整个python list输出出来(list的每一项由于没法被解析为python,都是字符串形式)
image

问题居然就这样解决了???!!!
居然只是把json存储变成python列表存储,就可以处理转义字符了???

原因分析

十分不服,也很困惑,于是写了如下的代码进行对比:

def extract_messages(data):
    content_list = []
    req_body = reqs.request
    for i in range(1):
        data_1 = reqs.request[i]
        data_2 = data[i]
        
    
        print(repr(data_1))
        print('--------------------------------')
        print(repr(data_2))
        print('--------------------------------')
        
        # 比较 data_1 和 data_2是否相同
        if data_1 == data_2:
            print("data_1 和 data_2_str 是相同的")
        else:
            print("data_1 和 data_2_str 是不同的")
    
    return content_list

if __name__ == "__main__":
    cache_file_path = 'json_data_cache.pkl'
    data = read_data_with_cache(cache_file_path)
    extract_messages(data)

data_1就是他的数据,data_2是我的数据,经过比较发现,唯一的区别就是,我的是json数据,他的是string。

为什么我是json呢?因为我在别的程序里,使用json.loads读取了json文件,并且存储为了pickle。

我此时对于data_1,可以通过两层加载的方式自动解码:

data_1_outer = json.loads(data_1)
req_body = json.loads(data_1_outer['request_body'])

而为什么我没办法去解码,或者我在存储pickle的文件为什么外层被扒开了而里层还没开呢?

一切的罪魁祸首就是tqdm!

真凶揭晓时刻

这是我读取json并缓存pickle文件的代码:

def read_json_with_cache(json_file_path, cache_file_path):
    """
    读取JSON文件并缓存数据。
    
    :param json_file_path: JSON文件的路径
    :param cache_file_path: 缓存文件的路径
    :return: 解析后的JSON数据
    """
    # 如果缓存文件存在,直接加载缓存数据
    if os.path.exists(cache_file_path):
        with open(cache_file_path, 'rb') as cache_file:
            print("从缓存加载数据...")
            return pickle.load(cache_file)
    
    # 否则,读取JSON文件并缓存数据
    try:
        with open(json_file_path, 'r', encoding='utf-8') as json_file:
            # 使用tqdm显示进度条
            file_size = os.path.getsize(json_file_path)
            with tqdm(total=file_size, unit='B', unit_scale=True, desc=json_file_path) as pbar:
                # 逐行读取文件并更新进度条
                data = []
                for line in json_file:
                    try:
                        json_object = json.loads(line)
                        data.append(json_object)
                    except json.JSONDecodeError as e:
                        print(f"解析行时发生错误: {e}")
                    pbar.update(len(line))
            
            # 将数据写入缓存文件
            with open(cache_file_path, 'wb') as cache_file:
                pickle.dump(data, cache_file)
            return data
    except FileNotFoundError:
        print(f"文件 {json_file_path} 未找到。")
    except json.JSONDecodeError as e:
        print(f"文件 {json_file_path} 不是有效的JSON格式。错误信息: {e}")
        # 打印出文件的前几行以帮助调试
        with open(json_file_path, 'r', encoding='utf-8') as json_file:
            for i in range(5):
                print(json_file.readline().strip())
    except Exception as e:
        print(f"读取文件时发生错误: {e}")

一切的原因都是,我在这里处理数据的时候,为了能看读取的进度来确定程序是否卡死,我使用了逐行读入,并逐行写入pickle。其中,如果在同行的json就被loads进行了第一次解析和转义,跨行的json被当作了内容字符串,没进行解析。少进行了一次转义

这导致我的pickle文件里面的数据是外层被转义过一次,部分里层比外层少转义一次,但是部分数据转义层数又是正常的。

至此,问题解决。

posted @   ZzTzZ  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示