ReasonGraph Cloud memory について
ReasonGraph は、AI エージェント向けのグラフ型永続メモリです。テキストからエンティティと因果関係を抽出し、文書やセッションをまたいで事実を結び付けます。複数ソースの発見や因果追跡に使え、HTTP と MCP のメモリサービスも備えています。
主な機能
- 01テキストからエンティティと因果関係を抽出
- 02独立したソース間の事実を接続
- 03セッション間のメモリ共有と矛盾解決
- 04原因、影響、反実仮想の追跡
- 05ハイブリッド検索とマルチホップ探索
- 06インメモリ、SQLite、PostgreSQL に対応
活用シーン
- 01別々の文書をまたぐ推論チェーンの構築
- 02複数のエージェントセッション間で事実を保持・発見
- 03指定時点での事実の照会
- 04根本原因とその後の影響の分析
MCP 対応
ReasonGraph は、エージェントがメモリを追加・照会できる HTTP および MCP メモリサービスを提供します。ホスト型クラウドサービスへの接続と、ローカル MCP サーバーの実行に対応します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://memory.primaxiom.ai/mcpclaude mcp add --transport http ai-primaxiom-memory-reasongraph https://memory.primaxiom.ai/mcp{"mcpServers":{"ai-primaxiom-memory-reasongraph":{"type":"http","url":"https://memory.primaxiom.ai/mcp"}}}Cursor で開く{"servers":{"ai-primaxiom-memory-reasongraph":{"type":"http","url":"https://memory.primaxiom.ai/mcp"}}}VS Code で開く{"mcpServers":{"ai-primaxiom-memory-reasongraph":{"type":"http","url":"https://memory.primaxiom.ai/mcp"}}}{"mcpServers":{"ai-primaxiom-memory-reasongraph":{"serverUrl":"https://memory.primaxiom.ai/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
https://memory.primaxiom.ai/mcp認証が必要ツール
詳細
ReasonGraph
グラフベースのAI エージェント向けメモリです。事実を取り込み、エンティティと因果関係を自動抽出し、独立したドキュメント間、さらにエージェントのセッション間のつながりを発見します。矛盾の解決、タイムトラベル、因果関係の追跡、反実仮想にも対応します。
ReasonGraph を選ぶ理由
一般的な RAG は、クエリに類似するドキュメントを検索します。ReasonGraph は永続的で更新可能なメモリであり、独立して書かれた事実の間にあるつながりを発見します。
add_texts() にテキストを渡すと、ReasonGraph はエンティティ(GLiNER を使用)と因果関係(専用の因果モデルを使用)を自動抽出し、グラフ内のノードと型付きエッジに変換します。エンティティや因果関係の連鎖を共有する事実は、互いに言及していなくてもつながります。さらに、マルチホップ探索でこれらのつながりをたどり、複数のソースにまたがる推論の連鎖を構築します。
検索機能に加え、エージェントメモリとしても機能します。スコープ/セッション(共有エンティティを介して、エージェント同士が互いのメモリから情報を発見)、矛盾の解決(新しい事実が矛盾する事実をソフトに置き換えます)、タイムトラベル(query(as_of=...))、因果関係の追跡(trace_effects / root_causes / causal_chain)、反実仮想(what_if)、さらに HTTP と MCP 経由で利用できるデプロイ可能な MemoryService に対応しています。
設定不要で、優れたデフォルトを備えています。 ReasonGraph() は、利用可能な最適なエンティティ抽出器、因果モデル、埋め込みモデル、リランカーを自動的に選択します。以下の評価結果は、これらのデフォルト設定によるものです。最先端の因果モデル(約 0.70 F1)を使うには pip install reasongraph[causal] を実行してください。グラフはこれを自動的に使用します。設定に関するセクションは、必要な場合に読むための詳しい情報であり、必読ではありません。
60 秒で使う
Claude Code / Cursor / 任意の MCP クライアント、ホスト型(EU、処理に LLM を使用しません):
claude mcp add --transport http memory https://memory.primaxiom.ai/mcp \
--header "Authorization: Bearer rgm_YOUR_KEY"
ローカル MCP サーバー(stdio、すべての処理をマシン上で実行、SQLite):
pip install "reasongraph[service,gliner,fastembed,sqlite]"
claude mcp add memory -- reasongraph-mcp
Python、プロセス内:
pip install "reasongraph[all]"
from reasongraph import ReasonGraph
graph = ReasonGraph()
graph.initialize_sync()
graph.add_texts_sync(["TSMC is building a chip fab in Phoenix, Arizona.",
"Arizona ordered water cuts for industrial users in Maricopa County."])
print(graph.discover_sync("water and chips")) # a path: water cuts -> Arizona -> TSMC fab
任意の言語、HTTP 経由(セルフホストまたはホスト型):
curl -X POST https://memory.primaxiom.ai/sessions/notes/memory \
-H "Authorization: Bearer rgm_YOUR_KEY" -H "Content-Type: application/json" \
-d '{"text": "Apple sources M-series chips from TSMC in Arizona."}'
すぐにコピーして使えるエージェント(Groq/OpenAI 互換のリサーチエージェント、1 つのメモリを共有する 2 つのエージェント、永続メモリを備えた Claude Code、LangGraph)は、
examples/agents/ にあります。
ホスト型:ReasonGraph Cloud
memory.primaxiom.ai では、このライブラリをサービスとして利用できます。サインインすると、無料キー(月 10,000 リクエスト)、リモート MCP エンドポイント、ブラウザーコンソール、プレイグラウンドを利用できます。 抽出は PrimAxiom が運用するサーバー上で小規模モデルを使って実行されます(現在は EU 内)。合成回答を求めた場合に限り、事実が LLM プロバイダーに送信されます。早期アクセス版です。
JavaScript と TypeScript
Python 以外で書かれたエージェントは、依存関係不要のクライアント
(clients/typescript)を通じてホスト型サービスを利用できます。プラットフォームの fetch を使用するため、Node 18+、
Bun、Deno、Cloudflare Workers、ブラウザーで動作します。npm install reasongraph を実行してください。
import { Memory, memoryTools } from "reasongraph";
const mem = new Memory({ apiKey: process.env.REASONGRAPH_API_KEY });
await mem.remember("scout", "TSMC is building a chip fab in Phoenix, Arizona.");
const facts = await mem.discover("What could disrupt the Phoenix fab?");
memoryTools(mem) は、フレームワークを使わずに関数を直接呼び出すエージェント向けに、実行関数が付属した OpenAI 形式のツール定義(remember、recall、why)を返します。
インストール
pip install reasongraph[all] # everything included
または、必要なものだけをインストールします。
pip install reasongraph # core: in-memory backend, NER extraction, embeddings
pip install reasongraph[gliner] # + GLiNER entity extraction + hybrid causal (default, recommended)
pip install reasongraph[causal] # + SOTA span-pointer causal model (~0.70 F1) + hybrid fallback
pip install reasongraph[gliner2] # + GLiNER2 alternative (single model does entities + causal)
pip install reasongraph[sqlite] # + SQLite backend with sqlite-vec
pip install reasongraph[postgres] # + PostgreSQL + pgvector backend
pip install reasongraph[service] # + HTTP + MCP memory service
pip install reasongraph[fastembed] # + pure-ONNX embedder / reranker (faster cold start)
ソース横断の発見
異なるトピックについての2つのレポートです。ソースAはTSMCの半導体工場を扱っています。ソースBはアリゾナ州の水危機を扱っています。どちらも、もう一方の話題には触れていません。
import asyncio
from reasongraph import ReasonGraph
source_a = [ # Tech industry report
"TSMC announced plans to build a $40 billion semiconductor fabrication plant in Phoenix, Arizona.",
"The Phoenix fab requires 10 million gallons of purified water daily to cool wafers during the chip etching process.",
"TSMC signed a long-term supply agreement with Apple to manufacture next-generation M-series processors at the Arizona facility.",
"Construction delays at the Phoenix site pushed first production to late 2025, raising concerns among TSMC's major customers.",
]
source_b = [ # Environmental report -- never mentions TSMC, semiconductors, or chips
"Arizona declared a water emergency after Lake Mead dropped to its lowest level since the 1930s, threatening water supply for millions.",
"The Arizona Department of Water Resources ordered mandatory water cuts for all industrial users in Maricopa County, where Phoenix is located.",
"Intel paused expansion of its Chandler, Arizona chip plant citing water availability concerns and rising operational costs.",
"Apple warned investors that component shortages from its Asian and North American suppliers could impact iPhone production timelines through 2026.",
]
async def main():
async with ReasonGraph() as graph:
await graph.add_texts(source_a)
await graph.add_texts(source_b)
results = await graph.query("How does the Arizona water crisis affect semiconductor manufacturing?")
for i, text in enumerate(results, 1):
source = "A" if text in source_a else "B"
print(f"{i}. [Source {source}] {text}")
asyncio.run(main())
1. [Source B] Intel paused expansion of its Chandler, Arizona chip plant citing water availability concerns and rising operational costs.
2. [Source B] The Arizona Department of Water Resources ordered mandatory water cuts for all industrial users in Maricopa County, where Phoenix is located.
3. [Source A] The Phoenix fab requires 10 million gallons of purified water daily to cool wafers during the chip etching process.
4. [Source B] Arizona declared a water emergency after Lake Mead dropped to its lowest level since the 1930s.
5. [Source A] TSMC announced plans to build a $40 billion semiconductor fabrication plant in Phoenix, Arizona.
6. [Source A] TSMC signed a long-term supply agreement with Apple to manufacture M-series processors at the Arizona facility.
結果には両方のソースが含まれています。この連鎖を含む単一のドキュメントはありません。内部で何が起きているかを説明します。
ReasonGraphは各テキストからエンティティと因果関係を抽出します(エンティティと因果関係の抽出器が必要です。例:pip install reasongraph[gliner] または [all]):
| テキスト(要約) | エンティティ | 因果関係 |
|---|---|---|
| TSMC、アリゾナ州フェニックスに工場を建設... | TSMC、フェニックス、アリゾナ州 | -- |
| フェニックスの工場には1,000万ガロンの水が必要... | フェニックス | -- |
| TSMCとAppleの供給契約... | TSMC、Apple、アリゾナ州 | -- |
| フェニックスの建設現場での遅延... | TSMC、フェニックス | 建設の遅延 -> 初回生産 |
| アリゾナ州の水不足、ミード湖... | アリゾナ州、ミード湖 | ミード湖の水位低下 -> 水危機 |
| マリコパ郡での義務的な節水措置... | アリゾナ州水資源局、フェニックス、マリコパ郡 | -- |
| Intel、アリゾナ州の半導体工場を一時停止... | Intel、チャンドラー、アリゾナ州 | -- |
| Apple、部品不足を警告... | Apple | 部品不足 -> iPhoneの生産スケジュール |
両方のソースに3つのエンティティが登場し、橋渡しノードを形成します:
| 橋渡しエンティティ | ソースAとのつながり | ソースBとのつながり |
|---|---|---|
| アリゾナ州 | TSMCの工場、TSMCとAppleの契約 | 水危機、Intelの一時停止、節水措置 |
| フェニックス | TSMCの工場、水の使用、遅延 | 産業利用者への節水措置 |
| Apple | TSMCとの供給契約 | 部品不足の警告 |
クエリの探索経路:
水危機に関するクエリ -> 埋め込みを通じて両方のソースから水関連のテキストを検索 -> Arizona と Phoenix のエンティティエッジをたどり、TSMCの水を大量に消費する工場を発見 -> TSMCの供給契約から Apple のエンティティエッジをたどり、Appleの部品不足の警告を発見します。因果関係 Lake Mead dropped -> water emergency によって、環境上の引き金と産業への影響が結び付けられます。
デモ全体:uv run python examples/cross_source_discovery.py
クイックスタート
組み込みデータセットを使用する
from reasongraph import ReasonGraph
graph = ReasonGraph()
graph.initialize_sync()
graph.load_dataset_sync("financial")
results = graph.query_sync("What caused the 2008 financial crisis?")
for i, text in enumerate(results, 1):
print(f"{i}. {text}")
graph.close_sync()
出力 -- キーワードの一致だけではなく、つながりのある推論チェーン:
1. Lehman Brothers filed for bankruptcy in September 2008 after massive MBS losses.
2. Loose lending standards fueled a housing price bubble across the United States.
3. Lehman's collapse triggered a global credit freeze as interbank lending stopped.
4. Mortgage-backed securities built on subprime loans collapsed when defaults surged.
5. The U.S. government enacted TARP, a $700 billion bailout to stabilize the financial system.
6. Banks issued subprime mortgages to borrowers with poor credit histories.
非同期API
import asyncio
from reasongraph import ReasonGraph
async def main():
async with ReasonGraph() as graph:
await graph.load_dataset("financial")
results = await graph.query("What caused the 2008 crisis?")
for text in results:
print(text)
asyncio.run(main())
機能
- ソース横断の発見 -- 共有エンティティと因果関係を通じて、独立したドキュメント間の事実を結び付けます
- 自動抽出 -- エンティティ(デフォルトではGLiNER
gliner_small-v2.5)と原因->結果の関係(専用のスパンポインター/ハイブリッド因果モデル)は、追加時に抽出されます。どちらもデフォルトで有効です。glinerがインストールされていない場合は、GLiNER2、次にBERT NERにフォールバックします - エージェントメモリ -- セッション間の発見機能を備えたスコープ/セッション、矛盾の解決(ソフトな置き換え)、過去の状態への移動(
as_of)、セマンティック重複排除、自動忘却 - 因果推論 -- 下流への影響、根本原因、方向性のある因果経路を追跡し、反実仮想の
what_ifを尋ねます - ハイブリッド検索 -- 埋め込みの類似度、キーワード(トライグラム)照合、またはその両方を組み合わせます
- マルチホップ探索 -- グラフエッジをたどり、つながりのある推論チェーンを発見します
- クロスエンコーダーによる再ランキング -- 各ホップでクロスエンコーダーを使って結果を再ランキングします(デフォルトでは
ms-marco-MiniLM-L-6-v2、ホスト型サービスでは多言語mMARCOを使用) - メモリサービス -- エージェントがメモリを共有してクエリできる、すぐに使えるHTTPおよびMCPサーバー
- 組み込みデータセット -- すぐに使えるよう、キュレーション済みの推論グラフを読み込みます
- 非同期優先 -- 同期用の便利なラッパーを備えたネイティブの非同期API
- プラグイン可能なバックエンド -- インメモリ(設定不要のデフォルト)、SQLite、またはpgvectorを使用したPostgreSQL
因果評価ケース
tests/data/causal_cases.jsonl(レビュー済み40ケース)、tests/data/causal_cases_batch2.jsonl
(さらに40ケース、8ドメイン×5、うち12ケースは英語以外)、tests/data/causal_cases_batch3.jsonl(さらに60ケース:
ドイツ語、スペイン語、フランス語がそれぞれ20ケース)、tests/data/causal_cases_batch4_trnl.jsonl(トルコ語20ケース、
オランダ語20ケース)には、それぞれ複数の情報源にまたがる理由を問う質問と正解のチェーンが含まれています。python tests/eval_causal_cases.py --cases tests/data/causal_cases_batch2.jsonlを実行してください。
デフォルトモデルを使ったbatch2のベースラインは、チェーン復元率100%、順序一致率47%、回答率100%、因果チェーン一致率65%です。
モデル
すべてのモデルスロットは差し替え可能です。以下はデフォルト設定と、ReasonGraph Cloudで使用される設定です。 いずれも小型で、CPU上で動作します。
| ステップ | ライブラリのデフォルト | ReasonGraph Cloud | 備考 |
|---|---|---|---|
| 文分割 | オフ(有効にするにはsplit="sat"または"regex") | SaT sat-3l-sm(wtpsplit) | 乱れたテキストでの境界復元率は84%で、正規表現分割器の40%を上回ります |
| エンティティ | GLiNER gliner-community/gliner_small-v2.5 | 同じ | ゼロショット、多言語対応。6言語のチェックで再現率97%、1回あたり約19 msです。REASONGRAPH_ENTITY_NORMALIZE=1(またはcanonicalizer=EntityNormalizer())を設定すると、表記の異なる形式(「Sabah」/「sabah」、「Bulk Export's」/「Bulk Export」)が1つのノードに統合されます。また、REASONGRAPH_ENTITY_CONTAINMENT=1(またはlink_contained_entities=True)を設定すると、インデックス化された先頭語検索を通じて、既存のエンティティがエンティティの全単語接頭辞に一致する、またはエンティティを拡張する場合(「malzeme」/「malzeme eksikliği)に、その事実もリンクされます。どちらもデフォルトではオフです。80ケースのbusy-tenant評価では、ルート再現率の向上は見られず、包含リンクは79%の確率で無関係なケース間をリンクしたため、実験用として残されています |
| 原因 → 結果 | Berk/causal-span-pointer-v2(ファインチューニング済みmDeBERTa-v3、オープンウェイト) | v3(現時点では非公開。目的節の方向判定は97%対20%、CNCは0.705)、および閾値0.1のトークンゲート | CausalNewsCorpusの開発データでF1値0.70。ゲートにより、因果グラフに単なる記述が含まれないようにします。REASONGRAPH_CAUSAL_ONNX=hf://owner/repo/file.onnxを設定すると、同じモデルをonnxruntime経由で実行でき、スパンは同一のままCPU上で2倍高速になります |
| 埋め込み | all-MiniLM-L12-v2 | paraphrase-multilingual-MiniLM-L12-v2(fastembed) | 事実が英語だけではない場合に切り替えてください |
| スパンのリンク | 埋め込みコサイン類似度 ≥ span_link_threshold(0.85) | スパンリンク用クロスエンコーダー(実測後にREASONGRAPH_SPAN_LINKER、ロジット ≥ REASONGRAPH_SPAN_LINK_LOGIT)を使用。類似度が見逃す言い換えられたホップを補足します(保留ケースで誤リンクゼロの場合、復元数は20件中17件で、類似度では7件) | |
| 再ランカー | cross-encoder/ms-marco-MiniLM-L-6-v2 | cross-encoder/mmarco-mMiniLMv2-L12-H384-v1 | 多言語再ランカーにより、評価でのドイツ語の発見率が62%から88%に向上しました |
| 矛盾チェック | オフ(resolve_conflicts=Trueにはリゾルバーが必要) | llama.cpp上でBerk/reasongraph-extractor-1.7b(ファインチューニング済みQwen3 1.7B、オープンウェイト)を使用し、埋め込みによる事前フィルターを適用 | 手動確認したペアでF1値0.95。CPU 2スレッドでペアあたり約0.4秒 |
| チャット/文章による回答 | なし(call_modelを独自に用意) | 外部プロバイダー。現在はGroq上のgpt-oss-120b | 大規模モデルを使う唯一のステップで、チャットを利用するか回答を求めた場合にのみ実行されます |
各スロットの評価スクリプトはtests/にあります(eval_causal_extraction.py、
eval_causal_cases.py)。結果は以下の各オプションの横に記載しています。
組み込みデータセット
| データセット | 説明 |
|---|---|
syllogisms | 古典的な三段論法の推論チェーン |
causal | エンティティ注釈付きの原因と結果の推論 |
taxonomy | 階層的な概念分類体系 |
financial | 金融危機の因果チェーン(2008年の危機、ドットコムバブル、インフレ、ユーロ圏) |
medical | 医学的な因果チェーン(心臓病、糖尿病、感染症、がん) |
analysis_patterns | データ分析の推論:シナリオの検出、手法の選択、実装パターン |
graph.load_dataset_sync("financial")
検索モード
embedding(デフォルト)は、意味に基づいてシードを見つけます。hybrid はこれに単語レベルのトライグラムチャネル(pg_trgm による厳密な単語類似度、Postgres でインデックスを利用)を組み合わせます。質問に含まれる名前、コード、数字、複合語が、その単語を埋め込みモデルが一度も見ていなくても、それを含む事実と一致します。keyword は既知の用語を検索するための、トライグラムチャネル単独のモードです。メモリループでも同じオプションを使用できます(MemoryLoop(search_mode="hybrid")、または REASONGRAPH_LOOP_SEARCH=hybrid)。デフォルトは引き続き embedding です。
測定済みなので、推測する必要はありません: 因果的な根本原因の評価(180 件、6 言語、1 つの高負荷テナント)では、hybrid は効果がなく、わずかに性能を下げます。根本原因の再現率は 9% → 7%、英語では 15% → 8%、p95 レイテンシは +22% です。これはチューニングの失敗ではなく、構造的な理由によるものです。根本原因は質問とはまったく異なる表現になるため、質問中の語句に一致すると、文脈の予算を奪い合う中間のつなぎの情報が見つかります。Hybrid が本領を発揮するケース(正確な名前、コード、部品番号、識別子)は実際にありますが、これは 検索 タスクであり、この評価では測定していません。検索形式のワークロードでは有効にし、「なぜ」という質問では無効のままにしてください。
探索の深さと方向
hops は探索の深さを制限します。causal_hops=(forward, backward) は方向ごとの深さを制限します。forward は原因 → 結果(結果)をたどり、backward は結果 → 原因(そこに至った経緯)をたどります。エンティティブリッジには影響しません。「なぜ」という質問は backward 方向なので、深さを非対称に割り当てる探索では、対称な探索では見つからない根本原因にたどり着けることがあります。
loop = MemoryLoop(graph, session="chat", causal_hops=(3, 2)) # or REASONGRAPH_CAUSAL_HOPS=3,2
デフォルトは対称(None)です。私たち自身の因果評価では、分割による違いはまったくありませんでした。そこでは、全体の hops 上限に達する前に、いずれか一方向で因果エッジを 2 つより多くたどる経路がなかったため、方向ごとの上限は一度も適用されません。これを使うのは、グラフに一方向へ 4 ホップ以上続く、純粋な原因間の長い連鎖が実際にある場合に限ってください。hops 自体を増やすことも測定しました。深さを 5 にすると、180 件中の正答数が 2 件増える一方で、データベース処理量はおよそ 2 倍になります。そのため、デフォルトは 3 のままです。
ある出来事を表す 2 つの言い回しをつなぐ
同じ出来事が、2 通りの表現で書かれることがあります。ある文では「コストが削減された」、次の文では「コスト削減」といった具合です。汎用検索用埋め込みモデルによるコサイン類似度では、これらを関連付けられません。関連付けに失敗すると因果関係の連鎖が途切れ、測定上、根本原因が失われる箇所になります。
この判断は独立した処理なので、専用のモデルを使えます。span_linker には、次のいずれかの形式を指定できます。
ReasonGraph(span_linker="bi:my-org/same-event-multilingual") # a similarity model, scored by cosine
ReasonGraph(span_linker="my-org/same-event-cross-encoder") # a cross-encoder, scored pairwise
または、同じ値を指定した REASONGRAPH_SPAN_LINKER を使います。どちらも方向を考慮した候補だけを参照します。結果のスパンが原因のスパンと比較されることはあっても、その逆はありません。span_link_top_k は、判定の前に各スパンと比較する近傍の数を設定します。デフォルトは 6 です。以前はリンカーを設定すると 10 に広げていましたが、測定の結果、これは誤りだと分かりました。341 件のケースでは、候補リストを広げると類似した表現が探索に大量に入り込み、言い換えられた連鎖での改善幅が半減し、通常の連鎖での小さな改善が小さな悪化に変わりました。候補リストを狭めることは、この一連の作業で最大の改善であり、コストもかかりません。
デフォルトでは、リンカーは埋め込みモデル独自のコサイン類似度を置き換えるため、コサイン類似度なら正しく関連付けていたリンクも失われることがあります。span_link_floor を指定すると、代わりにリンカーがリンクを追加します。コサイン類似度が作成するリンクはすべて維持され、リンカーはコサイン類似度がフロアとしきい値の間にあるペアに限って判断します。
ReasonGraph(span_linker="bi:my-org/same-event", span_link_floor=0.6) # or REASONGRAPH_SPAN_LINK_FLOOR
私たち自身のコーパスでは、フロアはどの設定でも効果なしでした。リンカーの候補集合内では、フロアが判断する範囲でコサイン類似度と学習済みモデルの判断が食い違わず、維持または除外する対象がありません。別のコーパスではそのような食い違いが生じる可能性があるため、この機能は引き続き利用できますが、測定せずに効果を期待しないでください。
コンテキストウィンドウ内に長い会話を収める
長いチャットをつなぎとめる要素は3つあります。直近のメッセージの原文、これまでの内容の要約、そして古い内容のうち、後になって関連性があると判明したものの想起です。ループはデフォルトで3つ目を処理し、最初の2つはセッションで設定します。
loop = MemoryLoop(
graph, session="support-chat",
max_history_tokens=6000, # fold once the transcript passes this
keep_tail_tokens=2000, # this much of the newest talk stays word for word
summarizer=my_model, # fn(messages, max_tokens=None) -> str; omit and old turns are dropped
summary_length_target=False, # cap the summary at its share of the budget; costs detail
summarize_in_background=True, # summarise after the reply, never before it
)
直近の N 件のメッセージではなく、トークン予算を使う理由。 固定件数は両方向で適切ではありません。1行のやり取りが10件あっても大したことはありませんが、スタックトレースを10件貼り付ければウィンドウからあふれます。予算では、実際にコストがかかるものを数えます。
ブロック単位で折りたたむ理由。 トランスクリプトが予算を超えたら、末尾より古い部分をすべて1つの要約にまとめ、末尾は原文のまま残します。メッセージ単位ではなくブロック単位で要約することで、要約処理の実行頻度を抑えられます。また、会話が予算に達しなければ、要約は一度も行われません。次に折りたたむときは、前の要約と新たに古くなったメッセージを合わせるため、要約が積み重なるのではなく、統合されていきます。
要約にかかるコストと、デフォルトで上限が設定されていない理由。 要約と原文のまま残す末尾部分は、max_history_tokens を共有します。末尾部分を数えたあとに残る容量が、要約に使える量、つまり loop.summary_budget_tokens です。モデルにその量を守らせるものはありません。後の返答で必要になる可能性がある詳細を17件含むリストを維持する条件で、qwen2.5 7Bを使い、110トークン分の容量で8回折りたたんだ結果は次のとおりです。
| 8回折りたたんだ後の要約 | 保持された詳細 | |
|---|---|---|
| 長さを指定しない(デフォルト) | 374 tokens | 17件中17件 |
summary_length_target=True | 228 tokens | 17件中11件 |
長さを指定すると、モデルはその長さに近づけようとし、そこに収めるために詳細を省きます。何も指定しないと、すべてを残そうとして容量を超えます。どちらにも代償があるため、選択は任意です。デフォルトでは詳細を残し、summary_length_target=True の場合は、プロンプトを収める必要があるときに、summary_budget_tokens を max_tokens として要約処理に渡します。messages のみを受け取る要約処理も、どちらの場合も引き続き動作します。1つのモデル、1つのトランスクリプト、1つのシードでの結果です。ご自身の環境でも改めて測定してください。
要約処理が応答のクリティカルパスに入ることはありません。 折りたたみでは、セッションがすでに持っている要約を使い、まだ要約が必要な内容を記録します。summarize_in_background を指定すると、返答の送信後に処理が行われるため、要約が反映されるのは1ターン後です。指定しない場合は、折りたたみ処理が完了を待ちます。どちらの場合も、要約処理の速度が遅い、停止している、または何も返さないといった状況でも、会話は続行できます。古いターンの文面を失うことは許容できますが、返答が滞るのは許容できないためです。
要約ではないもの。 要約は、根拠となるソースを持たないモデルによる言い換えです。そのため、独自のシステムメッセージとして追加され、根拠を伴う想起された事実と混ざることはありません。また、ここでは他の場合ほど重要ではありません。ウィンドウから外れたメッセージは observe によって事実として保存されているため、関連性があるときに意味に基づいて呼び戻されます。要約の目的は会話の連続性を保つことであり、記憶することではありません。
遡及的に指すメモ
人は原因を繰り返す代わりに、指し示してつなげます。「これでチェックアウトが壊れた」「そのためロールバックした」のようにです。抽出は文を1つずつ読み取るため、「これ」が参照するものを見つけられず、つながりが失われます。実際のインシデント報告では、文同士の因果関係のおよそ5分の1がこの種のものです。
ReasonGraph(resolve_back_references=True) # or REASONGRAPH_RESOLVE_BACK_REFERENCES=1
文頭で前の内容を指し、原因を述べる文は、その直前のメモにリンクされます。この表現は言語によって異なり、代名詞でないこともよくあります。ドイツ語やオランダ語では副詞(「dadurch」、「daardoor」)に参照が含まれ、トルコ語では格語尾(「bu nedenle」、「bundan dolayı」)で示されます。また、「as a result」や「por ello」のような接続表現だけでリンクを示す場合もあります。
デフォルトでは無効です。現状を率直にお伝えします。 生成したケースでは、これまで失われていたリンクの3分の1を誤ったリンクなしで復元し、標準評価には何も影響しません。一方、通常のトラフィックでの適合率はまだ確認されていないため、意図的に有効にして検証してください。どのルールでも解決できない限界が2つあります。スペイン語とトルコ語では主語が省略されることが多く、検出できる目印が残らないことがあります。また、トルコ語では1つの文の中で原因を表す傾向があるため、そもそも復元できるものが少なくなります。
測定済みなので、試した内容は読み飛ばせます。 汎用クロスエンコーダーのスコアは、単純なコサイン類似度を下回りました。一方、同一イベント用に特化して学習したモデルでは、両側の表現が異なるケースで根本原因の再現率が3倍になりました(1.6%から4.9%)。一方で、そもそも必要のなかったケースではわずかに低下しました(6.0%から5.0%)。このトレードオフに見合うかどうかはテキストによります。因果関係の両側で表現が異なるものが約4分の1を占めると損益分岐点に達し、一般的なドメインのメモではおよそ3分の2を占めるため、通常は約3倍の効果があります。決めつける前に、ご自身のデータの構成を測定してください。
大規模環境での再現性のある回答
10万件の事実を持つテナントで測定したところ、安心できる結果でした。実行中のサービスでは、すでに回答が再現可能です。 同じインデックスに同じ質問を2回すると、どのバージョンでも毎回同じ事実が返ります。結果内の順序も固定されており、追加コストはありません。
変動するのは再構築です。同じデータを使って独立に構築した2つのインデックスでも、検索が近似的であるため、近傍の結果にわずかな違いが生じます。そのテナントでは、2回の新規ビルド間で80個の質問のうち30個に違いがあり、そのうち4個では根本原因そのものが変わりました。単なる見た目の違いではありません。
2回の再構築の結果を一致させるには、厳密検索が必要です。その場合、再現率のレイテンシーがおよそ3.6倍になります。これはサービング時ではなく、移行時に設定するものです。
REASONGRAPH_PG_DETERMINISTIC=1 # exact search: rebuild-stable, much slower
REASONGRAPH_PG_EF_SEARCH=<n> # a wider candidate window, if you want it too
サービング時は両方とも無効のままにしてください。ストアを再構築し、置き換え前のストアと回答を一致させる必要がある場合は、最初の設定を有効にしてください。
レベルごとの走査
再現処理はシードからグラフを外側へたどります。各レベルの取得は、ノードごとに1回ずつではなく、バックエンド呼び出し1回(nearest_neighbors_many)で行います。ネットワーク越しでは再現処理のコストはラウンドトリップ数で決まり、測定では再現処理1回あたり110回のラウンドトリップが発生し、データベースへの1ホップが5 msの場合、再現レイテンシーはほぼ4倍になりました。バッチ処理に対応できないバックエンドでは、ループするデフォルトの実装が使われるため、この違いは透過的です。
1回の再現処理内では、事実のスコープ、因果関係、タイムスタンプを一度だけ取得します(ReasonGraph.request_cache()。MemoryLoop.recallによって開かれます)。再現処理では重複する事実に対して複数回の走査が行われ、ネットワーク越しでは繰り返しのたびにラウンドトリップが発生するためです。リクエストが終了するとキャッシュは破棄されるため、リクエストをまたいで古いデータが残ることはありません。また、メモ化されるのは読み取り専用のメタデータのみです。
複数の書き込み処理を実行するデプロイメント(APIと抽出ワーカーの併用など)での並行処理については、同じ行を対象とする書き込み処理同士がデッドロックしないよう、ノードとエッジのアップサートをキー順に実行します。スキーマ作成はアドバイザリーロックで直列化し、一時的な書き込みエラー(デッドロック、シリアライゼーション失敗、中断されたパイプライン)はバックオフを伴って再試行します。
# Pure embedding similarity (default)
results = graph.query_sync("credit freeze", search_mode="embedding")
# Pure keyword/trigram matching
results = graph.query_sync("credit freeze", search_mode="keyword")
# Hybrid: Reciprocal Rank Fusion of embedding + trigram rankings
results = graph.query_sync("credit freeze", search_mode="hybrid")
# Tune the RRF smoothing constant (default 60, lower = more weight to top ranks)
results = graph.query_sync("credit freeze", search_mode="hybrid", rrf_k=30)
エンティティと因果関係の抽出
エンティティ抽出と因果関係抽出は、互いに独立しており、どちらもデフォルトで有効な機能です。gliner がインストールされている場合、add_text() / add_texts() はエンティティ抽出に**gliner_small-v2.5**(高速で多言語に対応し、エンティティの再現率が最も高い)を使用し、利用できない場合は GLiNER2、次に BERT NER にフォールバックします。呼び出しごとに extractor 引数で変更できます。たとえば、より高い適合率が必要な場合は gliner_large-v2.5 を指定します。
from reasongraph import ReasonGraph, NERExtractor, GLiNER2Extractor
graph = ReasonGraph()
graph.initialize_sync()
# Default: GLiNER gliner_small-v2.5 for entities (+ the default causal model),
# falling back to GLiNER2 then BERT NER
entities = graph.add_text_sync("Apple released the iPhone in 2007.")
print(entities) # ['Apple', 'iPhone']
# Explicit: force BERT NER even if a GLiNER model is installed
entities = graph.add_text_sync("Apple released the iPhone in 2007.", extractor=NERExtractor())
# Explicit: GLiNER2 with custom entity types
gliner = GLiNER2Extractor(entity_types=["company", "product", "date"])
entities = graph.add_text_sync("Apple released the iPhone in 2007.", extractor=gliner)
# Conversational memory: ChatExtractor also captures preference/plan/topic,
# so "hard techno" or "visit" become bridgeable nodes -- not just people/places
from reasongraph import ChatExtractor
entities = graph.add_text_sync(
"I love hard techno and plan to visit Berlin.", extractor=ChatExtractor()
) # ['Berlin', 'hard techno', 'visit']
# Any callable works
entities = graph.add_text_sync("some text", extractor=lambda t: ["custom"])
因果推論(デフォルトで有効)
因果関係は主要な機能であるため、因果関係の抽出はデフォルトで実行されます
(呼び出しごとに causal=False を指定すると無効になります)。方向性のある原因→結果の関係は、
匿名のエンティティブリッジとは異なる、グラフ内の第一級の型付きエッジ(label="causes")となり、
discover() は事実ごとにそれらを返します。
graph.add_text_sync("Heavy rainfall caused severe flooding.")
# -> typed edge heavy rainfall --causes--> severe flooding
for fact in graph.discover_sync("flooding"):
print(fact["content"], fact["causes"]) # [{'cause': 'Heavy rainfall', 'effect': 'severe flooding'}]
因果関係の連鎖をたどる
原因→結果のエッジは方向性があり、第一級の要素であるため、因果グラフをたどることができます。 これはフラットなベクトルストアではできません。下流への影響をたどったり、根本原因までさかのぼったり、 2つの事実間の方向性のある因果パスを見つけたりできます。
graph.add_texts_sync([
"Heavy rainfall caused flooding.",
"Flooding caused power outages.",
"Power outages caused hospital disruptions.",
])
graph.trace_effects_sync("Heavy rainfall caused flooding.")["terminals"]
# e.g. -> ['hospital disruptions'] # downstream impact
graph.trace_causes_sync("Power outages caused hospital disruptions.")["terminals"]
# e.g. -> ['rainfall'] # upstream causes (same as root_causes_sync)
graph.causal_chain_sync("Heavy rainfall caused flooding.",
"Power outages caused hospital disruptions.")
# -> ordered causal hops, each cited to the fact that asserted it
正確なスパンは因果関係抽出器によって異なります。ある事実の結果スパンが次の事実の原因スパンと一致すると、
ホップが連鎖します。各ホップには、それを主張する事実、スコープ、および cross_session フラグが付与されます。
conflict_resolver が設定されている場合、デフォルトでは無効化済み(置き換え済み)の事実はスキップされます
(include_superseded=True を指定すると含まれます)。max_depth(デフォルトは 6)と
max_visited(デフォルトは 1000)で調整できます。エージェントには trace_memory MCP ツールと
/trace HTTP エンドポイントとして公開されます。
反実仮想:ある事実が偽だった場合、何が崩れるか
因果エッジが第一級の要素であるため、トレースを逆向きにたどる質問ができます。
ある事実が偽だった場合、どの下流の影響が崩れるでしょうか? what_if は事実を仮定上削除し(グラフは変更しません)、到達可能性を再度たどって、因果的な裏付けをすべて失った影響スパンと、別の経路を通じて存続した影響スパンを報告します。削除されるのは、削除した事実だけが裏付けているエッジです。別の事実も説明している影響は残ります。
graph.what_if_sync("Flooding caused power outages.")
# {
# 'pruned': 'Flooding caused power outages.',
# 'origin': 'Flooding caused power outages.', # walk start (== pruned unless origin= given)
# 'pruned_edges': [{'cause': 'flooding', 'effect': 'power outages'}],
# 'collapsed': [ # lost their only causal path
# {'span': 'power outages', 'fact': 'Flooding caused power outages.', 'depth': 0, ...},
# {'span': 'hospital disruptions', 'fact': 'Power outages caused hospital disruptions.', 'depth': 1, ...},
# ],
# 'survived': [], # spans an alternate path rescued
# }
上流の事実を基準に影響の崩壊を測定するには origin= を指定し、上流のどの原因が孤立するかを確認するには direction='causes' を指定します。what_if_memory MCP ツールおよび /what_if HTTP エンドポイントとして公開されています。
デフォルトの因果抽出器は、利用可能な最良のバックエンドを選択します。causal-span-model パッケージがインストールされている場合は、スパンポインターモデル(CausalPointerExtractor)を使用します。これはファインチューニング済みの mDeBERTa-v3 で、Causal News Corpus Subtask-2 の公式スコアラーで 約 0.70 F1 を達成し、主催者のベースラインである 0.627、ハイブリッド、および数ショットの LLM ベースライン(約 0.24〜0.41)を上回ります。英語で学習されていますが、推論時は多言語に対応しています(スクリプトを考慮した分割で、es/fr/de/pt/tr/ru/ar および zh/ja で検証済み)。また、因果性を判定するゲートを内蔵しているため、因果関係のないテキストには何も返しません。
内蔵ゲートは、分離型埋め込みゲートに置き換えられます。これは文の埋め込みを使った小型分類器です(causal-span-model の scripts/train_embed_gate.py で学習でき、.joblib ファイルとして保存されます)。文ごとの処理時間は 1 ミリ秒で、スパンヘッドに手を加えることなく、任意の負例の組み合わせで再学習できます。私たちの因果性評価では、内蔵ゲートよりエッジの数は少ないものの、精度が高くなりました。ローカルパス、または hf://owner/repo/file.joblib 形式の参照を指定してください。
ReasonGraph(causal_extractor=CausalPointerExtractor(
model="Berk/causal-span-pointer-v2", gate_threshold=1.0, # built-in gate off
embed_gate="hf://Berk/causal-span-pointer-v2/embed_gate_mlp.joblib",
embed_gate_threshold=0.9)) # keep P(causal) >= 0.9
causal_chain は、異なる表現で同じイベントを述べている事実同士も橋渡しします(「the system throttles performance」→「Throttling performance」、または次の原因スパンで単語が再び現れる単純なルート事実)。そのため、span_link_threshold がなくても、表現が変わった後も有向チェーンが維持されます。trace_causes(..., bridge=True) も同じ方法でさかのぼります。原因スパンから、そのイベントについて述べた他の事実の影響スパンへたどります(「the billing job ran twice whenever a payment retried」→「The billing job ran twice」)。また、独自の関係を持たない単純な事実から、それを説明する影響スパンへもたどるため、誰かが記録した症状(「the billing job started double-charging」)から、後で記録された説明へつながります。
それ以外の場合は、ハイブリッド(HybridCausalExtractor)にフォールバックします。高速でモデル不要の多言語手がかり判定が、明示的な表現や逆順の表現を正しい方向で処理し、因果を示す接続表現のない文(暗黙の因果関係)は gliner-relex-multi(Apache-2.0、mDeBERTa、約 100 言語対応)に渡します。4 種類の条件(明示的/多言語/暗黙的/逆順)を含むプローブセットでは、ハイブリッドは有向ペア再現率 100% を達成しました。各構成要素単独の 61〜79% を上回っており、互いの弱点を補っています。また、ほとんどの文ではモデルを使わないため、平均コストは低くなります。tests/bench_causal_extractors.py で再現できます。
from reasongraph import CausalPointerExtractor, HybridCausalExtractor, GlinerRelexExtractor
ReasonGraph() # best available (pointer if installed, else hybrid)
ReasonGraph(causal_extractor=CausalPointerExtractor()) # force the span-pointer model
ReasonGraph(causal_extractor=HybridCausalExtractor()) # force the hybrid
ReasonGraph(causal_extractor=GlinerRelexExtractor()) # relex model only
ReasonGraph(causal_extractor=False) # disable causal extraction
pip install reasongraph[causal] を実行すると、ポインターモデル(causal-span-model)とハイブリッド(gliner)の両方がインストールされるため、グラフはデフォルトで最先端のポインターモデルを使用し、自動的にハイブリッドへフォールバックします。どちらも利用できない場合、デフォルトでは因果関係を黙って破棄せず、一度だけ警告します。因果抽出器を解決できないとき、add_text(..., causal=True) は例外を発生させます。
取り込み時の文分割
パイプライン内のすべてのモデルは単文で学習されているため、段落を一つの事実として渡すと、エンティティ、因果スパン、検索のすべてに悪影響があります(私たちの 39 ケースの因果性評価では、チェーン再現率が 79% から 10% に低下します)。分割器を渡すと、各テキストが文ごとに一つの事実になります。
ReasonGraph(sentence_splitter="sat") # Segment-any-Text, 85 languages: pip install reasongraph[split]
ReasonGraph(sentence_splitter="regex") # dependency-free fallback (punctuation + newlines)
graph.add_texts([paragraph], split=True) # or per call; split=False keeps a text whole
サービスでは REASONGRAPH_SPLIT_SENTENCES=sat|regex を読み取ります。プッシュでは split: true/false を指定できます。
ディープメモリ統合:メモリループ
ツールもプロンプトの作成も不要です。あらゆるチャットモデルをラップすれば、すべてのやり取りがメモリになり、次の呼び出しの前に関連する情報が自動的に呼び戻されます。
from reasongraph import ReasonGraph, MemoryLoop
graph = ReasonGraph() # or your Postgres-backed graph
loop = MemoryLoop(graph, session="support-chat", max_facts=8)
history = [{"role": "user", "content": "Why did the Rotterdam warehouse lose power?"}]
reply, context = loop.chat_sync(call_model, history, system="You are a careful assistant.")
# call_model is any fn(messages) -> str: OpenAI-compatible, Claude, Ollama, llama.cpp
# context.facts -> what was recalled (with sources and cause->effect links)
# context.roots -> for why-questions, the root cause(s) the chain walks back to;
# they are spelled out in the injected block so a small model
# answers with the root, not only the nearest cause
# the question and the reply are now remembered in "support-chat"
このループは会話そのものも記憶します。保存された発話はほかの事実と同じように呼び戻されますが、ほかのすべての後に評価されます。そうしないと、直前にした質問や以前の「わかりません」が最も高いスコアを得て、すべての枠を占めてしまうためです。
graph.forget(scopes) は、セッション(またはテナント、テスト実行)を消去します。その範囲にしか関連付けられていない事実とエンティティは削除され、ほかの場所にも存在する文は削除されず、関連付けだけが解除されます。
loop.messages(history) は、呼び戻された事実をシステムメッセージとして挿入したメッセージリストを返すため、自分でモデルを呼び出したい場合に使えます。loop.observe(user, assistant) はやり取りを保存します。オプション:max_facts / max_chars(コンテキストの予算)、min_score(無関係な情報を除外)、rerank_min(その上で適用する、任意のクロスエンコーダーによるしきい値。コサイン類似度では「同じトピック」と「答えになる情報」を区別できませんが、再ランキングモデルなら区別できます。デフォルトの再ランキングモデルでは -4)、extend_query(「なぜ」という質問の因果関係の連鎖が、呼び戻された事実に記述されていない根本原因に至った場合、根本原因の背後にある単純な事実を取得するために、対象を絞ったクエリをもう1つ実行します)、bridge_causes(デフォルトで有効です。因果関係の追跡は、同じ出来事を異なる表現で記述した事実をまたぎ、単純な症状から始まります。これは、「次回の請求処理の前に気をつけることはありますか?」のような曖昧な質問が起点となる状況です。15件のインシデントを含む高負荷のメモリでは、小型の本番環境用埋め込みモデルを使った場合、このような質問で根本原因が得られる割合が33%から73%に上昇しました)、observe_user / observe_assistant、redact(保存前にテキストを削除または書き換える関数)、resolve_conflicts。ホスト型サービスでは、同じループを POST /chat として利用できます。エージェントの例:examples/agents/memory_loop_agent.py。
LangChain と LangGraph
pip install langchain-reasongraph(LangChain のパートナー形式のパッケージ。LangChain 標準のリトリーバーテストが含まれ、ソースは packages/langchain-reasongraph にあります)または
pip install "reasongraph[langchain]" を実行すると、ローカルの
ReasonGraph または reasongraph.client.MemoryClient を介したホスト型サービスで動作する3つのアダプターが追加されます。
from reasongraph.integrations.langchain import ReasonGraphRetriever, with_memory, memory_tools
retriever = ReasonGraphRetriever(target=graph) # documents = the facts the graph connects
model = with_memory(ChatOpenAI(...), graph, session="support-chat") # recall in, exchange remembered
tools = memory_tools(graph, session="agent") # remember / recall / discover for agents
ドキュメントの metadata には、ソース、事実にたどり着く際に使われた名称、原因->結果のリンクが含まれます。完全な例:examples/agents/langchain_memory.py。ツールを使う LangGraph エージェント:examples/agents/langgraph_agent.py。
チェーンとエージェント向けのメモリクラス
ReasonGraphMemory は従来の BaseMemory 形式(load_memory_variables /
save_context)なので、LangChain のメモリが使われる場所ならどこにでも組み込めます。各ターンでエージェントが受け取るものは2つです。入力に関連付けられた事実と、そのソースおよび原因->結果のリンクを含む memory、そして最も古いターンを1つの継続的な要約にまとめ、最新のターンはそのまま残してトークン予算内に収めた会話記録である history です。
from reasongraph.integrations.langchain import ReasonGraphMemory
from reasongraph.loop import make_summarizer
memory = ReasonGraphMemory(target=graph, session="ops-chat",
max_history_tokens=2000, keep_tail_tokens=800,
summarizer=make_summarizer(lambda msgs: llm.invoke(msgs).content))
seen = memory.load_memory_variables({"input": "Which version is staging on, and why?"})
seen["memory"] # "- We rolled staging back to 2.3.1 because the certificate expired. [ops-chat]\n because: ..."
seen["history"] # "Summary: ...\nHuman: How do I speed up rollbacks?\nAI: Keep the previous image warm..."
memory.save_context({"input": "..."}, {"output": "..."})
折りたたみによってモデルに表示される内容は決まりますが、何も削除されません。ウィンドウから外れたターンも事実として残り、再び関連するようになれば memory を通じて呼び戻されます。要約は save_context の後に書き込まれ、ターンの途中で書き込まれることはありません。また、要約器がなくても予算内に収まります。ReasonGraphChatMessageHistory は、RunnableWithMessageHistory 用に同じ会話記録を BaseChatMessageHistory として提供します。各ターンでエージェントに何が表示されるかを含む解説:examples/agents/langchain_memory_class.py。
高速推論(任意、純粋な ONNX)
デフォルト設定でも以下の評価品質がすでに得られるため、これは速度とメモリの最適化のみを目的としています。各モデルスロットは差し替え可能なので、PyTorch のデフォルトモデルを、品質が同等以上の CPU 最適化 ONNX モデルに置き換えられます。32 ケースの混合ドメイン評価での測定結果:
from reasongraph import ReasonGraph, FastEmbedEmbedder, FastEmbedReranker
graph = ReasonGraph(
embed_model=FastEmbedEmbedder("sentence-transformers/all-MiniLM-L6-v2"),
rerank_model=FastEmbedReranker("Xenova/ms-marco-MiniLM-L-6-v2"),
)
- 再ランキングモデル →
Xenova/ms-marco-MiniLM-L-6-v2:デフォルトの再ランキングモデルの ONNX ビルド版です。スコア(および評価品質)は同一ですが、コールドスタートは約 2.4 秒から約 0.03 秒に短縮されます。 - 埋め込みモデル →
all-MiniLM-L6-v2(ONNX):読み込みが約 2.3 倍高速になり、評価品質は同等以上です。 - ONNX のみのパイプライン:品質を同等以上に保ちながら、コールドスタートが約 3 倍高速になり、RAM 使用量が約 23%減少します。クエリごとのレイテンシーは増加します(約 12 ミリ秒から約 100 ミリ秒)。ウォーム状態のレイテンシーよりもコールドスタートとメモリを重視する場合に適したトレードオフです。
- 多言語埋め込みモデル(
paraphrase-multilingual-MiniLM-L12-v2)も選択肢として利用できますが、英語の品質は数ポイント低下します。
pip install reasongraph[fastembed] が必要です。tests/bench_pipeline.py で任意の構成をベンチマークできます。
抽出器の選択(任意)
選択する必要はありません。デフォルト(エンティティには gliner_small-v2.5、因果関係にはデフォルトのモデル)は、推奨されており、ベンチマーク済みの構成です。このセクションでは、このデフォルトの根拠と、特別なケース向けの代替案を説明します。特定の要件がある場合は、extractor 引数でエンティティモデルを切り替えてください(tests/bench_extractors.py で数値を再現できます)。
GlinerExtractor(デフォルト) -- convert-and-cache ONNX 推論を行う GLiNER v1 のゼロショット方式です(高速で、柔軟なエンティティタイプに対応します。エンティティのみを抽出し、因果関係は別のデフォルトの因果モデルが処理します)。デフォルトはgliner-community/gliner_small-v2.5です。10 言語の WikiANN ベンチマークでは、エンティティ再現率でトップ(86%。GLiNER2 は 74%)となり、1 回の呼び出しあたり約 67 ms、約 2.2 GB でした。また、GLiNER2 とは異なり、韓国語/アラビア語/トルコ語/ロシア語でも高い性能を維持します。チェックポイントは非常に重要です。古いurchade/gliner_multi-v2.1のスコアは約 12% です。モデルを固定し、tests/bench_ner_multilingual.pyでベンチマークしてください。GLiNER2Extractor-- エンティティタイプと因果関係の両方を 1 回の処理で抽出する単一モデルです。両方を 1 つのモデルで処理したい場合に適していますが、最も重く(読み込みが遅く、約 4.6 GB)、多言語のエンティティ再現率も低めです。OnnxTokenClassifierExtractor-- ONNX にエクスポートされた任意の BIO トークン分類モデルを実行し、モデル独自のid2labelからエンティティをデコードします。高速(1 回の呼び出しあたり約 30 ms)で、適切なモデルを使えば多言語にも対応します。ラベル体系はモデルに依存するため、専門の場所モデルも、カスタムの汎用 NER モデルも、コードを変更せずに利用できます。
サイズ別の比較(同じ WikiANN ベンチマーク)。大きいほど常に優れているわけではありません。
| モデル | 推論時間 | RAM | 再現率 | 適合率 | F1 |
|---|---|---|---|---|---|
gliner_small-v2.5 | 67 ms | 2.2 GB | 86% | 73% | 79% |
gliner_medium-v2.5 | 73 ms | 2.7 GB | 84% | 75% | 79% |
gliner_large-v2.5 | 142 ms | 4.8 GB | 86% | 84% | 85% |
knowledgator/gliner-x-base | 151 ms | 4.2 GB | 87% | 79% | 83% |
| GLiNER2 | 250 ms | 4.8 GB | 74% | 84% | 79% |
小型モデルは再現率で大型モデルに並びます。大型モデルはサイズを増やすことで適合率が向上し、F1 が最も高くなります。中型モデルは優位性がないため、選択肢から外してください。large-v2.5 は GLiNER2 を明確に上回ります(適合率は同等、再現率は高く、高速で、アラビア語/韓国語で大幅に優れています)。knowledgator/gliner-x-base(20 以上の言語に対応)は、small-v2.5 より再現率と適合率がわずかに高いものの、stanza と langdetect が必要で(言語ごとのモデルを実行時に取得します)、約 7 倍遅く、WikiANN の中国語再構成データでも優位性がありません。そのため、デフォルトは small-v2.5 のままです。レイテンシーより適合率を重視する場合に限り、x-base を選択してください。
gliner_small-v2.5 を ONNX 経由(GlinerExtractor(onnx=True))で実行すると、再現率を維持したまま推論時間を約 67 ms から 1 回の呼び出しあたり約 12 ms に短縮できます。これは高い再現率を保つ多言語対応オプションの中で最速です(変換結果は初回使用時にキャッシュされます)。
大まかな目安:高い再現率を保ちながら速度と RAM 使用量を最適化するなら gliner_small-v2.5(onnx=True を追加すると 1 回の呼び出しあたり約 12 ms)。全体的な品質を最優先し、多言語で GLiNER2 より確実に優れたモデルを求めるなら gliner_large-v2.5。因果関係の抽出が必要な場合に限り GLiNER2。場所に関する処理が中心で、最速の処理経路が必要なら place ONNX。
スコープ
スコープはファクトに付ける自由記述のタグ("user-alice"、"topic-economy"、"session-42")であり、パーティションではありません。グラフは共有されたままです。1 つのファクトに複数のスコープを同時に付けることができ、マルチホップ推論では、すべてのスコープにわたって共有エンティティをたどります。query() に指定したスコープで絞り込まれるのは、検索の 起点 だけです。探索では、他のスコープにある接続済みのファクトにも引き続き到達します。
await graph.add_texts(alice_facts, scopes=["user-alice"])
await graph.add_texts(economy_facts, scopes=["topic-economy"])
# One fact can belong to several scopes at once
await graph.add_texts(shared, scopes=["user-alice", "topic-economy"])
# Seeds come from user-alice; reasoning still bridges into topic-economy facts
results = await graph.query("Will it get harder to afford a home?", scopes=["user-alice"])
同じコンテンツを新しいスコープに追加すると、タグは結合されます(既存のタグが削除されることはありません)。クエリが自身のスコープのファクトにしか到達できないように厳密に分離するには、isolate=True を渡してください(マルチテナントと本番環境を参照)。デモ全体:uv run python examples/scoped_reasoning.py
バックエンド
デフォルトでは、ReasonGraph() は純粋な Python のインメモリバックエンド(MemoryBackend)を使用します。numpy 以外の依存関係がなく、どこでも動作します。永続化するには、ファイルパスを渡して JSON として保存・読み込みます。
from reasongraph import ReasonGraph, MemoryBackend
# In-memory only (default)
graph = ReasonGraph()
# In-memory with JSON file persistence (loads on init, saves on close)
graph = ReasonGraph(backend=MemoryBackend(file_path="graph.json"))
SQLite バックエンド
より大きなグラフや同時アクセスには、ベクトル検索に sqlite-vec を使用する SQLite バックエンドを使います。pip install reasongraph[sqlite] が必要です。
from reasongraph import ReasonGraph
from reasongraph.backends import SqliteBackend
graph = ReasonGraph(backend=SqliteBackend(db_path="graph.db"))
PostgreSQL バックエンド
from reasongraph import ReasonGraph
from reasongraph.backends import PostgresBackend
graph = ReasonGraph(backend=PostgresBackend(database_url="postgresql://user:pass@localhost/db"))
pip install reasongraph[postgres] が必要です。また、データベースで pgvector と pg_trgm の拡張機能を有効にしてください。
評価:複数ドメインにまたがる推論
すべての組み込みデータセット 6 件を単一のグラフ(テキストノード約 130 件、エンティティノード約 104 件、エッジ約 280 件)に読み込み、他のドメインの無関係な事実に惑わされずに、正しい因果関係の連鎖、三段論法による証明、分類階層、データ分析パターンをたどれるかどうかで、推論の品質を評価します。
32 件のテストケースでは、「2008 年の金融危機の原因を知りたい」や「インスリン抵抗性はどのように腎不全につながりますか?」、「2 つの数値列に関連性があるか確認して」のようなエージェント形式のクエリを模擬し、返された推論の連鎖が期待される正解と一致するかどうかを確認します。
ドメイン別の結果(ハイブリッド検索、top_k=5、hops=4、rerank_top_k=4):
| ドメイン | ケース数 | 連鎖の完全性 | Recall@5 | Precision@5 | ドメイン正解率 |
|---|---|---|---|---|---|
| 因果関係 | 5 | 100% | 100% | 92% | 100% |
| 金融 | 6 | 100% | 82% | 60% | 100% |
| 医療 | 5 | 100% | 92% | 76% | 92% |
| 三段論法 | 5 | 100% | 100% | 92% | 85% |
| 分類体系 | 3 | 100% | 83% | 53% | 92% |
| 分析パターン | 8 | 96% | 75% | 45% | 96% |
| 全体 | 32 | 99% | 88% | 68% | 95% |
32 件中 32 件が合格します(連鎖の完全性が 50% 以上)。分割再ランキングでは、橋渡しの発見(エンティティからテキストへのエッジ)よりも、連鎖の継続(テキストからテキストへのエッジ)を優先し、探索の焦点を保ちます。
検索モードの比較:
| モード | 連鎖の完全性 | Recall@5 | Precision@5 | ドメイン正解率 |
|---|---|---|---|---|
| 埋め込み | 99% | 88% | 68% | 95% |
| キーワード | 0% | 0% | 0% | 0% |
| ハイブリッド | 99% | 88% | 68% | 95% |
キーワードのみのモードのスコアが 0% なのは、評価クエリが自然言語の質問であり、データセットの宣言文と部分文字列が一致しないためです。これは想定どおりです。キーワード検索は、質問への回答ではなく、既知の用語の検索を目的としています。
再現方法:uv run python tests/eval_financial_reasoning.py
API リファレンス
ReasonGraph(backend=None, embed_model=None, rerank_model=None, forget_after=30, forget_every=None, synthesizer=None, causal_extractor=None, isolate_traversal=False, conflict_resolver=None)
causal_extractor:Noneの場合、利用可能な最適な因果抽出器を遅延読み込みします(causal-span-modelがインストールされている場合は span-pointer モデル、そうでない場合はハイブリッド)。Falseの場合は因果抽出を無効にします。extract_causalを備えた呼び出し可能オブジェクトまたはオブジェクトを指定した場合は、それを使用します。isolate_traversal:スコープ付きクエリの探索をそのスコープ内に限定するかどうか(マルチテナント)の、グラフ全体に適用されるデフォルト設定です。オフの場合はスコープをまたいだ探索が可能です。query(..., isolate=...)で呼び出しごとに上書きできます。conflict_resolver:書き込み時の矛盾解決(ソフト置換)と、読み取り時の廃止済み事実のフィルタリングを有効にします(マルチテナントと本番環境を参照)。
取り込み
| メソッド | 説明 |
|---|---|
add_nodes(nodes, scopes=None) | (content, type) のタプルをグラフに追加します |
add_edges(edges) | コンテンツのエッジ (from, to) または (from, to, label) を追加します(label の例:"causes") |
add_text(text, extractor=None, scopes=None, causal_extractor=None, causal=None, dedup_threshold=None, resolve_conflicts=None) | エンティティと因果関係を抽出してテキストを追加します。causal=False で無効化し、True で強制します(利用できない場合はエラーになります)。dedup_threshold で類似度の高い重複を除外し、スコープを統合します。conflict_resolver が設定されている場合、resolve_conflicts で矛盾する事実をソフト置換します |
add_texts(texts, extractor=None, causal_extractor=None, scopes=None, causal=None, dedup_threshold=None, resolve_conflicts=None) | add_text の一括処理版です(デフォルトで因果関係の抽出が有効です) |
取得
| メソッド | 説明 |
|---|---|
query(query, top_k=5, hops=4, rerank_top_k=4, search_mode="embedding", rrf_k=60, recency_weight=0.0, scopes=None, isolate=None, include_superseded=False, as_of=None) | グラフを検索してたどります。recency_weight を [0,1] に設定すると、順位付けに新しさを反映します。scopes でシードを絞り込みます(isolate=True でない限り、探索はスコープをまたいで続きます)。as_of=<datetime> で、その時点で有効だった状態を表示します。include_superseded=True で廃止された事実も含めます |
query_detailed(...) | query と同じシグネチャですが、しきい値設定や重複排除に使えるよう、各ヒットについて {content, score, created_at, scopes} を返します |
discover(query, top_k=5, hops=4, search_mode="embedding", rrf_k=60, scopes=None, max_results=10, max_visited=1000, isolate=None, include_superseded=False) | query と同様ですが、接続パス を返します。各事実がブリッジとなるエンティティを介してシードにどう結び付くかを示し、スコープをタグ付けして、セッションをまたぐリンクに印を付け、各事実の有向 causes 関係を列挙します。探索は max_visited 個のノードに達すると停止します |
answer(query, use_discover=True, top_k=5, hops=4, search_mode="embedding", scopes=None, max_results=10) | プラグイン可能な synthesizer を使い、取得した事実やパスを論理的な自然文に言い換えます |
因果推論
| メソッド | 説明 |
|---|---|
trace_effects(content, max_depth=6, scopes=None, isolate=None, include_superseded=False, max_visited=1000) | 因果関係を前向きにたどり、下流への影響を {origin, chain, terminals} として返します |
trace_causes(content, ...) | 因果関係を後ろ向きにたどり、content に至った要因を調べます |
root_causes(content, ...) | content の根本原因にあたるスパン(後ろ向き探索の終端)を返します |
causal_chain(from_content, to_content, max_depth=6, scopes=None, isolate=None, include_superseded=False) | 2つの事実をつなぐ順序付きの因果関係の段階を返します。該当するものがない場合は None を返します |
what_if(content, origin=None, direction="effects", max_depth=6, scopes=None, isolate=None, include_superseded=False, max_visited=1000) | 反実仮想分析を行います。事実を除外し、下流のスパンを collapsed(消滅)と survived(残存)に分けて報告します |
更新、忘却、時間
| メソッド | 説明 |
|---|---|
delete(content, purge_orphans=False) | コンテンツが完全一致するノードと、そこに接続されたエッジを削除します。purge_orphans=True にすると、孤立したエンティティも削除します |
supersede(old_content, new_text, extractor=None, purge_orphans=False) | 古くなった事実を置き換えます。new_text を追加してから old_content を削除します |
supersession_history(content) | 事実の {supersedes, superseded_by} の履歴を監査します |
delete_stale() | forget_after 日以内にアクセスされていないノードを削除します |
maybe_forget() | delete_stale() を間隔を空けて実行します。forget_every 秒に最大1回の頻度で削除を行い、forget_every が None の場合は何もしません |
データセットと確認
| メソッド | 説明 |
|---|---|
load_dataset(name) | 組み込みデータセットを読み込みます |
get_all_nodes(scopes=None) / get_all_edges() | グラフの内容を確認します(ノードはスコープで絞り込み可能です) |
ライフサイクルはinitialize()/close()で管理するか、async with ReasonGraph() as graph:を使用します。すべてのメソッドは非同期で、それぞれ同じパラメーターを取る_sync版もあります(例:query_sync、what_if_sync、add_text_sync)。 |
embed_modelには、モデル名(str)、SentenceTransformer、またはテキストをエンコードする任意のオブジェクト/呼び出し可能オブジェクトを指定できます。エンコーダーはstrを受け取って1つのベクトルを返すか、list[str]を受け取って各テキストにつき1つのベクトルを返す必要があります。出力形式はnumpy、torch、listのいずれでも使用できます。これにより、2つ目のスタックを読み込まずに、ホストで既に稼働している埋め込みモデルを再利用できます。
def encode(text_or_texts):
# reuse your own embedding library; return list[float] or list[list[float]]
...
graph = ReasonGraph(embed_model=encode)
エージェントメモリサービス
すぐに使えるサービスを利用すると、reasongraphを複数のエージェントで共有・発見できるメモリとして活用できます。ナレッジセッションはスコープです。エージェントは自身のセッションにメモリを追加し、クエリはそのセッションを起点にしますが、探索はすべてのセッションにまたがります。つまり、共有エンティティを介して、エージェントは互いのメモリにあるつながりを発見できます。pip install reasongraph[service]を実行してください。
from reasongraph.service import MemoryService
from reasongraph.backends import PostgresBackend
service = MemoryService(backend=PostgresBackend("postgresql:///memory"),
synthesizer=my_small_llm) # synthesizer is optional
await service.push("research-bot", "TSMC is building a chip fab in Arizona.")
await service.push("news-bot", "Arizona declared a water emergency.")
# research-bot discovers news-bot's fact via the shared 'Arizona' entity
paths = await service.discover("Arizona", session="research-bot")
answer = await service.answer("Arizona", session="research-bot") # logical free text
HTTP(reasongraph.service.http.create_app)またはMCP(reasongraph.service.mcp_server.create_mcp)経由で公開できます。HTTPのquery/discoverエンドポイントでは、フリーテキストのanswerを追加するsynthesizeフラグを指定できます。デモのuv run python examples/agent_memory_service.pyでは、5つのエージェントセッションにわたって経済/サプライチェーン/エネルギー/医療/政策に関する情報を追加し、市場についてのクエリから、他のエージェントが記録した台湾の干ばつや半導体工場にたどり着く様子を示します。
HTTPエンドポイント:POST /sessions/{session}/memory(および/batch。近接する事実に矛盾がないか確認するにはresolve_conflicts: trueを指定します)、/query(時間を遡って検索するためのas_ofとinclude_supersededに対応)、/discover、/causal_chain、/supersede、/delete、/history、/trace、/what_if、/forget、GET /sessions、/stats、さらに/healthと/readyのプローブ。
MCPツール:push_memory、query_memory、query_memory_detailed、discover_connections、causal_chain_memory、trace_memory、what_if_memory、answer、update_memory、delete_memory、memory_history、forget_stale、list_sessions
シンセサイザー
answer()とsynthesizeフラグは、取得した事実とそのつながりの経路を、筋の通ったフリーテキストに言い換えます。コア部分はモデルに依存しません。任意のcallable(query, context) -> str、または付属のアダプターを指定できます。
from reasongraph import TemplateSynthesizer, PromptSynthesizer, TransformersSynthesizer
ReasonGraph(synthesizer=TemplateSynthesizer()) # deterministic, no model
ReasonGraph(synthesizer=PromptSynthesizer(my_generate)) # bring any LLM: generate(prompt) -> str
ReasonGraph(synthesizer=TransformersSynthesizer()) # local small LLM (Qwen2.5-0.5B-Instruct)
PromptSynthesizerはプロンプト(質問+事実+セッションをまたぐ橋渡し情報)を組み立て、指定したgenerate(同期または非同期)を呼び出します。TransformersSynthesizerは、sentence-transformersによって既に導入されているtorch/transformersスタックを使い、小型の指示追従モデルをローカルで実行します。
デプロイ
環境変数に基づくエントリーポイントが、バックエンド、埋め込み生成器、合成器を環境変数から設定します。Docker で Postgres を使用するスタックを起動します。
docker compose up --build # Postgres (pgvector) + the service on :8000
curl localhost:8000/stats
または、直接サービスとして起動します(pip install reasongraph[service] により、コンソールスクリプト reasongraph-serve と ASGI ファクトリーが追加されます)。
REASONGRAPH_BACKEND=postgres \
REASONGRAPH_DATABASE_URL=postgresql:///memory \
REASONGRAPH_SYNTHESIZER=template \
reasongraph-serve # or: uvicorn reasongraph.service.app:create_app_from_env --factory
| 変数 | デフォルト | 用途 |
|---|---|---|
REASONGRAPH_BACKEND | memory | memory | sqlite | postgres |
REASONGRAPH_DATABASE_URL | -- | Postgres の URL、sqlite のパス、または memory の JSON パス |
REASONGRAPH_EMBED_MODEL | built-in | モデル名。純粋な ONNX を使用するには、接頭辞に fastembed: を付けます |
REASONGRAPH_SYNTHESIZER | template | none | template | transformers |
REASONGRAPH_SYNTH_MODEL | built-in | transformers 合成器用の指示モデル |
REASONGRAPH_FORGET_AFTER / REASONGRAPH_FORGET_EVERY | 30 / off | 自動忘却の期間(日数)とスイープ間隔(秒)。間隔を設定すると、サービスはバックグラウンドタスクでスイープを実行します。 |
REASONGRAPH_ISOLATE | off | クエリのセッション内に探索範囲を限定します(マルチテナント)。オフにすると、セッションをまたいだ発見が可能です。 |
REASONGRAPH_RESOLVE_CONFLICTS | off | デフォルトの NLI リゾルバーを使った矛盾解決(ソフトな置き換え)を有効にします。 |
REASONGRAPH_API_KEY | -- | 設定すると、データエンドポイントでキーが必要になります(Authorization: Bearer または X-API-Key)。/health と /ready は引き続き公開されます。 |
REASONGRAPH_DEFER_EXTRACT | off | エンティティ/因果関係の抽出をバックグラウンドワーカー(イベントループ外)で実行し、プッシュが即座に返るようにします。 |
REASONGRAPH_SPAN_LINK_THRESHOLD | off | コサイン類似度のしきい値(例:0.85)。この値を超える場合、新しい原因/結果スパンを既存の因果スパンに same_as で関連付けます。これにより、同じ出来事を異なる表現で述べた事実をまたいで trace_* / causal_chain を実行できます。 |
REASONGRAPH_CAUSAL_MODEL | berk/causal-span-pointer-mdeberta | スパンポインターモデルの HF リポジトリ ID またはローカルディレクトリ。 |
REASONGRAPH_CAUSAL_GATE_THRESHOLD | 0.5 | 組み込みゲート:ポインターが判定を棄却する P(non-causal) のしきい値。1.0 にすると無効になります。 |
REASONGRAPH_CAUSAL_EMBED_GATE | off | 埋め込みゲート分類器のパス、または hf://owner/repo/file.joblib。REASONGRAPH_CAUSAL_EMBED_GATE_THRESHOLD(デフォルトは 0.9)未満のテキストには関係が付与されません。 |
REASONGRAPH_DEDUP_THRESHOLD | off | コサイン類似度のしきい値(例:0.95)。この値を超える場合、プッシュされた事実は既存の事実の言い換えとして扱われ、スコープが統合され、新しいデータは保存されません。 |
REASONGRAPH_HOST / REASONGRAPH_PORT | 0.0.0.0 / 8000 | reasongraph-serve のバインドアドレスとポート。 |
実際のマルチエージェント並行処理には、永続バックエンド(PostgresBackend)を使用してください。
マルチテナントと本番環境
デフォルトではグラフは共有されています。スコープを指定したクエリはセッション内の情報を起点としますが、探索はセッションをまたいで行われます。これがセッション間の情報発見機能です。テナント間の機密性を確保するには、トラバーサル分離を有効にして、クエリが自身のセッションの事実だけに到達できるようにします。
ReasonGraph(isolate_traversal=True) # graph-wide default
graph.query("...", scopes={"tenant-a"}, isolate=True) # or per query
その他の本番環境向け制御:
- 認証:
create_app(service, api_key="...")(またはREASONGRAPH_API_KEY)により、すべてのデータエンドポイントを保護します。MCP サーバーでも同じツールを利用できます。 - 構造化された結果:
query_detailed(...)(および HTTP のdetailedフラグ/query_memory_detailedMCP ツール)は、閾値判定、重複排除、「 に記憶」といった用途に使える{content, score, created_at, scopes}を返します。 - 消去:
delete(content, purge_orphans=True)/supersede(..., purge_orphans=True)は、削除によって孤立したエンティティ(忘れられる権利)も削除します。共有エンティティは残ります。delete_memory/update_memoryMCP ツールとして利用できます。 - 意味的な重複排除:
add_text(..., dedup_threshold=0.95)は、ほぼ重複する言い換えを蓄積する代わりに除外し、保持された事実にスコープを統合します。 - 矛盾の解決:
ReasonGraph(conflict_resolver=NLIConflictResolver())(またはREASONGRAPH_RESOLVE_CONFLICTS=1)を指定すると、新しい事実と矛盾する事実をソフトに置き換えます。supersedesエッジにより、古い事実はデフォルトのquery/discoverによる想起から除外されますが、監査可能な状態に保たれ、include_superseded=Trueで取得できます。supersession_history(fact)で、何が何に置き換えられたかを確認できます。リゾルバーは差し替え可能です(contradictions(new, candidates)を持つ任意のオブジェクト)。NLIConflictResolverのクロスエンコーダーは LLM を必要としませんが、補完関係にある事柄も過剰にフラグ付けする場合があります(「ミュンヘンで働いている」と「ベルリンに住んでいる」を矛盾として扱います)。一方、LLMConflictResolver(generate)は任意の LLM を使用でき、より正確です。ソフト置換は意図的に取り消し可能です。事実を再度表明すると、その事実は復活します。また、query(..., as_of=<datetime>)を使うと、指定時点で有効だった状態にタイムトラベルできます(各事実はcreated_at/invalid_atの有効期間を持ちます)。エージェント向けにはmemory_historyMCP ツールおよび/historyエンドポイントとして利用できます。 - ヘルスチェック:オーケストレーションのプローブ向けに、
/health(稼働状態)と/ready(準備状態)を利用できます。 - Postgres は HNSW コサインインデックスを作成するため、ベクトル検索は逐次スキャンではなく、インデックスによって高速化されます。
- 速度:
tests/bench_speed.pyは、設定可能なグラフサイズとバックエンドで書き込みスループットと読み取りレイテンシー(query/discover/trace、p50/p95)を測定します(モデルを使わない計測には--fakeを指定します)。実モデルを使ったインメモリー環境での参考値は、query が約 14ms、discover が約 7ms、因果トレースが p50 で約 3ms です。
協業について
独自データで ReasonGraph を利用したい方、ホステッドサービス(memory.primaxiom.ai)として利用したい方、またはエージェントに組み込みたい方は、ぜひご相談ください。PrimAxiom Labs は企業向けに AI システムを構築・運用しています。まず短期間の有償スコーピングを行い、その後、4 週間のパイロットを実施します。 [email protected] までメールでお問い合わせください · primaxiom.ai
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。