拓冰建站拓冰建站
首页 / 资讯中心 / 正文

豆包智能体聊天记录导出与拆分:从JSON到Markdown的完整方案

这个需求我太懂了。在豆包里和智能体一来一回聊了好几个月想把这些对话记录整理出来却发现根本没有一个“导出聊天记录”的按钮尤其是记录已经多到几百上千轮的时候手动复制粘贴根本不现实而且复制出来的内容全是混在一起的根本分不清哪句是用户说的、哪句是智能体回的。这篇内容就是我处理豆包智能体聊天记录导出的完整过程包含怎么把用户和智能体的消息分开、记录量特别大时怎么处理以及我在实际整理中踩过的几个坑。如果你也面临同样的问题可以直接照着下面的方案选一个适合你的来操作。1. 为什么豆包里没有“导出聊天记录”这个按钮——先弄清数据怎么存先说个反常识的结论豆包智能体的聊天记录从来不是按“一篇对话”存在你的手机或电脑里的。实际存法是每一次对话是一个会话conversation会话下面挂着很多条消息message而每一条消息除了纯文本内容还带发送者字段、时间戳、消息ID等属性。用户消息和智能体回复在数据库里是像“一行一条”那样规整分开的发送者字段一般就是两种取值user 和 assistant或者叫 role 为 user 和 agent。这种数据形态意味着分开用户和智能体在数据层面完全没有难度难点只在于你用什么方式把数据拿到自己手里。理解了这一点再回头看产品界面上为什么没有一键导出你就能明白不是技术上做不了而是产品把重心放在了对话体验上导出这类需求通常要靠使用者自己想办法。想清了“数据本来就是分开存的”这个前提后面所有方案都只是“怎么把数据取出来”的问题。1.1 别被“记录有点多”带偏先想清楚导出后要干什么“记录太多了”这个说法背后通常对应着几种完全不同的需求有人想把对话整理成一份可读的文档留存有人想把智能体给过的建议单独拎出来做成自己的知识库也有人想把所有内容按时间顺序完整备份下来。需求不同导出方案也不会一样。如果是前两种我会建议你拿到 JSON 或 Markdown 格式方便后续检索和再加工如果只是留存查看那截长图、整段复制其实也够用。很多人一开始就直接问“怎么分用户和智能体”但我建议你先反问自己一句我到底要拿这些记录做什么想清楚这件事你再决定用第2章里的哪条路线后面处理的时候就不会在格式问题上反复纠结。1.2 数据字段的长相决定了拆分逻辑怎么设计我直接给一个典型的消息数据长什么样不同客户端版本字段名可能有差异但方向不会差太多字段名示例值作用conversation_id69012ab3标识属于哪一次会话message_idmsg_8847全局唯一用来去重sender_typeuser / assistant决定这条消息是谁说的content帮我梳理一下最近三天的学习计划消息正文create_time2025-06-01 22:14:03排序和时间线分析的关键如果你最终拿到的是这样一条条的结构化数据那“分开用户和智能体”就是一次简单的筛选取出 sender_typeuser 的行是用户视角取出 sender_typeassistant 的行是智能体视角如果你还想保留完整对话流就按 create_time 排序原样导出再按会话边界拆分。后面第3章里面的脚本核心逻辑就是这么几行并不会复杂。2. 四条可行路线从手动复制到接口取数按数据完整度排序当你理解了数据底层是“一行一条”接下来就是选择用哪种方式把数据取出来。我列了四条路线按“能拿到的数据完整度”从低到高排。选择的标准很简单记录越少越可以用轻量办法记录越多且结构越重要越应该往后面两种方案靠。2.1 方案A网页端手动复制适合几十轮以内的短对话如果你只需要导出一小段对话比如十来条消息那最快的方法就是打开豆包网页版找到目标会话鼠标从对话开头拖到结尾直接复制粘贴到文档里。这个方法的优点是不需要任何工具和技术门槛。但缺点也很明显网页版长列表滚动到顶部再全选非常容易漏消息复制出来的格式在不同浏览器里也不统一有些会带多余的空行而且因为没有结构化字段复制之后你得靠肉眼去区分哪句是用户、哪句是智能体。一旦对话超过几十条这个方案基本就不可用了所以我把它定义为“应急方案”不太适合你说的“记录有点多”的场景。2.2 方案B浏览器控制台直接抓取页面信息半自动生成可拆分文本比我上面那种手动复制好用一点的办法是用浏览器开发者工具去读已经渲染好的对话节点。具体操作在豆包网页版打开某个会话按 F12 打开开发者工具切到 Console控制台面板然后粘贴一段 JavaScript 代码让它把页面上所有消息节点抓出来再按发送者类型打上标记。下面是一个通用思路的示例豆包网页端如果更新了命名规则需要自己对一下实际 DOM 结构再调整字段const rows document.querySelectorAll([class*chat-message], [class*message-item]); let output ; rows.forEach((node, i) { const text node.innerText.trim(); if (!text) return; const isUser /user|human|用户/i.test(node.className); output (isUser ? \n## 用户\n : \n## 智能体\n) text \n; }); console.log(output); copy(output);这段代码的核心思路是通过判断消息节点 class 或 data 属性里的关键词来识别是用户消息还是智能体消息然后把每一条消息前面加上“## 用户”或“## 智能体”的标记最后生成一段带结构前缀的文本直接复制到剪贴板。优点是你不用碰任何接口也不用理解后端逻辑会打开控制台粘贴代码就行。缺点是它依赖页面 DOM 结构豆包前端一旦改版选择器可能就失效而且如果对话特别长浏览器在滚动过程中可能只渲染了一部分节点你需要借助自动滚动脚本把所有内容都触发出来操作上会稍麻烦一点。2.3 方案C抓接口拿原始 JSON全量记录且结构最完整如果你想要的不是“看起来像分开了”而是“数据本来就分开”那我最推荐这条路线直接抓豆包网页版的网络请求拿到对话历史上的 JSON 数据。操作流程是这样的在豆包网页版打开一个会话按 F12 切到 Network网络面板然后刷新页面或者在对话窗口里随便发一条消息接着在过滤框里输入类似 “message”“chat”“conversation”“history” 的关键词找到那些负责返回历史消息的接口。点开接口名在 Response响应标签页里你能看到一长串 JSON里面通常就是当前会话的消息列表。看到 JSON 之后鼠标右键选择 “Copy response” 或者 “Save as”把接口返回的完整内容保存到本地文件。这个方案的好处在数据层面最明显每条消息的 sender_type、content、create_time、message_id 都原样保存在 JSON 里不存在“混在一起”的问题拆分只是几行脚本的事。难点在于你需要稍微懂一点接口抓包知识能判断哪个接口才是真正的消息记录接口。另外如果豆包的接口做了分页一次请求可能只返回最近几十条你需要根据返回里的 cursor 或 page 参数继续翻页拉取。这部分逻辑不复杂但第一次找接口确实要花点时间。2.4 方案D读取客户端或手机本地数据库完整度最高但对设备权限要求高还有一种思路是绕过界面和接口直接去本地找豆包客户端缓存的数据库文件。手机端的情况是这样的Android 上豆包的数据通常存在私有目录里比如类似/data/data/com.example.doubao/databases/的路径正常用户没有 root 权限进不去哪怕用adb backup备份数据也不一定以明文形式出现。iOS 因为沙盒机制更严格普通用户基本拿不到原始数据库文件。电脑端客户端会比手机端稍微靠谱点。在 Windows 上如果豆包有桌面客户端它通常会在用户目录下的 Application Data 里存放本地缓存或数据库文件。你可以打开“运行”窗口输入%APPDATA%或者打开“资源管理器”地址栏输入%localappdata%然后在文件列表里按关键词搜索和豆包有关的目录找到后缀为.db或.sqlite的文件。找到之后用 DB Browser for SQLite 这类工具打开查看数据表结构把 messages 表里的内容导出来。这个方案能拿到最完整的数据但前提条件也确实苛刻路径因版本而异、数据库可能加密、桌面端缓存未必包含全部历史记录。所以我通常把它当作兜底方案只有当你对前几种路线都不放心而且确实能拿到文件权限时才去尝试。2.5 四条路线怎么选完整度与实际够用之间的取舍我把四条路线放在一起做个对比方便你快速决策方案数据完整度适合场景前置条件A 手动复制低偶尔一段短对话临时留存无B 控制台抓页面节点中记录量较大但不想接触接口能接受格式损失会打开浏览器控制台粘贴代码C 抓接口拿 JSON高需要结构完整、要分层处理、长期保存能看 Network 面板稍微认识接口返回D 本地数据库读取高想做离线完整备份或深入分析有设备文件权限懂一点数据库工具我的建议是如果你只回答“能不能分开用户和智能体”那答案是肯定能如果你问我用哪种方式最划算我一般会推荐方案C。因为它是获取全量结构化数据的最短路径不会像方案D那样受到设备权限限制也不会像方案B那样受前端改版影响。3. 分开“用户”和“智能体”把混合记录拆成结构化文件数据拿到手之后真正的重头戏才刚开始。不管你是从方案B拿到了带“## 用户”前缀的文本还是从方案C拿到了 JSON都需要在本地做一次拆分和清洗最终变成你想要的文件。3.1 先定输出格式Markdown、JSON、Excel 各自适合什么场景在写拆分脚本之前先想好最后要导出成什么文件。三种格式各有适用场景输出格式适合用途优点缺点Markdown阅读、共享、写总结人可读性最好能保留标题层级后续再分析需要重新解析JSON程序处理、二次加工字段完整、无损保留人直接看会犯晕Excel/CSV统计、筛选、做表可以透视、排序、画图长文本会撑爆单元格显示不友好我的个人习惯是JSON 做原始存档Markdown 做人可读版本。原始数据别丢Markdown 只是给人看的“渲染结果”。如果你不是程序爱好者那就直接以 Markdown 为主省事。3.2 从 JSON 里按角色提取用户和智能体消息如果你走的是方案C拿到了消息列表 JSON那用 Python 写一个拆分脚本很直接。假设你的 JSON 结构里面有messages数组每条消息包含sender_type和content字段字段名可能不一样先打印看结构脚本可以这样写import json with open(doubao_chat.json, r, encodingutf-8) as f: data json.load(f) # 常见结构可能是 data[messages] 或 data[items] 或 data[data] messages data.get(messages) or data.get(items) or data.get(data, []) user_messages [] agent_messages [] for msg in messages: sender (msg.get(sender_type) or msg.get(role) or ).lower() content (msg.get(content) or msg.get(text) or ).strip() if not content: continue if user in sender or human in sender: user_messages.append(content) else: agent_messages.append(content) with open(user_only.md, w, encodingutf-8) as f: f.write(\n\n.join(user_messages)) with open(agent_only.md, w, encodingutf-8) as f: f.write(\n\n.join(agent_messages))这里面有两个常见坑。第一个坑是接口返回的 key 不叫sender_type而可能叫author、from、sender、send_id所以脚本里我用了msg.get(sender_type) or msg.get(role)这样的兜底第二个坑是返回的数据可能不是数组而是套了一层data、items之类的包装。遇到结构不对时先用print(json.dumps(messages[:2], ensure_asciiFalse, indent2))打印前两条消息看清楚 key 叫什么再做调整。3.3 从复制粘贴的纯文本里反推对话双方如果你只有方案A那种整段复制的文本文本里没有 JSON 的结构化字段但也有办法拆。前提是你在粘贴时尽量保留了对话前缀或者至少能观察到对话的规律。比如很多聊天应用复制出来是这样的用户帮我写一份周报 智能体好的这是周报的结构…… 用户再精简一点 智能体精简后的版本如下……那你可以用正则表达式按“前缀”切分。Python 示例import re text open(chat.txt, r, encodingutf-8).read() # 匹配以“用户”或“智能体”开头的段落 pattern re.compile( r^(用户|智能体)[:]\s*(.?)(?^(?:用户|智能体)[:]|\Z), re.M | re.S ) for match in pattern.finditer(text): role match.group(1) content match.group(2).strip() print(f--- {role} ---) print(content)这里的正则逻辑是找到所有以“用户”或“智能体”开头的内容一直匹配到下一个同类前缀出现为止。如果复制出来的文本里带了时间戳比如“用户 2025-06-01 22:14:03”那就在正则里加上时间戳模式稍微改一下就能适配。3.4 不要只导出“只看用户”和“只看智能体”完整对话流同样重要很多人拿到拆分结果后会把用户消息单独存成一个文件、智能体消息单独存成另一个文件然后就不管了。但我遇到过好几次这样的情况过了几周再回来看单独的用户消息完全看不懂当时在问什么因为缺少智能体当时的回应单独看智能体消息也搞不清它在回答什么问题。所以我建议拆完之后再导一份“完整对话流”的 Markdown 文件把 user 和 agent 消息按时间排序交错排列并在每条消息前用加粗标题标明角色。这样你既能得到干净的“只有用户”和“只有智能体”文件又能留一份带上下文的完整版。具体做法就是在脚本里把user_messages和agent_messages按create_time合并成一个列表再写文件或者直接遍历原始 messages 数组每一条都输出为## 用户或## 智能体的标题加正文。4. 记录量近千条时怎样批量处理才不容易乱“记录有点太多”这个场景最怕的不是拆分脚本跑不起来而是你拉取数据的过程中漏了很多条、最后记录顺序乱了、或者同一个会话被拆成了好几段这些问题在大批量记录里会成倍放大。4.1 分页拉取时注意 cursor 和 offset方案C里提到接口一次最多返回几十条消息后面需要通过翻页拿完整记录。这种翻页常见有两种形式一种是返回一个next_cursor或cursor字段第二次请求时把这个字段带进去另一种是直接给page_num和page_size或者offset和limit手动累加页码。我的建议是写个小循环让它一直请求到没有下一页为止同时把每一条消息的message_id存到一个集合里用于去重。因为部分接口在翻页过程中可能会出现重复数据去重能防止最终文件里出现大量相同消息。脚本里判断结束的条件一般是这样返回的列表长度小于请求的page_size或者has_more字段为 false或者next_cursor为空不同接口字段名不一样以实际为准。4.2 合并多个导出文件时按消息ID去重如果你是从多个时间段分别导出或者在一个会话里翻了两次接口很有可能会出现同样的消息出现在两个文件里。合并的时候不要单纯按内容去重因为同一条内容可能被用户复制粘贴过多次本来就在对话里重复出现。最好的做法是拿message_id做去重没有消息ID时再退而求其次用 “会话ID 发送者 发送时间 内容前50字” 拼出来一个组合键做去重。这里的逻辑不复杂但确实是我在整理批量数据时最容易踩的坑。4.3 按时间间隔和会话ID切分“多轮对话”豆包里所谓的“会话”有时候是一个长期大窗口里面的话题可能一天一个样。如果你想把这些记录按“某一次讨论”拆开光靠conversation_id不够因为同一个会话下可能聊了很多不同主题。比较通用的切分思路是看时间间隔如果一条智能体回复和上一条用户消息之间的间隔超过了30分钟就默认这是一次新话题的边界。你可以把这个阈值设成10分钟、30分钟或更久取决于平时的聊天习惯。如果你拿到的字段里有更细的session_id或topic_id那优先按这个字段切时间间隔只作为辅助判断。这样处理之后几百上千条消息会被整理成若干个“对话块”每个块内部是正常的你来我往块与块之间泾渭分明。4.4 先过滤再导出避免用不到的记录占用空间记录量大的另一个麻烦是文件本身会很臃肿。有时候你其实并不需要全部消息而只需要某个日期之后的内容或者只关注包含“方案”“总结”“计划”这类关键词的智能体回复。可以在脚本里加一个过滤条件在输出前先筛掉不相关的内容。比如你只想导出智能体那边给过的方法论类回答那就遍历agent_messages用关键词列表做一次包含匹配keywords [总结, 建议, 步骤, 方案] filtered [msg for msg in agent_messages if any(k in msg for k in keywords)]这样做的好处有两点一是你拿到手的文件更短可读性更强二是你不需要在导出之后再手动删减省掉一个步骤。对应的代价是可能漏掉一些你当时没想到要保留的内容所以最保险的策略仍然是先全量存档 JSON再用过滤脚本去生成“精简版”。5. 我在导出和整理记录过程中踩过的几个关键坑到最后这部分我想分享几个我在实际操作中真真实实遇到过的问题。这些问题不一定每个都会出现在你身上但提前知道能帮你少走一些弯路。5.1 复制出来的代码块变成了一行格式直接报废方案A手动复制或者方案B抓取 DOM 时智能体回复里的代码块经常被压成一行。比如它本来给你的是带换行的列表和缩进复制到文档里之后所有换行都消失了变成了一个连续的长段落阅读体验非常糟糕。解决办法有两个一是优先走接口 JSON 方案因为 JSON 里的content字段保留了原始换行符二是如果只能用 DOM 抓取在 JavaScript 脚本里尽量用textContent配合innerText的差异去处理至少保留一部分段落结构。不要天真地以为“复制粘贴就是无损的”对于大段程序代码和列表内容粘贴后真的要检查格式。5.2 智能体消息被流式截断残缺消息需要用标记代替猜测豆包的智能体回复是流式生成的你在界面上看到的可能是一个字一个字蹦出来的。如果你在生成过程中强行刷新页面或者接口抓包时机太早有可能拿到一条只生成到一半的消息结尾非常突兀。碰到这种情况我的做法是在导出脚本里加一条判断如果智能体消息的最后一段没有正常结束比如最后是空格、逗号、或者明显截断的代码就在这一条后面加上“【本条可能不完整】”的标记而不是自作聪明地去补全它。因为补全可能引入错误信息标记出来至少能提醒以后的自己“这条消息当时没有看到结尾”。5.3 网页端和手机App的数据不同步混着用会漏记录豆包的网页版和手机端数据在某些情况下不同步尤其是你在手机上聊了一部分、又在网页上聊了一部分的时候两边分别导出的记录很可能各有缺失。如果你想做全量备份尽量固定在一个端上导出导出前先在那个端上翻一遍关键会话确认历史记录已经加载完整。不要一会儿用网页接口抓一半一会儿用手机数据库导一半然后直接合并那样很容易出现同一条消息在两个文件里存在但内容版本还不一样的情况。5.4 导出文件里往往带有大量个人隐私信息处理时留个心眼聊天记录这类数据尤其涉及工作细节和个人生活的时候敏感度比一般文本要高很多。导出之后文件不要随手放到公开网盘也不建议直接把完整记录粘贴到第三方工具做二次加工。我在整理完豆包智能体聊天记录之后会把 JSON 原档单独放在本地目录里只把脱敏后的 Markdown 分享给需要的人。做批量统计或格式化处理时也尽量用本地脚本跑完再把结果发出去。这一步不是为了制造麻烦而是事后省心。整理完这些记录后我最大的体会是豆包智能体聊天记录的导出本质上不是一个“找按钮”的问题而是一个“拿数据”的问题。只要理解它的数据是以结构化字段方式存储的分离用户和智能体就是可行的并且可以做得很干净。希望这篇记录能帮你少折腾几小时如果你在实际操作中遇到过更奇怪的坑也欢迎按同样思路在本地多做几轮验证方法本身是通用的。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门