feat: 附件分类结果写入层 + 运行统计 + --id 指定总排号

- db.py: 新增 upsert_attachments/fetch_all_ids,实现 Common.Attachment 幂等写入
  (先删受影响 NS 旧行再批量插入,依赖唯一索引,可安全重跑)
- write_attachments.py: 写入入口,支持 --limit/--ids-file/--id(单个或逗号分隔多个)
  /--mode/--dry-run/--enable-other,运行结束打印 token 与缓存命中率汇总
- llm_client.py: LLMCallResult 捕获 usage/elapsed_ms/model/attempt
- classifier.py: classify_batch 结果透传 meta(耗时分两种、上下文 token、缓存命中率),
  新增 summarize_results 聚合批统计
- main.py: 新增 --summary 把批汇总打到 stderr,stdout 保持干净 JSON Lines
- order_logger.py: 每次 LLM 尝试补充 [调用统计] 段,便于排查耗时与缓存效果
- README.md: 对齐上述接口与统计说明

Co-Authored-By: WorkBuddy <workbuddy@tencent.com>
This commit is contained in:
Misaka_Company
2026-07-24 15:38:06 +08:00
parent 4ca048bd26
commit 622f348cf1
7 changed files with 608 additions and 19 deletions

13
main.py
View File

@@ -11,6 +11,7 @@
python main.py --id 26B742 --pretty # 格式化输出JSON(默认单行紧凑)
python main.py --id 26B742 --log-dir /tmp/logs # 覆盖配置文件里的日志目录
python main.py --id 26B742 --enable-other # 允许模型使用"其他"兜底类目
python main.py --id 26B742 --summary # 额外在 stderr 打印本批运行汇总统计
分类模式(--mode):
coarse (默认) - 只判断大类: 资料/配件/耗材(启用 --enable-other 时还有"其他")
@@ -57,7 +58,7 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent / "src"))
from classifier import classify_batch # noqa: E402
from classifier import classify_batch, summarize_results # noqa: E402
from config_loader import ConfigError, load_config # noqa: E402
@@ -111,6 +112,11 @@ def main() -> None:
help="允许模型使用'其他'兜底类目。不指定则使用配置文件 business.enable_other_category"
"(缺省为关闭);本开关只能从命令行打开,无法用命令行强制关闭配置文件里已打开的设置",
)
parser.add_argument(
"--summary", action="store_true",
help="在 stderr 额外打印本批运行的汇总统计(耗时/token/缓存命中率);"
"stdout 仍只输出干净的 JSON Lines 结果,便于管道/重定向",
)
args = parser.parse_args()
if not args.id and not args.ids_file:
@@ -155,6 +161,11 @@ def main() -> None:
for r in results:
print(json.dumps(r, ensure_ascii=False))
if args.summary:
summary = summarize_results(results)
print("--- 运行汇总 ---", file=sys.stderr)
print(json.dumps(summary, ensure_ascii=False, indent=2), file=sys.stderr)
if __name__ == "__main__":
main()