Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Web 界面

drsg serve 提供一个内嵌于二进制的单页仪表盘,供你在浏览器中检视与操作数据库。它 通过 HTTP 使用与各 SDK 相同的 JSON-RPC 接口,并通过一条 WebSocket 获取实时更新。由于 是内嵌的,它不发起任何外部网络请求:所有资源均由同一来源(origin)提供,所有渲染 都在本地完成。

访问与鉴权

打开 drsg serve 报告的地址(默认 http://127.0.0.1:7700)。在回环地址上无需任何 设置:未配置令牌时,同源来源检查即授权本地界面;配置了 DRSG_TOKEN 时,服务端会把 令牌写入提供给回环浏览器的页面(以应用读取的 <meta> 元素形式,绝不以脚本形式), 界面再以 Bearer 凭据出示。无论如何,跨源请求都会被拒绝。

若监听其他地址(如 --addr 0.0.0.0:7700,容器镜像即如此),服务端必须配置令牌才会 启动,且绝不把令牌写入页面——因为该页面会发给任何能访问该端口的人。服务端第一次 回答“未授权”时会弹出输入框,把 DRSG_TOKEN 粘贴进去即可;它保存在标签页的会话存储 中(关闭标签页即消失),随每次调用以 Authorization: Bearer 发送,在 WebSocket 上则以 ?token= 发送(浏览器套接字唯一能携带的形式)。此时仪表盘自身的来源也须列入 allowed_origins / DRSG_ALLOWED_ORIGINS,因为它不是回环地址。

同一台机器上的反向代理(或端口转发)之后的回环监听,是网络部署而非本地部署:互联网上的 每个客户端都以回环对端地址到达服务端。凡能辨别之处,服务端都按网络部署对待——凡请求经代理 转发(带 Forwarded、X-Forwarded-*、X-Real-IP、Via)或寻址到非本机名称(Host)的 页面,绝不写入令牌;把代理的来源列入 allowed_origins(仪表盘在代理之后要能工作就必须如此) 会关闭所有页面的令牌写入,并要求启动时必须配置令牌(非回环的允许来源也从不算作本地界面)。 不加任何头、且保持回环 Host 的代理无法与本地浏览器区分,此时请设 DRSG_PAGE_TOKEN=0 ([server] page_token = false),页面一律不带令牌;仪表盘会像在其他地址上一样索要令牌。 只要监听前面有任何东西,就请配置令牌。

每个响应都带有 Content-Security-Policy,脚本与样式只能从服务端自身加载;仪表盘按此 策略构建,前置反向代理应原样透传而非替换它。

错误的令牌最多可出示五次;此后服务端对该客户端带令牌的请求回答 429 Too Many Requests,并附带 Retry-After,每再失败一次等待时间翻倍,最长五分钟,直到出示正确 令牌为止。不带令牌的请求既不计入也不拦截,因此无令牌的本地仪表盘不会触发它,页面与 /health 对其他人也照常应答。客户端以连接地址区分;在同一台机器的反向代理之后,则以代理 在 X-Forwarded-For 中给出的地址区分,因此一个乱猜者不会把代理后的所有人一起锁住。 一个 JSON-RPC 批次最多 64 个请求。

界面中凡是需要选择提供方的地方——语义搜索、自然语言查询、AIgest——只提供预设 (openai、deepseek、qwen、ollama),API 也只接受这些预设,或服务端配置的那一个 提供方([server] embed_provider)。base URL 在线上会被拒绝:服务端会以自己的网络、 替持有凭据的任何人去调用它;想用本地或自建端点的运维者应在服务端配置。会描述服务端 自身磁盘或其提供方回复的错误,只以类别加引用号返回(storage error (ref 00002a)), 细节在服务端日志中按该引用号可查。

界面包含三个视图,从顶部选择:Dashboard、Explore 与 AIgest。

Dashboard(仪表盘)

Dashboard 呈现数据库的健康状况与平面管理。

  • 健康状况。 这里展示一组统计数据:平面、节点、边、标签、边类型、已声明索引、 平均度、提交数(提交序号)与磁盘占用。它们通过 WebSocket 实时推送,会随数据库变化 而更新,一个连接指示器显示实时/离线状态。
  • 平面卡片。 每个平面一张卡片,显示其名称、描述与节点/边计数。卡片可选定该平面 (作为全局上下文)、将其导出为 JSONL(一个可被命令行 import 读回的下载),或在 一个键入确认的对话框后删除它。一张"新建平面"卡片用于创建平面。
  • 来源。 卡片会说明其平面来自何处、又可以询问谁。来自挂载数据库的平面带有该挂载 的名称;附着了其他平面(plane.attach)的平面,每一个附着带一个标签,位于另一个 实例上的标注为 remote,其 URL 见悬浮提示。既非挂载、也未附着任何平面的卡片不显示 这一行。
  • 已挂载的数据库。 当本进程在自有平面之外还服务其他库时(db.mount),平面卡片 下方会列出每一个:名称、打开它的路径、它贡献了多少平面,以及这些平面是否以该挂载名 为前缀——只有当两个挂载提供了同名平面时才会如此。其中每个平面都是一个可选定它的 按钮。没有任何东西被复制,也没有任何东西被重新消化;这些平面保留各自的名称,并出现 在上方的卡片之中。该小节会说明挂载被限定在哪个目录之下,未挂载任何库时则不出现。

Explore(浏览)

Explore 是一块由选项卡工具栏驱动的交互式图画布。选中一个节点或边会打开一个检视器, 显示其标签/类型与属性(向量被折叠在一个控件之后,而非直接打印);双击一个节点会 扩展其邻域;从一个节点拖拽到另一个节点会打开新建边对话框,并预填两个端点。

阅读一张稠密的图

任何规模的平面都超出一块画布一次所能呈现的范围,因此 Explore 先画出骨架,其余 的部分由你来索取。

  • 按重要性取种子。 初始视图取的是连接最多的 40 个节点及它们之间的边,而不是 扫描到的最先 40 个,为的是给出一个可读的形状,而非一份任意的样本。Show more(显示更多) 会将其扩展到 100、200、500。排序依据是度数;graph.seed 也提供 PageRank,但 PageRank 会把权重汇聚到汇点上,以至于一个中心节点的得分 可能低于它自己的邻居。
  • 图例即过滤器。 点击一个标签即可隐藏该类别,再次点击则恢复。这里做的是隐藏 而不是淡出:你关掉的类别,就不再属于当前要看的问题。
  • 拥挤的中心节点会被折叠。 某个节点的叶节点(只与它相连、别无他连的邻居) 一旦超过二十个,就会折叠成一个标注数量的圆点,点击即可展开。没有任何内容被 丢弃,你已经选中的叶节点也绝不会被折叠。
  • 扇形会被分组。 在该阈值以下,一个中心节点的叶节点会按标签成弧段排布在其四周, 于是环形读起来是若干区域,而非一片模糊。
  • 重要性会撑开布局。 与连接紧密的节点相接的边会被排布得更长,好让繁忙的邻域有 余地被看清。
  • 大图的布局在主线程之外运行。 超过 400 个节点时(例如在真实的平面上点 Show all),力导向布局会在 Web Worker 中运行有限的几秒钟,页面保持响应; 图形在视野中逐渐收敛,运行结束后定形。
  • Expand one hop 是分批发出的。 扩展边缘每次点击最多取 300 个节点,以每批 64 个的 JSON-RPC 批量请求发送,并说明有多少留给下一次点击、有多少调用失败。
  • 选中即聚焦。 选中项及其直接邻居保持全强度,再外一圈变暗,更远处则隐去并舍弃 标签。选中一条边会同时聚焦它的两个端点,因为一条边本身就是关于两个事物的 陈述。

节点大小反映其连接的紧密程度(并计入折叠在它之下的部分),图例则将颜色映射到标签。

工具栏选项卡:

  • Filters / Operations —— 从某个标签(或整个平面)为画布播种。
  • Algorithms —— 运行 PageRank、连通分量、最短路径或 Louvain,并将结果叠加到当前 图上(得分体现为节点大小/颜色,分量/社区体现为颜色分组)。
  • Hybrid —— 融合的向量 + 关键词 + 图邻近度检索,其各路信号与标签在栏中选择。
  • Ask —— 一个自然语言问题;生成的计划会被展示(带一个复制控件),其连通结果被 绘制出来。
  • Time-travel —— 一个覆盖提交历史的滑块(见下文)。
  • Live —— 变更流(见下文)。

Query(查询)

与 Dashboard、Explore 并列的独立视图,也是全应用唯一书写查询的地方:Explore 负责把 图画出来,这个视图负责向它提问并阅读答案(见第 4 章)。

编辑器是多行的,因为值得占一个页面的查询很少只有一行:⌘/Ctrl + Enter 运行, 回车即换行,Tab 接受键入时给出的关键词补全幽灵提示。编辑器下方给出若干示例查询作为 起点,输入的文本也会在刷新后保留。

结果呈现为查询所要的形状:

  • 投影(RETURN n.file, count(*) AS n)以表格返回,并给出行数、列数与耗时, 还有一个复制控件,把整张表以制表符分隔的文本放进剪贴板——含表头,可直接粘进 电子表格;
  • 返回完整记录的查询(RETURN n)按键、标签以及放得下的属性逐条列出;
  • 写操作报告其变更计数。

无法编译的查询会显示解析器自己的消息——它指名的是语法构造,而不是一个字符位置。

搜索

顶部带有一个针对当前平面的快速搜索,有两种模式:

  • 文本 —— 在键、标签与字符串属性上进行子串匹配。
  • 语义 —— 按嵌入相似度排序(带一个嵌入提供方选择器)。

选中一个结果会在 Explore 中聚焦到该节点或边。搜索同样遵从时间旅行游标:在钉住某个 历史提交后,它搜索图在该提交时当时的样子。

时间旅行

在原生后端的服务上,Explore 的 Time-travel 选项卡会探测可查询窗口 (plane.history),并在其可用时呈现一个覆盖提交序号的滑块,其最新端带有一个 Live 控件。向后拖动会将图重绘为该提交时的样子;播种与节点扩展读取历史快照。画布上 的一个标记在所有选项卡上都指示所钉住的提交,关闭后视图会恢复为实时。顶部搜索反映 同一个游标。在非原生后端上,该选项卡不出现。

滑块覆盖的是保留的窗口,而不是有史以来的每一次提交:plane.history 从 [server] retain_commits 保留的下限开始(省略该键时为 20;设 retain_commits = 0 则不限),读数会显示这个 窗口有多少次提交,db.stats 也以 retain_commits 报告该设置。需要更深的历史请提前 调高——越过下限的版本会在压缩时回收,之后就无法再访问。

Wires(线路)

HTTP 路由是解析器唯一无法转化为边的引用:处理端与调用端往往位于不同的语言、不同的 仓库,而它们之间只有一个字符串。因此预处理插件记录的是每一侧所声明的内容——处理端 记 serves,调用端记 requests,二者都写作 VERB /path/{},其中每个可变段都已归一 ——匹配则在有人询问时计算,而不被存储。

Explore 的 Wires 选项卡读取当前平面上的这些声明并将其配对。读取路由所用的选择与 wire 动词完全相同——只取声明了任一侧的节点,别无其他——因此任意规模的平面回答的都是 它的路由,而不是它自身。

  • matched 列出每个请求,以及每一个回应它的声明。无人回应的请求同样会被列出,并以 标记与底色示意,而不是被隐藏:它是更值得关注的一半,通常意味着其处理端位于这张图未 持有的仓库中。
  • requests 与 serves 各自单独列出一侧,每条路由同时给出归一后的形式与原文, 因而 /api/orders/{} 可以对照源码所写的 /api/orders/{id} 来读。
  • 动词过滤与路径子串过滤对三种视图均有效,且每个符号都是一个链接,点击会把该节点连同 其邻域置于画布中心。

两侧按动词与路径匹配:路径必须相等,动词相等或其中一侧为 *——未指明动词的一侧匹配 该路径上的所有动词。路径按精确字符串比较,因为插件已在建图时将其归一;没有插件记录的 路由,或写成 VERB path 之外形式的值,会被跳过而不是臆测。

Live 变更流

Explore 的 Live 选项卡通过 WebSocket 打开一个 plane.watch 订阅,并在提交落库时 将其流式呈现,最新者在前:每一条显示操作(创建 / 更新 / 删除,以颜色区分)、种类 (节点 / 边)、键或 id、标签,以及提交序号。该流可以暂停与恢复,并可收窄到单个标签; 选中一个节点变更会在画布中聚焦到它。

AIgest

AIgest 视图把一篇文档导入当前平面(见第 3 章):先上传或粘贴 文本——支持 Markdown、纯文本,以及 Word、PowerPoint、Excel、OpenDocument、RTF、 EPUB、CSV 与 PDF(这些格式会先转换为 Markdown,让模型看到的是标题、表格与列表, 而不是一堆散乱的字符);再选择对话与嵌入提供方;最后点 Preview(预览),模型 就会抽取实体与关系并给出方案。Write to graph(写入图) 会提交预览好的方案, 不会再产生任何额外的模型调用。可选项包括链接到既有节点(避免重复)与跳过嵌入 生成。

上传控件旁还有一行 URL:粘贴一个地址,可以再填一个主题,然后点 Fetch(抓取)。返回的不是直接填进文本框的正文,而是一份列表:该页面及它 链接到的页面,各自带着相关性得分、标题与大小,超过阈值的默认勾选。取消勾选某 一项,就能把它从文档中移除,且不会产生任何新的请求;一个可展开的折叠区会列出 未被保留的页面及其原因。在这份列表看起来没问题之前,不会有任何内容变成 token (第 3 章)。

Mode(模式) 决定抽取结果被清理到什么程度:coarse、fine(默认)或 super,这个选择会和提供方一起被记住,因为它是一项长期偏好,而不是每次运行都要 重新决定的临时选项。选中 super 时,控件正下方会给出提示:它会把每个实体连同 它的全部段落一并重读,输入 token 用量约为 15 倍。各模式各自换来什么,见 第 3 章。

设计

仪表盘会跟随主题明暗(即观看者的浅色/深色偏好),并且完全自包含:因为它是内嵌 且同源的,不依赖任何外部 CDN、字体或服务,除了所属服务自己的 API 与 WebSocket 之外,也不会发起任何其它请求。