Skip to main content
Stage 4 · Query

Run queries

Your pipeline is deployed, and keys are already generated. Now you run encrypted queries against it. Start a worker, load the existing key, send as many queries as you need, then stop the worker. The worker only ever receives ciphertext, so your input and result stay private.

Start, load key, query, stop

Querying is a loop with a clear start and end. You turn a worker on, load the key you generated in Key generation, run queries while it is up, and turn it off when you are done.
Start worker
Turn the worker on when you are ready.
credits begin
Load existing key
Call generate_key(load_if_exists=True) to reuse the Stage 3 key context.
×N
run_query()
Send a query, get a result. Repeat as many times as you want.
while worker is up
Stop worker
Turn it off when your work is done.
credits stop
You pay for the worker's runtime, not per query

Start the worker

A worker runs the body of your pipeline. Start it with the model_id from deploy. It uses credits from this moment until you stop it, so start it when you are ready to query.
query.pyPYTHON
# credits begin here
with studio.workers.running(model_id, stop_on_exit=True):
    # load key and run queries inside this block
    ...

Load the existing key

Create a query client with the access token from Key generation, then call generate_key(load_if_exists=True). That loads the secret key already on your machine. It does not generate a new key or re-register the evaluation key if those artifacts already exist. You installed the query client with Lattica Studio at setup. In a researcher setup, that is the same environment you deployed from.
query.pyPYTHON
from lattica_query import QueryClient

token = studio.tokens.load("MY_MNIST_MODEL")
query_client = QueryClient(token)

# load the key generated in Key generation
sk = query_client.generate_key(load_if_exists=True)
Load the token with studio.tokens.load using the same model_name you saved. generate_key(load_if_exists=True) returns the secret key your queries need.

Run a query

One call encrypts your input, runs it on the worker, and decrypts the result for you. Your plaintext never leaves your machine.
query.pyPYTHON
# run as many times as you need while the worker is up
res = query_client.run_query(sk, pt)
y_pred = res.argmax(dim=-1)
Inside that one call, three things happen:
Encrypt
Your input is encrypted on your machine. It is packed into slots first, and the last block is filled with zeros.
ciphertext
Run on worker
the worker computes on ciphertext
ciphertext
Decrypt
the result is decrypted, just for you
Run it again with a different input as often as you like. The worker stays up between queries, so each one is a single call.

Stop the worker

When you are done, stop the worker. Credits stop the moment it goes down. If you used studio.workers.running(..., stop_on_exit=True), the worker stops when the block exits.
query.pyPYTHON
# credits stop when the context exits (stop_on_exit=True)
studio.workers.stop(model_id=model_id)

Leave the worker running only while you need it. Billing is by runtime, so a worker left up keeps using credits even when idle. Start it for a session of queries, then stop it.

The full flow

That completes the path: from a plaintext input to an encrypted answer and back, after deploy and key generation.
Build → Deploy → Key generation → Query

Next

See it all together

End-to-End Example

One runnable walkthrough that threads build, deploy, key generation, and query in a single script.