视觉大模型正在从"能看懂图"走向"能结构化地看懂图"。Amazon Nova 2 Lite 是 Bedrock 上新增的多模态模型,它不仅能识别图中的物体,还能按你要求的 JSON 格式输出检测结果——坐标、类别、置信度一应俱全。这意味着你不再需要单独跑一个 YOLO 推理服务,直接用一次 API 调用就能完成"看图 → 出结构"的闭环。
这篇文章把从 Prompt 设计到 Lambda + API Gateway 部署的完整链路拆开讲,并给出可以直接改造的代码。
Nova 2 Lite 的检测能力边界
Nova 2 Lite 的目标检测不是传统 CV 模型那种"训练 → 推理"范式,而是基于多模态理解的 Prompt 驱动检测。你告诉它要找什么,它就在图中定位并返回结构化结果。
这种方式的优劣很明确:
- 优势:零训练、灵活定义类别、天然支持开放词汇检测。制造业想找"螺丝缺失"、农业想找"病斑"、物流想找"破损纸箱",只需要改 Prompt,不用改模型。
- 边界:对极小目标(像素级缺陷)的定位精度不如专用检测模型;高频实时场景(>10 FPS)不适合走 Bedrock API 调用链路。
理解了边界,就知道该在什么场景用它:低频、多类别、需要快速迭代的检测任务是它的甜区。
Prompt 设计:检测质量的关键杠杆
Nova 2 Lite 的检测结果质量,很大程度上取决于你怎么写 Prompt。以下是三条实测有效的原则:
1. 明确列出目标类别,不要用模糊描述。
差的写法:
找出图中所有有问题的地方
好的写法:
检测图中以下类别的物体:缺失螺丝、错位卡扣、表面裂纹。对每个检测到的物体,返回其类别名称、在图中的位置(用 bounding box 的左上角和右下角坐标表示,坐标系以像素为单位,原点在图片左上角),以及置信度(0-1之间的浮点数)。
2. 锁定输出格式,减少后端解析成本。
在 Prompt 中直接给出 JSON schema,比说"请用 JSON 格式输出"要稳定得多:
请严格按照以下 JSON 格式输出,不要添加任何额外字段或解释:
{
"detections": [
{
"label": "string - 类别名称",
"box": {"x1": "int", "y1": "int", "x2": "int", "y2": "int"},
"confidence": "float"
}
]
}
如果某个类别未检测到,该类别不出现在数组中。
3. 给坐标系定义,避免歧义。
坐标原点在哪、单位是像素还是比例、box 是 [x,y,w,h] 还是 [x1,y1,x2,y2]——这些细节不写清楚,模型可能每次格式都不一样。上面示例中的"原点在图片左上角、像素单位、左上右下角坐标"就是一次明确的约定。
Lambda 函数:一次调用的完整实现
下面是一个可以直接部署的 Lambda 函数,它接收图片(Base64 编码)和检测类别列表,调用 Bedrock 上的 Nova 2 Lite,解析 JSON 结果并返回。
import json
import base64
import boto3
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
MODEL_ID = "amazon.nova-2-lite"
def build_prompt(categories: list[str]) -> str:
"""根据目标类别列表构建检测 Prompt"""
category_str = ", ".join(categories)
return (
f"检测图中以下类别的物体:{category_str}。\n"
"对每个检测到的物体,返回其类别名称、在图中的位置"
"(bounding box 左上角和右下角坐标,像素单位,原点在图片左上角),"
"以及置信度(0-1 浮点数)。\n\n"
"请严格按照以下 JSON 格式输出,不要添加额外字段或解释:\n"
'{"detections":[{"label":"string","box":{"x1":"int","y1":"int","x2":"int","y2":"int"},"confidence":"float"}]}\n'
"如果某个类别未检测到,该类别不出现在数组中。"
)
def call_nova(image_b64: str, prompt: str) -> dict:
"""调用 Bedrock Nova 2 Lite 并解析 JSON 结果"""
# Nova 系列的请求格式:image 放在 content 里,text 作为消息
payload = {
"messages": [
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_b64,
},
},
{"type": "text", "text": prompt},
],
}
],
"inferenceConfig": {"maxTokens": 2048, "temperature": 0.1},
}
response = bedrock.invoke_model(
modelId=MODEL_ID,
body=json.dumps(payload),
contentType="application/json",
accept="application/json",
)
result = json.loads(response["body"].read())
# Nova 返回的结构中,文本在 output.message.content 里
text_output = result["output"]["message"]["content"][0]["text"]
# 模型可能在外面包一层 markdown code block,做一下清洗
text_output = text_output.strip()
if text_output.startswith("```json"):
text_output = text_output[len("```json"):]
if text_output.startswith("```"):
text_output = text_output[len("```"):]
if text_output.endswith("```"):
text_output = text_output[:-len("```")]
text_output = text_output.strip()
return json.loads(text_output)
def lambda_handler(event, context):
"""API Gateway 入口"""
try:
body = json.loads(event.get("body", "{}"))
image_b64 = body["image_base64"]
categories = body.get("categories", ["defect", "missing_part"])
prompt = build_prompt(categories)
detections = call_nova(image_b64, prompt)
return {
"statusCode": 200,
"body": json.dumps({
"status": "ok",
"detections": detections["detections"],
"count": len(detections["detections"]),
}),
}
except json.JSONDecodeError as e:
logger.error(f"JSON parse error: {e}")
return {"statusCode": 502, "body": json.dumps({"status": "error", "message": "模型输出无法解析为 JSON"})}
except Exception as e:
logger.error(f"Unexpected error: {e}")
return {"statusCode": 500, "body": json.dumps({"status": "error", "message": str(e)})}
部署前需要改的地方:region_name 换成你 Bedrock 开启的区域;MODEL_ID 确认模型标识符(Bedrock 模型列表中可查);Lambda 的执行角色需要 bedrock:InvokeModel 权限。
API Gateway 配置:把检测变成 HTTP 接口
用 API Gateway 把上面的 Lambda 暴露为 POST 接口,前端或边缘设备就能直接调用。以下是 SAM 模板的核心片段:
Resources:
DetectFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./src
Handler: app.lambda_handler
Runtime: python3.12
Timeout: 30
MemorySize: 256
Policies:
- Statement:
Effect: Allow
Action: bedrock:InvokeModel
Resource: !Sub "arn:aws:bedrock:${AWS::Region}::foundation-model/amazon.nova-2-lite"
Events:
DetectApi:
Type: Api
Properties:
Path: /detect
Method: post
部署命令:
sam build && sam deploy --guided
部署完成后,调用方式:
# 把图片转 base64 并调用
IMAGE_B64=$(base64 -i factory_photo.jpg)
curl -X POST "$API_ENDPOINT/detect" \
-H "Content-Type: application/json" \
-d "{\"image_base64\": \"$IMAGE_B64\", \"categories\": [\"missing_screw\", \"misaligned_clip\", \"surface_crack\"]}"
返回示例:
{
"status": "ok",
"detections": [
{"label": "missing_screw", "box": {"x1": 320, "y1": 180, "x2": 380, "y2": 220}, "confidence": 0.87},
{"label": "surface_crack", "box": {"x1": 510, "y1": 400, "x2": 620, "y2": 440}, "confidence": 0.72}
],
"count": 2
}
结果可视化:快速验证检测效果
拿到坐标后,最直接的验证方式是在原图上画框。以下脚本可以在本地跑,也可以嵌入 Lambda 做预处理:
from PIL import Image, ImageDraw
import json
def visualize(image_path: str, detections: list, output_path: str = "result.jpg"):
img = Image.open(image_path)
draw = ImageDraw.Draw(img)
for det in detections:
box = det["box"]
x1, y1, x2, y2 = box["x1"], box["y1"], box["x2"], box["y2"]
label = f"{det['label']} {det['confidence']:.2f}"
draw.rectangle([x1, y1, x2, y2], outline="red", width=3)
draw.text((x1, y1 - 15), label, fill="red")
img.save(output_path)
print(f"可视化结果已保存到 {output_path}")
# 使用示例
with open("api_response.json") as f:
resp = json.load(f)
visualize("factory_photo.jpg", resp["detections"])
三个行业的落地切入点
源文中提到的制造业、农业、物流场景,用 Nova 2 Lite 的检测方式各有不同的适配策略:
制造业——质检巡检:产线上拍一张组装完成图,Prompt 列出所有应存在的零件类别。检测到 missing 类别即触发告警。优势是换产品线只改 Prompt 里的类别列表,不用重新训练模型。
农业——病害识别:田间摄像头定期拍摄叶片照片,Prompt 指定"锈斑、霉层、虫蛀孔"。输出 JSON 后直接写入时序数据库,跟踪病害扩散趋势。注意:病害检测对颜色敏感,输入图片尽量保留原始色彩,不要做灰度化预处理。
物流——破损分拣:分拣线上的包裹图片送入检测接口,类别设为"外箱破损、标签撕裂、液体泄漏"。检测到任一类别就标记该包裹进入人工复核通道。这类场景图片分辨率通常不高,Prompt 中可以加一句"注意低分辨率下的边缘模糊特征"来提升检测敏感度。
上线前的检查清单
把 Nova 2 Lite 的检测服务推到生产环境前,逐项确认:
- Prompt 稳定性:同一张图跑 5 次,检测结果(类别 + 坐标)的偏差是否在业务容忍范围内。
temperature设为 0.1 可以降低随机性。 - 延迟预算:Bedrock 调用 + Lambda 执行的端到端延迟通常在 2-5 秒。如果业务要求 <1 秒响应,这个链路不合适。
- 图片尺寸:Nova 2 Lite 对输入图片有尺寸限制(具体上限查 Bedrock 文档)。超过限制的图片需要先缩放,缩放后坐标要按比例还原。
- JSON 解析兜底:模型偶尔会在 JSON 外加解释文字或 markdown 包裹。上面的 Lambda 代码已经做了清洗,但建议再加一层 try-catch,解析失败时返回原始文本供人工排查。
- 成本估算:Bedrock 按 request 计费,每次检测是一次 multimodal invoke。高频场景(每分钟数十次)下,成本可能超过自托管检测模型,需要做算账。
Nova 2 Lite 的 Prompt 驱动检测不是万能替代,但在"类别多变、迭代快速、调用低频"的场景下,它省掉了训练管线和模型运维,用一次 API 调用就把"看图出结构"这件事做完了。从 Prompt 到 Lambda 到 API Gateway,整条链路的代码量不到 200 行——这才是它最大的价值。