75 分钟。89 份 PDF。164 个候选主题。11 个新建页面。20 个更新页面。
这是 2026 年 6 月 19 日,我的 AI Agent 完成的一次批量知识摄入。输入是海思 Hi3519DV500 原厂 SDK 的全部技术文档(89 份 PDF,涵盖芯片手册、编程指南、硬件设计参考、驱动开发文档),输出是一个结构化的嵌入式 Linux Wiki——从 14 页涨到 25 页。
这篇文章拆解 Agen 的完整认知流水线——它怎么"读"、怎么"理解"、怎么"决策"、怎么"写"。
老规矩先看效果
摄入前后对比:
| 指标 | 摄入前 | 摄入后 | 变化 |
|---|---|---|---|
| 实体页 | 3 | 6 | +3(Hi3516DV500、ToolPlatform、SVP NPU 工具链) |
| 概念页 | 11 | 18 | +7(裸烧升级、U-Boot 移植、SDK 安装、外设驱动、安全启动…) |
| 对比页 | 0 | 1 | +1(Hi3519 vs Hi3516) |
| 更新已有页 | — | 4 | AI ISP、MPP 流水线、NPU 推理、启动配置 |
| 总页面数 | 14 | 25 | +11 |
决策分布:
| 决策 | 数量 | 占比 |
|---|---|---|
| 建页 | 11 | 12% |
| 更新 | 20 | 17% |
| 跳过 | ~133 | 71% |
| 候选总数 | ~164 | 100% |
71% 的跳过率不是"遗漏"——是精准过滤。
流水线全景:6 个阶段
Agent 的摄入流水线分为 6 个阶段,每个阶段有明确的输入、输出和决策逻辑:
Phase 1: 文件采集 → Phase 2: 文本提取 → Phase 3: 内容理解 Phase 4: 决策分类 → Phase 5: 页面生成 → Phase 6: 交叉引用Phase 1:文件采集——把 PDF 变成 Agent 能读的格式
输入:89 份 PDF,散落在 SDK 的 ReleaseDoc/zh/ 目录下。
Agent 的动作:
第一步——结构化归档。Agent 扫描了所有 PDF 文件名和目录结构,按照内容主题分为 3 大类、10 个子目录:
raw/docs/ ├── 00.hardware/ # 硬件设计类 │ ├── 芯片数据手册/ │ ├── 硬件设计指南/ │ └── 引脚定义/ ├── 01.software/ # 软件开发类 │ ├── SDK 开发指南/ │ ├── 驱动开发/ │ ├── AI ISP 开发/ │ └── 工具链使用/ └── 02.reference/ # 参考类 ├── API 参考手册/ ├── 寄存器手册/ └── 版本说明/这个分类不是让 Agent 看着玩的——它影响 Phase 4 的决策。hardware/ 下的 PDF 更可能产生 entity 页面(芯片、传感器),software/ 下的 PDF 更可能产生 concept 页面(驱动开发方法论、编译流程)。
第二步——文本提取。Agent 用 pymupdf 逐份读取 PDF,提取纯文本。每份 PDF 保存为 raw/docs/ 下的 .md 文件,并在 frontmatter 记录 source_url、ingested 时间、和 sha256 哈希(用于后续漂移检测)。
关键决策:为什么不直接用 PDF 原文?因为 Agent 需要用 search_files 在 raw/ 中搜索关键词——PDF 二进制文件无法被 grep。转成 .md 后,全 Wiki 的内容搜索可以覆盖 raw/ 目录。
Phase 2:文本提取——PDF 的三大技术坑
PDF 看起来像文本,但内部结构是一堆"在坐标 (x, y) 处画字符 ‘A’"的指令。Agent 必须把这些指令还原为可读的段落。
坑一:表格提取。PDF 的表格是用坐标位置对齐的,不是 HTML 的
标签。Agent 用 X 坐标聚类算法:把页面所有字符按 X 坐标分组——同一组 X 坐标的字符属于同一列。然后按 Y 坐标排序——同一行。最终重建出正确的表格结构。效果:原厂芯片手册里的寄存器定义表(100+ 行 × 5 列,多页跨页)被正确提取为 Markdown 表格。
坑二:页眉页脚。每页 PDF 的顶部和底部有重复的"Hi3519DV500 数据手册 V1.0"和页码。Agent 用编辑距离算法检测跨页重复文本行——连续 3 页以上出现在同一位置、相似度 > 90% 的文本块被识别为页眉/页脚,自动去除。
坑三:多栏布局。部分参考手册使用了双栏排版。Agent 检测页面中间是否有持续的垂直空白区——如果有,先按栏拆分再提取,避免 A 栏第 1 行 + B 栏第 1 行混排。
Phase 3:内容理解——从文本到候选主题
提取完文本后,Agent 不是立刻开始建页——它先"读"。
阅读策略:先读索引文档,再读正文。
Agent 按照优先级读取文件:
- 优先级 1:目录文件、产品简介——了解整体结构
- 优先级 2:核心设计文档——芯片架构、BSP 开发指南
- 优先级 3:具体功能文档——传感器驱动、NPU 使用、电源设计
这样读的原因是:读了产品简介后,Agent 知道 Hi3519DV500 有双核 A55 + NPU + AI ISP + MIPI 接口 + DDR4。然后读各模块文档时,自动把信息归入已有的概念——不会为"MIPI 接口"新建一个和"外设接口总览"重复的页面。
关键词提取与聚类:
Agent 从全部文本中提取了约 500 个高频术语。然后用 TF-IDF 计算每个术语在文档中的重要性——不是出现次数多就重要,而是"在当前文档中出现频率高但在其他文档中出现频率低"的术语才重要。
结果:164 个候选主题。其中 37 个是芯片/传感器名称,127 个是技术概念。
Phase 4:决策分类——建页 vs 更新 vs 跳过
这是整个流水线的核心判断。Agent 对 164 个候选主题逐一分类:
决策规则(来自 SCHEMA.md):
判断一个候选主题是否需要建页:
- ✅ 出现在 2+ 个不同来源中 → 建页
- ✅ 是某个来源的核心主题 → 建页
- ❌ 只是顺带提及 → 跳过
- 📝 是对已有页面的补充 → 更新已有页
三个典型案例:
案例一:Hi3516DV500(建页)。这个芯片在多份文档中被提及,每次都是和 Hi3519DV500 做对比——“相比 Hi3519,Hi3516 无 NPU 单元”。满足"2+ 来源"条件 → 建页。
案例二:SVB 动态调压(更新已有页)。电源管理页面已经存在。PDF 中有 3 页专门讲 SVB 调压原理和寄存器配置。Agent 判断:核心主题但不是新概念,应补充到已有页面 → 更新电源管理。
案例三:DDR PHY Training(跳过)。PDF 的 DDR 初始化章节提到 PHY Training 概念。但只有 2 段话,没有深入展开。Agent 判断:顺带提及 → 跳过。这个信息被嵌入 DDR4 接口设计页面的一小段里,不需要独立建页。
批量决策效率:164 个候选主题,Agent 的决策过程约 8 分钟。不是每个主题独立分析——Agent 先对所有候选做关键词聚类(37 个同类芯片名合并为 3 个页面候选、127 个概念合并为约 40 个页面候选),再批量判断。
Phase 5:页面生成——从候选到结构化 Markdown
建页模板:
每个新建页面遵循统一结构:
- YAML frontmatter(title / created / type / tags / sources / confidence)
- 概述段落(一句话说清楚这是什么)
- 主体内容(按逻辑分段,每段 ≤ 5 句话)
- [[wikilinks]] 交叉引用(至少 2 个出站链接)
更新已有页面:
Agent 不只是"追加新内容",而是:
- 检查新内容和已有内容的冲突
- 如果冲突,标注两个版本的来源和日期
- 如果互补,插入到对应段落
- 更新 frontmatter 的 updated 日期和 sources 列表
- 保持段落结构不变——不重写已有内容
Phase 6:交叉引用与回链
建页和更新完成后,Agent 执行最后一轮操作:backlink 同步。
新页面已经链了已有页面。但已有页面还没链回新页面。Agent 扫描新页面涉及的标签和关键词,在已有页面中搜索——找到 8 个已有页面需要加回链。然后逐一添加[[新页面]]引用。
最后更新 index.md、记录 log.md、输出变化报告。
Phase 4 深度拆解:决策不是"看一眼就定"
164 个候选主题的决策不是 Agent 一个个点过去的选择题。它有一个完整的决策流程:
第 1 步:聚合。37 个芯片/传感器名称中,多个是同义词或变体——“Hi3519” “Hi3519DV500” “HI3519” 指同一个芯片。Agent 先做名称归一化,37 个候选合并为 8 个实体候选。
第 2 步:去重。127 个技术概念中,约 30% 是同一个概念的不同表述——“启动流程” “boot sequence” “系统启动” “上电启动”。Agent 用 TF-IDF 相似度聚类,合并为约 40 个概念候选。
第 3 步:查已有页面。Agent 不盲目建页——先搜索 Wiki 中是否已有类似页面。40 个概念候选中,25 个已有对应页面(或部分覆盖),只需更新不需建页。
第 4 步:阈值过滤。剩下约 15 个真正的新概念候选。Agent 逐条检查来源数量——出现在 2+ 个来源中的直接建页,只出现在 1 个来源但信息量 > 500 字的考虑建页,其余跳过。
最终产出:8 个实体候选 → 3 个建页(Hi3516DV500、ToolPlatform、SVP NPU)+ 15 个概念候选 → 7 个建页(裸烧升级、U-Boot 移植…)+ 约 40 个已有页面 → 25 个更新。跳过的 ~133 个候选也不是"浪费"——它们的核心信息被嵌入了对应的已有页面中,没有丢失。
决策失败的三种模式
模式一:过度建页。如果阈值设为"所有概念都建页",40 个概念全建——结果是一堆"只有 3 句话"的僵尸页,被引用 0 次,占用搜索索引但不提供实质价值。
模式二:过度保守。如果阈值设为"只有用户明确要求的才建",89 份 PDF 只更新 3 个已有页面——大量有价值的知识沉在 raw/ 里永远变成"暗知识"。
模式三:重复建页。Agent 没查到已有页面就建了新的。结果 Wiki 里同时存在"MPP 媒体处理"和"媒体处理流水线"两个页面——内容 80% 重复。这需要更严格的"建页前搜索"和更宽松的"部分覆盖 → 更新而非新建"策略。
避免模式三的机制:建页前,Agent 必须执行一次全 Wiki 的关键词搜索(不是只看 index.md)。搜索范围包括已有的页面标题、frontmatter tags 和正文关键词。只有搜索结果为空时才进入建页流程。
不同来源类型的处理差异
PDF 来源:需要 Phase 1-2 的完整处理(分类 + 文本提取)。PDF 的信息密度通常高于纯文本——一份 19 页的 PDF 可能比一篇 2000 字的博客包含更多结构化知识。
纯文本/Markdown 来源:跳过 Phase 1-2,直接进入 Phase 3 内容理解。速度快 3-5 倍。
URL 来源:Agent 先抓取网页内容转 Markdown,保存到 raw/articles/。URL 来源的可靠性差异很大——官方文档 > 技术社区 > 个人博客。Agent 不判断来源可靠性,但会标记来源 URL 让读者自己判断。
对话/聊天记录来源:用户说"把今天的调试经验收进 Wiki"。Agent 读取飞书聊天记录(通过 session_search),提取技术讨论,去掉闲聊,按主题分配到已有的概念页面。这是 Wiki 最轻量的摄入方式——没有新页面创建,只有对已有页面的增量补充。
为什么是 6 阶段,不是 3 阶段
你可能会问:为什么不简化——"读到→理解→写"三步就完了?
因为PDF 知识摄入最大的坑不是"读不懂",而是"写乱了"。如果没有 Phase 1 的文件分类,Agent 不会知道硬件类和软件类文档的区别——硬件类更可能建 entity 页、软件类更可能建 concept 页。如果没有 Phase 4 的批量决策,Agent 会为 164 个候选全部建页——3 个月后 Wiki 爆炸。
6 个阶段不是多余的——每一个阶段都在防止一种特定的失败模式。
失败模式与对应防御阶段:
- 文件散乱、无法搜索 → Phase 1 结构化归档
- PDF 表格提取错误、信息丢失 → Phase 2 pymupdf + X 坐标聚类
- Agent 不了解整体结构、盲目建页 → Phase 3 先读索引后读正文
- 为每个候选主题建页、Wiki 爆炸 → Phase 4 阈值过滤 + 批量决策
- 页面格式不统一、信息碎片化 → Phase 5 模板化生成 + 标准化 frontmatter
- 新建页面孤立、已有页面没回链 → Phase 6 backlink 同步
每个阶段解决一个特定问题。缺任何一个,Wiki 质量都在对应维度上打折。
不同场景的流水线适配
完整 6 阶段流水线是为 PDF 批量摄入设计的。但实际使用中,大部分摄入都是轻量的。
轻量摄入(飞书聊天记录):跳过 Phase 1-2(没有 PDF),Phase 3 简化为读聊天上下文,Phase 4 简化为"更新已有页面",Phase 5 简化为追加段落,Phase 6 正常执行。全过程 30 秒。
URL 来源:Phase 1 改为网页抓取 + 转 Markdown,Phase 2 跳过(已经是纯文本),Phase 3-6 正常。全过程 1-2 分钟。
单文件 Markdown:Phase 1-2 全部跳过,直接进入 Phase 3。全过程 15 秒。
批量 PDF(89 份):完整 6 阶段,全过程 75 分钟。最耗时的是 Phase 2 的 PDF 提取(每份 PDF 3-15 秒)和 Phase 4 的决策(164 个候选)。