Skip to content

Latest commit

 

History

History
359 lines (285 loc) · 14.5 KB

File metadata and controls

359 lines (285 loc) · 14.5 KB

GraphAnything

把任意东西变成可导航的知识图谱。Markdown 笔记仓、OpenAPI 规格、合同、会议纪要、 聊天记录 —— 所有这些最终都汇聚到同一个 {nodes, edges} schema,带完整 provenance、版本管理、联邦合并与质量报告。

LLM 抽取走 GraphAnything 自带的 OpenAI 兼容客户端,任何 chat.completions 风格的端点都能接:

  • 本地 vLLM servellama.cppOllamaLM Studio
  • OpenAI 本身,或任意商用 OpenAI 兼容服务

English version → README.md

一图速览

Schema preset 10 个(chat-log / codebase / contracts / db-schema / fstree / meeting / obsidian-vault / openapi / papers / pr-review)
Extractor 8 个(markdown / json-yaml / openapi / fstree / chatlog / llm-entity / vlm-stub / noop)
渲染格式 9 种(mermaid / html / svg / cypher / graphml / ascii / json / canvas / timeline)
MCP 工具 17 个
CLI 子命令 19 个
LLM 后端 任意 OpenAI 兼容端点(HTTP)
外部 API 可选 —— 只读 / 规则系命令完全不需要 LLM

三种驱动,共用一套核心

              ┌──────────────────────────────────────────┐
              │   GraphAnything(core)                    │
              │   Session 状态机 + 8 个 extractor        │
              │   + 10 个 schema preset + 9 种渲染格式   │
              │   + temporal + federate + ask + quality  │
              └──────────────────────────────────────────┘
                  ▲              ▲              ▲
                  │              │              │
        ┌─────────┴────┐  ┌──────┴────┐  ┌──────┴──────────┐
        │  CLI / REPL  │  │  Skill    │  │  llm_client.py  │
        │ graphanything│  │ /graphany.│  │ (OpenAI 兼容)   │
        └──────────────┘  └───────────┘  └─────────────────┘

安装

cd GraphAnything
pip install -e .

会注册 graphanything 命令。兜底方案 python -m GraphAnything.cli ... 永远可用。

可选 extras:

pip install -e ".[mcp]"     # MCP stdio server(Claude Code / Cursor / Gemini CLI)
pip install -e ".[neo4j]"   # 直接推到运行中的 Neo4j
pip install -e ".[svg]"     # SVG 渲染(matplotlib)
pip install -e ".[repl]"    # 更好的 REPL(历史 + 补全)
pip install -e ".[all]"     # 上面全部

调 LLM 的命令(refine --llmsample --extractor llm-entityask --llmeval --llm)要把客户端指向任意 OpenAI 兼容端点:

# vLLM serve / llama.cpp / Ollama / LM Studio / OpenAI / …
export GA_API_BASE=http://localhost:8000/v1     # 默认
export GA_MODEL=Qwen3-32B-Instruct              # 必填
export GA_API_KEY=local                         # 可选,很多本地服务接收任意字符串

# 上游遗留环境变量也照单全收:
#   OPENAI_API_BASE / OPENAI_API_KEY / OPENAI_MODEL
#   API_BASE        / API_KEY        / SUMMARY_MODEL_NAME

规则系 extractor(markdownjson-yamlopenapifstreechatlog) 以及所有只读命令(render / explain / 不带 --llmask / versions / diff / federate / 不带 --llmeval)完全不需要 LLM

CLI 快速上手

# 一把梭
graphanything new ./vault/ --preset obsidian-vault --auto

# 分步(非平凡语料推荐)
graphanything new ./contracts --preset contracts
graphanything sample --n 5
graphanything review --merge ABC_Corp,abc_corp,ABC公司
graphanything refine "add GoverningLaw entity"
graphanything run

# 查询
graphanything ask "all clauses with amount > 100k"
graphanything explain ep_api_get_user

# 版本(只重抽 hash 变化的文件)
graphanything update
graphanything versions
graphanything diff 1 2

# 联邦
graphanything federate g1.json g2.json --out universe.json --fuzzy

# 质量报告
graphanything eval --out-dir graphanything-out/quality --llm --judge-n 20

# 渲染(9 种格式)
graphanything render --fmt mermaid                       # 贴给 Claude / 聊天
graphanything render --fmt cypher  --out g.cypher        # → Neo4j
graphanything render --fmt graphml --out g.graphml       # → Gephi
graphanything render --fmt html    --out g.html          # 独立力导向图
graphanything render --fmt timeline --out timeline.html  # X = 年, Y = community
graphanything render --fmt mermaid --budget-tokens 4000  # PageRank 裁剪到约定 token

19 个 CLI 子命令

子命令 作用
new <inputs> 开 session;--preset NAME--extractor NAME--auto、可加 budget 上限
propose [--n N] [--llm] 给出初始 schema(规则可推则规则,否则 generic / LLM)
refine "<指令>" [--llm] 编辑 schema(先 regex,失败转 LLM)
sample [--n N] [--extractor NAME] 抽前 N 个输入到 pending,自动给出合并建议
review --accept-all / --accept ID... / --reject ID... [--reason ...] / --merge a,b[,c]
run [--out DIR] [--extractor NAME] 锁 schema → 跑全量 → 写 graph.json + 快照
update [--out DIR] [--extractor NAME] 只重抽 source_hash 变化的输入,生成新快照
versions [--out-root R] 列出 run / update 写出的所有快照
diff <v_old> <v_new> 比对两个快照(节点 / 边的增删改)
ask "<问题>" [--llm] 自然语言查询(先 regex,失败转 LLM)
explain <id|label|"src → rel → tgt"> 节点 / 边的 provenance
render --fmt FMT [--out PATH] [--graph G] [--budget-tokens N] 9 种格式
federate g1 g2... --out U [--fuzzy] [--fuzzy-threshold T] [--llm] 多图合并成 universe
eval [--out-dir D] [--llm] [--judge-n N] [--graph G] 覆盖度 / 去重 / 各 extractor 统计 / LLM 抽样 judge
presets 列出 10 个内置 schema preset
extractors 列出 8 个已注册 extractor
sessions 列出 graphanything-out/sessions/ 下的 session
use <session_id> 切换当前 session
repl [<inputs>] 交互式 shell(装了 prompt_toolkit 自带历史 + 补全)

顶层 flag(对所有子命令生效):

  • --sessions-dir PATH —— session JSON 落盘目录,默认 graphanything-out/sessions/
  • --session ID —— 临时覆盖"当前 session"指针

new / repl 支持 budget 软上限:--max-tokens N / --max-dollars D / --max-api-calls Nrun / sample 一旦超限就提前停,剩余输入会列在结果的 notes 里。

Skill / MCP server(Claude Code、Cursor、Gemini …)

同一份 Session 核心,通过 17 个 MCP 工具对外暴露:

工具 作用
graphanything_open_session 在一组输入上开 session
graphanything_list_presets 10 个内置 schema 模板
graphanything_list_extractors 8 个 extractor(规则 + LLM + VLM 占位)
graphanything_propose_schema 给出初始 schema
graphanything_refine_schema 编辑 schema(regex + LLM 回退)
graphanything_sample 抽前 N 个输入到 pending
graphanything_review 应用 accept_all / accept / reject / merge / rule 决策
graphanything_run 全量抽取 → graph.json + 快照
graphanything_status 计数 + 成本 + schema
graphanything_ask 自然语言查询
graphanything_explain 节点 / 边的 provenance
graphanything_update 只重抽变化的文件
graphanything_versions 列出图快照
graphanything_diff 比对两个快照
graphanything_federate 多图合并
graphanything_eval 覆盖 / 去重 / 质量报告
graphanything_render Mermaid / HTML / SVG / Cypher / GraphML / ASCII / JSON / Canvas / Timeline

启动服务:

python -m GraphAnything.serve

把这条命令写到你的 MCP 配置(~/.claude.json / .mcp.json / 等)里, Claude Code / Cursor / Gemini CLI 即可直接调 17 个工具:

{
  "mcpServers": {
    "graphanything": {
      "command": "python",
      "args": ["-m", "GraphAnything.serve"],
      "env": {
        "GA_API_BASE": "http://localhost:8000/v1",
        "GA_MODEL": "Qwen3-32B-Instruct",
        "GA_API_KEY": "local"
      }
    }
  }
}

10 个 schema preset

graphanything presets 列出所有;graphanything new --preset NAME 应用一个。 自定义只需把 yaml 丢到 GraphAnything/schemas/<name>.yaml,下次启动自动识别。

Preset 适用场景
chat-log Slack / Claude Code .jsonl / Discord → user / message / tool
codebase 源代码仓库 → module / file / class / function / import / call
contracts 法律合同 → party / clause / date / amount / governing law
db-schema DDL / migrations / ORM → table / column / FK / index
fstree 纯文件系统 → directory / file / symlink
meeting 会议纪要 → person / topic / decision / action item
obsidian-vault Obsidian / Notion 风格 → note / tag / wikilink / backlink
openapi OpenAPI 2.x/3.x → endpoint / schema / ref / security
papers 通用 LLM 抽取论文
pr-review GitHub PR 评审 → file / function / reviewer / concern

8 个内置 extractor

graphanything extractors 列出所有。默认按文件后缀分发,--extractor NAME 强制覆盖。

Extractor LLM? 处理后缀 备注
markdown .md.markdown Note / Heading / Tag / WikiLink
json-yaml .json.ndjson.yaml.yml.toml 通用配置树 + $ref
openapi .yaml.yml.json API / Endpoint / Schema / Parameter,需 --extractor openapi 强制
fstree 目录 Directory / File / Symlink
chatlog .jsonl.txt.log Channel / User / Message / Tool / ToolCall
llm-entity *(任意文本) 通用 entity / relation,带 evidence_spanrationale
vlm .pdf.png.jpg.jpeg 占位 —— 装插件即可启用
noop * 空图;给测试用

注册自己的 extractor(Python 插件):

from GraphAnything import register_extractor

def extract_my_format(path, **_):
    return {
        "nodes": [{"id": "x", "label": "X", "file_type": "document",
                   "source_file": str(path)}],
        "edges": [],
    }

register_extractor(
    "my-format", extract_my_format,
    version="0.1.0", handles=(".myext",),
    description="My custom format extractor",
)

run_extractor() 会自动盖上 provenance(extractor_id / extractor_version / extraction_time / source_hash)。

把 VLM 占位换成真模型:

register_extractor(
    "vlm", my_real_impl, version="1.0.0",
    handles=(".pdf", ".png", ".jpg"),
    needs_llm=True, overwrite=True,
)

版本、联邦、质量

增量更新。graphanything update 重哈希所有输入,没变的文件直接复用之前的 nodes / edges,变了的重抽,合并归一后写成新的 versions/v<N>.json,diff 对任意两个版本都可用。

联邦。graphanything federate g1 g2 ... --out universe.json 把多个图合并成 一个 universe。同 type、同 label 的实体精确合并;加 --fuzzy --fuzzy-threshold 0.7 还会基于 Jaccard token overlap 提议 same_as 边,可选 --llm 让模型 对模棱两可的对做 tie-break。

质量评估。graphanything eval --out-dir graphanything-out/quality 写出 QUALITY_REPORT.md:按节点类型的覆盖度、去重密度、各 extractor 统计;加 --llm --judge-n 20 还会让 LLM 对 20 条采样边比对其 evidence_span 给出判定。

REPL 模式

graphanything repl ./contracts --preset contracts

进入后,所有 CLI 子命令同名可用(schemapropose [N]refine "..."sample [N]review accept-all|accept ID...|reject ID...|merge a,b[,c]run [DIR]render FMT [PATH]explain TARGETstatuscostllm on|offpresetsextractorshelpquit)。

装了 prompt_toolkit(pip install -e ".[repl]")能用历史和补全;否则退回 裸 input()

落盘 session 状态

graphanything-out/
├── sessions/
│   ├── .current               ← 当前 session 指针
│   ├── sess_a1b2c3d4.json     ← 每个 session 一份 json
│   └── sess_...json
├── graph.json                 ← 最新 run / update 的输出
├── versions/
│   ├── v1.json
│   ├── v2.json
│   └── manifest.json          ← 每个快照的 schema_version + source_hashes
└── quality/
    └── QUALITY_REPORT.md

session JSON 是真相源:accepted / pending / rejected 三段图、schema(带版本)、 feedback 日志、成本日志、normalize 规则、上次的 source_hashes(给增量 update 用)。 删除文件 → session 丢失;复制走 → 完整迁移。

配置参考(环境变量)

按需读取,都有合理默认。下面按优先级列出 —— 同一行里第一个被设置的生效。

环境变量 默认
chat-completions URL GA_API_BASE / OPENAI_API_BASE / OPENAI_BASE_URL / API_BASE http://localhost:8000/v1
模型名 GA_MODEL / OPENAI_MODEL / SUMMARY_MODEL_NAME (LLM 操作必填)
Bearer token GA_API_KEY / OPENAI_API_KEY / API_KEY 空(很多本地服务接受任意字符串)
HTTP 超时(秒) GA_HTTP_TIMEOUT 600

每次 LLM 调用都是标准的 chat.completions POST 到 {API_BASE}/chat/completions,带 model / messages / temperature / max_tokens,以及(chat_json 时)response_format: {type: "json_object"}。 如果服务器拒绝 response_format,客户端会自动重试不带这个字段并由 GraphAnything 自己用正则提取 JSON(reasoning 模型输出 <think>...</think> 也兼容)。

编程使用

from GraphAnything import open_session
from GraphAnything.llm_client import make_client

llm = make_client()                          # 读环境变量

sess = open_session(["./vault/"], preset="obsidian-vault")
sess.propose(auto_accept=True, llm=llm)
sess.run(llm=llm, out_dir="graphanything-out")

print(sess.accepted["nodes"][:3])

make_client() 也接受参数覆盖:

llm = make_client(
    api_base="http://h-100:8000/v1",
    model="Qwen3-32B-Instruct",
    api_key="local",
    timeout=900,
)

License

MIT.