安装
pip install hypgraph # engine, CLI, JSON API, UI — standard library only pip install "hypgraph[mcp]" # + the MCP server (FastMCP)
Python 3.10+。每份记录一个 SQLite 文件(Graph("research.hypgraph")),或用于测试和 notebook 的内存版 Graph()。
模型
有类型的节点 — 问题、假设、实验、运行、结果、主张、来源、审查、决策 — 由端点受约束的有类型链接相连(supports、challenges、requires、tests、produced、replicates、based_on …)。所有表都只追加;每次写入都是 SHA-256 链中的一个事件。不存储任何现状。每次读取都会推导:
- 审查 — 已核查 / 未核查 / 有争议 / 过时,依据审查者对当前版本的裁定;
- 风险 — 上游已倒下的前提(
AT RISK)、依据已变动的决策(REVISIT)、全部支撑已倒下(UNSUPPORTED); - 独立证据线 — 不共享运行、数据工件或来源的支撑;
- 证据 — 最强的一条线:智能体报告 → 仪器记录 → 已复现 → 独立实现 → 新数据 → 外部来源。
完整规则见记录格式;hypgraph schema --json 会打印词汇表。
策略与角色
from hypgraph import Graph, Policy
POLICY = Policy(
reviewers={"critic", "stats-reviewer"}, # whose verdicts count (an investigation can add its own)
instrument="runner", # the only author whose kind=lab runs are "recorded" evidence
operator="operator", # revises anything, settles disputes
importer="importer", # brings legacy records in, with their original dates
)
g = Graph("research.hypgraph", policy=POLICY)author=。凡是智能体能接触到图的地方,都在你这一侧固定它的作者并拒绝 POLICY.reserved — 内置的 MCP 服务器和 HTTP API 就是这么做的。一种适用于智能体团队的模式:
| 在你系统中的角色 | 在 HypGraph 中 |
|---|---|
| 工作智能体(研究员、分析员) | 各自使用自己的作者名;它们的主张会被核查;它们的审查是评论 |
| 批评者 / 审查者智能体 | reviewers;它们的裁定决定现状;从不针对它们自己的节点 |
| 执行代码的作业执行器 / 沙箱 | instrument:用哈希记录运行,使结果算作已记录 |
| 你,或代表你行事的编排器 | operator |
接入智能体
MCP
每个智能体身份一个服务器进程 — 作者在启动时固定:
hypgraph --db research.hypgraph --as critic mcp # stdio hypgraph --db research.hypgraph --as worker-1 mcp --transport http --port 8766 # streamable HTTP
或者在进程内构建(自定义策略、你自己的认证):hypgraph.mcp.build(graph, author="worker-1") 返回 FastMCP 服务器。
可运行的示例,同一个故事以六种方式集成(LangChain、LangGraph、PydanticAI、CrewAI、OpenAI Agents SDK、Claude Agent SDK):examples/frameworks。每个都可以用脚本化模型离线运行,或用 --real 在真实模型上运行。
Agent Skill
hypgraph skill --install 会写出 .claude/skills/hypgraph/SKILL.md:方法、各类拒绝及其修正方式,通过 CLI 使用。
你自己的工具
任何接受 Python 函数作为工具的框架(Claude Agent SDK、LangChain、LangGraph、OpenAI Agents …)— 返回拒绝文本,让模型能据此行动:
from hypgraph import GraphError
def add_claim(statement: str, scope: str, result: str, measurements: list[dict], why: str) -> str:
"""Add a claim supported by a result; every number in the statement must be bound in measurements."""
try:
n = g.create(author=AGENT_NAME, type="claim", inv=INV,
fields={"statement": statement, "scope": scope, "measurements": measurements},
links=[{"rel": "supports", "from": result, "why": why}])
return f"Added {n['code']}: {n['state']['sentence']}"
except GraphError as e:
return f"Refused — fix this and retry:\n{e}"在任务开始时把 g.report(inv)["markdown"] 或 MCP 文本 overview 放进智能体的上下文,让它先读到已确立的内容,而不是重新推导。
记录运行
from hypgraph import file_sha256
data, code = file_sha256("evals/heldout.jsonl"), file_sha256("eval.py")
a_data = g.create(author="runner", type="artifact", inv=INV, fields={**data, "format": "jsonl"})["id"]
a_code = g.create(author="runner", type="artifact", inv=INV, fields={**code, "format": "py"})["id"]
run = g.create(author="runner", type="run", inv=INV, fields={"kind": "lab", "state": "succeeded", "seed": 7},
links=[{"rel": "uses", "to": a_data, "data": {"role": "data"}},
{"rel": "uses", "to": a_code, "data": {"role": "code"}}])["id"]
res = g.create(author="runner", type="result", inv=INV, links=[{"rel": "produced", "from": run}],
fields={"summary": "Held-out accuracy, fine-tune vs baseline.",
"values": {"finetune": {"k": 1624, "n": 2000}, "baseline": {"k": 1568, "n": 2000}}})["id"]工件按内容寻址(相同字节,一个节点),因此用同样数据算出的两个结果会自动合并为一条证据线。重新运行会把 replicates 链接到 data.differs(new_seed、new_impl、new_data …),并提升证据等级。
配置与工作流
在调查上设置一个配置,记录就会执行该学科的规则 — 对于 @2 配置,还会执行它的工作流:带关卡的阶段、什么会使证据失效、diff、实例、来源或仓位必须具备的有类型形式。阶段和现状一样,在每次读取时推导。
inv = g.create(author="operator", type="investigation",
fields={"title": "Issue 412", "objective": "Fix the importer and prove it.", "profile": "software@2"})["id"]
q = g.create(author="operator", type="question", inv=inv, fields={"text": "Does the importer keep quoted commas?"})["id"]
g.stage(q) # {"stage": "implemented", "index": 2, "of": 6, "complete": False,
# "next": "no live artifact kind=diff (meta: base_sha, head_sha, files) part_of Q1", "gates": [...]}
g.stages(inv) # one row per live question; GET /api/graph/stages?inv=… · MCP tool: stage
g.completion(inv) # the profile's criteria for the whole investigation- 关卡是谓词。
hypothesis_stated、preregistered、diff_registered、tests_pass_current、backtested、positioned、still_valid、solved、result_reviewed… — 也可用作工单的done_when。 - 什么会使之失效。除前提外,工作流还把
uses(修正后的数据文件、被取代的 diff 或实例)或cites(被撤回的来源)加入到使依赖项有风险的条件中 — 按配置区分,因此@1下的记录保持原有的现状不变。 - 时效。如果某个结果的运行使用了现已被取代的工件,或其
valid_until已过,它就是过时的;当支撑一条主张的所有结果都过时,主张也过时。基于过时证据的核查不满足reviewed。 - 有类型的形式。
artifact.kind+meta(diff需要 base_sha、head_sha、files)、source.kind、带 size、stop、review_date、paper 的decision.kind=position— 不完整则被拒绝。重新记录相同字节会给无类型的工件加上类型,并添加所指定的链接。 - 诚实的结局。一个已核查的
inconclusive回答、一项no_position决策、一次已验证的失败(仪器记录的阴性结果,已核查)都能完成一个仅靠关卡永远无法完成的问题。
每种工作流所依据的方法,以及每个关卡背后的决策,在 docs/workflows 中各有一页。HypSwarm 的调度器正是据此为每个问题下达阶段工单。
做法:站得住的评估报告
- 预注册。在运行前建立一个实验,用
tests链接到每个假设(“微调更好”、“没有差异”),每个都带data.expected。 - 记录运行,方法如上;把计数以
{k, n}的形式写进结果的值中,而不只是百分比。 - 用测量来主张。“2,000 中 1,624,对比 1,568”是绑定的;没有结果字段对应 5 的“好 5 个点”会被拒绝。
- “没有差异”需要检验力。预埋一个已知效应(在预测的副本中注入 2 个点的差异),证明在这个样本量下比较能检测到它,并把该结果标记为
power: "demonstrated"。没有这一步,就把主张记录为inconclusive— 记录会坚持这一点。 - 审查。一个批评者智能体在保存的预测上重新运行评估器;它的
pass或fail被固定到这条主张的这个版本。 - 报告。
g.report(inv)["markdown"]是报告开头的事实表;它不能重述已撤回的主张。
成本
def spend(inv, tasks, since=None): # your meter: model calls per task id
rows = ledger.calls(task_ids=tasks, since=since)
return {"usd": sum(r.usd for r in rows), "calls": len(rows), "input_tokens": ..., "cached_tokens": ...,
"output_tokens": ..., "by_task": [{"task_id": t, "usd": ...} for t in tasks]}
g = Graph("research.hypgraph", policy=POLICY, spend=spend)
with g.writing_for(task_id): # events carry the task
g.create(...)
g.cost(inv) # $ for the investigation, per node, per verdict, and since the record last movedHTTP 与界面
hypgraph serve --db research.hypgraph # HypGraph UI + JSON API on 127.0.0.1:8765, read-only hypgraph serve --db research.hypgraph --writable # + POST /api/graph/write
在你自己的应用中(示例为 FastAPI;任何框架都可以):
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from hypgraph.server import dispatch
from hypgraph.ui import static_dir
app = FastAPI()
app.mount("/hypgraph", StaticFiles(directory=static_dir(), html=True))
@app.get("/api/graph/{path:path}")
def graph_api(path: str, request: Request):
status, body = dispatch(g, "GET", "/" + path, dict(request.query_params))
return body # (set the status code too)界面不需要框架,也没有构建步骤:HypGraph.mount(el, {source: HypGraph.HttpSource('/api/graph')}),或完全不用服务器的 HypGraph.BundleSource(bundle)。它实时跟随 GET /api/graph/stream,而 HypSwarm 运行的遥测(<record>.telemetry.jsonl)会加入每次模型和工具调用。hypgraph export --telemetry 会把它放进记录包以便回放,位于哈希链之外;{play: true} 以回放模式打开。用 CSS 变量 --hg-* 设置主题。在在线示例中查看。
CI 中的记录包
hypgraph export -o record.bundle.json # every event as the exact string that was hashed hypgraph verify record.bundle.json # exit 1 if anything was edited
发布结果时,把记录包的 head 哈希公布在你无法控制的地方(标签、论文、工单):之后经过该哈希的记录不可能改写任何更早的内容。审查者无需安装任何东西即可在 /verify 上检查记录包。
审查报告
大多数炒作存在于最终报告中,而不是记录里。hypgraph check 对照记录读取 markdown,出错时以 1 退出,因此智能体交付的摘要不能与真正被证明的内容相矛盾:
hypgraph check summary.md # errors fail hypgraph check --strict summary.md # warnings (unsourced numbers …) fail too
| 错误 | 能发现 |
|---|---|
REPORT_OVERSTATES_STANDING | 对记录中未核查、有争议或有风险的主张使用“已确立”/“已确认” |
REPORT_CITES_WITHDRAWN | 把已撤回的主张当作仍然成立来引用 |
REPORT_UNKNOWN_CODE | 引用不存在的主张或结果 |
REPORT_ABSOLUTE_UNBACKED · REPORT_ABSENCE_UNBACKED · REPORT_SIGNIFICANCE_UNBACKED | 背后没有任何引用的从不 / 无效应 / 显著 |
警告:没有任何结果包含或蕴含的数字、被省略的争议、被取代的引用、没有引用的因果表述。代码块、行内代码、URL、引用的段落、否定(“无法证明”)和指令(“绝不要使用评估集”)不被视为主张 — 已在二十多份真实报告上校准,这些报告都对照其所报告的活跃记录进行了检查。在 Python 中:g.check_text(text, inv);通过 HTTP:POST /api/graph/check;面向智能体:MCP 工具 check_report。
拒绝日志
每条被拒绝的主张都会被记录 — 作者、陈述、代码 — 当同一作者以诚实版本回来时标记为已修正。这是别人无法给你的数字:你的智能体多常试图过度主张、哪些规则拦住了它们、哪些它们悄悄放弃了。
hypgraph refusals # per author and rule, fixed vs open hypgraph refusals --author analyst # one agent's refusals in full
只追加,有自己的哈希链(g.verify_refusals()),与记录的链分开。在 Python 中:g.refusal_report(inv);HTTP GET /api/graph/refusals;MCP refusal_log;以及 HypGraph 概览中被拒绝过度主张的计数。
性能
| 节点 | 推导全部现状 | 读取一个节点 | 写入 | 验证链 |
|---|---|---|---|---|
| 1,001 | 0.047 s | 0.1 ms | 5.7 ms | 0.028 s |
| 3,301 | 0.095 s | 0.07 ms | 6.0 ms | 0.07 s |
| 10,001 | 0.37 s | 0.07 ms | 11.4 ms | 0.21 s |
纯 Python,在一台 Windows 笔记本上用 python dev/bench.py --nodes N 测量(Python 3.13,hypgraph 0.6)。其记录是一项调查,包含问题、绑定到值的结果、由此推导的主张,以及对其中一部分的审查;推导与记录以相同速度增长。一次写入的开销取决于它触及的内容:快照共享未触及的数据,写入无法触及的每个节点的缓存现状都会保留(已用随机化测试套件对照完整重建进行检查)。写入的大部分时间是 SQLite 提交到磁盘。在你的机器上、用你的规模运行基准测试。