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

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.

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, 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 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:

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.

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:

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 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 at lines 54–55, the contract defines a nested leader function that returns the JSON output, then passes that function to strict_eq:

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 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

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

JSON-Structured Prompt with Consensus

@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

@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, 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 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 lines 58–66. Explicit failures are safer than silent sentinel values because they prevent invalid states from reaching finality.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →