Getting Started
Getting Started with Synalinks
Welcome to Synalinks! This guide introduces you to the fundamental concepts and helps you build your first AI-powered application.
What is Synalinks?
Synalinks is a neuro-symbolic framework for building Language Model (LM) applications. Unlike traditional approaches where you write prompts manually, Synalinks lets you define what you want (using data models) and handles the how (prompt construction, parsing, validation) automatically.
graph LR
subgraph Traditional Approach
A[Write Prompt] --> B[Call LLM API]
B --> C[Parse Response]
C --> D[Handle Errors]
end
subgraph Synalinks Approach
E[Define DataModel] --> F[Synalinks]
F --> G[Structured Output]
end
Why Synalinks?
Traditional LLM development has several pain points:
- Prompt Engineering: Manually crafting prompts is tedious and error-prone
- Output Parsing: LLM responses are unstructured text that needs parsing
- Schema Validation: Ensuring responses match expected formats is difficult
- Reproducibility: Results vary based on prompt wording
Synalinks solves these by:
- Auto-generating prompts from your data model definitions
- Constraining outputs to always match your schema (no parsing errors!)
- Providing type safety through Pydantic-based data models
- Enabling training to improve your programs over time
Installation
# Using pip
pip install synalinks
# Or using uv (recommended for faster installs)
uv pip install synalinks
Environment Setup
Synalinks works with any OpenAI-compatible API. Set up your credentials:
# Create a .env file in your project root
OPENAI_API_KEY=your-api-key-here
# For Anthropic models
ANTHROPIC_API_KEY=your-anthropic-key
# For local models (Ollama) - no key needed
# Just run: ollama serve
Core Concepts
1. Data Models: The Foundation
In Synalinks, everything revolves around Data Models. A DataModel defines the structure of your inputs and outputs using Python classes:
import synalinks
class Question(synalinks.DataModel):
"""The input to our program."""
question: str = synalinks.Field(
description="The question to answer"
)
class Answer(synalinks.DataModel):
"""The output from our program."""
thinking: str = synalinks.Field(
description="Step-by-step reasoning process"
)
answer: str = synalinks.Field(
description="The final answer"
)
The description parameter is crucial - it tells the LLM what each field
should contain. Think of it as documentation that the AI reads.
2. The Generator Module
The Generator is the core module that transforms inputs into outputs:
generator = synalinks.Generator(
data_model=Answer, # What structure to output
language_model=language_model, # Which LLM to use
)
3. Programs: Composable Pipelines
A Program wraps your modules into a reusable, trainable unit:
Complete Example
Here's a complete, runnable example that demonstrates the core concepts:
import asyncio
from dotenv import load_dotenv
import synalinks
# Step 1: Define your data models
class Question(synalinks.DataModel):
"""Input: A question from the user."""
question: str = synalinks.Field(
description="The question to answer"
)
class Answer(synalinks.DataModel):
"""Output: An answer with reasoning."""
thinking: str = synalinks.Field(
description="Your step-by-step reasoning process"
)
answer: str = synalinks.Field(
description="The final answer based on your reasoning"
)
async def main():
# Load environment variables (API keys)
load_dotenv()
# Clear session for reproducible module naming
synalinks.clear_session()
# Step 2: Initialize the language model
language_model = synalinks.LanguageModel(
model="openai/gpt-4.1-mini" # Or "anthropic/claude-3-haiku", etc.
)
# Step 3: Build the program using the Functional API
inputs = synalinks.Input(data_model=Question)
outputs = await synalinks.Generator(
data_model=Answer,
language_model=language_model,
)(inputs)
program = synalinks.Program(
inputs=inputs,
outputs=outputs,
name="qa_program",
description="A simple question-answering program",
)
# Step 4: Run the program
result = await program(
Question(question="What is the capital of France?")
)
# Step 5: Access the structured output
print(f"Thinking: {result['thinking']}")
print(f"Answer: {result['answer']}")
if __name__ == "__main__":
asyncio.run(main())
Understanding the Output
When you run the program, you get a structured dictionary that exactly
matches your Answer data model:
This is guaranteed by Synalinks' constrained generation - the LLM is forced to produce valid JSON that matches your schema.
Key Takeaways
-
No Manual Prompting: Define data models instead of writing prompts. Synalinks automatically constructs effective prompts from your field descriptions.
-
Structured Output: Every response is guaranteed to match your schema. No more parsing errors or malformed responses.
-
Field Descriptions Matter: The
descriptionparameter guides the LLM. Write clear, specific descriptions for best results. -
Chain of Thought: Adding a "thinking" field encourages the LLM to reason step-by-step, improving accuracy on complex tasks.
-
Session Management: Use
synalinks.clear_session()at the start of scripts for reproducible module naming.
Next Steps
Now that you understand the basics, continue to:
- Guide 2: Data Models - Deep dive into data model features
- Guide 3: Programs - Learn about different program architectures
- Guide 4: Modules - Explore the available modules
API References
Answer
Bases: DataModel
Output: An answer with reasoning.