feat(tech-split): tech评估项抽取接机械拆解(2026-09-18用户裁定)+LENGTH字节口径修复——①_reconcile_tech_analysis_qc派发段:正文超split_chars拆N段并行子任务(char_range互不重叠,四维度A块同款);单体全文抽取实测弊病(甘肃r1):2.7小时串行+agent自选offset步进(700-1000字符)窗口大量重叠,(category,item_name)精确去重对跨窗口近义命名失效→733条注水QC6.8退回;不相交区间从源头消除跨窗口重复;②轮次口径改_dim_round_count(round去重):旧COUNT条数口径拆解后一轮N子任务会虚高N倍误触上限;③_tender_text_len修LENGTH(字节)→CHAR_LENGTH(字符):抽取工具按Python字符串索引切片,char_range是字符坐标;甘肃实测LENGTH=179031 vs CHAR_LENGTH=67658(CJK≈2.65字节/字),按字节拆段第2段仅尾部有效第3段越界空串——2026-09-15四维度拆解'实测通过'实际带病运行(区间错位浪费1/3子任务),本次修正全维度受益

This commit is contained in:
yumoqing 2026-09-18 10:48:25 +08:00
parent a1a97c6669
commit 05e5c6bff2

View File

@ -176,9 +176,16 @@ async def _open_dim_tasks(sor, project_id, dim):
async def _tender_text_len(sor, project_id):
"""项目最新招标文件正文字符数(无文件/无正文返回 0。拆解阈值判定用。"""
"""项目最新招标文件正文字符数(无文件/无正文返回 0。拆解阈值判定用。
必须 CHAR_LENGTH字符不能 LENGTH字节抽取工具按 Python 字符串
索引切片txt[offset:offset+length]char_range 区间是字符坐标甘肃实测
LENGTH=179031 vs CHAR_LENGTH=67658CJK utf8mb4 2.65字节/按字节拆
3 段时第 2 段仅尾部 8k 字符有效 3 段完全越界读空串2026-09-15 四维度
拆解"实测通过"实际带病运行区间错位浪费 1/3 子任务2026-09-18 tech 接入时修正
"""
recs = await sor.sqlExe(
"SELECT LENGTH(content_text) AS n FROM bid_tender_files "
"SELECT CHAR_LENGTH(content_text) AS n FROM bid_tender_files "
"WHERE project_id=${p}$ ORDER BY created_at DESC LIMIT 1", {"p": project_id})
await sor.sqlExe("COMMIT", {})
if not recs:
@ -1537,28 +1544,46 @@ async def _reconcile_tech_analysis_qc(sor, project_id, pname, n_items, latest_qc
return False, False, True
qc_imp = (latest_qc.get("improvement") or "") if (
latest_qc and str(latest_qc.get("passed")) != "1") else ""
attempts = await _count(
sor, "SELECT COUNT(*) AS c FROM pipeline_tasks WHERE tenant_id=${p}$ "
"AND pipeline_id='role_task' AND role=${r}$ AND state IN "
"('approved','completed','qc_rejected') AND params LIKE ${kw}$",
{"p": project_id, "r": R_ANALYST, "kw": '%bid_tech_analysis%'})
if attempts >= MAX_ANALYST_ATTEMPT + th["qc_max_round"]:
# 轮次口径2026-09-18 拆解配套,四维度 A 块同款):一个拆解轮派 N 个分段
# 子任务(同 round 标签),按任务条数计轮会把一轮误算 N 轮触发上限误判。
# 旧口径 COUNT(params LIKE '%bid_tech_analysis%') 数条数,拆解后同样虚高。
n_first = await _dim_round_count(sor, project_id, TECH_KIND, redo=False)
n_redo = await _dim_round_count(sor, project_id, TECH_KIND, redo=True)
_over = (n_redo >= th["qc_max_round"]) if qc_imp else (n_first >= MAX_ANALYST_ATTEMPT)
if _over:
ht = await find_human_task(sor, project_id, "general", status="pending")
if not ht:
await create_human_task(
sor, project_id, "general",
"技术评估项解析多未产出,需人工介入:%s" % pname,
("技术评估项解析任务已执行 %d 次,产出仍为空\n"
"技术评估项解析多未产出,需人工介入:%s" % pname,
("技术评估项解析已执行 %d 轮(首跑 %d / QC重做 %d),产出仍为空或未过审\n"
"请检查招标文件技术部分是否可读bid_tender_files.content_text"
"或用 list_tech_items/add_tech_item 人工补录评估项。" % attempts),
"或用 list_tech_items/add_tech_item 人工补录评估项。"
% (n_first + n_redo, n_first, n_redo)),
assignee_role="owner.superuser")
await sor.sqlExe("COMMIT", {})
acts.append("escalated: 技术评估项解析重试超限 → 人工介入")
acts.append("escalated: 技术评估项解析轮次超限 → 人工介入")
return False, False, True
tparams = {"stage": "tech_analysis", "task_kind": "bid_tech_analysis",
"analysis_dim": TECH_KIND, "flow_key": flow_key}
if qc_imp:
tparams["qc_redo"] = 1
# 大文件机械拆解2026-09-18 用户要求,四维度 A 块同款机制):正文超阈值
# → 拆 N 段并行子任务char_range 互不重叠。单体全文抽取实测弊病(甘肃 r1
# 2.7 小时串行 + agent 自选 offset 步进造成窗口大量重叠,(category,item_name)
# 精确去重对跨窗口近义命名失效 → 733 条注水QC 6.8 退回,判重复条目/source_ref
# 不可回溯)。不相交区间从源头消除跨窗口重复。
_tlen = await _tender_text_len(sor, project_id)
if _tlen > th["split_chars"]:
_ids = await _create_split_tasks(
sor, project_id, TECH_KIND, "技术评估项抽取", pname, tparams, _tlen,
th["split_chars"], ("redo%d" % (n_redo + 1)) if qc_imp else "run1",
qc_imp=["[tech_items] %s" % qc_imp[:2000]] if qc_imp else None)
await sor.sqlExe("COMMIT", {})
acts.append("created: 技术评估项抽取拆解 %d 个分段子任务(正文 %d 字符%s"
% (len(_ids), _tlen, "QC退回重做" if qc_imp else ""))
return False, False, True
if qc_imp:
tparams["qc_improvements"] = ["[tech_items] %s" % qc_imp[:2000]]
tid = await create_role_task(
sor, project_id, R_ANALYST,