视觉定位¶
步骤 | 技术 | 执行 |
---|---|---|
嵌入 | Hugging Face / Sentence Transformers | 💻 本地 |
向量存储 | Milvus | 💻 本地 |
生成式 AI | Hugging Face Inference API | 🌐 远程 |
此示例展示了 Docling 的视觉定位能力,该能力可与任何 Agentic AI / RAG 框架结合使用。
在本例中,我们利用 LangChain Docling 集成、Milvus 向量存储以及 sentence-transformers 嵌入来演示这些能力。
设置¶
- 👉 为了获得最佳转换速度,请尽可能使用 GPU 加速;例如,如果在 Colab 上运行,请使用支持 GPU 的运行时。
- Notebook 使用 HuggingFace 的 Inference API;为了增加 LLM 配额,可以通过环境变量
HF_TOKEN
提供 token。 - 可以按如下所示安装所需的依赖项(
--no-warn-conflicts
用于 Colab 预填充的 Python 环境;对于更严格的使用,可以随意删除)
In [1]
已复制!
%pip install -q --progress-bar off --no-warn-conflicts langchain-docling langchain-core langchain-huggingface langchain_milvus langchain matplotlib python-dotenv
%pip install -q --progress-bar off --no-warn-conflicts langchain-docling langchain-core langchain-huggingface langchain_milvus langchain matplotlib python-dotenv
Note: you may need to restart the kernel to use updated packages.
In [2]
已复制!
import os
from pathlib import Path
from tempfile import mkdtemp
from dotenv import load_dotenv
from langchain_core.prompts import PromptTemplate
from langchain_docling.loader import ExportType
def _get_env_from_colab_or_os(key):
try:
from google.colab import userdata
try:
return userdata.get(key)
except userdata.SecretNotFoundError:
pass
except ImportError:
pass
return os.getenv(key)
load_dotenv()
# https://github.com/huggingface/transformers/issues/5486:
os.environ["TOKENIZERS_PARALLELISM"] = "false"
HF_TOKEN = _get_env_from_colab_or_os("HF_TOKEN")
SOURCES = ["https://arxiv.org/pdf/2408.09869"] # Docling Technical Report
EMBED_MODEL_ID = "sentence-transformers/all-MiniLM-L6-v2"
GEN_MODEL_ID = "mistralai/Mixtral-8x7B-Instruct-v0.1"
QUESTION = "Which are the main AI models in Docling?"
PROMPT = PromptTemplate.from_template(
"Context information is below.\n---------------------\n{context}\n---------------------\nGiven the context information and not prior knowledge, answer the query.\nQuery: {input}\nAnswer:\n",
)
TOP_K = 3
MILVUS_URI = str(Path(mkdtemp()) / "docling.db")
import os from pathlib import Path from tempfile import mkdtemp from dotenv import load_dotenv from langchain_core.prompts import PromptTemplate from langchain_docling.loader import ExportType def _get_env_from_colab_or_os(key): try: from google.colab import userdata try: return userdata.get(key) except userdata.SecretNotFoundError: pass except ImportError: pass return os.getenv(key) load_dotenv() # https://github.com/huggingface/transformers/issues/5486: os.environ["TOKENIZERS_PARALLELISM"] = "false" HF_TOKEN = _get_env_from_colab_or_os("HF_TOKEN") SOURCES = ["https://arxiv.org/pdf/2408.09869"] # Docling 技术报告 EMBED_MODEL_ID = "sentence-transformers/all-MiniLM-L6-v2" GEN_MODEL_ID = "mistralai/Mixtral-8x7B-Instruct-v0.1" QUESTION = "Docling 中主要的 AI 模型有哪些?" PROMPT = PromptTemplate.from_template( "Context information is below.\n---------------------\n{context}\n---------------------\nGiven the context information and not prior knowledge, answer the query.\nQuery: {input}\nAnswer:\n", ) TOP_K = 3 MILVUS_URI = str(Path(mkdtemp()) / "docling.db")
文档存储设置¶
文档加载¶
我们首先定义转换器,这里包含保留页面图像(用于视觉定位)的选项。
In [3]
已复制!
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions
from docling.document_converter import DocumentConverter, PdfFormatOption
converter = DocumentConverter(
format_options={
InputFormat.PDF: PdfFormatOption(
pipeline_options=PdfPipelineOptions(
generate_page_images=True,
images_scale=2.0,
),
)
}
)
from docling.datamodel.base_models import InputFormat from docling.datamodel.pipeline_options import PdfPipelineOptions from docling.document_converter import DocumentConverter, PdfFormatOption converter = DocumentConverter( format_options={ InputFormat.PDF: PdfFormatOption( pipeline_options=PdfPipelineOptions( generate_page_images=True, images_scale=2.0, ), ) } )
我们建立一个简单的文档存储来保存转换后的文档,这是后续视觉定位所需的。
In [4]
已复制!
doc_store = {}
doc_store_root = Path(mkdtemp())
for source in SOURCES:
dl_doc = converter.convert(source=source).document
file_path = Path(doc_store_root / f"{dl_doc.origin.binary_hash}.json")
dl_doc.save_as_json(file_path)
doc_store[dl_doc.origin.binary_hash] = file_path
doc_store = {} doc_store_root = Path(mkdtemp()) for source in SOURCES: dl_doc = converter.convert(source=source).document file_path = Path(doc_store_root / f"{dl_doc.origin.binary_hash}.json") dl_doc.save_as_json(file_path) doc_store[dl_doc.origin.binary_hash] = file_path
现在我们可以实例化加载器并加载文档。
In [5]
已复制!
from langchain_docling import DoclingLoader
from docling.chunking import HybridChunker
loader = DoclingLoader(
file_path=SOURCES,
converter=converter,
export_type=ExportType.DOC_CHUNKS,
chunker=HybridChunker(tokenizer=EMBED_MODEL_ID),
)
docs = loader.load()
from langchain_docling import DoclingLoader from docling.chunking import HybridChunker loader = DoclingLoader( file_path=SOURCES, converter=converter, export_type=ExportType.DOC_CHUNKS, chunker=HybridChunker(tokenizer=EMBED_MODEL_ID), ) docs = loader.load()
Token indices sequence length is longer than the specified maximum sequence length for this model (648 > 512). Running this sequence through the model will result in indexing errors
👉 注意:如上所示,使用
HybridChunker
有时可能导致 transformers 库发出警告,但这只是一个“误报”——详情请查看这里。
检查一些样本分块
In [6]
已复制!
for d in docs[:3]:
print(f"- {d.page_content=}")
print("...")
for d in docs[:3]: print(f"- {d.page_content=}") print("...")
- d.page_content='Docling Technical Report\nVersion 1.0\nChristoph Auer Maksym Lysak Ahmed Nassar Michele Dolfi Nikolaos Livathinos Panos Vagenas Cesar Berrospi Ramis Matteo Omenetti Fabian Lindlbauer Kasper Dinkla Lokesh Mishra Yusik Kim Shubham Gupta Rafael Teixeira de Lima Valery Weber Lucas Morin Ingmar Meijer Viktor Kuropiatnyk Peter W. J. Staar\nAI4K Group, IBM Research R¨ uschlikon, Switzerland' - d.page_content='Abstract\nThis technical report introduces Docling , an easy to use, self-contained, MITlicensed open-source package for PDF document conversion. It is powered by state-of-the-art specialized AI models for layout analysis (DocLayNet) and table structure recognition (TableFormer), and runs efficiently on commodity hardware in a small resource budget. The code interface allows for easy extensibility and addition of new features and models.' - d.page_content='1 Introduction\nConverting PDF documents back into a machine-processable format has been a major challenge for decades due to their huge variability in formats, weak standardization and printing-optimized characteristic, which discards most structural features and metadata. With the advent of LLMs and popular application patterns such as retrieval-augmented generation (RAG), leveraging the rich content embedded in PDFs has become ever more relevant. In the past decade, several powerful document understanding solutions have emerged on the market, most of which are commercial software, cloud offerings [3] and most recently, multi-modal vision-language models. As of today, only a handful of open-source tools cover PDF conversion, leaving a significant feature and quality gap to proprietary solutions.\nWith Docling , we open-source a very capable and efficient document conversion tool which builds on the powerful, specialized AI models and datasets for layout analysis and table structure recognition we developed and presented in the recent past [12, 13, 9]. Docling is designed as a simple, self-contained python library with permissive license, running entirely locally on commodity hardware. Its code architecture allows for easy extensibility and addition of new features and models.\nHere is what Docling delivers today:\n· Converts PDF documents to JSON or Markdown format, stable and lightning fast\n· Understands detailed page layout, reading order, locates figures and recovers table structures\n· Extracts metadata from the document, such as title, authors, references and language\n· Optionally applies OCR, e.g. for scanned PDFs\n· Can be configured to be optimal for batch-mode (i.e high throughput, low time-to-solution) or interactive mode (compromise on efficiency, low time-to-solution)\n· Can leverage different accelerators (GPU, MPS, etc).' ...
摄取¶
In [7]
已复制!
import json
from pathlib import Path
from tempfile import mkdtemp
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
from langchain_milvus import Milvus
embedding = HuggingFaceEmbeddings(model_name=EMBED_MODEL_ID)
milvus_uri = str(Path(mkdtemp()) / "docling.db") # or set as needed
vectorstore = Milvus.from_documents(
documents=docs,
embedding=embedding,
collection_name="docling_demo",
connection_args={"uri": milvus_uri},
index_params={"index_type": "FLAT"},
drop_old=True,
)
import json from pathlib import Path from tempfile import mkdtemp from langchain_huggingface.embeddings import HuggingFaceEmbeddings from langchain_milvus import Milvus embedding = HuggingFaceEmbeddings(model_name=EMBED_MODEL_ID) milvus_uri = str(Path(mkdtemp()) / "docling.db") # 或根据需要设置 vectorstore = Milvus.from_documents( documents=docs, embedding=embedding, collection_name="docling_demo", connection_args={"uri": milvus_uri}, index_params={"index_type": "FLAT"}, drop_old=True, )
RAG¶
In [8]
已复制!
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_huggingface import HuggingFaceEndpoint
retriever = vectorstore.as_retriever(search_kwargs={"k": TOP_K})
llm = HuggingFaceEndpoint(
repo_id=GEN_MODEL_ID,
huggingfacehub_api_token=HF_TOKEN,
)
def clip_text(text, threshold=100):
return f"{text[:threshold]}..." if len(text) > threshold else text
from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_huggingface import HuggingFaceEndpoint retriever = vectorstore.as_retriever(search_kwargs={"k": TOP_K}) llm = HuggingFaceEndpoint( repo_id=GEN_MODEL_ID, huggingfacehub_api_token=HF_TOKEN, ) def clip_text(text, threshold=100): return f"{text[:threshold]}..." if len(text) > threshold else text
Note: Environment variable`HF_TOKEN` is set and is the current active token independently from the token you've just configured.
In [9]
已复制!
from docling.chunking import DocMeta
from docling.datamodel.document import DoclingDocument
question_answer_chain = create_stuff_documents_chain(llm, PROMPT)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)
resp_dict = rag_chain.invoke({"input": QUESTION})
clipped_answer = clip_text(resp_dict["answer"], threshold=200)
print(f"Question:\n{resp_dict['input']}\n\nAnswer:\n{clipped_answer}")
from docling.chunking import DocMeta from docling.datamodel.document import DoclingDocument question_answer_chain = create_stuff_documents_chain(llm, PROMPT) rag_chain = create_retrieval_chain(retriever, question_answer_chain) resp_dict = rag_chain.invoke({"input": QUESTION}) clipped_answer = clip_text(resp_dict["answer"], threshold=200) print(f"问题:\n{resp_dict['input']}\n\n答案:\n{clipped_answer}")
/Users/pva/work/github.com/DS4SD/docling/.venv/lib/python3.12/site-packages/huggingface_hub/utils/_deprecation.py:131: FutureWarning: 'post' (from 'huggingface_hub.inference._client') is deprecated and will be removed from version '0.31.0'. Making direct POST requests to the inference server is not supported anymore. Please use task methods instead (e.g. `InferenceClient.chat_completion`). If your use case is not supported, please open an issue in https://github.com/huggingface/huggingface_hub. warnings.warn(warning_message, FutureWarning)
Question: Which are the main AI models in Docling? Answer: The main AI models in Docling are: 1. A layout analysis model, an accurate object-detector for page elements. 2. TableFormer, a state-of-the-art table structure recognition model.
视觉定位¶
In [10]
已复制!
import matplotlib.pyplot as plt
from PIL import ImageDraw
for i, doc in enumerate(resp_dict["context"][:]):
image_by_page = {}
print(f"Source {i + 1}:")
print(f" text: {json.dumps(clip_text(doc.page_content, threshold=350))}")
meta = DocMeta.model_validate(doc.metadata["dl_meta"])
# loading the full DoclingDocument from the document store:
dl_doc = DoclingDocument.load_from_json(doc_store.get(meta.origin.binary_hash))
for doc_item in meta.doc_items:
if doc_item.prov:
prov = doc_item.prov[0] # here we only consider the first provenence item
page_no = prov.page_no
if img := image_by_page.get(page_no):
pass
else:
page = dl_doc.pages[prov.page_no]
print(f" page: {prov.page_no}")
img = page.image.pil_image
image_by_page[page_no] = img
bbox = prov.bbox.to_top_left_origin(page_height=page.size.height)
bbox = bbox.normalized(page.size)
thickness = 2
padding = thickness + 2
bbox.l = round(bbox.l * img.width - padding)
bbox.r = round(bbox.r * img.width + padding)
bbox.t = round(bbox.t * img.height - padding)
bbox.b = round(bbox.b * img.height + padding)
draw = ImageDraw.Draw(img)
draw.rectangle(
xy=bbox.as_tuple(),
outline="blue",
width=thickness,
)
for p in image_by_page:
img = image_by_page[p]
plt.figure(figsize=[15, 15])
plt.imshow(img)
plt.axis("off")
plt.show()
import matplotlib.pyplot as plt from PIL import ImageDraw for i, doc in enumerate(resp_dict["context"][:]): image_by_page = {} print(f"来源 {i + 1}:") print(f"文本: {json.dumps(clip_text(doc.page_content, threshold=350))}") meta = DocMeta.model_validate(doc.metadata["dl_meta"]) # 从文档存储加载完整的 Docling 文档: dl_doc = DoclingDocument.load_from_json(doc_store.get(meta.origin.binary_hash)) for doc_item in meta.doc_items: if doc_item.prov: prov = doc_item.prov[0] # 这里我们只考虑第一个 provenance 项 page_no = prov.page_no if img := image_by_page.get(page_no): pass else: page = dl_doc.pages[prov.page_no] print(f"页面: {prov.page_no}") img = page.image.pil_image image_by_page[page_no] = img bbox = prov.bbox.to_top_left_origin(page_height=page.size.height) bbox = bbox.normalized(page.size) thickness = 2 padding = thickness + 2 bbox.l = round(bbox.l * img.width - padding) bbox.r = round(bbox.r * img.width + padding) bbox.t = round(bbox.t * img.height - padding) bbox.b = round(bbox.b * img.height + padding) draw = ImageDraw.Draw(img) draw.rectangle( xy=bbox.as_tuple(), outline="blue", width=thickness, ) for p in image_by_page: img = image_by_page[p] plt.figure(figsize=[15, 15]) plt.imshow(img) plt.axis("off") plt.show()
Source 1: text: "3.2 AI models\nAs part of Docling, we initially release two highly capable AI models to the open-source community, which have been developed and published recently by our team. The first model is a layout analysis model, an accurate object-detector for page elements [13]. The second model is TableFormer [12, 9], a state-of-the-art table structure re..." page: 3
Source 2: text: "3 Processing pipeline\nDocling implements a linear pipeline of operations, which execute sequentially on each given document (see Fig. 1). Each document is first parsed by a PDF backend, which retrieves the programmatic text tokens, consisting of string content and its coordinates on the page, and also renders a bitmap image of each page to support ..." page: 2
Source 3: text: "6 Future work and contributions\nDocling is designed to allow easy extension of the model library and pipelines. In the future, we plan to extend Docling with several more models, such as a figure-classifier model, an equationrecognition model, a code-recognition model and more. This will help improve the quality of conversion for specific types of ..." page: 5
In [ ]
已复制!