Building with Amazon Nova

Part 1 - Building with Amazon Nova

Amazon Nova is Amazon’s family of foundation models on Amazon Bedrock. This part covers inference (Converse, InvokeModel, streaming), tool calling, multimodal inputs, and structured JSON output.

Next: Part 2 - Embeddings and RAG · Part 3 - Deploy, operate, integrate · Part 4 - AgentCore


Inference: Converse, InvokeModel, streaming, model IDs

For most new apps, start with the Converse API - one request shape for chat, tools, and multimodal content. Use InvokeModel when you need a model-specific payload or legacy samples.

Pick a Nova model

Model IDGood for
amazon.nova-micro-v1:0Lowest cost, simple tasks, high volume
amazon.nova-lite-v1:0Balanced speed and quality
amazon.nova-pro-v1:0Stronger reasoning and longer context
amazon.nova-premier-v1:0Highest capability in the Nova line (enable in console when available)

Always confirm IDs in your region: Bedrock console → Model catalog → Amazon Nova.

Converse sends messages, optional system, optional inferenceConfig, and optional toolConfig. The response includes output.message with content blocks (text, tool use, and so on).

Your app → bedrock-runtime:Converse → Nova → assistant message
AWS CLI - single turn with Converse
export AWS_REGION=us-east-1
export MODEL_ID=amazon.nova-lite-v1:0

aws bedrock-runtime converse \
  --region "$AWS_REGION" \
  --model-id "$MODEL_ID" \
  --messages '[{"role":"user","content":[{"text":"Summarize Bedrock in one sentence."}]}]' \
  --inference-config '{"maxTokens":256,"temperature":0.3}'
Python (boto3) - Converse
import boto3

client = boto3.client("bedrock-runtime", region_name="us-east-1")

response = client.converse(
    modelId="amazon.nova-lite-v1:0",
    messages=[
        {
            "role": "user",
            "content": [{"text": "What is the Converse API?"}],
        }
    ],
    inferenceConfig={"maxTokens": 512, "temperature": 0.2},
)

print(response["output"]["message"]["content"][0]["text"])

InvokeModel (model-native JSON)

InvokeModel passes a JSON body defined by each model provider. Use it when you follow older tutorials or need a field not on Converse yet.

AWS CLI - InvokeModel (Nova Lite)
aws bedrock-runtime invoke-model \
  --region us-east-1 \
  --model-id amazon.nova-lite-v1:0 \
  --content-type application/json \
  --accept application/json \
  --body '{"messages":[{"role":"user","content":[{"text":"Hello"}]}],"inferenceConfig":{"maxTokens":128}}' \
  /tmp/nova-out.json

cat /tmp/nova-out.json

Streaming

  • ConverseStream - same message format as Converse.
  • InvokeModelWithResponseStream - stream with InvokeModel bodies.
AWS CLI - ConverseStream (first events)
aws bedrock-runtime converse-stream \
  --region us-east-1 \
  --model-id amazon.nova-lite-v1:0 \
  --messages '[{"role":"user","content":[{"text":"Write a haiku about clouds."}]}]' \
  --inference-config '{"maxTokens":128}' \
  --output json | head -c 4000
Python - ConverseStream
import boto3

client = boto3.client("bedrock-runtime", region_name="us-east-1")
stream = client.converse_stream(
    modelId="amazon.nova-lite-v1:0",
    messages=[{"role": "user", "content": [{"text": "Count from 1 to 5."}]}],
    inferenceConfig={"maxTokens": 64},
)

for event in stream["stream"]:
    if "contentBlockDelta" in event:
        delta = event["contentBlockDelta"]["delta"]
        if "text" in delta:
            print(delta["text"], end="", flush=True)

Inference parameters

ParameterRole
maxTokensCap on generated tokens
temperatureRandomness (lower = more deterministic)
topPNucleus sampling
stopSequencesStrings that stop generation

Keep temperature low (0-0.3) for extraction and classification.

Converse vs InvokeModel

ConverseInvokeModel
Message shapeStandard across modelsProvider-specific JSON
ToolsBuilt-in toolConfigDepends on model
Multimodalimage, document, etc.Model-specific
Best forNew applicationsLegacy or special payloads
Client → API Gateway or ALB → Lambda → Converse → Nova

Tool and function calling

Tool calling lets Nova request structured actions instead of guessing facts. Your app runs the tool and sends results back.

TermMeaning
Tool specJSON schema: name, description, inputSchema
toolUseModel asks you to run a tool with arguments
toolResultYour reply with output (or error)
toolConfigTools list passed to Converse
User → Converse (tools) → toolUse → your Lambda/HTTP/DB
  → user message with toolResult → Converse → final text
AWS CLI - Converse with one tool
aws bedrock-runtime converse \
  --region us-east-1 \
  --model-id amazon.nova-lite-v1:0 \
  --tool-config '{
    "tools": [{
      "toolSpec": {
        "name": "get_weather",
        "description": "Get weather for a city",
        "inputSchema": {
          "json": {
            "type": "object",
            "properties": { "city": { "type": "string" } },
            "required": ["city"]
          }
        }
      }
    }]
  }' \
  --messages '[{"role":"user","content":[{"text":"Weather in Portland?"}]}]'
Python - tool round-trip loop
import json
import boto3

brt = boto3.client("bedrock-runtime", region_name="us-east-1")
MODEL = "amazon.nova-lite-v1:0"
TOOLS = {"tools": [{"toolSpec": {
    "name": "get_weather",
    "description": "Get weather for a city",
    "inputSchema": {"json": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    }},
}}]}

def run_tool(name, args):
    if name == "get_weather":
        return {"temp": 72, "city": args["city"]}
    raise ValueError(name)

messages = [{"role": "user", "content": [{"text": "Weather in Austin?"}]}]
resp = brt.converse(modelId=MODEL, messages=messages, toolConfig=TOOLS)

while True:
    msg = resp["output"]["message"]
    messages.append(msg)
    tool_uses = [b["toolUse"] for b in msg["content"] if "toolUse" in b]
    if not tool_uses:
        print(msg["content"][0]["text"])
        break
    results = []
    for tu in tool_uses:
        out = run_tool(tu["name"], tu["input"])
        results.append({
            "toolResult": {
                "toolUseId": tu["toolUseId"],
                "content": [{"text": json.dumps(out)}],
                "status": "success",
            }
        })
    messages.append({"role": "user", "content": results})
    resp = brt.converse(modelId=MODEL, messages=messages, toolConfig=TOOLS)

Design tips: small tools, strict schemas, idempotent handlers, timeouts, no secrets in prompts.


Multimodal: images, documents, video

Use the same Converse API with different content blocks: text, image, document, video (where supported). Prefer S3 URIs for large PDFs instead of inline base64.

AWS CLI - Converse with image (base64)
export MODEL_ID=amazon.nova-lite-v1:0
B64=$(base64 -w0 /path/to/photo.png)

aws bedrock-runtime converse \
  --region us-east-1 \
  --model-id "$MODEL_ID" \
  --messages "[{
    \"role\": \"user\",
    \"content\": [
      {\"image\": {\"format\": \"png\", \"source\": {\"bytes\": \"${B64}\"}}},
      {\"text\": \"Describe this image in two sentences.\"}
    ]
  }]"

For long video, use key frames, Transcribe, or Rekognition, then pass text to Nova. For scanned PDFs at scale, prefer Textract + RAG (Part 2) over huge inline documents.


Structured JSON output

ApproachWhen
Prompt + json.loads + retryQuick prototypes; low temperature
Tool use as schema contractReliable extraction (toolUse.input)
Model JSON mode (if available)Check Nova release notes for your region
Python - JSON extract with retry
import json
import boto3

brt = boto3.client("bedrock-runtime", region_name="us-east-1")

def structured_summary(text: str) -> dict:
    prompt = (
        "Return only valid JSON: {\"summary\": string, \"sentiment\": \"positive\"|\"neutral\"|\"negative\"}\n\n"
        f"Text:\n{text}"
    )
    for _ in range(2):
        resp = brt.converse(
            modelId="amazon.nova-lite-v1:0",
            messages=[{"role": "user", "content": [{"text": prompt}]}],
            inferenceConfig={"maxTokens": 256, "temperature": 0},
        )
        raw = resp["output"]["message"]["content"][0]["text"].strip()
        try:
            return json.loads(raw)
        except json.JSONDecodeError:
            prompt = "Reply again with JSON only."
    raise ValueError("invalid json from model")

Validate with JSON Schema or Pydantic before writing to DynamoDB or returning API responses.

Next: Part 2 - Embeddings and RAG