内容参考于:图灵AI大模型全栈

我们用的模型都是大语言模型(LLM),但是我肯定会要加载一些图片数据给到大模型的

下方是一个带图片的jinja2模版,这个{{ loop.index }}是可以获取到当前第几次循环,loop是jinja2内置的变量,index是当前第几次循环的数字,然后{{ image_path | image }}中的image_path是图片的目录,image是过滤器,这个|竖杠是管道,连起来就是image_path这个路径会传递给image这个方法,这个image方法是固定的,传递图片的方式有流式传输、二进制传输、base64传输,给大模型的是把图片数据转成base64编码,然后大模型会自己解析

{% chat role="system" %}
    你是一个专业的图像理解专家。请仔细观察图片内容,并回答用户的问题。
{% endchat %}

{% chat role="user" %}
    {% for image_path in image_list %}
        图片 {{ loop.index }}:
        {{ image_path | image }}
    {% endfor %}


    用户问题:{{ query_str }}
    请用中文回答,并分别描述每张图片的关键内容,最后总结它们的共同点。

{% endchat %}

它实现图片二进制转base64的方式,如下,它是通过调用ImageBlock里的方法来实现的

from llama_index.core.base.llms.types import ImageBlock

ImageBlock的说明可以在LLamaIndex官网里找到

官网地址:https://developers.llamaindex.ai/python/framework-api-reference/llms/

通过下图红框位置搜索ImageBlock,就可以找到它的说明了,如果还是看不懂,那就去问ai,可以把下图的链接给大模型,然后让大模型给你用小白的方式详细说明

如下图红框,可以看到image_to_base64,也就是图片转base64

上方{{ image_path | image }},就是把一个图片路径给到方法,然后方法转成base64,如下图红框图片转成base64然后拼接到提示词中

注意要用format_messages方法才能看到,如下图format是看不到base64的

图片转成了base64可以给大模型了

这里有一个问题,如下图访问的是千问的qwen3.7-plus模型,它回答的是无法直接查看图片,这个原因是并不是所有模型都支持多模态,要找支持多模态的模型才可以

如下图红框,qwen3.7-plus模型的说明,但看着它也是支持图片的,为什么不行?

换一个模型,如下图红框点击全模态,找全模态的模型,下图蓝框的模型可以确定是肯定支持图片解析的

如下图红框看它的介绍,它支持图片理解和交互

但是如下图,它还是不行,还是有问题

LLamaIndex中各个厂商会有单独的SDK,我们使用的是DashScope来调用的大模型,DashScope中并没有实现转换,这就需要我们自己写,国外的模型LLamaIndex是可以无法衔接的,我们国内的模型LLamaIndex现在还兼容的不好,如下图我们使用OpenAILike的方式就可以了,但前提也是要模型支持图片分析

所以要注意模型是否支持图片解析、厂商的SDK是否支持图片转换,如果SDK不支持就需要使用OpenAILike的方式

代码

# 从 LlamaIndex 核心提示词模块导入富提示词模板类
# 核心能力:支持 Jinja2 完整语法、结构化聊天消息、多模态内容过滤器,是构建复杂多模态提示词的标准组件
from llama_index.core.prompts import RichPromptTemplate
# 导入图片内容块类
# 类全称:ImageBlock
# 核心作用:LlamaIndex 多模态体系的标准图片数据封装类,用于在聊天消息中承载图片内容
# 设计原因:多模态消息的内容是「文本+图片」混合结构,不能直接用字符串表示图片路径
#           必须用 ImageBlock 对象封装,大模型适配层才能识别这是图片、而非普通文本
# 生成方式:既可手动实例化,也可通过模板中的 |image 过滤器自动从路径生成
from llama_index.core.base.llms.types import ImageBlock


# ====================== 定义多模态提示词模板字符串 ======================
# 模板语法:Jinja2 标准语法 + LlamaIndex 扩展的 chat 标签 + image 多模态过滤器
# 整体结构:系统人设 → 循环插入多张图片 → 用户问题与回答要求
# 核心亮点:通过循环 + image 过滤器,实现批量图片自动注入,支持任意数量的图片输入
multi_modal_template_str = """
{% chat role="system" %}
    你是一个专业的图像理解专家。请仔细观察图片内容,并回答用户的问题。
{% endchat %}

{% chat role="user" %}
    {# 循环遍历图片路径列表,批量生成图片内容 #}
    {# loop.index 是 Jinja2 内置循环变量,代表当前循环的序号(从1开始),用于标注第几张图 #}
    {% for image_path in image_list %}
        图片 {{ loop.index }}:
        {# 核心语法:| image 是 LlamaIndex 内置的多模态过滤器 #}
        {# 作用:将图片路径字符串自动转换为 ImageBlock 对象,让模型识别为图片输入,而非普通文本 #}
        {# 支持输入:本地文件路径、网络图片URL,底层会自动读取/加载图片数据 #}
        {{ image_path | image }}
    {% endfor %}

    用户问题:{{ query_str }}
    请用中文回答,并分别描述每张图片的关键内容,最后总结它们的共同点。

{% endchat %}

"""

# ====================== 实例化多模态富提示词模板 ======================
# 入参:模板字符串,内部包含 image 过滤器与循环逻辑
# 渲染后输出:多模态结构化聊天消息列表,消息内容为「文本块+图片块」的混合结构
multi_modal_template = RichPromptTemplate(multi_modal_template_str)


# ==================== 渲染模板生成结构化多模态消息 ====================
# 调用 format_messages 方法,传入图片路径列表与用户问题
# 入参说明:
#   image_list:列表类型,存放所有图片的路径(本地路径或URL均可)
#   query_str:字符串类型,用户的提问内容
# 执行流程:
#   1. 遍历 image_list 中的每个路径
#   2. 通过 image 过滤器将每个路径转为 ImageBlock 对象
#   3. 与文本内容拼接,生成完整的用户多模态消息
#   4. 最终返回 List[ChatMessage] 结构化消息列表
# 注意:渲染后的用户消息 content 不是纯字符串,而是「文本段 + ImageBlock」的混合列表
messages = multi_modal_template.format_messages(
    image_list=[
        "./data_file/img.png",
        "./data_file/img_1.png"
    ],

    query_str="这些图片里有什么共同点?"

)
# 打印消息结构可查看 ImageBlock 对象,调试时打开
# print(messages)

# ==================== OpenAILike 通用适配(当前启用) ====================
# 导入操作系统模块,用于读取环境变量
import os
# 导入 OpenAI 兼容格式的通用大模型适配类
# 类全称:OpenAILike
# 核心作用:通用适配所有兼容 OpenAI 接口协议的大模型服务
# 适用场景:只要模型服务提供了兼容 OpenAI 的 API 格式,都可以用这个类对接
#           比如通义千问、DeepSeek、本地 Ollama、各类私有化部署的模型服务
# 优势:通用性强,切换兼容接口的模型时,只改地址和模型名即可,代码结构不变
from llama_index.llms.openai_like import OpenAILike
# 导入环境变量加载工具
from dotenv import load_dotenv

# 加载 .env 配置文件到系统环境变量
load_dotenv()

# 初始化 OpenAILike 大模型实例,对接通义千问服务
llm = OpenAILike(
    # 指定要调用的模型名称,必须和服务端支持的模型名完全一致
    # 注意:处理图片必须用多模态模型(如 qwen-omni 系列),纯文本模型会报错
    model="qwen3.7-plus",
    # 从环境变量读取 API 密钥,对应 .env 中 DASHSCOPE_API_KEY
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    # 从环境变量读取接口基础地址
    # 必要性:非官方 OpenAI 服务必须手动指定接口地址,否则会默认请求 OpenAI 官方地址
    api_base=os.getenv("DASHSCOPE_BASE_URL"),
    # 标记当前模型为聊天对话模型
    # 作用:告知 LlamaIndex 该模型支持多轮聊天消息格式,内部按聊天接口协议发起请求
    # 取值:True=聊天模型(主流大模型均为此类),False=纯补全模型(老式模型)
    is_chat_model=True,   # 是否是 聊天模型
)

# 调用聊天接口,传入多模态结构化消息列表,获取模型回复
# 入参:List[ChatMessage],包含文本与图片的混合多模态消息
# 底层逻辑:OpenAILike 会自动识别消息中的 ImageBlock,按 OpenAI 多模态消息格式组装请求
# 返回值:ChatResponse 对象,包含模型的文本回复内容
res = llm.chat(messages)
# 打印模型回复结果,默认输出纯文本回答内容
print(res)

上方的提示词都是我们自己写的,在LLamaIndex中有写好的默认提示词

下图红框里都是LLamaIndex写好的提示词,

注意LLamaIndex默认提示词都是英文的,用英文写提示词是比较好的

中文翻译

这些默认的提示词lamaindex自己会用,我们不需要使用,只需要知道llamaindex有默认提示这回事就行

代码

# 从 LlamaIndex 核心默认提示词模块导入 4 个官方预置的标准提示词模板
# 模块定位:框架内置的官方默认提示词仓库,是各类索引、响应模式的默认配置
# 设计逻辑:提供一套经过通用场景优化的默认提示词,无需手动编写即可直接开箱使用
#           也可以基于默认模板修改,或完全替换为自定义业务模板
# 四个模板分别对应不同的检索响应模式与业务场景:
#   1. DEFAULT_TEXT_QA_PROMPT:标准问答模板,Stuff 响应模式默认使用
#   2. DEFAULT_REFINE_PROMPT:迭代优化模板,Refine 响应模式默认使用
#   3. DEFAULT_SUMMARY_PROMPT:单段文本总结模板,摘要索引默认使用
#   4. DEFAULT_TREE_SUMMARIZE_PROMPT:树状合并总结模板,Tree Summarize 响应模式默认使用
from llama_index.core.prompts.default_prompts import (
    DEFAULT_TEXT_QA_PROMPT,
    DEFAULT_REFINE_PROMPT,
    DEFAULT_SUMMARY_PROMPT,
    DEFAULT_TREE_SUMMARIZE_PROMPT,
)

print("=== 标准问答模板  ===")
# .template 属性:获取提示词模板对象的原始字符串本体
# 模板作用:Stuff 响应模式的核心问答模板,是查询引擎最基础、最常用的默认模板
# 工作机制:将检索召回的所有文档上下文一次性全部填入提示词,让大模型基于完整上下文一次性生成回答
# 特点:逻辑简单、回答连贯性好,适合上下文窗口充足、检索结果数量少的场景
# 内置固定占位符(框架自动填充,自定义时必须保留):
#   - {context_str}:检索召回的全部上下文文档内容
#   - {query_str}:用户的原始查询问题
print(DEFAULT_TEXT_QA_PROMPT.template)

print("\n=== 迭代优化答案模板 ===")
# 模板作用:Refine(精炼)响应模式的核心提示词
# 工作机制:逐个串行处理检索到的文档块,而非一次性全部塞入上下文
#   1. 先用第一个文档块生成初始回答
#   2. 依次将后续每个新文档块 + 上一轮的已有回答一起传给大模型
#   3. 让大模型基于新的上下文补充、修正、优化已有答案,逐轮迭代得到最终结果
# 适用场景:检索结果多、模型上下文窗口不足以一次性放下所有内容的场景
# 内置固定占位符:
#   - {existing_answer}:上一轮迭代生成的当前回答
#   - {context_msg}:当前新拿到的单段上下文文档内容
#   - {query_str}:用户的原始查询问题
print(DEFAULT_REFINE_PROMPT.template)


print("\n=== 总结模板  ===")
# 模板作用:单段文本总结的默认提示词,主要供 SummaryIndex(摘要索引)使用
# 工作机制:对单段独立文本进行概括提炼,生成对应摘要
# 适用场景:文档入库时生成片段摘要、长文本分段总结等纯总结场景
# 内置固定占位符:
#   - {context_str}:待总结的原始文本内容
print(DEFAULT_SUMMARY_PROMPT.template)

print("\n=== 树状总结模板  ===")
# 模板作用:Tree Summarize(树状总结)响应模式的核心提示词
# 工作机制:分层递归式合并总结,自底向上生成最终答案
#   1. 先将所有检索到的文档块分批,每批生成一个小总结
#   2. 再将多个小总结继续分批合并,生成更大层级的总结
#   3. 层层递归合并,直到最终生成一个完整的总回答
# 适用场景:长文档、大量检索结果的场景,相比 Refine 合并效率更高、更节省上下文
# 内置固定占位符:
#   - {context_str}:当前批次待合并的多段总结/上下文内容
#   - {query_str}:用户的原始查询问题
print(DEFAULT_TREE_SUMMARIZE_PROMPT.template)


img

更多推荐