Files

5.2 KiB

nantong-lease-audit Workflow 架构与批量运行指南

概述

nantong-lease-audit 是南通新东方租赁合同梳理的 uwf 状态机工作流(2026-06-27 建成并通过金飞达12份+人民中路2份测试)。

架构

OCR(手动/脚本) → uwf thread start(每份合同) → Excel builder(汇总) → delivery-gate → 交付

与 contract-portfolio-analysis skill Step 0→7 的关系

  • workflow 替代 Step 2 的 delegate_task 动作B(模版比对)+ rule-analyzer(法律风险分析)+ data-extractor(结构化数据提取)
  • Step 0(盘点)、Step 1(OCR)、Step 3(Excel生成)、Step 6(交付闸门)仍由脚本完成
  • Step 4-5(校对+终审)在 workflow 完成后由人工做

4 角色定义

角色 耗时(典型) 产出
classifier 60-90s 校区、主体、合同类型、模版类型、面积、期限
template-diff 180-200s 与07模版逐条比对差异清单(供L列)
rule-analyzer 280-300s 独立法律风险分析(供K列)+ 提前退租分析
data-extractor 120-150s 12列结构化数据 + H列四检 + 数学交叉验证

单份合同总耗时:~10分钟(4角色串行)。

YAML Frontmatter 输出大小限制

uwf 的 YAML frontmatter 解析有大小限制。当角色输出内容超过 ~2000 字符时,frontmatter 解析会失败,导致 thread suspended。

data-extractor 的解决方案

  • 将12列数据写入 /tmp/nantong-lease-audit/row_data.json 文件
  • YAML frontmatter 中只传文件路径:output_file: /tmp/nantong-lease-audit/row_data.json
  • 下游 Excel builder 从文件读取数据

规则:任何 uwf 角色的输出如果包含大量文本(>2000字符),应该:

  1. 将详细内容写入文件
  2. frontmatter 中只放文件路径和摘要字段
  3. 在 procedure 中明确指示 agent 必须写文件

批量启动模式

batch_runner.sh 模板

#!/bin/bash
UWF=/home/maggie/.hermes/node/bin/uwf
WF=nantong-lease-audit
CAMPUS=校区名
OCR_DIR=/tmp/校区/ocr
LOG=/tmp/校区/threads.log

FILES=("合同1" "合同2" ...)  # 文件名(不含.md后缀)
THREAD_IDS=()

for fname in "${FILES[@]}"; do
  md_path="${OCR_DIR}/${fname}.md"
  [ ! -f "$md_path" ] && continue
  
  OUT=$($UWF thread start $WF -p "校区:${CAMPUS} | 合同文件:${fname} | OCR文本路径:${md_path} | 原始文件名:${fname}.pdf" 2>&1)
  TID=$(echo "$OUT" | python3 -c "import re,sys; t=sys.stdin.read(); m=(re.search(r'\"thread\"\s*:\s*\"([^\"]+)\"', t) or re.search(r'Thread\s+(\S+)', t)); print(m.group(1) if m else '')")
  
  [ -n "$TID" ] && { THREAD_IDS+=("$TID"); sleep 8; }  # 8s CAS settle
done

# exec all threads
for tid in "${THREAD_IDS[@]}"; do
  cd /home/maggie && $UWF thread exec "$tid" -c 20 --background 2>&1
  sleep 2
done

# Wait loop with auto-resume of suspended threads
while true; do
  ALL_DONE=true
  for tid in "${THREAD_IDS[@]}"; do
    STATUS=$(cd /home/maggie && $UWF thread list --all 2>/dev/null | grep "$tid" | awk '{print $3}')
    if [ "$STATUS" = "suspended" ] || [ "$STATUS" = "idle" ]; then
      cd /home/maggie && $UWF thread exec "$tid" -c 10 --background 2>&1
      sleep 5
      ALL_DONE=false
    elif [ "$STATUS" != "end" ] && [ "$STATUS" != "cancelled" ]; then
      ALL_DONE=false
    fi
  done
  $ALL_DONE && break
  sleep 60
done

关键参数

  • sleep 8 between thread starts:CAS settle 防止 phantom thread
  • -c 20 --background:一次跑20步(足够覆盖4角色)
  • 自动 resume suspended/idle threads(API 429 限流会导致 suspended)

API 限流处理

14个并发 thread 会触发 API 429 (rate limiting)。表现:

  • rule-analyzer 或 data-extractor 阶段 suspended
  • 日志显示 "HTTP 429: Request rate increased too quickly"

处理:batch runner 的 wait loop 自动检测 suspended 状态并 resume。不需要手动干预。

生成 Excel

# 单份合同
python3 scripts/nantong-excel-builder.py <thread-id> <校区名> <xlsx路径> [文件名]

# 批量(所有已完成的thread)
python3 scripts/batch-excel-builder.py <xlsx路径>

Thread Read Quota 陷阱

uwf thread read 默认 quota 只有 4000 字符,远远不够读取完整输出(template-diff 和 rule-analyzer 输出通常 10000-30000 字符)。

必须用uwf thread read <id> --quota 200000 --start

  • --quota 200000:200K 字符足够
  • --start:包含 init step

Excel builder 脚本已内置此参数,不需要手动指定。

测试结果(2026-06-27)

校区 合同数 总耗时 完成率
金飞达 12份 ~60分钟 12/12 end
人民中路 2份 ~60分钟 2/2 end

14个并发 thread,API 限流导致部分 thread 需要 auto-resume,但全部完成。

已知问题

  1. Excel builder 解析精度:各 thread 输出格式不完全一致,部分行的 C/F 列(合同类型/面积)可能为空
  2. K/L 列内容:data-extractor 的 K/L 列有时写占位符而非实际分析内容(已修复 workflow prompt,但需验证)
  3. 按租赁物分类排序:batch builder 按 thread 完成顺序排列,不自动按"租赁物→合同性质→时间"排序——需要后续手动调整或增加排序逻辑