🪡この春、マルチエージェントOSSをゼロから作ってApache-2.0で公開した話
Zennfes Spring 2026「この春、始めたこと」エントリ記事です。
TL;DR
2026 年春、マルチエージェント・オーケストレーター OSS「Praxia」 を 1 ヶ月でゼロから作って公開しました(Apache-2.0)。
- 🚀 PyPI:
pip install praxia
—https://pypi.org/project/praxia/ - 📦 GitHub:https://github.com/praxia-dev/praxia
- 🎬 60 秒デモ:https://youtu.be/o_6NbjJU1AA
- 🌐 ランディング:https://praxia.tools/
差別化のコアは「個人 → 組織へのメモリ自動昇格」。シニアエンジニアが磨いた「効くプロンプト」が個人の引き出しに留まる問題を、5 層メモリスタック + 3 経路評価エンジン で解いています。
何を「始めた」のか — 春の決断
2025 年末から、LangChain / CrewAI / AutoGen を業務で触ってきて、ある 構造的な違和感 がずっと残っていました。
エージェントの精度を本当に分ける要素は、ライブラリ選定でもモデル選定でもなく、
「ドメイン特化の試行錯誤の蓄積」ではないか?
そしてその蓄積は、ほぼ必ず特定のシニアの頭の中(Cursor / VSCode / Obsidian)に閉じ込められている。退職と同時に蒸発する暗黙知に、汎用フレームワークは無力 でした。
2026 年 4 月、本業の合間にコードを書き始めました。1 ヶ月後、
v0.1.0を PyPI と GitHub に公開しました。
なぜ既存フレームではダメだったのか
実際に試した上での 4 つの壁:
| 壁 | 何が起きていたか |
|---|---|
| 設定の複雑さ | 「とりあえず動く」までに 2-3 日。本番判断が下せない |
| 暗黙知が届かない | 効くプロンプトはシニアの個人空間に閉じている |
| 評価のエビデンス不足 | 「動く」が「効く」を保証しない |
| エージェントが停滞する | 一度作ったらフィードバックループが回らない |
特に 2 番目が深刻でした。汎用エージェントフレームは「強い primitives」は提供しますが、「組織に知識を蓄積していく」プロセス自体は実装者の責任 に丸投げされています。
Praxia のコア設計 — 5 層 + 3 経路
ここからは技術選択の話。
5 層メモリスタック
L1 PersonalMemory 個人ごと(JSON / Mem0 / Letta / Zep / Hindsight / LangMem の 6 backend) L2 PromotionEngine 夜間バッチ。L1 → L3 への昇格判定 L3 SharedMemory 組織全体。RBAC ゲート、時間減衰 L4 MarkdownStore git 管理、PR レビュー必須、不変 L5 GraphLayer 任意(Zep / Graphiti)、関係抽出
肝は「L1 → L4 が手動ではない」こと。Sleep-time Consolidator(夜間バッチ)が個人メモリをスキャンし、組織知へ自動昇格させます。
3 経路の昇格エンジン
メモリ昇格を 3 つの独立シグナル で並行評価:
- 頻度(Frequency): N 人以上で繰り返される事項
- アウトカム相関(Outcome correlation): 受注 / PR 承認 / テスト合格などの成果と共起
- LLM 自己評価(Self-eval): 0..1 で「組織知候補度」スコア
最終スコアは加重ブレンドし、いずれか 1 経路でも決定的なら昇格。単一機構依存(=どれか 1 つが落ちると全部落ちる)を意図的に避けています。
実装: praxia/memory/promoter.py(~250 LoC)。
「自分で書ける」を成立させた設計選択
1 ヶ月で書ききれたのは、4 つの設計選択のおかげでした。
① 7 拡張ポイント
すべての拡張点を同じ
praxia.extensions.Registryプリミティブで実装:
| 拡張ポイント | LoC 目安 | エントリポイント |
|---|---|---|
| Connector(Box / Notion / Slack 等) | ~50 | praxia.connectors |
| Memory backend | ~80 | praxia.memory_backends |
| File parser | ~30 | praxia.parsers |
| Output exporter | ~30 | praxia.exporters |
| OAuth provider | ~20 | praxia.oauth_providers |
| Skill | ~50 | praxia.skills |
| Flow | ~50 | praxia.flows |
「コアファイルを編集せず、pyproject.toml の entry-point だけで拡張可能」を満たしているので、自分で書くときの認知負荷が低い。
② Apache-2.0 で全機能同梱(paywall なし)
SSO(Google / Microsoft Entra / Okta / GitHub / Keycloak)・RBAC・監査ログ・per-user OAuth(13 プロバイダ)・KMS-backed トークン暗号化(AWS / Azure / GCP / Vault / local)を すべて OSS コアに収録。
商用エージェント基盤が "Enterprise tier" として paywall する機能の大半が、Apache-2.0 で同梱されています。これは導入時の判断スピードに直結します。
③ LiteLLM で 100+ プロバイダ
主要 LLM プロバイダの違い(Anthropic の
response_format非対応、GPT-5.x の
temperature不可、Azure のデプロイ名形式など)を LiteLLM レイヤで吸収。Praxia 本体には特定プロバイダの API キーが入らない設計。
完全オフライン運用も可能(Ollama +
gemma-local/
qwen-local+
backend=json)。
④ Streamlit UI を「捨てやすい」設計に
UI は Streamlit で組みましたが、バックエンドは全部 praxia serve(FastAPI)としても起動可能。将来 Next.js / モバイルに差し替えるとき UI レイヤだけ捨てれば良い構造。
v0.1.0 で何を入れて、何を入れなかったか
入れたもの(意図的にフルセット):
- 5 層メモリ + 3 経路昇格エンジン
- 6 業務スキル(投資 / 営業 / 設計 / 購買 / 特許 / 法務)
- 6 LTM backend + Composite/Routed 並列融合
- 13 プロバイダの per-user OAuth(kintone 対応も含む)
- SSO + RBAC + ACL + 監査ログ
- 自律エージェント(LLM 駆動の tool-use ループ)
- Document Designer(
python-pptx
/docx
を sandbox 実行してデザイン済みファイル出力) - 8 言語の i18n(en / ja / zh-CN / ko / es / fr / de / pt-BR)
入れなかったもの(意図的に v0.2 以降):
- マルチテナント GUI:OSS は「単一組織で self-host」想定。SaaS 級のテナント分離は Open Core の有償版で
- PDF 出力:LibreOffice 経由のワークフロー推奨
-
Pinecone / Weaviate / Qdrant の native backend:Composite/Routed で
mem0
経由ラップ可能なので優先度低
「何を作らないか」のリストは「何を作るか」のリストと同じくらい重要でした。
ローンチで起きたこと(1 週間の記録)
- 5/12: 60 秒デモ動画を YouTube 公開 → README + ランディングに埋込
- 5/13: Google Analytics 4 + Search Console 連携完了
- 5/13: PyPI 公開 →
pip install praxia
で動作確認 - 5/14: docs 整備(quickstart の「初回ログイン」セクション補強 — bootstrap admin の API キーの取り出し方を明文化)
- 5/15: OG image 1200×630 を専用デザインに差替、Twitter / LinkedIn でリッチプレビュー化
完璧主義に陥らず「Done > Perfect」で出し続けるのが、個人開発で続けるコツだと改めて感じています。
ハマったポイント TOP 3
「動くものを 5 週間で出す」走りだったので、本当に時間を喰った 3 つはすべて 記憶層と昇格エンジン に関するものでした。
1. 3 経路スコアの「ばらつくスケールをどう混ぜるか」
PromotionEngine は L1 → L3 への昇格判定を Frequency / Outcome correlation / LLM self-eval の 3 シグナルで並列に評価します。これが想像より厄介でした:
- Frequencyは 0..∞ の整数 (同一事実への参照数)
- Outcome correlationは 0..1 の比率 (該当事実が共起したタスクの成功率)
- LLM self-evalは 0..1 連続値、ただし非決定的で provider ごとにスコア分布が違う(GPT-5 は厳しめ中央値 0.4、Claude は緩めの 0.7、Gemini は二峰性)
最初の実装は単純な加重平均でしたが、frequency が無制限なので「片手間に L1 で何度も触っただけの事実」が全部上位に来る挙動になりました。最終的にこの形:
@dataclass(frozen=True)
class PromoteSignal:
frequency: float # raw count
outcome_corr: float # 0..1
self_eval: float # 0..1, median of N=3 LLM calls
def decide_promotion(sig: PromoteSignal, cfg: PromoteConfig) -> bool:
# Z-score normalize on a rolling 30-day population, then sigmoid
z_freq = sigmoid((sig.frequency - cfg.freq_mean) / cfg.freq_std)
# OR logic with per-path threshold
return (
z_freq > cfg.freq_threshold # 0.85
or sig.outcome_corr > cfg.outcome_threshold # 0.70
or sig.self_eval > cfg.self_eval_threshold # 0.80
)
ポイント:
- Z-score 正規化で frequency の暴走を抑制
- OR ロジック + 経路ごと閾値にして「1 経路でも決定的なら昇格」 — 単一機構依存(=どれか 1 つに頼ると全部落ちる)を意図的に回避
- LLM self-eval は N=3 の中央値で非決定性を平均化(N=5 までやってみたが効果がプラトー)
-
decide_promotion
は純粋関数なので、過去の昇格ログを再生してパラメータ感度分析ができる
「Z-score → sigmoid → OR with thresholds」 に辿り着くまで設計を 5 回くらいやり直しました。教訓: シグナル統合は加重平均から始めるな。経路ごとの decisive threshold + OR が結果として一番堅い。
2. Composite backend の「fan-out 検索 × 単一書込」を整合させる
Composite backend は複数 backend (JSON / Mem0 / TiDB / Letta…) に並列で検索クエリを送り、Reciprocal Rank Fusion (RRF) で融合します。一方、書込は
write_to=で指定した 1 つに集約します。
この非対称性で 3 つの落とし穴にハマりました。
(a) あとから backend を追加すると過去データが見えない
Composite(backends=[A, B], write_to="A")で運用していて、後から C を追加すると C には過去の書込が一切ない。検索 fan-out で「ヒットする backend が 2 つ、しない backend が 1 つ」という不均衡状態に。ドッグフーディング中に「ある backend だけ検索品質が低い」という形で発覚しました。
→
replay_writes(source=A, target=C, since=...)という管理 API を後追いで追加。リバランス時に必要。
(b) write_to が落ちた時の graceful degradation
write_to が落ちた時、書込だけ止めて読みは続行、という選択肢が一見魅力的。が、これをやると 「検索でヒットしていた record が次回検索で消える」(write_to が復旧して書込が走らないため) という現象が起きうる。
最終的に graceful degradation を諦めて raise する 方針に。半端な可用性は eventual consistency の上にデータの真偽問題を重ねてしまう、と判断しました。「落ちている時は落ちていると正直に言う」のが結局一番運用しやすい。
(c) RRF 融合で同点 tie-breaking
複数 backend が 同じ record_id を rank 1 で返す とスコアが完全同点。tie-breaking ルールを定義しないと backend の登録順依存 で順序が変動し、CI でテストが flaky になる。
→
(rrf_score, timestamp DESC, backend_priority)の lexicographic tie-breaking を導入。これで CI 環境でも順序再現性が出るように。
3. Sleep-time Consolidator の冪等性
夜間バッチで L1 → L3 昇格を再実行する設計上、同じ事実を 2 回昇格させない ことが冪等性の鍵です。
record_idベースの厳格 dedup だけでは不十分でした:
- 同じユーザが「お客様 X は ROI を最優先」と「X さんは ROI 重視」と別文面で 2 回 L1 に記録 → 異なる record_id だが意味的に同一
- LLM 自己評価は 非決定的: 同じテキストでも 0.78 / 0.82 / 0.76 のように揺れる → 閾値ぎりぎりで「昨日昇格しなかったが今日した」が起きる
そこで fuzzy dedup を導入:
def is_duplicate(candidate: Record, l3_recent: list[Record]) -> bool:
# Already-promoted check: any L3 record within recent window whose
# embedding cosine-sim >= threshold is treated as duplicate
cand_vec = embed(candidate.text)
return any(
cosine_sim(cand_vec, r.embedding) >= 0.92
for r in l3_recent # already filtered to last 30 days
)
難しかったのは 2 つの閾値(類似度 + ウィンドウ)のチューニング:
| 設定 | 起きる問題 |
|---|---|
| 0.95 / 7 日 (厳しめ) | 表現が違うだけの「同じ事実」が複数の L3 に並ぶ |
| 0.85 / 90 日 (緩め) | 「新しいが類似した事実」(顧客 Y の同様傾向など)が抑制される |
| 0.92 / 30 日 (採用値) | 手動でラベル付けした 50 件のセットで false-merge / false-split が両方 < 5% |
決定打は 両方向のメトリクスを同時に instrument した こと。「重複を見逃した率」だけでなく 「本来別事実なのに重複扱いした率」も常時計測 する。片側だけ追うと必ずどちらかに偏ったチューニングになります。これは PromotionEngine 全体の校正ループにも横展開しました。
数字で見る v0.1.0
| 項目 | 値 |
|---|---|
| コードベース | ~25,000 LoC(Python + テスト + i18n) |
| テスト | 431 件 PASS |
| サポート LLM プロバイダ | 100+ via LiteLLM |
| 同梱コネクタ | 19 種(Pull + Push 両対応) |
| Per-user OAuth プロバイダ | 13 種 |
| ドキュメント | 英 + 日 で 30,000 字超 |
| 開発期間 | 約 5 週間(夜と週末) |
次の 3 ヶ月でやること
- v0.2: TiDB Vector / pgvector 公式 backend(現状は
mem0
ラップ経由) - v0.2: localhost loopback OAuth(
praxia serve
不要にする) - v0.3: マルチテナント Org 機能(Open Core の入り口)
- ドキュメント: 英語版チュートリアルの拡充
- コミュニティ: Discord 開設、Discussions の活性化
同じ立場の人へ
個人 OSS を始めるかどうか悩んでいる方へ、5 週間走り抜けて感じたことを 3 つだけ。
-
完成度より公開頻度:
v0.1.0
で出した方が、v0.0.4
で磨き続けるより必ず学びが多い - 差別化を 1 行で:Praxia の場合は「個人 → 組織メモリ自動昇格」。これが言えないと記事も書けない、HN も書けない、PR も来ない
- OSS の真の競合は『同じ問題を解いてる商用 SaaS』:LangChain でも CrewAI でもなく、有償エージェントプラットフォームの paywall。それを Apache-2.0 で同梱するだけで差別化になる
おわりに
⭐ Star / 🍴 Fork / Issue / PR をお待ちしています。
github.com/praxia-dev/praxia
もしこの記事が気に入ったら、デモ動画(60 秒)も見てみてください:
https://youtu.be/o_6NbjJU1AA
「個人の天才性 × 組織の継続性」を AI で結びつける — それが Praxia の春から始まったミッションです。