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

View File

@@ -103,6 +103,33 @@ class OrderLogger:
for line in (call_result.raw_response or "").splitlines():
self._lines.append(f" {line}")
# 调用统计模型名、单次调用耗时、token 用量与缓存命中情况。
# 失败调用(未拿到 usage时相应字段显示"无",保证排查信息完整。
self._lines.append("")
self._lines.append("[调用统计]")
self._lines.append(f" 模型: {call_result.model}")
if call_result.elapsed_ms is not None:
self._lines.append(f" 单次调用耗时: {call_result.elapsed_ms:.1f} ms")
else:
self._lines.append(" 单次调用耗时: 无(调用失败)")
u = call_result.usage
if isinstance(u, dict):
self._lines.append(
f" tokens: prompt={u.get('prompt_tokens')} "
f"completion={u.get('completion_tokens')} "
f"total={u.get('total_tokens')}"
)
prompt = u.get("prompt_tokens") or 0
hit = u.get("prompt_cache_hit_tokens") or 0
rate = round(hit / prompt, 4) if prompt else 0.0
self._lines.append(
f" 缓存: hit={u.get('prompt_cache_hit_tokens')} "
f"miss={u.get('prompt_cache_miss_tokens')} "
f"命中率={rate}"
)
else:
self._lines.append(" 用量统计: 无(调用失败或未返回 usage")
self._lines.append("")
if format_error is not None:
self._lines.append("[格式校验] 失败")