☰
用 AI 智能体给舞台工艺施工图审查排工期:四轮预算表 + 自动校验闸门,让 218 页不再压在一天
2026/11/3 8:55:24 网站建设 项目流程

用 AI 智能体给舞台工艺施工图审查排工期:四轮预算表 + 自动校验闸门,让 218 页不再压在一天

一、背景:为什么 218 页施工图审查会崩在单日冲刺

舞台工艺工程(为演出场馆做机械、灯光、音响等专项工艺设计与落地的工程门类)的施工图审查,天然是"多专业、大页量、强交付"的活。某城市交响音乐厅项目里,机械、灯光、音响三个专业合起来一共 218 页(机械 99 页、灯光 66 页、音响 53 页),当年为了赶报审节点,全部压在单日冲刺里一次性干完。

审图不能把全部页面压在单日冲刺,规划阶段就要排出"轮次预算表",用四轮+自动校验把"声称完成"变成"真校验通过"。

这句是本文的金标准,也是后来我们改造流程的纲。事件里最刺痛的是时间点:上午遭遇模型限流(HTTP 429)一直持续到 11:23,机械专业的后半段页和灯光、音响的关键页复验被迫整体后移。换句话说,本该在上午收口的交付物,因为缺少分批节拍,被一个限流事件整体拖垮。

问题不在活本身,而在排期方式。当时规划阶段手里只有"报审版次"这样一个结果锚点,没有"工期预算"——也就是没有人把 218 页拆成可节拍化的工作量。工作被一次性全量堆积到一天,过程中没有中途节拍器,上午一撞模型限流(HTTP 429),整条流水线就失速了。

把这件事抽象成可复用的教训,就三条:第一,规划阶段就要排期,而不是临时冲刺;第二,用自动化校验代替人工口头报"完成";第三,把"分批纪律"从派单纪律升格为时间节拍器。后面全篇就围绕这三条,给出可复制的工程化做法。

本文面向开发者生态,核心是:如何用脚本把"审图"这件事拆成四轮、如何用自动校验闸门(EXIT=0 判通过)杜绝"幽灵✅"、以及模型限流 429 下如何用断点续跑(–resume)稳住流水线。大模型在这条流水线里的角色,不是替代工程师做判读,而是把"读图—判读—成稿—终核"每一轮的可校验产物自动跑出来,再交给人工抽检。

二、环境准备:工具链与校验脚本前置

在动手排期之前,先把工具链和前置依赖备齐。下面给出一套最小可运行的本地环境,CentOS / Ubuntu / macOS 均可。

前置依赖清单:

  • Python 3.10 及以上
  • python-docx 1.1.x(用于读取与校验生成的审查意见表 docx)
  • 一个可调用的大模型客户端(本文以通用 AI 智能体平台或兼容 OpenAI 协议的自建网关为例)
  • 一份六列审查意见表的 Word 模板

安装依赖的命令如下:

python-mvenv .venvsource.venv/bin/activate# Windows 用 .venv\Scripts\activatepipinstallpython-docx requests

工作目录建议按"轮次"分桶,避免产物互相覆盖:

mkdir-pdwg out/round1_index out/round2_judge out/round3_draft state tpl tree-L2

几个专业实体先交个底,后文会反复用到,这里给白话注解:

DWG 是 AutoCAD 的原生图纸格式,审查时我们直接读它的图元与属性,不依赖栅格化(把矢量图转成位图图片)结果,避免像素级误读。

文字层指 DWG 里承载说明文字的图层(例如标注、附注),审图时主要核对它和标题栏(图纸右下角记录图号、版本、比例等元信息的栏目)是否一致。

A/B/C/D 等级是舞台工艺施工图审查里常用的严重度分级:A 级为必须整改的否决项、B 级为影响施工的重大项、C 级为一般瑕疵、D 级为优化建议。

这里要强调一个认知:审图不是"AI 写个总结就完事",而是 AI 智能体(能自主调用工具、读图、判读、成稿并自我校验的软件代理)在跑一条有闸门的流水线。智能体每完成一轮,闸门先校验再放行——这正是后面自动校验的立足点。所谓"闸门/放行"这套词,就是从 CI/CD 门禁语境来的:校验不通过,流水线卡住,绝不允许带病进下一轮。

三、步骤:拆四轮 + 排轮次预算表

把"审图"从一团活,拆成四个可独立校验的轮次:读图轮、判读轮、成稿轮、终核轮。每一轮带明确的输入、输出、校验项与节拍点。

轮次预算表的相对权重(注意:这属于轮次权重/相对估算,不是绝对工时;AI 处理时长不落盘)建议这样切:

读图轮(轮次权重约 0.20)

  • 目标:逐页读取 DWG 与提资图,建立全量图纸清单
  • 输入:./dwg/ 下三个专业的 218 个文件
  • 交付物:图纸索引表(CSV,含图号/专业/页数)
  • 自动校验:索引文件存在、行数 == 总页数(218)
  • 节拍点:第 1 日 10:00 前锁定清单,禁止后续增页

判读轮(轮次权重约 0.35)

  • 目标:大模型逐页判读问题,产出原始判读记录
  • 输入:图纸索引表 + 各页 DWG
  • 交付物:判读原始 JSON(每页一条,含问题草稿)
  • 自动校验:JSON 文件存在、键数 == 218、无空页
  • 节拍点:第 1 日 14:00 前完成机械 99 页;第 1 日 18:00 前完成灯光 66 + 音响 53

成稿轮(轮次权重约 0.30)

  • 目标:把判读记录落成六列审查意见表(Word)
  • 输入:判读原始 JSON + 六列模板
  • 交付物:审查意见表_终核.docx(每张表六列、带表线)
  • 自动校验:文件存在 + 六列 + 表线渲染闸门 EXIT=0
  • 节拍点:第 2 日 11:00 前成稿,进入终核

终核轮(轮次权重约 0.15)

  • 目标:自动校验闸门全量跑通,人工抽检 A/B 级
  • 输入:审查意见表_终核.docx
  • 交付物:校验报告(EXIT=0 清单)
  • 自动校验:闸门 EXIT=0;A/B 级 100% 人工抽检
  • 节拍点:第 2 日 15:00 前闸门放行,交付

把这张轮次预算表钉在规划阶段,本质是把"分批纪律"从一次性硬冲,升格为时间节拍器:每一轮有自己的截止点和放行条件,哪一轮卡住,影响范围被限制在当轮,不会像单日冲刺那样一撞全崩。

具体到 218 页的分批 checkpoint,建议按专业先切三块,再各自切片,避免瞬时并发撞 429:

机械 99 页|切 3 批:33+33+33|批次截止 第1日 11:00 / 12:30 / 14:00

灯光 66 页|切 2 批:33+33|批次截止 第1日 15:30 / 17:00

音响 53 页|切 2 批:27+26|批次截止 第1日 17:30 / 18:00

这样的分批 checkpoint 让每一批都有独立收口时间,任何一批因限流后移,都不会把整个判读轮拖死。

四、代码/命令:四轮脚本与自动校验闸门

下面给出可直接落地的命令与脚本。先是一组四轮编排命令,每个轮次支持 --resume 断点续跑:

# 读图轮:建立图纸清单python review_runner.py--roundread\--input./dwg/--output./out/round1_index/dwg_index.csv# 判读轮:大模型判读(断点续跑,撞 429 后从 state 续跑)python review_runner.py--roundjudge\--resume./state/judge.state\--input./out/round1_index/dwg_index.csv# 成稿轮:生成六列审查意见表(Word)python review_runner.py--rounddraft\--resume./state/draft.state\--template./tpl/six_col.docx# 终核轮:自动校验闸门python verify_gate.py ./out/round3_draft/审查意见表_终核.docxecho"EXIT=$?"

核心是大模型调用的退避与续跑。判读轮一次性把 218 页全量提交,最容易触发 429,所以要用指数退避加断点续跑:

importtimeimportjsonimportrequestsfrompathlibimportPathdefcall_model_with_backoff(client,prompt,max_retry=5,base_wait=5):"""模型限流 429 下的指数退避;耗尽后抛错由外层 --resume 续跑。"""forattemptinrange(max_retry):try:returnclient.complete(prompt)exceptrequests.exceptions.HTTPErrorase:ifgetattr(e.response,"status_code",None)==429:wait=base_wait*(2**attempt)print(f"[429] 触发模型限流,第{attempt+1}次退避{wait}s")time.sleep(wait)continueraiseraiseRuntimeError("模型限流持续,需 --resume 续跑或人工介入")defsave_state(state_path:Path,done:set):state_path.write_text(json.dumps({"done":sorted(done)},ensure_ascii=False))defload_state(state_path:Path)->set:ifstate_path.exists():returnset(json.loads(state_path.read_text()).get("done",[]))returnset()

然后是本文的压舱石——表线渲染闸门(EXIT=0 判通过)。它做三件事:文件存在、六列审查意见表列数正确、表线(边框)真实渲染。任何一项不过,exit code 非 0,闸门不放行下一轮:

# verify_gate.py - 审查意见表自动校验闸门importsysfrompathlibimportPathfromdocximportDocumentfromdocx.oxml.nsimportqn EXPECTED_COLS=6# 六列审查意见表:图纸编号/专业/问题位置/问题类别/等级/处理意见defcheck_file_exists(path:Path)->bool:ok=path.exists()andpath.stat().st_size>0print(f"[{'PASS'ifokelse'FAIL'}] 文件存在且非空:{path}")returnokdefcheck_six_cols(doc)->bool:ok=Trueforti,tableinenumerate(doc.tables):cols=len(table.columns)ifcols!=EXPECTED_COLS:ok=Falseprint(f"[FAIL] 表{ti}列数={cols}期望={EXPECTED_COLS}")else:hdr=[c.text.strip()forcintable.rows[0].cells]print(f"[INFO] 表{ti}表头:{hdr}")returnokdefcheck_table_lines(doc)->bool:"""表线渲染闸门:检查每张表是否真实带边框(杜绝无边框幽灵表)。"""ok=Trueforti,tableinenumerate(doc.tables):tbl_pr=table._tbl.tblPr borders=tbl_pr.find(qn("w:tblBorders"))has_line=FalseifbordersisnotNone:foredgeinborders:ifedge.get(qn("w:val"))notin(None,"none"):has_line=Truebreakifnothas_line:ok=Falseprint(f"[FAIL] 表{ti}表线未渲染(幽灵表)")returnokdefmain()->int:target=Path(sys.argv[1])ifnotcheck_file_exists(target):return2doc=Document(str(target))ifnotcheck_six_cols(doc):return3ifnotcheck_table_lines(doc):return4print("[PASS] 表线渲染闸门 EXIT=0,放行下一轮")return0if__name__=="__main__":sys.exit(main())

跑通后你会看到:

$ python verify_gate.py ./out/round3_draft/审查意见表_终核.docx[PASS]文件存在且非空: ./out/round3_draft/审查意见表_终核.docx[INFO]表0表头:['图纸编号','专业','问题位置','问题类别','等级','处理意见'][PASS]表线渲染闸门EXIT=0,放行下一轮EXIT=0

EXIT=0 是闸门放行的唯一判据。把这一步接在流水线门禁上,校验不通过就卡住,绝不允许带病进下一轮。

最后补一个 review_runner.py 的骨架,把四轮和分批 checkpoint 串起来,关键在判读轮按页切片、撞 429 续跑:

# review_runner.py - 四轮编排骨架(节选)importargparsefrompathlibimportPath BATCH_PLAN={"机械":[33,33,33],# 99 页切 3 批"灯光":[33,33],# 66 页切 2 批"音响":[27,26],# 53 页切 2 批}defrun_judge(resume:Path,index_csv:Path):done=load_state(resume)pages=read_pages(index_csv)# 读图纸索引表formajor,sizesinBATCH_PLAN.items():forsizeinsizes:batch=take_batch(pages,major,size,done)ifnotbatch:continueforpageinbatch:try:result=call_model_with_backoff(client,page.prompt)write_judge_json(page,result)done.add(page.id)exceptRuntimeError:save_state(resume,done)# 撞 429 兜底,--resume 续跑raisesave_state(resume,done)if__name__=="__main__":ap=argparse.ArgumentParser()ap.add_argument("--round",required=True,choices=["read","judge","draft"])ap.add_argument("--resume",type=Path)ap.add_argument("--input",type=Path)args=ap.parse_args()ifargs.round=="judge":run_judge(args.resume,args.input)

五、踩坑:三个真实教训

下面三坑都来自真实复盘,按"现象—成因—解法"给清。

坑一:单日冲刺无节拍器,429 一撞全盘后移

现象:规划阶段只有"报审版次"结果锚点,没有工期预算;218 页一次性全量堆积到一天。上午撞上模型限流(HTTP 429),从开跑到 11:23 才恢复,机械后半段和灯光、音响关键页复验被迫整体后移。

成因:工作被一次性全量堆积,过程中没有中途节拍器;任何一级失速,整条链都跟着失速。

解法:规划阶段先排轮次预算表,把四轮各自的截止点和放行条件钉死;把"分批纪律"升格为时间节拍器,每轮独立收口,卡住只影响当轮。

坑二:幽灵✅——声称完成但文件缺失 / 表线未渲染

现象:口头报"判读轮完成"“成稿轮完成”,但实际审查意见表 docx 不存在,或表格生成了却无边框(表线未渲染),打开是空白格。

成因:AI 智能体检查(这里指让 AI 智能体对交付物做存在性与完整性核对)没有落地成"文件存在 + 六列 + 表线 EXIT=0"的硬闸门,而是靠人工口头报"完成"。声称完成 ≠ 真校验通过。

解法:上自动校验闸门,文件存在、六列、表线三项全过才 EXIT=0;EXIT≠0 一律视为未通过,禁止进下一轮。把"完成"的定义从口头改成脚本判定。

坑三:批次无限流,429 雪崩

现象:判读轮把 218 页一次性全提交,瞬时并发直接触发 429,且退避不到位,反复重试放大限流。

成因:没有分批节拍器,无并发上限,也没有断点续跑兜底。

解法:按专业分批(机械 99 / 灯光 66 / 音响 53),每批再按页切片;设并发上限;指数退避;撞 429 后用 --resume 从 state 续跑,已完成的页不重算。

这三个坑串起来就是一句话:单日冲刺把风险全部耦合到一天,而四轮 + 自动校验把风险拆散、各自闸住。

六、总结

回到开篇那句金标准——审图不能把全部页面压在单日冲刺,规划阶段就要排出"轮次预算表",用四轮+自动校验把"声称完成"变成"真校验通过"。

把 218 页拆成读图轮、判读轮、成稿轮、终核轮四轮,每轮带完成态自动校验(文件存在 + 六列审查意见表 + 表线渲染闸门 EXIT=0),本质是把"分批纪律"从派单纪律升格为时间节拍器。这样做的好处很直接:规划阶段即排期,比临时冲刺更可控;用自动化校验代替人工口头报"完成",杜绝幽灵✅;模型限流 429 下用退避加断点续跑稳住流水线,单点失速不再拖垮全局。

给开发者的落地清单:第一,规划阶段就写轮次预算表,钉死四轮的截止点与放行条件;第二,六列审查意见表配表线渲染闸门,EXIT=0 才放行;第三,大模型调用一律带指数退避与 --resume,撞 429 不慌;第四,把"完成"的定义交给脚本,不交给人嘴。

当"声称完成"被替换成"真校验通过",218 页就不再是压在一天的负担,而是被节拍器切成可控轮次的可交付流水线。这,就是给审图排工期的全部要义。

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

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

立即咨询