Declarative LangGraph Builder powered by YAML
Project description
Yagra: YAML-to-Agent-Graph Builder
Yagra は、YAML 定義から LangGraph の StateGraph を構築・実行する Python ライブラリです。
フロー制御(分岐・ループ)とノード設定(prompt/model など)をコードから分離し、
workflow.yaml の差し替えだけで挙動を切り替えられます。
Yagraでできること
- 宣言的なワークフロー管理: ノード・エッジ・条件分岐を YAML で管理
- 実装と設定の分離:
handler文字列と Python callable を Registry で接続 - 安全な構成検証: Pydantic ベースのスキーマ検証で入力不整合を早期検出
- 最小コードで実行:
Yagra.from_workflow(...)でグラフを即構築
想定ユースケース
- LLM エージェントのフローをプロトタイプし、YAML 差し替えで高速に試行錯誤したい
- 非エンジニアも読める形式で、ワークフロー定義を運用したい
- LangGraph のコード量を抑えながら、分岐・ループを含む制御を扱いたい
インストール
- Python 3.12+
pip install yagra
開発者向けセットアップ
git clone https://github.com/shogo-hs/Yagra.git
cd Yagra
uv sync --dev
クイックスタート(条件分岐あり)
1. State とノード関数を定義
from typing import TypedDict
from yagra import Yagra
class AgentState(TypedDict, total=False):
query: str
intent: str
answer: str
__next__: str
def classify_intent(state: AgentState, params: dict) -> dict:
_ = params
intent = "faq" if "料金" in state.get("query", "") else "general"
return {"intent": intent, "__next__": intent}
def answer_faq(state: AgentState, params: dict) -> dict:
prompt = params.get("prompt", {})
return {"answer": f"FAQ: {prompt.get('system', '')}"}
def answer_general(state: AgentState, params: dict) -> dict:
model = params.get("model", {})
return {"answer": f"GENERAL via {model.get('name', 'unknown')}"}
def finish(state: AgentState, params: dict) -> dict:
_ = params
return {"answer": state.get("answer", "")}
2. Workflow YAML を定義
workflows/support.yaml
version: "1.0"
start_at: "classifier"
end_at:
- "finish"
nodes:
- id: "classifier"
handler: "classify_intent"
- id: "faq_bot"
handler: "answer_faq"
params:
prompt:
system: "pricing response"
- id: "general_bot"
handler: "answer_general"
params:
model:
provider: "openai"
name: "gpt-4.1-mini"
- id: "finish"
handler: "finish"
edges:
- source: "classifier"
target: "faq_bot"
condition: "faq"
- source: "classifier"
target: "general_bot"
condition: "general"
- source: "faq_bot"
target: "finish"
- source: "general_bot"
target: "finish"
3. Registry と実行
registry は dict[str, callable] を直接渡せます(InMemoryNodeRegistry は内部で自動利用)。
registry = {
"classify_intent": classify_intent,
"answer_faq": answer_faq,
"answer_general": answer_general,
"finish": finish,
}
app = Yagra.from_workflow(
workflow_path="workflows/support.yaml",
registry=registry,
state_schema=AgentState,
)
result = app.invoke({"query": "料金を教えて"})
print(result["answer"])
API
Yagra.from_workflow(...)
Yagra.from_workflow(
workflow_path: str | PathLike,
registry: NodeRegistryPort | Mapping[str, NodeHandler],
bundle_root: str | PathLike | None = None,
state_schema: Any = dict,
) -> Yagra
workflow_path: 入口となる workflow YAMLregistry:NodeRegistryPort実装、またはdict[str, callable]bundle_root: 分割参照解決の基準ディレクトリ(省略時は workflow の親)state_schema: LangGraph の状態スキーマ(既定dict)
Yagra.invoke(...)
Yagra.invoke(state: Mapping[str, Any]) -> dict[str, Any]
yagra visualize(Read Only 可視化)
Workflow YAML を Read Only の可視化 HTML に変換します。 出力 HTML は Mermaid を同梱しており、インターネット接続なしでも描画できます。
yagra visualize \
--workflow examples/workflows/loop-split.yaml \
--output /tmp/yagra-view.html \
--title "Yagra Workflow Viewer"
オプション:
--workflow: 可視化対象 workflow ファイル(必須)--bundle-root: 分割参照解決の基準ディレクトリ(任意)--output: 生成 HTML の出力先(既定:workflow-visualization.html)--title: ページタイトル(任意)
検証エラーがある場合は HTML は生成せず、エラー一覧を標準エラーへ出力します。
yagra studio(フォーム + DnD 編集 + 保存)
Workflow の prompt / model / condition 編集に加え、DnD でノード追加・接続変更を行い、diff 確認・保存・rollback を実行するローカル WebUI/API を起動します。
# ランチャー起動(UI で workflow を選択/新規作成)
yagra studio --port 8787
# 従来どおり直接指定で起動
yagra studio \
--workflow examples/workflows/loop-split.yaml \
--bundle-root examples \
--port 8787
起動後はブラウザで http://127.0.0.1:8787/ を開きます。
Studio は同梱アセットをローカル配信するため、インターネット接続なしでも表示・操作できます。
主な編集フロー:
- 必要に応じて
Add Nodeでノードを追加し、Node/Edge フォームで値を編集してApply ...Add Nodeは選択中ノードの近傍(未選択時は自動レイアウト位置)へ自動配置されます。
- Node Properties の
prompt yamlで参照先 YAML を選択すると、system prompt/user promptが自動で読み込まれます。- 候補一覧(
yaml_files)の再読込中でも、現在選択中のprompt yamlは自動で空に戻らず保持されます(明示的に(auto create on Apply)を選んだ場合のみ未選択化)。
- 候補一覧(
prompt yaml未選択のままApply Node Editした場合、workspace root(通常は project root)直下のprompts/<node-id>.yaml(重複時は連番)が自動作成され、prompt_refが自動設定されます。prompt keyを指定した場合はpath#key形式になり、生成 YAML は{ key: { system, user } }形式になります。
- Graph Canvas 上でノードをドラッグして位置調整し、右側ポート(output)から左側ポート(input)へドラッグしてエッジ追加(戻りループは下側 output → 上側 input で接続)
- 再接続時はエッジ端点をドラッグして接続先を変更(ドラッグ起点が新 source、ドロップ先が新 target)
- Node Properties で
node id(リネーム),prompt_ref,Model Settings(provider/name/temperatureなど)を設定node idを変更してApply Node Editすると、関連するedges[].source/targetとstart_at/end_atも自動で同期されます。
Preview Diffで変更差分と validation を確認Saveで workflow を保存(backup 作成)- 必要なら
Rollbackでbackup_idから復元
補足:
- Studio 画面は操作性優先のため
Workflow/UI Stateの生JSONは常時表示しません。必要時はGET /api/workflow/GET /api/workflow/formで確認してください。
オプション:
--workflow: 編集対象 workflow ファイル(任意、未指定時はランチャーで選択/作成)--bundle-root: 分割参照解決の基準ディレクトリ(任意)--ui-state: UI サイドカー JSON の保存先(既定:<workflow>.workflow-ui.json)--workspace-root: ランチャーが探索/作成可能なワークスペースルート(既定:workflowがカレント配下ならカレント、そうでなければ<workflow> の親、--workflow未指定時はカレント)--backup-dir: バックアップ保存先(既定:.yagra/backups)--host: バインドホスト(既定:127.0.0.1)--port: バインドポート(既定:8787)
保存時は以下を実施します。
- 保存前 validation(M-05 契約)
- atomic write(中途半端な書き込み防止)
- backup 作成(
<backup-dir>/<workflow-stem>/<backup_id>.*) - 失敗時の自動復旧
フォーム向け API:
GET /api/workflow/formPOST /api/workflow/form/preview- M-09 の入力契約として、下記フィールドはすべて必須
base_revision,ui_statenode_creates[]/node_edits[]edge_creates[]/edge_rewires[]/edge_edits[]
仕様上の契約(Implicit Contracts)
1. 条件分岐の契約
edges[].conditionは分岐ラベルです。- 分岐元ノードは
{"__next__": "<condition-label>"}を state update として返します。 - 例:
condition: "faq"がある場合、__next__は"faq"を返す必要があります。
2. prompt 参照解決の契約
prompt_refは実行前に解決されます。- handler が受け取る
paramsには解決済み値が入ります。params["prompt"]params["model"]
prompt_refとpromptを同時指定した場合、prompt_ref解決結果にpromptが上書きマージされます(ノード側優先)。- 実行時に handler へ渡る
paramsからはprompt_refは除去されます(prompt/modelを利用)。 model_refは廃止です。モデル設定はnodes[].params.modelにインライン定義します。prompt_refの参照形式:<path>(YAML ルートが prompt mapping の場合)<path>#<key.path>(YAML 内キーを指定)
例:
nodes:
- id: planner
handler: planner_loop_handler
params:
prompt_ref: "../prompts/support_prompts.yaml#planner"
model:
provider: openai
name: gpt-4.1-mini
kwargs:
temperature: 0.1
3. end_at の挙動
end_atは「終了ノードIDのリスト」です(複数可)。- Yagra は各ノードを LangGraph の finish point として登録します。
- YAML 上で
ENDという特別ノードを直接書く仕様ではありません。
4. ノード関数シグネチャ
Yagra は次の順で呼び出しを試みます。
handler(state, params)handler(state)
YAML 仕様(要点)
トップレベル:
version: strstart_at: strend_at: list[str]nodes: list[NodeSpec]edges: list[EdgeSpec]params: dict[str, Any](任意)
NodeSpec:
id: strhandler: strparams: dict[str, Any](任意)
EdgeSpec:
source: strtarget: strcondition: str | null(任意)
補足:
edgesは 0 件でも有効です(例:start_atとend_atが同一の単一ノード workflow)。
同梱サンプル
examples/workflows/branch-inline.yaml- 条件分岐の最小例
examples/workflows/loop-split.yaml- ループ + 条件分岐 +
prompt_ref分割参照 + model インライン定義
- ループ + 条件分岐 +
examples/prompts/support_prompts.yamlexamples/models/openai_models.yaml
開発コマンド
uv run ruff check .
uv run mypy .
uv run pytest -q
uv run pre-commit run --all-files
ドキュメント(Sphinx)
ローカルで HTML を生成:
uv run sphinx-build -b html docs/sphinx/source docs/sphinx/_build/html
生成先:
docs/sphinx/_build/html/index.html
公開先(GitHub Pages):
https://shogo-hs.github.io/Yagra/
公開の前提:
- GitHub の
Settings > Pagesで Source をGitHub Actionsに設定する .github/workflows/docs.ymlがmainへの push または手動実行で成功する
PyPI 公開
公開ワークフローは v* タグ push をトリガーに実行されます。
- workflow:
.github/workflows/publish.yml - build:
uv build - 検証:
uvx twine check dist/* - publish:
pypa/gh-action-pypi-publish(OIDC)
前提:
- PyPI 側で private repository
shogo-hs/Yagraを Trusted Publisher として登録しておく - GitHub Actions の
pypienvironment が利用可能である - Git タグ(
vX.Y.Z)とpyproject.tomlのversionを一致させる
リリース実行例:
git tag v0.1.3
git push origin v0.1.3
ライセンスと変更履歴
- ライセンス:
LICENSE(MIT) - 変更履歴:
CHANGELOG.md
エージェント実行規約
エージェント運用ルールは AGENTS.md を参照してください。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yagra-0.1.8.tar.gz.
File metadata
- Download URL: yagra-0.1.8.tar.gz
- Upload date:
- Size: 1.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77504fc9c6d9bdc8a65185122e61bd6e9018f06365bddfd09264126dedf9a747
|
|
| MD5 |
3268b2d64c811af079d29d9a8ca7a83c
|
|
| BLAKE2b-256 |
d2820a69b115c7e369f334db9b25f7d8f5fd57d0e8df3d0c2fc0332fc60c43df
|
Provenance
The following attestation bundles were made for yagra-0.1.8.tar.gz:
Publisher:
publish.yml on shogo-hs/Yagra
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yagra-0.1.8.tar.gz -
Subject digest:
77504fc9c6d9bdc8a65185122e61bd6e9018f06365bddfd09264126dedf9a747 - Sigstore transparency entry: 953543494
- Sigstore integration time:
-
Permalink:
shogo-hs/Yagra@0d326231b6f2d25ed37d68108ad92b2f9a758859 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/shogo-hs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0d326231b6f2d25ed37d68108ad92b2f9a758859 -
Trigger Event:
push
-
Statement type:
File details
Details for the file yagra-0.1.8-py3-none-any.whl.
File metadata
- Download URL: yagra-0.1.8-py3-none-any.whl
- Upload date:
- Size: 1.0 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cb95e108bc2e4c95919a666a83c2d43b2ec63d0b8ec1e0d94a716b21091d595
|
|
| MD5 |
1abad2771bade457b2afc489dbc3e801
|
|
| BLAKE2b-256 |
51f8eefae5e57b3df3204a588e8a5cb57d06b678eca513806097a5bf29ba50b8
|
Provenance
The following attestation bundles were made for yagra-0.1.8-py3-none-any.whl:
Publisher:
publish.yml on shogo-hs/Yagra
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yagra-0.1.8-py3-none-any.whl -
Subject digest:
9cb95e108bc2e4c95919a666a83c2d43b2ec63d0b8ec1e0d94a716b21091d595 - Sigstore transparency entry: 953543495
- Sigstore integration time:
-
Permalink:
shogo-hs/Yagra@0d326231b6f2d25ed37d68108ad92b2f9a758859 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/shogo-hs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0d326231b6f2d25ed37d68108ad92b2f9a758859 -
Trigger Event:
push
-
Statement type: