为了账号安全,请及时绑定邮箱和手机立即绑定

使用Langchain和Gemini提取图像信息:一步一步教你怎么做

在这篇文章里,我们将探索使用Langchain和多模态大语言模型Gemini-Flash-1.5来构建一个图像元数据提取流程。我们还将展示一种确保生成内容具有足够多样性的方法,这有助于提升SEO优化和用户体验。

桌上摆满了图片,有个像C3PO的机器人正看着这些图片

你有没有一大批图片需要标注?你用语言模型来标注这些图片。本指南将带你了解如何操作,利用Langchain和Gemini-Flash-1.5从图片里提取信息并返回结构化属性。我们已经为一家大型在线零售商实施了这项方案,处理了成千上万张产品图片。通过描述图片并提取颜色、SEO标签等额外属性,我们可以生成结构化数据,以提升上传到电子商务网站时的用户体验和SEO排名。

我们使用多种大型语言模型(LLMs)来处理各种子任务,并通过Langchain高效解析LLM输出。Langchain还通过并行操作来提升性能。

我们的照片

以这个案例为例,我拍了一些水果的照片;我们将用它们创建一个提取流程并尝试用一个LLm(大型语言模型)进行标注。

     # 从这些图片中提取数据  
    fruits = ['https://storage.googleapis.com/vectrix-public/fruit/apple.jpeg',  
              'https://storage.googleapis.com/vectrix-public/fruit/banana.jpeg',  
              'https://storage.googleapis.com/vectrix-public/fruit/kiwi.jpeg',  
              'https://storage.googleapis.com/vectrix-public/fruit/peach.jpeg',  
              'https://storage.googleapis.com/vectrix-public/fruit/plum.jpeg']

直接将图片喂入模型:

我们可以直接将图片传递给LLM而不通过Langchain。让我们用Gemini Flash模型测试一下模型的反应。请将你的API密钥设置为环境变量GOOGLE_API_KEY

代码示例
    from langchain_core.messages import HumanMessage  
    from langchain_google_genai import ChatGoogleGenerativeAI  
    import base64, httpx  

    # 初始化模型实例  
    model = ChatGoogleGenerativeAI(model="gemini-1.5-flash")  

    # 下载并编码图片  
    image_data = base64.b64encode(httpx.get(fruits[0]).content).decode("utf-8")  

    # 使用这张图片创建消息  
    message = HumanMessage(  
        content=[  
            {"type": "text", "text": "描述这张图片里的水果"},  
            {  
                "type": "image_url",  
                "image_url": {"url": f"data:image/jpeg;base64,{image_data}"},  
            },  
        ],  
    )  

    # 通过消息调用模型  
    response = model.invoke([message])  

    # 打印模型的回复  
    print(response.content)
模型响应(仅标题)

系统会用详细的方式来描述图片里的水果。比如说:

这个水果是苹果。它是红色和黄色的,顶部有一个小小的梗。这个苹果中间有一个小坑,那是茎的连接处。苹果有点儿磕碰。

它是怎么工作的
  1. 初始化模型:我们使用来自Langchain的ChatGoogleGenerativeAI包来初始化Gemini Flash模型。
  2. 下载并编码图像:图像被下载并使用base64编码,并将其转换为base64格式。
  3. 创建消息:我们创建一个包含文本提示和base64编码图像的HumanMessage
  4. 调用模型:模型被调用,并根据图像生成描述。
  5. 打印响应:模型生成的响应被打印出来,提供水果的详细描述。

通过使用ChatGoogleGenerativeAI包,我们可以直接与Gemini Flash模型交互,发送图片并接收描述性反馈。这种方法使我们能够快速测试模型的能力并了解它如何处理图片输入。

现在我们有了图片,接下来让我们使用模型并设置一下提取流程。

第一步:定义输出的格式和结构

下一步是從圖像提取結構化數據。我們可以利用 Pydantic 解析器和多模態消息來達成這個目標。首先,我們會定義一個 Pydantic 數據模型,然後再傳遞給模型,從圖像提取結構化的數據。

定义数据模型

我们使用 Pydantic 来定义数据模型,这有助于确保提取的数据既结构化又经过验证。举个例子,我们定义了一个 Fruit 模型(水果模型),包含水果名称、颜色、口味和营销描述等。

    from langchain.output_parsers import PydanticOutputParser  
    from langchain_core.prompts import ChatPromptTemplate  
    from langchain_core.pydantic_v1 import BaseModel, Field  

    # 定义一个 Pydantic 模型来解析模型的输出  
    class Fruit(BaseModel):  
        name: str = Field(description="图片中展示的水果名称")  
        color: str = Field(description="图片中展示的水果颜色")  
        taste: str = Field(description="图片中展示的水果的味道")  
        marketing_description: str = Field(description="图片中展示的水果的市场推广描述")  

    parser = PydanticOutputParser(pydantic_object=Fruit)
设置提示

我们使用 ChatPromptTemplate 创建一个提示,要求模型以所需的 JSON 格式返回响应。该提示包含系统消息和用户消息,其中用户消息提供了 base64 编码的图片 URL。

    prompt = ChatPromptTemplate.from_messages([  
        ("system", "请用 {language} 返回所需的响应对象。\n'{format_instructions}'\n"),  
        ("user", [  
            {  
                "type": "image_url",  
                "image_url": {"url": "data:image/jpeg;base64,{image_data}"},  
            },  
        ]),  
    ])
结合提示词、模型和解析工具

我们将提示词、模型和解析器(PydanticOutputParser)组合成一个链。模型处理图像,并将结果以JSON格式返回,然后将其解析并验证是否符合Fruit数据模型。

    chain = prompt | 模型 | 解析  

    # 获取图像的Base64编码数据  
    image_data = base64.b64encode(httpx.get(fruits[3]).content).decode("utf-8")  

    # 运行链并输出结果  
    print(chain.invoke({  
        "language": "English",  
        "format_instructions": parser.get_format_instructions(),  
        "image_data": image_data  
    }).json(indent=2))
它是怎么运作的
  1. 创建提示ChatPromptTemplate 构建了一个提示,指示模型以特定的 JSON 格式作答。
  2. 模型处理:多模态大模型 Gemini-Flash-1.5 处理图像并生成一个包含结构化数据的 JSON 回应。
  3. 解析并验证PydanticOutputParser 解析 JSON 回应,并根据 Fruit 数据模型进行验证,确保数据结构正确无误并符合定义的模型。

如上所述,我们创建了一个新的链,结合提示、图片和格式说明,让模型按照所需的JSON格式返回回应。然后,我们使用PydanticOutputParser从LLM的输出中提取JSON并将其转换为字典。最终的响应对象如下:

{
  "name": "桃",
  "color": "橙",
  "taste": "甜甜的",
  "marketing_description": "多汁又美味的桃子,非常适合夏天当零食或甜点。"
}
步骤2:并行地处理图像

我们在第一步定义的管道运行得非常好,但如果你需要处理数千张图片,速度可能会变慢。对于大型数据集,顺序处理可能需要好几个小时甚至几天。解决这个问题的办法是使用并行处理,幸运的是,Langchain 提供了一个解决方案,即使用 chain.batch 函数。

并行执行链式流程

要并行处理所有图像,我们首先准备一个包含每张图像所需数据的字典的列表。然后,我们使用链上的批处理方法,这样我们就能同时处理多张图像了。

    # 准备图像数据的字典列表
    all_images = [{"语言代码": "English",  
                   "格式指令": parser.get_format_instructions(),  
                   "图像信息": base64.b64encode(httpx.get(url).content).decode("utf-8")}  
                  for url in fruits]
它是怎么工作的
  1. 准备数据: 我们创建一个包含每张图片URL语言、格式说明和base64编码图片数据的字典列表。
  2. 并行处理请求 :通过在链上使用batch方法,我们可以并行处理所有提取请求。max_concurrency配置选项有助于管理并发请求的数量,避免达到模型API的速率限制。
  3. 获取结果: results对象包含一个字典列表,其中每个字典包含每张图片提取的数据。
示例结果

结果对象将包含每个图像的结构化数据,如下示例数据所示。

    {  
      "name": "苹果",  
      "color": "红绿相间",  
      "taste": "又甜又酸",  
      "marketing_description": "脆嫩多汁的苹果,又甜又酸,无论是当零食还是烘焙都非常合适。"  
    }  
    {  
      "name": "香蕉",  
      "color": "黄色的",  
      "taste": "甜",  
      "marketing_description": "既美味又营养的水果,适合快速小吃或健康早餐。我们的香蕉已经熟透,可以直接食用,口感甜美顺滑,深受大家喜爱。"  
    }  
    ...
步骤3:确保输出有多样性:保证输出包含足够的变化。

如上面的例子所示,描述可以非常相似。当给定相同的提示时,语言模型会生成类似的输出。虽然调整模型的温度设置可以缓解这种情况,但如果设置过高,也可能破坏JSON结构。

这样的输出对SEO不利,所以我们必须确保模型生成独特描述。我们可以通过让模型从一个随机字母和一个随机长度开始生成来实现一些变化。这里是我们用来实现这一功能的函数。

导入 random 模块

def generate_random_letter():  
    letters = ['A', 'B', 'C', 'D', 'M', 'P', 'R', 'S', 'T']  
    return random.choice(letters)

def generate_random_number():  
    return random.randint(30, 45)
更新提示内容

首先,我们更新提示。在更新中,我们加入起始字母和长度这两个变量。

    # 这是一个新的提示模板,营销描述需要以指定的字母开头
    prompt = ChatPromptTemplate.from_messages([  
        (  
            "system", "以字母 '{starting_letter}' 开头,用 {language} 返回请求的响应对象。确保营销描述以字母 '{starting_letter}' 开头\n'{格式说明}'\n"  
        ),  
        (  
            "human", [  
                {  
                    "type": "图片链接",  
                    "image_url": {"url": "data:image/jpeg;base64,{image_data}"},  
                },  
            ],  
        )  
    ])
增加批次的随机性

接下来,修改调用批处理所用的字典,使其在提示中加入一些随机性。

    # 准备包含随机性的图像数据字典列表
    all_images = [{"language": "English",   
                   "format_instructions": parser.get_format_instructions(),  
                   "image_data": base64.b64encode(httpx.get(url).content).decode("utf-8"),  
                   "starting_letter": generate_random_letter()}   
                  for url in fruits]  

    chain = prompt | model | parser  

    # 以指定的最大并发数并行运行链
    results = chain.batch(all_images, config={"max_concurrency": 5})  

    # 打印结果
    for result in results:  
        print(result.json(indent=2))
它是怎么工作的.
  1. 生成随机值:我们使用 generate_random_letter:为每个描述生成一个随机的起始字母,以确保输出的多样性。
  2. 更新提示:提示中包含起始字母变量,使模型必须以该字母开始营销描述。
  3. 并行处理中的随机性:通过将起始字母添加到 all_images 列表中的每个字典,我们在批量处理中引入了变化,以增加多样性。
示例输出

打印结果会显示出变化更多、更丰富的输出。

    {  
      "name": "苹果",  
      "color": "红绿",  
      "taste": "甜中带酸",  
      "marketing_description": "这苹果脆爽多汁,味道丰富,是任何场合的理想小食。你可以单独享用,也可以用于你喜爱的食谱中。"  
    }  
    {  
      "name": "香蕉",  
      "color": "黄色",  
      "taste": "甜",  
      "marketing_description": "香蕉不仅美味,而且用途广泛,可以多种方式享用。它们富含钾和纤维,还含有丰富的维生素B6和维生素C。香蕉是一种很好的零食,也可以用于奶昔、烘焙食品和其他食谱中。它们还是一种很好的能量来源,有助于改善心情。"  
    }  
    {  
      "name": "猕猴桃",  
      "color": "绿色",  
      "taste": "甜中带酸",  
      "marketing_description": "请来尝一下我们美味的猕猴桃!这种绿色水果甜中带酸,既可作为健康的小吃,也可为冰沙增添美味。"  
    }  
    ...

通过在提示中加入随机元素,我们可以确保模型生成独特且多样的描述,这对SEO非常有帮助。

最后的想法

我们希望这份指南能激发你在你的项目中尝试提取图像元数据的实验。要深入了解代码并实际操作,可以去我们放在Google Colab上的Jupyter Notebook看看。

在GitHub上浏览bselleslagh的Jupyter笔记本

如果您有任何问题或想了解更多关于我们在Vectrix的工作,请访问我们的网站https://vectrix.ai,我们总是很乐意与志同道合的AI爱好者交流和合作,并帮助您实现您的想法。

谢谢你的阅读,祝你编程愉快!🙏

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消