Figure Description Language Propagation#
The Bug#
RAGFlow datasets have a configurable language setting that flows through the chunking pipeline — including the vision-LLM prompts used to describe embedded figures. Two parsers, MinerU and Mistral, bypass the standard VisionFigureParser machinery and call vision_llm_figure_describe_prompt() directly without a language argument. Because the prompt function accepts no language parameter and renders a static template , all figure descriptions are generated in English regardless of the dataset's language setting.
Additionally, the four wrapper functions in figure_parser.py that do route through VisionFigureParser share the same underlying gap: VisionFigureParser.__init__ never stores self.language, and the prompt calls inside VisionFigureParser.__call__ also omit the language argument .
Architecture: The Two Paths#
Standard path — VisionFigureParser#
deepdoc/parser/figure_parser.py defines four public wrapper functions that orchestrate figure description for the deepdoc/rag-app layer:
| Wrapper | Primary callers |
|---|---|
vision_figure_parser_docx_wrapper | rag/app/book.py, rag/app/manual.py |
vision_figure_parser_figure_xlsx_wrapper | rag/app/table.py |
vision_figure_parser_pdf_wrapper | rag/app/naive.py, rag/app/manual.py, rag/app/paper.py |
vision_figure_parser_docx_wrapper_naive | rag/app/naive.py, rag/app/one.py |
Each wrapper constructs a VisionFigureParser instance and calls it. VisionFigureParser.__call__ selects between vision_llm_figure_describe_prompt() (no context) or vision_llm_figure_describe_prompt_with_context(...) (with surrounding text), then runs picture_vision_llm_chunk() per figure .
Bypass path — MinerU and Mistral#
MinerU: _enhance_images_with_vlm() calls vision_llm_figure_describe_prompt() at line 897 with no arguments, then passes the prompt string to vision_llm_chunk() for each image. No language is extracted from kwargs — even though parse_pdf() does receive lang via parser_config or kwargs .
Mistral: _describe_image() calls vision_llm_figure_describe_prompt() at line 329 with no arguments. parse_pdf() never captures a language/lang kwarg to forward .
Root Cause Chain#
The chunk() functions in rag/app/ declare lang as an explicit named parameter — so it is not captured in **kwargs. When the wrappers receive only **kwargs, lang is already absent . For MinerU and Mistral, the gap is simpler: neither parser's image-description method receives or forwards a language value.
Dataset language setting
→ task_executor.py → chunker (lang= parameter)
→ rag/app/*.py chunk() — lang declared as named param, absent from **kwargs
→ figure_parser.py wrappers receive **kwargs only (lang missing)
→ VisionFigureParser (no self.language)
→ vision_llm_figure_describe_prompt() ← no language parameter
→ prompt template rendered without {{ language }}
→ VLM produces English output regardless of dataset language
MinerU / Mistral bypass this chain entirely:
parse_pdf() → _enhance_images_with_vlm() / _describe_image()
→ vision_llm_figure_describe_prompt() ← same static call
Affected Components#
| File | Location | Issue |
|---|---|---|
deepdoc/parser/figure_parser.py | wrappers L49–196, VisionFigureParser L201–293 | Wrappers have no lang= param; VisionFigureParser stores no self.language; prompts called without language |
deepdoc/parser/mineru_parser.py | _enhance_images_with_vlm() L879–914 | Calls prompt function at L897 without language |
deepdoc/parser/mistral_parser.py | _describe_image() L315–333 | Calls prompt function at L329 without language |
rag/prompts/generator.py | vision_llm_figure_describe_prompt() L363–365 | No language parameter; renders static template |
Fix Status (as of 2026-08-05)#
Two open PRs address the figure_parser.py wrappers, but neither fixes MinerU or Mistral:
-
PR #17677 — Superseding fix covering all four wrappers. Adds
lang="English"to each wrapper signature, storesself.languageinVisionFigureParser.__init__, passeslanguage=self.languageto prompt calls in__call__, and adds alanguageparameter to both prompt functions ingenerator.py. Adds## OUTPUT LANGUAGEwith{{ language }}to both prompt templates. Includes 15 unit tests. -
PR #17227 — Earlier partial fix for the
_naivewrapper; superseded by #17677 forfigure_parser.py. Also coversrag/flow/parser/agent-flow paths not addressed by #17677.
How to complete the fix for MinerU / Mistral#
For MinerU: forward the lang already extracted at line 938 into _enhance_images_with_vlm(), then pass language=lang to vision_llm_figure_describe_prompt(language=lang) inside the worker.
For Mistral: pop language from kwargs in parse_pdf() (alongside vision_model at line 459), store it as self.language, and pass it to vision_llm_figure_describe_prompt(language=self.language) in _describe_image().
Both fixes depend on vision_llm_figure_describe_prompt() accepting a language parameter — which PR #17677 adds to generator.py.