ryanking3/nullcontext-runner
GitHub: ryanking3/nullcontext-runner
本地优先的安全推理运行时,为 llama.cpp 的 LLM 会话提供显式生命周期管理、审计报告和隐私清理验证。
Stars: 4 | Forks: 0
# NullContext
NullContext 是一个本地优先的安全推理环境,用于运行具有显式生命周期可见性、审计报告、可配置持久化行为以及基于本地浏览器运行时检查的 LLM 会话。
该项目目前主要针对使用以下技术的本地推理工作流:
- Rust
- llama.cpp
- Axum
- React
- 本地 GGUF 模型
- CUDA 加速(Windows)
- 基于浏览器的 localhost UI
NullContext 的设计理念是,本地推理系统应该公开:
- 存储了什么
- 保留了什么
- 删除了什么
- 执行了哪些清理操作
- 还存在哪些残余风险
而不是将本地推理视为一个不透明的黑盒。
## 当前架构
```
Browser UI
↓
Local Axum API server
↓
NullContext runtime
↓
llama.cpp
↓
Local GGUF model
```
整个技术栈在本地运行。
不需要云端推理。
## 当前功能
### 本地推理运行时
- llama.cpp 后端集成
- 本地 GGUF 模型支持
- 基于 stdin 的 prompt 输入
- 单次流式推理
- 单次基于语料的检索
- 运行时复用的活跃聊天会话
- 活跃聊天基于语料的检索
- 可配置的推理模式
- 持久和临时会话
- 可配置的 token 限制
- 可配置的 GPU 卸载
- Windows CUDA 支持
- 本地 HTTP API 服务器
### 安全 / 隐私功能
- 显式工作区生命周期管理
- 递归产物扫描
- 针对 `llama-server` 的 Windows 直接进程内存扫描原型
- 运行时和关闭后的 prompt/response 标记扫描
- 启动失败时的清理标记扫描
- 当运行时 PID 仍可观察时的清理阶段进程扫描捕获
- 重复的受控金丝雀助手验证运行
- 针对清理重启/流失探测的助手阶段专用金丝雀扫描
- 跨会话的内存验证历史记录
- 平台能力矩阵报告
- Rust 拥有的缓冲区清零
- RAM 清零验证
- llama 运行时暴露报告
- 实时 llama 运行时 RAM/VRAM 使用快照
- 关闭后的 llama 运行时检查
- 基于 macOS vmmap 的 RAM 检查和驻留区域增量分析
- 基于 Windows PowerShell 的进程内存观察
- NVIDIA `nvidia-smi` 计算应用和 `pmon` 回退检查路径
- allocator / KV 生命周期能力报告
- 运行时信号和清理信号契约报告
- 清理阶段 VRAM 比较和内存验证评分卡
- 重复的清理阶段趋势汇总
- 清理阶段建议证据类别
- 重复的验证发布门控指导
- Windows/NVIDIA GPU 来源、信任边界、证据层级、声明边界和上下文可见性报告
- 审计操作跟踪
- 清理操作报告
- 结构化隐私报告
- 可配置的保留行为
- 针对保留会话的手动清理和协调操作
- 计划的保留期到期清理
- 针对孤立会话/工作区的启动生命周期协调
- 生命周期感知的隐私报告
- 语料库生命周期清理和协调操作
- 语料库保留策略控制
- 生命周期变更后的语料库报告同步
- 针对活跃聊天的显式 End + Sanitize 工作流
- 针对长生命周期运行时的残余风险报告
### 会话注册表
持久化会话在本地进行索引:
```
~/.nullcontext/index.json
```
注册表跟踪:
- 会话 ID
- 时间戳
- 安全模式
- 选定的模型 ID 和名称
- 工作区路径
- 报告路径
- 清理状态
- 生命周期状态
- 保留策略和截止时间
- 产物计数
### 模型注册表
本地模型注册表支持:
- 默认模型选择
- 命名的模型 ID
- 每个模型的 token、GPU、模板和上下文默认值
- 在浏览器 UI 和 API 中切换模型
- 模型文件验证
- llama-server 运行时就绪状态报告
### 语料库注册表
本地语料库注册表支持:
- txt、markdown 和 pdf 摄入
- 针对稀疏页面的混合 pdf 提取与 OCR
- 浏览器原生的文件上传摄入,支持拖放和上传进度
- 持久和临时语料库
- 本地分块和嵌入产物
- 通过 API 直接查询语料库
- 单次和活跃聊天基础支撑
- 语料库生命周期清理、协调和保留控制
- 针对孤立语料库的启动生命周期协调
- 带有生命周期元数据的保留摄入报告
- 结构化语料库报告查看,可选的原始 JSON 检查
### 本地 Web UI
当前的浏览器 UI 支持:
- 单次 prompt 执行
- 针对基础支撑运行的单次语料库选择
- 活跃聊天会话的启动、流式传输、停止和结束
- 当模型/语料库/配置状态无效时,在网络启动前的活跃聊天预检阻断
- 针对基础支撑会话的活跃聊天语料库绑定
- 针对过期或已清理的语料库绑定的显式语料库分离操作
- 专用的模型注册表浏览器
- 专用的语料库注册表浏览器
- 基于路径的语料库摄入
- 浏览器原生的语料库文件上传摄入
- 聊天机器人风格的编辑器,用于上传 txt/md/pdf 基础支撑语料库
- 在语料库浏览器内查看结构化语料库报告
- 单次和活跃聊天的模型选择
- 模型默认值与手动覆盖控制
- 可选择的活跃聊天 prompt 模板
- 可配置的活跃聊天上下文 token 预算和轮次限制
- 运行时生命周期可视化
- 审计操作检查
- 隐私报告检查
- 平台能力矩阵检查
- 内存验证历史记录和清理阶段证据检查
- 运行时日志检查
- 持久化会话浏览
- 深色/浅色终端风格 UI
- 活跃聊天运行时处于活动状态时的卸载前警告
- 纯本地 API 交互
- 仅限 localhost 执行
## 安全模式
### 安全
默认模式。
特征:
- 临时工作区
- 自动清理
- 审计报告
- 产物扫描
- 缓冲区清理
- 建议使用 stdin prompt 摄入
### 标准
允许持久会话。
特征:
- 保留的工作区
- 保留的报告
- 会话注册表索引
### air-gapped
保留用于未来更严格的运行时策略。
目前的行为类似于 secure 模式。
## 运行时生命周期
典型的会话生命周期:
```
1. Prompt ingestion
2. Runtime launch
3. Local inference
4. Artifact scan
5. Audit operation emission
6. Buffer sanitization
7. Workspace cleanup or retention
8. Privacy report generation
9. Session indexing (persistent only)
```
### 单次模式
一次 prompt 创建完整的生命周期:
```
create session
→ launch llama-server
→ stream completion
→ shutdown runtime
→ scan artifacts
→ sanitize Rust-owned buffers
→ cleanup or retain workspace
→ emit privacy report
```
### 活跃聊天模式
一个聊天会话会创建一个长生命周期的运行时:
```
start active session
→ launch llama-server once
→ send multiple messages through same runtime
→ keep chat context in memory until session end
→ end session explicitly
→ shutdown runtime
→ zeroize Rust-owned chat history
→ scan artifacts
→ cleanup or retain workspace
→ emit privacy report
```
活跃聊天使用:
- 感知模型的 prompt 模板
- 有界的近期上下文管理
- 当较旧的轮次从 prompt 窗口中被丢弃时的审计可见性
- 每一轮可选的绑定语料库检索
## 当前 API
本地 API 服务器目前公开:
### 健康
```
GET /api/health
```
### 运行 Session
```
POST /api/run
```
运行一个非流式的单次会话并返回收集到的 stdout/stderr。
### 流式运行 Session
```
POST /api/run/stream
```
请求体示例:
```
{
"prompt": "Explain secure local inference.",
"mode": "secure",
"persistent": false,
"model_id": "",
"corpus_id": "",
"chat_template": "auto",
"chat_context_token_budget": 2048,
"chat_context_turn_limit": 12
}
```
当提供 `corpus_id` 时,`/api/run/stream` 会首先检索本地语料库上下文,并在推理前注入一个基础支撑的 prompt 包装器。
### Corpus Registry
```
GET /api/corpora
POST /api/corpora
GET /api/corpora/:corpus_id/report
POST /api/corpora/:corpus_id/query
POST /api/corpora/:corpus_id/retention
POST /api/corpora/:corpus_id/cleanup
POST /api/corpora/:corpus_id/reconcile
```
摄入请求体示例:
```
{
"name": "incident-briefing",
"paths": [
"/Users/you/docs/briefing.pdf",
"/Users/you/docs/notes"
],
"persistent": true,
"ocr_enabled": true
}
```
### Model Registry
```
GET /api/models
```
### 启动 Active Chat Session
```
POST /api/chat/start
```
请求体示例:
```
{
"mode": "secure",
"persistent": false,
"model_id": "",
"corpus_id": "",
"chat_template": "auto",
"chat_context_token_budget": 2048,
"chat_context_turn_limit": 12
}
```
### Active Chat 状态
```
GET /api/chat/:session_id/status
```
### 流式传输 Active Chat Message
```
POST /api/chat/:session_id/message/stream
```
请求体示例:
```
{
"prompt": "Explain secure local inference in 2 short bullet points."
}
```
### Active Chat Template 和 Context 字段
- `model_id`
按 ID 选择已注册的模型
- `corpus_id`
按 ID 绑定已注册的本地语料库以进行基础支撑检索
- `chat_template`
可选值:`auto`、`generic`、`chatml`、`llama3-instruct`
- `chat_context_token_budget`
用于近期活跃聊天上下文选择的近似 token 预算
- `chat_context_turn_limit`
在活跃聊天上下文中包含的最大近期先前轮次数
当 `chat_template` 为 `auto` 时,NullContext 会从选定的模型路径中解析模板。
如果 UI 正在使用模型默认值,它会省略这些覆盖字段,并让选定的模型驱动有效的模板和上下文设置。
如果在启动活跃聊天时提供了 `corpus_id`,NullContext 会绑定该语料库,以便在会话结束之前的每一轮后续对话中进行检索。
### 结束 Active Chat Session
```
POST /api/chat/:session_id/end
```
### 取消 Active Chat Generation
```
POST /api/chat/:session_id/cancel
```
### 列出 Session
```
GET /api/sessions
```
### 更新 Session 保留策略
```
POST /api/sessions/:session_id/retention
```
### 清理已保留的 Session
```
POST /api/sessions/:session_id/cleanup
```
### 同步 Session 生命周期状态
```
POST /api/sessions/:session_id/reconcile
```
### 显示报告
```
GET /api/reports/:session_id
```
### 流式 Event Types
流式传输 endpoint 发出包含 JSON 事件的 SSE 风格 `data:` 块。当前的事件类型包括:
- `runtime`
- `audit`
- `model`
- `report`
- `stderr`
- `error`
- `complete`
## 当前限制
NullContext 目前不保证:
- VRAM 清理
- llama.cpp 内部 allocator 清理
- OS 交换空间清理
- shell 历史记录清理
- 跨进程内存清理
- CUDA 内存清理
- Rust 拥有的缓冲区之外的取证内存清除
- 完美的 PDF 布局重建
- 每一个扫描型或纯图像 PDF 的 OCR 准确性
活跃聊天还会保持一个长生命周期的 llama.cpp 运行时和内存中的上下文处于活动状态,直到用户明确结束会话。
语料库摄入可以从许多 PDF 中恢复文本,包括通过 OCR 处理的扫描页面,但复杂的布局、表格和劣质扫描的提取效果可能仍然不完美。
NullContext 现在尽最大努力进行 llama 运行时检查,包括关闭路径报告、运行时信号契约报告、实时 RAM/VRAM 观察、关闭后验证、针对已配置标记的直接 Windows 进程内存扫描、重复的基于金丝雀的验证、清理阶段比较、macOS `vmmap` 检查(如果可用)以及 Windows/NVIDIA 回退观察路径。这些检查提高了可见性,但它们并不能证明 allocator 已清零或完整的 RAM/VRAM 清理。
清理阶段的建议现在可以区分当前的最佳阶段是由标记支持、清理信号支持、GPU/进程趋势支持,还是仍然受限,但该指导仍然是对比性的证据,而不是 allocator 或驱动程序清理的证明。
特别是在 Windows 上,PowerShell 进程指标、直接标记扫描覆盖范围和 NVIDIA 工具仍然可能不完整或依赖于驱动程序模式,尤其是在 WDDM 下的每进程 VRAM 可见性、CUDA-context 可见性以及 allocator 级别的 GPU 真实情况方面。
隐私报告有意披露了这些残余风险。
## 开发设置
### 环境要求
### Windows
- Rust
- Node.js
- pnpm
- Visual Studio Build Tools
- CUDA Toolkit
- llama.cpp
- 本地 GGUF 模型
### macOS
- Rust
- Node.js
- pnpm
- Xcode Command Line Tools
- llama.cpp
- 本地 GGUF 模型
## llama.cpp 设置
克隆:
```
git clone https://github.com/ggml-org/llama.cpp
```
### Windows CUDA 构建
从:
```
x64 Native Tools Command Prompt for VS
```
运行:
```
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release
```
预期二进制文件:
```
build/bin/Release/llama-server.exe
build/bin/Release/llama-cli.exe
```
### macOS 构建
```
cmake -B build
cmake --build build --config Release
```
## 配置
配置文件:
```
~/.nullcontext/config.toml
```
模型注册表配置示例:
```
llama_path = "C:\\dev\\llama.cpp\\build\\bin\\Release\\llama-server.exe"
default_model = "qwen-small"
default_mode = "secure"
max_tokens = 128
gpu_layers = 999
chat_template = "auto"
chat_context_token_budget = 2048
chat_context_turn_limit = 12
[[models]]
id = "qwen-small"
name = "Qwen 2.5 0.5B Instruct"
model_path = "C:\\models\\qwen2.5-0.5b\\qwen2.5-0.5b-instruct-q4_k_m.gguf"
max_tokens = 128
gpu_layers = 999
chat_template = "chatml"
chat_context_token_budget = 2048
chat_context_turn_limit = 12
[[models]]
id = "llama3-8b"
name = "Llama 3 8B Instruct"
model_path = "C:\\models\\llama3-8b\\meta-llama-3-8b-instruct-q4_k_m.gguf"
max_tokens = 256
gpu_layers = 999
chat_template = "llama3-instruct"
chat_context_token_budget = 3072
chat_context_turn_limit = 16
```
### 注意事项
```
gpu_layers = 999
```
表示:
```
offload as many layers as possible onto the GPU
```
额外的活跃聊天选项:
```
chat_template = "auto"
chat_context_token_budget = 2048
chat_context_turn_limit = 12
```
模板选项:
- `auto`
- `generic`
- `chatml`
- `llama3-instruct`
`chat_context_token_budget` 和 `chat_context_turn_limit` 都必须大于 `0`。
仅使用 `model_path` 的旧版单模型配置仍然受支持。当不存在 `[[models]]` 数组时,NullContext 会自动合成一个默认模型条目。
### 工作区路径
NullContext 会话工作区是在系统临时目录下的 `nullcontext` 子目录中创建的。
典型示例:
```
macOS/Linux: $TMPDIR/nullcontext or /tmp/nullcontext
Windows: %TEMP%\nullcontext
```
确切的路径是在运行时使用 Rust 的 `std::env::temp_dir()` 确定的。
## 后端运行时
构建 Rust 运行时:
```
cargo build
```
直接运行:
```
echo "Explain secure local inference." | cargo run -- --stdin
```
持久会话示例:
```
echo "Explain persistent audit trails." | cargo run -- --mode standard --persistent --stdin
```
## 本地 API 服务器
启动本地 API 服务器:
```
cargo run -- serve
```
默认地址:
```
http://127.0.0.1:3333
```
健康检查:
```
http://127.0.0.1:3333/api/health
```
流式单次执行示例:
活跃聊天示例:
```
curl -X POST http://127.0.0.1:3333/api/chat/start \
-H "Content-Type: application/json" \
-d '{"mode":"secure","persistent":false,"model_id":"","corpus_id":""}'
```
对于 Windows/NVIDIA 验证,请在活跃聊天会话期间捕获实时的 `llama-server` PID,并将 NullContext 的报告与主机工具进行比较:
```
Get-Process -Id
Get-CimInstance Win32_Process -Filter "ProcessId = "
nvidia-smi
nvidia-smi --query-compute-apps=pid,used_gpu_memory --format=csv,noheader,nounits
nvidia-smi pmon -c 1
```
## Web UI
从:
```
apps/web
```
安装依赖项:
```
pnpm install
```
运行开发服务器:
```
pnpm dev
```
默认 UI 地址:
```
http://localhost:5173
```
活跃聊天会话配置面板允许你:
- 浏览已注册的模型目录
- 浏览已注册的语料库目录
- 在启动会话之前按 ID/名称选择模型
- 为基于基础支撑的单次运行或下一个活跃聊天会话选择本地语料库
- 为模板/上下文设置使用每个模型的默认值或手动覆盖
- 选择一个 prompt 模板或从模型路径中自动检测它
- 设置有界的近期上下文 token 预算
- 设置有界的近期上下文轮次限制
语料库浏览器还允许你:
- 从绝对的本地文件和目录路径摄入语料库
- 从浏览器选择的本地文件中通过拖放摄入语料库
- 直接从聊天编辑器的 `+` 菜单摄入基础支撑文件
- 检查语料库生命周期状态和保留的产物路径
- 加载保留的语料库报告
- 执行语料库协调、清理和保留操作
模型浏览器还会显示:
- 每个模型文件路径是否可启动
- 配置的 `llama-server` 路径是否就绪
- 确切的模型路径、模板默认值、token 限制、GPU 设置和上下文默认值
会话开始后,运行时横幅会显示选定的模型、任何已绑定的语料库、解析出的模板以及活动的上下文策略。
## 会话命令
列出持久会话:
```
cargo run -- --list-sessions
```
显示报告:
```
cargo run -- --show-report
```
## 当前开发重点
目前的开发重点是:
- 结构化运行时流
- Server-Sent Events
- 本地语料库摄入和检索生命周期管理
- 流式 token 输出
- 流式审计事件
- 更强大的内存清理原语
- 直接进程内存证据
- allocator / KV 生命周期证据
- VRAM 检查与分析
- llama 运行时 RAM/VRAM 检查和证据驱动的清理报告
- 重复的验证和清理阶段证据汇总
- Windows/NVIDIA 运行时检查验证
- 取证产物可见性
- Linux 原生的底层内存工作
## 项目状态
NullContext 目前正处于活跃的早期开发阶段。
该项目功能正常,支持:
- 本地推理
- 本地浏览器 UI
- 本地 API 执行
- 单次流式传输
- 单次基础支撑检索
- 活跃聊天会话
- 活跃聊天基础支撑检索
- 生成停止控制
- 显式的活跃聊天取消
- 持久化会话
- 生命周期策略引擎
- 结构化的模型注册表和模型切换
- 带有混合 OCR 提取的 txt/md/pdf 语料库摄入
- 浏览器原生的语料库文件上传
- 聊天机器人风格的编辑器,用于上传基础支撑语料库
- 语料库生命周期控制
- 产物跟踪
- 清理报告
- 审计可视化
- llama 运行时检查报告
- 内存验证评分卡和历史记录
- 平台能力矩阵报告
然而,该项目目前尚不应被视为一个经过强化的安全推理环境。
目前的重点是在尝试实现更强的底层内存保证之前,构建透明的运行时可见性和显式的生命周期控制。
标签:Vectored Exception Handling, 可视化界面, 实时告警, 通知系统