SAG

Zleap-AIMIT活跃维护

一种新的 RAG 检索架构,用知识图谱和向量检索构建知识库,让人和 Agent 都能高效查询结构化知识。

A new SOTA for RAG — an original retrieval architecture and an open-source knowledge base for humans and agents.

v1.9.2发布于 2026-10-22 08:22 UTC2,882star +109 / 7 天208fork同步于 2026-11-10 11:42 UTC

怎么上手

由 README 提炼,执行前请确认
git clone https://github.com/Zleap-AI/SAG.git
cd SAG
docker compose up -d --build
硬件要求按 README 说明

README 未说明显存或 GPU 要求;默认本地优先单用户部署,使用 SQLite 和 LanceDB,无需外部数据库,Docker 启动不要求本机安装 Python 或 Node 运行时。

支持 Apple Silicon有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

基于原创 SAG 检索架构的开源自托管知识库,把文档变成可搜索、可溯源、可被 Agent 调用的知识

一种新的 RAG 检索架构,用知识图谱和向量检索构建知识库,让人和 Agent 都能高效查询结构化知识。

核心能力

  • 用事件-实体索引加查询时动态超边替代传统 RAG 与 GraphRAG
  • 支持 Fast、Precise 及可选 JEV 重排三种检索模式
  • 每条检索结果和引用都能回溯到原始文本块
  • 提供事件-实体知识图谱查看与多轮带引用问答
  • 通过 REST/OpenAPI、OpenAI 兼容接口、MCP 和 Python 包对外集成

容易踩的坑

首次启动需在设置中配置模型连接,嵌入模型用于索引和向量检索、LLM 用于事件抽取与生成回答,未配置时界面可启动但无法完成索引和问答;PDF 解析在配置 MinerU 时使用 MinerU,否则回退到本地 MarkItDown;切换嵌入模型需等已有文档删除完成后再改模型并重新导入,升级已有 BGE 索引时需保留 SAG_EMBEDDING_MODEL=bge-large-en-v1.5。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.9.2
  1. v1.9.2SAG v1.9.2最新正式版2026-10-22 · 2026-10-22 08:22 UTC

    Downloads

    • macOS Apple Silicon: download the .dmg installer.

    • Windows x64: download the Setup.exe installer. It is currently unsigned, so Windows may show an unknown-publisher warning.

    • Desktop updates require choosing Download, then Restart and install. Older clients first receive the compatible bridge release.

    Changes

    • 新增结构化输出模式设置和自动降级,兼容不支持严格结构化输出的模型;改善口语化提问的查询分析与语义结果保留(#248)。
    • 新增客户端设备授权、会话撤销、令牌自动刷新及可恢复的幂等写入,支持 CLI 长期自动化任务(#248)。
    • 桌面端新增可选的 NAS / 远程工作台配置入口,保留默认本机使用方式;隔离连接登录状态并修复切换、退出与签名资源加载问题(#248)。
    • 修复 Windows / Mac 桌面端因本机 API 端口被占用而无法启动的问题,自动选择空闲端口并同步前端及内部控制地址,保留页面地址与登录存储(#251)。

    Checksums are provided in SHA256SUMS.txt.

  2. fnos-v1.5.13-fnosSAG fnOS Native x86 1.5.13-fnos2026-10-22 · 2026-10-22 05:26 UTC
    查看更新说明

    Published from fnos/develop @ f42357a64bbfd9875f93c1c2996a4035b2ba153a

    • Base version: 1.5.13
    • FPK: sag-1.5.13-fnos-x86.fpk
    • SHA256: ab020c4884059a9e3bfaca76125587e2fd60ebe0cf4c8c64beadbf5cf11eb6af
  3. fnos-v1.5.12-fnosSAG fnOS Native x86 1.5.12-fnos2026-10-20 · 2026-10-20 07:33 UTC
    查看更新说明

    Published from fnos/develop @ 5840650f6cc973b7fc40850aa22ef5a3e371bbb7

    • Base version: 1.5.12
    • FPK: sag-1.5.12-fnos-x86.fpk
    • SHA256: cffcf203d0d9c2c8c300290994c22d8d1e3b5e67f7b417a612a982a55a846909
  4. v1.9.1SAG v1.9.12026-10-19 · 2026-10-19 06:50 UTC
    查看更新说明

    Downloads

    • macOS Apple Silicon: download the .dmg installer.

    • Windows x64: download the Setup.exe installer. It is currently unsigned, so Windows may show an unknown-publisher warning.

    • Desktop updates require choosing Download, then Restart and install. Older clients first receive the compatible bridge release.

    Changes

    • 修复桌面包在部分系统上因默认 CA 证书路径不可用而导致 JEV 等 HTTPS 调用失败的问题;在 HTTP 客户端初始化前加载随包证书,兼容 macOS 和 Windows,保留用户显式证书配置及原有模型、知识库设置(#242)。

    Checksums are provided in SHA256SUMS.txt.

  5. v1.9.0SAG v1.9.02026-10-19 · 2026-10-19 02:48 UTC
    查看更新说明

    Downloads

    • macOS Apple Silicon: download the .dmg installer.

    • Windows x64: download the Setup.exe installer. It is currently unsigned, so Windows may show an unknown-publisher warning.

    • Desktop updates require choosing Download, then Restart and install. Older clients first receive the compatible bridge release.

    Changes

    JEV 精排

    • 新增可选 JEV 精排,直接为候选证据评分,无需生成长篇推理;支持 302.AI、TypeSafe 官方及自定义服务,显式选择后启用。
    • 支持 LanceDB、Elasticsearch;pgvector 暂不支持 JEV。默认限时 30 秒、失败报错,可选择粗排降级,已有文档无需重新入库。

    在公开数据集 MuSiQue 上的测试中,JEV 的 Recall@10 为 81.27%,高于 LLM 非 CoT ranking 的 79.12%,接近 LLM CoT ranking 的 82.77%;平均每次搜索耗时分别为 1.1 秒、3.0 秒和 36.8 秒。按每次搜索约 1.15 万 JEV 输入 token 和官方定价估算,JEV 精排成本约 0.00048 美元/次搜索,每万次搜索约 4.8 美元。以上结果来自不同检索配置的比较,费用不含其他模型调用。

    其他更新

    • 引擎升级至 zleap-sag 0.15.0,支持输入级隔离;重处理成功前保留上一版内容,兼容的失败任务可手动恢复,删除内容先从公开检索和读取中隐藏,再后台清理。
    • 上传展示实际传输进度,后台处理展示当前阶段及分块计数;修复抽取期间冷信源检索等待。
    • 新增独立问答模型与查询 Embedding 连接,支持模型卡逐卡测试和保存,查询沿用原始模型与维度,扩展 302.AI、DeepSeek 及向量服务快速配置。
    • 新增原生 Responses API 接入,支持兼容服务、Azure 和 Bedrock,以及流式回答、结构化输出与工具调用。
    • 新增可选 AnyDoc 本地解析,支持 DOCX、PPTX、EPUB、文本 PDF 和 CSV。
    • 支持自托管 MinerU 4.x,保留解析图片、结构化附件、标题及页码信息。
    • 完善 MCP/REST 原文读取和标题大纲,二进制文档返回解析后的 Markdown,活跃 OCTX 原文无需初始化引擎即可读取。
    • 修复新建对话重新打开旧会话,以及历史问题、重试丢失所选信源范围的问题。
    • 修复抽取 Schema、Excel 数字解析、知识宇宙分页边界和 OCTX 批量向量失败原因缺失的问题。
    • 将 dsh-sag 源码纳入统一维护,适配 DeepSeek Harness 0.2.0-rc.2,保留独立插件发布流程。
    • 完善桌面服务异常清理与重试,退出、安装更新前检查未完成任务,优化构建缓存及并行发布流程。

    Checksums are provided in SHA256SUMS.txt.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    https://github.com/user-attachments/assets/ac805e3c-ab52-4857-bef6-2865f3831b2f

    Contents


    Project

    Changelog

    See CHANGELOG.md for release history and version-specific changes.

    SAG in one minute

    SAG is not a fusion of traditional RAG and GraphRAG. It is an original retrieval architecture that replaces both.

    Through event-entity indexing and query-time dynamic hyperedges, SAG delivers semantic retrieval and relational reasoning in one system, without maintaining two RAG systems or merging two retrieval paths.

    Experiments on HotpotQA, 2WikiMultiHopQA, and MuSiQue show that SAG achieves the best retrieval and end-to-end QA performance on every benchmark, establishing a new state of the art for RAG.

    This project is a complete knowledge base application for individuals and Agents built on SAG:

    sources and documents → structured knowledge → search and source tracing → cited Agent answers → reuse through API or MCP

    Upload a document once. SAG parses it, splits it into chunks, embeds it, extracts events and entities, and keeps every retrieval result connected to the original text. You can then search across sources, inspect the event-entity graph, ask questions with citations, or expose the same knowledge to another application.

    CapabilityWhat it gives you
    Knowledge ingestionFile and web sources, document parsing, chunking, embedding, event/entity extraction, background processing
    SearchCross-source or source-scoped retrieval with Fast (vector / multi_es_fast), Precise (multi), and optional JEV reranking (multi_jev) modes
    Source tracingOpen any result or citation back to the exact original chunk
    Knowledge graphInspect events, entities, and their queryable associations
    Agent chatMulti-turn answers grounded in selected sources, with clickable citations
    IntegrationSelf-hosted REST/OpenAPI, OpenAI-compatible chat, MCP, and the zleap-sag Python package

    The product is deliberately local-first and single-user. It starts with SQLite and LanceDB, requires no external database, and keeps a clear path to PostgreSQL/pgvector and other production backends.


    Technology

    Paper

    SAG: SQL-Retrieval Augmented Generation with Query-Time Dynamic Hyperedges Yuchao Wu*, Junqin Li, XingCheng Liang, Yongjie Chen, Yinghao Liang, Linyuan Mo, and Guanxian Li

    Read the paper · Reproduce the benchmark

    An original third architecture

    Traditional dense RAG retrieves chunks mainly by semantic similarity. GraphRAG adds offline graph construction, but pays for triple extraction, entity merging, relation normalization, global maintenance, and difficult incremental updates.

    SAG does not wrap those two systems. It replaces that choice with its own data model and execution path:

    chunk → one semantically complete event
    chunk → multiple indexing entities
    event ↔ entities → one latent hyperedge
    
    • Event carries the complete meaning of a chunk. It is not fragmented into independent triples.
    • Entity is a lightweight index and expansion point, not a replacement for the event's meaning.
    • Query-time dynamic hyperedge is created locally when SQL joins events that share entities around the current query. SAG does not pre-build or globally maintain those hyperedges.
    • Original evidence remains the output boundary. Selected events always map back to source chunks for generation and citation.

    The semantic and structural paths inside SAG are native parts of the SAG pipeline. They are not a traditional RAG service and a GraphRAG service running side by side.

    How retrieval works

    Offline indexing

    1. Parse a document into semantically coherent chunks.
    2. Extract one event and multiple entities from each chunk in parallel.
    3. Persist chunks, events, entities, and event-entity associations to relational storage.
    4. Persist chunk, event, and entity representations to vector/full-text indexes.

    Online retrieval

    1. Find seed entities and events using semantic and lexical signals.
    2. Use SQL joins over shared entities to expand from seed events into a local candidate space.
    3. Instantiate only the hyperedges relevant to this query; no global graph traversal or rebuild is required.
    4. Select the strongest event and direct-chunk candidates, deduplicate them, and return the original evidence chunks.

    This makes incremental writes natural: a new chunk adds its own event, entities, and associations without recomputing a global graph.

    A new SOTA for RAG

    Under the same BGE-Large-EN-v1.5 embedding and Qwen3.6-Flash LLM configuration, SAG achieves the best retrieval and end-to-end QA performance on every benchmark across HotpotQA, 2WikiMultiHopQA, and MuSiQue.

    • Across the three datasets, SAG averages 90.07%/72.96% in Recall@5 and F1, outperforming the strongest baseline for each metric by 6.79/4.33 percentage points, respectively.
    • On the most challenging MuSiQue dataset, SAG outperforms the strongest baseline for each metric by 11.52/7.01 percentage points in Recall@5 and F1, respectively.

    Full results:

    See the paper and SAG-Benchmark for the full method and reproduction scripts.


    User Guide

    Desktop app (easiest)

    Download the latest desktop installer from GitHub Releases:

    PlatformDownloadUpdate behavior
    macOS 15+, Apple SiliconSAG-*-mac-arm64.dmgSigned and notarized; in-app updates require separate download and install confirmation
    Windows 10/11, x64SAG-Setup-*-win-x64.exeUnsigned for now; Windows may show an unknown-publisher warning; in-app updates require separate download and install confirmation

    The desktop app bundles the Web workspace and local knowledge backend, so users do not need to install Python, Node.js, or a database. Application updates preserve the knowledge base and uploads in the operating system's application-data directory. Release checksums are published as SHA256SUMS.txt.

    If SAG detects incompatible legacy knowledge data, it leaves that data unchanged until you confirm a backup and a fresh workspace. SAG does not automatically migrate or merge the old knowledge base; upload your documents again after setup. The backup remains available for manual recovery. Accounts and model settings are preserved, while previous knowledge bases, documents, agents, conversations and related tasks do not appear in the new workspace. Current-format workspaces continue using their existing data directories.

    Quick start (Docker, self-hosted)

    Requirements: Docker Desktop, or Docker Engine with Compose v2.

    git clone https://github.com/Zleap-AI/SAG.git
    cd SAG
    docker compose up -d --build
    

    No API key, Python runtime, Node runtime, or external database is required to boot the application. When both services are healthy, open:

    On first launch:

    1. Enter your name to create or restore the local identity.
    2. Choose 302.AI or DeepSeek quick setup, or open Settings → Models to configure your model connections.
    3. Create a source, upload documents, and wait until their status is Ready.
    4. Search, open the original source, or start a cited conversation.

    DeepSeek uses Flash in non-thinking mode. Either setup supports embeddings from 302.AI, Zhipu, or Alibaba Cloud Bailian; enter a separate Key when using a different provider.

    The UI and services still start without model credentials. Embeddings are required for indexing/vector retrieval; the LLM is required for event extraction, query understanding, and generated answers.

    Model settings precedence

    SAG_LLM_* values in Docker Compose or .env provide the initial model configuration. After an administrator saves model settings in the web UI, the persisted Settings value is used for subsequent extraction and generation jobs without a restart.

    New model setup suggests qwen3.8-flash for generation and Qwen/Qwen3-Embedding-4B for embeddings. Upgrades preserve saved model settings and explicit environment values; deployments without an explicit generation model retain the existing runtime default qwen3.6-flash. When upgrading an existing BGE index, retain SAG_EMBEDDING_MODEL=bge-large-en-v1.5. To switch models, wait for existing indexed documents to finish deleting, change the model, then import them again.

    To make the deployment configuration mandatory, set SAG_LOCK_LLM_CONFIG=true. SAG then shows the generation fields as locked in Settings and continues to use the SAG_LLM_* values. Change Docker Compose or .env and recreate the API container to update a locked configuration. API keys remain deployment-managed and are never returned by the Settings API.

    For separate chat and query endpoints, enable Chatbot LLM or Query embedding in the same Models page. Both are optional and leave document extraction/indexing on the original connections. Query embeddings share the original model and vector dimensions. See optional chatbot connections for deployment settings, credential storage, and recovery.

    Select OpenAI-compatible, then choose the Responses API format for original generation or the optional chatbot LLM to use OpenAI-compatible, Azure, or Bedrock Responses endpoints. See Responses API setup for endpoint configuration, reasoning controls, authentication, and verification.

    Use Test to check an unsaved original or optional model connection before saving it. Success shows a green check with the model or embedding dimensions; failure shows a red error. Testing does not save the draft. Successful optional connection saves apply to subsequent operations, while operations already running keep their captured configuration. During background document processing, queries can reuse an initialized compatible engine to reduce waiting. See optional chatbot connections for the runtime details.

    Import knowledge

    Create a source and add Markdown, text, PDF, Office, or other supported documents. SAG normalizes documents to Markdown, then runs chunking, embedding, event extraction, and entity extraction in the background.

    File uploads show actual transfer progress. The document list and details show the current processing stage and available chunk counts (for example, “Processed 810 / 2,033 chunks”), without an overall processing percentage. A document is ready to search when its status becomes Ready.

    PDF files use MinerU when it is configured and fall back to local MarkItDown when it is unavailable or fails. Other Office and text formats use MarkItDown by default.

    PDF parsing also supports a self-hosted MinerU 4.x V1 API (mineru-kit api-server). Configure SAG_MINERU_PROVIDER=self_hosted, SAG_MINERU_BASE_URL, and SAG_DOCUMENT_PARSER=auto or mineru using .env.example. Local or private-network endpoints also require SAG_MINERU_ALLOW_PRIVATE_BASE_URL=true. Recreate the API container after deployment changes. Previously saved parser/MinerU settings override environment defaults; update those saved values through authenticated PUT /api/v1/system/model-config and check the effective configuration before importing PDFs.

    You can also switch the parsing method to AnyDoc in settings (or set SAG_DOCUMENT_PARSER=anydoc): docx/pptx/epub/pdf/csv are converted on this machine by AnyDoc, nothing is uploaded, and no hosted OCR runs. XLS/XLSX retain local MarkItDown conversion to preserve Excel record groups and searchable chunks; the actual parser is recorded. Only files explicitly rejected as unsupported fall back to MarkItDown; other conversion errors are reported as failures. CSV is first decoded with SAG's encoding detection and normalized to UTF-8 before AnyDoc sees it, so non-UTF-8 Chinese CSV does not turn into mojibake. A scanned or image-only PDF is reported as needing OCR for the whole file (with page numbers) — switch to a configured MinerU and reprocess it; no partial text is cached. The default auto behaviour is unchanged.

    Search and verify the source

    Search across sources or restrict the query to selected sources. Without an explicit selection, global search and default Agent retrieval use up to 16 candidate sources by default. Use @ to target the sources you need. Every result can open the original chunk beside the ranked result, so retrieval quality is inspectable before an Agent uses it.

    Ask with citations

    The Agent searches the knowledge sources in the current scope, streams the answer, and attaches clickable citations. The same conversation path is also available through an OpenAI-compatible endpoint.

    Select sources with @ to narrow a question's knowledge scope. Each question keeps its selected-source badges in conversation history, and Retry reuses that saved scope. The badges show the selected search scope; the answer's citations show the evidence actually used. See source scope in chat history.

    Use New conversation in the sidebar to open a blank draft from any page. The draft stays selected when returning to chat, even while an older conversation finishes generating. Existing conversations remain in history; a new thread is saved when you send the first question. SAG generates one answer at a time, so wait for the ongoing answer to finish or stop it before sending in the new draft.

    Explore mode

    Explore mode unfolds the entire knowledge base into an interactive knowledge universe. Search events and entities, travel through their relationships, and open event details or original sources without leaving the same view.

    Explore the event-entity graph

    Switch a source from list view to graph view to inspect the events, entities, and associations produced by the SAG index.

    MCP guide

    The recommended path is two steps: CLI mounts the MCP, Skill teaches the Agent how to explore it. Together they give you a complete knowledge retrieval setup with zero hand-edited config.

    Step 1: mount MCP with the CLI

    @zleap-ai/sag-cli is the official command-line client. It auto-discovers your local Docker SAG container, verifies the MCP works, and wires it into Codex or Claude Code — for the local Docker path no JWT is needed.

    Install (Node.js ≥ 20.19):

    npm install --global @zleap-ai/sag-cli
    

    Wire the MCP in one command:

    sag mcp test                     # verify the SAG MCP is reachable
    sag agent connect codex          # mount into Codex
    sag agent connect claude-code    # or mount into Claude Code
    sag agent status                 # see what's wired
    

    For a remote SAG instance (no local Docker), sign in from the terminal first:

    sag profile add prod https://sag.example.com
    sag profile use prod
    sag auth login --name "Your name" # signs in to SAG directly
    sag agent connect claude-code
    

    The CLI never writes your JWT into an Agent's config file, stores tokens in the OS keychain when available, and only removes MCP entries it created itself. Preview any write with --dry-run. Full guide: SAG CLI User Guide.

    Step 2: install the Skill

    The Skill ships in @zleap-ai/sag-cli. Copy it into your Agent's skills directory:

    # Claude Code
    SKILL_SRC="$(npm root -g)/@zleap-ai/sag-cli"
    cp -r "$SKILL_SRC/skill" ~/.claude/skills/sag-knowledge
    
    # Codex
    SKILL_SRC="$(npm root -g)/@zleap-ai/sag-cli"
    cp -r "$SKILL_SRC/skill" ~/.codex/skills/sag-knowledge
    
    Manual mounting (fallback)

    If you can't install the CLI, open Settings → Integrations → Knowledge MCP in SAG, pick HTTP or local command, and paste the copied block into your Agent's MCP config file yourself. The HTTP snippet already includes the current JWT and exposes all sources by default; scope it with source_id when needed.

    Use SAG in DeepSeek Harness

    Connect your SAG knowledge base to DeepSeek Harness with dsh-sag. The current plugin, dsh-sag 0.2.0, supports DeepSeek Harness 0.2.0-rc.2.

    Start SAG. After dsh-sag 0.2.0 is published to npm, install and run the plugin:

    dsh plugin --profile web add @zleap-ai/[email protected]
    dsh plugin --profile web exec dsh-sag doctor
    dsh --profile web
    

    Ask dsh: “Search SAG for the upload limit and cite the original text.” See the plugin usage guide for connection options and supported capabilities.

    Use SAG as a model (OpenAI-compatible)

    SAG exposes an OpenAI Chat Completions endpoint with the same retrieval and citation behavior as the built-in chat:

    curl -s http://localhost:8000/api/v1/openai/<AGENT_ID>/chat/completions \
      -H "Authorization: Bearer <SAG_JWT>" \
      -H "Content-Type: application/json" \
      -d '{"messages":[{"role":"user","content":"What is this material about?"}]}'
    

    The response is a standard chat.completion with an additional sag.citations field; standard clients ignore unknown fields. Set "stream": true to receive SSE chunks.

    Use SAG as a Dify external knowledge base

    SAG can connect to Dify's Connect to an External Knowledge Base feature through a dedicated compatibility endpoint, with no Dify source-code changes. For the API key, Docker network, Source ID, and Dify console configuration, see docs/dify-integration.en.md.

    Operate and update

    docker compose ps                  # api and web should be healthy
    docker compose logs -f api web     # follow logs
    docker compose restart             # restart services
    docker compose down                # stop and keep all data
    
    git pull --ff-only                 # update the source checkout
    docker compose up -d --build       # rebuild without deleting volumes
    

    Default persistence:

    RuntimeApplication metadataKnowledge engineLocation
    Docker defaultSQLiteSQLite + LanceDBDocker volume sagdata
    Local developmentSQLiteSQLite + LanceDBapps/api/.data/
    PostgreSQL overridePostgreSQLPostgreSQL + pgvectorpgdata and sagdata volumes

    docker compose down preserves data. docker compose down -v permanently deletes the database, knowledge index, and uploaded files.

    Network and production safety

    The default Compose configuration binds ports 3000 and 8000 to 127.0.0.1 and uses SAG_AUTH_MODE=local: the name is a local identity, not password authentication. Do not expose this default mode to an untrusted network.

    For custom ports or a trusted LAN address:

    cp .env.example .env
    # Edit BIND_ADDRESS, WEB_PORT, API_PORT, SAG_CORS_ORIGINS, and NEXT_PUBLIC_API_BASE.
    # For remote access, also set SAG_AUTH_MODE=password and keep SAG_ALLOW_REGISTRATION=false.
    docker compose up -d --build
    

    On first launch, password mode guides you through creating an email and password. Later sign-ins require both credentials and never fall back to a name or the first user. SAG_ALLOW_REGISTRATION=false still permits the first credential account, then closes registration.

    NEXT_PUBLIC_API_BASE is compiled into the web image, so changing it requires --build. A server deployment should also use a strong SAG_SECRET_KEY, HTTPS, and protection such as VPN, IP allowlisting, or reverse-proxy rate limiting. The current sag auth login --name command is for local mode; with password mode, sign in through the web UI first and provide the issued token to the CLI through SAG_TOKEN.


    Developer Guide

    System boundaries

    SAG has a separated Next.js frontend and FastAPI backend. The backend is a reference application built on the public zleap-sag Python engine. You can reuse the complete backend from another frontend, or embed zleap-sag directly in a Python service of your own.

    Repository map

    apps/
    ├── web/                    Next.js 15 + React 19 product UI
    ├── desktop/                Electron shell, packaging, and local runtime lifecycle
    └── api/
        ├── sag_api/
        │   ├── api/v1/         FastAPI HTTP routes and serialization
        │   ├── connectors/     File/web source connectors and registry
        │   ├── parsing/        MarkItDown and MinerU normalization
        │   ├── jobs/           Background ingest → extract state machine
        │   ├── sag/            The only application adapter importing zleap-sag
        │   ├── generation/     Retrieved evidence → streamed cited answer
        │   ├── mcp/            Knowledge MCP server and HTTP mount
        │   ├── services/       Application/domain orchestration
        │   └── tools/          Built-in and remote MCP Agent tools
        └── sag_agent/          Framework-independent Agent runtime core
    deploy/                     Deployment initialization assets
    integrations/dsh-sag/       Independently published DeepSeek Harness plugin and embedded runtime
    docs/assets/readme/         README screenshots and diagrams
    

    The central dependency rule is simple: application code reaches the engine through apps/api/sag_api/sag/; the engine does not know about FastAPI, the Web UI, users, conversations, or citations.

    Local development

    Start the backend and frontend in separate terminals from the repository root.

    # Terminal 1: API at http://localhost:8000
    cd apps/api
    python -m venv .venv
    . .venv/bin/activate
    pip install -e ".[dev]"
    cp .env.example .env
    uvicorn sag_api.main:app --reload
    
    # Terminal 2: Web at http://localhost:3000
    cd apps/web
    npm install
    npm run dev
    

    Useful checks:

    cd apps/api && pytest
    cd apps/api && ruff check .
    cd apps/web && npm run typecheck
    cd apps/web && npm run build
    

    Desktop client

    The Electron client packages the same Next.js application together with the local FastAPI backend. Desktop development, target-specific release builds, signing, update configuration, and data locations are documented in apps/desktop/README.md.

    Use zleap-sag directly

    zleap-sag is the continuously maintained Python engine behind the SAG application. Distribution name: zleap-sag; import path: zleap.sag; Python: 3.11+; license: MIT. The application currently requires zleap-sag==0.15.0.

    Install the zero-infrastructure local stack:

    pip install zleap-sag==0.15.0
    

    With an existing knowledge.md and working model credentials, run the complete ingest → extract → search lifecycle:

    import asyncio
    from pathlib import Path
    
    from zleap.sag import DataEngine, EngineConfig
    from zleap.sag.config import EmbeddingConfig, LLMConfig
    from zleap.sag.pipeline import SearchOptions, SearchRequest, SearchScope
    
    
    async def main() -> None:
        config = EngineConfig(
            storage_mode="normal",
            llm=LLMConfig(
                api_key="sk-...",
                base_url="https://your-openai-compatible-host/v1",
                model="qwen3.8-flash",
            ),
            # When api_key/base_url are omitted, embedding reuses the LLM endpoint.
            embedding=EmbeddingConfig(model="Qwen/Qwen3-Embedding-4B"),
            language="en",
        )
    
        # One DataEngine instance represents one logical data source.
        async with DataEngine(config, data_source_id="knowledge-demo") as engine:
            chunks = await engine.ingest(Path("knowledge.md"))
            events = await engine.extract(chunks)
            request = SearchRequest(
                query="Why is SAG effective for multi-hop retrieval?",
                scope=SearchScope(data_source_ids=(chunks.data_source_id,)),
                options=SearchOptions(strategy="full_expand", top_k=5, return_type="chunk"),
            )
            result = await engine.search(request)
    
            print(chunks.chunk_count, events.event_count)
            for hit in result.chunks:
                print(hit.content[:200])
    
    
    asyncio.run(main())
    

    Local storage is created automatically under ./.zleap/. Add that directory to .gitignore.

    Configuration

    Use one configuration style, not both:

    StyleConstructionBest for
    Parameter injectionEngineConfig(storage_mode="normal", llm=..., embedding=...)Libraries, notebooks, explicit application wiring
    EnvironmentEngineConfig.from_env() or from_env(env_file=".env")Containers and 12-factor services

    Minimal environment configuration:

    export SAG_STORAGE_MODE=normal
    export OPENAI_API_KEY=sk-...
    export OPENAI_BASE_URL=https://your-openai-compatible-host/v1
    export LLM_MODEL=qwen3.8-flash
    export EMBEDDING_MODEL=Qwen/Qwen3-Embedding-4B
    
    from zleap.sag import EngineConfig
    
    config = EngineConfig.from_env()
    

    EngineConfig(...) does not read environment variables implicitly. Use explicit parameters or from_env(). A separate embedding endpoint can be set with EmbeddingConfig(api_key=..., base_url=..., model=...).

    Public DataEngine API
    APIPurpose
    await engine.start()Initialize connections; local SQLite/LanceDB schema is created automatically
    await engine.aclose()Close engine resources; handled automatically by async with
    await engine.parse(source, options=None)Parse a FileSource, TextSource, or other SourceInput into a ParsedSource without persisting it
    await engine.chunk(parsed, options=None)Chunk a ParsedSource into a ChunkSet without persisting it
    await engine.ingest(source, ...)Parse, chunk, embed, and persist a path, text, or SourceInput; return a ChunkSetRef
    await engine.extract(target, options=None)Extract and persist events/entities from a ChunkSetRef or PersistedChunkSelector; return an EventSetRef
    await engine.search(request)Search with an explicit SearchRequest (query, scope, options); return a SearchResult with chunks, events, and stats
    await engine.init_schema()Idempotently initialize production schemas; not needed for the default local stack

    Pipeline request and result types are available from zleap.sag.pipeline: ParsedSource, ChunkSet, ChunkSetRef, EventSetRef, SearchRequest, and SearchResult. All engine exceptions derive from SagError in zleap.sag.exceptions, so application boundaries can catch one base type.

    Retrieval modes
    UI labelApp/API strategyImplementation
    Fast (vector)vectorDirect retrieval by semantic similarity for a faster response
    Fast (multi_es-fast)multi_es_fastBM25 entity recall and event multi-hop retrieval, skipping LLM reranking
    PrecisemultiCombines entity relationships with LLM reranking for more complete results
    JEV rerankingmulti_jevScores recalled and graph-expanded evidence through an independent JEV service

    These are the application/API strategy names; the application maps multi to the Python engine's full_expand and multi_es_fast to pruned_expand_rff. Availability depends on storage capabilities: multi_es_fast requires lexical search support.

    Configure 302.AI, TypeSafe, or a custom JEV service in Settings → Knowledge → Retrieval (default model: jev-latest, separate API key), then select JEV reranking. Saving the service alone does not enable it. The default deadline is 30 seconds; failures return an error unless coarse fallback is enabled.

    Supported on LanceDB and Elasticsearch; pgvector is currently unsupported. PostgreSQL relational storage can use JEV with a supported vector backend. Existing retrieval settings remain until JEV is selected; documents do not need reindexing. See the benchmark results and cost estimates.

    Storage backends
    DeploymentRelational storageVector storagePackage extra
    Local defaultSQLiteLanceDBnone
    Single databasePostgreSQLpgvectorzleap-sag[postgres]
    Production splitMySQL/PostgreSQL/OceanBaseElasticsearchzleap-sag[mysql], [postgres], [es]
    Single databaseOceanBase 4.3.3+OceanBase vectorzleap-sag[mysql]

    Changing EngineConfig changes the backend without changing ingest/extract/search calls. Each DataEngine instance owns its connections and resources; close it with async with or aclose().

    For the full package configuration, extras, examples, and changelog, see the zleap-sag package page.

    Build your own frontend with the SAG backend

    A browser cannot import a Python package directly. A custom frontend should call a Python HTTP service that owns DataEngine. This repository's FastAPI backend is that reference service, and it is already separated from the Next.js UI.

    The self-hosted API is available after starting SAG:

    EntryAddress
    API basehttp://localhost:8000/api/v1
    Interactive OpenAPIhttp://localhost:8000/docs
    OpenAPI schemahttp://localhost:8000/openapi.json
    MCP Streamable HTTPhttp://localhost:8000/mcp/

    This is a self-hosted API, not a hosted public cloud API. In the default local mode, most routes use a SAG JWT issued after name login:

    curl -s http://localhost:8000/api/v1/auth/login \
      -H 'Content-Type: application/json' \
      -d '{"name":"Developer"}'
    

    Copy access_token from the response and send it as:

    Authorization: Bearer <SAG_TOKEN>
    

    With SAG_AUTH_MODE=password, create the first credential through POST /auth/register, then sign in with email and password:

    curl -s http://localhost:8000/api/v1/auth/login \
      -H 'Content-Type: application/json' \
      -d '{"email":"[email protected]","password":"<YOUR_PASSWORD>"}'
    
    API map
    AreaMain routesPurpose
    SystemGET /system/health, /system/ready, /system/capabilitiesHealth and active engine capabilities
    IdentityPOST /auth/login, GET /auth/meLocal identity and JWT
    SourcesGET/POST /sources, GET/PATCH/DELETE /sources/{id}Source lifecycle
    Documents/sources/{id}/documents and /documents/ingestFile upload, continuous text/message ingestion, reprocessing, deletion
    SearchPOST /search, POST /sources/{id}/searchGlobal or source-scoped vector/multi retrieval
    GraphGET /sources/{id}/entities, /sources/{id}/graphEvent-entity inspection
    Agents/agents, /threads, /askAgent configuration, conversations, SSE runs, citations
    OpenAI-compatiblePOST /openai/{agent_id}/chat/completionsUse any SAG Agent as a cited model, streamed or non-streamed
    MCP/mcp/ or /mcp/?source_id={id}Expose the whole knowledge base or one source to an MCP host

    Create a source, ingest text, and search it:

    BASE=http://localhost:8000/api/v1
    TOKEN=<SAG_TOKEN>
    
    SOURCE_ID=$(curl -s -X POST "$BASE/sources" \
      -H "Authorization: Bearer $TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{"name":"Product docs"}' | jq -r .id)
    
    curl -s -X POST "$BASE/sources/$SOURCE_ID/documents/ingest" \
      -H "Authorization: Bearer $TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{"title":"SAG","text":"SAG uses event-entity indexing and query-time dynamic hyperedges."}'
    
    curl -s -X POST "$BASE/sources/$SOURCE_ID/search" \
      -H "Authorization: Bearer $TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{"query":"How does SAG retrieve knowledge?","strategy":"multi","top_k":5}'
    

    Document ingestion is processed by the background job queue. Check the returned document status or its job before expecting search results.

    For a frontend served from another origin, add it to SAG_CORS_ORIGINS. If the API address changes, rebuild the Web image with the matching NEXT_PUBLIC_API_BASE.

    PostgreSQL/pgvector deployment

    The optional production override moves application metadata and engine storage to PostgreSQL/pgvector:

    cp .env.example .env
    openssl rand -hex 32   # set SAG_SECRET_KEY
    openssl rand -hex 24   # set POSTGRES_PASSWORD
    
    docker compose -f compose.yaml -f compose.postgres.yaml config
    docker compose -f compose.yaml -f compose.postgres.yaml up -d --build
    

    Set real SAG_CORS_ORIGINS and NEXT_PUBLIC_API_BASE values before server deployment. Back up both pgdata and sagdata before upgrades.


    Contributing and License

    SAG is released under the MIT License.


    Community

    Join the SAG community on Discord or WeChat to connect with maintainers and other users.