> ## Documentation Index
> Fetch the complete documentation index at: https://docs-v1.latitude.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Render a prompt with steps

> Learn how to render the steps of a prompt with the Latitude SDK

## Prompt

Chains and Steps are used to create multi-step prompts that can interact with the AI model in stages. Chains in PromptL allow you to break complex workflows into smaller, manageable steps. You can read more [about it here](/promptl/advanced/chains#chains-and-steps).

In this example, we use two steps. In the first step, we ask the model to think about the answer. Then, in the second step, we ask it to provide an explanation for why it chose that answer.

<CodeGroup>
  ```markdown example theme={null}
  ---
  provider: Latitude
  model: gpt-4o-mini
  temperature: 0.7
  ---

  <step>
    You're a helpful assistant. Think about user question and provide the best answer.
    This is the question:
    {{ question }}
  </step>

  <step>
    Now that you have the best answer, please provide a detailed explanation of how you arrived at this answer.
  </step>
  ```
</CodeGroup>

## Code

The key point to understand is that for each `<step>` found in the prompt, the SDK will invoke `onStep`. At that point, you can ask your LLM to provide a response.

<CodeGroup>
  ```typescript Typescript theme={null}
  import { Latitude, Adapters, Message } from '@latitude-data/sdk'
  import OpenAI from 'openai'

  async function run() {
    const sdk = new Latitude(process.env.LATITUDE_API_KEY, {
      projectId: Number(process.env.PROJECT_ID),
      versionUuid: 'live',
    })
    const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

    const prompt = await sdk.prompts.get('render-chain/example')
    const result = await sdk.prompts.renderChain({
      prompt,
      parameters: { question: 'What is the meaning of life?' },
      adapter: Adapters.openai,
      onStep: async ({
        config,
        messages,
      }: {
        config: { [s: string]: unknown }
        messages: Message[]
      }) => {
        const response = await openai.chat.completions.create({
          model: config.model as string,
          temperature: config.temperature as number,
          messages,
        })

        return response.choices[0].message
      },
    })

    console.log('Result:', JSON.stringify(result, null, 2))
  }

  run()
  ```

  ```python Python theme={null}
  import asyncio
  import os
  from typing import Any, Dict, List, Sequence, Union

  from devtools import pprint
  from latitude_sdk import Latitude, LatitudeOptions, RenderChainOptions
  from openai import AsyncOpenAI
  from promptl_ai import Adapter, MessageLike


  async def run():
      api_key = os.getenv("LATITUDE_API_KEY")
      sdk_options = LatitudeOptions(
          project_id=int(os.getenv("PROJECT_ID")),
          version_uuid="live",
      )
      sdk = Latitude(api_key, sdk_options)

      # Use oficial OpenAI SDK
      openai = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))

      async def on_step(
          messages: List[MessageLike], config: Dict[str, Any]
      ) -> Union[str, MessageLike, Sequence[MessageLike]]:
          response = await openai.chat.completions.create(
              model=config["model"],
              temperature=config["temperature"],
              messages=[message.model_dump() for message in messages],
          )

          return response.choices[0].message.model_dump()

      prompt = await sdk.prompts.get("render-chain/example")

      # Here we render the chain and each step will be sent to OpenAI
      result = await sdk.prompts.render_chain(
          prompt,
          on_step,
          RenderChainOptions(
              parameters={"question": "What is the meaning of life?"},
              adapter=Adapter.OpenAI,
          ),
      )

      pprint(result)


  asyncio.run(run())
  ```
</CodeGroup>
