Skip to content

Commit 5906594

Browse files
committed
Add operator examples
1 parent c6933d9 commit 5906594

File tree

5 files changed

+297
-1
lines changed

5 files changed

+297
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<a href="https://synalinks.github.io/synalinks" target="_blank"><strong>Documentation</strong></a> ·
1313
<a href="https://synalinks.github.io/synalinks/FAQ/" target="_blank"><strong>FAQ</strong></a> ·
1414
<a href="https://discord.gg/82nt97uXcM" target="_blank"><strong>Discord</strong></a> ·
15-
<a href="https://synalinks.github.io/synalinks" target="_blank"><strong>Code Examples</strong></a>
15+
<a href="https://github.com/SynaLinks/synalinks/tree/main/examples" target="_blank"><strong>Code Examples</strong></a>
1616
</p>
1717

1818
</div>
@@ -28,6 +28,7 @@
2828
[![Discord](https://img.shields.io/discord/1118241178723291219)](https://discord.gg/82nt97uXcM)
2929
[![Python package](https://github.com/SynaLinks/Synalinks/actions/workflows/tests.yml/badge.svg)](https://github.com/SynaLinks/SynaLinks/actions/workflows/tests.yml)
3030
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://opensource.org/license/apache-2-0)
31+
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/SynaLinks/synalinks)
3132

3233
Too busy to read the documentation? Give **[LLM.md](https://raw.githubusercontent.com/SynaLinks/synalinks/refs/heads/main/LLM.md)** to your favorite LM provider.
3334

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import synalinks
2+
3+
# Concatenation with Synalinks
4+
5+
class Query(synalinks.DataModel):
6+
query: str
7+
8+
9+
class Answer(synalinks.DataModel):
10+
answer: str
11+
12+
# Synalinks operators works at a metaclass level
13+
# In that case, the result is a `SymbolicDataModel`
14+
# A `SymbolicDataModel` can be understand as a data
15+
# specification/contract. It only contains a JSON schema
16+
# and cannot be used for computation. It allow Synalinks
17+
# to build directed acyclic graph (DAG) of computation
18+
# from inputs and outputs, like the tensor shape
19+
# in deep learning frameworks.
20+
21+
qa_pair = Query + Answer
22+
23+
assert isinstance(qa_pair, synalinks.SymbolicDataModel)
24+
25+
print(qa_pair.prettify_schema())
26+
# {
27+
# "additionalProperties": false,
28+
# "properties": {
29+
# "query": {
30+
# "title": "Query",
31+
# "type": "string"
32+
# },
33+
# "answer": {
34+
# "title": "Answer",
35+
# "type": "string"
36+
# }
37+
# },
38+
# "required": [
39+
# "query",
40+
# "answer"
41+
# ],
42+
# "title": "Query",
43+
# "type": "object"
44+
# }
45+
46+
# Once we concatenate two instanciated data models, the result
47+
# is a JsonDataModel, a data model containing both a JSON schema and
48+
# a JSON object containing the actual data.
49+
50+
qa_pair = \
51+
Query(query="What is the French city of aeronautics and robotics?") + \
52+
Answer(answer="Toulouse")
53+
54+
assert isinstance(qa_pair, synalinks.JsonDataModel)
55+
56+
print(qa_pair.prettify_json())
57+
# {
58+
# "query": "What is the French city of aeronautics and robotics?",
59+
# "answer": "Toulouse"
60+
# }
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import synalinks
2+
3+
class Query(synalinks.DataModel):
4+
query: str
5+
6+
# Concatenation with Synalinks (Part 2)
7+
8+
# What happen if you concatenate two data
9+
# models with the same fields?
10+
# When property names conflict, numerical suffixes are
11+
# added to ensure uniqueness.
12+
13+
two_queries = Query + Query
14+
15+
print(two_queries.prettify_schema())
16+
17+
# {
18+
# "additionalProperties": false,
19+
# "properties": {
20+
# "query": {
21+
# "title": "Query",
22+
# "type": "string"
23+
# },
24+
# "query_1": {
25+
# "title": "Query 1",
26+
# "type": "string"
27+
# }
28+
# },
29+
# "required": [
30+
# "query",
31+
# "query_1"
32+
# ],
33+
# "title": "Query",
34+
# "type": "object"
35+
# }
36+
37+
two_queries = \
38+
Query(query="Why is neuro-symbolic systems powering the next AI wave?") + \
39+
Query(query="Can you give a multiple of 5?")
40+
41+
42+
print(two_queries.prettify_json())
43+
# {
44+
# "query": "Why is neuro-symbolic systems powering the next AI wave?",
45+
# "query_1": "Can you give a multiple of 5?"
46+
# }
47+
48+
# Now, what happen when you concatenate with `None`?
49+
# An exception is raised!
50+
51+
failing_query = \
52+
Query(query="Why is neuro-symbolic AI powering the next wave?") + \
53+
None
54+
# ValueError: Received x1=query='Why is neuro-symbolic AI powering the next wave?' and x2=None
55+
56+
# This behavior can be summarized with the following truth table:
57+
58+
# Truth Table:
59+
60+
# | `x1` | `x2` | Concat (`+`) |
61+
# | ------ | ------ | ----------------- |
62+
# | `x1` | `x2` | `x1 + x2` |
63+
# | `x1` | `None` | `Exception` |
64+
# | `None` | `x2` | `Exception` |
65+
# | `None` | `None` | `Exception` |
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import synalinks
2+
3+
# Logical AND with Synalinks
4+
5+
class Query(synalinks.DataModel):
6+
query: str
7+
8+
9+
class Answer(synalinks.DataModel):
10+
answer: str
11+
12+
13+
qa_pair = Query & Answer
14+
15+
assert isinstance(qa_pair, synalinks.SymbolicDataModel)
16+
17+
print(qa_pair.prettify_schema())
18+
# {
19+
# "additionalProperties": false,
20+
# "properties": {
21+
# "query": {
22+
# "title": "Query",
23+
# "type": "string"
24+
# },
25+
# "answer": {
26+
# "title": "Answer",
27+
# "type": "string"
28+
# }
29+
# },
30+
# "required": [
31+
# "query",
32+
# "answer"
33+
# ],
34+
# "title": "Query",
35+
# "type": "object"
36+
# }
37+
38+
# When performing an And operation with `None` the output is `None`
39+
# You can see the logical And as a robust concatenation operation.
40+
41+
qa_pair = Query(query="Why is neuro-symbolic AI powering the next wave?") & None
42+
43+
assert isinstance(qa_pair, None)
44+
45+
# Here is the table summarizing the behavior
46+
47+
# Truth Table:
48+
49+
# | `x1` | `x2` | Logical And (`&`) |
50+
# | ------ | ------ | ----------------- |
51+
# | `x1` | `x2` | `x1 + x2` |
52+
# | `x1` | `None` | `None` |
53+
# | `None` | `x2` | `None` |
54+
# | `None` | `None` | `None` |
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import synalinks
2+
import asyncio
3+
4+
class Query(synalinks.DataModel):
5+
query: str
6+
7+
class Answer(synalinks.DataModel):
8+
answer: str
9+
10+
class AnswerWithThinking(synalinks.DataModel):
11+
thinking: str
12+
answer: str
13+
14+
# Logical Or
15+
16+
# When a two data models are provided, the logical or perform a concatenation
17+
# of the two data models. However when given a `None`, it ignore it to give
18+
# you the one that isn't None.
19+
20+
# This behavior can be summarized in the following truth table:
21+
22+
# Truth Table:
23+
24+
# | `x1` | `x2` | Logical Or (`|`) |
25+
# | ------ | ------ | ---------------- |
26+
# | `x1` | `x2` | `x1 + x2` |
27+
# | `x1` | `None` | `x1` |
28+
# | `None` | `x2` | `x2` |
29+
# | `None` | `None` | `None` |
30+
31+
answer = Answer(answer="Toulouse") | None
32+
33+
print(answer.prettify_json())
34+
# {
35+
# "answer": "Toulouse"
36+
# }
37+
38+
answer = None | AnswerWithThinking(
39+
thinking=
40+
(
41+
"LAAS CNRS (Laboratoire d'Analyse et d'Architecture des Systèmes) is located in "
42+
"Toulouse and is renowned for its research in robotics."
43+
" Toulouse is also widely recognized as a central hub for aeronautics and"
44+
" space in Europe. It houses the headquarters of Airbus and several "
45+
"important aerospace research centers. and aeronautics."
46+
),
47+
answer="Toulouse")
48+
49+
print(answer.prettify_json())
50+
# {
51+
# "thinking": "LAAS CNRS (Laboratoire d'Analyse et d'Architecture des
52+
# Syst\u00e8mes) is located in Toulouse and is renowned for its research
53+
# in robotics. Toulouse is also widely recognized as a central hub for
54+
# aeronautics and space in Europe. It houses the headquarters of Airbus
55+
# and several important aerospace research centers. and aeronautics.",
56+
# "answer": "Toulouse"
57+
# }
58+
59+
# Why is that useful ? Let's explain it with an example,
60+
# imagine you want an adaptative system that is able to
61+
# answer shortly, or take more time to "think" before answering
62+
# depending on the question difficulty.
63+
#
64+
# Example:
65+
66+
async def main():
67+
language_model = synalinks.LanguageModel(model="ollama/mistral")
68+
69+
inputs = synalinks.Input(data_model=Query)
70+
answer_without_thinking, answer_with_thinking = await synalinks.Branch(
71+
question="Evaluate the difficulty of the query",
72+
labels=["easy", "difficult"],
73+
branches=[
74+
synalinks.Generator(
75+
data_model=Answer,
76+
language_model=language_model,
77+
),
78+
synalinks.Generator(
79+
data_model=AnswerWithThinking,
80+
language_model=language_model,
81+
)
82+
],
83+
language_model=language_model,
84+
# We can optionally return the decision,
85+
# in Synalinks there is no black-box component!
86+
# Every LM inference, can be returned
87+
# for evaluation or explainability
88+
return_decision=False,
89+
)(inputs)
90+
91+
# The outputs is the answer without thinking OR the answer with thinking
92+
outputs = answer_without_thinking | answer_with_thinking
93+
94+
program = synalinks.Program(
95+
inputs=inputs,
96+
outputs=outputs,
97+
name="adaptative_qa",
98+
description="A program that take the time to think if the query is difficult to answer"
99+
)
100+
101+
answer = await program(Query(query="What is French city of robotics and aeronautics?"))
102+
103+
print(answer.prettify_json())
104+
# {
105+
# "thinking": "The answer to the given query involves finding a city in
106+
# France that is known for robotics and aeronautics. While there might be
107+
# several cities that have significant presence in these fields, Toulouse
108+
# is one of the most renowned due to the presence of well-established
109+
# institutions like EADS (European Aeronautic Defence and Space Company),
110+
# IRIT (Institut de Recherche en Informatique pour le Traitement Automatique des Images)
111+
# and LAAS CNRS (Laboratoire d'Analyse et d'Architecture des Syst\u00e8mes).",
112+
# "answer": "Toulouse"
113+
# }
114+
115+
if __name__ == "__main__":
116+
asyncio.run(main())

0 commit comments

Comments
 (0)