synalinks-training/SKILL.md
Use when training Synalinks programs — program.compile() / fit() / evaluate() / predict(), validation_split, validation_data, batch_size, epochs, callbacks (ProgramCheckpoint, custom Callback subclasses), History, in-context reinforcement learning workflow. For reward functions see synalinks-rewards; for optimizer internals see synalinks-optimizers.
npx skillsauth add synalinks/synalinks-skills synalinks-trainingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Train programs with in-context reinforcement learning. Unlike traditional ML, no weights are updated — instead, trainable variables (prompts, examples, plans) are evolved by the optimizer to maximize a reward.
1. Build a Program (functional / sequential / subclassing)
2. compile() — attach reward, optimizer, metrics
3. fit() — train on (x_train, y_train), monitoring validation
4. evaluate() — measure on test set
5. predict() — batch inference
6. save() — persist architecture + variables + optimizer state
import numpy as np
import synalinks
class Question(synalinks.DataModel):
question: str = synalinks.Field(description="A question")
class Answer(synalinks.DataModel):
thinking: str = synalinks.Field(description="Step-by-step reasoning")
answer: str = synalinks.Field(description="Final answer")
async def train():
lm = synalinks.LanguageModel(model="openai/gpt-4o-mini")
inputs = synalinks.Input(data_model=Question)
outputs = await synalinks.Generator(data_model=Answer, language_model=lm)(inputs)
program = synalinks.Program(inputs=inputs, outputs=outputs, name="qa")
program.compile(
reward=synalinks.rewards.ExactMatch(in_mask=["answer"]),
optimizer=synalinks.optimizers.RandomFewShot(),
metrics=[synalinks.metrics.F1Score(in_mask=["answer"])],
)
history = await program.fit(
x=x_train, y=y_train,
validation_split=0.2,
epochs=10,
batch_size=32,
)
metrics = await program.evaluate(x=x_test, y=y_test, batch_size=32)
program.save("trained.json")
compile() accepts string identifiers (case-insensitive), config dicts, or instances:
# Set defaults so string-form optimizers can resolve LM/EM
synalinks.set_default_language_model("openai/gpt-4o-mini")
synalinks.set_default_embedding_model("openai/text-embedding-3-small")
program.compile(
optimizer="omega", # or "randomfewshot", "greedyoptimizer"
reward="exactmatch", # or "cosinesimilarity", "lmasjudge"
metrics=["mean"], # or [{"class_name": "Mean", "config": {}}]
)
Training data is NumPy arrays of DataModel instances:
import numpy as np
x_train = np.array([
Question(question="What is 5 + 3?"),
Question(question="Capital of France?"),
], dtype="object")
y_train = np.array([
Answer(thinking="5 + 3 = 8", answer="8"),
Answer(thinking="Paris is the capital of France.", answer="Paris"),
], dtype="object")
Built-in datasets return data in this format — see synalinks-datasets.
program.compile(
reward=synalinks.rewards.ExactMatch(in_mask=["answer"]),
optimizer=synalinks.optimizers.RandomFewShot(),
metrics=[synalinks.metrics.F1Score(in_mask=["answer"])],
)
history = await program.fit(
x=x_train, # NumPy array of input DataModels
y=y_train, # NumPy array of target DataModels
validation_split=0.1, # Defaults to 0.1 — last fraction held out
# OR:
# validation_data=(x_val, y_val),
epochs=1, # Defaults to 1
batch_size=1, # Defaults to 1
minibatch_size=4, # Random val sub-sample per train batch (default 4)
validation_batch_size=32, # Defaults to 32
validation_freq=1, # Run end-of-epoch validation every N epochs
callbacks=[...],
)
Returns a History object with metrics per epoch (visualizable via synalinks.utils.plot_history — see synalinks-datasets).
Note: fit() always iterates batches with shuffle=False internally — there is no public shuffle argument.
metrics = await program.evaluate(
x=x_test,
y=y_test,
batch_size=32,
)
Batch inference, no labels required:
predictions = await program.predict(x_test, batch_size=32)
Save the best program by a monitored metric:
checkpoint = synalinks.callbacks.ProgramCheckpoint(
filepath="best.json",
monitor="val_reward", # which metric to track
mode="max", # "max" or "min"
save_best_only=True,
)
history = await program.fit(..., callbacks=[checkpoint])
class MyCallback(synalinks.callbacks.Callback):
def on_train_begin(self, logs=None):
print("Training started")
def on_epoch_end(self, epoch, logs=None):
print(f"Epoch {epoch}: reward={logs.get('reward')}")
def on_train_end(self, logs=None):
print("Training finished")
Callback hooks are synchronous (they're invoked synchronously by CallbackList). Available hooks: on_{train,test,predict}_{begin,end}, on_epoch_{begin,end}, on_{train,test,predict}_batch_{begin,end}. The callback's bound program is available as self.program.
Saves architecture + trainable variables + optimizer state:
program.save("model.json")
program = synalinks.Program.load("model.json")
Useful for sharing trained prompts without architecture:
program.save_variables("variables.json")
program.load_variables("variables.json")
synalinks.utils.plot_history(history, to_folder="output")
# Multiple evaluations for stability analysis
results = []
for _ in range(5):
results.append(await program.evaluate(x_test, y_test))
synalinks.utils.plot_metrics_with_mean_and_std(results, to_folder="output")
# Before/after comparison
synalinks.utils.plot_metrics_comparison_with_mean_and_std({
"before_training": baseline,
"after_training": trained,
}, to_folder="output")
batch_size small for expensive models — each example is an LM callpredict() is stochastic, average for stabilitydevelopment
Use when configuring or writing Synalinks reward functions and metrics — ExactMatch, CosineSimilarity, LMAsJudge, ProgramAsJudge, RewardFunctionWrapper, custom reward functions (async, register_synalinks_serializable), in_mask / out_mask filtering, F1Score / FBetaScore / BinaryF1Score / ListF1Score metrics, MeanMetricWrapper, or whenever you're shaping the signal that drives optimization.
tools
Use when integrating Synalinks with LM providers — picking the right model prefix (openai/, anthropic/, ollama/, groq/, cohere/, openrouter/, bedrock/, deepseek/, together_ai/, doubleword/, hosted_vllm/ (alias vllm/), gemini/, xai/, mistral/, azure/), env vars per provider, structured-output dispatch (constrained json_schema vs tool-call), local OpenAI-compatible servers (LMStudio, vLLM) requiring litellm.register_model and a dummy OPENAI_API_KEY, and OpenRouter embeddings (LiteLLM doesn't support them — use OpenRouterEmbeddingModel).
development
Use when building or composing a Synalinks Program — the four building APIs (Functional, Sequential, Subclassing, Mixed), Input nodes, multi-input/multi-output graphs, the call/build lifecycle, training=True/False semantics, summary, get_module, plot_program, save/load, get_state_tree/set_state_tree, get_config/from_config and custom serialization. For DataModel/Field, JSON operators (+ & | ^ ~), and LanguageModel/EmbeddingModel basics see synalinks-core. For inner modules see synalinks-modules; for compile/fit/evaluate/predict see synalinks-training.
development
Use when picking, configuring, or tuning a Synalinks optimizer — RandomFewShot (nb_min_examples, nb_max_examples, sampling, sampling_temperature), OMEGA (Dominated Novelty Search, mutation/crossover, k_nearest_fitter, population_size, mutation_temperature, crossover_temperature, selection_temperature, merging_rate, algorithm "dns" vs "ga", selection "softmax"/"best"/"random", reasoning_effort), or evolutionary / quality-diversity prompt optimization in general.