@customize-agent/knowledge 4.3.3 → 4.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -109,9 +109,14 @@ function collectTenderFormatBlock(lines, start) {
|
|
|
109
109
|
/** 招标文件:泛化引用行("详见投标人须知前附表"类短行,无实质项目信息;后缀短语可选) */
|
|
110
110
|
const TENDER_GENERIC_LINE_RE = /^(详见|具体见|以|按).{0,30}?(前附表|招标文件|招标公告|补疑|澄清|清单|图纸|合同文件)((的)?(要求|规定|为准|执行))?[。;;]?$|^投标人应(仔细|认真)(阅读|核对)(招标文件|本项目)(的全部内容)?[。;;]?$|^未(按|依照|按照)(上述|本|招标文件)要求/u;
|
|
111
111
|
/** 招标文件:电子投标程序句(行级)。投标人须知条目式排版无可靠段落边界,按句删除
|
|
112
|
-
*
|
|
112
|
+
* 程序性操作(加密/解密/上传/撤回/签号/病毒防范/获取/发布/提出/发出/发送/下载/拒收/提交/开标/导入/制作/中断/在线/查询/登录/进行/公示);
|
|
113
113
|
* 双重信号(程序动词 + 程序对象)防止误删技术条款。仅招标文件生效。 */
|
|
114
|
-
const
|
|
114
|
+
const TENDER_EPROCEDURE_PREFIX_RE = /(?:电子交易系统|数字证书|加密|解密|撤回操作|上传投标文件|签号|病毒防范)/u;
|
|
115
|
+
const TENDER_EPROCEDURE_LINE_RE = /(?:电子交易系统|数字证书|加密|解密|撤回操作|上传投标文件|签号|病毒防范).{0,45}(?:上传|递交|撤回|解密|完成|显示|关闭|发放|发送|防范|获取|发布|提出|发出|下载|拒收|查看|接收|提交|开标|导入|拒绝|制作|中断|在线|查询|登录|进行|公示)|(?:投标截止时间).{0,35}(?:上传|递交|撤回|自动关闭)/u;
|
|
116
|
+
/** 具体时间/地点证据:跨行拼接删除的防护——拼接后含实质时间地点信息的不删 */
|
|
117
|
+
const TENDER_TIME_PLACE_RE = /\d{4}年\d{1,2}月\d{1,2}日|\d{1,2}时\d{1,2}分|地点[::为是]/u;
|
|
118
|
+
/** 折行接续行判定:行首非编号/序号/条文标题(PDF 折行接续的行首是句中词) */
|
|
119
|
+
const TENDER_CONTINUATION_HEAD_RE = /^(?:###\s*)?(?:第[一二三四五六七八九十百零两\d]+[条章节]|[((]?[一二三四五六七八九十\d]+[))、.、.]|\d{1,3}[.、.]|[【[])/u;
|
|
115
120
|
/** 补疑文件:零信息回复行("答:按招标文件执行"类套话;含数字/单位的实质回复不删) */
|
|
116
121
|
const CLARIFICATION_BOILERPLATE_RE = /^(?:(?:答|答复|回复)[::]\s*)?(?:按|以)(招标文件|招标公告|合同文件|清单|图纸|补疑|答疑)?(约定|规定|要求|执行|为准)[。;;]?$|^(?:(?:答|答复|回复)[::]\s*)?不(作|做|予)(调整|修改|变更)[。;;]?$|^(?:(?:答|答复|回复)[::]\s*)?维持(不变|原状)[。;;]?$|^(?:(?:答|答复|回复)[::]\s*)?(本项|此项)(无|没有)(调整|修改|变化)[。;;]?$/u;
|
|
117
122
|
/** 图纸:无汉字纯坐标数字行(≥2 组相邻 "数字,数字" 坐标对即 ≥3 个连续坐标值,设计坐标不写入施组正文) */
|
|
@@ -424,6 +429,24 @@ export function cleanExtractedText(input) {
|
|
|
424
429
|
index += 1;
|
|
425
430
|
continue;
|
|
426
431
|
}
|
|
432
|
+
// 招标文件:电子投标程序句(跨行拼接;PDF 提取折行把程序动词折到下一行,行间夹空行)
|
|
433
|
+
if (TENDER_EPROCEDURE_PREFIX_RE.test(trimmed)
|
|
434
|
+
&& !/[。;;::!!??]$/u.test(trimmed)) {
|
|
435
|
+
let nextIdx = index + 1;
|
|
436
|
+
while (nextIdx < lines.length && !lines[nextIdx].trim())
|
|
437
|
+
nextIdx += 1;
|
|
438
|
+
if (nextIdx < lines.length && nextIdx - index <= 3) {
|
|
439
|
+
const next = lines[nextIdx].trim();
|
|
440
|
+
const continuation = next.length > 0 && next.length < 80 && !TENDER_CONTINUATION_HEAD_RE.test(next);
|
|
441
|
+
const joined = `${trimmed}${next}`;
|
|
442
|
+
if (continuation && TENDER_EPROCEDURE_LINE_RE.test(joined) && !TENDER_TIME_PLACE_RE.test(joined)) {
|
|
443
|
+
drop(line, s => { s.tenderEprocedureLines += 1; });
|
|
444
|
+
drop(lines[nextIdx], s => { s.tenderEprocedureLines += 1; });
|
|
445
|
+
index = nextIdx + 1;
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
427
450
|
}
|
|
428
451
|
// 6. 补疑文件:零信息回复行(行级,长度 ≤25 且无数字/单位)
|
|
429
452
|
if (docKind === 'clarification' && trimmed.length <= 25 && CLARIFICATION_BOILERPLATE_RE.test(trimmed) && !/\d/u.test(trimmed)) {
|
|
@@ -856,6 +856,10 @@ export class KnowledgeBaseManager {
|
|
|
856
856
|
rerankBoost += 160;
|
|
857
857
|
if (normalizedPhrase.length >= 4 && normalizedContent.includes(normalizedPhrase))
|
|
858
858
|
rerankBoost += 220;
|
|
859
|
+
// 时间类查询下,含具体日期/时刻的 chunk 是精确答案(如「获取时间:2026年8月13日」),
|
|
860
|
+
// 应优先于仅含规则条款的程序句(「距投标截止时间不足15日」类无具体时间)
|
|
861
|
+
if (/(时间|日期|工期|截止|开标|获取|递交)/u.test(query) && /20\d{2}年\d{1,2}月\d{1,2}日|\d{1,2}时\d{1,2}分/u.test(item.content))
|
|
862
|
+
rerankBoost += 60;
|
|
859
863
|
const titleText = `${item.titlePath ?? ''}\n${item.sectionTitle ?? ''}`.toLowerCase();
|
|
860
864
|
const normalizedTitle = this.normalizeSearchText(titleText);
|
|
861
865
|
let matchedTermCount = 0;
|
|
@@ -873,7 +877,7 @@ export class KnowledgeBaseManager {
|
|
|
873
877
|
rerankBoost += 22;
|
|
874
878
|
}
|
|
875
879
|
if (matchedTermCount >= 2)
|
|
876
|
-
rerankBoost += matchedTermCount *
|
|
880
|
+
rerankBoost += matchedTermCount * 30;
|
|
877
881
|
for (const label of factLabels) {
|
|
878
882
|
const normalizedLabel = this.normalizeSearchText(label);
|
|
879
883
|
if (normalizedContent.includes(normalizedLabel))
|
|
@@ -881,8 +885,11 @@ export class KnowledgeBaseManager {
|
|
|
881
885
|
if (normalizedTitle.includes(normalizedLabel))
|
|
882
886
|
rerankBoost += 120;
|
|
883
887
|
}
|
|
888
|
+
// 表格块惩罚仅针对「无任何查询词命中」的表格(清单特征块命中查询词时应保留竞争力);
|
|
889
|
+
// 表格行(清单特征「混凝土强度等级:C35」)在向量空间天然弱势,RRF 名次扁平下
|
|
890
|
+
// 若再吃 -80 惩罚,会被普通段落(绿建专篇)挤到后面,丢失精确词命中优势
|
|
884
891
|
if (item.chunkKind === 'table')
|
|
885
|
-
rerankBoost += wantsTable ? 25 : -80;
|
|
892
|
+
rerankBoost += wantsTable ? 25 : (matchedTermCount > 0 ? -10 : -80);
|
|
886
893
|
if (item.chunkKind === 'metadata')
|
|
887
894
|
rerankBoost += wantsDrawing ? 60 : -100;
|
|
888
895
|
if (item.chunkKind === 'data')
|
|
@@ -893,7 +900,9 @@ export class KnowledgeBaseManager {
|
|
|
893
900
|
rerankBoost -= wantsDrawing ? 60 : 160;
|
|
894
901
|
}
|
|
895
902
|
if (/工作表:|COL\d+|专业工程暂估价计价表|分部分项工程量清单计价表|材料(工程设备)暂估单价一览表/u.test(item.content)) {
|
|
896
|
-
|
|
903
|
+
// 计价表行无查询词命中是纯标题噪音(-140);命中查询词的清单特征行
|
|
904
|
+
// (「混凝土强度等级:C35」)是用户直接目标,仅轻惩罚维持正文优先
|
|
905
|
+
rerankBoost -= wantsTable ? 35 : (matchedTermCount > 0 ? 20 : 140);
|
|
897
906
|
}
|
|
898
907
|
if (/第\s*\d+\s*页\s*共\s*\d+\s*页|PDF\s*第\s*\d+\s*页/iu.test(item.content) && factLabels.length > 0)
|
|
899
908
|
rerankBoost -= 12;
|
|
@@ -921,8 +930,12 @@ export class KnowledgeBaseManager {
|
|
|
921
930
|
}
|
|
922
931
|
queryTerms(query) {
|
|
923
932
|
const base = query.toLowerCase().split(/[\s,,。;;::、]+/u).filter(Boolean);
|
|
933
|
+
// 字母数字与汉字连续串按边界拆词(与 store.expandSearchTerms 的边界拆分一致):
|
|
934
|
+
// 「C35混凝土」须拆出「c35」「混凝土」,重排层才能识别清单特征块的双词命中,
|
|
935
|
+
// 否则 terms 只有整串连写短语,对「强度等级:C35」类特征块零命中、错吃 table 惩罚
|
|
936
|
+
const splitParts = base.flatMap(term => term.split(/([\p{Script=Han}]+)/u).filter(part => part.length > 0));
|
|
924
937
|
const labels = this.queryFactLabels(query).map(label => label.toLowerCase());
|
|
925
|
-
return [...new Set([...base, ...labels].filter(term => term.length > 0))];
|
|
938
|
+
return [...new Set([...base, ...splitParts, ...labels].filter(term => term.length > 0))];
|
|
926
939
|
}
|
|
927
940
|
queryFactLabels(query) {
|
|
928
941
|
const labels = [];
|
|
@@ -944,6 +957,12 @@ export class KnowledgeBaseManager {
|
|
|
944
957
|
labels.push('招标人', '项目业主', '建设单位');
|
|
945
958
|
if (/临水|临电|临时水电|水电接引|接驳点|挂表计量|施工水电/u.test(query))
|
|
946
959
|
labels.push('临水临电', '临时水电接引', '施工水电接引费', '接驳点挂表计量', '挂表计量');
|
|
960
|
+
if (/获取时间|获取方式/u.test(query))
|
|
961
|
+
labels.push('获取时间', '招标文件获取时间');
|
|
962
|
+
if (/投标截止|截止时间/u.test(query))
|
|
963
|
+
labels.push('投标截止时间', '投标文件递交的截止时间');
|
|
964
|
+
if (/开标时间|开标地点|开标/u.test(query))
|
|
965
|
+
labels.push('开标时间和地点', '开标时间', '开标地点');
|
|
947
966
|
if (/场地限制|材料堆场|办公区|生活区|加工区/u.test(query))
|
|
948
967
|
labels.push('场地限制', '不具备材料堆场', '搭设加工区', '搭设办公区', '搭设生活区');
|
|
949
968
|
if (/拆除|修补|破损处|改造维修/u.test(query))
|