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

快速上手

本章介绍如何安装 Dr Strange(用发行版二进制或从源码构建均可)、如何初始化数据库、 在命令行中发起查询,以及如何运行服务,包括本地运行和以容器镜像方式部署。

环境准备

安装发行版二进制除 curl(Windows 上为 PowerShell)之外别无所需。以下准备仅适用于 其他方式:

  • 从源码构建:当前的 Rust 工具链(stable 通道),经 rustup 安装。
  • Web 仪表盘:bun 编译单页应用,以及可选的 just 作为任务运行器。
  • 容器工作流:Docker(Engine 24+;仅在自行构建镜像时才需要 BuildKit)。

构建通过 rustls/ring 链接 TLS,无需 OpenSSL 工具链。

安装发行版二进制

每个打了标签的发行版都会发布 Linux、macOS 与 Windows 的二进制。安装脚本会选取与宿主 平台匹配的归档包,校验其发布的 SHA-256,并将二进制置入 PATH。可安装的二进制有两个: 命令行工具与服务端 drsg,以及面向 LLM 智能体的 MCP 服务 drsg-mcp(第 8 章)。

Linux

# 命令行与服务端 —— drsg
$ curl -fsSL https://raw.githubusercontent.com/wangyingsm/dr-strange/master/scripts/install.sh | sh

# MCP 服务 —— drsg-mcp
$ curl -fsSL https://raw.githubusercontent.com/wangyingsm/dr-strange/master/scripts/install.sh | sh -s -- --bin drsg-mcp

macOS(脚本相同,Apple 芯片与 Intel 版本均有发布)

# 命令行与服务端 —— drsg
$ curl -fsSL https://raw.githubusercontent.com/wangyingsm/dr-strange/master/scripts/install.sh | sh

# MCP 服务 —— drsg-mcp
$ curl -fsSL https://raw.githubusercontent.com/wangyingsm/dr-strange/master/scripts/install.sh | sh -s -- --bin drsg-mcp

Windows,在 PowerShell 中执行。第二种写法将脚本作为代码块运行,因为以管道送入 iex 的脚本无法接收参数。

# 命令行与服务端 —— drsg
PS> irm https://raw.githubusercontent.com/wangyingsm/dr-strange/master/scripts/install.ps1 | iex

# MCP 服务 —— drsg-mcp
PS> & ([scriptblock]::Create((irm https://raw.githubusercontent.com/wangyingsm/dr-strange/master/scripts/install.ps1))) -Bin drsg-mcp

三个选项可调整安装行为,每个都有对应的环境变量,便于在非交互场景中使用:

选项(Windows)环境变量作用
--bin drsg-mcp(-Bin)DRSG_INSTALL_BIN安装哪个二进制——drsg(默认)、drsg-mcp 或 all
--version v1.1.0(-Version)DRSG_VERSION指定某个发行版本,而非最新版
--dir <path>(-Dir)DRSG_INSTALL_DIR安装目录

安装目录默认为 ~/.local/bin,Windows 上为 %LOCALAPPDATA%\Programs\drsg\bin,且脚本 会将该目录加入用户 PATH。在 Linux 与 macOS 上,若该目录尚不在 PATH 中,请将其写入 shell 配置:

$ export PATH="$HOME/.local/bin:$PATH"

升级

drsg update 用与安装脚本相同的方式解析最新发行版本——走 releases/latest 的 重定向,而不是对未认证调用者有速率限制的 API——再与当前运行的构建比较。无事可做 时它会明说并停下:

$ drsg update
drsg 2.27.1 is the latest release — nothing to do

确有新版本时,它会先打印即将执行的命令,然后变成它:进程被首次安装所用的同一 个安装脚本替换,因此退出码就是安装脚本自己的退出码,也不会留下一个父进程等在一个 刚刚被覆盖掉的二进制里。

$ drsg update
drsg 2.27.0 -> 2.27.1
$ curl -fsSL https://raw.githubusercontent.com/wangyingsm/dr-strange/v2.27.1/scripts/install.sh | sh -s -- --bin 'drsg' --version 'v2.27.1' --dir '/home/me/.local/bin'
Dr Strange v2.27.1 (x86_64-unknown-linux-gnu)
  downloading dr-strange-v2.27.1-x86_64-unknown-linux-gnu.tar.gz
  checksum verified
  installed /home/me/.local/bin/drsg

两个阶段都要穿过网络,也都遵循代理设置:版本检查是 drsg 自己发出的请求(参见 在 HTTP 代理之后工作),而它随后交棒的安装脚本由 curl 执行,读取的是同一批变量。在需要代理的网络里,最先失败的是版本检查,因此一次 够不到 GitHub 的 update 根本走不到安装脚本那一步。

它运行的安装脚本是随所装版本一起打了标签的那一份,而非 master 上的副本, 并把该版本作为 --version 一并传入:校验归档的脚本就是与它一同审阅、一同发布的 脚本,移动分支改变不了升级所执行的内容。两个安装脚本都要求归档的 .sha256 校验文件——缺失、格式不对或不匹配都是硬性失败,没有 sha256sum/shasum 可用 也是。--insecure-skip-checksum(PowerShell 中为 -InsecureSkipChecksum;两者 及 drsg update 均可用 DRSG_INSECURE_SKIP_CHECKSUM=1)会带着警告照装不误:它 是给不发布校验文件的镜像用的,名字已说明代价。

安装目录取的是正在运行的这个二进制所在的目录,而不是安装脚本的默认值——升级必须 替换 PATH 上的那一份,而不是在别处放一份更新的、让旧的继续被运行。若 drsg 装在无写权限的位置,用 --dir 覆盖。同一目录下若装有 drsg-mcp,它会随 drsg 一并更新,无需另行指定——两个二进制属于同一个发行版本,若智能体宿主拿上一版的 服务端去对接这一版的 drsg,没有任何东西会提醒它。不想这样时,用 --bin 指明 要更新的对象:drsg、drsg-mcp 或 all。

比最新发行版本更新的构建——来自源码,或来自最后一个标签之后的分支——会被告知 自己在前面,不会安装任何东西:update 从不回退。在 Windows 上则什么都不会运行, 因为正在运行的可执行文件被锁定、无法被覆盖;它转而打印出可在新终端里粘贴执行的 命令。

归档包及其校验和也可以从发行页 直接下载。安装脚本只是对同一批产物的便捷封装,两个脚本都放在 scripts/,可以在 使用前自行查看。

从源码构建

Dr Strange 是一个 Cargo 工作区。编译命令行二进制 drsg:

$ cargo build --release -p drsg

产物为 target/release/drsg。默认构建选用原生 LSM 存储引擎;遗留的 redb 后端仍可 通过特性开关启用。

Web 仪表盘由 web crate 的构建脚本在编译期嵌入二进制。若要嵌入编译好的仪表盘而非占位 页,请在构建二进制之前先编译单页应用:

$ just web-build          # bun install && vite build
$ cargo build --release -p drsg

面向 LLM 智能体的 MCP 服务(第 8 章)是一个独立的二进制 drsg-mcp:

$ cargo build --release -p dr-strange-mcp

产物为 target/release/drsg-mcp。将其置于 PATH 中,或在宿主配置里以绝对路径引用它。

磁盘布局

--db 参数用于选择数据库路径。在原生后端下,数据库是一个目录,里面存放着 预写日志(WAL)与有序的 SST 文件,此外还有两个存放检索索引的伴生文件:

graph.drsg/          数据库(WAL + SST 文件)
graph.drsg.hnsw      向量索引伴生文件
graph.drsg.bm25      关键词索引伴生文件

数据库在首次访问时创建,无需单独的初始化步骤。

创建一张图

先创建一个平面,再插入数据。openCypher 子集会编译为引擎直接执行的同一个逻辑计划:

$ drsg --db graph.drsg plane create social

$ drsg --db graph.drsg cypher --plane social \
    'CREATE (a:Person {name:"Ada"}),
            (b:Person {name:"Alan"}),
            (a)-[:KNOWS]->(b)'

查询结果:

$ drsg --db graph.drsg cypher --plane social \
    'MATCH (p:Person)-[:KNOWS]->(q:Person) RETURN q'

检视所得数据的形态与软 schema:

$ drsg --db graph.drsg stats
$ drsg --db graph.drsg catalog --plane social

向量索引与相似度检索

向量是普通的属性值。在某个 (标签, 属性) 对上声明索引,然后对其发起查询。对文本 查询做嵌入是在服务端执行的,因此进程环境中需要一个提供方密钥(例如 OPENAI_API_KEY)。针对字面量向量的查询则不需要任何提供方。

$ drsg --db graph.drsg index ensure Doc embedding --plane social

$ OPENAI_API_KEY=… drsg --db graph.drsg cypher --plane social \
    'SEARCH (d:Doc) ON embedding NEAR "a friendly greeting" TOPK 5 RETURN d'

由于结果均为图节点,可从其继续遍历——即第 1 章介绍的 GraphRAG 模式。

运行服务

$ drsg --db graph.drsg serve

此命令启动 JSON-RPC 2.0 接口、WebSocket 变更流以及内嵌的仪表盘,并报告所绑定的 地址(默认 127.0.0.1:7700)。

鉴权。 未配置令牌时,只有同源的浏览器界面可以调用接口。若要允许来自 SDK 或 curl 的程序化访问,请配置一个共享令牌,并以 Bearer 凭据形式携带:

$ DRSG_TOKEN=please-change-me drsg --db graph.drsg serve

监听回环以外的任何地址时令牌是必需的:未设置 DRSG_TOKEN(或 [server] token) 的 drsg serve --addr 0.0.0.0:7700 会拒绝启动,因为离开回环后同源检查不再构成任何 保护。在这类地址上,提供的仪表盘页面也不携带令牌——浏览器每个标签页会询问一次 (见 Web 界面一章),且仪表盘自身的来源须列入 allowed_origins。HTTP 上以 Authorization: Bearer <token> 发送令牌,WebSocket 升级请求也优先如此;/ws 上的 ?token= 仅为无法设置请求头的浏览器而设,查询字符串往往会被代理和浏览器记录。

连续五次以上出示错误令牌的对端会收到 429 与一个逐次加倍、至多五分钟的 Retry-After;一次正确的令牌即清除它。

经由 API 指定提供方时,名字只能是某个预设,或恰好是服务端已配置的那个 embed_provider;base URL 只从 CLI 与配置文件接受,绝不从请求接受。

配置文件

服务、日志与提供方设置也可以通过一个 TOML 配置文件提供,而非逐个使用命令行标志与 环境变量。配置文件的解析顺序为:--config <路径>,其次 $DRSG_CONFIG,再次为 当前目录下的 ./drsg.toml(若存在)。系统会拒绝未知的键。

[server]
addr = "0.0.0.0:7700"                       # 监听地址(命令行 --addr 覆盖此项)
token = "please-change-me"                  # 共享 API 令牌(→ DRSG_TOKEN);会成为进程环境变量,建议改为在启动环境中导出
max_concurrent = 1024                       # 并发请求上限
write_timeout_secs = 30                     # 一次写等待单写者槽位多久后以可重试的超时失败(0 表示一直等)
query_timeout_secs = 60                     # 一次请求内的查询可运行多久后以同样的方式停止(0 表示跑到结束)
retain_commits = 20                         # 时间旅行可回溯的提交数;更早的版本在压缩时回收(0 表示全部保留)。对每个打开数据库的 drsg 命令生效,不只是 serve
source_root = "/srv/myrepo"                 # grep/snippet 智能体工具读取的源码树(serve watch 会用 --dir 设置它)
mount_root = "/srv/repos"                   # `drsg mount` 可以从哪一个目录下打开数据库(默认:你的主目录);该目录内平面所记录的树也因此可被 grep/snippet 读取
allowed_origins = ["https://app.example.com"]  # 额外允许的浏览器来源
# 把 /mcp 放到域名后面:DRSG_ALLOWED_HOSTS=memory.example.com(环境变量;仅在设置了 token 时生效,见 MCP 一章)

[server.tls]                                # 存在此节 ⇒ 以 HTTPS 提供服务
cert = "/etc/drsg/cert.pem"                 # PEM 证书链
key  = "/etc/drsg/key.pem"                  # PEM 私钥

[logging]
dir = "/var/log/drsg"                       # 滚动日志文件所在目录

[llm]                                       # 提供方密钥,导出至进程环境
OPENAI_API_KEY = "sk-…"
DEEPSEEK_API_KEY = "…"
DASHSCOPE_API_KEY = "…"
DRSG_CHAT_OMIT = "temperature,max_tokens"   # 可选:对话请求中省略的字段,供拒绝它们的模型使用

[digest]                                    # 服务端 AIgest 调优
concurrency = 8                             # 并发进行的分块抽取调用数
chunk_chars = 4000                          # 目标分块大小
embed_provider = "openai"                   # search / write_nodes / watch 重新向量化所用的嵌入提供方
embed_model = "text-embedding-3-small"      # 其模型(各提供方均有默认值)
embed_key_env = "OPENAI_API_KEY"            # 存放密钥的环境变量
ignore_files = ["gitignore"]                # 由谁的忽略文件决定什么是源码;[] 表示两者都不读
tracked_only = false                        # 置为 true 则只读取 git 已跟踪的文件
code_only = false                           # 置为 true 则只读取处理器认领的文件(不含 Markdown/PDF)

[plugins]                                   # 预处理沙箱调优(均可省略)
fuel = 200000000000                         # 每次沙箱调用的指令预算(0 为不设限)
memory_mb = 3072                            # 每次调用的线性内存上限,MiB;按照 wasm32 标准,最高支持 4096
deadline_secs = 300                         # 单次调用的墙钟上限,秒(0 为不设限)
total_memory_mb = 6144                      # 进程内所有调用合计可持有的线性内存,MiB(0 为 memory_mb 的两倍)
hostcall_mb = 1024                          # 单次调用最多能从沙箱拷出的数据量,MiB(0 为 wasmtime 默认的 128)

[fetch]                                     # URL 导入(第 3 章)
enabled = true                              # 置为 false 则彻底拒绝 URL 抓取
max_pages = 10                              # 单次爬取保留的页数上限
max_depth = 3                               # 请求可申请的沿链接深度上限
concurrency = 4                             # 并发请求数
allow_private = []                          # 见下文——通常保持为空

[network]                                   # 本程序自身发出的请求走向何处
proxy = "http://127.0.0.1:7897"             # 也可为 socks5://…;被 ALL_PROXY / HTTPS_PROXY / HTTP_PROXY 覆盖
no_proxy = ".internal, 192.168.1.10"        # NO_PROXY 形式的绕行清单;被 NO_PROXY 覆盖

[fetch] 改变的是服务端的网络姿态,在启用其中任何一项之前值得先读一读。当 URL 导入处于开启状态(默认如此)时,客户端可以指定一个地址,而后由服务端去连接它。 服务端在网络中所处的位置通常更为特权,因此系统会拒绝一切不可路由的地址:回环地址、 RFC-1918 私有网段、链路本地地址(169.254.0.0/16,云实例元数据服务在此应答凭据) 等等。检查针对的是解析之后的地址而非主机名,并在每一次重定向跳转时重新执行; 一个内部携带 IPv4 地址的 IPv6 地址(v4-mapped、6to4、Teredo、NAT64 的 64:ff9b::/96)按那个 IPv4 地址判定。

allow_private 用来重新放行特定的 CIDR 网段(例如设为 ["10.0.0.0/8"],以便 读取内网 wiki)。它是上述规则唯一经过深思的例外,而不是关闭这层防护的开关: 暴露给不受信任客户端的服务端应当让它保持为空。若要完全拒绝 URL 抓取,请设置 enabled = false。

在 HTTP 代理之后工作

[network] 管辖的是 drsg 代表你发出的请求:drsg plugin install、 drsg update、drsg digest <url>、LLM 提供方,以及副本拉取快照。可以写在配置 文件里,也可以导出 ALL_PROXY、HTTPS_PROXY 或 HTTP_PROXY 中的任意一个(每个 同时按小写形式读取)。socks5:// 与 http:// 同样受支持。

其中有三条规则值得了解,因为每一条都是经过权衡的决定,而非偶然:

由调用方指定的 URL 绝不走代理。 JSON-RPC 上的 /digest/fetch 与 plugin.install 接受调用方给出的 URL,而上文所述的地址防护正是用来阻止这个 URL 指向服务端自身的回环地址或云元数据端点。代理会代替服务端解析名字并建立连接,防护 因此再无地址可供判断——它在代理之下无法生效,drsg 也不会假装它仍然生效。这些请求 保持直连并受防护约束。当配置了代理时,drsg serve 会在启动时说明这一点。

回环地址永不走代理,无论如何配置。本机模型服务——ollama 预设即 http://localhost:11434/v1——并不是任何人为访问外网而设置 https_proxy 时想要 改道的目标。除此之外的地址一律遵循配置;只有 localhost 与回环网段是自动的。

环境变量优先。 已设置的变量会覆盖配置文件,因此无需改动任何文件即可让单条命令 走另一个代理:

https_proxy=http://127.0.0.1:1080 drsg plugin install ts   # 仅本次运行
https_proxy= drsg plugin install ts                        # 已设置但为空:直连

no_proxy 接受 NO_PROXY 形式的清单,以逗号或空格分隔:精确主机名、.suffix 或 *.suffix 通配、IP 字面量、带端口的条目(example.com:8080),或用 * 表示 全部。不支持 CIDR 网段。环境中的 NO_PROXY 会替换配置文件中的清单,而不是与 之合并。

优先级是固定的:进程中已设置的环境变量始终优先于配置文件中对应的取值,而 --addr 标志覆盖 [server].addr。提供 [server.tls] 会将服务切换为 HTTPS。

只读副本(serve --follow)

以 --follow 启动的第二个 drsg serve 会以只读方式镜像一个正在运行的实例—— 用于在一组智能体之间扩展读取,而无需让每一次查询都挤过同一个进程:

$ drsg --db replica.drsg serve --addr 127.0.0.1:7701 \
    --follow ws://master-host:7700 --follow-token please-change-me

无论令牌是否有效,任何写入 RPC 都会被拒绝。启动时——以及此后每次断线重连 时——副本都会从主库的 /snapshot 端点拉取一份完整、一致的快照,随后跟随其 /ws/wal 获取后续提交;每次重连都会从零开始重新同步(arch/01 §9),因此 --db 必须指向一个空目录,或指向这个副本自己曾经使用过的目录(由一个 .drsg-follower 标记文件记录)——除此之外的目录会被拒绝,而不是被静默清空。

--follow-token(或 DRSG_FOLLOW_TOKEN)是提交给主库的凭据,与这个副本自己 用来约束其下游客户端的 DRSG_TOKEN 相互独立。当主库的地址不是回环地址时, --follow 应当指向 wss:// 而非 ws://——否则承载令牌的连接会以明文传输, 这与 [server.tls] 对入站连接的要求是同一个道理。

容器镜像

一个多架构镜像(linux/amd64 与 linux/arm64)已发布至 GitHub 容器镜像仓库 (GHCR)。直接拉取并运行,无需构建:

$ docker run -p 7700:7700 -v drsg-data:/data \
    -e DRSG_TOKEN=please-change-me \
    ghcr.io/wangyingsm/dr-strange:latest

docker run 会在首次使用时拉取镜像。若需可复现的部署,请以版本标签 ghcr.io/wangyingsm/dr-strange:1.0.2 替代 :latest。运行时镜像绑定到 0.0.0.0:7700,数据库存放在 /data 卷中(原生后端下数据库是一个目录,这个卷 负责把它持久化保存)。提供方密钥通过环境变量传入。

容器中 必须 设置 DRSG_TOKEN:镜像绑定 0.0.0.0,而 drsg serve 在没有令牌时 拒绝非回环绑定,不会把 API 与仪表盘开放给任何能连到该端口的人(容器会退出并 打印指出该变量的消息)。所有客户端都出示这个令牌——SDK 与 curl 作为 bearer, 仪表盘通过它的提示框。在 Docker 宿主机上以 http://localhost:7700 打开仪表盘 无需其他设置;浏览器若以其他名字访问容器——http://graph.example:7700——则该 来源必须列入 DRSG_ALLOWED_ORIGINS(逗号分隔,或 [server] allowed_origins): 离开回环后页面不再携带令牌,未列出的来源会被当作跨站请求拒绝。

对于持久化部署,docker-compose.yml 拉取同一镜像并定义了一个具名卷。它把 DRSG_TOKEN 标记为必填,未设置时 docker compose up 会带消息停下,而不是启动一个 随即退出的容器;DRSG_ALLOWED_ORIGINS 设置了就会透传:

$ DRSG_TOKEN=please-change-me docker compose up
$ DRSG_TOKEN=please-change-me DRSG_ALLOWED_ORIGINS=http://graph.example:7700 docker compose up

若想改为在本地构建镜像,仓库提供了一个多阶段 Dockerfile:它会编译仪表盘、将其 内嵌进二进制,并产出一个精简的运行时镜像:docker build -t dr-strange:latest .。

下一步

  • 第 3 章 —— AI 原生: 嵌入、混合检索、自然语言查询与文档导入。
  • 第 4 章 —— 查询语言: openCypher 子集及其底层的逻辑计划。
  • 按访问方式:第 6 章 —— SDK(应用代码)、第 7 章 —— 嵌入式命令行(运维)、 第 8 章 —— MCP(LLM 智能体)。