用机器人实现视觉驱动的闲聊:一次 GPT-5 冒险之旅 🤖👀
嘿!👋 想象一下,在这样一个世界里,你最喜欢的聊天机器人或社交机器人不仅能回应基于文本的输入,还能实时地对对话进行视觉观察。很令人兴奋,对吧?嗯,我们借助 GPT-5 实现了这一点,我将解释你该如何做到!但首先,这里有一个展示最终效果的视频:
在这场简短的冒险中,我们将探索如何使用大型语言模型和来自网络摄像头的实时视觉输入,将它们混合在一个有效的提示(prompt)中,并对其进行总结以使其运行得更快、更便宜。我们将创造一种真正具有情境感知能力的对话体验。
🖼️ GPT-5 与图像
首先,你需要一个 OpenAI 账户:https://platform.openai.com/
并获取你的 API 密钥。我知道……我也希望能有一个开源的替代方案,但我们尝试了 IDEFICS 和 LLaVA,效果并不理想。项目目前只能用OpenAI的多模态模型如:GPT-4o或者GPT-5等
项目使用
首先在github上下载代码包,项目地址下载包 https://github.com/giubots/vision-enabled-dialogue/releases/tag/v0.2.0
这里我是用的Visual 工具
打开的项目文件夹
- 打开项目文件,只需配置一下文件中的
test.py
文件 - OpenAI获取API Key比较麻烦,这里代替OpenAI获取Kei的方案是用的:
uiuiAPI.com
,如果你有OpenAI API Key那就直接配置。
client = OpenAI(
api_key="sk-JKzxxxxxxxxxxxxxxxxxxxxxxxP", #输入在uiuiAPI获取的API kEY
base_url="https://sg.uiuiapi.com/v1"
)
def query(prompt) -> str:
params = {
"model": "gpt-5",
"messages": prompt,
"max_tokens": 200,
}
- 配置好了以后运行
test.py
文件既可以使用项目。
你也可以使用 Python:运行 pip install openai opencv-python
来获取我们需要的库。以下是几行让你开始使用 GPT-5 视觉功能的代码。
from openai import OpenAI
client = OpenAI(api_key="YOUR-KEY-HERE")
def query(prompt) -> str:
params = {
"model": "gpt-4-vision-preview",
"messages": prompt,
"max_tokens": 200,
}
result = client.chat.completions.create(**params)
return result.choices[0].message.content
📜 提示 (The Prompt)
你想发送给 GPT-5 的提示结构有些复杂,但这是迄今为止一直可靠有效的方法。基本上,它是一个消息数组。你可能已经知道,GPT-5 支持不同类型的消息。这里有一个快速概述。
系统消息 (System Message) 指示模型应该如何表现。它的结构是这样的:
def format_system(content):
return {"role": "system", "content": content}
要添加来自用户的文本,或 base64 格式的图像(下面会详细说明如何加载图像),你会想用类似这样的代码:
def format_text(content):
return {
"role": "user",
"content": [{"type": "text", "text": content}],
}
def format_image(content):
return {
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"url": "data:image/jpeg;base64," + content},
}
],
}
最后,当你想将 GPT-5 的回复也整合到提示中时,可以这样做:
def format_assistant(content):
return {
"role": "assistant",
"content": [{"type": "text", "text": content}],
}
现在,要把所有的文本和图像组合起来,你有不同的选择。保持元素的正确顺序很重要,最简单的方法就是用一个大列表。这个项目的代码仓库 (repo) 包含一个 Conversation
类来做这件事(以及其他一些事,稍后详述)。
📷 拍照
在这个例子中,与系统对话时,我们将在用户回合开始时通过网络摄像头拍照,从而将图像整合到我们的提示中。在代码仓库 (repo) 中,你会找到如何按固定间隔在对话中连续截图、加载视频,或使用 Furhat 机器人作为视频源的方法。在这里,我们只做打开网络摄像头、拍张照、将其编码为字符串、关闭网络摄像头,然后返回该字符串。
def get_image():
vid = cv2.VideoCapture(0)
_, frame = vid.read()
_, buffer = cv2.imencode(".jpg", frame)
string64 = base64.b64encode(buffer).decode("utf-8")
vid.release()
return string64
🪄 系统提示 (The System Prompt)
太棒了!我们已经准备好了所有的组件……除了一个:系统提示。我们必须告诉 GPT-5 如何解释我们发送的图像,以及如何回应。这需要耐心和时间,多次试验和一点提示工程的魔法。我们直接来看那个给了我们最满意结果的提示吧。
system = (
"You are impersonating a friendly kid. "
"In this conversation, what you see is represented by the images. "
"For example, the images will show you the environment you are in and possibly the person you are talking to. "
"Try to start the conversation by saying something about the person you are talking to if there is one, based on accessories, clothes, etc. "
"If there is no person, try to say something about the environment, but do not describe the environment! "
"Have a nice conversation and try to be curious! "
"It is important that you keep your answers short and to the point. "
"DO NOT INCLUDE EMOTICONS OR SMILEYS IN YOUR ANSWERS. "
)
如你所见,我们要求模型扮演一个友好的孩子,这听起来可能有点奇怪,但这能去除 GPT-5 输出中大部分烦人的警告和免责声明。然后我们告诉模型,图像就是它所“看到”的,如果能通过观察对方来开启对话会很不错。GPT-5 会很努力地描述它看到的一切,但我们不希望这样;我们也不希望模型喋喋不休,所以我们告诉它不要这样做。最后,我们召唤出的这个友好孩子角色特别喜欢在回答中加表情符号,这对我们没用,所以我们用大写字母要求它不要包含这些,以使其格外清晰响亮。
🧩 整合一切
让我们把所有东西都粘合在一起,好吗?
import base64
import cv2
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY")
def query(prompt) -> str:
params = {
"model": "gpt-4-vision-preview",
"messages": prompt,
"max_tokens": 200,
}
result = client.chat.completions.create(**params)
return result.choices[0].message.content
def format_system(content):
return {"role": "system", "content": content}
def format_text(content):
return {
"role": "user",
"content": [{"type": "text", "text": content}],
}
def format_image(content):
return {
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"url": "data:image/jpeg;base64," + content},
}
],
}
def format_assistant(content):
return {
"role": "assistant",
"content": [{"type": "text", "text": content}],
}
def get_image():
vid = cv2.VideoCapture(0)
_, frame = vid.read()
_, buffer = cv2.imencode(".jpg", frame)
string64 = base64.b64encode(buffer).decode("utf-8")
vid.release()
return string64
system = (
"You are impersonating a friendly kid. "
"In this conversation, what you see is represented by the images. "
"For example, the images will show you the environment you are in and possibly the person you are talking to. "
"Try to start the conversation by saying something about the person you are talking to if there is one, based on accessories, clothes, etc. "
"If there is no person, try to say something about the environment, but do not describe the environment! "
"Have a nice conversation and try to be curious! "
"It is important that you keep your answers short and to the point. "
"DO NOT INCLUDE EMOTICONS OR SMILEYS IN YOUR ANSWERS. "
)
conversation = [format_system(system)]
while True:
image = get_image()
conversation.append(format_image(image))
text = input("You: ")
conversation.append(format_text(text))
response = query(conversation)
conversation.append(format_assistant(response))
print("Assistant:", response)
铛铛!一个不错的无限循环就搞定了!把它保存为一个好听的名字,比如 main.py
,然后用 python main.py
运行它。祈祷一切顺利,如果一切正常,你就可以从网络摄像头拍照,并就此展开愉快的聊天了。很棒,不是吗?去探索一下当你关掉灯或者在最奇怪的场景下 GPT-4 会如何回答吧,祝你玩得开心。请务必遵守 OpenAI 的使用条款,并留意账单,因为发送大量高分辨率图片可能会很昂贵。
如前所述,在代码仓库 (repo) 中,你可以找到一个可以从网络摄像头、视频或 Furhat 机器人连续捕获画面的版本。
✂️ 缩减提示大小
你很快会发现你的提示会变得过大,导致计算速度变慢,价格增加。这可不好。为了解决这个问题,我们想到了普通对话提示中常用的方法:让大型语言模型(LLM)来总结对话的第一部分!
但我们不能把图像和对话一起总结,一张图片胜过千言万语,我们的对话实际上会消失在图像描述的海洋中。还记得我告诉过你代码仓库 (repo) 中的 Conversation
类也做其他事情吗?嗯,当提示变得太长时,这个类会请求 GPT-5 总结其中的一些图像。它会扫描整个消息列表,找到前 n
张连续的图像,并用一个摘要来替换它们。如果你感兴趣,这篇论文包含更多相关细节。
这是我们在 Conversation
类中使用的代码。
🔭 项目代码分析
我希望这次将 GPT-5 与实时视觉输入相结合的旅程能激发你的好奇心!可能性就像你的想象力一样广阔。现在,你已经掌握了整合大型语言模型和实时视觉输入的知识,可以创造出真正互动和具有情境感知能力的对话体验。那么,你还在等什么呢?深入代码,探索语言和视觉的迷人交集,让你的创造力尽情驰骋吧。聊天机器人和社交机器人的未来不仅仅是基于文本的——它是文字和图像的动态融合,而你正处在这场变革的最前沿。我们将继续努力改进这种方法,探索新的、令人兴奋的方式来让对话代理变得更好。敬请期待!
项目名称:Vision-Enabled Dialogue(视觉增强对话)
功能概述:
- 将视频帧/摄像头画面作为视觉上下文与对话文本一起发送到 LLM(默认 gpt-4o),实现“看着环境进行聊天”的交互。
- 连续帧会被周期性总结成一句话,减少上下文长度与费用。
- 支持两种运行模式:
- 独立应用(本机摄像头或视频文件)main.py
- Furhat 机器人集成 main_furhat.py(通过 ZeroMQ 接收视频流,Remote API 进行语音交互)
一、环境与依赖
- Python 版本:建议 3.10+(requirements 中的包对 3.8–3.11 普遍兼容)
- 依赖安装:
- 独立应用:pip install -r requirements.txt(opencv-python、openai==1.2.4 等)
- Furhat 集成:pip install -r requirements-furhat.txt(额外包含 furhat-remote-api、pyzmq 等)
- OpenAI API Key:通过环境变量 OPENAI_API_KEY 读取
- Windows PowerShell:
$env:OPENAI_API_KEY=‘YOUR-KEY-HERE’; python .\main.py - Windows CMD:
set OPENAI_API_KEY=YOUR-KEY-HERE && python main.py - Linux/macOS:
OPENAI_API_KEY=‘YOUR-KEY-HERE’ python main.py
- Windows PowerShell:
二、独立应用用法(vision/main.py)
- 启动(默认使用摄像头):
- PowerShell:
$env:OPENAI_API_KEY=‘YOUR-KEY-HERE’; python .\main.py - CMD:
set OPENAI_API_KEY=YOUR-KEY-HERE && python main.py - Linux:
OPENAI_API_KEY=‘YOUR-KEY-HERE’ python main.py
- PowerShell:
- 使用视频文件作为输入(逐帧发送,默认每5秒取一帧并显示窗口,可按 ESC 退出):
python main.py --video=./path/to/video.mp4 - 使用脚本文件作为输入(脚本为 JSON 字符串数组;每条需按 Enter 继续):
python main.py --script=./script.json - 交互说明:
- 程序启动后开一条视频线程采集画面(摄像头或视频),主线程进行文本对话:
- 终端输入“You: …”后回车,模型返回“AI: …”
- OpenCV 会弹出窗口显示画面:
- 摄像头窗口名“Webcam”,视频窗口名“Video”
- 窗口获得焦点时按 ESC 退出视频采集线程
- 退出对话后,程序会通知视频线程停止并回收
- 程序启动后开一条视频线程采集画面(摄像头或视频),主线程进行文本对话:
- 可选的 script.json 示例:
[
“你好!你现在看到什么?”,
“这附近有什么有趣的东西?”,
“你觉得我现在的穿搭如何?”
]
三、Furhat 集成用法(vision/main_furhat.py)
- 额外准备:
- 安装依赖:pip install -r requirements-furhat.txt
- 启动 Furhat 远程 API 服务(官方文档)
- 启用外部视频流(官方文档)
- 将 main_furhat.py 中 FURHAT_IP 设置成机器人 IP
- 运行:
- PowerShell:
$env:OPENAI_API_KEY=‘YOUR-KEY-HERE’; python .\main_furhat.py - CMD:
set OPENAI_API_KEY=YOUR-KEY-HERE && python main_furhat.py - Linux:
OPENAI_API_KEY=‘YOUR-KEY-HERE’ python main_furhat.py
- PowerShell:
- 工作流程:
- 视频:通过 ZeroMQ SUB 连接 tcp://FURHAT_IP:3000,默认每 50 帧抽一帧送入对话(detection_period=50)
- 语音:Furhat 监听用户语音 -> 将文本传给 LLM -> Furhat 口播回复并带有简单注视/动作
四、内部机制与可配置项
- 模型与 OpenAI 接入(vision/vision_enabled_dialogue/llm.py)
- 默认类 GPT4 使用 OpenAI Python SDK v1(openai==1.2.4)
- 模型默认 “gpt-4o”(支持 vision),如需切换,修改 llm.py 中 params[“model”]
- 返回长度 max_tokens=200,可根据需要调整
- 消息格式(vision/vision_enabled_dialogue/messages.py)
- 帧:image_url 作为 user role 内容传给聊天补全接口
- 文本:user/assistant/system 各自封装
- 帧摘要:FSummaryMessage,会把摘要作为“Image summary: …”的文本注入上下文
- 对话与帧摘要策略(vision/vision_enabled_dialogue/conversation.py)
- Conversation(GPT4(), fr_buff_size=4, fr_recap=3)
- 每收到 fr_buff_size 张帧后触发摘要
- 最多回顾 fr_recap 张帧,并在遇到下一条 user 消息或达到回顾上限时进行总结
- 摘要指令要求“仅一句话”,用于压缩视觉上下文,降低持续费用
- 主系统提示词:扮演友好的小孩,开场先结合视觉谈论人/环境;回答简短且不包含表情符号
- Conversation(GPT4(), fr_buff_size=4, fr_recap=3)
- 采样周期与显示(vision/main.py)
- 摄像头/视频发送周期 period=5 秒(函数 send_cam/send_vid 内硬编码)
- OpenCV 显示窗口,ESC 退出;窗口关闭时会释放资源
- 如需更高频率/更低成本,可在 main.py 中修改 period(如改为 2 或 10)
五、常见问题与排错
- OpenAI 相关
- 报错 “Invalid API key” 或 401:确认 OPENAI_API_KEY 设置正确(PowerShell vs CMD 语法不同)
- 网络超时/429:可能是网络或速率限制,降低帧发送频率(period),或稍后重试
- 模型不支持图片:确保使用 gpt-4o 或其它支持图像输入的型号
- OpenCV / 摄像头
- 窗口不响应 ESC:点击激活窗口焦点后再按 ESC
- 摄像头打不开或黑屏:更换设备索引(cv2.VideoCapture(1/2)),检查驱动与权限
- 使用视频文件失败:确认路径、编码和权限;尝试常见格式(mp4)
- Furhat/网络
- 无法接收视频:确认已启用外部视频流;ZeroMQ 端口 3000 未被防火墙拦截;FURHAT_IP 正确
- 无法语音交互:确认 Remote API 已启动、网络可达
- 依赖安装
- Windows 若遇到编译相关错误:opencv-python 提供预编译轮子,一般无需编译;如失败请升级 pip 或更换 Python 小版本
- 成本与性能
- 每次发送图像都会计费;默认每 5 秒一帧 + 摘要策略,有助于控制成本
- 可通过增大 period、减小 fr_buff_size、减小 fr_recap 来进一步降本
六、快速开始(建议命令)
- 创建与激活虚拟环境(可选):
- Windows:
python -m venv .venv
..venv\Scripts\activate - Linux/macOS:
python3 -m venv .venv
source .venv/bin/activate
- Windows:
- 安装依赖并运行摄像头版本(Windows PowerShell):
pip install -r requirements.txt
$env:OPENAI_API_KEY=‘YOUR-KEY-HERE’; python .\main.py - 运行视频文件版本(Windows CMD):
pip install -r requirements.txt
set OPENAI_API_KEY=YOUR-KEY-HERE && python main.py --video=.\video.mp4 - 运行脚本驱动版本(Linux):
pip install -r requirements.txt
OPENAI_API_KEY=‘YOUR-KEY-HERE’ python main.py --script=./script.json