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

# Use prompts in code

> Call prompts from your application, build them locally, handle tool calls, stream responses, and invoke them over the REST API.

Prompts created in Braintrust can be called directly from your application code. Reference a prompt by its slug, and changes you make in the UI take effect immediately without redeploying your application.

## Two ways to run a prompt

Your application can run a prompt in one of two ways, which differ in where the model call happens and what you get back:

* **Invoke it on Braintrust.** `invoke()` runs the prompt against its configured model and returns the model's response. Braintrust makes the model call and logs it.
* **Load it and run it yourself.** `loadPrompt()` fetches the prompt's configuration, and `build()` compiles it into request parameters that you pass to your own LLM client.

The return values make the difference concrete. For the same `summarizer` prompt:

<CodeGroup>
  ```json Load and build theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  {
    "model": "gpt-5-mini",
    "temperature": 0.5,
    "messages": [
      { "role": "system", "content": "You are a helpful assistant that summarizes text." },
      { "role": "user", "content": "Summarize the following text: Long text to summarize..." }
    ]
  }
  ```

  ```json Invoke theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  "The article argues that evaluation, not model choice, is the bottleneck in shipping AI features."
  ```
</CodeGroup>

Invoke a prompt when you want Braintrust to run and log the call for you. Load a prompt when you need to make the model call yourself, either to use a provider client you already have configured or to inspect or change the messages before sending them.

## Invoke a prompt

`invoke()` runs a prompt on Braintrust using its configured model and parameters, and returns the model's response. Call it by slug:

<CodeGroup dropdown>
  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { invoke } from "braintrust";

  const result = await invoke({
    projectName: "My Project",
    slug: "summarizer",
    input: {
      text: "Long text to summarize...",
    },
  });

  console.log(result);
  ```

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from braintrust import invoke

  result = invoke(
      project_name="My Project",
      slug="summarizer",
      input={"text": "Long text to summarize..."},
  )

  print(result)
  ```
</CodeGroup>

The `input` parameter values map to template variables in your prompt. For example, `{{text}}` in your prompt gets replaced with the `text` value from input.

Invoking prompts this way:

* Automatically logs inputs and outputs.
* Tracks which prompt version was used.
* Enables A/B testing different prompt versions.
* Lets you update prompts without code changes.

<Note>
  The Ruby SDK doesn't support server-side invocation. Instead, load a prompt and build it locally, then call your own LLM client. See [Load a prompt](#load-a-prompt).
</Note>

<Tip>
  To pin a specific version or load the version assigned to an environment, see [Version prompts](/docs/evaluate/prompts/versions).
</Tip>

## Load a prompt

Use `loadPrompt()` (TypeScript), `load_prompt()` (Python), or `client.LoadPrompt()` (Go) to fetch a prompt's configuration, then call `build()` on the result to compile its template into request parameters for your own LLM client:

<CodeGroup dropdown>
  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { OpenAI } from "openai";
  import { initLogger, loadPrompt, wrapOpenAI } from "braintrust";

  const logger = initLogger({ projectName: "My Project" });
  const client = wrapOpenAI(new OpenAI());

  async function runPrompt() {
    const prompt = await loadPrompt({
      projectName: "My Project",
      slug: "summarizer",
      defaults: {
        model: "gpt-5-mini",
        temperature: 0.5,
      },
    });

    return client.chat.completions.create(
      prompt.build({ text: "Article to summarize..." }),
    );
  }
  ```

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from braintrust import init_logger, load_prompt, wrap_openai
  from openai import OpenAI

  logger = init_logger(project="My Project")
  client = wrap_openai(OpenAI())

  def run_prompt():
      prompt = load_prompt(
          "My Project",
          "summarizer",
          defaults=dict(model="gpt-5-mini", temperature=0.5)
      )

      return client.chat.completions.create(
          **prompt.build(text="Article to summarize...")
      )
  ```

  ```go #skip-compile theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import (
  	"context"

  	"github.com/braintrustdata/braintrust-sdk-go"
  	"github.com/braintrustdata/braintrust-sdk-go/prompt"
  	traceopenai "github.com/braintrustdata/braintrust-sdk-go/trace/contrib/openai"
  	openai "github.com/openai/openai-go"
  	"go.opentelemetry.io/otel/sdk/trace"
  )

  func runPrompt(ctx context.Context) error {
  	bt, err := braintrust.New(trace.NewTracerProvider(), braintrust.WithProject("My Project"))
  	if err != nil {
  		return err
  	}

  	p, err := bt.LoadPrompt(ctx, prompt.LoadOpts{Slug: "summarizer"})
  	if err != nil {
  		return err
  	}

  	built, err := p.Build(map[string]any{"text": "Article to summarize..."})
  	if err != nil {
  		return err
  	}

  	params, err := traceopenai.ChatCompletionParams(built)
  	if err != nil {
  		return err
  	}

  	_, err = openai.NewClient().Chat.Completions.New(ctx, params)
  	return err
  }
  ```

  ```ruby theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  require "braintrust"

  prompt = Braintrust::Prompt.load(
    project: "My Project", # Or project_id: "your-project-uuid"
    slug: "summarizer"
  )

  params = prompt.build(text: "Long text to summarize...")

  puts params[:messages]
  # Pass params to your own LLM client, e.g. openai.chat.completions.create(**params)
  ```
</CodeGroup>

`build()` returns the compiled messages, model, and parameters without calling the model, so you can pass them straight to a client or inspect them first.

The TypeScript and Python functions cache the loaded prompt in memory and on disk, so repeated loads skip the network round trip and fall back to the last cached copy if Braintrust is unreachable. The Go `client.LoadPrompt()` method fetches the prompt on every call.

Unlike `invoke()`, loading a prompt doesn't log anything on its own. Braintrust records the call only if the client you pass the messages to is instrumented, which is why the examples above wrap the client with `wrapOpenAI()`/`wrap_openai()`. See [Trace LLM calls](/docs/instrument/trace-llm-calls) for the instrumentation options in each language.

<Note>
  In Ruby, identify the project by name (`project:`) or by UUID (`project_id:`). Providing neither raises an `ArgumentError`. After loading, `prompt.version` returns the resolved version's transaction ID, which you can pass to `Braintrust::Prompt.load(version:)` to re-pin the exact same version later.
</Note>

<Tip>
  For the full Go prompt surface, including inline `prompt.Definition` prompts and `built.AnnotateSpan` for trace linkage, see the [Go API reference](/docs/sdks/go/api-reference#prompts).
</Tip>

## Use within a trace

When calling prompts from instrumented code, they automatically nest within your parent trace:

<CodeGroup dropdown>
  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { initLogger, traced } from "braintrust";

  const logger = initLogger({ projectName: "My Project" });

  const summarize = traced(async (text: string) => {
    return await logger.invoke("summarizer", { input: { text } });
  });

  // This creates a trace with "summarize" as parent
  const result = await summarize("Long text to summarize...");
  ```

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from braintrust import init_logger, traced

  logger = init_logger(project_name="My Project")

  @traced
  async def summarize(text: str):
      return await logger.invoke("summarizer", input={"text": text})

  # This creates a trace with "summarize" as parent
  result = await summarize("Long text to summarize...")
  ```
</CodeGroup>

This creates a hierarchical trace where the prompt execution appears as a child span of your function.

## Handle tool calls

When a prompt includes tools, the response contains tool calls that your code must handle:

<CodeGroup dropdown>
  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { invoke } from "braintrust";

  const result = await invoke({
    projectName: "RAG App",
    slug: "document-search",
    input: { question: "What is Braintrust?" },
  });

  // Handle tool calls
  if (result.toolCalls) {
    for (const toolCall of result.toolCalls) {
      console.log(`Tool: ${toolCall.function.name}`);
      console.log(`Arguments: ${toolCall.function.arguments}`);
      // Execute tool and return results...
    }
  }
  ```

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from braintrust import invoke

  result = invoke(
      project_name="RAG App",
      slug="document-search",
      input={"question": "What is Braintrust?"},
  )

  # Handle tool calls
  if hasattr(result, "tool_calls"):
      for tool_call in result.tool_calls:
          print(f"Tool: {tool_call.function.name}")
          print(f"Arguments: {tool_call.function.arguments}")
          # Execute tool and return results...
  ```
</CodeGroup>

See [Add tools](/docs/evaluate/prompts/create#add-tools) to attach tools to a prompt, and [Deploy functions](/docs/deploy/functions) for details on deploying tools alongside prompts.

## Add extra messages

The `messages` parameter appends messages after the prompt's own messages, letting you continue a conversation while reusing the prompt's model and configuration. The example below invokes the `assistant` prompt, then invokes it again with the model's first answer and a follow-up question so it can reconsider its response:

<CodeGroup dropdown>
  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { invoke } from "braintrust";

  async function reflection(question: string) {
    const result = await invoke({
      projectName: "My Project",
      slug: "assistant",
      input: { question },
    });

    const reflectionResult = await invoke({
      projectName: "My Project",
      slug: "assistant",
      input: { question },
      messages: [
        { role: "assistant", content: result },
        { role: "user", content: "Are you sure about that?" },
      ],
    });

    return reflectionResult;
  }
  ```

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from braintrust import invoke

  def reflection(question: str):
      result = invoke(
          project_name="My Project",
          slug="assistant",
          input={"question": question},
      )

      reflection_result = invoke(
          project_name="My Project",
          slug="assistant",
          input={"question": question},
          messages=[
              {"role": "assistant", "content": result},
              {"role": "user", "content": "Are you sure about that?"},
          ],
      )

      return reflection_result
  ```
</CodeGroup>

## Stream responses

Set `stream: true` to receive responses incrementally:

<CodeGroup dropdown>
  ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import { invoke } from "braintrust";

  const stream = await invoke({
    projectName: "My Project",
    slug: "summarizer",
    input: { text: "Long text to summarize..." },
    stream: true,
  });

  for await (const chunk of stream) {
    process.stdout.write(chunk);
  }
  ```

  ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  from braintrust import invoke

  stream = invoke(
      project_name="My Project",
      slug="summarizer",
      input={"text": "Long text to summarize..."},
      stream=True,
  )

  for chunk in stream:
      print(chunk, end="")
  ```
</CodeGroup>

Streaming works automatically through the Gateway and logs the complete response to Braintrust. For the Server-Sent Events format and streaming through the Gateway or wrapped clients, see [Stream responses](/docs/deploy/streaming).

## Manage from the CLI

Use the [`bt` CLI](/docs/reference/cli/quickstart) to browse and test prompts without opening the UI.

**Browse prompts:**

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
bt prompts list                   # List all prompts in the active project
bt prompts view summarizer        # View a specific prompt's definition
bt prompts versions summarizer    # List a prompt's versions
```

**Test a prompt:**

Use [`bt functions invoke`](/docs/reference/cli/functions) to call a prompt and see its output directly from the terminal:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
bt functions invoke --slug summarizer --input '{"text": "Long text to summarize..."}'
```

See [`bt prompts`](/docs/reference/cli/prompts) for the full command surface, including assigning a prompt version to an environment.

## Use the REST API

Call prompts directly via HTTP.

<Note>
  In the examples below, organizations on the EU [data plane](/docs/admin/organizations#data-plane-region) should replace `api.braintrust.dev` with `api-eu.braintrust.dev`.
</Note>

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
curl https://api.braintrust.dev/v1/function \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $BRAINTRUST_API_KEY" \
  -d '{
    "project_name": "My Project",
    "slug": "summarizer",
    "input": {
      "text": "Long text to summarize..."
    }
  }'
```

The REST API supports all the same parameters as the SDK, including versioning, environments, and streaming.

## Next steps

* [Version prompts](/docs/evaluate/prompts/versions) to pin versions and assign them to environments.
* [Stream responses](/docs/deploy/streaming) to return incremental output from prompts and functions.
* [Deploy functions](/docs/deploy/functions) to deploy tools and workflows alongside prompts.
* [Monitor deployments](/docs/deploy/monitor) to track prompt performance in production.
