agno 图像标注到向量数据库:用 Agent 抽取结构化描述并构建可搜索媒体库的完整管线
【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno
导读
本文以 agno cookbook 中的_09_image_extraction_to_vectordb示例为骨架,完整讲解"图像标注 → 向量化 → 检索"的端到端管线:一个 Agent 从图片 URL 中抽取结构化ImageDescription(主体、场景、氛围、关键物体),把结构化字段展平为可搜索文本,再用GeminiEmbedder嵌入并写入 LanceDb,最终支持用自然语言查询相似图片。读完本文,你将掌握在 agno 中搭建"可搜索媒体库 / 以文搜图 / 找相似"类标注管线的完整实操方法与底层原理,并看到该管线在真实环境中的测试验证结果。
该示例位于 cookbook/data_labeling/_09_image_extraction_to_vectordb,核心实现文件为 basic.py,配套说明见 README.md。本文所有结论均依据仓库中的文档与源码。
一、示例定位:一条完整而非片段化的标注工作流
在 agno 的 data_labeling 系列 cookbook 中,_09_image_extraction_to_vectordb的价值恰恰在于它是完整的端到端管线,而不是某一个环节的单独演示。README 明确指出:basic.py把"extract → embed → store → search"四个步骤浓缩在一个文件里,没有额外变体,价值在于完整管线本身。
管线的四个环节:
- 对每张图片 URL,用一个 Agent 抽取结构化的
ImageDescription(subject 主体、setting 场景、mood 氛围、key_objects 关键物体); - 将结构化字段展平为单条可搜索文本;
- 用
GeminiEmbedder对文本做嵌入,存入 LanceDb; - 用自然语言查询检索索引,返回最相似的图片。
值得强调的一点(README 中专门提醒):该检索作用于抽取出的文本描述,而非图像本身的嵌入——两张图片匹配,是因为它们的描述文本匹配。这决定了它适合的落地场景:
- 用自然语言查询搜索图库(stock photo library);
- 按描述相似度对商品目录去重(注意:去重依据是抽取出的文本描述);
- 在用户上传的媒体上构建"find more like this"(找相似)功能。
二、快速运行:环境准备与执行命令
运行该示例只需要两步(来自 README.md):
pip install lancedb python cookbook/data_labeling/_09_image_extraction_to_vectordb/basic.py运行前提与产物:
- API Key:需要
GOOGLE_API_KEY环境变量。在源码层面,GeminiEmbedder 在构建客户端时通过getenv("GOOGLE_API_KEY")读取该变量,未设置时会记录错误日志GOOGLE_API_KEY not set。此外也可通过GOOGLE_GENAI_USE_VERTEXAI=true切换到 Vertex AI 方式(此时读取GOOGLE_CLOUD_PROJECT与GOOGLE_CLOUD_LOCATION)。 - 数据目录:运行会写入仓库根目录下的
tmp/lancedb/。LanceDb 默认uri="/tmp/lancedb",示例显式传入uri="tmp/lancedb"(相对路径,落在仓库根)。 - 可选依赖说明:TEST_LOG 实测确认,未安装
tantivy也能正常运行——因为本例只使用SearchType.vector(向量检索),关键字检索引擎tantivy仅在 keyword/hybrid 检索时需要。
三、核心代码逐段拆解(basic.py)
3.1 结构化输出 Schema:ImageDescription
抽取 Agent 的输出不是自由文本,而是一个 Pydantic 模型,四个字段各带描述(basic.py):
class ImageDescription(BaseModel): subject: str = Field(..., description="The main subject of the image") setting: str = Field(..., description="Where the image takes place") mood: str = Field(..., description="Overall mood or tone") key_objects: List[str] = Field( default_factory=list, description="Up to five notable objects" )subject:图片主体;setting:图片发生场景/地点;mood:整体氛围或基调;key_objects:最多五个值得注意的物体(默认空列表)。
用 Pydantic 模型做output_schema,是 agno 结构化输出的标准做法——模型必须按该 Schema 返回,才能被后续步骤可靠地展平与入库。
3.2 抽取 Agent
extractor = Agent( model="google:gemini-3.5-flash", instructions="You describe images as structured, search-friendly metadata.", output_schema=ImageDescription, )- 模型使用
google:gemini-3.5-flash; - 指令明确要求"把图片描述成结构化、便于搜索的元数据"——提示词与 Schema 双管齐下,确保输出是"搜索友好"的元数据而非散文;
output_schema=ImageDescription让每次run的.content直接是ImageDescription实例。
3.3 向量数据库:LanceDb + GeminiEmbedder
vector_db = LanceDb( uri="tmp/lancedb", table_name="data_labeling_images", search_type=SearchType.vector, embedder=GeminiEmbedder(id="gemini-embedding-001"), )对应 agno 的 LanceDb 实现,关键点:
uri:LanceDB 数据库位置,示例用本地相对路径;table_name:表名data_labeling_images,表已存在时打开,不存在则后续创建;search_type:取自 agno.vectordb.search.SearchType,可选vector(向量检索,本例所用)、keyword(关键字检索)、hybrid(混合检索);embedder:默认值为OpenAIEmbedder(源码中未传时会回退并打印提示),本例显式指定GeminiEmbedder(id="gemini-embedding-001");- 其他可配置项(源码可见,便于按需扩展):
distance(默认Distance.cosine,余弦距离)、nprobes(检索探针数)、reranker(重排器)、on_bad_vectors(坏向量处理策略:error/drop/fill/null)与fill_value。
GeminiEmbedder 的关键默认值:模型id="gemini-embedding-001",task_type="RETRIEVAL_QUERY",dimensions=1536,并支持通过request_params/client_params透传额外参数。嵌入请求通过 Google GenAI 客户端的models.embed_content完成(google.py),output_dimensionality与task_type均会随请求发送。值得注意:LanceDb 构造时会校验Embedder.dimensions必须已设置,否则抛ValueError(lance_db.py)——GeminiEmbedder默认dimensions=1536,满足此约束。
3.4 管线函数:describe / to_searchable_text / index_images
三个函数共同构成管线主体(basic.py):
def describe(url: str) -> ImageDescription: return extractor.run("Describe this image.", images=[Image(url=url)]).content def to_searchable_text(d: ImageDescription) -> str: return ( f"Subject: {d.subject}. Setting: {d.setting}. Mood: {d.mood}. " f"Objects: {', '.join(d.key_objects)}." ) def index_images(urls: List[str]) -> None: vector_db.create() docs: List[Document] = [] for url in urls: description = describe(url) docs.append( Document( name=url, content=to_searchable_text(description), meta_data={"url": url, "subject": description.subject}, ) ) vector_db.insert(content_hash="image_batch_1", documents=docs)describe:把图片 URL 包装为agno.media.Image(url=url),随提示词一起交给 Agent,返回结构化描述;to_searchable_text:把四个字段拼接成单一可检索文本——这是"把结构化输出变成可搜索文本"的关键一步,也是 README 强调"检索作用于文本描述"的直接体现;index_images:先vector_db.create()建表,再对每张图抽取、构造Document(name用图片 URL,content用展平文本,meta_data附带 url 与 subject 便于检索后回看元信息),最后以content_hash="image_batch_1"为批次标识整体插入。Document对应 agno/knowledge/document/base.py 中的核心数据结构。
3.5 主流程:三张示例图 + 两条自然语言查询
if __name__ == "__main__": urls = [ "https://agno-public.s3.amazonaws.com/images/krakow_mariacki.jpg", "https://www.gstatic.com/webp/gallery/1.jpg", "https://storage.googleapis.com/generativeai-downloads/images/generated_elephants_giraffes_zebras_sunset.jpg", ] index_images(urls) for query in ["a historic city at night", "wildlife on the savanna"]: results = vector_db.search(query, limit=2) pprint({"query": query, "hits": [r.meta_data for r in results]})- 三张图片:克拉科夫圣母圣殿(城市夜景主题)、gstatic 图库样例、大象/长颈鹿/斑马/鳄鱼汇聚水塘的野生动物场景;
vector_db.search(query, limit=2):以自然语言查询向量索引,返回前 2 条命中;- 结果打印各命中的
meta_data(含 url 与 subject),方便对照。
四、实测验证:TEST_LOG 的端到端结果
仓库中的 TEST_LOG.md 记录了 2026-07-18 在gemini-3.5-flash+gemini-embedding-001(embedder)、agno 2.7.4 环境下的实测结论,可作为该管线的可信度佐证:
- 运行方式:删除
tmp/lancedb/后从干净状态跑完整管线; - 抽取质量:三张图全部成功产出结构规整的输出。例如克拉科夫图得到 subject "St. Mary's Basilica framed by the arches of the Cloth Hall"(圣玛丽大教堂与纺织会馆拱门同框)、mood "Magical and serene"(魔幻而宁静);野生动物图得到 subject "A diverse group of African wildlife, including elephants, giraffes, zebras, and a crocodile, gathered at a watering hole"(多种非洲野生动物汇聚水塘);
- 写入结果:3 条文档成功插入;
- 检索正确性:查询 "a historic city at night" 命中克拉科夫圣母圣殿;查询 "wildlife on the savanna" 命中大象/长颈鹿/斑马场景——两条查询均返回语义正确的最相似图片;
- 性能参考:单张图片抽取耗时约 2.7–4.8 秒(该值依赖模型与网络,仅作参考,不作为普遍性能承诺);
- 环境边界:未安装
tantivy也能跑通,再次印证向量检索不依赖关键字引擎。
五、从源码看底层工作方式:为什么这条管线成立
- 结构化输出的可靠性:
output_schema+ 指令双约束,使 Agent 的输出稳定落在ImageDescription上,从而可以机械地展平为检索文本——这是后续一切的前提。 - 嵌入与维度一致性:
GeminiEmbedder固定输出 1536 维(dimensions默认值),LanceDb 构造时校验embedder.dimensions已设置(lance_db.py),保证建表时向量维度与嵌入结果一致;检索默认使用余弦距离(Distance.cosine)。 - 文本检索而非图像检索:整个流程中 LanceDb 存的是"描述文本的嵌入",查询时
search(query)内部同样先对查询文本做嵌入再比对。因此召回质量取决于抽取出的描述质量——这也解释了为何指令要强调"search-friendly metadata"。 - 可扩展配置:如需混合检索,可把
search_type改为SearchType.hybrid(此时需安装tantivy);如需云上 LanceDB,可传api_key=或设置LANCEDB_API_KEY(源码对db://开头的 Cloud URI 强制要求 API Key,见 lance_db.py);如需切换 Embedder,直接替换embedder=参数即可。
六、延伸阅读
- 同系列标注管线入口:cookbook/data_labeling/README.md,可对比文本、图像、音频、视频、文档等各模态的标注与抽取方案;
- 向量存储的其他后端示例:cookbook/06_storage(MySQL、Postgres、SQLite、Redis、Mongo 等);LanceDb 源码实现在 libs/agno/agno/vectordb/lancedb/lance_db.py,Embedder 抽象在 libs/agno/agno/knowledge/embedder/base.py,
GeminiEmbedder在 libs/agno/agno/knowledge/embedder/google.py; - 若需要构建 Agent 自身的知识检索(RAG),可参考 cookbook/07_knowledge 中的向量库接入方式。
【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考