@unieai/uad-studio-kb-sources
v0.1.21
Published
Read knowledge-base citations out of Studio's MCP tool results
Readme
@unieai/uad-studio-kb-sources
English | 中文
从 Studio 的 MCP 工具结果里读出知识库引用——答案背后的文档、页码、章节、分数与证据 id——好让界面能说明答案是从哪里来的。
它是一个纯读取器:没有服务、没有注册、不连网、不持有状态。调用方手上已经有工具名与那段文本,调 kbSourcesOf(name, text) 就得到若干行,或者一个空列表。
为什么这是解析,而不是读一个字段
Studio 的 MCP 服务器对一次工具调用只回一个纯文本块。没有 structuredContent、没有 _meta、没有 annotations——所以它知道的每一条引用,都是以 JSON 塞在那段文本里传过来的,外面最多裹着三层信封:JSON-RPC 的 error、MCP 的 isError 结果,然后才是工具自己的载荷。读字段当然是更好的设计;但那不是现存的设计,而本包就是唯一知道这件事的地方。
这个形状属于产品,它可以在不通知本仓库的情况下改变。因此每一条分支的答案都是「没有引用」而不是抛错:一个遇到意外载荷就大声失败的读取器,会把 Studio 的一次发布变成桌面版的一次故障。真正钉住它看得懂的那些形状的,是测试文件,不是 schema。
两个工具对页码的算法不一致
kb_search 回报的是从零开始的原始页索引。kb_grep 已经加过一了。把两者都归一到从一开始这件事,在这里做、只做一次,因为另一种结局是一个只在 grep 结果上出现的差一错误——search 看起来一直是对的,而 grep 永远差一页,于是一条指向错误页码的引用会被当成检索质量问题,而不是算术问题。
kb_grep 也完全不回报 id,所以它的行不带证据 id,也就不带链接。这是刻意的:一个伪造的链接比没有链接更糟。
怎么回到原文
Studio 从不把知识库 id 作为字段送出。它是证据 id <kbId>:<docId>:<idx>:<digest> 的第一段,由 documentRefOf 还原——两半一起给,或者都不给,这样拿到不可用 id 的调用方会略过链接,而不是拼出一个坏的。
工具名
以后缀匹配(kb_search、kb_grep),因为 MCP 工具抵达时会带上提供它的服务器的命名空间,而那个前缀由部署决定。载荷形状属于工具,不属于命名。
Services consumed
无。本包在运行期不从 harness 引入任何东西。
Model Experience
None, as 本包不注册任何工具、提示词、schema 或上下文:它读的是模型已经看过的结果,产出的是给人看的界面所需的行。
KV Cache effect
无。这里不贡献提示词片段、不注册工具定义、也不注入上下文条目,因此不存在会因它而移动的复用边界。
Known Limitations and Deferred Work
- 文本可能在本包读到之前就已经被替换。
dsh-spill-policy在配置启用时,会把过大的、面向模型的结果换成预览加定位符,完整文本随后存在 spill 制品里。若调用方从一个已被 spill 的结果的模型可见文本里读引用,会什么都读不到;它必须去读那个制品,或者在 spill 之前先解析。参考产品有同一个隐患,而且更严重——它在每次渲染时从一段 200 字符的预览里重新推导引用——这也正是本包被设计成「调用方可以在仍然握有完整文本的那一刻调用」的一个函数的原因。 - 不读
kb_fetch。 它回的是一份文档而不是引用列表,目前也没有界面向它要出处。 - 没有知识库名称。 这些工具回报文档,但不回报它属于哪个知识库;需要名称的界面得自己用
kbId去解析。
