- AI Agent
- 人工智能
- 大模型
- AI 应用
- 工具调用
- 本地部署
- MCP Clients
- Agent 记忆
【免费下载链接】Operit
The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent
本文档系统讲解 Operit(Android 上的 AI Agent 与 AI 聊天应用)所采用的 Markdown 聊天记录导入/导出格式。该格式以简洁的 HTML 注释承载元数据,让用户无需编写复杂 JSON 即可手工编写对话记录,并支持通过 Zip 压缩包批量迁移多个对话。读完本文,你将掌握 chat-info / msg 注释的完整语法、默认值规则、格式自动检测逻辑,以及导入导出在源码层的实现原理,能够自行编写、校验并批量迁移 Operit 聊天记录。
为什么选择「HTML 注释 + Markdown」格式
在导入/导出聊天记录的场景中,最常见的做法是导出为结构化 JSON。但 Operit 面向的是「人可以直接阅读、甚至可以手工编写」的交换格式,因此采用了基于 HTML 注释的简洁解析模式。
- 简单易写:使用
key=value键值对注释存储元数据,无需编写复杂 JSON; - 大量缺省:只需指定必要信息,其余字段自动生成;
- 精准分割:基于注释分割消息,消息内容纯净,不受正文干扰;
- 批量支持:通过 Zip 压缩包支持多对话一次性导入/导出。
该设计理念在格式协议文档中定义为“新版 Markdown 格式聊天记录导入规范”,并在导入示例文件中给出了可直接使用的完整样例。
关键约定:每个 Markdown 文件对应一个独立对话。不再支持在单个文件中使用
---分割多个对话;---出现时会被视为正文内容的一部分。
单文件基本结构
一个合法的导入文件包含三个部分:chat-info全局元数据注释、若干条msg消息注释、以及紧随其后的消息正文。以下示例取自 chat_import_markdown_example.md:
<!-- chat-info: title=Python 编程讨论, group=编程技术 --> # Python 编程讨论 <!-- msg: user --> ## 👤 User 如何在 Python 中读取 JSON 文件? <!-- msg: ai, model=gpt-4 --> ## 🤖 Assistant *Model: gpt-4* 在 Python 中读取 JSON 文件很简单,可以使用内置的 `json` 模块: ```python import json # 方法1:读取 JSON 文件 with open('data.json', 'r', encoding='utf-8') as f: data = json.load(f)关键要点:
json.load()用于从文件对象读取json.loads()用于从字符串读取
👤 User
如果 JSON 文件很大怎么办?
可以看出:文件开头可选的 `# 标题`、每条消息前的 `## 👤 User` / `## 🤖 Assistant` 装饰标题,在导入时都会被自动忽略或按装饰处理,真正驱动解析的是注释标记。 ## chat-info:全局元数据注释 文件头部包含 `chat-info` 注释,用于描述整个对话的元信息。 **格式**: ```html <!-- chat-info: key=value, key=value -->支持字段(均可选):
| 字段 | 说明 | 缺省值 |
|---|---|---|
title | 对话标题 | "Imported from Markdown" |
created | 创建时间 | 当前导入时间 |
id | 唯一标识符 | 自动生成 UUID |
group | 分组名称 | "从 Markdown 导入" |
示例:
<!-- chat-info: title=Python 学习笔记, group=编程 -->在源码 MarkdownConverter.kt 中,chat-info的解析逻辑位于主解析循环开头:命中<!-- chat-info:前缀后调用parseSimpleProperties提取键值对,其中title与created会被实际消费,分别覆盖标题与创建时间;created字符串通过parseDate按多种格式尝试解析(如ISO_LOCAL_DATE_TIME、yyyy-MM-dd HH:mm:ss等,见dateFormatters列表)。其余字段如id、group在导入端并不覆盖内部值——id一律重新生成UUID.randomUUID(),group统一取本地化字符串markdown_import_from(即“从 Markdown 导入”)。
msg:消息元数据注释
每条消息以msg注释开头,声明角色及可选的模型、时间戳信息。
格式:
<!-- msg: role, key=value... -->支持简写:可以直接写角色名,无需role=前缀。
<!-- msg: user -->等同于<!-- msg: role=user --><!-- msg: ai -->等同于<!-- msg: role=ai -->
支持字段:
| 字段 | 说明 | 缺省值 |
|---|---|---|
role | 角色 (user/ai) | user |
model | 模型名称 | markdown |
timestamp | 时间戳 | 自动顺序生成 |
示例:
<!-- msg: user --> <!-- msg: ai, model=gpt-4 --> <!-- msg: user, timestamp=1700000000000 -->源码层面的解析细节(MarkdownConverter.kt):
- 属性按逗号或分号分割,
key=value形式存入映射;没有等号的项(如简写角色user)整体作为 key、值为空字符串存入——这为角色简写提供了统一的数据结构基础; - 角色识别由
parseRole完成:除user/ai/assistant英文关键字外,还支持本地化字符串(如中文“用户/助手/系统/模型”,取自R.string.message_role_user、R.string.role_assistant等),并且会先剔除 emoji 与特殊符号再比对;system被映射为user,model被映射为ai;无法识别时返回null,此时才回退到默认角色user; model缺省为字符串markdown;timestamp缺省时按baseTimestamp + messageIndex * 100L自动顺序生成,保证消息时间戳单调递增;显式给出则直接使用。
消息内容与装饰标题处理
紧跟在msg注释后的内容即为消息正文。若注释后紧接着出现## User或## Assistant形式的标题,导入时会自动将该行忽略(作为视觉装饰)。
源码中通过justStartedMessage标志实现该逻辑(MarkdownConverter.kt):在刚解析完一条msg注释后,若遇到以##开头的行,且该行经parseRole可识别为角色文本,则跳过;注释后的空行同样被跳过;此后所有非注释行按行追加进当前消息内容,直至下一条msg注释出现。
也就是说,正文中的任何 Markdown 语法(代码块、列表、加粗、嵌套标题等)都会原样保留,导入端不会做内容改写,消息内容“纯净”地取自注释之间的区间。
格式自动检测:如何识别 Markdown 导入文件
Operit 的导入流程并不要求用户手动声明格式,而是由 ChatFormatDetector.kt 自动判定:
- 强匹配:内容中任意一行以
<!-- chat-info:或<!-- msg:开头,直接判定为 Markdown 格式; - 弱匹配:同时满足「存在
#开头的 Markdown 标题」与「存在## User|Assistant|AI|System|Model|用户|助手|系统|模型这类整行对话标记」时,也判定为 Markdown; - 检测顺序为 Markdown → CSV → JSON(含 ChatGPT / Operit / Claude / 通用 JSON 细分)→ 纯文本,见
detectFormat与detectFormatByExtension(.md/.markdown扩展名直接映射为 MARKDOWN)。
导入端的分发逻辑位于 ChatHistoryManager.kt,检测结果为ChatFormat.MARKDOWN时实例化MarkdownConverter(context)执行转换;转换失败会抛出携带本地化提示文案的ConversionException。
导出实现:导入格式的镜像
Operit 导出 Markdown 时(MarkdownExporter.kt)生成的产物与导入规范完全互操作:
- 头部写入一行
chat-info,依次携带id、title、created、updated与可选的group; - 同时保留一段 YAML Front Matter(
title/created/updated/group/messages计数)用于兼容旧版解析器与提升可读性——导入端 MarkdownConverter.kt 也确实兼容解析旧版 YAML Front Matter; - 每条消息输出
<!-- msg: role, model=..., timestamp=... -->(角色用简写形式,模型非markdown时才写出,时间戳总是写出); - 随后附上
## 👤 User/## 🤖 Assistant装饰标题与*Model: xxx*视觉元信息,便于人类阅读; - 消息正文原样写出。
由此,导出文件可直接作为导入文件使用,形成闭合的“导出 → 手工编辑 → 再导入”工作流。
Zip 批量导入/导出
当对话数量较多时,Operit 通过 Zip 压缩包统一管理。
导出:选择 Markdown 导出多对话时,系统生成chat_backup_<时间戳>.zip。包内每个对话对应一个.md文件,文件名为对话标题;非法文件名字符(\ / : * ? " < > |)会被替换为下划线,重名文件自动追加(1)、(2)等序号避免覆盖(见 ChatHistoryManager.kt,使用ZipOutputStream逐条写入)。
导入:将多个符合规范的.md文件打包为.zip后一次性导入,系统使用ZipInputStream自动解压并逐个读取包内所有.md文件,每个文件被导入为一个独立对话。
常见问题
Q: 可以在一个文件中混合不同的对话吗?
A:不再支持。每个对话必须保存为单独的.md文件;在单个文件中使用---分隔会被当作正文内容的一部分。源码 MarkdownConverter.kt 中splitConversations直接返回整个文件内容,注释明确说明“不再支持通过---分割对话,整个文件视为一个对话”。
Q: 我可以手动编写这种格式吗?
A:可以。只需确保文件扩展名为.md,且包含<!-- msg: ... -->注释即可。其余字段均可省略,靠缺省值兜底。
Q: 为什么我的文件无法导入?
A:请依次检查:
- 文件是否包含
<!-- msg: ... -->注释(这是格式检测与消息解析的前提); - 如果是 Zip 包,请确保包内是
.md文件而不是嵌套压缩包或其他格式; - 确认没有在单个文件中用
---尝试分割多个对话。
兼容性与边界说明
- 旧版兼容:导入端仍支持 YAML Front Matter 头部(
title:、created:键值),可平滑迁移旧格式文件; - 角色映射:
system角色在导入时被映射为user,model被映射为ai,说明当前对话模型以双角色(user/ai)为主; - 本地化:角色识别与导入分组的文案均走资源字符串(
values/strings.xml及values-en、values-ro等多语言副本),意味着非英文角色名也可被识别; - 格式边界:
ChatFormat枚举中还包含 OPERIT(原生 JSON)、CHATGPT、CHATBOX、CLAUDE、GENERIC_JSON、CSV、PLAIN_TEXT 等格式(见 ChatFormat.kt),Markdown 只是导入生态中的一环;Claude 格式目前回退到通用 JSON 转换器处理。
掌握以上规范后,你既可以手工编写或程序化生成 Operit 可识别的 Markdown 对话文件,也能理解导出产物的每个字段来源,实现跨设备、跨工具的聊天记录无损迁移。
- AI Agent
- 人工智能
- 大模型
- AI 应用
- 工具调用
- 本地部署
- MCP Clients
- Agent 记忆
【免费下载链接】Operit
The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent
相关推荐
Operit 新版 Markdown 聊天记录导入/导出格式全指南:基于 HTML 注释的轻量对话交换协议
Operit 新版 Markdown 聊天记录导入/导出格式全指南:基于 HTML 注释的轻量对话交换协议 本指南系统讲解 Operit(Android 端 A
AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆GUI 自动化Operit 聊天记录按会话选择导出:从全量导出到多选归档的交互设计与实现
Operit 聊天记录按会话选择导出:从全量导出到多选归档的交互设计与实现 本文以 Operit 的「设置 数据备份与恢复 聊天记录」导出功能为对象,系统讲解其
AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆GUI 自动化微信聊天记录永久保存指南:3种格式轻松导出你的珍贵对话
微信聊天记录永久保存指南:3种格式轻松导出你的珍贵对话 还在担心重要的微信对话会丢失吗?想要永久保存那些珍贵的聊天记录吗?现在,通过这款强大的微信消息管理工具,
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考