欢迎光临
我们一直在努力

Zorv AI 对话框 AIP 排版引擎:让大模型回答在聊天气泡里直接长成文档 / PPT / 思维导图

根据您提供的文档片段和上下文,以下是为您还原并整理完整的 Zorv AI 技术架构文档。

这份文档详细阐述了 Zorv AI 如何通过 AIP (AI Presentation Protocol) 协议,将大模型的流式输出转化为对话框内原生的文档、PPT 和思维导图渲染。


📄 Zorv AI 对话框 AIP 排版引擎 · 技术架构文档

AIP = AI Presentation Protocol 让大模型的长回答不再是“一坨 Markdown",而是在聊天气泡里直接长成 文档 / PPT / 思维导图 的原生排版协议。

源码依据:github.com/Quor-a/ZorvAI @ main (2026-09-07) 包名:com.ai.assistance.quro · 技术栈:Kotlin + Jetpack Compose · 协议:Apache-2.0


📑 目录

  • 定位与设计原则
  • 全局分层架构
  • 三档通道与路由决策
  • 协议层:AIP 信封与块型
  • 容错解析:四级降级机制
  • 形态互转与导出序列化
  • 渲染层:AIP Canvas
  • 对话框接入链路
  • 工具调用通道:aip_compose
  • 模型侧契约(系统提示词)
  • 端到端时序
  • 工程坑位与修复清单
  • 代码地图与规模

  • 一、定位与设计原则

    1.1 它解决什么问题

    在传统 AI 对话框中,面对“写一份行业调研报告”或“做个 PPT"的需求,用户通常只有两种糟糕的体验:

  • 纯 Markdown:排版简陋,难以阅读长文档。
  • 生成文件跳转:必须下载文件并跳出对话去打开,打断心流。
  • AIP 走出了第三条路: 模型输出结构化 JSON 信封 ➡️ 客户端原生渲染 ➡️ 排版结果直接长在聊天气泡里。支持一键转换为 PPT、思维导图,或直接导出为 docx/pptx 文件。

    1.2 四条设计原则

    源自 Aip.kt 文件头注释及 PRD 4.1:

    原则实现手段
    流式友好 lastSafeCut() 截断边界扫描,任意位置截断都能部分解析
    模型友好 optString/optInt + 默认值 + 安全转换,字段缺失不报错(L1)
    渲染友好 一个 Block = 一个可独立渲染的 UI 单元,块间无隐式依赖
    演进友好 未知块型 → Block.Fallback 富文本兜底,绝不丢弃内容

    1.3 三条硬底线

  • 永不空白气泡:解析彻底失败也走 Markdown 兜底。
  • JSON 源码不上界面:用户永远看不到原始 JSON,只看到渲染后的精美 UI(仅 Fallback 会显示原始内容,且渲染为富文本)。
  • 零三方依赖:解析使用标准 org.json,图表使用 Compose Canvas 手绘,导出使用自研 OOXML 引擎。

  • 二、全局分层架构

    Zorv AI 采用严格的分层架构,确保协议解析与 UI 渲染解耦:

    ┌──────────────────────────────────────────────────────────────────┐
    │ L5 模型契约层 QuroChatViewModel 系统提示词 │
    │ 通道路由表 / AIP 信封结构 / 16+ 块型说明 / 写法铁律 │
    ├──────────────────────────────────────────────────────────────────┤
    │ L4 路由层 CanvasRouter.kt │
    │ A 增强 Markdown │ B 结构化 AIP │ C WebView 模板 │
    ├──────────────────────────────────────────────────────────────────┤
    │ L3 接入层 ChatScreen.kt │
    │ parseBlocks() 围栏识别 → MsgBlock.Aip │
    │ 气泡过滤 + 消息底部全宽内联 │
    │ 工具结果路径:aip_compose 返回值嗅探 │
    ├──────────────────────────────────────────────────────────────────┤
    │ L2 协议层 core/canvas/Aip.kt │
    │ Envelope / Block(18) / parse() / 四级降级 │
    │ sanitizeJson · extractEnvelopeJson · lastSafeCut │
    ├──────────────────────────────────────────────────────────────────┤
    │ L2' 转换层 core/canvas/AipConvert.kt │
    │ doc ⇄ deck ⇄ mindmap · toMarkdown · toPptxText │
    ├──────────────────────────────────────────────────────────────────┤
    │ L1 渲染层 ui/canvas/AipCanvas.kt │
    │ AipCanvas · AipCanvasBlock(when 注册表) │
    │ DeckPager · SlideCard · MindmapView · AipChart │
    ├──────────────────────────────────────────────────────────────────┤
    │ L0 基础设施 MarkdownText · HtmlPreviewWebView · AiwpsCreateTool│
    └──────────────────────────────────────────────────────────────────┘

    关键解耦:协议层(core/canvas)不 import 任何 Compose;渲染层(ui/canvas)不碰 JSON。两边只通过 Aip.Block sealed interface 对话。


    三、三档通道与路由决策

    3.1 通道定义

    通道名称覆盖场景实现方式
    A 增强 Markdown 默认档,约 70% 日常问答 Compose 原生 MarkdownText
    B 结构化 AIP 长文档 / 导图 / PPT / 图表主力 Aip.parse + AipCanvas 原生渲染
    C WebView 模板 逃生舱,B 表达不了时启用 复用既有 html 工件路径

    3.2 决策链 (CanvasRouter.route)

    系统根据用户意图和流式内容动态选择最佳渲染模式:

    flowchart TD A[用户 query] –> B{硬指令关键词命中?} B –>|PPT/幻灯/演示文稿/汇报材料 | C[锁定 deck → B 通道] B –>|思维导图/脑图/发散一下 | D[锁定 mindmap → B 通道] B –>|写成文档/调研报告/建设方案 | E[锁定 doc → B 通道] B –>|否 | F{信封头 kind 有效?} F –>|doc/deck/mindmap| G[信封头信号 → B 通道] F –>|否 | H{复杂度启发式} H –>|长度>1500 或 二级标题≥3 或 含表格图表 | I[升 B 通道] H –>|否 | J[默认 A 通道]

    关键词规则表:

    • Deck: "ppt", "幻灯", "汇报材料", "演示文稿", "slide", "做成演示", "deck"
    • Mindmap: "思维导图", "导图", "脑图", "mindmap", "发散一下", "头脑风暴", "梳理一下结构"
    • Doc: "写成文档", "写一份", "调研报告", "建设方案", "行业方案", "长文档", "word", "docx"

    ⚠️ 注意:代码实际执行顺序为「硬指令 → 信封头 → 复杂度 → 兜底」。虽然注释提及意图分类器,但 V1 版本主要依赖规则匹配。

    3.3 生成中途软重路由

    若模型声称输出 AIP 但实际一直在吐 Markdown,系统执行软改道(不打断、不重绘):

    • 若前 120 token 未检测到信封头,或前 240 token 未检测到 "blocks" 字段,自动切换回 A 通道(Markdown)。

    四、协议层:AIP 信封与块型

    4.1 信封结构 (Envelope)

    模型输出的标准 JSON 结构,支持扁平与嵌套双兼容:

    {
    "v": 1,
    "kind": "doc",
    "meta": { "title": "行业调研", "author": "Zorv AI" },
    "theme": { "name": "aurora", "accent": "#2E6BE6" },
    "blocks": [
    { "type": "heading", "data": { "level": 1, "text": "市场概况" } },
    { "type": "chart", "data": { "chartType": "bar", "labels": […], "series": […] } }
    ]
    }

    兼容性逻辑:优先读取 meta.title,若为空则读取顶层 title;主题色同理。

    4.2 块型全表 (18 种)

    Aip.Block 是 sealed interface,包含 17 种具体类型 + 1 种兜底:

    #Type描述关键字段
    1 heading 标题 level(1-6), text
    2 paragraph 段落 text (支持 Markdown)
    3 list 列表 ordered, items[]
    4 table 表格 headers[], rows[][]
    5 code 代码块 lang, code
    6 quote 引用 text, cite
    7 callout 提示框 tone, title, text
    8 divider 分割线
    9 image 图片 ref, caption, ratio
    10 chart 图表 chartType, labels, series
    11 columns 分栏 ratio[], children[][]
    12 steps 步骤条 items[], direction
    13 timeline 时间轴 items[].{time,title,text}
    14 mindmap 思维导图 root (递归树结构)
    15 slide 幻灯片页 layout, bullets, stats 等
    16 section 章节 level, title
    17 html HTML html (兼容 data.html 或块级 html)
    fallback 兜底 type, text (未知/损坏块转为富文本)

    ⚠️ 文档债:系统提示词中常遗漏 html 块型说明,导致模型较少主动使用该类型,但引擎完全支持。


    五、容错解析:四级降级机制

    面对大模型流式输出的不稳定性(截断、格式错误),Zorv AI 设计了坚如磐石的容错机制:

    级别名称触发条件表现
    L1 字段级修复 类型不符 / 字段缺失 自动补全默认值,类型安全转换 (FieldRepair)
    L2 块级降级 单块解析抛异常 该块转为 Fallback 富文本,其余块正常渲染
    L3 通道降级 整体 JSON 解析失败 无缝回退至增强 Markdown 模式 (ChannelDown)
    L4 纯文本兜底 内容为空 / 彻底不可解析 按 raw 纯文本渲染,永不显示空白 (TextDown)

    核心容错算法

  • sanitizeJson:修复字符串内的裸换行符和控制字符,防止 JSONTokener 崩溃。
  • extractEnvelopeJson:从模型的废话(如“好的,这是您的文档:”)中精准提取第一个完整的 {…} JSON 对象。
  • lastSafeCut (流式截断修复):
    • 当网络中断在 JSON 中间时,通过深度扫描找到最后一个安全的闭合点(如完整块结束 } 或数组结束 ])。
    • 自动补全后缀(如 ]}),确保已接收的部分能立即渲染,绝不等待后续数据。

  • 六、形态互转与导出序列化

    AipConvert 模块让一份内容在三种形态间自由切换,用户点击 Chip 即可实时变换视图。

    6.1 转换矩阵

    • Doc ⇄ Deck:
      • Doc → Deck:标题变封面,段落聚合成要点,图表/表格独占一页。
      • Deck → Doc:每页转为 Section,要点转为列表。
    • Doc ⇄ Mindmap:
      • 依据标题层级(H1-H3)自动生成树状结构,正文截断为叶子节点。
    • 成本优化:若目标形态与当前一致,直接返回原对象(O(1));否则线性遍历 blocks (O(N))。

    6.2 导出序列化

    内置自研 OOXML 引擎(零三方依赖),支持导出:

    • .docx / .md:调用 toMarkdown()生成标准语法。
    • .pptx:调用 toPptxText(),利用 — 分页符控制幻灯片切分。
    • 智能分页:在转 PPT 时,强制让 Chart 和 Table 独占一页,避免排版破碎。

    七、渲染层:AIP Canvas

    基于 Jetpack Compose 的原生渲染器。

    7.1 核心逻辑

    @Composable
    fun AipCanvas(source: String, onLinkClick: (String) Unit) {
    val result = remember(source) { Aip.parse(source) } // 解析缓存
    var kindOverride by remember { mutableStateOf<String?>(null) }

    if (result.envelope != null) {
    val env = remember(result.envelope, kindOverride) { AipConvert.convert(result.envelope, kindOverride ?: result.envelope.kind)
    }
    // 渲染 Header + 工具栏 (Doc/Deck/Mindmap 切换) + Block 列表 Column {
    env.blocks.forEach { block -> AipCanvasBlock(block, onLinkClick)
    }
    }
    } else {
    // 降级处理:显示降级横幅 + MarkdownText(result.raw)
    }
    }

    7.2 块渲染注册表

    使用 when 表达式将 Aip.Block 映射到具体的 Composable 函数:

    • Heading → Text (不同字号/字重)
    • Chart → AipChart (Canvas 手绘柱状/折线/饼图)
    • Mindmap → MindmapView (自定义 Layout 绘制树状连线)
    • Slide → DeckPager (横向翻页器)
    • Fallback → MarkdownText (展示原始内容以防丢失)

    —## 八、对话框接入链路

  • 接收流:ChatViewModel 接收 SSE 流。
  • 预检:每帧调用 looksLikeAip() (O(1) 检查前 400 字符)。
  • 路由:若命中 B 通道,累积 Buffer;若命中 A 通道,直接推送到 Markdown 渲染器。
  • 解析:流结束时(或达到阈值),调用 Aip.parse()。
  • 渲染:
    • 成功:替换气泡内容为 AipCanvas。
    • 失败:保留 Markdown 视图,并在底部添加“尝试以文档视图查看”的 Toast(若部分解析成功)。

  • 九、工具调用通道:aip_compose

    除了直接输出 JSON,模型也可通过 Tool Call (aip_compose) 返回结构化数据。

    • 优势:强制模型遵循 Schema,减少格式错误。
    • 处理:ChatScreen 嗅探工具返回结果,若包含 blocks 字段,直接注入 AIP 解析流程,跳过围栏识别步骤。

    十、模型侧契约(系统提示词)

    System Prompt 中必须包含以下关键指令:

  • 格式铁律:输出必须包裹在 aip … 围栏中(可选,推荐直接输出 JSON)。
  • 块型限制:仅允许使用定义的 16+ 种块类型。
  • 容错引导:若无法生成完整 JSON,优先保证已生成部分的合法性,不要强行闭合导致整体解析失败。
  • Kind 声明:必须在信封头部明确声明 kind (doc/deck/mindmap)。

  • 十一、端到端时序

  • User: "帮我写一份关于新能源车的调研报告,要能转 PPT"
  • Router: 检测到 "调研报告" + "PPT" → 锁定 B 通道 (Deck)。
  • Model: 流式输出 JSON { "kind": "deck", "blocks": […] }。
  • Client:
    • 流式接收,lastSafeCut 实时监测。
    • 网络波动中断 → 自动截断并补全 ]}。
    • 解析出前 5 个 Slide → 立即渲染出前 5 页 PPT。
  • User: 点击 "文档视图" Chip。
  • Client: AipConvert.toDoc() → 瞬间重组 UI 为长文档模式。
  • User: 点击 "导出 PPTX"。
  • Client: 调用本地 OOXML 引擎 → 生成 .pptx 文件并分享。

  • 十二、工程坑位与修复清单

    • [已修复] BOM 头问题:trim() 不去除 \\uFEFF,导致 JSON 解析失败。→ 增加 trimStart('\\uFEFF')。
    • [已知] HTML 块缺失:Prompt 未提及 html 块型,模型极少使用。→ 待更新 System Prompt。
    • [优化] 深度嵌套:columns 块目前仅支持一层嵌套,过深会导致递归栈溢出或渲染错乱。→ 限制最大嵌套深度为 2。
    • [体验] 大图加载:image 块在弱网下占位符闪烁。→ 增加 Compose AsyncImage 的淡入动画。

    十三、代码地图与规模

    • 核心协议: core/canvas/Aip.kt (~600 行) – 定义数据结构与解析逻辑。
    • 容错引擎: core/canvas/AipParser.kt (~400 行) – 包含 sanitizeJson, lastSafeCut。
    • 转换层: core/canvas/AipConvert.kt (~350 行) – 形态互转逻辑。
    • 渲染层: ui/canvas/AipCanvas.kt (~800 行) – Compose UI 实现。
    • 路由层: feature/chat/CanvasRouter.kt (~200 行)。
    • 总计: 核心代码约 2500 行,无第三方重型依赖,轻量可控。

    👉 立即体验与贡献 访问项目主页获取源码与最新文档:

    https://github.com/Quor-a/ZorvAI

    赞(0)
    未经允许不得转载:171主机测评 » Zorv AI 对话框 AIP 排版引擎:让大模型回答在聊天气泡里直接长成文档 / PPT / 思维导图
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址