Nano Banana多模态 RAG
本文介绍如何结合 Nano Banana 和 Milvus 构建企业级多模态 RAG 系统,以及这种组合为何能够开启下一波 AI 应用浪潮。
Nano Banana 现在在社交媒体上火了,而且绝对有它的理由!你可能已经看过它生成的图像,甚至亲自尝试过。这是一款最新的图像生成模型,能够以惊人的精度和速度将纯文本转换为收藏级的手办照片。
输入类似“交换 Elon 的帽子和裙子”之类的内容,大约 16 秒后,你就能得到照片级逼真的效果:衬衫塞好,颜色混合,配饰到位——无需手动编辑,毫无延迟。

我也忍不住尝试了一下。我的提示是:
“使用 Nano Banana 模型,以逼真的风格和环境,创建一个 1/7 比例的插画人物商业化手办。将手办放在电脑桌上,使用圆形透明亚克力底座,底座上不带任何文字。在电脑屏幕上,显示手办的 ZBrush 建模过程。在屏幕旁边,放置一个印有原图的万代风格玩具包装盒。”
最终效果让我惊叹不已——它看起来就像刚从展台上拿下来的量产原型。

毫不奇怪,各大团队已经找到了它的重要用例。我们的一位客户,一个以扭蛋和装扮游戏为特色的移动娱乐平台,正在开发一项功能,允许玩家上传照片,并立即用游戏内的配饰装扮他们的虚拟形象。一些电商品牌正在尝试“一次拍摄,永久重复使用”:拍摄一张基础模型图像,然后用人工智能生成无数种服装和发型变化,而不是在工作室里重复拍摄20次。
但问题在于——单靠图像生成并不能解决所有问题。这些系统还需要智能检索:能够从海量非结构化媒体库中即时找到合适的服装、道具和视觉元素。没有智能检索,生成模型就如同在黑暗中摸索。公司真正需要的是一个多模态RAG(检索增强生成)系统——其中Nano Banana负责创意,强大的矢量数据库负责处理上下文。
这就是 Milvus 的用武之地。作为一个开源矢量数据库,Milvus 可以索引和搜索数十亿个嵌入向量——图像、文本、音频等等。与 Nano Banana 搭配使用,它将成为企业级多模态 RAG 流程的骨干:搜索、匹配和生成。
在本博客的其余部分,我们将介绍如何结合 Nano Banana 和 Milvus 构建企业级多模态 RAG 系统,以及这种组合为何能够开启下一波 AI 应用浪潮。
1、构建文本转图像检索引擎
对于快速发展的消费品品牌、游戏工作室和媒体公司来说,AI 图像生成的瓶颈不在于模型,而在于数据本身的混乱。
他们的档案库充斥着非结构化数据,包括产品照片、角色素材、宣传视频和服装渲染图。当你需要查找“上一季春夏新品中的红色披风”时,祝你好运——传统的基于关键词的搜索根本无法解决这个问题。
解决方案?构建一个文本转图像检索系统。
具体方法如下:使用 CLIP 将文本和图像数据嵌入到向量中。将这些向量存储在 Milvus 中,这是一个专为相似性搜索而构建的开源向量数据库。然后,当用户输入描述(“带金色边饰的红色丝绸披风”)时,你就会访问数据库,并返回语义上最相似的前 3 张图片。
它速度快,可扩展,还能将你杂乱的媒体库变成一个结构化、可查询的素材库。
构建方法如下:
安装依赖项
# Install necessary packages
%pip install --upgrade pymilvus pillow matplotlib
%pip install git+https://github.com/openai/CLIP.git导入必要的库:
import os
import clip
import torch
from PIL import Image
import matplotlib.pyplot as plt
from pymilvus import MilvusClient
from glob import glob
import math
print("All libraries imported successfully!")初始化 Milvus 客户端:
milvus_client = MilvusClient(uri="http://localhost:19530",token="root:Miluvs")
print("Milvus client initialized successfully!")加载 CLIP 模型:
# Load CLIP model
model_name = "ViT-B/32"
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load(model_name, device=device)
model.eval()
print(f"CLIP model '{model_name}' loaded successfully, running on device: {device}")
print(f"Model input resolution: {model.visual.input_resolution}")
print(f"Context length: {model.context_length}")
print(f"Vocabulary size: {model.vocab_size}")输出结果:
CLIP model `ViT-B/32` loaded successfully, running on: cpu
Model input resolution: 224
Context length: 77
Vocabulary size: 49,408定义特征提取函数:
def encode_image(image_path):
"""Encode image into normalized feature vector"""
try:
image = preprocess(Image.open(image_path)).unsqueeze(0).to(device)
with torch.no_grad():
image_features = model.encode_image(image)
image_features /= image_features.norm(dim=-1, keepdim=True) # Normalize
return image_features.squeeze().cpu().tolist()
except Exception as e:
print(f"Error processing image {image_path}: {e}")
return None
def encode_text(text):
"""Encode text into normalized feature vector"""
text_tokens = clip.tokenize([text]).to(device)
with torch.no_grad():
text_features = model.encode_text(text_tokens)
text_features /= text_features.norm(dim=-1, keepdim=True) # Normalize
return text_features.squeeze().cpu().tolist()
print("Feature extraction functions defined successfully!")创建 Milvus 集合:
collection_name = "production_image_collection"
# If collection already exists, delete it
if milvus_client.has_collection(collection_name):
milvus_client.drop_collection(collection_name)
print(f"Existing collection deleted: {collection_name}")
# Create new collection
milvus_client.create_collection(
collection_name=collection_name,
dimension=512, # CLIP ViT-B/32 embedding dimension
auto_id=True, # Auto-generate ID
enable_dynamic_field=True, # Enable dynamic fields
metric_type="COSINE" # Use cosine similarity
)
print(f"Collection '{collection_name}' created successfully!")
print(f"Collection info: {milvus_client.describe_collection(collection_name)}")集合创建成功输出:
Existing collection deleted: production_image_collection
Collection 'production_image_collection' created successfully!
Collection info: {'collection_name': 'production_image_collection', 'auto_id': True, 'num_shards': 1, 'description': '', 'fields': [{'field_id': 100, 'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'params': {}, 'auto_id': True, 'is_primary': True}, {'field_id': 101, 'name': 'vector', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 512}}, {'field_id': 102, 'name': 'function': [], 'aliases': [], 'collection_id': 460508990706033544, 'consistency_level': 2, 'properties': {}, 'num_partitions': 1, 'enable_dynamic_field': True, 'created_timestamp': 460511723827494913, 'updated_timestamp': 460511723827494913}处理并插入图片:
# Set image directory path
image_dir = "./production_image"
raw_data = []
# Get all supported image formats
image_extensions = ['*.jpg', '*.jpeg', '*.png', '*.JPEG', '*.JPG', '*.PNG']
image_paths = []
for ext in image_extensions:
image_paths.extend(glob(os.path.join(image_dir, ext)))
print(f"Found {len(image_paths)} images in {image_dir}")
# Process images and generate embeddings
successful_count = 0
for i, image_path in enumerate(image_paths):
print(f"Processing progress: {i+1}/{len(image_paths)} - {os.path.basename(image_path)}")
image_embedding = encode_image(image_path)
if image_embedding is not None:
image_dict = {
"vector": image_embedding,
"filepath": image_path,
"filename": os.path.basename(image_path)
}
raw_data.append(image_dict)
successful_count += 1
print(f"Successfully processed {successful_count} images")图片处理进度输出:
Found 50 images in ./production_image
Processing progress: 1/50 - download (5).jpeg
Processing progress: 2/50 - images (2).jpeg
Processing progress: 3/50 - download (23).jpeg
Processing progress: 4/50 - download.jpeg
Processing progress: 5/50 - images (14).jpeg
Processing progress: 6/50 - images (16).jpeg
…
Processing progress: 44/50 - download (10).jpeg
Processing progress: 45/50 - images (18).jpeg
Processing progress: 46/50 - download (9).jpeg
Processing progress: 47/50 - download (12).jpeg
Processing progress: 48/50 - images (1).jpeg
Processing progress: 49/50 - download.png
Processing progress: 50/50 - images.png
Successfully processed 50 images将数据插入 Milvus:
# Insert data into Milvus
if raw_data:
print("Inserting data into Milvus...")
insert_result = milvus_client.insert(collection_name=collection_name, data=raw_data)
print(f"Successfully inserted {insert_result['insert_count']} images into Milvus")
print(f"Sample inserted IDs: {insert_result['ids'][:5]}...") # Show first 5 IDs
else:
print("No successfully processed image data to insert")定义搜索和可视化函数:
def search_images_by_text(query_text, top_k=3):
"""Search images based on text query"""
print(f"Search query: '{query_text}'")
# Encode query text
query_embedding = encode_text(query_text)
# Search in Milvus
search_results = milvus_client.search(
collection_name=collection_name,
data=[query_embedding],
limit=top_k,
output_fields=["filepath", "filename"]
)
return search_results[0]
def visualize_search_results(query_text, results):
"""Visualize search results"""
num_images = len(results)
if num_images == 0:
print("No matching images found")
return
# Create subplots
fig, axes = plt.subplots(1, num_images, figsize=(5*num_images, 5))
fig.suptitle(f'Search Results: "{query_text}" (Top {num_images})', fontsize=16, fontweight='bold')
# Handle single image case
if num_images == 1:
axes = [axes]
# Display images
for i, result in enumerate(results):
try:
img_path = result['entity']['filepath']
filename = result['entity']['filename']
score = result['distance']
# Load and display image
img = Image.open(img_path)
axes[i].imshow(img)
axes[i].set_title(f"{filename}\nSimilarity: {score:.3f}", fontsize=10)
axes[i].axis('off')
print(f"{i+1}. File: {filename}, Similarity score: {score:.4f}")
except Exception as e:
axes[i].text(0.5, 0.5, f'Error loading image\n{str(e)}',
ha='center', va='center', transform=axes[i].transAxes)
axes[i].axis('off')
plt.tight_layout()
plt.show()
print("Search and visualization functions defined successfully!")执行文本转图像搜索:
# Example search 1
query1 = "a golden watch"
results1 = search_images_by_text(query1, top_k=3)
visualize_search_results(query1, results1)搜索查询执行输出:
Search query: 'a golden watch'
1. File: images (19).jpeg, Similarity score: 0.2934
2. File: download (26).jpeg, Similarity score: 0.3073
3. File: images (17).jpeg, Similarity score: 0.2717
2、使用 Nano-banana 创建品牌宣传图片
现在,我们的文本转图片搜索系统已经与 Milvus 兼容,接下来让我们集成 Nano-banana,根据检索到的素材生成新的宣传内容。
安装 Google SDK:
%pip install google-generativeai
%pip install requests
print("Google Generative AI SDK installation complete!")配置 Gemini API:
import google.generativeai as genai
from PIL import Image
from io import BytesIO
genai.configure(api_key="<your_api_key>")生成新图片:
prompt = (
"An European male model wearing a suit, carrying a gold watch."
)
image = Image.open("/path/to/image/watch.jpg")
model = genai.GenerativeModel('gemini-2.5-flash-image-preview')
response = model.generate_content([prompt, image])
for part in response.candidates[0].content.parts:
if part.text is not None:
print(part.text)
elif part.inline_data is not None:
image = Image.open(BytesIO(part.inline_data.data))
image.save("generated_image.png")
image.show()
3、这对您的开发工作流程意味着什么
作为开发者,Milvus 与 Nano-banana 的集成从根本上改变了您处理内容生成项目的方式。您无需管理静态素材库或依赖昂贵的创意团队,而是拥有一个动态系统,可以实时检索和生成应用程序所需的内容。
考虑以下最近的客户场景:一个品牌推出了几款新产品,但选择完全跳过传统的照片拍摄流程。使用我们的集成系统,他们可以将现有的产品数据库与 Nano-banana 的生成功能相结合,立即生成宣传图片。
提示:一位模特在海滩上穿着这些产品

当您需要创建复杂、多变的内容时,真正的强大功能就显现出来了,而这通常需要摄影师、模特和布景设计师之间进行大量的协调。 Milvus 负责资源检索,Nano-banana 负责生成,您可以以编程方式创建符合您特定需求的复杂场景:
提示:一位模特正倚靠在一辆蓝色敞篷跑车上摆姿势。她身着露背连衣裙及配饰,佩戴着钻石项链和蓝色手表,脚踩高跟鞋,手捧拉布布吊坠。

对于游戏或收藏品领域的开发者来说,该系统为快速原型设计和概念验证开辟了全新的可能性。您无需花费数周时间进行 3D 建模才能确定一个概念是否可行,现在您可以生成包含包装、环境背景甚至制造流程的逼真产品可视化效果:
提示:使用 nano-banana 模型,以逼真的风格和环境创建插图中角色的 1/7 比例商业化模型。将模型放置在电脑桌上,使用圆形透明亚克力底座,底座上不带任何文字。在电脑屏幕上显示模型的 ZBrush 建模过程。在电脑屏幕旁边放一个印有原版图案的万代风格玩具包装盒。

4、结束语
从技术角度来看,Nano Banana 不仅仅是一个新奇事物——它已经具备了生产环境的可操作性,这对开发者来说至关重要。它最大的优势在于一致性和可控性,这意味着更少的边缘情况会渗透到你的应用程序逻辑中。同样重要的是,它能够处理微妙的这些细节往往会阻碍自动化流程:保持品牌色彩的一致性、生成符合物理规律的光照和反射,以及确保多种输出格式的视觉一致性。
真正的魔力在于将其与 Milvus 矢量数据库相结合。矢量数据库不仅仅是存储嵌入,它还能成为一个智能的资产管理器,能够呈现最相关的历史内容,指导新一代模型的生成。其结果是:更快的生成时间(因为模型拥有更佳的上下文)、更高的应用程序一致性,以及自动执行品牌或风格指南的能力。
简而言之,Milvus 将 Nano Banana 从一个创意玩具转变为一个可扩展的企业系统。
当然,没有哪个系统是完美无缺的。复杂的多步骤指令仍然可能出现问题,而光照物理特性有时会超出您的预期。我们见过的最可靠的解决方案是使用存储在 Milvus 中的参考图像来补充文本提示,这为模型提供了更丰富的基础、更可预测的结果和更短的迭代周期。通过此设置,您不仅可以试验多模式 RAG,还可以满怀信心地在生产中运行它。
原文链接:Nano Banana + Milvus: Turning Hype into Enterprise-Ready Multimodal RAG
汇智网翻译整理,转载请标明出处