从网页截图到图文问答:基于 ColiVara 与 DeepSeek Janus-Pro 的多模态网站 RAG 实战
2026/9/10 22:10:19 网站建设 项目流程

从网页截图到图文问答:基于 ColiVara 与 DeepSeek Janus-Pro 的多模态网站 RAG 实战

【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub

本文以 Colivara-deepseek-website-RAG 项目为蓝本,系统讲解如何将任意网页抓取为截图、切片成 PDF、交给 ColiVara 完成多模态索引与检索,最终由 DeepSeek 的多模态模型 Janus-Pro 结合图片上下文生成回答的完整链路。读完本文,你将掌握一套「网页级多模态 RAG」的工程实现:既能理解环境搭建、API 配置与一键启动方式,也能从 app.py 与 rag_code.py 的源码级视角,看懂 Firecrawl、ColiVara、Janus-Pro 三者之间真实的调用关系与关键参数。

项目概览:四个组件构成的网页级多模态 RAG

传统 RAG 只处理纯文本,而网页内容天然包含版式、图表、截图等视觉信息。本项目把「网页」这一非结构化输入完整地转换为图像证据,再走「检索 → 多模态生成」的路线,形成一套无需清洗 HTML 文本即可直接问答的方案。

项目共使用四类工具,各司其职:

组件职责在本项目中的角色
DeepSeek Janus-Pro多模态大模型理解检索到的网页截图,结合图片内容生成答案
ColiVara文档理解与检索对 PDF(网页截图切片)建索引,按语义召回最相关图片
Firecrawl网页抓取将目标网页渲染为整页截图(fullPage screenshot)
StreamlitWeb 界面提供侧边栏配置、PDF 预览与流式对话聊天 UI

项目还提供了一份演示视频,可以直接查看从输入 URL 到对话出结果的真实运行效果。

环境准备与安装

安装 DeepSeek Janus

Janus-Pro 是 DeepSeek 推出的多模态模型,需要先从官方仓库克隆并做本地可编辑安装(注意:请将下述命令中的仓库地址替换为你实际可访问的 DeepSeek 官方 Janus 仓库地址):

git clone https://github.com/deepseek-ai/Janus.git pip install -e ./Janus

这一步至关重要:rag_code.py 顶部直接以包的形式导入了 Janus 仓库内的代码:

from Janus.janus.models import MultiModalityCausalLM, VLChatProcessor from Janus.janus.utils.io import load_pil_images

其中VLChatProcessor负责把「对话消息 + 图片」编码为模型输入,load_pil_images负责从对话结构中取出 PIL 图片列表。如果跳过 Janus 的安装步骤,运行时导入会直接失败。

安装 Python 依赖

官方要求 Python 3.11 或更高版本,然后执行:

pip install streamlit-pdf-viewer colivara-py streamlit fastembed flash-attn transformers

各依赖用途如下:

  • colivara-py:ColiVara 官方 Python SDK,用于创建集合、上传文档、执行检索;
  • streamlit:Web 界面框架;
  • streamlit-pdf-viewer:在 Streamlit 侧边栏内嵌渲染 PDF;
  • transformers:加载 Hugging Face 上的 Janus-Pro 权重(AutoModelForCausalLM.from_pretrained);
  • flash-attn:加速注意力计算,提升推理速度;
  • fastembed:ColiVara 生态常用的嵌入组件依赖。

需要补充说明的是,从 app.py 的实际导入语句看,运行时还会用到以下几个未出现在上述 pip 列表中的包,请一并确保已安装:

from pdf2image import convert_from_path # 依赖系统级 poppler 工具 from fpdf import FPDF # fpdf2,用于切片生成 PDF from firecrawl import FirecrawlApp # Firecrawl 官方 SDK from dotenv import load_dotenv # 读取 .env from PIL import Image # 图片裁剪 import requests # 下载截图

配置 API 密钥

本项目需要两个云服务密钥:ColiVara(文档理解与检索)和 Firecrawl(网页抓取)。在项目根目录创建.env文件并写入:

COLIVARA_API_KEY="<COLIVARA-API-KEY>" FIRECRAWL_API_KEY="<FIRECRAWL-API-KEY>"

app.py 通过load_dotenv()加载该文件,随后用os.getenv("COLIVARA_API_KEY")os.getenv("FIRECRAWL_API_KEY")读取并注入 FirecrawlApp 与 ColiVara 客户端。

启动项目

完成上述三步后,一行命令即可启动:

streamlit run app.py

启动后浏览器会打开 Streamlit 界面,侧边栏输入网页 URL、点击Start RAG,系统便会自动完成「抓取 → 切 PDF → 建索引」三步预处理,之后即可在底部输入框开始图文问答,并支持Clear ↺按钮重置会话。

源码解读:一次「网页 → 问答」的完整旅程

下面沿着 app.py 与 rag_code.py 的实际代码,拆解整条数据流。

第一步:Firecrawl 全页截图

点击 Start RAG 后,app.py 会实例化 FirecrawlApp 并抓取目标网页:

app = FirecrawlApp(api_key=os.getenv("FIRECRAWL_API_KEY")) scrape_result = app.scrape_url(url_input, params={'formats': ['screenshot@fullPage'], 'waitFor': 10000})

两个关键参数值得注意:

  • formats: ['screenshot@fullPage']:要求 Firecrawl 返回整页截图,而不是只截首屏,从而保证长网页的内容不被截断;
  • waitFor: 10000:等待 10 秒再截图,给前端 JavaScript 渲染(尤其是懒加载内容)留出时间,避免截到空白页。

第二步:截图切片生成 PDF

ColiVara 的文档理解面向 PDF,因此需要把一张超长网页截图转成 PDF。create_pdf_from_screenshot 的实现思路是垂直均分为 10 片

slice_height = math.ceil(height / 10) # 每片高度 = 总高 / 10 pdf = FPDF(unit='pt', format=[width, slice_height]) # 每页大小与切片一致 pdf.set_auto_page_break(auto=False) # 关闭自动分页 for i in range(10): top = i * slice_height bottom = min((i + 1) * slice_height, height) slice_img = image.crop((0, top, width, bottom)) # 逐片裁剪 pdf.add_page() pdf.image(temp_filename, x=0, y=0, w=width, h=bottom-top)

这里的工程细节是:每片对应 PDF 的一页,页尺寸严格贴合切片的长宽比;同时关闭auto_page_break,避免内容被系统自动分页再次切割而失真。最后输出screenshot_slices.pdf供后续索引。

第三步:ColiVara 集合创建与文档索引

得到 PDF 后,app.py 初始化 ColiVara 客户端并完成两级写入:

rag_client = ColiVara(api_key=os.getenv("COLIVARA_API_KEY")) new_collection = rag_client.create_collection( name=st.session_state.collection_name, metadata={"description": "Webpage screenshots"} ) document = rag_client.upsert_document( collection_name=st.session_state.collection_name, name="webpage_document", document_path=st.session_state.pdf_path )
  • create_collection:创建专属集合,集合名由uuid生成("webpage_collection" + str(session_id),见 app.py),避免多次会话互相污染;
  • upsert_document:上传 PDF,ColiVara 在服务端完成版面分析、文本与视觉信息提取,建立多模态索引。

值得强调的是,本项目把会话级缓存也考虑了进去:st.session_state.file_cache"{session_id}-webpage.pdf"为 key 缓存已建好的 query_engine,同一会话重复点击不会重复建索引(app.py)。

第四步:Retriever 检索与图片召回

检索逻辑封装在 rag_code.py 的Retriever类中:

class Retriever: def search(self, query): results = self.rag_client.search( query=query, collection_name=self.collection_name, top_k=3 ) related_image = results.results[0].img_base64 # 取最相关的一张 image_data = base64.b64decode(related_image) image = Image.open(io.BytesIO(image_data)) image.save("tempfile.jpeg") return "tempfile.jpeg"

关键点:

  • top_k=3:召回 3 个候选,但最终只取results[0]最相关的一张作为上下文图片;
  • 召回结果直接以img_base64形式返回,无需再次下载,解码后落盘为tempfile.jpeg供多模态模型读取;
  • 这说明 ColiVara 检索返回的不只是「文本片段」,而是图片本身——这是本项目区别于文本 RAG 的核心差异。

第五步:Janus-Pro 多模态生成

生成侧由 rag_code.py 的RAG类完成。模型默认使用deepseek-ai/Janus-Pro-1B,初始化时加载权重并转为 bfloat16 精度:

class RAG: def __init__(self, retriever, llm_name="deepseek-ai/Janus-Pro-1B"): self._setup_llm() def _setup_llm(self): self.vl_chat_processor = VLChatProcessor.from_pretrained( self.llm_name, cache_dir="./Janus/hf_cache") self.tokenizer = self.vl_chat_processor.tokenizer self.vl_gpt = AutoModelForCausalLM.from_pretrained( self.llm_name, trust_remote_code=True, cache_dir="./Janus/hf_cache").to(torch.bfloat16).eval()

query()方法把检索到的图片与用户问题拼装为 Janus 的对话格式:

qa_prompt_tmpl_str = f"""The user has asked the following question: Query: {query} Some images are available to you for this question. You have to understand these images thoroughly and extract all relevant information that will help you answer the query.""" conversation = [ {"role": "User", "content": f"<image_placeholder> \n {qa_prompt_tmpl_str}", "images": [image_context]}, {"role": "Assistant", "content": ""}, ]

随后经过load_pil_imagesvl_chat_processor(...)编码 →prepare_inputs_embeds组装图像与文本 embedding → 语言模型生成:

outputs = self.vl_gpt.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, pad_token_id=self.tokenizer.eos_token_id, bos_token_id=self.tokenizer.bos_token_id, eos_token_id=self.tokenizer.eos_token_id, max_new_tokens=512, do_sample=False, use_cache=True, )

这里隐含了几个可调参数:

  • max_new_tokens=512:答案最长生成 512 个 token;
  • do_sample=False:使用贪心解码,输出确定性更强;
  • use_cache=True:启用 KV Cache 加速;
  • prompt 模板明确要求模型先彻底理解图片再回答,将“读图”这一指令固化进系统提示。

最后,app.py 在 Streamlit 端以流式方式逐 chunk 渲染回答(带光标效果),形成完整的对话体验。

关键参数速查表

参数位置默认值作用与调优建议
waitForapp.py10000ms等待页面 JS 渲染;动态站点可调大,静态站可调小以提速
formatsapp.pyscreenshot@fullPage整页截图,保证长页内容完整
切片数量app.py10 片切片越多单页越高清,但 PDF 体积与索引耗时同步上升
top_krag_code.py3召回候选数;最终只取 top-1 图片,可修改为多图拼接上下文
llm_namerag_code.pydeepseek-ai/Janus-Pro-1B可换成更大规格的 Janus-Pro 权重,按显存权衡
精度rag_code.pybfloat16兼顾显存与精度;显存充足时可试 fp16 或原始精度
max_new_tokensrag_code.py512需要长答案时可调大
cache_dirrag_code.py./Janus/hf_cache模型权重缓存目录,注意预留磁盘空间

使用建议与限制

  • 硬件要求:Janus-Pro-1B 需在本地以 bfloat16 加载并完成图片编码推理,建议具备支持 bf16 的 GPU;若仅 CPU 运行,生成速度会明显下降。
  • 网络依赖:Firecrawl 抓取与 ColiVara 索引均为云端服务,需要网络连通与有效 API 密钥;本地模型推理则完全离线。
  • 超长网页:截图切片固定为 10 片,超长网页单页内容密度更高,若视觉细节被压缩,可考虑增加切片数。
  • 会话隔离:集合名绑定会话 UUID,并配合file_cache缓存避免重复索引,多开会话互不干扰。
  • 只读仓库提醒:本仓库为只读展示用途,文章所述安装、运行与配置均在本地环境完成,无需修改仓库内容。

延伸阅读

  • 项目说明:Colivara-deepseek-website-RAG/README.md
  • Web 界面与主流程:Colivara-deepseek-website-RAG/app.py
  • 检索与多模态生成核心:Colivara-deepseek-website-RAG/rag_code.py
  • 演示视频:Colivara-deepseek-website-RAG/video-demo.mp4

【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询