AgensFlow adapter for LangGraph — decorator-based routing across a declared model pool
Project description
agensflow-langgraph
Decorator-based routing for LangGraph agents. Learn which model in your declared pool each node of your graph should use — automatically, per node, from feedback.
Status: v0.1.1 (alpha).
The free-tier bundle
Everything needed to run an adaptive MAS end-to-end, no hosted service, no external dependencies:
| Piece | What it is |
|---|---|
agensflow-mcp |
The policy server. UCB1 bandits, tenant isolation, HTTP + MCP surfaces. Self-hostable (SQLite or Postgres) or hosted. |
agensflow-langgraph |
This package. The @agensflow decorator wraps any LangGraph node and routes its LLM calls through the server. |
| Starter policy | examples/starter_policies/parallel_critic_v1.json — a converged 40-run bandit state you import to skip cold-start exploration. |
| Quickstart notebook | notebooks/quickstart.ipynb — boots the whole stack in-process, imports the starter, runs a real MAS query. Runs top-to-bottom in ~2 min for ~$0.30 of OpenRouter fees. |
For anyone wanting to just try it: open the notebook. It boots the policy
server in-process (no separate uvicorn), issues an API key, imports the
starter, builds a real 6-node MAS with parallel critic+verifier, and runs one
query against OpenRouter — all in eight cells.
Install
pip install agensflow-langgraph
# For the notebook / examples:
pip install agensflow-mcp langchain-openai jupyter
60-second example
from langgraph.graph import StateGraph
from langchain_openai import ChatOpenAI
from agensflow_langgraph import agensflow, record_reward
# OpenRouter unifies every provider under one API key — one env var, many models
def or_model(model_id: str):
return ChatOpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
model=model_id,
)
# Declare a per-node pool. The substrate learns which arm wins.
@agensflow(pool={
"cheap": or_model("openai/gpt-4o-mini"),
"balanced": or_model("openai/gpt-4o"),
"deep": or_model("anthropic/claude-sonnet-4"),
})
async def classify_intent(state, model, config=None):
return {"messages": [await model.ainvoke(state["messages"])]}
graph = StateGraph(State)
graph.add_node("classify_intent", classify_intent)
# ... rest of your graph unchanged
# Attach an explicit reward at the graph terminal
def terminal(state):
record_reward(thread_id=state.get("thread_id"), quality=0.85)
return {...}
Every model call inside a decorated node routes through the policy server;
UCB1 over per-node signatures picks the pool arm. Cost + tokens are captured
via LangChain's AIMessage.usage_metadata callback path.
Two topology examples
examples/evidence_heavy_mas/— linear planner → memory → solver → verifier → evaluator with a verifier-gate revision loop. Exercises conditional edges + revision cycles.examples/parallel_critic_mas/— solver fans out to critic + verifier in parallel, evaluator merges both signals. Exercises parallel node execution + fan-in state reducers.
Both use real ChatOpenAI(base_url=openrouter) calls, structured Pydantic
handoffs via .with_structured_output(method="function_calling"), and
InMemorySaver checkpointing.
Configuration
export AGENSFLOW_SERVER_URL="https://mcp.agensflow.ai" # or your self-hosted URL
export AGENSFLOW_API_KEY="agf_..." # bearer token
export OPENROUTER_API_KEY="sk-or-..." # for the examples
Or pass them per-decorator:
@agensflow(pool={...}, server_url="http://localhost:8000", tenant_key="agf_...")
Documentation
- Integration guide — fail-open behavior, three reward paths (explicit / verifier / OpenRouter judge), signature derivation, idempotency, warm-start, streaming, checkpointer + thread_id, real-model cost capture
- Starter policies — how to import a converged policy for warm-start
- Individual example READMEs in
examples/*/README.md
License
Apache-2.0
Project details
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 agensflow_langgraph-0.1.1.tar.gz.
File metadata
- Download URL: agensflow_langgraph-0.1.1.tar.gz
- Upload date:
- Size: 69.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.17.1 {"ci":null,"cpu":"x86_64","distro":{"name":"macOS","version":"14.6.1"},"implementation":{"name":"CPython","version":"3.11.11"},"installer":{"name":"hatch","version":"1.17.1"},"openssl_version":"OpenSSL 3.6.2 7 Apr 2026","python":"3.11.11","system":{"name":"Darwin","release":"23.6.0"}} HTTPX2/2.5.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06515a5e15f464fd9e9e0eafb15dfd332a28ca28a9f02857458d672c5678bab4
|
|
| MD5 |
f85a9c46876e75ce49afa3a18e64b4f0
|
|
| BLAKE2b-256 |
2f1cc3e57f4b083454671e1c7f5db74502561257267317f438d78986d7907042
|
File details
Details for the file agensflow_langgraph-0.1.1-py3-none-any.whl.
File metadata
- Download URL: agensflow_langgraph-0.1.1-py3-none-any.whl
- Upload date:
- Size: 30.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.17.1 {"ci":null,"cpu":"x86_64","distro":{"name":"macOS","version":"14.6.1"},"implementation":{"name":"CPython","version":"3.11.11"},"installer":{"name":"hatch","version":"1.17.1"},"openssl_version":"OpenSSL 3.6.2 7 Apr 2026","python":"3.11.11","system":{"name":"Darwin","release":"23.6.0"}} HTTPX2/2.5.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4f039966a09e879e3b380ea73799ad9af897095ca2ec9b9da27f51758e4e882
|
|
| MD5 |
efe0828cc210811e31f92f15d753a4ef
|
|
| BLAKE2b-256 |
d3ebd2c06386cc0c8102b852334755d51156d23d59482145ffbc1f2eab409e1c
|