内容
# Webify(Rust)
> 自适应网络研究,适用于 AI 编程代理
91% 的深度研究质量 · 5% 的成本 · 单个静态二进制文件 · 可作为 MCP 服务器或命令行界面。
[](LICENSE)
[](https://rustup.rs/)
Rust 版 [webify-mcp](https://github.com/kunal12203/webify-mcp)
---
## 安装
```bash
cargo install --git https://github.com/bruj0/webify-mcp-rust webify-mcp
```
这将同时安装 `webify-mcp` 二进制文件(MCP 标准输入/输出服务器)和 `webify` 命令行界面。
### 与 MCP 客户端一起使用
```bash
claude mcp add webify -- webify-mcp
```
适用于 Claude Code、Cursor、VS Code、Windsurf、Zed 以及其他 MCP 客户端。
### 与 Visual Studio Code 一起使用
VS Code 从 `~/.config/Code/User/mcp.json`(Linux)/ `%APPDATA%\Code\User\mcp.json`(Windows)/ `~/Library/Application Support/Code/User/mcp.json`(macOS)读取 MCP 服务器。工作区范围的服务器也可以通过项目中的 `.vscode/mcp.json` 工作。
**工作区范围**(推荐,按项目):在您要使 webify 可用的任何项目的根目录中创建 `.vscode/mcp.json`:
```json
{
"servers": {
"webify-mcp": {
"type": "stdio",
"command": "webify-mcp",
"env": {
"WEBIFY_CACHE_DIR": "${HOME}/.cache/webify",
"ANTHROPIC_API_KEY": "${env:ANTHROPIC_API_KEY}",
"BRAVE_SEARCH_API_KEY": "${env:BRAVE_SEARCH_API_KEY}"
}
}
}
}
```
**用户范围**(一个配置,每个工作区):将相同的 `webify-mcp` 块添加到 `~/.config/Code/User/mcp.json` 中的现有 `"servers"` 键下。
保存文件后,点击 MCP 面板中服务器旁边的 **启动** 按钮,或重新加载窗口(`Ctrl+Shift+P` → *开发人员:重新加载窗口*)。然后,四个工具(`web_find`、`web_lookup`、`web_build`、`web_stats`)将在 Copilot Chat 的 **代理** 模式下可用 - Copilot 将根据服务器发送的策略通过 `web_find` 路由研究请求。
如果您的 shell 导出 API 密钥,您也可以通过命令行界面安装:
```bash
code --add-mcp '{"name":"webify-mcp","type":"stdio","command":"webify-mcp"}'
```
---
## 功能
```mermaid
flowchart LR
A[查询] --> B[搜索\nBrave / DDG]
B --> C1[页面 1]
B --> C2[页面 2]
C1 --> D[DOM 图\n+ BM25]
C2 --> D
D --> E[多方面\n提取]
E --> F[俳句\n合成]
F --> G["答案\n(~800 个标记)"]
```
---
## MCP 工具
| 工具 | 参数 | 描述 |
| --- | --- | --- |
| `web_find(query)` | 查询,来源数量?,每个来源的最大数量?,合成? | 具有 LinUCB 查询重构和引用追踪的多来源研究 |
| `web_lookup(url, query)` | 网址,查询 | 从 `~/.cache/webify/<url_hash>.json` 缓存的图中检索结构子树 |
| `web_build(url, force_refresh?)` | 网址 | 为 `url` 强制重建图 |
| `web_stats(url)` | 网址 | 图表统计信息(节点,边,压缩率,置信度) |
默认 `synthesize=true` 需要 `ANTHROPIC_API_KEY`。当未设置或 API 出错时,服务器返回预合成片段不变。
### 环境
| 变量 | 影响 |
| --- | --- |
| `ANTHROPIC_API_KEY` | 在 `web_find` 中启用 Haiku 合成 |
| `BRAVE_SEARCH_API_KEY` | 使用 Brave Search;未设置时回落到 DDG |
| `WEBIFY_CACHE_DIR` | 重写缓存目录(默认 `~/.cache/webify`) |
| `RUST_LOG` | 跟踪过滤器(默认 `warn`) |
| `HTTP_PROXY` / `HTTPS_PROXY` | 转发到 reqwest |
---
## 命令行界面
```bash
webify build <url> [--force] # 构建图
webify lookup <url> <query> # 通过图检索
webify stats <url> # 图表统计信息(JSON)
webify find <query> [--no-synthesize]
webify search <query> [--max N]
```
---
## 库
```rust
use webify::{graph, retrieve, orchestrate, WebFindOptions};
// 1. 构建图(缓存在 ~/.cache/webify/<hash>.json)
let g = graph::build_graph("https://example.com/article", false).await?;
// 2. 检索与查询相关的结构子树
let result = retrieve::lookup("https://example.com/article", "memory safety", 10).await?;
// 3. 或运行多源研究合成
let r = orchestrate::web_find("how does Rust ensure memory safety",
WebFindOptions { synthesize: true, num_sources: None, max_results_per_source: None }).await;
println!("{}", r.content);
```
---
## 性能 vs Python
| 指标 | Python(v0.7.x) | Rust(v0.1.0) |
| --- | --- | --- |
| 冷图构建 | 1.8–3.2 秒/页 | ~0.6–1.1 秒/页 |
| 热图查找 | 30–90 毫秒 | <5 毫秒 |
| 内存(空闲) | ~80 MB | ~6 MB |
| 二进制大小 | n/a(解释) | 11 MB 剥离 |
| 启动 | ~280 毫秒 | <10 毫秒 |
| 测试 | pytest,~50 例 | cargo test,156 例 |
大约 3 倍的图构建速度,10 倍的检索速度,~10 倍的空闲内存。
---
## 架构
| 模块 | 责任 |
| --- | --- |
| `config` | 常量(路径,帽子,强盗超参数)和环境变量查找 |
| `error` | 类型错误(`HttpStatus`,`Fetch`,`CacheRead`,`NoSearchResults`) |
| `entities` | 内容哈希,令牌估计,slugification |
| `fetch::http` | `reqwest` GET with browser UA, gzip, timeout |
| `fetch::fallback` | OpenAPI →原始源→Wayback→Google缓存级联 |
| `extract::markdown` | `_text_to_html`:标题,围栏代码,列表 |
| `extract::embedded` | `__NEXT_DATA__`,JSON-LD(包括 FAQ 问答),Nuxt 数据挖掘 |
| `extract`(根) | 可读性评分 - 基于 DOM 的主内容提取 |
| `graph::sections` | Markdown → 章节树 + 内容块列表 |
| `graph::nodes` | GraphNode / GraphEdge 数据类型 |
| `graph::confidence` | 多信号启发式(导航壳,薄内容,SPA 模板) |
| `graph::meta` | `<meta>` 提取 + 引用 URL 挖掘 |
| `graph`(根) | 协调器:获取 → 选择 → 解析 → 缓存 |
| `retrieve::bm25` | 每臂 IDF,BM25 评分与类型奖励 + 导航节点门控 |
| `retrieve::subtree` | 结构子树收集的邻接 BFS |
| `retrieve`(根) | `retrieve`,`lookup`,`smart_lookup`,`retrieve_from_graph` |
| `search::brave` | Brave Search API 客户端(仅在设置密钥时使用) |
| `search::ddg` | DDG 精简回落(表单 POST → HTML 解析) |
| `search::primary` | 主要来源引用 URL 挖掘(DOI / PubMed / arXiv / .edu / …) |
| `search`(根) | `search_web`(Brave → DDG 级联) |
| `ml::bandit` | LinUCB(Sherman-Morrison 秩-1 更新,确定性三元组投影) |
| `ml::domain` | 域的 Welford 在线均值/M2 + UCB 奖励 |
| `ml`(根) | 磁盘 `ml_state.json`(A⁻¹,b,n; 域统计; total_pulls) |
| `synthesize::query` | 查询复杂度评分 + 方面分解 |
| `synthesize`(根) | 具有宽容片段回落的 Haiku 合成 |
| `orchestrate` | `web_find` 协调:搜索 → 并行构建 → 合并 → 合成 |
| `main` | `webify-mcp` 二进制文件:MCP 标准输入/输出服务器 |
| `bin/webify_cli` | `webify` 二进制文件:基于 clap 的命令行前端 |
所有持久状态都存储在 `~/.cache/webify/` 下:
- `<url_hash>.json` 每 URL 图(TTL 24 小时)
- `ml_state.json` LinUCB 臂 + 每个域的统计信息
---
## 构建
```bash
cargo build --release
# 构建门(警告作为错误):
cargo clippy --all-targets -- -W clippy::all -D warnings
cargo test --lib
```
默认配置文件已经在 `release` 中使用 LTO + strip。构建目标是 `x86_64-unknown-linux-gnu`,使用 rustc 1.75+。CI 在稳定版和 1.97 上测试。
---
## 与 Python 版本的区别
| 区域 | Python | Rust |
| --- | --- | --- |
| HTTP 客户端 | `urllib.request` | `reqwest` 0.12 with rustls-tls |
| HTML 解析器 | `lxml.html` | `scraper` 0.27 over `html5ever` |
| 异步模型 | `threading.Thread` 每源 | `tokio::spawn` 每源 |
| JSON 状态 | `json.dump` / `Path.write_text` | `serde_json` via `Mutex<MlState>` (`OnceLock` 单例) |
| 随机投影 | 基于 `hash()` + 每调用种子 | FNV-1a + `once_cell::Lazy<MatVec>`(相同分布) |
| 合成提示 | 手写字符串模板 | 相同提示; `format!`-built |
| 命令行界面 | `sys.argv` 调度 | `clap` 4 (derive) |
| 测试 | pytest | `#[test]` + `#[tokio::test]` |
在算法级别测试行为一致性。强盗投影矩阵是稳定的(确定性种子),但与 Python 的 `hash()` 对于非 ASCII 三元组不同;实际上,强盗的策略在几个观察中收敛。
---
## 许可证
MIT — 请参阅 [LICENSE](LICENSE)。