BanditDB

com.banditdb由 banditdb.com 發布v0.3.1更新於 Oct 27, 2026

Persistent decision memory for agents — learns which action works in which context

已驗證STDIO僅桌面資料與分析AI 與機器學習

概覽

AI 產生的概覽

BanditDB 的 MCP 伺服器:以情境式多臂吃角子老虎機資料庫,讓代理記住哪種動作在何種情境下有效。

可以做什麼
  • 建立、列出、封存與還原決策活動,並新增或暫停動作
  • 依指定情境取得最佳動作,可單次或批次,並記錄成功或失敗結果
  • 檢視各動作的學習狀態、收斂報告與各資源的預算消耗
  • 連線 BanditDB 伺服器,讓所有代理的結果共同改進模型
適用情境
適合助手或一群代理需要反覆在多個動作(模型、優惠、路由)之間選擇並從回饋中學習時;也適合需要共享、持久決策記憶而非無狀態重試的情境。
執行需求
需要本機 Python 執行環境與 uvx(banditdb-python 套件),以及可連線的 BanditDB 伺服器。設定 BANDITDB_URL 為伺服器位址,BANDITDB_API_KEY 為 API 金鑰;writer 角色金鑰即可使用直覺與結果記錄工具,建立或刪除活動則需 admin 金鑰。
安裝前請注意
API 金鑰以環境變數傳入,具備對共享活動狀態的寫入權限;admin 金鑰可建立與刪除活動。記錄結果與新增動作會改變所有已連線代理共用的模型。預算在預測時即被消耗且不會重置,昂貴動作可能永久無法選用。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 BanditDB,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

BanditDB Python SDK

The official Python client and Model Context Protocol (MCP) server for BanditDB — the ultra-fast, lock-free Contextual Bandit database written in Rust.

BanditDB abstracts away the complex linear algebra of Reinforcement Learning (LinUCB, Thompson Sampling) behind a dead-simple API. Build real-time personalizers, dynamic A/B tests, and give LLM agents mathematically rigorous persistent memory.

mcp-name: com.banditdb/mcp

Installation

bash
pip install banditdb-python

Requires the BanditDB Rust server running (default: http://localhost:8080).


1. Standard SDK Usage

The client features automatic connection pooling, exponential backoff retries, and strict timeouts.

python
from banditdb import Client, BanditDBError
# Connect to the BanditDB server.# Pass api_key if BANDITDB_API_KEY is set on the server.db = Client(    url="http://localhost:8080",    timeout=2.0,    api_key="your-secret-key",   # omit if server runs without auth)
try:    # 1. Create a campaign (run once at startup)    # algorithm defaults to "linucb"; use "thompson_sampling" for Bayesian exploration    db.create_campaign(        campaign_id="checkout_upsell",        arms=["offer_discount", "offer_free_shipping"],        features=["is_mobile", "cart_value", "is_returning_user"],    )    # or: db.create_campaign(..., algorithm="thompson_sampling")
    # 2. A user arrives — ask the database what to show them.    # Scale each value to 0–1; the SDK puts them in order, adds a constant 1    # and normalises the vector.    arm_id, interaction_id = db.predict("checkout_upsell", {        "is_mobile": 1.0,        "cart_value": min(cart_total / 200, 1.0),        "is_returning_user": 0.0,    })    print(f"Showing: {arm_id}")  # e.g., "offer_free_shipping"
    # 3. The user clicked — send the reward    db.reward(interaction_id, reward=1.0)
except BanditDBError as e:    print(f"Database error: {e}")

Named features or a vector. With features=[...] the campaign stores the feature order in its metadata, and predict, batch_predict and interact accept a dict keyed by name. A missing or misspelt name raises ValueError before any request is sent. Campaigns created in the BanditDB console accept dicts too. The order is read once per campaign with campaign_info() and cached on the client. To manage the vector yourself, pass feature_dim instead and send lists — normalize_context() scales one to unit length.

All Client methods

Health

MethodDescription
health()Returns True if the server is reachable and the WAL writer is healthy.
health_detail()Returns the full health dict including per-campaign entropy and status ("ok" / "warning" / "critical").

Campaigns

MethodDescription
create_campaign(campaign_id, arms, feature_dim=None, alpha=1.0, algorithm="linucb", metadata=None, decay_half_life_hours=None, pacing=None, features=None)Register a new campaign. Pass features (names, in order) to predict with dicts, or feature_dim to send vectors. algorithm accepts "linucb", "thompson_sampling", NeuralLinUCBConfig, NeuralTSConfig, or ProgressiveConfig. metadata is an arbitrary JSON dict (≤ 64 KB). pacing takes a PacingConfig — see Budget constraints.
list_campaigns()Returns a list of all campaigns (active and archived) with alpha, arm_count, and algorithm.
campaign_info(campaign_id)Returns full per-arm state: theta, theta_norm, prediction and reward counters. Raises APIError (404) if not found.
report(campaign_id)Business-level convergence report. converged=True means one arm has a statistically significant lead at 95% CI — safe to stop. converged=False means leading but CIs still overlap. converged=None means not enough data yet (< 30 rewards per arm).
diagnostics(campaign_id)Operator diagnostics: per-arm theta norms, A_inv uncertainty bounds, entropy health (selection_entropy, entropy_status, entropy_trend, likely_cause, suggested_action), tournament traffic, and neural buffer size.
archive_campaign(campaign_id)Soft-delete: pauses predictions/rewards but preserves all learned weights. Recoverable with restore_campaign().
restore_campaign(campaign_id)Restore an archived campaign to active status with all weights intact.
delete_campaign(campaign_id)Permanently delete a campaign. Returns False if not found.
pacing(campaign_id)Budget state of a pacing campaign: per-resource budget, consumed, remaining, utilization, lambda (shadow price), is_exhausted. None if the campaign has no pacing. Server 2.3.0+.
add_arm(campaign_id, arm_id, group=None, warm_start=None, costs=None)Add an arm to a live campaign (admin key). costs maps resource name → units consumed per prediction, for pacing campaigns.
set_arm_status(campaign_id, arm_id, status)"active", "paused" (not selectable, reversible) or "retired". The arm keeps what it learned. Admin key.

Predict & Reward

MethodDescription
predict(campaign_id, context, eligible_arms=None, exclude_arms=None)context is a dict of feature values (named campaigns) or a vector. Returns (arm_id, interaction_id). Pass interaction_id to reward() to close the loop. The optional filters narrow candidates for this call only.
batch_predict(predictions)Predict for up to 100 campaign/context pairs in a single round-trip. Each item: `{"campaign_id": str, "context": dict
reward(interaction_id, reward)Record outcome. reward must be in [0.0, 1.0]. Raises APIError if the interaction has already been rewarded or has expired (default TTL: 24 h).

Data & Export

MethodDescription
checkpoint()Flush WAL, snapshot models, write Parquet shards, run neural retrain + tournament eval, rotate WAL. Returns a summary string.
export()List Parquet export shards grouped by campaign. Returns {export_dir, shards}.

Budget constraints

Server 2.3.0+. Give a campaign one or more budgeted resources and per-arm costs; the server learns a shadow price per resource and steers spend to last the horizon, choosing costly arms only where their uplift is worth it.

python
from banditdb import Client, PacingConfig, ResourceConstraint
db.create_campaign(    "promos", ["none", "discount_10", "discount_20"], feature_dim=4,    pacing=PacingConfig(resources=[        ResourceConstraint(            name="promo_budget",            budget=5_000.0,      # units available over the horizon            horizon=100_000,     # decisions the budget should last            arm_costs={"discount_10": 1.0, "discount_20": 2.0},  # "none" costs 0        ),    ]),)
# Arms added later declare their own costsdb.add_arm("promos", "discount_30", costs={"promo_budget": 3.0})
for r in db.pacing("promos")["resources"]:    print(f"{r['name']}: {r['utilization']:.0%} spent, lambda={r['lambda']:.3f}")

Worth knowing:

  • Budget is spent at predict, not reward. A recommendation you never act on still consumes budget.
  • Budget never resets and pacing is immutable. Once spent, costly arms stay unselectable until the campaign is recreated.
  • arm_costs keys must be campaign arms. The server would silently treat a misspelt arm as free; the SDK raises ValueError instead.
  • Predicts on a pacing campaign can return 503 if the server's WAL is saturated.
  • Downgrading the server below 2.3.0 silently drops pacing.

2. The AI "Hive Mind" (Model Context Protocol)

Standard LLM agents are stateless — if they route a task to the wrong model and fail, they repeat the same mistake tomorrow. BanditDB's built-in MCP server gives the entire agent swarm shared persistent memory.

Starting the MCP server

bash
# Set environment variables before startingexport BANDITDB_URL=http://localhost:8080export BANDITDB_API_KEY=your-secret-key   # omit if server runs without auth
banditdb-mcp

Connecting to Claude Desktop

Add to your Claude configuration file:

  • Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
json
{  "mcpServers": {    "banditdb": {      "command": "banditdb-mcp",      "args": [],      "env": {        "BANDITDB_URL": "http://localhost:8080",        "BANDITDB_API_KEY": "your-secret-key"      }    }  }}

The agent swarm now has twelve tools:

ToolWhat it does
create_campaignCreate a new decision campaign. Accepts algorithm ("linucb" or "thompson_sampling"), alpha, and optional budgets for actions that cost something limited. Use Thompson Sampling for natural Bayesian exploration with no tuning needed.
list_campaignsList all active campaigns (shows algorithm and alpha) — useful to check what exists before calling get_intuition.
campaign_diagnosticsInspect per-arm learning state: theta_norm, prediction counts, reward rates, and entropy health. Use when a campaign doesn't seem to be learning or one arm is dominating.
campaign_reportBusiness-level convergence report. Tells you whether the campaign has statistically converged and which arm is winning with confidence intervals.
get_intuitionAsk BanditDB which arm to pick for a given context. Optional exclude_arms / eligible_arms narrow the choice for this request only. Returns the arm and an interaction_id to save.
batch_get_intuitionGet decisions for multiple campaigns in a single round-trip. Pass a list of {campaign_id, context} dicts.
record_outcomeReport whether the chosen action succeeded (1.0) or failed (0.0). Updates the shared model.
archive_campaignSoft-delete a campaign. Pauses predictions/rewards but preserves all learned weights.
restore_campaignRestore an archived campaign to active status with all weights intact.
campaign_budgetBudget spend per resource: consumed, remaining, utilization, shadow price, exhaustion.
add_armAdd an action to a live campaign, optionally warm-started from existing arms and with budget costs.
set_arm_statusPause, retire, or reactivate an action. It keeps everything it learned.

Every decision made by any agent in the network improves the routing for all future agents.


3. Data Science & Offline Evaluation

BanditDB event-sources every prediction and reward to a Write-Ahead Log (WAL). Calling checkpoint() compiles completed prediction→reward pairs into Snappy-compressed Parquet files — one per campaign — for offline analysis with Polars or Pandas.

Every prediction is guaranteed to appear in the Parquet file even if its reward arrives hours later: BanditDB re-emits in-flight interactions at each checkpoint so delayed rewards are always captured in a future cycle.

python
# Checkpoint: snapshot models, write Parquet, rotate the WAL.# Call this on a schedule or after significant traffic.summary = db.checkpoint()print(summary)# "Checkpoint written and WAL rotated: 2 campaigns, offset 4821 bytes,#  150 interactions exported, 3 in-flight re-emitted"
# List which Parquet files are availableprint(db.export())# 'Parquet files in /data/exports: ["llm_routing.parquet"]'
# Load directly from the mounted volume into Polars.# Flat schema: interaction_id | arm_id | reward | predicted_at | rewarded_at | propensity | feature_0 | ...import polars as pldf = pl.read_parquet("/data/exports/llm_routing.parquet")print(df.head())print(df.columns)

Offline Policy Evaluation (OPE)

The SDK ships three OPE estimators in banditdb.eval. They answer the question: "what would my average reward have been under a different policy — without running a live experiment?"

Install the eval dependencies:

bash
pip install "banditdb-python[eval]"
EstimatorFunctionHow it worksWhen to use
Replayreplay(df)Accepts each interaction with probability (1/K) / propensity (Li et al. 2010). Unbiased sample of the uniform random policy.Sanity check baseline. Low coverage is expected — ~1/K of interactions are used.
IPS / SNIPSips(df, clip=10.0)Uses every interaction with importance weight (1/K) / propensity. Self-normalised to reduce variance. Weight clipping (default 10×) controls the bias-variance tradeoff.Primary estimator. Use when you have enough data but want full coverage.
Doubly Robustdoubly_robust(df, clip=10.0)Fits a linear reward model, then applies an IPS correction on residuals. Consistent if either the reward model or the propensities are correct.Best statistical efficiency. Use when comparing multiple policies or sweeping alpha.

All three estimators:

  • Accept a Polars or pandas DataFrame loaded from a BanditDB Parquet export
  • Evaluate the uniform random policy as the target (the unbiased baseline to beat)
  • Raise ValueError for Thompson Sampling campaigns (propensity column is null — TS does not log propensities)
  • Return an OPEResult with estimate, std_error, n_used, n_total, and method
python
import polars as plfrom banditdb.eval import replay, ips, doubly_robust
df = pl.read_parquet("/data/exports/llm_routing.parquet")
# How much reward would a uniform random policy have earned?print(replay(df))# OPEResult(method='replay', estimate=0.4821, std_error=0.0312, coverage=22.1% [33/149])
print(ips(df))# OPEResult(method='ips', estimate=0.5103, std_error=0.0187, coverage=100.0% [149/149])
print(doubly_robust(df))# OPEResult(method='doubly_robust', estimate=0.5219, std_error=0.0141, coverage=100.0% [149/149])
# Compare against the observed reward of the logging policy:print("Observed (logging policy):", df["reward"].mean())# If observed >> estimate, the campaign has learned something real — it outperforms random.

Practical use: sweep alpha offline before deploying. Train a campaign on real traffic, checkpoint to Parquet, then replay different alpha values through doubly_robust() to find the best exploration level — no live experiment needed.

Note: OPE requires the propensity column, which is only written for LinUCB campaigns. Thompson Sampling campaigns log null propensities because TS arm selection is stochastic and propensity scoring requires a deterministic logging policy.


Choosing an Algorithm

BanditDB supports five algorithms, selected at campaign creation time.

Algorithmalgorithm valueExploration styleWhen to use
LinUCB"linucb" (default)Deterministic UCB bonus: θ·x + α√(x·A⁻¹·x)Predictable, tunable. Sweep alpha offline to calibrate.
Linear Thompson Sampling"thompson_sampling"Samples θ̃ ~ N(θ, α²·A⁻¹), scores by θ̃·xBayesian posterior — no alpha-sweep needed. Concurrent users automatically diversify choices.
NeuralLinUCBNeuralLinUCBConfig(...)Deep MLP embedding + LinUCB in embedding spaceNon-linear reward functions. Retrains the MLP every N rewards.
NeuralTSNeuralTSConfig(...)Same MLP embedding as NeuralLinUCB; scores by a posterior draw in embedding space instead of a UCB boundNon-linear rewards where long-run performance matters more than early regret. Converges further at 20K+ interactions.
ProgressiveProgressiveConfig(...)Self-tuning tournament: runs base + challenger in parallel, shifts traffic to the winnerZero-configuration model selection. Picks the best algorithm automatically.
python
from banditdb import Client, NeuralLinUCBConfig, NeuralTSConfig, ProgressiveConfig
db = Client("http://localhost:8080")
# LinUCB (default)db.create_campaign("routing", ["fast", "cheap"], feature_dim=4, alpha=1.5)
# Thompson Sampling — natural Bayesian exploration, alpha=1.0 is idealdb.create_campaign("routing_ts", ["fast", "cheap"], feature_dim=4,                   algorithm="thompson_sampling")
# NeuralLinUCB — learns a deep embedding of the context, then applies LinUCBcfg = NeuralLinUCBConfig(    context_dim=4,     # must match feature_dim    embed_dim=32,      # arm matrix dimension (default 32)    hidden_dim=128,    # MLP hidden layer width (default 128)    retrain_every=200, # retrain the MLP every N cumulative rewards)db.create_campaign("routing_neural", ["fast", "cheap"], feature_dim=4, algorithm=cfg)
# NeuralTS — same parameters as NeuralLinUCB, posterior-sampling explorationcfg = NeuralTSConfig(context_dim=4, embed_dim=32)db.create_campaign("routing_nts", ["fast", "cheap"], feature_dim=4, algorithm=cfg)
# Progressive — runs LinUCB vs NeuralLinUCB, shifts traffic to whoever wins SNIPS checkpointscfg = ProgressiveConfig(    base="linucb",    challenger=NeuralLinUCBConfig(context_dim=4, embed_dim=32),    min_obs=100,       # minimum buffer entries per arm before any traffic shift    required_wins=3,   # consecutive checkpoint wins to earn one traffic step    step_bps=1000,     # traffic delta per win run, in basis points (1000 = 10%))db.create_campaign("routing_prog", ["fast", "cheap"], feature_dim=4, algorithm=cfg)

All five algorithms share the same predict → reward loop. Either neural config also works as a Progressive base or challenger.

NeuralLinUCB vs NeuralTS

NeuralLinUCBNeuralTS
ExplorationUCB upper bound (deterministic)Posterior sample (stochastic), spread scaled by alpha
Early regretLowerHigher
Convergence at 20K+ interactionsSlowerFaster
Best forProduction safety, costly early mistakesMaximum long-run performance
PaperXu, Wen, Zhao & Gu, ICLR 2022 (arXiv:2012.01780)Zhang, Zhou, Li & Gu, ICLR 2021 (arXiv:2010.00827)

Both neural algorithms need a server built with the neural feature: check "neural" in db.server_info()["features"].


Error Handling

ExceptionWhen raised
BanditDBErrorBase exception — catch this to handle all SDK errors.
ConnectionErrorServer is offline or unreachable.
TimeoutErrorRequest exceeded the configured timeout.
APIErrorServer returned an error (e.g., campaign not found, unauthorized).

License

Apache-2.0 — Copyright (C) 2026 Simeon Lukov and Dynamic Pricing Ltd. See the main repository for details.

來源:README.md,提交 b1d8e65

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

2
  1. v0.3.1最新Oct 11, 2026
  2. v0.2.1Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分