MATM is a framework for population-level storage and retrieval of agent-generated action-observation trajectories. Producer agents contribute trajectories to a shared repository; consumer agents retrieve relevant trajectory segments at inference time to improve task execution. Agents can serve both roles without coordination or joint training.
┌────────────────────────────────────────┐
│ Shared Trajectory Repository │
│ ┌─────────┐ ┌─────────┐ ┌───────┐ │
│ │ chunk 1 │ │ chunk 2 │ │ ... │ │
│ └─────────┘ └─────────┘ └───────┘ │
└──────────▲───────────────┬─────────────┘
│ │
index trajectories retrieve top-k
│ │
┌────────┴────┐ ┌────▼────────┐
│ Producer │ │ Consumer │
│ Agents │ │ Agents │
│ (generate) │ │ (utilize) │
└─────────────┘ └─────────────┘
Key components:
- Population-level memory sharing: heterogeneous producer agents contribute trajectories to a shared repository that consumer agents query at inference, enabling collective experience reuse without coordination or joint training.
- State-conditioned indexing: trajectories are chunked with window size W=5 (key = task description + last 5 action-observation steps; value = next 5 steps).
- LTRT (learning-to-rank trajectories) reranker: Rerankers trained on marginal-utility labels (outcome improvement vs. no-retrieval baseline), using 44 features show further improvement of performance of consumer agents that participates in the MATM framework. Three ranker families were trained: FFN (pointwise), LambdaMART (pairwise), and SVMRank (pairwise).
- Main Results
- Released Artifacts
- Repository Structure
- Installation
- Configuration
- Building the Shared Trajectory Index
- Running Evaluation
- LTR Pipeline
- Trajectory Dataset
- Citation
- License
Benchmarks: ALFWorld (text-based household tasks) and WebArena (web-based tasks).
MATM improves both effectiveness and efficiency.
Evaluation of MATM-augmented agents across 34 consumer models (averaged over five runs with randomized task–model allocation). SR = success rate; RPP = return-paired preference (joint success–efficiency metric; higher is better). Best per column in **bold**.| Method | ALFWorld SR↑ | ALFWorld # steps↓ | ALFWorld RPP↑ | WebArena SR↑ | WebArena # steps↓ | WebArena RPP↑ |
|---|---|---|---|---|---|---|
| no retrieval | 0.4708 | 11.7664 | −0.1586 | 0.1818 | 21.9886 | −0.0511 |
| single-stage | 0.5511 | 11.1796 | −0.0451 | 0.2045 | 20.2614 | 0.0284 |
| rerank-FFN | 0.5861 | 11.0336 | −0.0046 | 0.2045 | 19.9091 | 0.0398 |
| rerank-LambdaMART | 0.5715 | 10.8474 | 0.0608 | 0.1818 | 20.4205 | −0.0341 |
| rerank-SVMRank | 0.6431 | 10.3453 | 0.1474 | 0.2045 | 20.2841 | 0.0170 |
Retrieval from the shared MATM repository consistently improves both effectiveness and efficiency over the no-retrieval baseline. On ALFWorld, single-stage retrieval raises success rate from 47% to 55%; LTR reranking with SVMRank further boosts it to 64% while reducing average steps to 10.3. On WebArena, gains are more modest (single-stage and rerank-FFN reach 20.5% SR vs. 18.2% baseline), reflecting longer task horizons and greater sensitivity to early-step errors.
MATM scales.
Consumer agent performance improves as the MATM index grows. On ALFWorld, success rate and step efficiency improve monotonically from 10% to 100% of the full index. WebArena shows a similar overall trend.Other findings.
-
Whether the consumer model is strong or weak, MATM provides benefits.
-
MATM offers cross-task generalization.
For more results and analyses, see our paper.
LTRT (learning-to-rank trajectories) models
| Model | File path |
|---|---|
| ALFWorld FFN | ltr/ltr_models/alfworld/ffn_model.pt |
| ALFWorld LambdaMART | ltr/ltr_models/alfworld/lambdamart_model.pkl.* |
| ALFWorld SVMRank | ltr/ltr_models/alfworld/svmrank_model.pkl |
| WebArena FFN | ltr/ltr_models/webarena/ffn_model.pt |
| WebArena LambdaMART | ltr/ltr_models/webarena/lambdamart_model.pkl.* |
| WebArena SVMRank | ltr/ltr_models/webarena/svmrank_model.pkl |
🤗 Collected/Generated Trajectories
| Split | HuggingFace |
|---|---|
| ALFWorld pre-population trajectories | link |
| ALFWorld generated trajectories | link |
| WebArena pre-population trajectories | link |
| WebArena generated trajectories | link |
matm/
├── traj_retrieval/ # MATM retrieval framework
│ ├── core/ # Runtime engine: env handlers, episode loops,
│ │ # LanceDB client (pull) + online memory (push),
│ │ # retrieval, reranker orchestrator
│ ├── strategies/ # LLM action policies (retrieval + reranker filtering)
│ ├── preprocess/ # Index/split generation scripts (see preprocess/README.md)
│ │ ├── alfworld/ # ALFWorld trajectory staging & index building
│ │ ├── webarena/ # WebArena trajectory staging & index building
│ │ └── new_splits/ # Canonical train/test split definitions (JSON)
│ ├── evaluation/ # Metrics + LTR training-data pipeline
│ │ └── ltr_data/ # LTR pipeline scripts + TF-IDF artifacts
│ │ ├── generate_disagreements.py
│ │ ├── enrich_disagreements.py
│ │ ├── build_chunk_aligned_enriched_jsonl.py
│ │ └── build_ltr_train_tsv.py
│ ├── utils/ # Logging & metrics helpers
│ ├── run_evaluation.py # Async runner (ALFWorld)
│ ├── run_webarena.py # Sync runner (WebArena)
│ └── run_evaluation_config.yaml # Master YAML configuration
├── ltr/ # Learning-to-Rank (LTRT) library
│ ├── models/ # Ranker code (FFN, LambdaMART, SVMRank)
│ ├── data/ # Data loaders
│ ├── ltr_models/ # Trained model binaries per env (load these directly)
│ ├── svm_rank/ # SVMRank binaries (svm_rank_learn / svm_rank_classify)
│ ├── train.py # Ranker training entrypoint (python -m ltr.train)
│ └── runtime_features.py # Feature extraction for LTR
├── setup_environments.py # Environment setup helper
├── .env.example # Template for environment variables
├── requirements-base.txt # Core Python dependencies
└── requirements-alfworld.txt # ALFWorld-specific dependencies
- Python 3.10+ (the lint env in
tox.initargets 3.10; nothing in the code requires 3.10-only syntax, but ML deps are tested against 3.10) - CUDA-capable GPU (recommended for embedding model inference)
- Clone the repository:
git clone https://github.com/kimdanny/matm.git
cd matm- Create a virtual environment:
python -m venv .venv
source .venv/bin/activate- Install dependencies:
pip install -r requirements-base.txt
pip install -r requirements-alfworld.txt # For ALFWorld experiments
pip install -r requirements-webarena.txt # For WebArena experiments (see notes inside)For WebArena, you must also deploy the WebArena browser environment and install
its upstream Python package (browser_env) — see
requirements-webarena.txt for the full step list,
including the WEBARENA_RENEW_WEBARENA_PATH and WEBARENA_HOST env vars the
runner reads.
- Configure environment variables:
cp .env.example .env
# Edit .env with your paths and API keysMATM uses environment variables and YAML configuration files.
| Variable | Description | Default |
|---|---|---|
MATM_DATA_ROOT |
Root directory for environment data, indices, and trajectory logs | ./environments |
OPENROUTER_API_KEY |
API key for OpenRouter (required for LLM evaluation) | — |
WEBARENA_HOST |
Hostname of your WebArena deployment (required for WebArena) | — |
WEBARENA_RENEW_WEBARENA_PATH |
Absolute path to your local clone of the upstream webarena repo (required for WebArena) |
— |
ONLINE_MEMORY_ENABLED |
Set to 1 to push successful trajectories into the shared index at runtime |
0 |
SVMRANK_BIN_DIR |
Directory containing svm_rank_learn / svm_rank_classify (shipped in ltr/svm_rank/) |
ltr/svm_rank |
ALFWORLD_LANCEDB_PATH |
LanceDB URI for ALFWorld (LTR scripts) | ${MATM_DATA_ROOT}/train_only_lancedb/alfworld/lancedb_indices |
WEBARENA_LANCEDB_PATH |
LanceDB URI for WebArena (LTR scripts) | ${MATM_DATA_ROOT}/train_only_lancedb/webarena/lancedb_indices |
See .env.example for the full template.
The main config is traj_retrieval/run_evaluation_config.yaml. It defines:
- Environment selection:
environment_name(alfworldorwebarena) - Retrieval settings:
retrieval.frequency_strategy(CLI:--strategy) - Index location:
indices_dirunder each environment block (must match preprocess output) - LTR reranker config:
search_config.reranker(model type, feature set, model paths) - Per-environment overrides: evaluation sets, env-specific browser/handler config
Retrieval index paths written by the preprocess scripts (relative to repo root):
| Environment | indices_dir |
|---|---|
| ALFWorld | environments/train_only_lancedb/alfworld/lancedb_indices |
| WebArena | environments/train_only_lancedb/webarena/lancedb_indices |
The load_config() function in run_evaluation.py resolves paths using
MATM_DATA_ROOT and supports runtime overrides via CLI arguments. Index path
and LTR reranker settings are configured in YAML, not via CLI flags.
MATM's shared memory is a LanceDB table of state-conditioned trajectory chunks
that consumer agents retrieve from. The full generation pipeline and the
canonical splits that ship with the repo are documented in
traj_retrieval/preprocess/README.md.
The short version:
- Fetch ALFWorld data (WebArena: follow the WebArena setup guide separately):
python setup_environments.py --worlds alfworld- Build splits (canonical definitions land in
traj_retrieval/preprocess/new_splits/):
python traj_retrieval/preprocess/alfworld/create_data_splits_train_only.py
python traj_retrieval/preprocess/webarena/create_data_splits_train_only.py- Build the LanceDB index (writes to
environments/train_only_lancedb/<env>/lancedb_indices):
# ALFWorld
python traj_retrieval/preprocess/alfworld/create_seq_to_seq_indices_train_only.py
python traj_retrieval/preprocess/alfworld/create_lancedb_index_train_only.py
# WebArena
python traj_retrieval/preprocess/webarena/stage_gold_trajectories_train_only.py
python traj_retrieval/preprocess/webarena/create_lancedb_indices_train_only.py
python traj_retrieval/preprocess/webarena/create_lancedb_index_train_only.pyThe default indices_dir values in run_evaluation_config.yaml already point
at these paths.
- Pull (consumer agents): at inference, agents retrieve relevant chunks from
the LanceDB index via
LanceDBClient.search(...), wired through the retrieval handlers and the YAMLsearch_config. - Push (producer agents): set
ONLINE_MEMORY_ENABLED=1to let agents commit their own successful runtime trajectories back into the shared index during a run (AlfworldOnlineMemoryWriter/WebarenaOnlineMemoryWriter). This is what makes the memory population-level: any agent can act as both producer and consumer without coordination or joint training.
Evaluation is driven by traj_retrieval/run_evaluation_config.yaml. Common CLI
overrides: --environment-name, --strategy, --model, --rank-retrieve.
Ensure indices_dir in the YAML matches your built index (see
Configuration) before running retrieval experiments.
python traj_retrieval/run_evaluation.py \
--environment-name alfworld \
--strategy none \
--model "openai/gpt-oss-20b"Set retrieval strategy via CLI; index path comes from YAML (indices_dir):
python traj_retrieval/run_evaluation.py \
--environment-name alfworld \
--strategy agentic \
--rank-retrieve 1In run_evaluation_config.yaml, under environments.alfworld:
retrieval:
frequency_strategy: agentic # or pass --strategy agentic
indices_dir: environments/train_only_lancedb/alfworld/lancedb_indices
search_config:
candidate_generation:
rank_retrieve: 1
reranker:
enabled: falseEnable the LTR reranker in YAML (pre-trained models ship under ltr/ltr_models/):
python traj_retrieval/run_evaluation.py \
--environment-name alfworld \
--strategy agentic \
--rank-retrieve 5# environments.alfworld in run_evaluation_config.yaml
indices_dir: environments/train_only_lancedb/alfworld/lancedb_indices
search_config:
candidate_generation:
rank_retrieve: 5
reranker:
enabled: true
mode: ltr
ltr_model_type: svmrank
ltr_model_file: null # defaults to ltr/ltr_models/alfworld/svmrank_model.pklSVMRank inference uses the binaries shipped in ltr/svm_rank/ (override with
SVMRANK_BIN_DIR if needed).
WebArena uses a synchronous runner with the same CLI flag names:
python traj_retrieval/run_webarena.py \
--environment-name webarena \
--strategy agentic \
--rank-retrieve 5Set environments.webarena.indices_dir to
environments/train_only_lancedb/webarena/lancedb_indices in the YAML config.
MATM ships pre-trained LTR rerankers under ltr/ltr_models/{alfworld,webarena}/.
Most users only need to enable the reranker in YAML and run
evaluation. The steps below are for retraining a ranker from your own
retrieval-disagreement logs.
- Install dependencies (
requirements-base.txt). - Build the LanceDB index (Building the Shared Trajectory Index).
- Enable
search_config.rerankerinrun_evaluation_config.yaml(see LTR-Reranked Retrieval). - Run evaluation with
--strategy agenticand--rank-retrieve 5(or higher).
The runtime reads feature column order from ltr/data_out/<environment>/ltr_train.tsv.
That file is not committed (gitignored); if you use the shipped models without
retraining, copy or regenerate a matching TSV, or point feature_tsv in YAML to a
local copy. Shipped models were trained on the schema documented in the pipeline
output below.
Prerequisites (complete Building the Shared Trajectory Index first):
| Requirement | Purpose |
|---|---|
LanceDB index at environments/train_only_lancedb/<env>/lancedb_indices |
Feature enrichment + chunk alignment |
TF-IDF vectorizers under traj_retrieval/evaluation/ltr_data/<env>/ |
Lexical features during enrichment |
Trajectory logs under environments/<env>/traj_logs and simulation_traj_logs |
Disagreement mining |
Comparison JSON at traj_retrieval/evaluation/ltr_data/<env>/simulation_compare_<env>_e0_vs_e{6,7}_ranks.json |
Input to generate_disagreements.py |
Note on the comparison JSON.
generate_disagreements.pyconsumes a per-query comparison file that pairs the baseline retrieval ranks (e0) with an alternative experiment (e6for ALFWorld,e7for WebArena). This file is derived from your own evaluation runs (it is the per-query union of two evaluation runs' top-k candidates with ranks/scores) and is not shipped — override the path withDISAGREEMENTS_COMPARISON_FILE=/abs/path/to/your_file.jsonif your filename differs. Reach out to the authors if you want the exact JSON used in the paper.
Build TF-IDF vectorizers once per environment (requires LanceDB):
python traj_retrieval/evaluation/ltr_data/calculate_tf_idf_corpus.py| Step | Script | Main outputs |
|---|---|---|
| 0 | calculate_tf_idf_corpus.py |
ltr_data/<env>/tfidf_vectorizer_*.pkl |
| 1 | generate_disagreements.py |
ltr_data/<env>/processed_disagreements_*.json |
| 2 | enrich_disagreements.py |
ltr_data/<env>/1enriched_disagreements_*.json |
| 3 | build_chunk_aligned_enriched_jsonl.py |
*_chunk_aligned.json (+ .summary.json) |
| 4 | build_ltr_train_tsv.py |
ltr/data_out/<env>/ltr_train.tsv, qid_map.tsv |
| 5 | python -m ltr.train |
ltr/ltr_models/<env>/<model>_model.* |
Intermediate JSON under ltr_data/<env>/ is gitignored; only the TF-IDF pickles
and pipeline scripts are committed.
Run from the repository root. Set the environment for each stage:
# 1. Mine label disagreements from simulation + baseline trajectory logs
export DISAGREEMENTS_ENV=alfworld
python traj_retrieval/evaluation/ltr_data/generate_disagreements.py
# 2. Add dense/lexical/source-model features (uses LanceDB + TF-IDF)
export ENRICH_ENV=alfworld
python traj_retrieval/evaluation/ltr_data/enrich_disagreements.py
# 3. Align retrieved chunks to LanceDB rows (adds retrieved_doc)
python traj_retrieval/evaluation/ltr_data/build_chunk_aligned_enriched_jsonl.py \
--inputs traj_retrieval/evaluation/ltr_data/alfworld/1enriched_disagreements_multiple_queries_t99.json
# 4. Export learning-to-rank TSV
python traj_retrieval/evaluation/ltr_data/build_ltr_train_tsv.py \
--inputs traj_retrieval/evaluation/ltr_data/alfworld/1enriched_disagreements_multiple_queries_t99_chunk_aligned.json \
--environment alfworld
# 5. Train a ranker (ffn | lambdamart | svmrank)
python -m ltr.train --environment alfworld --model-type svmrankSame five stages, with webarena/ paths and the e0_vs_e7 comparison file:
# 1. Mine label disagreements
export DISAGREEMENTS_ENV=webarena
python traj_retrieval/evaluation/ltr_data/generate_disagreements.py
# 2. Add dense/lexical/source-model features
export ENRICH_ENV=webarena
python traj_retrieval/evaluation/ltr_data/enrich_disagreements.py
# 3. Align retrieved chunks to LanceDB rows
python traj_retrieval/evaluation/ltr_data/build_chunk_aligned_enriched_jsonl.py \
--inputs traj_retrieval/evaluation/ltr_data/webarena/1enriched_disagreements_multiple_queries_t99.json
# 4. Export learning-to-rank TSV
python traj_retrieval/evaluation/ltr_data/build_ltr_train_tsv.py \
--inputs traj_retrieval/evaluation/ltr_data/webarena/1enriched_disagreements_multiple_queries_t99_chunk_aligned.json \
--environment webarena
# 5. Train a ranker
python -m ltr.train --environment webarena --model-type svmrankIf your WebArena LanceDB index is not under the default MATM_DATA_ROOT layout,
set WEBARENA_LANCEDB_PATH to its absolute path before running steps 2–3.
| Variable | Used by | Default |
|---|---|---|
DISAGREEMENTS_ENV |
generate_disagreements.py |
alfworld |
ENRICH_ENV |
enrich_disagreements.py |
alfworld |
MATM_DATA_ROOT |
All LTR scripts | ./environments |
ALFWORLD_LANCEDB_PATH |
Enrichment / chunk alignment | ${MATM_DATA_ROOT}/train_only_lancedb/alfworld/lancedb_indices |
WEBARENA_LANCEDB_PATH |
Enrichment / chunk alignment | ${MATM_DATA_ROOT}/train_only_lancedb/webarena/lancedb_indices |
NUM_WORKERS |
Parallel enrichment / alignment | 32 (enrich), 1 (chunk align) |
Input/output filenames for steps 1–2 can be overridden with DISAGREEMENTS_* and
ENRICH_* env vars (see the top of each script).
build_ltr_train_tsv.py writes:
ltr/data_out/<env>/ltr_train.tsv— columnsqid,label,docid, then numeric features.labelis the disagreement score from step 1;docidis the run key for each retrieved candidate.ltr/data_out/<env>/qid_map.tsv— maps eachqidto its cluster-head query text.
To match the feature schema of a shipped model when retraining, pass a reference header:
python traj_retrieval/evaluation/ltr_data/build_ltr_train_tsv.py \
--inputs traj_retrieval/evaluation/ltr_data/alfworld/<chunk_aligned>.json \
--environment alfworld \
--reference-tsv ltr/data_out/alfworld/ltr_train.tsvMultiple --inputs files can be merged into one TSV (same --environment).
Point the YAML reranker block at your new model (or leave ltr_model_file: null to
use the default path under ltr/ltr_models/<env>/):
search_config:
reranker:
enabled: true
mode: ltr
ltr_model_type: svmrank
ltr_model_file: null
feature_tsv: ltr/data_out/alfworld/ltr_train.tsvSee LTR-Reranked Retrieval for a full evaluation example.
SVMRank inference uses the binaries in ltr/svm_rank/ (override with SVMRANK_BIN_DIR).
Trained models are stored in ltr/ltr_models/{alfworld,webarena}/.
Each ranker family can be loaded directly from its saved file:
from ltr.models import SVMRanker # or FFNRanker, LambdaMARTRanker
model = SVMRanker.load("ltr/ltr_models/alfworld/svmrank_model.pkl")
scores = model.predict(X, qid) # X: (n_samples, n_features), qid: (n_samples,)At evaluation time the retrieval runtime loads models from the YAML
search_config.reranker block (ltr_model_type, optional ltr_model_file).
Generated trajectories are available on HuggingFace:
from datasets import load_dataset
dataset = load_dataset("toeunkim/matm-trajectories")The dataset includes:
- Evaluation trajectories: compact action-observation sequences from baseline, single-stage, and LTR-reranked runs across a population of 34 consumer models.
- Expert/source trajectories: publicly available successful trajectories used to build the shared index during the pre-population phase.
- Metadata: model identity, retrieval strategy, task type, final score, success flag, step count, and more.
@article{kim2026multiagenttransactivememory,
title={Multi-Agent Transactive Memory},
author={To Eun Kim and Xuhong He and Dishank Jain and Ambuj Agrawal and Negar Arabzadeh and Fernando Diaz},
year={2026},
eprint={2606.19911},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2606.19911},
}See LICENSE for details.