0xRyanlee/salva
GitHub: 0xRyanlee/salva
一个自托管的结构化发现智能运行时,面向 Agent/MCP/CLI/API 提供多轮检索、记忆复利与 n-ary 超图实体关系构建能力。
Stars: 1 | Forks: 0
# Salva Runtime
Salva 是一个自托管的 **Discovery Intelligence Runtime** — 面向 Agent、CLI 和 API 调用的结构化检索服务。
## 核心定位
- **Event-triggered**:由调用触发,非定时轮询
- **API-first**:REST API + MCP + CLI 三端整合
- **Agent-native**:MCP 是主要 agent 接口(Claude Code / Claude Desktop 直接接入)
- **Review-gated compounding**:content terms 可沉淀到隔离记忆,但默认不跨 run 读取;只有同 campaign 已提升的记忆会再次注入
## Pipeline 运作机制
```
trigger (agent / CLI / API call)
→ Intent 解析 + domain 路由
→ KeywordGraph 擴展(依 ExecutionContext 決定是否注入 memory seeds)
→ Multi-round multi-provider 檢索
→ 提取 → BM25 去重 → 評分
→ content_terms 提取 → 沉澱進 memory
→ 輸出 entities + relations + telemetry
```
### 记忆与复利(B1+B2)
```
Round N 結果片段
→ _extract_content_terms() [B1: controller.py]
→ telemetry.metadata["content_terms"]
→ content_nodes_json 持久化 [B2: persistence/runs.py]
↓
後續 run(僅 campaign_promoted / campaign_all / global_legacy)
→ seed_from_memory() 讀取允許範圍內的 content_nodes
→ 注入圖中,擴展查詢範圍
```
默认值是 `read_scope=none`、`write_mode=quarantine`。单次调用内的多轮
KeywordGraph 仍在内存中运作,不需要在项目根目录建立 cache。
### 执行与数据隔离
```
{
"execution": {
"campaign_id": "naturehike-dach-2026",
"continuation_id": "channel-map-r1",
"persistence": "audit",
"memory": {
"read_scope": "campaign_promoted",
"write_mode": "quarantine"
}
}
}
```
- Agent 负责声明 objective、campaign、continuation 与是否需要旧记忆。
- Salva 负责强制 campaign filter、quarantine/promote 与 no-write 模式。
- 部署平台负责 auth、tenant 权限、filesystem roots、secrets。
完整契约:[docs/spec/execution-context.md](docs/spec/execution-context.md)
## 调用方式
### 1. MCP(推荐 — Agent 首选)
配置 `apps/mcp/server.py` 为 Claude Code MCP extension:
```
{
"mcpServers": {
"salva": {
"command": "python3",
"args": ["-m", "apps.mcp"]
}
}
}
```
可用工具:
| 工具 | 用途 |
|------|------|
| `salva_discover` | 同步 discovery(小任务) |
| `salva_job_create` | 异步 job(大任务) |
| `salva_job_status` | 轮询 job 状态 |
| `salva_run_result` | 取完整 run 结果 |
| `salva_audit` | 质量审计 |
| `salva_pilot` | 下一步建议 |
| `salva_hold_walk` | 遍历 n-ary 超图 |
| `salva_routing_table` | 查看学习到的 source 权威排名 |
| `salva_memory_summary` | 顶层 query families + content seeds |
### 2. REST API(同步)
```
curl -X POST http://localhost:8000/v1/discover \
-H "Content-Type: application/json" \
-d '{
"objective": "find_companies",
"intent": {"market": "US", "industry": "AI hardware"},
"max_results": 10
}'
```
### 3. REST API(异步)
```
# 創建 job
curl -X POST http://localhost:8000/v1/jobs \
-d '{"discovery": {...}, "wait_for_completion": false}'
# 查狀態
curl http://localhost:8000/v1/jobs/{job_id}
```
### 4. CLI
```
salva find --market US --industry "AI hardware"
salva job status
salva audit
```
## API 端点
| 端点 | 说明 |
|------|------|
| `POST /v1/discover` | 同步 discovery |
| `POST /v1/jobs` | 创建异步 job |
| `GET /v1/jobs/{job_id}` | Job 状态 |
| `GET /v1/jobs/{job_id}/stream` | SSE 事件流 |
| `GET /v1/runs/{run_id}` | Run 结果 |
| `GET /v1/query-families` | 依 campaign / continuation / status 查询记忆 |
| `POST /v1/query-families/{memory_id}/promote` | 提升已审核的 query-family memory |
| `GET /v1/routes` | 路由目录 |
| `GET /v1/providers` | 供应商列表 |
| `POST /v1/pilot` | 下一步建议 |
| `POST /v1/audits/{run_id}` | 质量审计 |
| `GET /v1/hold/walk` | 超图遍历 |
| `GET /v1/usage` | 用量统计 |
## 项目结构
```
salva/
├── apps/
│ ├── api/ # REST API (FastAPI)
│ ├── cli/ # CLI (typer)
│ └── mcp/ # MCP Server(9 tools,agent 主要入口)
├── core/
│ ├── controller.py # 協調器 + B1 content term 提取
│ ├── keyword_graph.py # 查詢圖 + B2 memory seed 注入
│ └── domain_vocab.py # 領域詞彙 registry
├── retrieval/ # 供應商適配器(SearXNG / Whoogle / DDG)
├── processing/
│ ├── dedup.py # BM25-hybrid 去重
│ └── scorer.py # 評分(injectable ScorerConfig)
├── enrichment/ # LLM/OSINT 富化(omlx bounded prompts)
├── hold/ # 超圖容器入口
├── experiments/ # 理論驗證實驗(E1–E9)
└── salva_core/
├── persistence/ # SQLite — 分模組
│ ├── db.py # Schema + migration
│ ├── runs.py # Run 記錄(含 content_nodes_json)
│ ├── memory.py # Query family memory + seed 查詢
│ ├── hold.py # n-ary 超邊、canonical entities、routing memory
│ ├── jobs.py # Job 記錄
│ ├── evidence.py # 證據鏈
│ ├── telemetry.py # 遙測
│ └── usage.py # 用量統計
├── relation_ontology.py # FtM 對齊關係類型(7 canonical + multilingual surface forms)
├── vector_backends.py # JinaOmlxVectorBackend(1024d)+ HybridHash fallback
├── schemas.py # Canonical types
├── execution.py # ExecutionContext 標準化與 metadata
└── service.py # 核心服務
```
## 快速启动
```
# 1. 安裝
pip install -e ".[dev]"
# 2. 設置環境變數
cp .env.example .env # 或直接編輯 .env
# 必填:
# OMLX_BASE_URL=http://localhost:8140 (本地 omlx,Jina embedding + LLM)
# SALVA_SQLITE_PATH=./data/salva.db
# SEARXNG_ENABLED=false (若無本地 SearXNG)
# 3. 啟動 API
python3 -m uvicorn apps.api.main:app --port 8000
# 4. 健康檢查
curl http://localhost:8000/health
# 5. 測試
pytest
```
## Embedding Backend
| Backend | 启用方式 | 用途 |
|---------|---------|------|
| `jina_omlx` | `SALVA_SEMANTIC_VECTOR_BACKEND=jina_omlx` | 内容语义搜索(1024d Jina v5) |
| `hybrid_hash` | 默认 | 轻量 hash 备用(无 omlx 时自动降级) |
**注意:** Jina v5 小模型不适合跨字形实体名称解析(台积电↔TSMC cosine≈0.04)。
跨语言实体合并依赖 `canonical_entities` + `entity_aliases` gazetteer(Hold C2)。
## n-ary 超图(Hold)
Salva 使用 n-ary 超边表示多方关系(如 §13(d)(3) 集体持股、多方控股协议):
```
# 一條 acting_in_concert 超邊包含多個參與者
hyperedge: acting_in_concert
├── BlueMountain Capital [group_lead, 5.2%]
├── BM Fund A [group_member, 2.1%]
├── BM Fund B [group_member, 1.8%]
└── Chatham Lodging Trust [target]
evidence: SEC EDGAR SC 13D/A 2013-05-15
```
支持:
- HIF(Hypergraph Interchange Format)lossless round-trip export/import
- Bipartite projection(entity ↔ hyperedge)
- Star projection(entity ↔ entity via shared hyperedge)
## 实验验证结果(E1–E9)
| VP | 主张 | 结论 |
|----|------|------|
| VP1 | n-ary 超图忠实度 | ✅ E1 PASS |
| VP2 | 公开源可得性 | ✅ E2 PASS |
| VP3 | 真实 filing → n-ary 事实 | ✅ E3 PASS |
| VP4 | 路由表自我优化 | ✅ E4 PASS |
| VP5 | 跨语言实体解析 | ✅ gazetteer / ⚠️ Jina FAIL(跨字形 F1=0.31) |
| VP6 | 跨语义关系合并 | ✅ E6 PASS(7→3 canonical 超边) |
| VP7 | 语义+二跳 > 关键词 | ⚠️ E7 INCONCLUSIVE(2-hop recall=1.00;precision 下降) |
| VP8 | HIF round-trip + 投影 | ✅ E8 PASS(零 diff) |
| VP9 | 持久化复利可量测 | ✅ E9 PASS(seeds 0→46,nodes 34→61) |
详细结果:`experiments/hg_penetration/E*_FINDINGS.md`
### Agent-only vs Salva Dogfood(E10)
Naturehike DACH 渠道检索的 live dogfood 显示:
| Condition | Round 1 | Round 2 | Round 3 | Best pooled recall |
|---|---:|---:|---:|---:|
| Agent-only | 5 verified | 11 cumulative | 15 cumulative | 88.2% |
| Salva | 2 verified | 0 snapshot | 0 snapshot | 11.8% |

Pooled recall 的分母是两条路径事后验证候选的联集,不是预先冻结的外部 ground
truth。这也不是等预算 benchmark:Agent raw SERP 未完整保存、耗时不可比、Salva
使用 DDG live provider 且 R2/R3 发生零结果。它是可重现的 dogfood 与失败模式记录,
不能被解读为一般性模型排名。
详见:[experiments/agent_vs_salva/README.md](experiments/agent_vs_salva/README.md)
## 文档导航
| 文件 | 用途 |
|------|------|
| [CLAUDE.md](CLAUDE.md) | 开发者必读:设计原则与架构边界 |
| [DEVELOPMENT_PROGRESS.md](DEVELOPMENT_PROGRESS.md) | 本次开发进度报告 |
| [TODO.md](TODO.md) | 开发任务清单 |
| [docs/spec/](docs/spec/) | 行为契约(正式规范) |
| [docs/reports/execution-isolation-update-2026-06-08.md](docs/reports/execution-isolation-update-2026-06-08.md) | 隔离架构、风险与对抗审计 |
| [docs/dogfood/naturehike-dach-2026-06-08.md](docs/dogfood/naturehike-dach-2026-06-08.md) | Naturehike DACH 渠道与 dogfood 结果 |
| [experiments/EXPERIMENT_PLAN.md](experiments/EXPERIMENT_PLAN.md) | 实验计划与验证状态 |
## 错误处理
- `400` — 验证失败或输入错误
- `403` — Tenant 权限不足
- `404` — 找不到资源
- `429` — Quota 超限
- `500` — 内部错误
## 许可证
采用 [Apache License 2.0](LICENSE)。允许商用、修改与私有部署,并附带专利授权;再散布时请保留版权与授权声明。
Copyright © 2026 Ryan Lee.
标签:MCP, REST API, 数据提取, 检索引擎, 自托管, 逆向工具