分享一些 agent 开发中常遇到的解析问题

我们平时说“处理文档”,很容易把文档理解成一长串文字。这个理解在简单问答里够用,但在真实工作里很快就不够了。

比方说,一份合同里,重要的不只是某个条款的句子,还有它属于哪一版?和哪个定义条款有关?例外条件在哪里?哪些批注已经接受?哪些还在审阅?

一份投资 memo 里,重要的不只是结论,还有这个结论依赖哪张表、哪个市场假设、哪份访谈记录?以及这些假设有没有被后来的数据推翻?

以及一份产品文档里,除了说明文字,还有版本、配置前提、截图、变更记录、上下游模块和还没关闭的问题。如果把这些东西都压成文本片段,很多信息在进入模型之前就已经丢了。

这种处理方式太过扁平,你可以理解为“二维”的,用在传统的软件那里还好,反正下一个任务又重新开始嘛。

但现在的 agent 不一样了,它要求你是智能化的、要越用越聪明的,要像人类实习生,教过一遍就要记得,下次干活就能用上,越干越熟练。所以就要求你的解析方式,也得进步,要引入时间、位置、来龙去脉、前因后果等等三维甚至四维的变量,还要帮 agent 形成记忆,不能我说一遍,啊,第二天又忘了,又要重新教,这样的 agent 不就跟猪一样了么。

所以,做长任务的 agent ,比做一次问答的 agent ,会更容易出问题:它能把一份报告里的数字搬进另一份 memo ,却不知道这个数字来自哪张表、是否已经更新、会不会让后面的结论失效。它能生成一段很流畅的文字,却不知道这段文字破坏了哪个引用、哪个前提、哪个还没定下来的决定。

这不是单纯的 RAG 的问题,也不是单纯的 context 不够,虽然上下文太短确实会看不全,但现在随着模型发展已经不是最大的限制了,最大的限制是它没有一个可以行动其上的外部世界。

我的解决办法也很简单,就是给它一个外部现实,对于企业场景,这个现实就是文档、版本、引用、表格、图片、批注、来源、权限和它们之间的关系。文档不是附件,文档是 Agent 要进入的工作现场,它大概包含:

Document
  -> Section
  -> Chunk
  -> Asset(table/image/page/slide)
  -> Metadata
  -> Source path
  -> Graph link
  -> Retrieval trace

Document 让系统知道证据属于哪份材料,而不是一段孤立文本。Section 保留章节层级和语义范围。Chunk 是最小可检索内容,但它不能只保存 content ,还要保存位置、路径、类型和来源。Asset 让表格、图片、页面和 PPT 图示不从链路里消失。Metadata 保存页码、文件名、关键词、摘要和 chunk type 。Graph link 表达跨章节、跨文档、跨资产的基础关系。Retrieval trace 让一次回答可以回看证据路径。

如果系统维护了文档状态,Agent 可以做更细的动作:

search(query)
open_document(document_id)
expand_section(section_path)
inspect_asset(asset_id)
compare_chunks(chunk_a, chunk_b)
follow_edge(edge_id)
cite(source_path)
revise_query(reason)

我专门做了一个工具 Knowhere ,来完成这件事: https://github.com/Ontos-AI/knowhere

当前的链路大概是这样的:

dirty documents
  -> parse
  -> hierarchy / sections
  -> chunks / assets / metadata
  -> graph
  -> agentic retrieval
  -> cited evidence

这个工具会把一次性的文件处理,变成 Agent 可以长期访问的文档状态,补的是记忆、检索和上下文这一层,让复杂文档以可被执行框架管理的形态进入系统:

Model:           负责语言推理和生成
Harness:         负责工具、状态、约束、执行边界
Knowhere:        把复杂文档建成可被 Harness 调用的记忆状态
Retrieval infra: 负责索引、召回、排序、存储性能

最后,整个解析工作就是这样:模型负责推理和生成,Harness 负责工具、上下文策略、执行边界和反馈循环。当 Agent 进入更长的任务和更复杂的材料环境时,Harness 里就分出一层文档 world state:文档、章节、chunk 、资产、来源、关系的可导航表征。Knowhere 让文档不再只是 prompt 里的一段附件,而是 Agent 可以反复回到、反复导航、反复引用的可操作状态。

模型会继续变强,材料会继续变杂。但真正能进入知识工作的 Agent ,缺的不是更多上下文,而是一个可以行动的知识状态。

感兴趣的老哥可以体验一下: https://knowhereto.ai/?utm_source=

仓库在这里,开源小项目,欢迎各位随时反馈: https://github.com/Ontos-AI/knowhere

这个思路其实跟我做的供应链管理系统很像,都是要把松散的文件变成有结构的对象,不过我们是用xml做的,agent那边还没想好怎么接。你提到的graph link具体是怎么实现的?是用图数据库还是自己维护邻接表?

mark,回头仔细看看

其实不太明白,把文档拆那么细真的有用吗?我之前试过按章节拆分,效果感觉跟整篇丢进去差不多啊,是不是我用的模型不够大?

又来这种帖子了,说得好像自己发现了新大陆,结果最后还不是在github上卖工具

楼上说效果差不多的,你可能没遇到复杂场景。我们做金融合规检查,一份合同里“除外条款”可能分散在五个章节,还得跟附件里的表格交叉引用。传统RAG把文档压平后根本串不起来,agent经常漏掉关键例外。我后来也是自己写了解析器,把条款编号、引用关系都抽成图,效果才上去。不过维护成本确实高。

小白问一下,这里说的"agentic retrieval"和普通retrieval有什么区别?是不是就是多轮对话里那种可以主动追问的检索?

不知道这个工具对扫描的PDF效果怎么样?我们公司很多历史合同都是扫描件,里面还有手写批注,这种能处理吗?

别碰,坑太多

周末吃火锅了吗?我看你们讨论得好激烈

处理带表格的文档:1.用camelot或tabula抽表格 2.把表格转成markdown格式 3.给每个单元格加行列坐标元数据 4.表格标题和上下文文本建立关联 5.如果表格跨页要合并

你提到的“外部现实”这个概念让我想到之前做游戏AI时的world state设计。不过文档世界的变化比游戏世界难追踪多了,比如版本更新时,怎么让agent知道某个结论依赖的假设已经失效了?你们在Knowhere里是怎么处理文档版本变化的,是每次全量重建graph还是做增量更新?

给单元格加行列坐标这步关键,不然表格一拆就读串行了

表格转markdown加行列坐标这招好,我之前漏了坐标元数据,检索老对不上

简单文档拆不拆差别不大,复杂合同交叉引用才看出区别

把文档拆成结构化对象这步,做不好后面全是坑

给单元格加行列坐标这招实用,不然表格一拆就读串了