SkillAgentSearch skills...

Synalinks

From idea to production in just few lines: Graph-Based Programmable Neuro-Symbolic LM Framework - a production-first LM framework built with decade old Deep Learning best practices

Install / Use

/learn @SynaLinks/Synalinks

README

<div align="center"> <img height=200 src="https://github.com/SynaLinks/synalinks/blob/main/img/synalinks.svg?raw=true"> </div> <div align="center">

<b>From idea to production in just few lines</b>

<em>The first neuro-symbolic Language Model (LM) framework leveraging the simplicity of Keras and the rigor of Deep Learning best practices.</em>

<b>Build RAGs, autonomous agents, multi-agents systems, self-evolving systems and more in just few lines</b>

Deutsch | English | Español | Français | 日本語 | 한국어 | Português | Русский | 中文

<p align="center"> <a href="https://synalinks.github.io/synalinks" target="_blank"><strong>Documentation</strong></a> · <a href="https://synalinks.github.io/synalinks/FAQ/" target="_blank"><strong>FAQ</strong></a> · <a href="https://discord.gg/82nt97uXcM" target="_blank"><strong>Discord</strong></a> · <a href="https://github.com/SynaLinks/synalinks/tree/main/examples" target="_blank"><strong>Code Examples</strong></a> </p> </div> <div align="center">

⭐ If you find Synalinks useful, please star the repo! Help us reach more AI/ML engineers and grow the community. ⭐

Beta Code style: black Coverage Badge Downloads Discord Python package License: Apache-2.0 Ask DeepWiki

</div> <div align="center">

Too busy to read the documentation? Give the llms.txt or llms-full.txt to you favorite LMs or AI coding tools. Or better, use Synalinks Claude Skills with Claude Code to use Synalinks right away!

</div>

What Is Synalinks?

Synalinks is an open-source neuro-symbolic framework that makes it simple to create, train, evaluate, and deploy advanced LM-based applications, including RAGs, autonomous agents, and self-evolving reasoning systems.

Think Keras for Language Models applications, a clean, declarative API where:

  • 🧩 You compose Modules like you would with deep learning Layers.
  • ⚙️ You train & optimize with in-context reinforcement learning.
  • 🌐 You deploy as REST APIs or MCP servers.

Key Principles

  • Progressive complexity: Start simple and grow advanced naturally.
  • Neuro-symbolic learning: Combine logic, structure, and language models.
  • In-context optimization: Improve model reasoning without retraining weights.

Who Is It For?

<div align="center">

| Role | Why Synalinks Helps | | ------------------------- | -------------------------------------------------------- | | 🧑‍💻 Developers | Build complex LM apps without boilerplate. | | 🧠 Researchers | Prototype neuro-symbolic and RL-in-context systems fast. | | 🏢 Data Scientists | Integrate LM workflows with APIs & databases. | | 🎓 Students/Hobbyists | Learn AI composition in a clean, intuitive framework. |

</div>

Why Synalinks?

Building robust LM apps is hard. Synalinks simplifies it with:

  • Prompt/Anything optimization per module via In-Context RL
  • Versionable, JSON-serializable pipelines
  • Constrained structured outputs (JSON) for correctness
  • Automatic async & parallel execution by default
  • Metrics, rewards & evaluations built-in
  • Native integrations: Ollama, Anthropic, Mistral, Azure, Groq, Gemini
  • Embeddable fast knowledge base support: based on DuckDB
  • API-ready: Deploy with FastAPI or FastMCP
  • KerasTuner compatibility for hyperparameter search
  • Built-In MLFlow callbacks and hooks for observability
<div align="center">

| Framework | MCP | Logical Flow | Robust Branching | Parallel Function Calling | Hyperparameter Tuning | Ease of Use | | --- | --- | --- | --- | --- | --- | --- | | Synalinks | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | 😀 | | DSPy | ✅ Yes | ❌ No | ❌ No | ❌ No | ❌ No | 😢 | | AdalFlow | ✅ Yes | ❌ No | ❌ No | ❌ No | ❌ No | 😢 | | TextGrad | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No | 😭 | | Trace | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No | 😭 |

</div>

Installation

uv pip install synalinks

Example

import synalinks
import asyncio

class Query(synalinks.DataModel):
    query: str = synalinks.Field(
        description="The user query",
    )

class NumericalAnswer(synalinks.DataModel):
    answer: float = synalinks.Field(
        description="The final numerical answer",
    )

language_model = synalinks.LanguageModel(
    model="gemini/gemini-2.5-pro",
)

@synalinks.saving.register_synalinks_serializable()
async def calculate(expression: str):
    """Calculate the result of a mathematical expression.

    Args:
        expression (str): The mathematical expression to calculate, such as
            '2 + 2'. The expression can contain numbers, operators (+, -, *, /),
            parentheses, and spaces.
    """
    if not all(char in "0123456789+-*/(). " for char in expression):
        return {
            "result": None,
            "log": "Error: invalid characters in expression",
        }
    try:
        # Evaluate the mathematical expression safely
        result = round(float(eval(expression, {"__builtins__": None}, {})), 2)
        return {
            "result": result,
            "log": "Successfully executed",
        }
    except Exception as e:
        return {
            "result": None,
            "log": f"Error: {e}",
        }

async def main():
    inputs = synalinks.Input(data_model=Query)

    outputs = await synalinks.FunctionCallingAgent(
        data_model=NumericalAnswer,
        tools=[
            synalinks.Tool(calculate),
        ],
        language_model=language_model,
    )(inputs)

    program = synalinks.Program(
        inputs=inputs,
        outputs=outputs,
        name="math_agent",
        description="A math agent",
    )

Data Model Operators

Synalinks provides Python operators for combining and manipulating data models, enabling sophisticated control flow:

<div align="center">

| Operator | Name | Description | Use Case | | :---: | --- | --- | --- | | + | Concatenation | Combines fields from both data models. Raises exception if either is None. | Merging outputs from parallel branches | | & | Logical And | Safe concatenation that returns None if either input is None. | Combining with potentially null branch outputs | | \| | Logical Or | Returns the non-None data model. If both are non-None, merges them. | Gathering outputs from conditional branches | | ^ | Logical Xor | Returns data if exactly one input is non-None, otherwise None. | Exclusive branch selection | | ~ | Logical Not | Returns None if input is non-None, or a empty data model if None. | Inverting branch conditions | | in | Contains | Checks if a string key exists in the schema properties, or if another data model's schema is contained. Returns True or False. | Conditional field checking, schema validation |

</div>
# Parallel branches with concatenation
x1 = await generator1(inputs)
x2 = await generator2(inputs)
combined = x1 & x2  # Merge both outputs

# Conditional branches with logical or
(easy, hard) = await synalinks.Branch(
    question="Is this query complex?",
    labels=["easy", "hard"],
    branches=[simple_generator, complex_generator],
)(inputs)
result = easy | hard  # Get whichever branch was selected

Getting a summary of your program

To print a tabular summary of your program:

program.summary()

Or a plot (Useful to document your system):

synalinks.utils.plot_program(
    program,
    show_module_names=True,
    show_trainable=True,
    show_schemas=True,
)

Running your program

To run your program use the following:

result = await program(
    Query(
        query=(
            "A bookstore receives a shipment of 135 new books."
            "They place the books evenly onto 9 shelves."
            "Later, they decide to move 3 books from each shelf to a display table"
            " at the front of the store. "
            "How many books are left on the shelves after the books are moved?"
        )
    ),
)

Training your program/agent

async def main():

    # ... your program definition

    (x_train, y_train), (x_test, y_test) = synalinks.datasets.gsm8k.load_data()

    program.compile(
        reward=synalinks.rewards.ExactMatch(
            in_mask=["answer"],
        ),
        optimizer=synalinks.optimizers.OMEGA(
            language_model=language_model,
            embedding_model=embedding_model,
        ),
    )

    batch_size=1
    epochs=10

    history = await program.fit(
        x_train,
        y_train,
        validation_split=0.2,
        batch_size=batch_size,
        epochs=epochs,
    )

if __name__ == "__main__":
    as
View on GitHub
GitHub Stars425
CategoryEducation
Updated2d ago
Forks36

Languages

Python

Security Score

100/100

Audited on Mar 25, 2026

No findings