基于 NIM 建构多模态 AI-Agent (代码解析)

news2024/9/20 1:00:24

本次课程将着重介绍一下内容:

  • 多模态模型基于 NIM 的调用方式
  • 基于 NIM 接口实现 Phi-3-Vision 的推理实践
  • 基于 Gradio 框架建立前端互动界面

申请NIM的API Key,来调用NIM的计算资源

进入NVIDIA NIM | phi-3-vision-128k-instruct, 点击Get API Key按钮,生成一个秘钥

第一步, 导入工具包

本次实验主要需要三个工具包:

  • langchain_nvidia_ai_endpoint: 用来调用nvidia nim的计算资源
  • langchain: 用来构建对话链, 将智能体的各个组件串联起来
  • base64: 因为本实验是构建多模态的智能体, 需要base64来对图像进行编解码

from langchain_nvidia_ai_endpoints import ChatNVIDIA
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableLambda
from langchain.schema.runnable.passthrough import RunnableAssign
from langchain_core.runnables import RunnableBranch
from langchain_core.runnables import RunnablePassthrough
 
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

import os
import base64
import matplotlib.pyplot as plt
import numpy as np

将上面准备好的秘钥粘贴在此处, 当我们向服务器发送计算请求时, 需要用到

os.environ["NVIDIA_API_KEY"] = "nvapi-Exxxxxx"

查看当前可以使用的模型

ChatNVIDIA.get_available_models()

第二步, 利用Microsoft Phi 3 vision 来解析图片数据

将图片进行编解码

def image2b64(image_file):
    with open(image_file, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode()
        return image_b64

image_b64 = image2b64("eco-good-bad-chart.png")

查看图片

from PIL import Image
display(Image.open("economic-assistance-chart.png"))

将编码后的图像按照格式给到Microsoft Phi 3 vision , 利用其强大能力解析图片中的数据

chart_reading = ChatNVIDIA(model="ai-phi-3-vision-128k-instruct")
result = chart_reading.invoke(f'Generate underlying data table of the figure below, : <img src="data:image/png;base64,{image_b64}" />')
print(result.content)

当然您也可以调用任何其他大模型来为您工作

下面的示例中, 调用Llama3 70b的模型,通过中文输入提示词,来进行工作

instruct_chat = ChatNVIDIA(model="ai-llama3-70b")
# result = instruct_chat.invoke('How to implement Fibonacci in python using dynamic programming')
result = instruct_chat.invoke('怎么用 Python 实现快速排序')
print(result.content)

第三步, 使用 LangChain 构建多模态智能体

Agent 应用场景:将图片中的统计图表转换为可以用 python 进行分析的数据

Agent 工作流

  • 接收图片,读取图片数据
  • 对数据进行调整、分析
  • 生成能够绘制图片的代码,并执行代码
  • 根据处理后的数据绘制图表

接收图片 -> 分析数据 -> 修改数据 -> 生成绘制图片的代码 -> 执行代码 -> 展示结果

辅助函数

这里的函数用于显示输入, 执行代码等, 在我们执行过程中可能会用到

import re

# 将 langchain 运行状态下的表保存到全局变量中
def save_table_to_global(x):
    global table
    if 'TABLE' in x.content:
        table = x.content.split('TABLE', 1)[1].split('END_TABLE')[0]
    return x

# helper function 用于Debug
def print_and_return(x):
    print(x)
    return x

# 对打模型生成的代码进行处理, 将注释或解释性文字去除掉, 留下pyhon代码
def extract_python_code(text):
    pattern = r'```python\s*(.*?)\s*```'
    matches = re.findall(pattern, text, re.DOTALL)
    return [match.strip() for match in matches]

# 执行由大模型生成的代码
def execute_and_return(x):
    code = extract_python_code(x.content)[0]
    try:
        result = exec(str(code))
        #print("exec result: "+result)
    except ExceptionType:
        print("The code is not executable, don't give up, try again!")
    return x

# 将图片编码成base64格式, 以方便输入给大模型
def image2b64(image_file):
    with open(image_file, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode()
        return image_b64

定义多模态数据分析 Agent

  • 这里首先定义了提示词模板, chart_reading_prompt, 我们输入的图片会边恒base64格式的string传输给它
  • 将处理好的提示词输入给char_reading, 也就是microsoft/phi-3-vision大模型来进行数据分析, 得到我们需要的表格或者说table变量
  • 将Phi3 vision处理好的table和提示词输入给另一个大模型llama3.1, 修改数据并生成代码
  • 将生成的代码通过上面的执行函数来执行python代码, 并得到结果

def chart_agent(image_b64, user_input, table):
    # Chart reading Runnable
    chart_reading = ChatNVIDIA(model="ai-phi-3-vision-128k-instruct")
    chart_reading_prompt = ChatPromptTemplate.from_template(
        'Generate underlying data table of the figure below, : <img src="data:image/png;base64,{image_b64}" />'
    )
    chart_chain = chart_reading_prompt | chart_reading

    # Instruct LLM Runnable
    # instruct_chat = ChatNVIDIA(model="nv-mistralai/mistral-nemo-12b-instruct")
    # instruct_chat = ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
    #instruct_chat = ChatNVIDIA(model="ai-llama3-70b")
    instruct_chat = ChatNVIDIA(model="meta/llama-3.1-405b-instruct")

    instruct_prompt = ChatPromptTemplate.from_template(
        "Do NOT repeat my requirements already stated. Based on this table {table}, {input}" \
        "If has table string, start with 'TABLE', end with 'END_TABLE'." \
        "If has code, start with '```python' and end with '```'." \
        "Do NOT include table inside code, and vice versa."
    )
    instruct_chain = instruct_prompt | instruct_chat

    # 根据“表格”决定是否读取图表
    chart_reading_branch = RunnableBranch(
        (lambda x: x.get('table') is None, RunnableAssign({'table': chart_chain })),
        (lambda x: x.get('table') is not None, lambda x: x),
        lambda x: x
    )
    # 根据需求更新table
    update_table = RunnableBranch(
        (lambda x: 'TABLE' in x.content, save_table_to_global),
        lambda x: x
    )
    # 执行绘制图表的代码
    execute_code = RunnableBranch(
        (lambda x: '```python' in x.content, execute_and_return),
        lambda x: x
    )

    chain = (
        chart_reading_branch
        #| RunnableLambda(print_and_return)
        | instruct_chain
        #| RunnableLambda(print_and_return)
        | update_table
        | execute_code
    )

    return chain.invoke({"image_b64": image_b64, "input": user_input, "table": table}).content

初始化

# 使用全局变量 table 来存储数据
table = None
# 将要处理的图像转换成base64格式
image_b64 = image2b64("image.png")

#展示读取的图片
from PIL import Image

display(Image.open("image.png"))

执行上面构建好的智能体

先将图片的数据转为字符串
user_input = "show this table in string"
chart_agent(image_b64, user_input, table)
print(table)    # let's see what 'table' looks like now

让 Agent 自己尝试修改其中的内容

比如我们这里要把所有的UK 替换成United Kingdom

user_input = "replace table string's 'UK' with 'United Kingdom'"
chart_agent(image_b64, user_input, table)
print(table)    # let's see what 'table' looks like now
用 python 绘制图表

这里会让大模型生成绘制图像的代码, 并执行生成的代码

!pip install gradio
!pip install pandas
user_input = "draw this table as stacked bar chart in python"
result = chart_agent(image_b64, user_input, table)
print("result: "+result)  # let's see what 'table' looks like now

第四步, 将多模态智能体封装进Gradio

当我们完成上述任务的时候, 就拥有了一个可以分析图片, 生成代码, 修改数据, 执行代码的智能体

接下来我们给这个智能体添加一个UI界面, 让我们可以更舒服的与之对话

我们修改一下执行代码的函数, 因为原生的Python中exec函数的返回是Nan, 所以我们给他添加一个生成图片的路径

在下面的代码中, 路径是作者的PC中的路径, 请您根据您自己的系统更换这个文件夹路径

global img_path
# img_path = '/home/nvidia/2024_summer_bootcamp/day3/'+'image.png'
img_path = 'C:\\Users\\wei\\Documents\\nvidiafiles\\day3\\'+'image.png'
print(img_path)
def execute_and_return_gr(x):
    code = extract_python_code(x.content)[0]
    try:
        result = exec(str(code))
        #print("exec result: "+result)
    except ExceptionType:
        print("The code is not executable, don't give up, try again!")
    return img_path

这个chart_agent函数的输入原来是base64格式, 但是gradio中上传图片的格式是png或jpg等图片格式

所以我们更新了这个函数, 在最开始的步骤中加入了一个编码的过程

def chart_agent_gr(image_b64, user_input, table):

    image_b64 = image2b64(image_b64)
    # Chart reading Runnable
    chart_reading = ChatNVIDIA(model="microsoft/phi-3-vision-128k-instruct")
    chart_reading_prompt = ChatPromptTemplate.from_template(
        'Generate underlying data table of the figure below, : <img src="data:image/png;base64,{image_b64}" />'
    )
    chart_chain = chart_reading_prompt | chart_reading

    # Instruct LLM Runnable
    # instruct_chat = ChatNVIDIA(model="nv-mistralai/mistral-nemo-12b-instruct")
    # instruct_chat = ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
    #instruct_chat = ChatNVIDIA(model="ai-llama3-70b")
    instruct_chat = ChatNVIDIA(model="meta/llama-3.1-405b-instruct")

    instruct_prompt = ChatPromptTemplate.from_template(
        "Do NOT repeat my requirements already stated. Based on this table {table}, {input}" \
        "If has table string, start with 'TABLE', end with 'END_TABLE'." \
        "If has code, start with '```python' and end with '```'." \
        "Do NOT include table inside code, and vice versa."
    )
    instruct_chain = instruct_prompt | instruct_chat

    # 根据“表格”决定是否读取图表
    chart_reading_branch = RunnableBranch(
        (lambda x: x.get('table') is None, RunnableAssign({'table': chart_chain })),
        (lambda x: x.get('table') is not None, lambda x: x),
        lambda x: x
    )
    
    # 根据需求更新table
    update_table = RunnableBranch(
        (lambda x: 'TABLE' in x.content, save_table_to_global),
        lambda x: x
    )

    execute_code = RunnableBranch(
        (lambda x: '```python' in x.content, execute_and_return_gr),
        lambda x: x
    )
    
    # 执行绘制图表的代码
    chain = (
        chart_reading_branch
        | RunnableLambda(print_and_return)
        | instruct_chain
        | RunnableLambda(print_and_return)
        | update_table
        | execute_code
    )

    return chain.invoke({"image_b64": image_b64, "input": user_input, "table": table})

这里是示意提示词, 放大家打开Gradio页面时候直接复制粘贴

user_input = "replace table string's 'UK' with 'United Kingdom', draw this table as stacked bar chart in python, and save the image in path: "+img_path
print(user_input)

执行上述代码, 将打开一个Gradio的服务, 我们可以利用Gradio的页面与构建好的智能体对话

import gradio as gr
multi_modal_chart_agent = gr.Interface(fn=chart_agent_gr,
                    inputs=[gr.Image(label="Upload image", type="filepath"), 'text'],
                    outputs=['image'],
                    title="Multi Modal chat agent",
                    description="Multi Modal chat agent",
                    allow_flagging="never")

multi_modal_chart_agent.launch(debug=True, share=False, show_api=False, server_port=5000, server_name="0.0.0.0")

执行完后,可以打开 http://localhost:5000.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2125771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBootWeb案例(续)

书接上回&#xff0c;上篇文章CSDN 复习了部门管理功能的开发。这篇文章来复习员工管理模块功能开发 基于以上页面原型&#xff0c;我们可以把员工管理功能分为&#xff1a; 分页查询&#xff08;重点&#xff09; 带条件的分页查询&#xff08;重点&#xff09; 删除员工 新…

泰语快速学习方法!速成方法学习!

要快速学习泰语&#xff0c;可以采取多种策略&#xff0c;如掌握基础语法和词汇&#xff0c;专注于发音练习以掌握泰语特有的音调系统&#xff0c;利用语言学习软件进行互动学习&#xff0c;通过观看泰语媒体内容提高听力理解&#xff0c;与母语者进行语言交换来锻炼口语&#…

GDB 查看汇编

查看汇编 x disassemble

MySQL 按照条件(分组)只取一个形成列表 group max

方法一、通过Max形成where条件 SELECTt1.* FROMbiz_customer_hold AS t1 WHEREt1.ch_create_time ( SELECT MAX( ch_create_time ) FROM biz_customer_hold AS t2 WHERE t2.ch_cust_no t1.ch_cust_no ) ORDER BYt1.ch_create_time DESC,t1.ch_hold_time DESC 方法二、通…

部署TC服务 服务集成Seata

一、部署TC服务 tc在管理全局事务和分支事务是需要记录&#xff0c;最好放在数据库中持久保存 1.创建数据库表 创建一个名为Seata的库建立四张表 语句如下 CREATE DATABASE IF NOT EXISTS seata; USE seata;CREATE TABLE IF NOT EXISTS global_table (xid …

【PGCCC】Postgres 17 中的 3 大特性

一年又一年&#xff0c;Postgres 已成为世界上最受喜爱和最受信任的数据库 — Postgres 17将变得更好。即将发布的版本在开发人员体验和性能方面都有所改进。 Postgres 17 中的 3 大特性 #01 具有 RETURNING 支持的 MERGE 命令 它可以帮助需要处理条件数据修改而无需处理多…

CMU 10423 Generative AI:HW1(理论部分)

备注&#xff1a;S24版GitHub上有某CMU学生分享了自己的全套理论编程作业&#xff0c;以下内容的整理结合了我自己的理解查阅、GPT4的解答、以及CMU学生的答案。 文章目录 0 作业概述1 RNN语言模型1.1 问题1&#xff1a;Elman&#xff08;即RNN&#xff09; 网络模型条件输出问…

IDEAJ真正修改maven(.m2)在Windows环境下缓存路径

IDEAJ真正修改maven(.m2)缓存路径的方法 下面这种方式虽然当前项目生效了&#xff0c;IntelliJ IDEA修改默认.m2和.gradle缓存路径-CSDN博客文章浏览阅读251次&#xff0c;点赞4次&#xff0c;收藏8次。文章浏览阅读1.3k次。1&#xff0c;File -ProjectStructure - Artifacts &…

RISC-V (十二)系统调用

系统模式&#xff1a;用户态和内核态 当前的代码都是实现在machine模式下。 系统模式的切换 epc寄存器的值存放的是ecall指本身的地址 。 用ecall指令 系统调用的执行流程 mret这条指令会利用status的mpp值恢复到之前的特权级别。 蓝色的线表示涉及到权限切换。 系统调用的传…

【VUE】pinia持久化存储

前言&#xff1a;状态持久化存储的意义在于它能够确保用户在与应用程序交互时&#xff0c;其操作状态、用户偏好、应用数据等关键信息在页面刷新、浏览器关闭或重新启动后依然得以保留&#xff0c;从而提供连贯、无缝的用户体验&#xff0c;避免因状态丢失导致的不便和重复操作…

绑定域名解析怎么做?

在当今数字化时代&#xff0c;拥有一个网站已经成为许多个人和企业展示自己、提供服务或进行商业活动的重要方式。而要让网站能够在互联网上被访问到&#xff0c;绑定域名解析是一个关键的步骤。 绑定域名解析究竟该怎么做呢&#xff1f; 一、了解域名解析的基本概念 域名解…

【重要】MThings V0.7.1更新要点

下载地址http://gulink.cn/download 01. [新增]逻辑控制功能。 “逻辑控制”作为一项全新的商用版功能&#xff0c;通过使用直观的可视化积木搭建方法&#xff0c;为系统级数据处理提供了高度的可定制性。它能够简化复杂的数据计算、控制算法设计和仿真验证流程&#xff0c;同…

探索未来住宿体验:酒店触摸开关的科技魅力

在快节奏的现代生活中&#xff0c;人们对于旅行住宿的期待已远不止于基本的休息与安眠&#xff0c;而是更加注重个性化、便捷化与智能化。随着科技的飞速发展&#xff0c;酒店行业也迎来了前所未有的变革&#xff0c;其中&#xff0c;触摸开关作为智能客房的标志性元素&#xf…

【网络安全】-xss跨站脚本攻击-pikachu

文章目录 前言 什么是xss跨站脚本攻击&#xff1f; 1&#xff0e;xss的分类&#xff1a; 1.1 反射型xss 1.2 存储型xss 1.3 Dom型xss&#xff1a; 2.同源策略&#xff1a; 2.1同源策略的定义 2.2同源策略的绕过 2.3 绕过同源策略的绕过 前言 什么是xss跨站脚本攻击&#xff1…

两个月冲刺软考——重点理解传值方式与传引用方式的区别

1.总线的分类(按功能划分) 数据总线负责传输实际的数据。 地址总线用于指定数据的来源或目的地的内存地址。 控制总线传输控制信号&#xff0c;如读写指令和其他操作指令。 2.传值方式与传引用方式 传值方式&#xff1a;形参取的是实参的值&#xff0c;形参的改变不会导致调…

开源数据集 FreiHAND rgb 三维手势建模 手部关键点 >> DataBall

开源数据集 FreiHAND rgb 三维手势建模 手部关键点 mano hand 混合现实 深度学习 人工智能 FreiHAND是一个用于评估和训练深度神经网络以从单色图像中估计手部姿态和形状的数据集&#xff0c;这是在我们的论文中提出的。其当前版本包含32560个独特的训练样本和3960个独特的评估…

【JavaScript】LeetCode:26-30

文章目录 26 矩阵置零27 螺旋矩阵28 旋转图像29 搜索二维矩阵Ⅱ30 相交链表 26 矩阵置零 2次双重for循环。第1次&#xff1a;将matrix[i][j]为0时的i、j分别存放于数组res_i、res_j&#xff0c;记录有哪些行、列应该置为0。第2次&#xff1a;将记录中的行、列置为0。 /**- par…

揭秘蛇形机器人的主动SLAM算法和障碍物避让策略

更多优质内容&#xff0c;请关注公众号&#xff1a;智驾机器人技术前线 1.论文信息 论文标题&#xff1a;An active SLAM with multi-sensor fusion for snake robots based on deep reinforcement learning 作者&#xff1a;Xin Liu, Shuhuan Wen, Yaohua Hu, Fei Han, Hong…

如何利用免费工具轻松设计出专业Logo?

Logo 作为品牌的象征和视觉核心&#xff0c;承载了品牌的价值和理念。无论是创业公司还是个人品牌&#xff0c;拥有一个独特的 Logo 都显得尤为重要。然而&#xff0c;设计一个专业的 Logo 通常需要高昂的设计费用&#xff0c;许多人因此望而却步。幸运的是&#xff0c;随着互联…

视频合并实用教程分享,教你6个合并视频方法,不可错过!

多个视频怎么合成一个视频&#xff1f;如何把2个视频合成一个&#xff1f;怎么把多个视频合成一个视频&#xff1f;您是否也曾产生过这样的疑问呢&#xff1f;在如今互联网高速发展的时代&#xff0c;各行各业都难免需要涉及到视频制作领域&#xff0c;如果您正在考虑视频如何有…