u*#^LWo&A@HoJVj11|TWa@OS&1FZWX
z?>=;=Xbfrt9r^>3)@iwthw>$%BmG0E*cuE7lG=-2ODSl+vuo&2=@yAMyBnoNY6hFw
zMj^!Oo$=4Q`JlvBD=#=lvl|9oqNr5;zb%%Gw})5lc1iAo?D}#xLlfy^t*svG3I=^1
zo^ym9dIOhF;9XpYR>TGbHt3Qh9<+y+u{jX(bB=mDEgJ%&OhVB?ne+xcewli5=gvCk
zw%P`n33Xe@bm4m!M#>QXAmtP
zd%I#=dDCto;N{&?Q>(|%3!#;0OEhr-_aRsbH(higLr7oZ75~dtjIX_!C7)qSyq*#7y0$n5EnD%Fp}${zBadRUWMzrz~Ah99MFW+oF|Y
zOntO!#z0wi?1?iL*`hCydX
z^{Rt7w1n)%TJY-)B=cC~@}GSJAV{GoK_+yz$NDp6SD%B#xf=
zKIh$kArnL>qa^#!O`m#i>L1=p#7@q3>piNkXWbz|;Qf+*Fxjczj}VgB>lcH(+tUno
zN3;50M~^6-Cf+(S-5;HN>oAB8LQP%#c=Dr*tYTMoS2kAFI2(3V)j5Aw*-&3wzr(q!
zzN&iDYOSqYe7AZszB;^iw_+4Gl(XU?PcX=HY{}i4Y+7x1)C(kNJ#0!TB)l@^enNg%
zo6F;K9q{oh*pLW7C*>jBAJ-BDG~x&V@~Z5~(3DVDPjh)Y+ne3N}v`%EO(1f!O0DTjfV
zKK0Dfr%RVM`RxzEFVw{DPFWCTpQBxiPUFoUNB}(PW!bNXya4CYH!8l{Y0BMern$DW`V0NlLyclKyQroky-ZUCBOro$H&Z}Km-
zGj>8Y2)vvl@<@TQu|)`kf{
z6eqVqflAH;;A{^$)d@M>9c~}*sPF~c0FE|0Q0+&do%nM|qS$zT;i&~D7sMAmGPL)T
zr#^VjO6dUp5HK>-w@x^IFi4&D`#w8abMfXK$rPTTVC(HUMfC+^;qu0uGaXX
zRmyt?!;4+`jFGTHN*HNIKn7VrHqwsEMmL}YNkF;|SLtU!vufGQncE|{Lq3M{wUd-F=oiUJf(Jcm}%?R<_w3>2rqC0LBP)25^
z2(uQ&c6RUVE9(2Z3wYPg5liXe>gd)k{DE2*FXmr8R>G_c0wl{pe8%j?vn8l0VQMf!R4v
z8kUHq(!E+?gyhUxuj?=XJjQJBh_fj3wZeQ;s|R{8pnqChn33M+56G5nMG4NP_4K3U
z$pB6N&vNAbRdVG2&DNvfuacwiZzf04UnR#qcacMf%G|sNaRxi9!vMriEyE<8f4LtM
z2pro7x$W4q#6GMYUxuy0M7$kN|2_u!;N0e52{LKM`KpAB66`YWXlqW8qo{pZL
z`s7&3t@%6$9Id?M;#`u8O`bbH_3j(2%F%Vbh;a1L=aa7vCQn>k1ukFcV1sb2mP8HU
z0ys|ox<3(nd;07EyL(?_&8~U?#Wjdp13FC=6F_tFpI%S)cc-O;ti<5&L6XF=OOr1T
z!aYNgb!p>4UKKb9G>WT*XWIb-rEmBS$5PbtgFgZ*IQ9HTiH}eH0CpFUQtM@)eo`c%
z(;22#JJtYxZCfLof+2y2>4%MIzAM9wLtnl|01OoWEUcz8a7d==sv9e}RW??t=%KVO
zwOlKoRH?^ucCBL#Q}1f!%ax^L^!)H@W>2WK)djSUIx#U265KrSJUq{~B0vJ@*(Ie_
z%Y>~`An5e*ZM@GRJu9iQF*03Szo)Ts=g#Vea8U;Luu_07Jgqzv&QsLmRMn%jta)k{
zu?2UYP>aVeKFuJ^!){U}okM$-qayuslxo4qIStiSyBfC1Sa`m&GxTL*dA|s2$d$8p
zn@plInXcA|B-sQ22k?j>(*R%H0e`cnMW!Lo3HalnC_D(dQ6Nzo|HxFU>k!X*1X0dW
zR$o-X5b|vbR06cK4!&hmN}sY-ggYj5sB9NerjclXPn!eKRZ2^;p*eU52D(R;T%~FB
zMnWZY-T;5%XK?1C*o=)Z=6*pH-lDMFdA(d;-G%ZI+xn}vZ9}Ee9pgoduNN&JE?PcP
zWWQdta=2*a1#VwmMr>;bt48Uvp{=R9@%)le
z%8n{;oKrdeVA+UmTBeh?{00uEce{NaAWT0lx>E9_w8@z!z72T?Co!1qML^4
zirbTPS)49|*OoZF<@UEQ;QBbd?zUJ5Dm_BhVAwws^J;R5Kbs3`iiv;8EvT^*|5{j3
zvyS-7y#=*6aRsAmEW{Nvj?!FX%>vVvVq?vNrYm-1&05oyb;g>_rq6I=En}L6BmqCF
zNOC)vn@l8mhhJHUE|XqVf6l`Z3cHRU0T06&I`QXlKc&9gam@>*ng494GaK4WBO%Q%
zie?F6UgZH~n?h4Za7m|^(g+nW6~f5M<3-ntIgeK-#?l2`4rkIlHbS`GEJ%>k>9uWG
zjBp!TFt_1pxB>w=Mu>P%PJ}pV=%Go>Z*+slbsIW~c0`5|>DffcHe9$rVi3&fJix;g
zx{#kG{Kjb>m5$7iSB{}s@0Q@=TyeE;y|h2x3dm%*VT6S`6}p(tLay4T6emlA^~
z)xi_9u>drh_~=E&XU_#C6Ca)c`9Ol?@7{#4-Q=0~k}sc6zVuSs#j%N(1^^snz=c(a
z-at-)g`k@{1sFl;KE(loPmmC?#j4V)6dxPx2&!~EgnLpbB{}f=^xHj&H-A6%-gynA
zs3<^j9N{gB153q8z#B>svq3J{&t(Xha?;?3fFTJ0=z;pJ9uZM$;jKys8a_$oK7s-_
zh;Yk*KpNr3wtHY=`Z75j4w*?;6MhOiP{zx{4plIf{ef`<;Nd_p#H6Kb>nxtbZdDy&
zVO@X=`S|*Pv>gROss$k+$fO^jNZPf^Mvn+{ku3_dxTm2C1w>Tl;Q<(3am2Dwgs6)o
z6QByj_K3Uy0TFc!0>~<0Ayn#A#)A+qK@L0}8BuA4SuRyyT46T~(FuQI0utm>jm83S
zso){M8#mu~12Y&4#>}=@S$A1)+g0=8F-!g}0<+xr-!lZ1+y>7J&JH=kP2HRNi$~25
zj@y=uS?X>QhFoR_GtdmwFfwtbew5smA`@c%Zhv3Xg|#C#M|8*7{GXh&zGfY8kIpY0
zv8*1RU)sCoZP!arz{h`GwXBX-$1SVJO@)2yhE43}TWjC+4LmcrX7Fc&wZqFc|9hmz
z5M#QT-il$0g-ZPopDTNpSxosg@)5BZW_pA)
zVaMoFqBrjW;=Hkx_;i73>x1N{OGrp(c@M-OC_Kb-aNsjZO^rtYJFMI6bRM0-Q>1g#
z%tSg5Yz^ikJ5`%wY|ZJ!p~tk{A%G^$V%@=>l9F!WBYG$&TMz`SuI@{q?;qKUGb%wL
zbNc3&x;f?=Si>65lr*2cDi1%
z6#)M8=0*xq&^Lv*HA-;TAolFA=PL0`g-KKlfC8*l
zYhs%vlPDm#tr{Z-e95HL5#(jc=|ncn>69%E>J3M+Y{Gg}g_Z;e-lBDZ_&$oA8M
z4NCV)cOts>X>2Fi>hk!7{gBfSf8rn{z&DdiM#*L4H2nlcsn1jZjRepMyZ42=G=H5J7QjP
z-CR0sE{!{?u9~aH3+_YseEm&=EVRvFq!mCbX4!_{DpJhV@@r(tceiK-(-LTS2*cKn
zQjd*O`PZpM!_=ZtYVjCloiRb-Z4t3`zp7ldwE+9Hpmb{mfz}62%jtxBm&xgb2(;6w
z8hk_<3y-0s3?+zOS6O91zgUJ=D$!45o0X*zo`kP|#8kpu;q$4AR>iYy7M_731QbP7
z2aq?8|0hY}CEy
ejm?F)eP#tlTDrnli3OjN)Y0v*D_C-2VYXsnO;D
literal 0
HcmV?d00001
diff --git a/docker/scripts/entrypoint.sh b/docker/scripts/entrypoint.sh
index 275efe1..58a42a1 100644
--- a/docker/scripts/entrypoint.sh
+++ b/docker/scripts/entrypoint.sh
@@ -19,5 +19,10 @@ if [ -f ${SCRIPTS_DIR}/apply_mineru_patches.py ]; then
${VENV}/bin/python ${SCRIPTS_DIR}/apply_mineru_patches.py || echo "[entrypoint] apply_mineru_patches.py failed (non-fatal)"
fi
+# 确保 vllm 源码目录在 PYTHONPATH 中
+# patch_vllm_platform.py 中的 os.environ 修改不持久化到父进程
+# 这里无条件导出,防止 editable install 被破坏后 vllm 无法导入
+export PYTHONPATH="/opt/vllm:${PYTHONPATH}"
+
echo "[entrypoint] starting: $*"
exec "$@"
diff --git a/docker/scripts/patch_vllm_platform.py b/docker/scripts/patch_vllm_platform.py
index adc8c8c..788a232 100644
--- a/docker/scripts/patch_vllm_platform.py
+++ b/docker/scripts/patch_vllm_platform.py
@@ -6,7 +6,9 @@
"""
import os
+import re
import sys
+import sysconfig
import traceback
VLLM_DIR = '/opt/vllm/vllm'
@@ -38,26 +40,88 @@ def patch6_init_platform_fallback():
def patch7_rocm_break_import_cycle():
"""补丁 7:platforms/rocm.py —— logger.warning_once → sys.stderr.write
- 这个补丁会直接改写 vLLM 源码中的函数调用。部分 vLLM 版本里
- logger.warning_once(...) 参数不一定兼容 sys.stderr.write(...),改写后可能
- 导致 import vllm / import vllm.platforms.rocm 失败。MinerU 会把这种导入失败
- 包装成 "Please install vllm",因此默认禁用,只在显式设置环境变量时启用。
+ 默认启用安全的“整段 except 块”替换,避免 logger.warning_once() 在平台检测
+ 期间触发循环导入,导致 current_platform 落到 UnspecifiedPlatform。
+ 如需禁用,设置 VLLM_PATCH_ROCM_WARNING_ONCE=0。
"""
- if os.environ.get('VLLM_PATCH_ROCM_WARNING_ONCE') != '1':
- print('Patch 7: skipped (set VLLM_PATCH_ROCM_WARNING_ONCE=1 to enable).')
+ if os.environ.get('VLLM_PATCH_ROCM_WARNING_ONCE') == '0':
+ print('Patch 7: skipped (VLLM_PATCH_ROCM_WARNING_ONCE=0).')
return
f = os.path.join(VLLM_DIR, 'platforms', 'rocm.py')
c = open(f).read()
- old = 'logger.warning_once('
- new = 'import sys as _sys\n _sys.stderr.write('
- c2 = c.replace(old, new)
+ if 'amdsmi unavailable, using torch.cuda fallback' in c:
+ print('Patch 7: already applied.')
+ return
+ pattern = re.compile(
+ r'(\n\s*except Exception as e:\n'
+ r'\s*logger\.debug\("Failed to get GCN arch via amdsmi: %s", e\)\n'
+ r'\s*logger\.warning_once\(\n'
+ r'(?:\s*"[^"]*"\n)+'
+ r'\s*\)\n)',
+ re.MULTILINE,
+ )
+
+ def repl(match):
+ indent = re.search(r'\n(\s*)except Exception as e:', match.group(1)).group(1)
+ body_indent = indent + ' '
+ return (
+ f'\n{indent}except Exception as e:\n'
+ f'{body_indent}import sys as _sys\n'
+ f'{body_indent}_sys.stderr.write('
+ '"vLLM ROCm: amdsmi unavailable, using torch.cuda fallback for GPU detection\\n")\n'
+ )
+
+ c2, n = pattern.subn(repl, c, count=1)
if c2 != c:
open(f, 'w').write(c2)
- print('Patch 7: rocm.py circular import broken.')
+ print('Patch 7: rocm.py logger.warning_once circular import patch applied.')
else:
print('Patch 7: already applied or pattern not found.')
+def ensure_vllm_dist_info():
+ """为 /opt/vllm 源码导入创建最小 dist-info。
+
+ vLLM 平台检测会通过 importlib.metadata 查询 vllm 分发元数据/entry points。
+ 如果只靠 PYTHONPATH 导入源码,没有 dist-info,就会出现:
+ "The vLLM package was not found...",并可能得到 UnspecifiedPlatform。
+ """
+ try:
+ import vllm
+ except Exception:
+ return
+
+ version = getattr(vllm, '__version__', '0.1.dev1') or '0.1.dev1'
+ site_packages = sysconfig.get_paths().get('purelib')
+ if not site_packages:
+ return
+ dist_info = os.path.join(site_packages, f'vllm-{version}.dist-info')
+ os.makedirs(dist_info, exist_ok=True)
+
+ metadata = os.path.join(dist_info, 'METADATA')
+ if not os.path.exists(metadata):
+ with open(metadata, 'w') as fp:
+ fp.write(
+ 'Metadata-Version: 2.1\n'
+ 'Name: vllm\n'
+ f'Version: {version}\n'
+ 'Summary: vLLM source tree mounted at /opt/vllm\n'
+ )
+
+ with open(os.path.join(dist_info, 'top_level.txt'), 'w') as fp:
+ fp.write('vllm\n')
+ with open(os.path.join(dist_info, 'INSTALLER'), 'w') as fp:
+ fp.write('mineru-rocm-runtime\n')
+ with open(os.path.join(dist_info, 'entry_points.txt'), 'w') as fp:
+ fp.write(
+ '[vllm.platform_plugins]\n'
+ 'rocm = vllm.platforms.rocm:rocm_platform_plugin\n'
+ )
+ with open(os.path.join(dist_info, 'RECORD'), 'w') as fp:
+ fp.write('')
+ print(f'vllm dist-info ensured: {dist_info}')
+
+
def ensure_vllm_installed():
"""确保 vLLM Python 包在当前虚拟环境中可导入。
@@ -94,9 +158,16 @@ def main():
patch7_rocm_break_import_cycle()
try:
ensure_vllm_installed()
+ ensure_vllm_dist_info()
import vllm
from vllm.platforms import current_platform
print(f'vllm runtime import OK: {vllm.__version__}, platform={type(current_platform).__name__}')
+ if type(current_platform).__name__ == 'UnspecifiedPlatform':
+ raise RuntimeError(
+ 'vLLM platform detection returned UnspecifiedPlatform; '
+ 'ROCm backend is not usable. Check amdsmi, /dev/kfd, /dev/dri, '
+ 'and vllm.platform_plugins metadata.'
+ )
except Exception:
print('ERROR: vllm runtime import failed after platform patches:')
traceback.print_exc()