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

# Multilook

> Ask many independent questions about one image or video in a single call and pay for the shared context once.

# Multilook: many prompts, one context

Multilook sends one shared `context` — an image, a video, a few reference frames, or any message sequence you would pass to `/v1/chat/completions` — together with up to 16 independent `prompts`. The context is prefilled once and reused across every prompt, and the reused tokens are billed at the reduced cache-read rate. Each prompt gets its own completions, in request order, without seeing any other prompt.

<CardGroup cols={2}>
  <Card title="Multilook Chat Completions" icon="layer-group" href="/perceptron-mk1/api-reference/endpoint/multilook-chat-completions">
    Full field reference, response shape, and request limits.
  </Card>

  <Card title="Pricing" icon="coins" href="/perceptron-mk1/guides/tokenization#pricing">
    Input, output, and cached-input rates for Perceptron Mk1.
  </Card>
</CardGroup>

## When to use it

Reach for Multilook whenever several questions share the same media:

* **Checklists and rubrics** — run every item of an inspection checklist over one clip in a single call.
* **Unrelated questions about one input** — count people, describe the setting, and flag an action, without re-sending the video three times.
* **Sampling several looks** — set `n > 1` to draw multiple completions per prompt for self-consistency or majority voting.
* **Comparing prompt phrasings** — send the same question worded several ways and compare the answers side by side.

Compared with issuing the same questions as separate `/v1/chat/completions` calls, one Multilook request bills the shared context at the cache-read rate for every prompt after the first, and counts as a single request against its own rate-limit bucket. Compared with client-side fan-out from the [Batch guide](/perceptron-mk1/guides/batch), it removes the per-call media upload and the coordination code.

Multilook is **not** the right tool when:

* You need `stream`, `response_format`, or `stop` — none are supported on this endpoint.
* Prompts depend on one another. Prompts are fully isolated: no prompt observes another prompt's text or completions, so multi-turn conversations still belong on `/v1/chat/completions`.

## How it works

* **`context` is prefilled once.** It uses the same message format as `/v1/chat/completions`, including media parts (`image_url`, `video_url`, `video_frames`, `image_file_id`, `video_file_id`).
* **Each prompt is an implicit final `user` turn** that extends the context. A prompt is either a bare string or `{ "content": [ ...parts ] }` with the same part types as a user message.
* **Each prompt produces `n` completions** (1–8), sampled with the same `temperature`, `top_p`, `top_k`, penalties, and `vision_config` for every prompt.
* **`results[]` comes back in request order.** Each entry carries `prompt_index` plus either `completions` (with per-prompt `usage.completion_tokens`) or an `error`.
* **`usage` is reported once per call.** `prompt_tokens_details.cached_tokens` is the subset of `prompt_tokens` served from the in-request prefill.

See the [endpoint reference](/perceptron-mk1/api-reference/endpoint/multilook-chat-completions) for every field and its constraints.

## Quickstart

<CodeGroup>
  ```bash curl theme={null}
  curl https://api.perceptron.inc/v1/chat/completions/multilook \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $PERCEPTRON_API_KEY" \
    -d '{
      "model": "perceptron-mk1",
      "context": [
        { "role": "user",
          "content": [
            { "type": "video_url",
              "video_url": { "url": "https://raw.githubusercontent.com/perceptron-ai-inc/perceptron/main/cookbook/_shared/assets/tutorials/isaac_frame_by_frame/surf.mp4" }
            }
          ]
        }
      ],
      "prompts": [
        "How many people are visible?",
        "Describe the setting in one sentence.",
        "Does anyone pick up an object? If so, what?"
      ],
      "n": 1,
      "max_completion_tokens": 128
    }'
  ```

  ```python Python theme={null}
  import os

  import requests

  VIDEO_URL = "https://raw.githubusercontent.com/perceptron-ai-inc/perceptron/main/cookbook/_shared/assets/tutorials/isaac_frame_by_frame/surf.mp4"

  response = requests.post(
      "https://api.perceptron.inc/v1/chat/completions/multilook",
      headers={"Authorization": f"Bearer {os.environ['PERCEPTRON_API_KEY']}"},
      json={
          "model": "perceptron-mk1",
          "context": [
              {
                  "role": "user",
                  "content": [
                      {"type": "video_url", "video_url": {"url": VIDEO_URL}},
                  ],
              }
          ],
          "prompts": [
              "How many people are visible?",
              "Describe the setting in one sentence.",
              "Does anyone pick up an object? If so, what?",
          ],
          "n": 1,
          "max_completion_tokens": 128,
      },
      timeout=300,  # matches the server-side request budget
  )
  response.raise_for_status()
  data = response.json()

  for result in data["results"]:
      if result.get("error"):
          print(f"prompt {result['prompt_index']} failed: {result['error']['message']}")
          continue
      for completion in result["completions"]:
          print(result["prompt_index"], completion["index"], completion["message"]["content"])

  usage = data["usage"]
  print(
      f"prompt={usage['prompt_tokens']} "
      f"cached={usage['prompt_tokens_details']['cached_tokens']} "
      f"completion={usage['completion_tokens']}"
  )
  ```
</CodeGroup>

## Per-prompt media

A prompt can carry its own content parts, including images or video. Use this when every prompt shares a reference but also brings its own input — for example, comparing a batch of parts against one approved sample:

```json theme={null}
{
  "model": "perceptron-mk1",
  "context": [
    { "role": "system",
      "content": "You are a QA inspector. Answer yes or no, then explain in one sentence." },
    { "role": "user",
      "content": [
        { "type": "text", "text": "Reference image of an approved part:" },
        { "type": "image_file_id", "image_file_id": { "file_id": "file-abc123" } }
      ]
    }
  ],
  "prompts": [
    { "content": [
        { "type": "image_url", "image_url": { "url": "https://example.com/part-001.jpg" } },
        { "type": "text", "text": "Does this part match the reference?" }
      ]
    },
    { "content": [
        { "type": "image_url", "image_url": { "url": "https://example.com/part-002.jpg" } },
        { "type": "text", "text": "Does this part match the reference?" }
      ]
    },
    "What makes the reference part acceptable?"
  ],
  "max_completion_tokens": 96
}
```

The reference image in `context` is prefilled once and shows up in `cached_tokens`. The per-prompt images (`part-001.jpg`, `part-002.jpg`) sit outside the shared prefix: they are fetched, preprocessed, and prefilled per prompt, and are **not** reported in `cached_tokens`. Media you intend to reuse across prompts belongs in `context`.

File ids work in both places. See [Working with files](/perceptron-mk1/guides/files) for uploading media once and referencing it by id.

## Sampling multiple looks (`n > 1`)

Set `n` (1–8) to draw several completions per prompt. Two constraints apply:

* `n > 1` requires `temperature > 0`. `temperature` defaults to `0.0`, so set it explicitly.
* `prompts × n` must not exceed 64 completions per call.

Completions for `n > 1` do not re-bill prompt tokens — you pay only for the extra output. A simple majority vote over the sampled looks:

```python theme={null}
from collections import Counter

for result in data["results"]:
    if result.get("error"):
        continue
    answers = [c["message"]["content"].strip() for c in result["completions"]]
    winner, votes = Counter(answers).most_common(1)[0]
    print(f"prompt {result['prompt_index']}: {winner!r} ({votes}/{len(answers)} looks agree)")
```

## Handling partial failures

A prompt that fails returns an `error` object in place of its `completions`. The other prompts are unaffected, and the call still returns `200` as long as at least one prompt succeeded. If every prompt fails, the whole request returns the first error's status.

```json theme={null}
{
  "id": "mlcmpl-7f3a2c",
  "object": "chat.completion.multilook",
  "model": "perceptron-mk1",
  "results": [
    { "prompt_index": 0,
      "completions": [
        { "index": 0,
          "message": { "role": "assistant", "content": "Yes. The part matches the reference." },
          "finish_reason": "stop" }
      ],
      "usage": { "completion_tokens": 9 } },
    { "prompt_index": 1,
      "error": {
        "type": "invalid_request_error",
        "code": null,
        "message": "Could not fetch image at https://example.com/part-002.jpg (HTTP 404)."
      } },
    { "prompt_index": 2,
      "completions": [
        { "index": 0,
          "message": { "role": "assistant", "content": "It has no visible scratches and the mounting holes are aligned." },
          "finish_reason": "stop" }
      ],
      "usage": { "completion_tokens": 14 } }
  ],
  "usage": {
    "prompt_tokens": 4212,
    "completion_tokens": 23,
    "total_tokens": 4235,
    "prompt_tokens_details": { "cached_tokens": 2604 }
  }
}
```

<Note>
  The `error.type` and `error.code` values above are illustrative. Branch on the presence of `error` rather than on specific codes.
</Note>

```python theme={null}
succeeded, failed = [], []
for result in data["results"]:
    if result.get("error"):
        failed.append((result["prompt_index"], result["error"]["message"]))
    else:
        succeeded.append(result)

for index, message in failed:
    print(f"prompt {index} failed: {message}")
```

Other things to plan for:

* **Request budget**: each call has 300 seconds to finish. On a timeout, retry with fewer prompts, a lower `n`, or a smaller `max_completion_tokens`.
* **Rate limits**: Multilook has its own 150 requests/min bucket, separate from `/v1/chat/completions`. Handle `429` with backoff as described in the [Scaling guide](/perceptron-mk1/guides/scaling#rate-limits).

## Billing

Each call produces one usage event, billed at Perceptron Mk1's standard rates:

* `prompt_tokens − cached_tokens` — \$0.15 / M tokens (input rate)
* `cached_tokens` — \$0.0375 / M tokens (cache-read rate)
* `completion_tokens` — \$1.50 / M tokens (output rate)

`prompt_tokens` counts the shared context once per prompt, matching `/v1/chat/completions` accounting. `cached_tokens` is the part of that total served from the in-request prefill, and it approaches `(P − 1) / P` of `prompt_tokens` for `P` prompts as each prompt's own text becomes small relative to the context. Reuse is scoped to the call: a subsequent identical call reports `cached_tokens: 0`.

**Worked example.** Four prompts over one \~60-frame video (\~8,900 context tokens each) bill 35,612 prompt tokens, of which 25,872 are at the cache-read rate, plus 94 completion tokens:

|                                                  | Tokens | Rate         | Cost           |
| ------------------------------------------------ | ------ | ------------ | -------------- |
| Uncached input (`prompt_tokens − cached_tokens`) | 9,740  | \$0.15 / M   | \$0.00146      |
| Cached input (`cached_tokens`)                   | 25,872 | \$0.0375 / M | \$0.00097      |
| Output (`completion_tokens`)                     | 94     | \$1.50 / M   | \$0.00014      |
| **Total**                                        |        |              | **≈ \$0.0026** |

The same four questions as four separate `/v1/chat/completions` calls would bill all 35,612 prompt tokens at the input rate — about \$0.0055 in total, roughly twice the cost. Figures are illustrative; actual token counts depend on your media and prompts.

## Limits

All request limits — prompts per call, completions per call, media inputs, body size, rate limit, and request budget — are listed on the [endpoint page](/perceptron-mk1/api-reference/endpoint/multilook-chat-completions#limits).
