# How to Use LLM Prompts with `gl.nondet.exec_prompt` in GenLayer Contracts

> Learn to use LLM prompts with gl.nondet.exec_prompt in GenLayer contracts. Wrap calls in gl.eq_principle.strict_eq for validator consensus on non-deterministic output.

- Repository: [GenLayer Labs/genlayer-project-boilerplate](https://github.com/genlayerlabs/genlayer-project-boilerplate)
- Tags: how-to-guide
- Published: 2026-08-20

---

**Use `gl.nondet.exec_prompt` to call large-language-model prompts inside GenLayer contracts, and always wrap the call in an equivalence principle such as `gl.eq_principle.strict_eq` so validators can reach consensus on the non-deterministic output.**

The `genlayer-project-boilerplate` repository demonstrates how to integrate LLM prompts directly into smart contracts using the GenLayer SDK. Because these calls are non-deterministic, the platform requires special consensus patterns to ensure validator agreement on the result. Understanding how to use `gl.nondet.exec_prompt` correctly is essential for building reliable GenLayer applications that process natural language, structured data, or visual inputs.

## Basic LLM Prompt Calls with `gl.nondet.exec_prompt`

The simplest way to invoke an LLM from a GenLayer contract is to pass a plain text prompt to `gl.nondet.exec_prompt`. This method returns the raw string response from the model. Default configuration values for these non-deterministic API calls are defined in [`config/genlayer_config.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/config/genlayer_config.py).

```python
result = gl.nondet.exec_prompt("Summarize this article")

```

This pattern is illustrated in the integration test `describe_raw_bytes` inside [`tests/integration/test_new_features.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/tests/integration/test_new_features.py), where the prompt is sent directly to the LLM at line 90.

## Returning Structured JSON Output

For downstream contract logic that requires parsed data, supply the `response_format="json"` parameter. The SDK automatically parses the LLM reply into a Python dictionary.

The [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) contract shows this approach at line 51. It constructs a task string that instructs the model to return a JSON object containing the match score and winner:

```python
task = """
Extract the match result for:
Team 1: {team1}
Team 2: {team2}
...
Respond in JSON: {"score": str, "winner": int}
"""
json_result = gl.nondet.exec_prompt(task, response_format="json")

```

Using `response_format="json"` eliminates manual string parsing and lets you access fields directly as a Python `dict`.

## Passing Image Data to `exec_prompt`

The `exec_prompt` method also accepts visual input through the `images` keyword argument. You can supply raw bytes, such as a PNG buffer, or a `gl.nondet.Image` object returned by `gl.nondet.web.render`.

```python
desc = gl.nondet.exec_prompt(
    "Describe this image",
    images=[image_bytes]      # raw bytes

)

```

Alternatively, after rendering a webpage screenshot with `gl.nondet.web.render`, pass the image's raw payload:

```python
img = gl.nondet.web.render(url, mode="screenshot")
desc = gl.nondet.exec_prompt("Describe this image", images=[img.raw])

```

These visual patterns appear in [`tests/integration/test_new_features.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/tests/integration/test_new_features.py) between lines 89 and 99, which cover screenshot rendering and validator interaction.

## Reaching Consensus with Equivalence Principles

Because every call to `gl.nondet.exec_prompt` is non-deterministic, the result can vary across validators. To reach consensus, you must wrap the prompt inside an equivalence principle such as `gl.eq_principle.strict_eq` or `gl.eq_principle.prompt_comparative`. These utilities capture the leader validator's output and re-execute the call during validation to confirm agreement.

In [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) at lines 54–55, the contract defines a nested `leader` function that returns the JSON output, then passes that function to `strict_eq`:

```python
def get_match_result():
    def leader():
        return gl.nondet.exec_prompt(task, response_format="json")
    return json.dumps(gl.eq_principle.strict_eq(leader), sort_keys=True)

```

The `gl.eq_principle.strict_eq` wrapper ensures that follower validators receive the same result as the leader before the transaction is finalized. For advanced use cases, you can also invoke the low-level validator API via `glvm.run_nondet_unsafe`.

## Handling Errors in Non-Deterministic Calls

If the LLM fails or returns malformed JSON, the contract should raise an exception or return a sentinel value. The equivalence principle mechanism expects a well-formed result so that validators can compare outputs deterministically.

The [`contracts/PatternTest.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/PatternTest.py) contract demonstrates this behavior between lines 58 and 66. It shows a leader function that intentionally raises an error and a validator pattern that detects the failure during consensus. Designing your contract to fail explicitly prevents undefined states from propagating through the validator set.

## Complete Contract Examples

The following snippets combine the patterns above into full GenLayer contract methods.

### Simple Text Prompt

```python
@gl.public.write
def ask_llm(self, query: str) -> str:
    return gl.nondet.exec_prompt(query)

```

### JSON-Structured Prompt with Consensus

```python
@gl.public.write
def get_match(self, team1: str, team2: str) -> str:
    task = f"""
    Extract the winner and score for:
    Team 1: {team1}
    Team 2: {team2}
    Respond in JSON: {{"winner": int, "score": str}}
    """
    def leader():
        return gl.nondet.exec_prompt(task, response_format="json")
    # strict_eq ensures validators see the same JSON

    return gl.eq_principle.strict_eq(leader)

```

### Image Description with Raw Bytes

```python
@gl.public.write
def describe_png(self, png_bytes: bytes) -> str:
    desc = gl.nondet.exec_prompt("Describe this image", images=[png_bytes])
    # Run through strict_eq so validators can verify the description

    return gl.eq_principle.strict_eq(lambda: desc)

```

These examples mirror the implementation patterns found in [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py), [`contracts/PatternTest.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/PatternTest.py), and the integration test suite.

## Summary

- **`gl.nondet.exec_prompt`** is the primary SDK method for invoking LLM prompts inside GenLayer contracts.
- Always wrap non-deterministic LLM calls in an **equivalence principle** such as `gl.eq_principle.strict_eq` to satisfy validator consensus.
- Use **`response_format="json"`** to receive parsed dictionary output instead of raw strings.
- Pass **image bytes** or **`gl.nondet.Image.raw`** via the `images` parameter to process visual inputs.
- **Raise exceptions** for malformed or failed LLM responses so the validator network can detect errors consistently.

## Frequently Asked Questions

### What is `gl.nondet.exec_prompt` used for in GenLayer?

`gl.nondet.exec_prompt` is the GenLayer SDK function that lets smart contracts invoke large-language-model prompts. It returns the model's text or JSON output and is classified as non-deterministic because the same prompt can yield slightly different responses across executions.

### Why must LLM prompts be wrapped in an equivalence principle?

GenLayer validators must agree on the state of the blockchain. Because LLM outputs are inherently non-deterministic, a raw `exec_prompt` call could produce different results on different validators. Wrapping the call in `gl.eq_principle.strict_eq` captures the leader's result and forces follower validators to match it, enabling consensus without sacrificing the utility of AI inference.

### Can `exec_prompt` process images?

Yes. The method accepts an `images` argument that can receive a list of raw byte buffers or `gl.nondet.Image` objects. The integration tests in [`tests/integration/test_new_features.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/tests/integration/test_new_features.py) demonstrate passing PNG bytes and screenshots rendered via `gl.nondet.web.render` to the LLM for visual analysis.

### How do I handle malformed JSON from an LLM call?

Design your contract to raise an exception when the LLM returns unexpected or malformed data. The equivalence principle will propagate this failure across the validator set, as shown in [`contracts/PatternTest.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/PatternTest.py) lines 58–66. Explicit failures are safer than silent sentinel values because they prevent invalid states from reaching finality.