豆包智能体聊天记录批量导出实战:从抓包到本地备份的完整方案
1. 为什么我要折腾聊天记录备份这件事用了大半年豆包智能体我陆陆续续攒了几十个对话窗口有用来做知识库问答的有专门跑文案润色的还有几个是帮团队做客服话术训练的。直到上个月电脑主板挂了重装系统之后打开豆包网页版发现之前那些对话记录全没了——不是账号丢了是本地缓存和部分会话上下文没同步上去。那一刻我才意识到聊天数据备份这件事不能指望平台自动帮你兜底。后来我在几个技术群里问了一圈发现遇到类似情况的人不少。有人是换了设备之后历史记录对不上有人是想把某个智能体的优质回答整理成文档还有人纯粹是想做批量导出方便做二次分析。但豆包官方目前并没有提供一个显眼的一键导出全部对话按钮网页版只能一条条翻客户端也没有批量操作入口。这就催生了一个很实际的需求手动把聊天数据批量导出来存成自己能掌控的格式。这篇内容就是把我自己踩过的坑、试过的方案、以及最后跑通的一套流程完整记录下来。适合两类人看一类是像我这样有几十上百个对话需要归档的普通用户另一类是手里有多个智能体、想把对话数据拿去做训练语料或者分析的技术同学。整个过程不需要写复杂代码但需要你对浏览器开发者工具和基本的文件操作有一点耐心。核心关键词就三个豆包、智能体、批量导出围绕它们把技术原理和操作步骤讲透。2. 批量导出的底层逻辑数据到底存在哪里2.1 聊天记录的三种存在形态在动手之前得先搞清楚豆包的聊天数据到底以什么形式存在。我通过抓包和翻本地存储梳理出来三种形态第一种是服务端会话记录。你每次发消息请求会带着会话ID打到服务端服务端把这一轮问答存进数据库。这部分数据你在网页版刷新之后还能看到说明它是跟着账号走的。但问题是服务端并没有开放一个导出全部会话的接口给普通用户你只能通过会话列表逐个拉取。第二种是浏览器本地缓存。网页版为了加快加载速度会把最近打开的会话内容存在IndexedDB或者localStorage里。这部分数据的特点是读取快、结构清晰但容量有限而且清缓存就没了。我实测下来网页版大概会缓存最近二三十个会话的完整消息体更早的就需要重新请求。第三种是客户端本地数据库。如果你用的是豆包电脑版客户端它会在本地建一个SQLite数据库文件把会话、消息、智能体配置都存进去。这个文件才是批量导出的富矿因为它是结构化的一张表存会话一张表存消息字段清晰。但不同版本的客户端数据库路径和表结构会有差异需要你根据实际情况去定位。提示我下面讲的操作以网页版为主因为网页版跨平台、不需要装客户端通用性最强。客户端方案我会在第四节单独说适合数据量特别大的情况。2.2 为什么不能直接复制粘贴有人可能会说我直接打开每个对话全选复制粘贴到Word里不就行了我试过十个对话以内还能忍超过二十个就是纯体力活而且复制出来的格式全乱角色标识、时间戳、代码块全都混在一起。更麻烦的是智能体的回答里经常有Markdown表格和代码块粘贴到Word里直接变成一坨。所以批量导出的核心诉求不是能导出而是导出后还能用。这就要求我们拿到的是结构化的数据最好是JSON格式每条消息带角色、时间、内容字段这样后续无论是转成Markdown、导入知识库、还是做数据分析都有得商量。2.3 整体技术路线选型我把可行的方案列了个表对比一下各自的优劣方案原理优点缺点适合场景浏览器开发者工具抓接口监听网络请求拿到会话列表和消息接口数据最全结构清晰需要手动翻页接口可能变几十到上百个会话本地存储读取从IndexedDB/localStorage提取缓存速度快无需网络只有最近部分会话快速备份近期对话客户端数据库导出直接读SQLite文件一次性拿全量需要定位文件版本差异大数据量特别大页面自动化脚本模拟点击逐条抓取不依赖接口慢容易被限流接口不可用时兜底我最终采用的是接口抓取为主、本地存储为辅的组合方案。原因很简单接口返回的数据最完整包含会话标题、创建时间、消息列表本地存储可以作为补充把接口没覆盖到的近期缓存捞回来。两者一合并基本能做到不丢数据。3. 动手前的环境准备与关键参数3.1 你需要准备的东西在开始之前确认手头有这几样一台能正常访问豆包网页版的电脑Chrome或Edge浏览器都行我用的Chrome 120以上版本。登录你的豆包账号确保能看到完整的会话列表。一个用来存放导出文件的文件夹建议单独建一个比如doubao_backup。如果会话数量超过五十个建议准备一个能处理JSON的工具比如VS Code或者任何文本编辑器。不需要装额外的软件也不需要什么特殊权限。整个过程都在浏览器里完成。3.2 关键参数会话ID和分页机制抓接口之前得先理解两个关键参数。会话IDconversation_id每个对话窗口都有一个唯一ID通常是一串长字符串。你打开某个对话时URL里或者请求参数里会带上它。批量导出的第一步就是先把所有会话ID收集齐。分页参数会话列表接口一般不会一次性返回全部而是分页的。常见的是offset和limit两个参数limit控制每页返回多少条offset控制从第几条开始。我实测下来把limit设成50比较稳妥太大容易超时太小翻页次数多。注意不同时期豆包的接口参数名可能有变化比如有的版本用page和page_size。你在抓包的时候以实际看到的为准不要死记我这里的参数名。3.3 打开开发者工具的正确姿势按F12打开开发者工具切到Network面板勾选Preserve log保留日志这样页面跳转时请求记录不会被清空。然后刷新一下豆包页面你会看到一堆请求刷过去。这时候在筛选框里输入conversation或者message把无关的请求过滤掉。我一般会先点开一个对话观察发出去哪些请求找到返回消息列表的那个。通常它的Response是一个JSON里面有data字段里面套着messages数组。找到目标接口之后右键选择Copy as cURL把它存到一个文本文件里。这一步很关键因为后面我们要用这个请求模板去批量拉取不同会话的数据。4. 完整实操流程从抓包到落地成文件4.1 第一步收集全部会话ID打开豆包的会话列表页面在Network面板里找到返回会话列表的那个接口。它的Response大概长这样{ data: { conversations: [ {id: conv_abc123, title: 文案润色助手, created_at: 1700000000}, {id: conv_def456, title: 知识库问答, created_at: 1700000100} ], has_more: true } }你要做的就是不断翻页把每一页的conversations数组里的id字段提取出来汇总成一个列表。手动翻页的话改offset参数重新发请求就行。如果会话不多翻个三五页就齐了。我自己的做法是把这个接口的cURL复制出来改一下offset在终端里用curl循环跑把结果存成一个个JSON文件。这样比在浏览器里点快得多。# 示例循环拉取会话列表offset从0开始每次加50 for offset in 0 50 100 150 200; do curl https://xxx/conversation/list?offset$offsetlimit50 \ -H cookie: 你的cookie \ -o conv_list_$offset.json done跑完之后用一段简单的Python把所有的id抽出来去重import json, glob ids set() for f in glob.glob(conv_list_*.json): data json.load(open(f)) for conv in data[data][conversations]: ids.add(conv[id]) print(len(ids)) with open(conv_ids.txt, w) as fp: fp.write(\n.join(ids))这一步做完你就有了一个纯文本的会话ID列表一行一个。4.2 第二步批量拉取每个会话的消息有了ID列表接下来就是逐个拉消息。消息接口通常长这样https://xxx/conversation/messages?conversation_idxxx。同样用curl循环while read cid; do curl https://xxx/conversation/messages?conversation_id$cid \ -H cookie: 你的cookie \ -o messages_$cid.json sleep 1 done conv_ids.txt这里我加了个sleep 1目的是控制请求频率。实测下来如果不加延迟连续请求几十次之后会触发限流返回429。加一秒延迟基本能稳住一百个会话也就两分钟的事。提示cookie是有有效期的一般几个小时到几天不等。如果你中途发现请求返回401或者跳登录页重新登录一下把新的cookie换上去就行。4.3 第三步数据清洗与格式统一拉下来的原始JSON结构可能不太一致有的消息内容在content字段有的在text字段角色标识有的用role: user有的用is_user: true。所以需要做一层清洗统一成下面这种格式{ conversation_id: conv_abc123, title: 文案润色助手, created_at: 2024-01-01T10:00:00, messages: [ {role: user, content: 帮我把这段话润色一下, time: 2024-01-01T10:00:05}, {role: assistant, content: 好的以下是润色后的版本..., time: 2024-01-01T10:00:08} ] }清洗脚本用Python写核心就是遍历每个messages_*.json把字段映射到统一结构。我大概写了三十行代码就搞定了关键是要处理一下空消息和异常字段避免脚本中途崩掉。import json, glob, os result [] for f in glob.glob(messages_*.json): try: raw json.load(open(f, encodingutf-8)) except Exception as e: print(skip, f, e) continue msgs [] for m in raw.get(data, {}).get(messages, []): msgs.append({ role: user if m.get(is_user) else assistant, content: m.get(content) or m.get(text) or , time: m.get(created_at, ) }) result.append({ conversation_id: raw.get(data, {}).get(conversation_id, ), title: raw.get(data, {}).get(title, ), messages: msgs }) json.dump(result, open(doubao_backup.json, w, encodingutf-8), ensure_asciiFalse, indent2)跑完之后你会得到一个doubao_backup.json里面是所有会话的完整消息。这个文件就是你的数据资产后面想怎么用都行。4.4 第四步转成可读格式JSON虽然结构化好但直接看不太方便。我一般会再写个小脚本把它转成Markdown每个会话一个文件标题作为文件名消息按角色分段。这样用任何Markdown阅读器都能看也方便导入到笔记软件里。import json, re data json.load(open(doubao_backup.json, encodingutf-8)) for conv in data: title re.sub(r[\\/:*?|], _, conv[title] or conv[conversation_id]) with open(foutput/{title}.md, w, encodingutf-8) as fp: fp.write(f# {conv[title]}\n\n) for m in conv[messages]: prefix **我** if m[role] user else **豆包** fp.write(f{prefix}{m[content]}\n\n)到这一步整个批量导出流程就跑通了。从抓包到落地成Markdown一百个会话大概花了我二十分钟其中大部分时间是在等请求返回。5. 常见问题与排查技巧实录5.1 请求返回401或跳登录页这是最常见的问题九成是cookie过期了。解决办法很简单重新登录豆包网页版按F12打开开发者工具在Network面板里随便找一个请求把cookie请求头完整复制出来替换掉脚本里的旧cookie。注意cookie里包含多个字段要整段复制不要只复制其中一部分。如果换了新cookie还是401检查一下请求头里有没有漏掉user-agent或者referer。有些接口会校验这两个字段缺了就会被拒。5.2 翻页翻到一半返回空列表这种情况通常是offset设太大了超出了实际会话总数。你可以在返回结果里看has_more字段如果是false就说明到底了不用再翻。另外有些版本的接口用cursor而不是offset每次返回一个next_cursor下次请求带上它就行。以实际抓到的为准。5.3 消息内容出现乱码或截断乱码一般是编码问题确保你的脚本在读写文件时都指定了encodingutf-8。截断则可能是单条消息太长接口做了长度限制。我遇到过一条智能体回答超过五千字被截成两段的情况解决办法是把两段按时间顺序拼回去或者直接保留原始JSON不做截断处理。5.4 请求频率过高被限流前面提过加sleep是最简单的办法。如果会话特别多比如上千个建议把sleep调到2到3秒或者分批跑跑一百个歇十分钟。别想着并发拉取限流策略对并发更敏感得不偿失。5.5 客户端数据库找不到如果你用的是电脑版客户端数据库文件一般在安装目录下的data或者userdata文件夹里文件名可能是chat.db或者message.sqlite。用SQLite工具打开之后找conversation和message两张表。不同版本表名可能不一样实在找不到就用关键词搜一下.db文件。找到之后导出成CSV再转JSON流程和网页版类似。注意操作客户端数据库之前先复制一份备份别直接在原文件上改万一搞坏了客户端就打不开了。6. 几个让我少走弯路的实操心得第一个心得是先小范围试跑。别一上来就把几百个会话全拉一遍先拿三五个ID跑通整个流程确认数据格式没问题、脚本没报错再放量。我第一次就是贪快结果脚本里一个字段名写错了拉了两百个文件全是废的白等半小时。第二个心得是原始数据一定要留着。清洗后的JSON和Markdown是给人看的但原始接口返回的JSON别删。万一后面发现某个字段清洗错了还能从原始数据里重新提取。我专门建了个raw文件夹存原始文件占不了多少空间。第三个心得是定期备份比一次性导出更重要。我现在养成了习惯每个月月初跑一次导出脚本把新增的会话追加进去。这样即使某天账号出问题最多也就丢一个月的记录。脚本可以做成增量式的只拉created_at比上次备份时间新的会话速度快很多。第四个心得是注意智能体配置的备份。聊天记录只是数据的一部分如果你自己搭建过智能体它的提示词、知识库文件、参数配置同样重要。这些内容有的在会话里有的在单独的配置接口里导出的时候别漏了。我一般会把智能体配置单独存一个JSON和聊天记录放一起。最后说个细节导出的Markdown文件如果会话标题有重复会互相覆盖。我在脚本里加了个序号前缀比如001_文案润色助手.md这样就不会冲突了。小问题但不注意的话会丢文件。这套流程我跑了三个月累计导出了四百多个会话没出过什么大问题。核心就是理解数据在哪、怎么拿、怎么存这三件事。工具会变、接口会变但思路是通用的。你要是也在用豆包智能体攒了一堆对话不妨按这个路子试一次跑通之后心里会踏实很多。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →