全部文章
强 AI 时代,知识图谱产线该存什么
一个足够强的智能体拿着 grep 和原始文件,能替代产线的哪一部分?用「重新发现的代价 × 复用频率 × 正确性要求」把产线拆成四层,会发现我们把力气花在了最容易被替代的那一层。
知识图谱 架构
企业知识图谱产线做到后来,我总觉得它有点「四不像」。常被问到的「本体有什么用」「社区摘要有什么用」,也很难直接回答。于是我先不谈方案,换一个更根本的角度,把产线拆开看。
在强 AI 面前,产线提供了什么
最直接的对照组,是一个足够强的智能体,直接拿到客户的原始文件,再配上 grep、读文件、跑代码这些工具。
产线的意义,只能落在这个智能体做不到、做得太慢、或者每次都要重做的地方。所以要问的不是「本体有什么用」「社区有什么用」,而是哪些东西值得预先算好、存下来。可以用一个粗略的公式来衡量:
记忆的价值 ≈ 重新发现的代价 × 被复用的频率 × 对正确性的要求
产线里其实有四种东西
按这个标准看,产线里的东西性质完全不同:
层 内容 模型变强之后
① 原始数据的忠实转换 Excel 版面、PPT、图片转成可读文本;单元格原文;原始文件原样直通 不会贬值。模型读不了的格式还是读不了,而且这是客户数据进入系统的唯一边界
② 确定性的骨架 代码 AST、建表语句、外键、接口定义、ER 图、批处理作业定义 不会贬值。这些是事实,不是推断,便宜又准
③ LLM 推断出的缓存 抽取的实体与关系、社区摘要、本体归类、业务全景合成 会贬值。每换一代模型都能重新生成,而且新生成的更好
④ 人的判断 确认与纠正、Fit&Gap 判定、变更影响的结论、设计与实现不一致的裁决 只会升值。没办法重新生成
这样一看,「四不像」的感觉可能就是从这里来的:我们把大部分精力花在了第三层,也就是最容易被替代的那一层。第四层在产线里几乎没有位置。人的判断散落在 PPT、Excel、任务看板和聊天记录里,从来没有流回记忆。
本体和社区之所以说不清楚意义,是因为它们都属于第三层。它们是为了弥补模型能力不足、预先计算出来的一种组织方式。模型越强,这一层就越应该从「预先全量算好」转向「查询时按需去算」。LazyGraphRAG 把建图时的 LLM 调用推迟到查询时,「先行动、再按需固化 schema」的思路,也都在往这个方向走。
由此推出的几个方向
下面都还只是假设,但每一条都能拿真实任务去验证。
重心下沉。 把第一层和第二层做到极致:无损、可追溯、能增量更新。这是护城河,也最不怕模型换代。
第三层变成可丢弃的缓存。 不再追求一次性全量构建、所有东西都要正确,而是按需生成,用完可以重算。本体这时更像「给智能体用的地图图例」,而不是「必须提前填满的数据库」。
第四层成为真正的记忆。 产线不只在构建时写入,在被使用时也要写入。智能体每回答一次、人每确认或纠正一次,这个判断都沉淀下来,下次直接复用。
用任务来定义意义。 功能好不好,不看图谱有多漂亮,而看客户那几类核心问题答得准不准、快不快:变更影响、Fit&Gap、设计与实现是否一致、规格问询。
一个旁证
后来我去拆 Palantir 的公开文档,发现他们的对象库也是可以重建的缓存,真正的数据源是底层数据集加上编辑记录(见《Palantir 的本体里没有魔法数据库》 )。他们敢在 schema 变更时整库重建,正是因为缓存和真相分得清楚。
这和上面的分层是同一个道理:能重算的东西不必当宝贝,不能重算的东西一个都不能丢。
全部文章
AI 写代码的时候,我在做什么
八个月里,我名下 174 个 PR、约 770 次提交,大部分代码是编码智能体写的。我的时间花在五件事上:定结构、找信息在哪一步丢了、怀疑指标、不把导出属性当 KPI、读产出。
工程 方法
今年 2 月到 9 月,我从几份 GraphRAG 基础脚本开始,搭起了一条把设计文档和源代码变成知识图谱的产线。我名下有 174 个 PR、约 770 次提交,代码大部分是 Claude Code 这类编码智能体写的。经常有人问:那你做什么?
我的回答是:模型生成内容,结构由我来定。下面是这几个月反复用到的五件事,每件都配一个真实的例子。
一、结构由我定
产线有几十个阶段。我花时间最多的地方,是每个阶段的输入输出契约:吃什么文件、产出哪些列、ID 怎么生成、谁有权改哪张表。所有 schema 只在一份文档里定义,运行时再按契约校验一遍。
有一次,关系抽取的候选数量突然少了一半多。查下来,是我们把「从几十种关系类型里选一个」直接写进了抽取指令。GraphRAG 的合并、计数和补抽机制都假设抽取是自由的;强制归类之后,模型遇到拿不准的就干脆不报。改法是让抽取回到自由描述,归类挪到出口单独做一层。这类问题模型自己发现不了,因为它只看得到眼前这一步。
二、找信息在哪一步丢了
给一份大文档做向量嵌入要跑将近 6 小时。直觉是批量太小,实测下来瓶颈却是下载带宽:每条向量以 JSON 十进制浮点返回,约 29KB,七万多条就是两个多 G。改成 base64 编码后每条约 8KB,再加上真正的批量和断点续跑,整体快了 5.3 倍。
如果只盯着批量大小,永远改不对。先量清楚时间花在哪里,再动手。
三、怀疑指标
有一段时间,关系召回率怎么调都停在 0.39 附近,结论几乎要写成「生成已经饱和,只能靠扩大覆盖」。后来我坚持换几种方式再测,才发现评测脚本本身有 bug,真实召回约 0.66。修完以后,之前的几条结论全部改写:生成远没有饱和,真正免费的杠杆是关系类型对的覆盖,一项改动就把召回提高了 15 个点,误报没有增加。
从那以后我多了一条规矩:指标钉死不动的时候,先查指标。
四、别把导出属性当 KPI
代码连到文档的「跨模态边」一度被当成成果指标,越多越好。后来发现,其中一部分是靠改写端点「制造」出来的。我们把规则改成:一条边算不算跨模态,只能由两端实体的出身推出来,不能被操作出来。改完数量从几千条降到一千出头,但每一条都有出处,悬空的边归零。
数字变小不等于退步。能被操作的指标,迟早会被操作。
五、读产出,数字只用来定位
不管是图谱还是生成的文本,出问题时我会把产出和发给模型的指令并排,逐段读,找出每一段是照着哪句料来的。统计脚本只用来告诉我该去哪里读,不用来下因果结论。凭数字下的因果,我错过不止一次。
最后
这五件事都不需要手写多少代码,但每一件都决定了智能体写出来的东西有没有用。我理解的 AI 驱动开发,是把人的时间从「写」挪到「定结构、找真因、验结果」上。
全部文章
静默失败:数据产线里最贵的 bug
在一次全流程问题清点里,将近一半的损失来自静默失败:步骤失败了,系统却记成完成。五个真实的例子,和后来定下的七条不变式。
工程 数据质量
报错的 bug 会有人修。静默失败没人知道:数据在某一步悄悄蒸发,下游照常运行,报告照常生成,直到客户问到某个问题,才发现答案缺了一块。
在一次全流程的问题清点里,我们把几十个问题按造成的损失归类,将近一半来自静默失败。下面是其中五个。
例一:「不认识」被当成「不要」
资料入口的识别器只认识几种格式:Excel、PDF、PPT、Word、图片和 Markdown。其余文件被标成「未知」,然后悄悄丢掉。结果客户文件夹里的源代码和纯文本,从来没有进入后续流程。下游其实早就有处理代码的能力,只是一直在空转。
修法是给入口定一条不变式:每个文件出口时必须有明确去向,三选一(结构化、原样直通、隔离),全部记进清单,并且进来的数量必须等于有去向的数量。系统垃圾文件可以跳过,但要写明理由。一个 218 个文件的混合文件夹,修完之后对账闭合:33 个走结构化,172 个原样直通,13 个系统文件显式跳过。
例二:审计记录说了谎
文档理解有三道防线:规则初筛、小模型复核、总览判定。总览判定失败时没有重试,只打一行日志;补救步骤又只认总览给出的标记。更糟的是,每个步骤不管成败,都被标成「已执行」。
三道防线实际上是单点。我们抽查一批真实数据,大约三分之二的单元没有拿到总览判定,记录里却全是「已完成」。
修法:成功才打标,失败写明原因;补救步骤的触发条件不只认一个信号;总览判定做成幂等,对历史产物重跑一次就能把缺的补齐。
例三:测试数据和生产数据不同形
一套按关系类型生效的规则,在测试里一切正常,上了真实数据却始终不起作用。原因是生产数据里的类型名全大写,规则表里是首字母大写,比较时区分大小写,于是全部失配。测试用的标准答案恰好也是首字母大写,所以从来没有暴露。
例四:组件按自己的目录解析路径
Office 自动化组件在服务进程里按它自己的工作目录解析相对路径。传给它的相对路径全都找不到文件,Word 这条处理线从上线起就没有真正跑通过,只是没有人注意到产出是空的。
例五:截断不报
长表格的处理有几处硬上限:只取前 200 个非空行,每行最多 500 字,图形里的文字最多 3,000 字。超出的部分直接丢弃,不留任何痕迹。
后来坚持的七条
入口无损。 进来的数量等于有去向的数量,不等就停。
「未知」不等于「不要」。 看不懂的东西先原样带着走。
成功才打标。 审计记录不能由执行者顺手盖章,失败必须留下原因。
补救不能只认一个信号。 否则多道防线会退化成单点。
测试数据要和生产同形。 大小写、编码、路径格式都算。
出口计数加硬校验。 每个阶段结束时数一遍,对不上就报错。
让补救变便宜。 步骤做成幂等,修好之后重跑一次就能补齐,不必从头再来。
这些规则单看都很朴素。它们的价值在于:产品交到客户现场以后,没有人会盯着每一个文件看,无损只能靠代码层面的硬保证。
全部文章
置信度不能让模型自己打分
客户想知道图谱里每个实体和关系有多可信。调研完主流工具和论文,我们没有用 LLM 自报的分数,而是用证据和规则来算,并让每个数字都能点开看到来源。
知识图谱 评测
一次客户会议上,对方提出:图谱里的实体和关系,能不能告诉我们哪些可信、哪些存疑。听起来只是加一个分数,做起来要先回答一个问题:这个分数从哪来。
主流项目怎么做
我先去翻了几个主流知识图谱工具的源码和文档:
微软 GraphRAG 的输出表里没有置信度列。关系权重是 LLM 自报的「强度」按出现次数累加,唯一的裁决机制默认是关闭的。
Neo4j 官方的图谱构建工具不打分,只做规则化的 schema 剪枝。
iText2KG 只有向量余弦阈值这一个旋钮。
再看 LightRAG、nano-graphrag、graphiti 等八个同类项目,没有一家在抽取时给实体和关系统一输出置信度。社区的趋势反而是去数值化。
结论是:没有任何主流项目输出学习型的黑箱置信度。走可解释的规则化路线,和整个生态是同一个方向。
论文怎么说
LLM 用语言报出来的置信度系统性地过度自信,不能直接当分数用(Xiong 等,ICLR 2024 )。
更可靠的几条路:微调一个做二值裁决的验证器(GraphJudge );让验证有证据可依(KGValidator 接入外部知识库后准确率明显上升,但在专业领域失效,所以私有领域要用自己的图谱做依据);支持度计数、本体规则和 LLM 组合使用;多次采样看一致性,比自报可靠,但成本更高。
人工审核最划算的分流方式,是只在几个自动验证器意见不一致时送人看。
还有一条死路:直接读模型输出的概率。我们用的推理系列模型,在云服务上明确不提供这类概率。
我们的设计
最后定下的模型很朴素:
关系置信度 = 基础计数 × 验证权重 × 证据权重
基础计数: 这条关系在多少段原文里出现过,次数越多越高,有上限。
验证权重: 独立验证通过、未验证、存疑,分三档。
证据权重: 能逐字引用到原文的高,没有引用的低。
实体的置信度看两件事:出现了多少次,以及有多少条高置信的关系给它作证。一组实体构成的整体(比如一条业务流程),取成员里最低的那一档,短板说了算。所有参数都放进可配置的档案,不同客户可以调。
最重要的一条
展示时,每个数字都必须能点开,看到它是怎么算出来的:出现在哪几段原文、谁验证过、引用的是哪一句。客户不需要相信一个分数,他需要能检查这个分数。
落地顺序也按这个思路排:先把流程里本来就有、却被算完即弃的信号保存下来;再让抽取时顺带输出原文引用;然后统一算分;最后才是人工审核的分流。
全部文章
few-shot 示例会长成假数据
抽取指令里的示例用了真实感很强的业务名词,模型把它们当成了数据:一份毫不相干的图谱里长出 36 个假实体、112 条假关系、11 份假社区摘要,而且彼此自洽。
知识图谱 提示词
我们的实体抽取指令里有几条 few-shot 示例,用来教模型输出格式。示例写得很具体,是一个订单管理的场景:订单系统、订单头表、库存、出货。
后来我们用一份公开的产品文档语料建图,内容和订单管理毫无关系。建完一查,图里多出了 36 个实体、112 条关系,还有 11 份社区摘要,全是订单管理的内容:订单编号、库存管理部、订单审批……
为什么比随机噪声更危险
这些假数据只占全图的千分之一左右,但它们彼此连通、互相印证,看起来就像真的存在这样一块业务。随机噪声容易被过滤;自洽的假数据会被当成知识,进而污染检索和回答。
修法
示例里的实体名,一律换成不可能被误当成真数据的抽象占位符,比如 ___SYSTEM_1___,并在示例前写明「绝不输出这些占位符」。这样即使模型仍然泄漏,也无法形成自洽的假领域,而且可以一键过滤。
还有一个细节:示例要改在源头的配置里,而不是改某一次渲染出来的指令文件,否则下次重新生成,旧示例又回来了。
清理已经被污染的图谱
先备份。
以泄漏的名词为锚,删掉对应实体,再删掉任一端连到它们的关系。
删掉标题被泄漏名词主导的社区摘要。按「泄漏实体占比」来判断并不可靠,会误伤真实数据里恰好相似的内容。
同步删掉对应的向量,并清掉社区里对这些实体和关系的引用。
更普遍的提醒
GraphRAG 官方的指令自动调优,生成的示例里也会带具体的专有名词,同样有泄漏风险。凡是给模型看的示例,都值得问一句:如果它把这个当真了,会怎样?
全部文章
把上下文看成元胞自动机:一次先设证伪器的实验
我写了一篇综述,把智能体的记忆管理看成图上的局部规则系统,并先设计了证伪器。在读取路径上,主要设想被驳倒,只有一个变体站住;在写入路径上,局部规则反而是必要的。
研究 智能体记忆
现在的智能体记忆系统五花八门:向量检索、图检索、个性化 PageRank、各种「扩散激活」。我想用一个统一的框架看它们:把每条记忆当作一个元胞,元胞之间有邻域,每个元胞有状态,按某种局部规则更新,再由一个读出函数决定交给模型看什么。这就是论文标题里的 Context as a Cellular Automaton。
用这个框架看,很多系统其实是同一种东西的不同参数。HippoRAG 的个性化 PageRank 是一种线性扩散;ProGraph 的第二阶段是一种阈值自动机。更有意思的是,现有系统的转移规则只有两种极端:要么是余弦阈值,要么让大模型直接生成。中间那一层,用一个小型、非生成的决策模型来当规则,几乎是空白。
先设计证伪器
框架好讲,但「局部迭代扩展比一次性选择更好」这个核心主张需要实验。我先定了一个证伪器:同样的预算下,用一个交叉编码器一次性重排序。如果迭代扩展连它都赢不了,主张就站不住。
实验在 MemHop 上做,三个场景各 300 题,总花费大约 15 美元。
读取路径:主张被驳倒
同样预算下,逐候选迭代扩展的链召回是 0.837,一次性重排序是 0.987。迭代输了,回答准确率则没有差别。
原版的扩展规则会「渗透」到几乎所有元胞,147 个里扩到 141 个,读出的内容是原始对话长度的 9 倍。
把记忆拆成原子事实(类似 Mem0 的做法)看起来省 token,但在回答层面崩了:准确率从 0.890 掉到 0.617,需要两跳以上的问题全面失败。多跳问题需要保留叙述层。
加入干扰数据后,基于字符串共现的邻域会放大干扰:原版选中的元胞里 67% 来自别的场景,一次性重排序只有 5%。
唯一站住的变体
同样的交叉编码器、同样的邻域、同样的预算,只改一件事:判断要不要扩展时,把种子片段和候选放在一起给门控模型看,而不是只看候选本身。
这个「成对门」把链召回从 0.733 提到 0.897,四跳链从 0.52 提到 0.85。原因是邻域的真正价值,在于把所有片段两两比较的巨大空间收窄到真实存在的边上,让模型读关系文本变得负担得起。
写入路径:局部规则是必要的
反过来看写入:一条新信息进来,哪些旧记忆需要跟着更新。这里没有一个能看到全局的读者,只能沿邻域传播。实验里沿邻域传播的一致性超过 0.95,原版规则漏掉了 61%。
所以我的结论改成:元胞自动机这个视角,在读取路径上只带来代价;在受限窗口下的信息传导和一致性维护上,才是真正需要的。
这次实验教给我的
先写证伪器,再写主张。
负结果要写进正文。这篇论文里最有用的部分,恰恰是被驳倒的那几条。
实验顺带产出了大约 1,700 对「变化句、元胞」的标注,可以拿来训练写入路径的门控模型。这是下一步。
论文:doi.org/10.5281/zenodo.23176958 ;代码与逐题结果:github.com/GA777777777/context-ca
全部文章
Palantir 的本体里没有魔法数据库
拆完 Palantir 的公开文档:对象库是可以重建的缓存,数据集加编辑记录才是真身。强 AI 改变的是建模的成本,不是结构的必要性。
架构 调研
做企业知识图谱,绕不开 Palantir。客户会拿它来对比,团队里也常说「本体」。我花了几天,把它的官方文档和能找到的工程博客逐条过了一遍,想回答两个问题:它底下到底是什么数据库;在模型越来越强的今天,这套设计哪些还有必要。
没有魔法数据库
对象存储是一套自研的索引编排:批处理用 Spark,流处理用 Flink;检索面是 Lucene / Elasticsearch 一系的索引(这一点来自工程博客,官方文档只说「专用对象数据库」);重查询切到 Spark。
持久层永远是数据集(Parquet)。对象库是可以重建的缓存,数据集加编辑记录才是真身。正因为如此,它才敢在 schema 变更时蓝绿重建整个对象库。
对象之间的链接不走图数据库,而是索引加连接表,一次关联搜索有数量上限。
schema 怎么管
只有一个权威来源;变更走分支和提案,类似代码的 PR。
破坏性变更(改类型、改主键、改数据源)会被自动检测,强制给出迁移方案,生成新的 schema 版本,用替换管线重建,数据灌满之后才切换。
写入怎么管
所有写入只有一个入口:Action。写入后立刻进索引,再异步落成独立的数据集。
编辑和源数据冲突时,合并策略可以配置:编辑永远优先,或者按时间戳。
权限怎么管
权限是一层层叠上去的:强制标记、角色权限、行级、对象和属性级,再到敏感操作时要求填写理由,最后是审计和血缘。值得学的一点是,策略变更会触发重新索引,权限直接物化进索引,而不是在查询时再过滤。
AIP:本体是中心,模型是外设
它的 AI 平台延续同一个思路:智能体只接触治理过的本体层,不碰原始数据;一切写操作都要经过 Action 的校验、暂存、人工批准和审计。2026 年他们也开始通过 MCP 对外暴露本体,这和我们把检索服务收口到 MCP 是同一个方向。
强 AI 之后,哪些还有必要
我的判断是:强 AI 改变的是读侧建模的成本,不是结构的必要性。schema 不再贵在创建,它可以从证据里长出来;但它仍然贵在写错,写入那一侧依然需要完整的类型和校验。
由此我更倾向于反过来做。Palantir 是先建 schema 再行动;我们可以先行动,某个动作需要什么字段,就固化什么字段,让 schema 沿着动作的足迹结晶。至于 schema 可不可信,答案不是让 AI 生成的 schema 变得可信,而是换权威来源:字段类型、长度、主键直接继承源系统自己的定义,比如建表语句和接口定义;AI 合成的部分要有人签字;AI 的解释只做参考。
五条可以直接用的启示
守住数据集作为唯一真相源,索引和对象库都当缓存。
schema 要有版本,数据灌满再切换。
编辑的合并语义做成配置,不要写死。
把权限策略物化进检索索引。
敏感变更的台账里,理由必须必填。
全部文章
多智能体产线:少加关卡,先改指令
我搭过一条十几个智能体位串起来的长篇内容生成产线。踩过的坑大多是同一类:质量上不去就加检查关卡,结果模型学会了应付关卡。这是后来定下的七条规矩。
智能体 方法
这条产线把一部长篇内容从设定、规划、编排一路做到成文,中间有规划、编排、写作、审读等十几个智能体位,每个位都有自己的指令和产出格式。下面这些规矩,都是在它上面反复试错得来的。
一、同一类错连犯两轮,先查指令
模型反复交出不对的东西时,我的第一反应曾经是加一道检查。后来发现,很多时候是指令根本没把任务说清楚:第一句没说你是谁、要交什么;产出格式没有把必交的部分逐个列出来;还留着「没提到的可以不改」这种口子;里面塞满了只有内部才懂的行话。
关卡只能拦,不能告诉模型该交什么。指令含糊时加关卡,只会让回炉越来越多、额度越烧越快。
二、统计指标不要进回炉条件
有一次我们把文风统计(句长、逗号数、短句占比)设成回炉的触发条件,还在回炉指令里写明「怎么写才能过」。模型就照着指标凑数:强行插入极端的长短句,删标点凑句长,正文被改成了提纲。
那一晚的回炉件里,四十多条判项是机检误报,真正的问题只有十几条。后来定下的口径是:只有事实性、可修复的问题才触发回炉;风格和统计类指标只记录,不拦截。
三、拆限制,不要在限制上加限制
内容重复是最难治的病。我们一度的做法是加核查:换人核、场景轮换核、解法重复核。模型很快学会了应付:换个道具、改个标签就过去了。
重复的根子,是生成时没有东西可换,又被指令和核查卡死。正确的顺序是:先让上游多想,给出更多可选的方向;再删掉指令里对人物、场景、配比的硬性限制。硬拦只留在事实层:照搬专有名词、已经死去的人还在做事、同一个人同时出现在两处、时间倒流。
四、每个位一条会话,热续
早期很多位是每次冷启动,一发一个结果。问题是,失忆的位只能复读,接不住上文已经创造出来的东西。后来每个位都改成一条会话持续多轮:首轮给全料,后续每轮只给增量并引用上文。核心工作变成了设计多轮指令的时序:这一轮它已经知道什么,这一轮新给什么,按什么顺序给。
五、评测要对准层
有一次,我拿量「设定」那一层的尺子,去给「执行」那一层的机制下结论,结论自然全错。后来的规矩是:下结论之前,先写清这把尺子量的是哪一层的什么功能;对照实验的各组之间只换被测的那一层,其余逐字相同;每组至少生成两份,控制住生成本身的随机性。
六、读产出,别只看数字
判断产出为什么不好,要把那一步的指令和产出并排,逐段读,找出每一段是照着哪句料写出来的。我曾经凭统计数字下过一个结论,逐段读完才发现完全反了。
七、例子是评测点,不是答案
负责人举一个例子来说明方向时,我曾经直接把例子写进了数据。这只证明我会改,证明不了系统会做。正确的做法是把例子变成评测点:同样的输入,看系统自己能不能规划出类似的东西。
全部文章
让 AI 放手做事之前,先量三把尺子
不做评测,能不能先划出 AI 可以自己做的范围?没有正式标准,但有三类标尺可用:能力、任务属性、自治等级。评测的作用是升级凭证,不是划初始边界。
智能体 治理
给运维智能体开权限时,我们得回答:哪些事它可以直接做,哪些要人批准,哪些绝对不能碰。最理想的是先做评测,但评测要时间,产品等不了。那有没有不做评测也能用的默认标准?
没有正式标准
截至 2026 年 10 月初,我没有找到覆盖智能体自主范围的正式标准。ISO 42001 管的是 AI 管理体系,不涉及智能体的具体边界;美国 NIST 的 AI 智能体标准倡议还在征求意见阶段。现有的「标尺」都是别人评测的副产品,可以分成三类。
尺子一:能力,能做多长、多难的任务
METR 的时间跨度指标衡量模型能独立完成多长的任务。按他们 2026 年 5 月的报告,前沿模型在 50% 成功率下能完成约 12 小时的任务,在 80% 成功率下只有约 1.5 小时。两者差了 8 倍:能做,不等于能可靠地做。
能力的边界是锯齿状的:难度相近的任务,模型有的能做、有的不能,事先很难预测。
尺子二:任务属性,最接近「免评测的默认值」
这一类的维度已经比较收敛:
可验证性: 结果能不能被客观检查。
可逆性: 做错了能不能撤回。要分清动作本身可逆,和后果可逆。
影响面: 做错了会波及多大范围。
主观性: 有没有标准答案。
问责: 出了事由谁负责。
一条实用的经验律:最弱的那个维度,决定自治的上限。DeepMind 关于智能委托的研究还给了一个好办法:如果一个任务不可验证,就继续往下拆,直到每一块都可验证。
尺子三:自治等级,给多大的决策权
有几套分级可以参考:从「人操作、AI 辅助」到「AI 执行、人旁观」的五级划分;把「能做到的自主」和「被允许的自主」分开衡量的思路;以及 CSA 的 0 到 5 级(它自己注明是非官方草案)。
落到产品里
我们最后的映射是:
白名单内的操作直接执行,相当于自治档。
需要确认的操作走承认门,相当于建议档。
禁止清单上的操作硬拦。
评测在这里的位置也清楚了:它是把某一类任务从「需要确认」升到「直接执行」的凭证,而不是一开始划边界的前提。先用任务属性定一个保守的初始边界,再用评测一类一类地放开。
全部文章
从法条到本体
我是学法律出身的。转到 AI 之后才发现,法律训练里最有用的是对概念边界的敏感:定义、构成要件、上下位关系、例外。这些几乎原样搬进了本体建模。
法律 随笔
我的履历在外人看来跳得厉害:在律所做知识产权和诉讼,然后去做法律大模型,再做语音智能体平台,现在做企业知识图谱。但回头看,有一条线一直没断。
法律教会我的
法律分析的基本动作,是拿一个事实去对概念:这个行为符不符合某个罪名的构成要件,这个标志算不算近似商标。为了对得准,你必须清楚每个概念的定义、它的上位概念和下位概念,以及它的例外情况,也就是法条里的「但书」。
这和本体建模几乎是同一件事。一个实体该归到哪个类型,凭什么证据;两个类型之间是上下位还是并列;哪些情况是例外,需要单独的规则。做本体时最常见的错误,是概念边界画得模糊,结果同一个东西在图里出现三种名字。法律训练让我对这种模糊特别敏感。
语音智能体教会我的
做语音外呼和客服智能体时,最难的不是对话内容,而是控制:用户打断了怎么办,什么时候转人工,网络抖动时状态怎么恢复。这逼着我用状态机来想问题:每一个时刻系统处在什么状态,什么事件会让它迁移到哪里。
后来做知识图谱和多智能体产线时,我发现几乎所有棘手的问题,最后都能还原成状态问题:一条数据现在处在哪一步,谁有权改变它的状态,失败了停在哪里。
评测教会我的
在面壁做法律大模型评测时,我花了很多时间让机器评分和人工评分对齐。那段经历让我对「分数从哪来」格外较真。后来设计图谱的置信度时,我坚持不用模型自报的分数,而是让每个数字都能追溯到证据。
串起来
定义要清楚,状态要明确,分数要有出处。这三件事分别来自法律、语音智能体和评测,最后在知识图谱里汇合。我现在做事的方式可以总结成一句话:结构由人来定,内容交给模型,结果要能被检查。
全部文章
检索时摘要:在设计书语料上复现 LazyGraphRAG 的查询侧
GraphRAG 在建索引时就把社区写成摘要,可写摘要时并不知道以后会被问什么。LazyGraphRAG 把摘要推迟到提问时,但微软没有开源查询侧。我在一套融资系统的设计书上做了原型,和向量检索、索引时摘要三路对照,再看社区导航到底有没有用。
研究 知识图谱
GraphRAG 的全局问答靠社区报告:建索引时把实体描述合并,再按社区写成摘要。问题在于写摘要的时候不知道以后会被问什么,被压掉的细节恰好可能就是答案。LazyGraphRAG 的思路是索引时不写摘要,只建一张便宜的导航图,等问题来了再去原文里找、再总结。索引侧我之前已经做成零 LLM 的版本,这次补查询侧。微软的查询侧没有开源,只能按论文和博客的描述自己实现。
原型怎么走
向量本地现算。 497 个文本块用一个 256 维的本地日文嵌入模型现算向量,130 秒,不依赖云端。
沿社区树最佳优先往下找。 最顶层最大的一个社区占了 42% 的文本块,太粗,所以从第二层起步。每个社区按其中最相似的几个块排序,抽 3 块交给 LLM 打 0 到 3 分;命中的社区再进入子社区。每题最多判定 60 次。
从原文抽事实再汇总。 只对判为相关的块抽取事实,再汇总成带出处标注的回答。这一步是 map-reduce,和 GraphRAG 全局搜索同构,只是 map 的对象是原文块,不是社区报告。
三路对照
另跑两组:B 直接取向量最相似的前 N 块,走同样的抽取和汇总;C 在原来 62 份 LLM 社区报告上跑 GraphRAG 的全局搜索,代表索引时摘要。
问题 A 检索时摘要 B 向量前 N C 索引时摘要
局部:利息计算的尾数处理 完整答对:精度转换、三种处理区分、默认舍去、按商品区别、最终期调整 同样完整 答「资料中不明」
全局:业务功能与数据流 能答,偏业务视角;30 个相关块里有 20 个不在向量前 30 能答,覆盖文档更多 能答,代码名最多
变更影响:担保评估额 60 次判定只有 7 个相关,帐票和文件答不出 相近 候选更多,但多是「可能」
成本每题约 0.03 美元,A 用时 20 到 27 秒,C 每题 0.03 到 0.06 美元。
局部题最说明问题。 尾数处理的规则在原文里写得很清楚,经过「实体描述、合并、社区报告」三层压缩之后就没了。这正是索引时摘要的根本缺陷。
全局题索引时摘要不输。 它的报告建在 LLM 抽出的实体图上,自带代码名;检索时摘要的社区来自名词共现,偏业务词。
变更影响题三路都不够。 这类问题要沿「程序、文件、帐票、批处理」的结构走,文本里能找到的就那么多。变更影响要靠结构图,不能靠文本摘要。
社区导航起作用了吗
第一版有个尴尬的发现:嵌入的相似度全挤在 0.85 到 0.87 之间,社区排序和单纯按向量排几乎一样。也就是说,原型只证明了「按问题判断相关性、从原文抽事实」有效,还没证明社区导航本身有价值。
第二轮做了两件事。一是去重:同一个块在一轮里只判定一次,已判过的分数直接沿用。二是给每个社区生成一行标签:按社区算的 c-TF-IDF 选出的特征词、标识符对应的业务名(从表格行里投票挖出 578 个)、出现最多的出处文档。标签单独算向量,相似度在每层内部做 z 标准化,用来对付分数挤成一团的问题。
问题 按块排序(去重后) 按标签排序 各占一半
全局(相关块 / 文档数) 34 / 12 41 / 16 36 / 13
局部(相关块) 46 49 46
变更影响(相关块) 9 8 8
标签确实改变了查找路径。全局题上两种排序判定的 60 块只有 33 块重合,多找到的内容来自另外 4 份文档;局部题上「尾数、取整」「精度校验」这几个社区在标签排序下排到了最前面。这是第一次看到社区导航真正起作用。各占一半的混合反而没有更好,按块排序那一半把标签的好处冲淡了。变更影响题三种排序合起来也只有 9 个相关块,瓶颈不在排序。
一条调优原则
导航结构要尽量编码向量空间里没有的信息。如果社区本身就是对块向量做聚类,它只是在重复向量排序已经做的事,第一版就是这样。标签之所以有效,是因为它带进了向量里没有的东西:特征词的区分度、标识符对应的业务名、出处文档。顺着这条原则,后面能调的地方分四层:
社区怎么建。 让每个块只属于一个主社区,边权混合向量近邻、共有特征词和文档结构;调平衡度;再加一棵按「文档、章节、页」的结构树并行走。
社区怎么表示。 加 BM25 和标识符精确匹配的词面通道,用业务名词典扩展查询;对嵌入做白化,从根上修相似度挤压;一个社区用多个代表向量取最大值。
查询时怎么走。 用相关性反馈(Rocchio)把 LLM 的判定当场折回查询向量,零额外调用;先用本地重排模型刷掉明显无关的块;按问题类型选广度或深度,变更影响题直接交给结构图做 PPR 扩散;把预算分配换成多臂老虎机,避免一开始走偏就回不来。
把判定攒成学习信号。 每次查询都产生「问题、文本块、0 到 3 分」的记录,是免费的标注。短期可以蒸馏成本地重排模型,让系统越用越便宜;长期可以试 JEPA 式的预测器,输入问题向量直接预测证据所在区域,相当于在向量空间里做 HyDE。后者是推测,没见过在企业文档上验证过的公开结果。
几句诚实的话
只有 3 道题,每种模式只跑了一次,41 对 34 这样的差距还没超出 LLM 判定本身的波动。下一步是补 5 到 10 道题,每种方案跑 3 次取平均。
标签里混进了假业务名(把「无」这类取值当成了名字),挖业务名时要过滤。
这次能下的结论只有两条:检索时摘要在局部细节上明显赢过索引时摘要;社区导航要有价值,必须带进向量没有的信息。
全部文章
GraphRAG 的钱花在哪:社区报告值不值 42%
把一次 GraphRAG 建图的 LLM 账单逐项拆开:抽取占 48%,描述合并占 10%,社区报告占 42%。报告大多是在改写 LLM 自己写过的描述,真正有价值的只有业务语言的标题和一段串联摘要,而这两样可以零成本拿到大半。
知识图谱 研究
上一篇讲检索时摘要 ,这一篇是它的前因:在决定把摘要推迟到提问时之前,我先把 GraphRAG 建图时 LLM 的钱逐项拆开看了一遍。语料是一套融资系统的设计书,495 个文本块,每次调用的 token 和费用都直接从缓存里读出来。
钱花在三件事上
步骤 LLM 在做什么 占比
抽取 逐块抽实体和关系,并给每个实体、每条关系写描述;再加一轮补漏,每块调两次 48%
描述合并 同一个实体在多个块里各有一段描述,合成一段 10%
社区报告 每个社区写一份报告,自底向上逐层生成 42%
社区报告这 42% 买到了什么
主体是改写和扩写。 报告中位长度约 1,900 字,是输入成员描述的 3.7 倍,和原描述的字面重合只有 19%。而成员描述本身就是抽取阶段 LLM 写的,等于把 LLM 写过的东西又改写了一遍。
评分没用。 62 份报告的重要性评分全部落在 7 到 9 分,区分不出轻重。
成本跟社区数线性相关。 单份约 0.012 美元。同一批语料换成零 LLM 的共现图有 812 个社区,全写报告约 10 美元,到大客户的规模再高一个数量级。
真正多出来的价值只有两样: 一个用业务语言起的标题,和一段把成员串起来的摘要。
零 LLM 能拿回多少
我先看了自己零 LLM 版本的报告,问题很典型:标题按全局度数取前三个词,于是枢纽词当了标题,最大的社区叫「记录、IBM、客户」;812 份里有 110 个标题重复;「主要共现」一栏全是模板表头对;代表文本取的是块开头 160 字,内容是文书封面。改了几处之后,效果分三档:
明显有效:出处文档。 列出社区的块来自哪些文档,比如「程序一览(13)、逻辑文件定义书(4)」。文档名本身就是业务名,是最强的导航信号。
明显有效:抽取要点。 从社区的块里挑覆盖特征词最多的 3 句,812 个社区里 808 个能挑到,挑出来的多是定义性的表格行。
部分有效:c-TF-IDF 选标题。 按社区算词频乘逆频,再乘文档 IDF 压掉模板词。泛用词开头的标题从 2.6% 降到 0.4%,但很多标题变成一串代码,人看不懂。
关键的一步是业务名可以零成本挖出来。设计书的表格里,代码和业务名通常写在同一行相邻的格子里。只靠这条规则,860 个标识符里有 486 个(57%)挖到了业务名,比如还款计划表、操作日志、节假日主表。标题于是能写成「还款计划(LMSSCHDP)、还款实绩查询(LMSSCHDL4)」,LLM 报告最主要的价值基本就拿到了。这份「代码与业务名对照表」在报告之外也有用,跨模态焊接和实体名溯源都要它。
结论
默认用零 LLM 报告:业务名加特征词组成标题、出处文档、抽取要点、上下位和关联社区,重要性改按覆盖的文档数算。需要摘要时有两个选择:只让 LLM 起标题和写一句话,单个社区约 0.0007 美元,比现在便宜十几倍;或者干脆像 LazyGraphRAG 那样,等查询走到某个社区时再总结。后者就是下一篇做的事。
两个限制要说清楚:报告质量受抽取器噪声限制,时间值组成的团和识别乱码还会混进来;这些判断是按内容看出来的,最终要看检索时用起来怎么样。
全部文章
向量检索会吞掉编号的精确命中
在客户现场发现:画面编号、工号这类编号向量化以后搜不准,精确标题排在第 10。原因是只要向量有结果就不再走精确匹配。修法是三步:精确和别名优先、内置一条按编号查的预存查询、全角半角数字自动展开。
知识图谱 工程
在一个项目现场,同事发现用编号查知识库总是不准,只好自己在旁边维护了一份编号索引。编号是这类场景里最主要的检索键:画面编号、程序编号、工号、API 名。我回去把检索链路从头审了一遍。
现象
查「LMS061」这个画面编号,精确同名的实体排在 10 条结果的最后一条,第 1 条是另一个程序的别名实体。同一个画面还有第二个节点,编号只写在它的别名字段里,根本没返回。
原因
向量优先,有结果就返回。 实体搜索在配了向量库时,名字走向量(嵌的是实体描述),只要向量给出结果就直接返回,标题精确匹配和子串匹配那条路径根本不跑。而向量对编号天生迟钝:LMSB063 和 LMSB0603 在向量空间里几乎没有区别。
确定性路径太窄。 唯一的精确查询只认大写完全一致的标题,不看别名和描述;纯数字编号还会被误当成内部序号。
图数据库没有合适的索引。 只有 id 唯一约束和标题的范围索引,没有全文索引,按描述查只能全表扫。
预存查询接好了,但一条都没预置。 服务端从 7 月起就支持存一条参数化查询、让智能体按名字调用,可默认是空的,只有一个现场的同事手建过 4 条。
修法
精确和别名优先。 建一个「编号到实体」的精确和别名索引,搜索先查它,命中的结果单独标出来排在最前,再接向量结果。
内置一条「按编号查」的预存查询。 服务启动时在后台写入,不覆盖用户已有的;空编号直接拒绝,因为实测「包含空串」会匹配全部。图数据库补上标题范围索引和描述全文索引后,同一个查询从扫描 8.6 万次、32 毫秒降到扫描两百次以内、5 毫秒,结果相同。
全角半角在检索时处理,对用户无感。 日文资料里编号常混着全角数字和全角字母。查询参数标一个「按编号展开」,执行器自动生成原样、NFKC 归一、大写、全角数字、全角英数几个变体,再加一个前后不贴英数字的边界正则。实测半角、全角、混排、小写全部命中;查「000」从 500 行降到 11 行;有索引时中位 14 毫秒,没有时 146 毫秒。
还剩的问题
括号全角半角混排的长标题,预存查询仍不命中,搜索和精确查询可以。
「1,000」仍会被「000」命中。
向量库开启时精确结果和向量结果的排序只有单测,没在真机上量过。
一句话
编号是「只有身份、没有意思」的字符串,语义检索在这里帮不上忙。混合检索不是把两路分数加起来就完事,精确命中必须有自己的通道和优先级,否则会被向量结果静默吞掉。这和静默失败 是同一类问题:没有报错,只是答案不在第一页。
全部文章
Excel 进知识库时被悄悄截断的三处
现场同事说功能一览表里的几个画面在知识库里找不到。查下来文件入过两次图,内容却只剩每个单元格的前十几行。原因不是一个,是三处各自合理、叠起来致命的截断,而完整原文其实一直躺在一个没人读的字段里。
工程 数据质量
这是静默失败 那篇的一个续集。一位现场同事反馈:客户的功能一览表里有三个画面的定义,在知识库里怎么也查不到。我核对了一下,这个文件入过两次图,两次都包含那张表,画面编号也作为实体存在。内容去哪了?
第一处:固定行高
Excel 走 Office 渲染成 PDF 再交给视觉模型读。那几行设置了固定行高,比如 243.75 磅,单元格里却写了 35 行字,打印出来只看得见前 18 行左右,后面的排序规则、编辑方式、业种这些定义全在裁切区。渲染代码没有做任何自动调整行高。顺带排除了一个怀疑对象:文件自带的打印区域不是原因,渲染时会被覆盖成实际使用范围。
第二处:元数据通道每行 500 字
除了渲染,还有一条元数据通道:把每行非空单元格用制表符拼成一段,作为正文旁的参考文本一起进图。这条通道在拼接时截了 500 字。那一行有 1,301 字,只剩 500;另一行 2,504 字,丢了 2,004。查提交历史,这个上限最早是给智能体当提示用的,标题截 80 字、区域截 500 字,完全够用;一周后有人把这些片段原样灌进了正文,上限没跟着改,提示的上限就变成了正文的截断。
第三处:只取前 200 行
同一条通道只取工作表前 200 个非空行,形状里的文字截 3,000 字,表格截成 5 张、每张 30 行 10 列。大表的后半部分整体不进图。
完整原文其实一直都在
讽刺的是,每个单元格的完整文本在解析时就已经取出来了,存在元数据的扩展字段里,随文档一起入库。但它不切块、不嵌入、检索不到。另有一条本该读它的通道需要一个外部参数,服务模式下从来不传,于是那一步每次都被跳过,等于死通道。
怎么修
当天先交付可用的路径。 给检索服务和 MCP 加一个「按文档取单元格全文」的工具,直接读那份完整原文。上线后两周半,这个工具被调用了 6.8 万次,在全部工具里排第四。
根治在上游。 单元格全文直接灌进正文,去掉 500 字和 200 行的上限;渲染前自动调整行高;长文本单元格单独扫描;图片附件和概要页的静默失败分别开票。
教训
每个上限在它诞生的地方都是合理的。危险的是数据流改了,上限没跟着改,它的含义就从「提示长度」变成了「丢多少正文」。
「入过图」不等于「内容完整入图」。核对时要用文末的标记词去查,而不是只查文件名或编号在不在。
最好的修复入口往往是那份已经存在、只是没人读的完整数据。
全部文章
本体管准,社区管全:以及主流智能体怎么用记忆
本体论回答「东西是什么、连着谁」,社区回答「整体有哪几块」,两者是两种粒度,不能互相替代。再看 Claude Code、Codex 和几个开源记忆系统怎么用记忆,它们的共识恰好和我们的知识库产线反过来。
知识图谱 智能体记忆
这是《强 AI 时代,知识图谱产线该存什么》 的续篇。那篇把产线拆成四层,结论是我们把力气花在了最容易被替代的那一层。这篇回答两个跟着来的问题:本体和社区各自到底解决了什么;业界做得好的智能体又是怎么用记忆的。
本体回答什么
本体回答的是:这个领域里有哪些种类的东西,种类之间应该有哪些关系。落到产线上做了三件事:规定抽什么,不让模型自由发挥抽出一堆杂词;把叫法归一,同一个东西在不同资料里的不同名字收到同一个实体上;让检索能沿路径走,回答「改这张表会影响哪些画面」「这个功能对应哪段代码」这类问题。这些问题都是精确、局部、能核对的,答案是一条条可以回到原文的边。它答不了的是「这批资料整体在讲什么」。
社区回答什么
社区是先按连接把东西聚成团,再总结每一团。它的价值是能回答全局问题、能压缩、能发现本体没预先定义的分组。局限也是我们踩过的:社区是统计意义上的团,不是语义上的团,代码侧调用密集的东西会聚到一起,跟业务边界对不上;会被枢纽词带偏;报告是散文,结论很难追溯到具体的边。
一句话:本体负责准,社区负责全。 治理必须靠本体,全局概览可以借助社区,但不能把社区当成业务结构的定义。我们产线里一度有四套「归堆」机制并存:连接密度聚类、按本体类型打标签、业务域合成、代码侧规则聚类。真正校准过的「社区」应该是业务域,不是类型;而它缺的不是一份审计报告,是结构上的一个承认门:由 LLM 提案、人来签字。
主流智能体怎么用记忆
Claude Code。 人写的项目说明每次完整加载;自动记忆一个事实一个小文件,索引常驻、细节按需读;只存从代码和提交历史推不出来的东西,比如偏好、纠正、决策和原因;记忆只当线索,用之前要回现场核对。找代码不靠索引,直接 grep 和读文件。
Codex。 结构基本一样:人写的说明逐层叠加,会话结束后后台总结经验存在本机,找代码同样靠现场搜索。
Mem0。 从对话里抽事实存向量,可选存图。它自己的论文里图版本只比纯向量版高一点点(68.4 对 66.9),速度慢约 3 倍。
Graphiti / Zep。 时序知识图谱,每条边记两个时间:事实何时成立、系统何时得知。核心是事实会变、要能追溯,不是图更聪明。
Letta。 把记忆当操作系统,上下文是内存、归档是磁盘,由智能体自己管换入换出。
它们的共识是:语料不预先理解,用时再搜再读;持久化的只有经验和判断,而且是少量、人能直接读懂的文本;记忆是线索不是事实;在使用中写入,离线时整理;索引常驻、细节按需。我们重点投入的那层(预先抽实体关系、聚社区、做归类),正是 Claude Code 明确放弃的那层;它们最看重的「判断」,在我们的产线里几乎是空白。
不能照搬的地方
它们面对的是代码仓:纯文本、grep 得到、规模可控。企业知识库面对的是 Excel、PPT、扫描件,grep 读不了;日文叫法五花八门,同一个东西有三四种说法;设计书里的表和代码里的类之间的连接,现场去找代价很高;几万份文档、客户本地部署,每次从零搜索太贵。所以可读化的原始资料、确定性的骨架、术语对照和跨模态锚点这类最小导航层,仍然值得预先算好。
由此得到的方向:产线从「预先构建一个完整的知识图谱」,改成「可读化的原始资料、确定性骨架、最小导航层、在使用中增长的判断账本」。本体在这个结构里的角色,从抽取的模具变成判断账本的词汇表:人确认的结论用什么术语记、挂在哪个对象上。
全部文章
知识库智能体为什么停在「顾问」这一步
智能体加外挂知识库,今天大多数落地都停在顾问:AI 读、推理、提建议,人判断、执行、担责。这一步的价值有一个硬上限。我拿一个精心设计的类 AIP 平台做靶子,讲它为什么把「停在这里」写进了架构,以及越过顾问需要的五样东西。
智能体 治理
和同事讨论一个正在做的类 AIP 平台时,我被问到一个更根本的问题:一个智能体利用外挂知识库,这件事的范围到底到哪里为止?我的判断是,今天世界上大部分落地只到「顾问」这一步。
顾问这一步的硬上限
顾问的结构是:AI 读、AI 推理、AI 提建议;人来判断、人去执行、人负责验证。它建立在三样东西上:智能体循环让它能自己探索、多跳;多轮对话让人可以随时纠偏,实际上是人在实时担当验证器;知识库让上下文里没有的东西也能被召回。这一步的价值有一个硬上限:
顾问的价值 = 为人省下的时间 - 人核对的成本
只要执行和担责的人还在,知识库的精度就决定核对成本有多高。知识库做得再好,也只是把核对成本往下压,改变不了「人是瓶颈」这个结构。
一个顾问阶段的极致设计
那个平台回答的是「怎样让 AI 的建议能被人放心采纳」,每个设计都服务这个目标:证据加出处让人能核对;五档置信度、区分「没看到」和「没有」,让人知道该信多少;只有人写的内容才能进业务本体,责任归属清楚;产物是差异报告、设计评审、诊断书,交付物是给人读的文档。它复刻的是系统集成商的工作流,让 AI 辅助每一步。AIP 不复刻工作流,它替换的是干活的那个面。
批判
系统的吞吐量就是人的吞吐量。 每个要素都要人承认,人一忙系统就停。AI 能力每年翻几倍,这套架构的上限锁死在人身上,等于在给一个过渡阶段做最重的投资。
「为什么只有人知道」被用过头了。 规则背后的原因只在要修改规则时才需要;执行时 AI 需要的是规则本身,而规则写在代码里。人应该出现在例外和变更的决策点,而不是每一个要素上。
业务本体没有下游消费者。 它最后给人看,或者给只读的智能体回答问题,没有任何东西会自动按它行动。为知识而做知识,这是鸡肋感的根源。
衡量的是地图,不是地面。 评测测的是抽取的召回和精度,从没测过一次变更有没有成功、快了多少。
「人必须在环里」被做成了结构,而不是参数。 智能体只读、本体只能人写,都是硬编码。将来想往前走一步,要动的不是配置而是架构。
公平地说,有些场景顾问就是正确的天花板:错误不可逆、法律上要求人担责、客户自己要求人签字;日本的系统集成市场也确实在买诊断书。问题不在于它做错了,而在于它停在了顾问,并且把「停在这里」写进了架构。
越过顾问需要什么
基础 作用
可执行的环境 沙箱、CI、部署通道,AI 能真正动手
自动验证器 测试、可执行的规则、冒烟,替代人做核对
可逆性 版本、回滚、完整历史
契约和权限 AIP 式的动作:AI 能动什么、范围多大
结果的记忆 记住「什么改动成功了」,不只是「文档里说了什么」
这时人的角色从逐条承认 AI 的产出,翻转为定义验证器和契约、只处理例外。顾问阶段的资产都能转过去:给人看的校验规则变成 AI 改动必须通过的测试;置信度从「告诉人该信多少」变成自治的门槛;影响范围从写进报告变成 AI 能改的边界;全量审批只留下验证器拦下来的、超出范围的、不可逆的例外。这和我在三把尺子 那篇里说的「可验证、可逆、影响面」是同一组标尺。
一句话:要往前走,真正要改的是那条原则。「AI 提案、人落地」应该改成「人定义验证器,AI 在验证器之内落地,人处理例外」。
全部文章
结构、语义、本体:别让一次抽取背三重不确定性
5 月刚接手产线时,代码和设计书都直接丢给 GraphRAG 抽取:模型既要猜一个类包含哪些方法,又要猜这个方法算业务规则还是服务操作。我当时定下的三层分离,后来成了整条产线的设计原点。
知识图谱 架构
刚接手知识图谱产线时,代码文件是被原样转成文本、丢进 GraphRAG 抽取的。我读了几个做代码知识图谱的开源仓库,又把 GraphRAG 3.0.9 的源码拆了一遍,得出一个后来贯穿全部工作的判断:问题不是缺 AST,而是把三件性质完全不同的事压进了一次 LLM 抽取。
阻抗不匹配
一次抽取同时在回答三个问题:结构是什么(这个类包含哪些方法、调用了谁),它意味着什么(这个方法是在实现一条业务规则吗),它属于哪个类型(服务、规则、数据)。第一个问题本有确定答案,却交给了概率模型去猜;三重不确定性叠加,错误还会互相放大。
三层分离
结构层:存在什么。 由语法解析器产出,确定性、覆盖全部代码。文件包含类、类包含方法、方法调用方法、方法读写哪张表、类继承谁,这些边全部从语法直接读出。节点 id 用「文件、名字、起始行」算哈希,不依赖模型命名,天然支持增量和去重。
语义层:意味着什么。 这才交给 LLM,而且任务被缩小了:不必再发现结构,只做跨域标注,比如「这个方法实现了一条计算规则」「这个类对外暴露一个 API」。这类跨域边只有模型能推断,语法给不了。
本体层:属于什么。 由预先定义的骨架决定,实例通过「是某类型的实例」挂到骨架上,和语义层的边共存、互不覆盖。
什么该建节点
同时定了粒度规则:类、方法、表这种会被检索和引用的建节点;单个 import 不建,折叠成外部包;局部变量不建。给代码向量化时优先用签名和注释,不用整个函数体,降噪很明显。
不改 GraphRAG 源码就能接入
拆源码时发现两个关键口子:流水线运行时传入现成的文档表就会跳过读取步骤;工作流可以动态注册和替换。所以结构层可以在 GraphRAG 之外独立产出,再从这两个口子接进去,不需要维护一份分叉。
后来怎样了
这三层后来长成了产线的骨架:结构层变成各语言的 AST 车道和CRUD 足迹 ,语义层变成受本体约束的抽取和跨模态焊接,本体层变成客户自适应生成的本体。半年后回头看,最常回到的还是这条原则:能确定的事别交给概率去猜。
全部文章
召回调不动时,先查指标
关系召回卡在 0.39,换模型、加补漏、加诱导都纹丝不动,我一度下结论说生成已经饱和。最后发现是评测脚本把召回算错了。修正之后,真正的免费杠杆浮出来:类型对覆盖,召回加 15 点、零误报。
评测 知识图谱
这是一段完整的研发弧,从「开个参数调召回」一路挖到落成生产改动。它最值钱的部分不是结论,而是中间那次翻转。
一度看起来像天花板
关系抽取的召回卡在 0.39 左右。打开「每个实体至少一条边」的诱导,没动;加 verify 和证据核对,召回也没掉;换更大的模型,召回和小模型完全相同。两个容量不同的模型撞在同一堵墙上,我于是判断墙是结构性的,生成侧已经饱和。
翻转
被追问「再多试试」之后,我回头去看评测脚本本身。脚本里的计分函数返回的是(命中数、预测数、标准答案数),算 F1 的地方却把它当成(命中、误报、漏报)来用,召回实际被算成了「命中 ÷(命中 + 标准答案数)」。修正后真实召回约 0.65 到 0.68。前面那些「诱导无效、模型无效、生成饱和」的结论,全部作废。
教训只有一句:指标钉死不动,先查指标,别急着下收敛结论。
把漏掉的边分类
修好指标后,我把每条漏掉的标准答案归类:命中约 66%;关系类型标错约 14% 到 17%;被类型对门控挡掉约 8% 到 11%;方向反了约 5%;真正没生成出来只有 3% 到 6%。再细看,标错类型的那部分是同一个问题的下游症状:本体里没给这对实体类型提供正确的关系选项,模型只能从允许集合里挑一个错的。证据核对的误杀率为零。
真正的杠杆:类型对覆盖
标准答案里有 27.5% 的「源类型、关系、目标类型」组合根本不在本体允许的范围内,比如「程序写入表」只允许挂在方法上。这一处声明同时在两个地方起作用:抽取提示词只问允许的组合,门控只放行允许的组合。补全覆盖后,召回从 0.677 到 0.831,加 15 点,误报零增加。相比之下,去掉门控加 3 点但误报翻几倍,多轮补漏加 2 到 4 点,诱导反而伤精度,换模型几乎没用。
覆盖从哪来:治理必须是语义的
本体自适应生成原本只对实体类型做增删改,关系类型对只会「继承默认再删掉」,默认里没有的组合永远进不来。我补上了关系轴:从语料里开放地发现「类型、关系、类型」三元组,再把模型自由起名的关系对齐到标准词表。受控对比里,用字符串相似度对齐几乎没用(+0),用嵌入做语义对齐加 11.7 点,离理想上界只差一半。这是「标准语法对齐」这件事最硬的一条证据:治理的价值在语义质量,不在格式。
可复用的结论
召回的一级杠杆在模型上游的本体覆盖,生成侧的技巧多半是用精度换召回。
宽覆盖管召回,证据核对和 verify 管精度,两者是正确的组合。
先换覆盖,再换模型。覆盖没解锁时换大模型只是加成本。
全部文章
索引慢,往往不是 LLM 慢
GraphRAG 建一次图跑了 11 个小时还没跑完,第一反应是加并发、换快模型。实测下来两个瓶颈都不在模型:抽取慢在单线程组图且越建越慢,嵌入慢在下载带宽。分片后快 3.73 倍,换编码后快 5.3 倍。
工程 知识图谱
大语料建图很慢,最自然的猜测是 LLM 慢、限流、并发不够。我在两个环节上分别量了一遍,答案都不是。
抽取:慢在单线程组图
证据很直接:缓存全命中、零调用、零费用的时候,CPU 仍然单核 100%,每分钟只处理约 40 个块。而且单进程建一张大图会超线性变慢:一次运行一夜 11 小时只走到 11,189 块里的 6,885 块,早期每分钟 40 块,后半夜掉到个位数,因为每个块都要并进越来越大的内存图。加并发只能加快「发新调用」那段;换大核机器也没用,这是全局解释器锁下的单线程;GPU 对组图毫无帮助。
解法是多进程分片加全局合并。抽取本来就按块独立,分片不改变任何块的抽取结果;实体之间的关联是靠最后全局按名字合并形成的,所以只要最后统一合并、在合并图上重算社区,结果和不分片一致。每片只建小图,既并行又不触发超线性退化。本地 16 核 4 片实测 3.73 倍,接近线性。
两个配方细节:分片要按块数或文档大小均衡,不能按文档个数,一个 1.4MB 的巨型文档落在一片里能把整体拖到 0.2 倍;也不能一个文档一片,启动开销会主导。另外缓存键不含机器信息,拷到任何机器同配置都能命中,换机重跑不用重付钱。
嵌入:慢在下载带宽
一册 2,332 页的手册要嵌入 74,464 条文本,跑了 5.7 小时。产线里嵌入批量被钉成 1,看起来像是 batch 的锅。实测真因是返回体:向量用 JSON 十进制浮点返回,3072 维每条约 29KB,7.4 万条约 2.1GB,那条链路下载顶死在每秒约 110KB,正好约 5.3 小时。batch 化本身不省字节。
杠杆是让服务端用 base64 返回原始浮点字节,体积降到约 3.5 分之一;再绕开中间层直连接口做真正的批量;按 token 均衡切片、支持断点续跑。结果约 65 分钟,5.3 倍,和原生结果的余弦一致性在 0.99997 以上。首轮还因为连接中途断开崩过一次,续跑时 17 片里 4 片零重算复用。顺带的坑:连接被截断抛出的异常不属于操作系统错误类,重试列表要显式包含它。
并发也有拐点
另一次实测:并发 25 时每分钟 43 块,60 时 48 块,200 时反而掉到 18 块。拐点在 60 左右,而且没收到 429 不代表没被限流,服务端可能在隐性排队。
一句话
「慢」先量再猜。看 CPU 在不在干活、网络字节有多少、调用数和吞吐的关系,三个数字就能把瓶颈从模型身上摘下来。
全部文章
版面检测漏掉一整页,根因在权重
设计书里的版面图和 Excel 画面原型,切图时常常一个框都检不出来,然后静默退回整页。查下来根因不在代码,而在模型权重:它是训在欧美 PDF 版面上的,日文设计书对它来说是陌生数据。
工程 数据质量
文档进知识库前要先切图:版面检测模型找出图、表、文字块的坐标,再在矢量 PDF 上按坐标裁出子图交给视觉模型。有一类页面总是出问题:并排的两个画面切不开,稀疏的图文页一个框都检不出,然后静默退回整页处理,质量记录里也看不到。
根因
从权重文件里读出训练参数:这是一个训在 DocLayNet 上的检测模型,输入尺寸 640,训练数据是欧美 PDF 的 11 类版面。Excel 画面原型和日文设计书对它来说是分布外的数据。生产推理时也没传输入尺寸,默认就是 640。另外裁切逻辑只做纵向聚类,裁片固定全宽,所以左右并排的块永远切不开。
架构上正确的部分要保留:模型只出坐标,裁切发生在矢量 PDF 上,所以降低检测分辨率伤的是检出率,不伤裁片清晰度。
实验
11 张样张上,生产配置全场最差,接口概要页和功能一览页 0 检出。原权重改成 1280 输入能救回功能一览页,结构图的置信度从 0.44 升到 0.91;换成 DocLayout-YOLO 底座、1024 输入,是唯一救活稀疏图文页的配置(0 到 7 个框),它还自带「可丢弃」类别,页眉页脚自动过滤。没有一个尺寸对所有页面都好。
修法
双后端。 默认 DocLayout-YOLO,旧权重加 1280 输入作为可回滚选项。
阶梯升档,不全局升档。 有效框少于 3 个或页面长宽比大于 3 时,才升到 1600 并和原尺度结果做 union-NMS 合并。全局用 1600 被实验否决:稀疏图文页在 1600 下会塌成只剩「可丢弃」框。
二维聚类。 同一行有两个以上簇、净距不小于 40 像素才分列,策略保守。
零检出要留痕。 不再静默退回整页,写进质量记录并调低质量等级。
视觉地板。 前置的小模型判「这页没图」时,如果确定性证据显示图片面积占比不低于 20%,或者结构上可疑,就顶回去走视觉车道,兜住检测模型的盲区。
端到端验证:两个 0 检出页复活,12 个裁片对了 11 个,正常页无回归。权重随包分发,内网工作机拿到即用。
一句话
用开源权重之前先读它的训练参数。很多「代码没问题但效果差」的情况,根因是模型从没见过你的数据。
全部文章
把智能放对位置:代码和设计书的跨模态焊接
把设计书里的业务概念连到实现它的代码,前三轮都失败了。转折是换了分工:确定性代码负责把双边证据组织完整,LLM 只推理一次并允许弃权。高置信精度从 25% 到 33% 提到约 86%。
知识图谱 智能体
企业知识散在两处:日文设计书和遗留代码。让人和智能体能问「这个业务处理在代码里是哪个类」,就要在两张图之间焊上跨模态的边。结构层的焊接(表名、列名、命名规则)相对容易,难的是行为层:设计书里的一个业务处理,对应代码里哪个处理器。
前三轮为什么失败
第一次直接复用文档抽取的流程,要求关系必须在原文里逐字陈述。但代码和设计书之间的行为关联是跨日英两种语言推断出来的,两边都没明说,结果大多弃权。第二到第四次,我试着把「解析表名、选目标」全部做成确定性规则,LLM 只在末端说是或否。每一轮偏离一点,质量就掉一点:一次漏进了数据传输对象,一次方向反了。
回头看,根本错位在于智能放错了位置,而且上下文是饿的:该推理的地方用了规则,该给足证据的地方只给了一个是非题。
正确的分工
先亲手用工具追了两个真实概念,看清了关联到底是什么:它不是语义相似,而是两张图各自已持有的结构化事实的连接和三角验证。同一张表(靠注释在日文逻辑名和物理名之间架桥)、同一组列、同一种操作(登录对应 insert)落在同一个代码物上。
确定性负责组织证据。 概念侧取两跳邻域,把表实体的描述和物理名带进视野;候选侧取两跳,处理器到 Mapper 到 SQL 到表。完整、不幻觉。
LLM 负责综合。 在组织好的双边证据上推理一次:架桥、选目标、校准置信度,或者弃权。
100 个概念上:27 条连上(14 条高置信),72 条诚实弃权;高置信抽检 12/14,约 86%。之前的批量评测是「25% 到 33% 精度且自信地答错」。全程确定性组织加每个概念一次 LLM 调用,可以批量跑。
另外三条体会
跨边少,等于解析不到位。 画面和设计书的焊接一开始很少,原因是前端抽取器只抓了表格列标题,漏掉了表单上的日文标签。每修一处抽取,跨边就涨一截,最终从 682 条到约 7,000 条。「两边没有共同锚点」常常是草率的否决。
注册表是钥匙。 设计书里的概念用日文逻辑表名,代码里是物理表名,直接连接为 0;表定义书里的逻辑名和物理名对照是唯一的桥。另外大小写和全半角归一一项就救回 951 条边。
跨边变少,先怀疑是自己在破坏。 有一次审计把逻辑桥焊上的约 4,000 条边当成水分清掉,跨边从 7,009 降到 2,914,后来证明是误判并回滚。之后立了一条规矩:数字变少默认是我在破坏,先证明被删的确实错,再动。
歧义的匹配不静默丢、也不静默猜,进人工确认队列。人只处理确定性和 AI 都拿不准的那部分。
全部文章
没适配却静默,是最坏的失败
焊接模块换到第二种语料上,产出 0 条边,程序正常退出,没有任何报警。事后考古出 20 条写死的假设。修法不是让 AI 兜底,而是把适配做成机器强制的穷举:适配矩阵加审计闸。
工程 方法
代码和设计书的焊接模块,在第一种语料(Java 加 MyBatis 的系统)上调到了约 7,000 条跨边。换到第二种语料,一套 RPG 写的融资系统,重跑一遍:0 条。程序退出码是 0,日志里没有任何警告。
考古
逐个车道盘点,找出 20 条写死在代码里的假设:Mapper 的命名方式、表定义书用制表符分隔、日文注释写在 Javadoc 里、画面用 React 写、文件路径带 .java……第二种语料三重失配:表格渲染出来是竖线分隔不是制表符,没有表定义书那种体裁,代码里没有日文注释。每一条单独看都是合理的实现,合起来就是「这个模块只认识一个客户」。
一个洞察
锚点的生成和语言栈相关,锚点的消费(落边、分层、置信度、人工队列)和栈无关,问题全在生成侧。而且最大的空洞是零成本的那种锚:两边完全同名,却没有任何车道去接。比如「给代码实体找一段文档语言的文本」这个抽象本身是对的,绑死的只是来源:Java 的来源是 Javadoc,RPG 的对应物是文件定义里的 TEXT 字段,VB6 是行内注释。
修法:穷举适配,机器强制
我最初想做声明式的配置包,被否了:变更点多、操作难,那次手工配了十几个环境变量就是反面教材。最后定下的规范是三件套:
出口对账闸。 双向账本,每个实体的归因只能是「已焊、对面不存在、孪生、在人工队列、车道缺失」之一。「车道缺失」大于 0,就是该适配没适配,自动失败。这和取入时「输入数等于入账数」的对账是同一个结构。
适配矩阵物化。 车道乘语言栈,每个新栈对每条车道都要表态:已适配、不适用、待做。有空格就过不了校验。
AI 只兜发现,不兜判定。 扫描未焊实体只产出人工候选,不直接落边。
落地后三条报警链都实弹验证过:原样跑出 0 报警加 5 笔如实列出的债;故意把一条车道谎报成已适配,审计报警退出;删掉一格,校验直接拒绝。第二种语料先用「完全同名加归一同名」的通用车道加 LLM 碰撞裁决从 0 做到 508 条边,还完三笔债后到 698 条,另开了一本 496 条的同义边账。
「数不对」时先拆账
有人觉得 698 太少。拆开看:跨模态焊接的上限由两侧名字的交集封顶,代码侧本身是样例代码,交集只有 266,「感觉该多」多不出来。多出来的其实是另一本账:文档内部的同义词,此前根本没开。素材池不等于可焊数,感觉少要先拆口径,再怀疑管线。
一句话
覆盖靠兜底加闸,正确靠穷举加验证加人工队列。最怕的不是报错,是不报错地什么也没做。
全部文章
版本和消歧正面冲突
「给知识库加时间戳」听起来是加一列的事,拆开看是知识库的版本管理,而且和实体消歧正面冲突:消歧要把不同名字折成一个,版本要把同一个名字按时间分开。两者必须一起解。
知识图谱 架构
有一个看似小的需求:给知识库加时间戳,资料改版后能分清新旧。拆开看,它不是每行加一个创建时间,而是知识库的版本管理;更麻烦的是,它和实体消歧正面冲突。
二维身份
一个实体的身份其实有两个维度:规范形和版本。消歧沿「形」轴折叠,比如设计书里的「融资编号」和代码里的 LNNO 是同一个东西,要合并;版本沿「时」轴分离,2026 年版和 2027 年版的同一张表要分开,还要能连出「演化为」的边。偏偏判断演化的逻辑靠的是精确同名分组:没有跨版本消歧,就检测不到演化。两件事必须一起解。
GraphRAG 给了挂载点,没给逻辑
读源码的结论:工作流列表可替换、文档级的原始数据能透传,挂载点是有的;但实体身份是随机生成的 id 加大写名字精确匹配,增量合并按名字坍缩,消歧完全没有,时间字段只写不读。挂载位置都有,核心逻辑都得自己写,但不需要分叉源码。
四个预留接缝
抽取时溯源加版本盖章。 每次提及带上文档、文本块、版本标签、内容时间,只带料,不判断。
非破坏式的规范身份列。 这是命门:不改写实体名,新增一列规范 id,下游按它分组。身份可以重算,不用重抽。
可插拔的消歧步骤。 默认只做 Unicode 归一,可以换成精确、注册表、向量、LLM 逐级升档,也可以限定在版本内。
版本合并槽位。 按「规范 id 乘版本」生成演化边。
后处理也随之瘦身:只做解码和关系类型物化,按规范 id 连边。增量更新也只产出提及,交给消歧步骤,不用原生的按名合并。所有选择收进配置,默认等于现状,选哪套版本方案只是开启对应的接缝。
后来验证了什么
做增量合并时,这套预留救了不少事:实体有了 id 以后,任何「按名字合并」碰到重名都会把一条边炸成 N 条(实测代码边从 19 万涨到 140 万);消歧放在全量后处理里只删行、不修引用,会在增量下留下死 id,挪到合并工具里带着 id 映射重映射后,悬空引用从 394 降到 0。版本和消歧解耦,不是设计洁癖,是增量能跑通的前提。
全部文章
schema 不再贵在创建,仍贵在写错
强 AI 改变的是读侧建模的成本,不是结构的必要性。我逐条清点了 AIP 的对象、动作、应用三侧,判断哪些是弱 AI 时代的脚手架可以换掉,哪些是不变量必须保留,并提出和它顺序相反的路线:先有动作,schema 沿动作足迹结晶。
架构 智能体
这篇接着Palantir 的本体里没有魔法数据库 。那篇拆的是对象库;这篇讨论一个更大的问题:在强 AI 的前提下,AIP 那套机制里,哪些是为弱 AI 时代搭的脚手架,哪些是无论模型多强都要保留的不变量。
一句话主张
强 AI 改变的是读侧建模的成本,不是结构的必要性。schema 不再贵在创建,可以从证据里长出来;但仍然贵在写错,写侧必须全类型化。
一个内部证据:同一个模型,拿两份不同的证据包回答同一件事,一致性分别是 0.93 和 0.97。运行时让 AI 现读现判是不稳的,这恰恰是当年 AIP 把一切类型化的原因。所以正确的姿势是 AI 在构建时合成一次、人签字,服务时确定性地消费。
逐条清点
对象侧最大的缺口是跨构建稳定的主键。 解法不是新发明,是激活早就预留的规范身份列和可插拔消歧,变成一个持久的对象注册表。
属性类型不做全量建模,动作触及才固化。 没有动作用到的属性,类型化是浪费。
有类型的边,我们反而更强。 代码侧的调用、读写、继承都是语法给的确定性边。
动作侧缺副作用和函数式动作。 规则类的修改走「台账吸收式写入」:编辑先进台账再合入,比直接改对象更可审计,诚实的代价是有延迟。
应用侧大半可以换掉。 读侧的界面搭建可以被对话和生成替代;写和审批侧必须保留类型化界面。
act-first:顺序倒过来
AIP 是先建 schema 再行动;我们是先行动,schema 沿动作的足迹结晶,动作需要什么才固化什么。四步:对象注册表;动作驱动 schema 固化;读侧 AI、写侧审批两条轨;写侧补上副作用、执行时再校验和台账式新建对象。比 AIP 多出的一件是:动作类型可以由业务缺口来提案,和裁决记在同一本账上。
影子系统与可信性
Palantir 自己也是影子:数据同步进来,编辑落在自己的编辑层,不直接改源系统,回写走动作的 webhook 调源系统接口,再绞杀式地慢慢替代。准确的说法是「按状态所有权拆」,不是「按接口拆」:记录系统保有操作真值,影子保有决策真值。
AI 生成的 schema 怎么才可信?答案是换权威来源,不是让 AI 变可信。三级:写合同继承既有系统自己的合同,比如文件定义的字段长度和键、DDL、OpenAPI,这是系统自己说的;语义路由由 AI 合成、人签字;解释只给 AI 当参考。我们和 Palantir 的真正差异是它叠的是运营数据,必须活性同步;我们叠的是知识资产,变化资料的撤回和增量车道已经覆盖了这一块。