feat: export core Hermes skills
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
# 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 模板
|
||||
|
||||
```bash
|
||||
#!/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
|
||||
|
||||
```bash
|
||||
# 单份合同
|
||||
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 完成顺序排列,不自动按"租赁物→合同性质→时间"排序——需要后续手动调整或增加排序逻辑
|
||||
Reference in New Issue
Block a user