dqy08 commited on
Commit
791970e
·
1 Parent(s): 1c6227e

语义分析功能小改进

Browse files
backend/runtime_config.py CHANGED
@@ -91,7 +91,7 @@ SEMANTIC_RUNTIME_CONFIGS = {
91
  "default_cpu_machine": {"max_token_length": 500},
92
  "cloud_cpu_16g": {"max_token_length": 500},
93
  "cloud_cpu_32g": {"max_token_length": 2000},
94
- "cloud_cuda": {"max_token_length": 4000},
95
  "local_mps": {"max_token_length": 500},
96
  }
97
 
 
91
  "default_cpu_machine": {"max_token_length": 500},
92
  "cloud_cpu_16g": {"max_token_length": 500},
93
  "cloud_cpu_32g": {"max_token_length": 2000},
94
+ "cloud_cuda": {"max_token_length": 2000},
95
  "local_mps": {"max_token_length": 500},
96
  }
97
 
backend/semantic_analyzer.py CHANGED
@@ -3,7 +3,7 @@ Semantic analysis:基于 instruct 模型提取原文 token 与 query 的相关
3
 
4
  使用 logits_gradient 梯度归因策略(与预测更一致),子策略由 --logits_gradient_submode 指定:
5
  - count:top-10 logits 梯度(排除 0),prompt 引导「数量」。0.6b下只适合用于判断文章整体是否有关联,1.7b下全能
6
- - match_score:目标 token logit 梯度,prompt 引导「相关度打分」。0.6b/1.7b下都不太有竞争力
7
  - fill_blank:填空式,top-10 logits 梯度(排除 无),prompt 引导「最相关的一个词」。0.6b下只适合用于给token打分,1.7b下全能
8
 
9
  count/fill_blank 按概率加权(Σ pᵢ·zᵢ)。
@@ -24,7 +24,7 @@ from .runtime_config import get_semantic_max_token_length
24
 
25
 
26
  def _get_logits_gradient_submode() -> str:
27
- """logits_gradient 子策略:count / match_score / fill_blank"""
28
  try:
29
  from backend.app_context import get_args
30
  return getattr(get_args(), "logits_gradient_submode", "fill_blank")
@@ -63,7 +63,7 @@ def _analyze_logits_gradient(
63
  ) -> Dict:
64
  """
65
  梯度归因:logits 对输入 embedding 的梯度。
66
- 子策略:count / match_score / fill_blank,由 --logits_gradient_submode 指定。
67
  submode_override: 评估时可选覆盖,用于同一进程内测试不同子模式。
68
  """
69
  TOTAL_STEPS = 4
@@ -74,9 +74,10 @@ def _analyze_logits_gradient(
74
  if progress_callback:
75
  progress_callback(1, TOTAL_STEPS, "encoding", None)
76
  # 根据submodule来决定不同的instruction
 
77
  if submode == "count":
78
  instruction = f"以下是一篇文章,请问原文中有多少个词和查询主题({query})相关?文章内容:\n\n"
79
- elif submode == "match_score":
80
  instruction = f"以下是一篇文章,请问原文和查询主题({query})的相关程度是多少?请回答0/1/2(2为最高相关)。文章内容:\n\n"
81
  elif submode == "fill_blank":
82
  instruction = f"以下是一篇文章,请问原文中哪个词与查询主题({query})最相关?如无相关词则回答“无”。文章内容:\n\n"
@@ -94,7 +95,7 @@ def _analyze_logits_gradient(
94
  # 生成引导词:chat template 只支持完整消息,引导词需追加到 formatted
95
  if submode == "count":
96
  generation_guide = f"**原文中**出现的,和查询主题({query})相关的词的数量 = **"
97
- elif submode == "match_score":
98
  generation_guide = f"文章和查询主题({query})的相关程度(0-2)打分为:**"
99
  elif submode == "fill_blank":
100
  # “引号是特意为了防止模型生成引号
@@ -109,6 +110,10 @@ def _analyze_logits_gradient(
109
  idx = formatted.find(instruction)
110
  instruction_start_char = idx if idx >= 0 else 0
111
  text_start_char = instruction_start_char + len(instruction)
 
 
 
 
112
 
113
  enc = tokenizer(
114
  formatted,
@@ -131,10 +136,6 @@ def _analyze_logits_gradient(
131
  embed_layer = model.get_input_embeddings()
132
  embeds = embed_layer(input_ids).detach().clone().requires_grad_(True)
133
 
134
- text_end_char = text_start_char + len(truncated_text)
135
- lines = truncated_text.splitlines()
136
- abbrev_text = truncated_text if len(lines) <= 2 else f"{lines[0]}\n...\n{lines[-1]}"
137
- abbrev = formatted[:text_start_char] + abbrev_text + formatted[text_end_char:]
138
  use_gc = _get_gradient_checkpointing()
139
  print(f"📌 logits_gradient: 推理原文 (tokens={len(offset_mapping)}, gradient_checkpointing={use_gc}):\n{abbrev}")
140
  if progress_callback:
@@ -143,7 +144,7 @@ def _analyze_logits_gradient(
143
  if use_gc:
144
  model.gradient_checkpointing_enable()
145
  try:
146
- with torch.set_grad_enabled(True):
147
  outputs = model(
148
  inputs_embeds=embeds,
149
  attention_mask=attention_mask,
@@ -164,11 +165,11 @@ def _analyze_logits_gradient(
164
 
165
  neg_token = "无" if submode == "fill_blank" else "0"
166
  neg_id = tokenizer.encode(neg_token, add_special_tokens=False)[0]
167
- # 全文匹配度:count/match_score 用 1-P("0"),fill_blank 用 1-P("无")
168
  p_neg = probs[0, neg_id].item()
169
  full_match_degree = round(1.0 - p_neg, 4)
170
 
171
- if full_match_degree_only and submode == "count":
172
  return {
173
  "model": get_semantic_model_display_name(),
174
  "token_attention": [],
@@ -186,7 +187,7 @@ def _analyze_logits_gradient(
186
  w[topk_ids[0] == neg_id] = 0
187
 
188
  target_logit = (w * vals).sum()
189
- elif submode == "match_score":
190
  target_ids = tokenizer.encode("2", add_special_tokens=False)
191
  if not target_ids:
192
  raise ValueError("tokenizer 无法编码 '2'")
@@ -253,7 +254,7 @@ def analyze_semantic(
253
  Args:
254
  query: 查询主题
255
  text: 原文
256
- submode_override: 评估时可选覆盖子模式(count/match_score/fill_blank)
257
  progress_callback: 可选进度回调 (step, total_steps, stage, percentage)
258
  debug_info: 为 True 时返回 debug_abbrev(推理原文缩写);topk_tokens、topk_probs 始终在结果中
259
 
 
3
 
4
  使用 logits_gradient 梯度归因策略(与预测更一致),子策略由 --logits_gradient_submode 指定:
5
  - count:top-10 logits 梯度(排除 0),prompt 引导「数量」。0.6b下只适合用于判断文章整体是否有关联,1.7b下全能
6
+ - match_score:目标 token logit 梯度,prompt 引导「相关度打分」。0.6b/1.7b下都不太有竞争力。【已废弃】
7
  - fill_blank:填空式,top-10 logits 梯度(排除 无),prompt 引导「最相关的一个词」。0.6b下只适合用于给token打分,1.7b下全能
8
 
9
  count/fill_blank 按概率加权(Σ pᵢ·zᵢ)。
 
24
 
25
 
26
  def _get_logits_gradient_submode() -> str:
27
+ """logits_gradient 子策略:count / match_score(已废弃) / fill_blank"""
28
  try:
29
  from backend.app_context import get_args
30
  return getattr(get_args(), "logits_gradient_submode", "fill_blank")
 
63
  ) -> Dict:
64
  """
65
  梯度归因:logits 对输入 embedding 的梯度。
66
+ 子策略:count / match_score(已废弃) / fill_blank,由 --logits_gradient_submode 指定。
67
  submode_override: 评估时可选覆盖,用于同一进程内测试不同子模式。
68
  """
69
  TOTAL_STEPS = 4
 
74
  if progress_callback:
75
  progress_callback(1, TOTAL_STEPS, "encoding", None)
76
  # 根据submodule来决定不同的instruction
77
+ # 文档前用 \n\n 分隔,避免 tokenizer 将首字符与空格合并,导致 offset_mapping 计算错误
78
  if submode == "count":
79
  instruction = f"以下是一篇文章,请问原文中有多少个词和查询主题({query})相关?文章内容:\n\n"
80
+ elif submode == "match_score": # 已废弃
81
  instruction = f"以下是一篇文章,请问原文和查询主题({query})的相关程度是多少?请回答0/1/2(2为最高相关)。文章内容:\n\n"
82
  elif submode == "fill_blank":
83
  instruction = f"以下是一篇文章,请问原文中哪个词与查询主题({query})最相关?如无相关词则回答“无”。文章内容:\n\n"
 
95
  # 生成引导词:chat template 只支持完整消息,引导词需追加到 formatted
96
  if submode == "count":
97
  generation_guide = f"**原文中**出现的,和查询主题({query})相关的词的数量 = **"
98
+ elif submode == "match_score": # 已废弃
99
  generation_guide = f"文章和查询主题({query})的相关程度(0-2)打分为:**"
100
  elif submode == "fill_blank":
101
  # “引号是特意为了防止模型生成引号
 
110
  idx = formatted.find(instruction)
111
  instruction_start_char = idx if idx >= 0 else 0
112
  text_start_char = instruction_start_char + len(instruction)
113
+ text_end_char = text_start_char + len(truncated_text)
114
+ lines = truncated_text.splitlines()
115
+ abbrev_text = truncated_text if len(lines) <= 2 else f"{lines[0]}\n...\n{lines[-1]}"
116
+ abbrev = formatted[:text_start_char] + abbrev_text + formatted[text_end_char:]
117
 
118
  enc = tokenizer(
119
  formatted,
 
136
  embed_layer = model.get_input_embeddings()
137
  embeds = embed_layer(input_ids).detach().clone().requires_grad_(True)
138
 
 
 
 
 
139
  use_gc = _get_gradient_checkpointing()
140
  print(f"📌 logits_gradient: 推理原文 (tokens={len(offset_mapping)}, gradient_checkpointing={use_gc}):\n{abbrev}")
141
  if progress_callback:
 
144
  if use_gc:
145
  model.gradient_checkpointing_enable()
146
  try:
147
+ with torch.set_grad_enabled(not full_match_degree_only):
148
  outputs = model(
149
  inputs_embeds=embeds,
150
  attention_mask=attention_mask,
 
165
 
166
  neg_token = "无" if submode == "fill_blank" else "0"
167
  neg_id = tokenizer.encode(neg_token, add_special_tokens=False)[0]
168
+ # 全文匹配度:count/match_score(已废弃) 用 1-P("0"),fill_blank 用 1-P("无")
169
  p_neg = probs[0, neg_id].item()
170
  full_match_degree = round(1.0 - p_neg, 4)
171
 
172
+ if full_match_degree_only:
173
  return {
174
  "model": get_semantic_model_display_name(),
175
  "token_attention": [],
 
187
  w[topk_ids[0] == neg_id] = 0
188
 
189
  target_logit = (w * vals).sum()
190
+ elif submode == "match_score": # 已废弃
191
  target_ids = tokenizer.encode("2", add_special_tokens=False)
192
  if not target_ids:
193
  raise ValueError("tokenizer 无法编码 '2'")
 
254
  Args:
255
  query: 查询主题
256
  text: 原文
257
+ submode_override: 评估时可选覆盖子模式(count/match_score已废弃/fill_blank)
258
  progress_callback: 可选进度回调 (step, total_steps, stage, percentage)
259
  debug_info: 为 True 时返回 debug_abbrev(推理原文缩写);topk_tokens、topk_probs 始终在结果中
260
 
client/src/index.html CHANGED
@@ -154,9 +154,9 @@
154
  <label class="semantic-submode-label" for="semantic_submode_select">submode: </label>
155
  <select id="semantic_submode_select" class="semantic-submode-select">
156
  <option value="count">count</option>
157
- <option value="match_score">match_score</option>
158
  <option value="fill_blank">fill_blank</option>
159
  <option value="hybrid">hybrid</option>
 
160
  </select>
161
  </span>
162
  <span class="semantic-submode-group semantic-submode-group-right">
 
154
  <label class="semantic-submode-label" for="semantic_submode_select">submode: </label>
155
  <select id="semantic_submode_select" class="semantic-submode-select">
156
  <option value="count">count</option>
 
157
  <option value="fill_blank">fill_blank</option>
158
  <option value="hybrid">hybrid</option>
159
+ <option value="match_score">match_score (废弃)</option>
160
  </select>
161
  </span>
162
  <span class="semantic-submode-group semantic-submode-group-right">
client/src/ts/api/GLTR_API.ts CHANGED
@@ -249,7 +249,7 @@ export class TextAnalysisAPI {
249
  * @param query 查询主题
250
  * @param text 原文
251
  * @param onProgress 可选进度回调,传入时启用 SSE 流式响应
252
- * @param submode 可选子模式:count/match_score/fill_blank/hybrid
253
  */
254
  public async analyzeSemantic(
255
  query: string,
 
249
  * @param query 查询主题
250
  * @param text 原文
251
  * @param onProgress 可选进度回调,传入时启用 SSE 流式响应
252
+ * @param submode 可选子模式:count/fill_blank/hybrid;match_score 已废弃
253
  */
254
  public async analyzeSemantic(
255
  query: string,
client/src/ts/lang/translations.ts CHANGED
@@ -188,8 +188,7 @@ export const translations: Translations = {
188
  'information per token histogram': 'token信息量直方图',
189
  'information per token progress': 'token信息量进度图',
190
  'token index': 'token索引',
191
- 'raw score normed histogram': '归一化原始分数直方图',
192
- 'semantic signal prob histogram': '语义信号概率直方图',
193
  'signal prob': 'signal概率',
194
  'signal ratio': '信号比',
195
  'pw score': 'pw 分数',
 
188
  'information per token histogram': 'token信息量直方图',
189
  'information per token progress': 'token信息量进度图',
190
  'token index': 'token索引',
191
+ 'semantic score histogram': '语义分数直方图',
 
192
  'signal prob': 'signal概率',
193
  'signal ratio': '信号比',
194
  'pw score': 'pw 分数',
client/src/ts/start.ts CHANGED
@@ -262,7 +262,21 @@ window.onload = () => {
262
  currentParams['minimap'] = enableMinimap ? '1' : '0';
263
  URLHandler.updateUrl(currentParams, false);
264
  },
265
- onSemanticAnalysisToggle: () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  visualizationUpdater.syncSemanticUiFromConfig();
267
  },
268
  },
 
262
  currentParams['minimap'] = enableMinimap ? '1' : '0';
263
  URLHandler.updateUrl(currentParams, false);
264
  },
265
+ onSemanticAnalysisToggle: (enabled: boolean) => {
266
+ // 打开/关闭时都清除 URL 参数、输入框、选项,避免残留旧数据
267
+ const currentParams = URLHandler.parameters;
268
+ delete currentParams['semantic_query'];
269
+ delete currentParams['semantic_submode'];
270
+ delete currentParams['semantic_color_source'];
271
+ URLHandler.updateUrl(currentParams, false);
272
+ const queryEl = document.getElementById('semantic_search_input') as HTMLInputElement | null;
273
+ if (queryEl) queryEl.value = '';
274
+ const submodeEl = document.getElementById('semantic_submode_select') as HTMLSelectElement | null;
275
+ if (submodeEl) submodeEl.value = 'count';
276
+ const colorEl = document.getElementById('semantic_color_source_select') as HTMLSelectElement | null;
277
+ if (colorEl) colorEl.value = 'raw_score_normed';
278
+ appStateManager.setLastSearchedQuery(null);
279
+ if (enabled) visualizationUpdater.clearSemanticState();
280
  visualizationUpdater.syncSemanticUiFromConfig();
281
  },
282
  },
client/src/ts/utils/settingsMenuManager.ts CHANGED
@@ -96,6 +96,10 @@ export class SettingsMenuManager {
96
  this.semanticAnalysisToggle.on('change', () => {
97
  const enabled = (this.semanticAnalysisToggle.node() as HTMLInputElement)?.checked || false;
98
  setSemanticAnalysisEnabled(enabled);
 
 
 
 
99
  if (this.callbacks.onSemanticAnalysisToggle) {
100
  this.callbacks.onSemanticAnalysisToggle(enabled);
101
  }
 
96
  this.semanticAnalysisToggle.on('change', () => {
97
  const enabled = (this.semanticAnalysisToggle.node() as HTMLInputElement)?.checked || false;
98
  setSemanticAnalysisEnabled(enabled);
99
+ // 自动同步 Disable info density(用户仍可随时手动切换)
100
+ setInfoDensityRenderDisabled(enabled);
101
+ this.setDisableInfoDensity(enabled);
102
+ window.dispatchEvent(new CustomEvent('info-density-render-change'));
103
  if (this.callbacks.onSemanticAnalysisToggle) {
104
  this.callbacks.onSemanticAnalysisToggle(enabled);
105
  }
client/src/ts/utils/signalThresholdDetector.ts CHANGED
@@ -22,7 +22,7 @@ import { fitLogNormalTruncatedMLE, logNormalExpectedCountInInterval, normCdf, LN
22
  import { computeFitQuality } from './fitQuality';
23
 
24
  /** 置信度阈值,达到此值即判定「确定找到」信号边界;默认 0.9999 */
25
- const CONFIDENCE_THRESHOLD = 0.9999;
26
  /** excess 最小阈值,排除无意义随机波动;需 excess > 此值才计为命中 */
27
  const EXCESS_MIN = 0.1;
28
  const MIN_OBSERVED = 1; // 每个 bin 至少 N 个观测
 
22
  import { computeFitQuality } from './fitQuality';
23
 
24
  /** 置信度阈值,达到此值即判定「确定找到」信号边界;默认 0.9999 */
25
+ const CONFIDENCE_THRESHOLD = 0.99999;
26
  /** excess 最小阈值,排除无意义随机波动;需 excess > 此值才计为命中 */
27
  const EXCESS_MIN = 0.1;
28
  const MIN_OBSERVED = 1; // 每个 bin 至少 N 个观测
client/src/ts/utils/topkChartUtils.ts CHANGED
@@ -7,6 +7,8 @@ import * as d3 from 'd3';
7
  import { processCandidateText } from './tokenDisplayUtils';
8
 
9
  const DISPLAY_TOPK = 10;
 
 
10
  /** Tooltip 默认条形宽度 */
11
  const MAX_BAR_WIDTH = 60;
12
  /** Semantic debug 专用:更大条形与列宽,tooltip 不受影响 */
@@ -23,6 +25,8 @@ export interface TopkChartOptions {
23
  /** 条形列单元格宽度 px */
24
  barCellWidth?: number;
25
  numFormat?: (n: number) => string;
 
 
26
  }
27
 
28
  function getThemeColors(): { normalColor: string; selectedColor: string } {
@@ -44,13 +48,17 @@ export function renderTopkChartHtml(
44
  const norm = options?.normalColor ?? normalColor;
45
  const sel = options?.selectedColor ?? selectedColor;
46
  const maxBar = options?.maxBarWidth ?? MAX_BAR_WIDTH;
47
- const numF = options?.numFormat ?? d3.format('.3f');
48
 
49
  const maxProb = data[0]?.prob ?? 1;
50
  const scale = d3.scaleLinear().domain([0, maxProb]).range([0, maxBar]);
51
  const barCellW = options?.barCellWidth ?? 110;
 
52
 
53
- const rows = data.slice(0, DISPLAY_TOPK).map((d) => {
 
 
 
54
  const color = options?.selectedToken !== undefined && d.token === options.selectedToken ? sel : norm;
55
  const bar = `<div style="display: table-cell; width:${barCellW}px;padding-left:5px;">` +
56
  `<div style="display:inline-block;width: ${scale(d.prob)}px;background-color:${color};height: 10px;"></div>` +
 
7
  import { processCandidateText } from './tokenDisplayUtils';
8
 
9
  const DISPLAY_TOPK = 10;
10
+ /** 插入数据中表示省略行的占位符,左侧列空、token 列显示 ⋮ */
11
+ export const TOPK_SEP = '\0__TOPK_SEP__\0';
12
  /** Tooltip 默认条形宽度 */
13
  const MAX_BAR_WIDTH = 60;
14
  /** Semantic debug 专用:更大条形与列宽,tooltip 不受影响 */
 
25
  /** 条形列单元格宽度 px */
26
  barCellWidth?: number;
27
  numFormat?: (n: number) => string;
28
+ /** 最大显示行数,默认 DISPLAY_TOPK */
29
+ maxRows?: number;
30
  }
31
 
32
  function getThemeColors(): { normalColor: string; selectedColor: string } {
 
48
  const norm = options?.normalColor ?? normalColor;
49
  const sel = options?.selectedColor ?? selectedColor;
50
  const maxBar = options?.maxBarWidth ?? MAX_BAR_WIDTH;
51
+ const numF = options?.numFormat ?? ((v: number) => d3.format('.3g')(v * 100) + '%');
52
 
53
  const maxProb = data[0]?.prob ?? 1;
54
  const scale = d3.scaleLinear().domain([0, maxProb]).range([0, maxBar]);
55
  const barCellW = options?.barCellWidth ?? 110;
56
+ const maxRows = options?.maxRows ?? DISPLAY_TOPK;
57
 
58
+ const rows = data.slice(0, maxRows).map((d) => {
59
+ if (d.token === TOPK_SEP) {
60
+ return `<div class="row" style="display: block; text-align: left; padding-left: 30px; color: ${norm}; font-weight: bold;">⋮</div>`;
61
+ }
62
  const color = options?.selectedToken !== undefined && d.token === options.selectedToken ? sel : norm;
63
  const bar = `<div style="display: table-cell; width:${barCellW}px;padding-left:5px;">` +
64
  `<div style="display:inline-block;width: ${scale(d.prob)}px;background-color:${color};height: 10px;"></div>` +
client/src/ts/utils/visualizationConfigs.ts CHANGED
@@ -77,7 +77,7 @@ export const getSurprisalProgressConfig = (): ScatterPlotBaseConfig => ({
77
  * 获取 Raw score normed 直方图配置(归一化 0-1)
78
  */
79
  export const getRawScoreNormedHistogramConfig = (): HistogramBaseConfig => ({
80
- label: tr("semantic raw score histogram"),
81
  no_bins: 20,
82
  xAxisTickSkip: 1,
83
  xAxisTickRound: true,
 
77
  * 获取 Raw score normed 直方图配置(归一化 0-1)
78
  */
79
  export const getRawScoreNormedHistogramConfig = (): HistogramBaseConfig => ({
80
+ label: tr("semantic score histogram"),
81
  no_bins: 20,
82
  xAxisTickSkip: 1,
83
  xAxisTickRound: true,
client/src/ts/utils/visualizationUpdater.ts CHANGED
@@ -438,6 +438,16 @@ export class VisualizationUpdater {
438
  this.updateSemanticDebugInfo();
439
  }
440
 
 
 
 
 
 
 
 
 
 
 
441
  /**
442
  * 根据语义分析配置同步 UI 状态(查询输入框、文本渲染模式等)
443
  * 界面完全由配置决定,不因数据有无而改变
@@ -447,6 +457,19 @@ export class VisualizationUpdater {
447
  const el = document.getElementById('semantic_analysis_section');
448
  if (el) el.style.display = enabled ? '' : 'none';
449
  this.deps.lmf.updateOptions({ semanticAnalysisMode: enabled }, false);
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  // 语义分析配置影响 Upload/Save 的 dataReadyForSave 条件,需始终更新按钮状态
451
  this.deps.appStateManager.updateButtonStates();
452
  }
@@ -661,6 +684,7 @@ export class VisualizationUpdater {
661
  }
662
  if (!abbrev && !top10?.length) {
663
  el.style.display = 'none';
 
664
  return;
665
  }
666
  el.style.display = 'block';
 
438
  this.updateSemanticDebugInfo();
439
  }
440
 
441
+ /**
442
+ * 清除语义分析相关数据(直方图、debug、semanticData),用于打开模式时初始化
443
+ */
444
+ public clearSemanticState(): void {
445
+ this.currentState.semanticData = null;
446
+ const rawScoreNormedItem = document.getElementById('raw_score_normed_histogram_item');
447
+ if (rawScoreNormedItem) rawScoreNormedItem.style.display = 'none';
448
+ this.updateSemanticDebugInfo();
449
+ }
450
+
451
  /**
452
  * 根据语义分析配置同步 UI 状态(查询输入框、文本渲染模式等)
453
  * 界面完全由配置决定,不因数据有无而改变
 
457
  const el = document.getElementById('semantic_analysis_section');
458
  if (el) el.style.display = enabled ? '' : 'none';
459
  this.deps.lmf.updateOptions({ semanticAnalysisMode: enabled }, false);
460
+ if (!enabled) {
461
+ // 关闭时清除语义数据、直方图、debug 信息(不重渲染,避免重复渲染信息密度)
462
+ this.currentState.semanticData = null;
463
+ const rawScoreNormedItem = document.getElementById('raw_score_normed_histogram_item');
464
+ if (rawScoreNormedItem) rawScoreNormedItem.style.display = 'none';
465
+ this.updateSemanticDebugInfo();
466
+ const displayResult = this.computeDisplayResult();
467
+ this.deps.highlightController.updateCurrentData(displayResult ? { result: displayResult } : null);
468
+ if (!displayResult) {
469
+ d3.select('#all_result').style('opacity', 0);
470
+ this.deps.appStateManager.updateState({ hasValidData: false });
471
+ }
472
+ }
473
  // 语义分析配置影响 Upload/Save 的 dataReadyForSave 条件,需始终更新按钮状态
474
  this.deps.appStateManager.updateButtonStates();
475
  }
 
684
  }
685
  if (!abbrev && !top10?.length) {
686
  el.style.display = 'none';
687
+ el.innerHTML = '';
688
  return;
689
  }
690
  el.style.display = 'block';
client/src/ts/vis/ToolTip.ts CHANGED
@@ -6,7 +6,7 @@ import * as d3 from "d3";
6
  import { tr } from "../lang/i18n-lite";
7
  import { getTokenRenderStyle } from "../utils/tokenRenderStyle";
8
  import { escapeHtml, visualizeSpecialChars } from "../utils/tokenDisplayUtils";
9
- import { renderTopkChartHtml } from "../utils/topkChartUtils";
10
 
11
  const SEPARATOR = '─────────────';
12
 
@@ -280,9 +280,12 @@ export class ToolTip {
280
  const tokenData = ri.tokenData as FrontendToken;
281
  const s = ri.semantic;
282
  const hasSemantic = s && (s.pwScore !== undefined || s.signalProb !== undefined || s.rawScoreNormed !== undefined || s.rawScore !== undefined);
283
- const hasRealTopk = tokenData?.real_topk != null && Array.isArray(tokenData.real_topk);
284
  const predTopk = tokenData?.pred_topk ?? [];
285
  const hasPredictions = predTopk.length > 0;
 
 
 
 
286
 
287
  // 1. 构建语义区块(pw score = raw_score_normed × P_pw,P_pw: x≤threshold 为 0,x>threshold 为 1)
288
  const semanticRows: string[] = [];
@@ -300,7 +303,6 @@ export class ToolTip {
300
  const surprisal = calculateSurprisal(prob);
301
  const isClassic = getTokenRenderStyle() === 'classic';
302
  infoRows.push(renderField({ label: tr('information:'), value: `${this.significantF(surprisal)} bits` }, detailColor, valueColor));
303
- infoRows.push(renderField({ label: tr('prob:'), value: this.significantF(prob), valueColor: false }, detailColor, valueColor));
304
  if (!isClassic) {
305
  const informationDensity = calculateSurprisalDensity(tokenData);
306
  const utf8Size = new TextEncoder().encode(tokenData.raw).length;
@@ -332,10 +334,15 @@ export class ToolTip {
332
  .style('display', 'block')
333
  .html(() => `<div style="color:${detailColor};padding-left:5px;">${tr('Top-k data not available.')}</div>`);
334
  } else {
335
- const topkData = predTopk.slice(0, 10).map(([token, prob]) => ({ token, prob }));
 
 
 
 
 
336
  this.predictions.html(renderTopkChartHtml(topkData, {
337
  selectedToken: tokenData.raw,
338
- numFormat: this.numF,
339
  }));
340
  }
341
  }
 
6
  import { tr } from "../lang/i18n-lite";
7
  import { getTokenRenderStyle } from "../utils/tokenRenderStyle";
8
  import { escapeHtml, visualizeSpecialChars } from "../utils/tokenDisplayUtils";
9
+ import { renderTopkChartHtml, TOPK_SEP } from "../utils/topkChartUtils";
10
 
11
  const SEPARATOR = '─────────────';
12
 
 
280
  const tokenData = ri.tokenData as FrontendToken;
281
  const s = ri.semantic;
282
  const hasSemantic = s && (s.pwScore !== undefined || s.signalProb !== undefined || s.rawScoreNormed !== undefined || s.rawScore !== undefined);
 
283
  const predTopk = tokenData?.pred_topk ?? [];
284
  const hasPredictions = predTopk.length > 0;
285
+ // 占位符 real_topk: [0, 1](prob=1)+ 空 pred_topk 表示仅语义分析,无真实信息密度数据
286
+ const isPlaceholderTopk = tokenData?.real_topk != null && Array.isArray(tokenData.real_topk)
287
+ && tokenData.real_topk[1] === 1 && predTopk.length === 0;
288
+ const hasRealTopk = tokenData?.real_topk != null && Array.isArray(tokenData.real_topk) && !isPlaceholderTopk;
289
 
290
  // 1. 构建语义区块(pw score = raw_score_normed × P_pw,P_pw: x≤threshold 为 0,x>threshold 为 1)
291
  const semanticRows: string[] = [];
 
303
  const surprisal = calculateSurprisal(prob);
304
  const isClassic = getTokenRenderStyle() === 'classic';
305
  infoRows.push(renderField({ label: tr('information:'), value: `${this.significantF(surprisal)} bits` }, detailColor, valueColor));
 
306
  if (!isClassic) {
307
  const informationDensity = calculateSurprisalDensity(tokenData);
308
  const utf8Size = new TextEncoder().encode(tokenData.raw).length;
 
334
  .style('display', 'block')
335
  .html(() => `<div style="color:${detailColor};padding-left:5px;">${tr('Top-k data not available.')}</div>`);
336
  } else {
337
+ let topkData = predTopk.slice(0, 10).map(([token, prob]) => ({ token, prob }));
338
+ const isInTopk = topkData.some(d => d.token === tokenData.raw);
339
+ if (!isInTopk && hasRealTopk) {
340
+ const currentProb = tokenData.real_topk![1];
341
+ topkData = [...topkData, { token: TOPK_SEP, prob: 0 }, { token: tokenData.raw, prob: currentProb }];
342
+ }
343
  this.predictions.html(renderTopkChartHtml(topkData, {
344
  selectedToken: tokenData.raw,
345
+ maxRows: topkData.length,
346
  }));
347
  }
348
  }
model_paths.py CHANGED
@@ -11,8 +11,9 @@ DEFAULT_SEMANTIC_MODEL = "qwen3-0.6b-instruct"
11
  SEMANTIC_MODEL_PATHS = {
12
  "qwen3-0.6b-instruct": "Qwen/Qwen3-0.6B",
13
  "qwen3-1.7b-instruct": "Qwen/Qwen3-1.7B",
14
- # "qwen3-4b-instruct": "Qwen/Qwen3-4B",
15
  "qwen3-4b-instruct": "Qwen/Qwen3-4B-Instruct-2507",
 
 
16
  "qwen3.5-0.8b-instruct": "Qwen/Qwen3.5-0.8B",
17
  "qwen3.5-2b-instruct": "Qwen/Qwen3.5-2B",
18
  "qwen3.5-4b-instruct": "Qwen/Qwen3.5-4B"
@@ -22,16 +23,16 @@ SEMANTIC_MODEL_PATHS = {
22
  MODEL_PATHS = {
23
  # 标准模型(FP16/BF16)
24
  'qwen2.5-0.5b': 'Qwen/Qwen2.5-0.5B',
 
25
  'qwen3.0-0.6b': 'Qwen/Qwen3-0.6B-Base',
26
  'qwen3.0-1.7b': 'Qwen/Qwen3-1.7B-Base',
27
  'qwen3.0-4b': 'Qwen/Qwen3-4B-Base',
28
  'qwen3.0-8b': 'Qwen/Qwen3-8B-Base',
29
  'qwen3.0-14b': 'Qwen/Qwen3-14B-Base',
30
- 'qwen3.0-30b-a3b': 'Qwen/Qwen3-30B-A3B-Base',
31
  'qwen3.5-0.8b': 'Qwen/Qwen3.5-0.8B-Base',
32
- 'qwen2.5-32b': 'Qwen/Qwen2.5-32B',
33
- 'qwen2.5-72b': 'Qwen/Qwen2.5-72B',
34
-
35
  # AWQ 量化模型(W4A16,显存占用约为标准模型的 1/4)
36
  # 自动检测,仅支持 Docker + CUDA 环境
37
  # Qwen3-14B-AWQ评估质量差,因为基于instruct版本而不是base版本
 
11
  SEMANTIC_MODEL_PATHS = {
12
  "qwen3-0.6b-instruct": "Qwen/Qwen3-0.6B",
13
  "qwen3-1.7b-instruct": "Qwen/Qwen3-1.7B",
 
14
  "qwen3-4b-instruct": "Qwen/Qwen3-4B-Instruct-2507",
15
+ "qwen3-8b-instruct": "Qwen/Qwen3-8B",
16
+ # qwen3.5
17
  "qwen3.5-0.8b-instruct": "Qwen/Qwen3.5-0.8B",
18
  "qwen3.5-2b-instruct": "Qwen/Qwen3.5-2B",
19
  "qwen3.5-4b-instruct": "Qwen/Qwen3.5-4B"
 
23
  MODEL_PATHS = {
24
  # 标准模型(FP16/BF16)
25
  'qwen2.5-0.5b': 'Qwen/Qwen2.5-0.5B',
26
+ # qwen3.0
27
  'qwen3.0-0.6b': 'Qwen/Qwen3-0.6B-Base',
28
  'qwen3.0-1.7b': 'Qwen/Qwen3-1.7B-Base',
29
  'qwen3.0-4b': 'Qwen/Qwen3-4B-Base',
30
  'qwen3.0-8b': 'Qwen/Qwen3-8B-Base',
31
  'qwen3.0-14b': 'Qwen/Qwen3-14B-Base',
32
+ # qwen3.5
33
  'qwen3.5-0.8b': 'Qwen/Qwen3.5-0.8B-Base',
34
+ 'qwen3.5-2b': 'Qwen/Qwen3.5-2B-Base',
35
+ 'qwen3.5-4b': 'Qwen/Qwen3.5-4B-Base',
 
36
  # AWQ 量化模型(W4A16,显存占用约为标准模型的 1/4)
37
  # 自动检测,仅支持 Docker + CUDA 环境
38
  # Qwen3-14B-AWQ评估质量差,因为基于instruct版本而不是base版本
run.py CHANGED
@@ -44,7 +44,7 @@ def _parse_args():
44
  "--logits_gradient_submode",
45
  default="fill_blank",
46
  choices=["count", "match_score", "fill_blank"],
47
- help="logits_gradient 子策略:count=数量;match_score=相关度打分;fill_blank=填空式",
48
  )
49
  parser.add_argument(
50
  "--gradient_checkpointing",
 
44
  "--logits_gradient_submode",
45
  default="fill_blank",
46
  choices=["count", "match_score", "fill_blank"],
47
+ help="logits_gradient 子策略:count=数量;match_score=相关度打分(已废弃);fill_blank=填空式",
48
  )
49
  parser.add_argument(
50
  "--gradient_checkpointing",
scripts/cases/eval_cases_long.json CHANGED
@@ -1,11 +1,112 @@
1
  [
2
- {"name": "人工智能", "query": "人工智能", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,「新美联储通讯社」预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是「首选」,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
3
- {"name": "股票", "query": "股票", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,「新美联储通讯社」预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是「首选」,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
4
- {"name": "墨西哥", "query": "墨西哥", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,「新美联储通讯社」预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是「首选」,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
5
- {"name": "美联储", "query": "美联储", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,新美联储通讯社预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是首选,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
6
- {"name": "航天", "query": "航天", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,「新美联储通讯社」预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是「首选」,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
7
- {"name": "玩具模型_无关", "query": "玩具模型", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,「新美联储通讯社」预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是「首选」,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
8
- {"name": "爱情电影_无关", "query": "爱情电影", "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,「新美联储通讯社」预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是「首选」,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"},
9
- {"name": "北京美食", "query": "北京的美食", "text": "北京烤鸭是北京最著名的特色美食,皮酥肉嫩,配上薄饼和甜面酱。\n故宫是明清两代的皇家宫殿,也是世界上现存规模最大的木质结构古建筑群。\n炸酱面是北京的传统面食,用黄酱配上黄瓜丝和豆芽菜。\n长城是中国古代的军事防御工程,绵延数千公里。\n老北京涮羊肉以铜锅为特色,羊肉鲜嫩,蘸料丰富。\n天坛是明清两代皇帝祭天的场所,建筑精美。\n豆汁儿是北京独特的传统小吃,口味特别,配上焦圈最地道。\n颐和园是清朝的皇家园林,以昆明湖和万寿山为主体。\n南京鸭血粉丝汤是南京最著名的特色美食。\n但是南京的盐水鸭就不好吃了。不喜欢它的颜色和味道。\n苏州的美食臊子面也挺好吃的。"},
10
- {"name": "北京景点", "query": "北京的景点", "text": "北京烤鸭是北京最著名的特色美食皮酥肉嫩,配上薄饼甜面酱。\n故宫是明清两代的皇家宫殿也是世界上现存规模最大的木质结构古建筑群。\n炸酱面是北京的传统面食用黄酱配上黄瓜丝和豆芽菜。\n长城中国古代的军事防御工程绵延数千公里。\n老北京涮羊肉以铜锅为特色羊肉鲜嫩,蘸料丰富。\n天坛是明清两代皇帝祭天的场所,建筑精美。\n豆汁儿是北京独特的传统小吃口味特别,配上焦圈最地道。\n颐和园是清朝的皇家园林以昆明湖和万寿山为主体。\n南京鸭血粉丝汤是南京最著名的特色美食。\n但是南京的盐水鸭就不好吃了不喜欢它的颜色和味道。\n苏州的美食臊子面也挺好吃的。"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  ]
 
1
  [
2
+ {
3
+ "name": "人工智能",
4
+ "query": "人工智能",
5
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,新美联储通讯社预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是首选,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
6
+ },
7
+ {
8
+ "name": "股票",
9
+ "query": "股票",
10
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平纳指道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将“首选”伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%PPI同比降幅收窄至1.4%。\n载人登月又一里程碑长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线 (来自华尔街见闻)"
11
+ },
12
+ {
13
+ "name": "墨西哥",
14
+ "query": "墨西哥",
15
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
16
+ },
17
+ {
18
+ "name": "美联储",
19
+ "query": "美联储",
20
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,���新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
21
+ },
22
+ {
23
+ "name": "航天",
24
+ "query": "航天",
25
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
26
+ },
27
+ {
28
+ "name": "玩具模型_无关",
29
+ "query": "玩具模型",
30
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
31
+ },
32
+ {
33
+ "name": "爱情电影_无关",
34
+ "query": "爱情电影",
35
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
36
+ },
37
+ {
38
+ "name": "经济以外",
39
+ "query": "与经济无关的内容",
40
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要���应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
41
+ },
42
+ {
43
+ "name": "AI以外",
44
+ "query": "与AI无关的内容",
45
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
46
+ },
47
+ {
48
+ "name": "政策",
49
+ "query": "政策",
50
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
51
+ },
52
+ {
53
+ "name": "股票指数",
54
+ "query": "股票指数",
55
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
56
+ },
57
+ {
58
+ "name": "经济数据",
59
+ "query": "经济数据",
60
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
61
+ },
62
+ {
63
+ "name": "坏消息",
64
+ "query": "坏消息",
65
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
66
+ },
67
+ {
68
+ "name": "利空消息",
69
+ "query": "利空消息",
70
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
71
+ },
72
+ {
73
+ "name": "公司利空",
74
+ "query": "公司的利空消息",
75
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
76
+ },
77
+ {
78
+ "name": "比预期差",
79
+ "query": "比预期差",
80
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
81
+ },
82
+ {
83
+ "name": "公司名",
84
+ "query": "公司名",
85
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
86
+ },
87
+ {
88
+ "name": "国家名",
89
+ "query": "国家名",
90
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
91
+ },
92
+ {
93
+ "name": "明示反义词",
94
+ "query": "明示的反义词",
95
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征���号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
96
+ },
97
+ {
98
+ "name": "苹果水果_无关",
99
+ "query": "苹果(水果)",
100
+ "text": "【华尔街见闻早餐 | 2026年2月12日】标普500指数基本持平,纳指和道指小幅下跌;原油期货上涨;黄金、白银走高;镍价升至近两周来最高,主要供应国印尼暗示今年将大幅削减产量。\n美国1月非农新增就业13万人,创去年4月以来最大增幅,失业率降至4.3%,年度下修86.2万。华尔街预计首次降息延至7月,“新美联储通讯社”预计降息暂停期更久。\n油价日内涨超2%,报道:特朗普私下考虑退出《美墨加协定》。\n特朗普称同伊朗达成协议将是“首选”,伊朗最高领袖顾问:美国趋向理性。\n李强:全面推进人工智能科技创新、产业发展和赋能应用,培育壮大新质生产力。\n国务院国资委推动中央企业积极扩大算力有效投资。\n中国1月CPI同比涨幅回落至0.2%,PPI同比降幅收窄至1.4%。\n载人登月又一里程碑,长征十号与梦舟飞船首次飞行试验任务成功。\nDeepSeek正灰度测试新一代模型。\n智谱发布新一代旗舰模型GLM-5,重点提升编程与智能体能力。\n苹果新Siri发布或又推迟,据称测试暴露问题,部分功能或延至9月上线。 (来自华尔街见闻)"
101
+ },
102
+ {
103
+ "name": "北京美食",
104
+ "query": "北京的美食",
105
+ "text": "北京烤鸭是北京最著名的特色美食,皮酥肉嫩,配上薄饼和甜面酱。\n故宫是明清两代的皇家宫殿,也是世界上现存规模最大的木质结构古建筑群。\n炸酱面是北京的传统面食,用黄酱配上黄瓜丝和豆芽菜。\n长城是中国古代的军事防御工程,绵延数千公里。\n老北京涮羊肉以铜锅为特色,羊肉鲜嫩,蘸料丰富。\n天坛是明清两代皇帝祭天的场所,建筑精美。\n豆汁儿是北京独特的传统小吃,口味特别,配上焦圈最地道。\n颐和园是清朝的皇家园林,以昆明湖和万寿山为主体。\n南京鸭血粉丝汤是南京最著名的特色美食。\n但是南京的盐水鸭就不好吃了。不喜欢它的颜色和味道。\n苏州的美食臊子面也挺好吃的。"
106
+ },
107
+ {
108
+ "name": "北京景点",
109
+ "query": "北京的景点",
110
+ "text": "北京烤鸭是北京最著名的特色美食,皮酥肉嫩,配上薄饼和甜面酱。\n故宫是明清两代的皇家宫殿,也是世界上现存规模最大的木质结构古建筑群。\n炸酱面是北京的传统面食,用黄酱配上黄瓜丝和豆芽菜。\n长城是中国古代的军事防御工程,绵延数千公里。\n老北京涮羊肉以铜锅为特色,羊肉鲜嫩,蘸料丰富。\n天坛是明清两代皇帝祭天的场所,建筑精美。\n豆汁儿是北京独特的传统小吃,口味特别,配上焦圈最地道。\n颐和园是清朝的皇家园林,以昆明湖和万寿山为主体。\n南京鸭血粉丝汤是南京最著名的特色美食。\n但是南京的盐水鸭就不好吃了。不喜欢它的颜色和味道。\n苏州的美食臊子面也挺好吃的。"
111
+ }
112
  ]
scripts/{eval_semantic_submodes.py → eval_semantic.py} RENAMED
@@ -1,29 +1,31 @@
1
  #!/usr/bin/env python3
2
  """
3
- 五个子模式(topk_sum / count / match_score / binary / fill_blank)效果评估脚本
4
 
5
  通过 HTTP 调用 /api/analyze-semantic 接口进行评估。
6
 
 
 
7
  评估维度:
8
  1. 生成的 top10 (token和概率) 的合理性
9
- 2. token_attention score 的合理性,主要是归一化后的score的合理性(不同配置下绝对值大小无意义)
10
  3. 完全无关查询时的结果合理性
11
 
12
  用法(从项目根目录运行):
13
- python scripts/eval_semantic_submodes.py [--submode topk_sum|count|match_score|binary|fill_blank] [--output eval_result.json]
14
- python scripts/eval_semantic_submodes.py -c scripts/eval_cases_short.json scripts/eval_cases_long.json -o eval_result.json
15
- python scripts/eval_semantic_submodes.py --url http://localhost:5001
16
- python scripts/eval_semantic_submodes.py --url https://xxx.hf.space --hf-token hf_xxx
17
- export HF_TOKEN=hf_xxx && python scripts/eval_semantic_submodes.py --url https://xxx.hf.space
18
- 不指定 --submode 时依次评估五个子模式;-c 可指定多个 JSON 用例文件。
19
  """
20
 
21
  import argparse
22
  import json
23
  import os
24
  import sys
 
25
  from pathlib import Path
26
- from typing import Optional
27
 
28
  # Hugging Face Token(用于Private Space,可通过环境变量HF_TOKEN设置)
29
  HF_TOKEN_ENV = "HF_TOKEN"
@@ -49,12 +51,12 @@ TEST_CASES = [
49
  DEFAULT_API_BASE = "http://localhost:5001"
50
 
51
 
52
- def analyze_semantic_http(api_base: str, query: str, text: str, submode: str, token: Optional[str] = None, prob_weighted: Optional[bool] = None, timeout: int = 300) -> dict:
53
  """通过 HTTP 调用 analyze-semantic 接口"""
54
  url = f"{api_base.rstrip('/')}/api/analyze-semantic"
55
- payload: dict = {"query": query, "text": text, "submode": submode, "debug_info": True}
56
- if prob_weighted is not None:
57
- payload["prob_weighted"] = prob_weighted
58
  headers = {"Content-Type": "application/json"}
59
  if token:
60
  headers["Authorization"] = f"Bearer {token}"
@@ -67,25 +69,68 @@ def analyze_semantic_http(api_base: str, query: str, text: str, submode: str, to
67
  return data
68
 
69
 
70
- def run_eval(api_base: str, submode: str, test_cases: list, token: Optional[str] = None, prob_weighted: Optional[bool] = None) -> list:
 
 
 
71
  results = []
72
- for name, query, text in test_cases:
73
- print(f"\n{'='*60}")
74
- print(f"子模式: {submode} | 用例: {name}")
75
- print(f"query: {query}")
76
- print(f"text: {text[:50]}...")
77
- print("=" * 60)
78
  try:
79
- res = analyze_semantic_http(api_base, query, text, submode, token=token, prob_weighted=prob_weighted)
80
- except Exception as e:
81
- print(f"❌ 失败: {e}")
82
- results.append({
83
- "submode": submode,
84
- "case": name,
85
- "query": query,
86
- "error": str(e),
87
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  di = res.get("debug_info", {})
91
  topk_tokens = di.get("topk_tokens", [])
@@ -126,34 +171,30 @@ def run_eval(api_base: str, submode: str, test_cases: list, token: Optional[str]
126
  },
127
  }
128
  results.append(record)
 
 
 
 
 
 
129
 
130
- print(f"\n📌 top10 预测 token & 概率:")
131
- for t, p in zip(topk_tokens, topk_probs):
132
- print(f" {repr(t):20} {p*100:.2f}%")
133
- print(f"\n📌 token_attention 中 score 最高的 10 个 token (score / 0-max归一化):")
134
- for item in top_scored:
135
- print(f" {repr(item['raw']):20} score={item['score']} norm={item['score_norm']} offset={item['offset']}")
136
- print(f"\n📌 score 统计: min={record['score_stats']['min']}, max={record['score_stats']['max']}, mean={record['score_stats']['mean']}, mean_norm={record['score_stats']['mean_norm']}")
137
- if record.get("full_match_degree") is not None:
138
- print(f"📌 full_match_degree: {record['full_match_degree']}")
139
-
140
- return results
141
 
142
 
143
  def main():
144
- parser = argparse.ArgumentParser(description="评估 semantic analyzer 五个子模式效果(HTTP)")
145
  parser.add_argument(
146
  "--submode",
147
- choices=["topk_sum", "count", "match_score", "binary", "fill_blank"],
148
  nargs="+",
149
  default=None,
150
- help="指定子模式(可多个),不指定则依次评估五个",
151
  )
152
  parser.add_argument(
153
  "--output", "-o",
154
  type=Path,
155
  default=None,
156
- help="结果输出 JSON 路径",
157
  )
158
  parser.add_argument(
159
  "--url",
@@ -166,12 +207,6 @@ def main():
166
  default=None,
167
  help=f"Hugging Face Token(用于Private Space,也可通过环境变量{HF_TOKEN_ENV}设置)",
168
  )
169
- parser.add_argument(
170
- "--timeout",
171
- type=int,
172
- default=300,
173
- help="请求超时秒数",
174
- )
175
  parser.add_argument(
176
  "--cases", "-c",
177
  type=Path,
@@ -180,11 +215,16 @@ def main():
180
  help="自定义测试用例 JSON 文件,可指定多个,格式 [{name, query, text}, ...]",
181
  )
182
  parser.add_argument(
183
- "--prob-weighted",
184
- choices=["true", "false"],
185
- default=None,
186
- metavar="true|false",
187
- help="count/fill_blank 时是否按概率加权,仅 HTTP 测试用",
 
 
 
 
 
188
  )
189
  args = parser.parse_args()
190
 
@@ -195,20 +235,29 @@ def main():
195
  test_cases = []
196
  for path in args.cases:
197
  raw = json.loads(path.read_text(encoding="utf-8"))
198
- test_cases.extend([(c["name"], c["query"], c["text"]) for c in raw])
 
199
  print(f"已加载 {len(test_cases)} 个用例,来自 {len(args.cases)} 个文件")
200
  else:
201
  test_cases = TEST_CASES
202
 
203
- submodes = args.submode if args.submode else ["topk_sum", "count", "match_score", "binary", "fill_blank"]
204
- prob_weighted = {"true": True, "false": False}.get(args.prob_weighted) if args.prob_weighted else None
205
- all_results = []
 
 
 
 
206
  for sm in submodes:
207
- all_results.extend(run_eval(api_base, sm, test_cases, token=hf_token, prob_weighted=prob_weighted))
208
-
 
 
 
 
 
209
  if args.output:
210
- args.output.write_text(json.dumps(all_results, ensure_ascii=False, indent=2), encoding="utf-8")
211
- print(f"\n✅ 结果已写入 {args.output}")
212
 
213
 
214
  if __name__ == "__main__":
 
1
  #!/usr/bin/env python3
2
  """
3
+ Semantic analyzer 效果评估脚本
4
 
5
  通过 HTTP 调用 /api/analyze-semantic 接口进行评估。
6
 
7
+ 支持 submode:count / match_score(已废弃) / fill_blank
8
+
9
  评估维度:
10
  1. 生成的 top10 (token和概率) 的合理性
11
+ 2. token_attention score 的合理性
12
  3. 完全无关查询时的结果合理性
13
 
14
  用法(从项目根目录运行):
15
+ python scripts/eval_semantic.py -c scripts/cases/eval_cases_short.json -o eval_result.jsonl
16
+ python scripts/eval_semantic.py --submode count fill_blank -o eval_result.jsonl
17
+ python scripts/eval_semantic.py --url http://localhost:5001
18
+
19
+ 输出为 JSONL 格式,每完成一例追加一行;中断后可再次运行,从中断处续跑。
 
20
  """
21
 
22
  import argparse
23
  import json
24
  import os
25
  import sys
26
+ import time
27
  from pathlib import Path
28
+ from typing import Optional, Tuple
29
 
30
  # Hugging Face Token(用于Private Space,可通过环境变量HF_TOKEN设置)
31
  HF_TOKEN_ENV = "HF_TOKEN"
 
51
  DEFAULT_API_BASE = "http://localhost:5001"
52
 
53
 
54
+ def analyze_semantic_http(api_base: str, query: str, text: str, submode: Optional[str] = None, token: Optional[str] = None, timeout: int = 300) -> dict:
55
  """通过 HTTP 调用 analyze-semantic 接口"""
56
  url = f"{api_base.rstrip('/')}/api/analyze-semantic"
57
+ payload: dict = {"query": query, "text": text, "debug_info": True}
58
+ if submode is not None:
59
+ payload["submode"] = submode
60
  headers = {"Content-Type": "application/json"}
61
  if token:
62
  headers["Authorization"] = f"Bearer {token}"
 
69
  return data
70
 
71
 
72
+ def _load_jsonl(path: Path) -> list:
73
+ """加载 JSONL 文件,用于断点续跑"""
74
+ if not path.exists():
75
+ return []
76
  results = []
77
+ for line in path.read_text(encoding="utf-8").strip().split("\n"):
78
+ if not line:
79
+ continue
 
 
 
80
  try:
81
+ results.append(json.loads(line))
82
+ except json.JSONDecodeError:
83
+ pass
84
+ return results
85
+
86
+
87
+ def _append_record(path: Path, record: dict) -> None:
88
+ """追加单条记录到 JSONL 文件"""
89
+ with path.open("a", encoding="utf-8") as f:
90
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
91
+
92
+
93
+ def run_eval(
94
+ api_base: str,
95
+ submode: str,
96
+ test_cases: list,
97
+ token: Optional[str] = None,
98
+ output_path: Optional[Path] = None,
99
+ all_results: Optional[list] = None,
100
+ completed: Optional[set] = None,
101
+ max_retries: int = 3,
102
+ timeout: int = 300,
103
+ ) -> Tuple[list, bool]:
104
+ """返回 (results, aborted),重试后仍失败时 aborted 为 True"""
105
+ completed = completed or set()
106
+ results = []
107
+ for j, (name, query, text) in enumerate(test_cases):
108
+ prog = f"[{j+1}/{len(test_cases)}]"
109
+ if (submode, name) in completed:
110
+ print(f"{prog} ⏭ 跳过: {submode} | {name}", flush=True)
111
  continue
112
+ print(f"{prog} 执行: {submode} | {name}", flush=True)
113
+ res = None
114
+ last_error = None
115
+ for attempt in range(max_retries + 1):
116
+ try:
117
+ res = analyze_semantic_http(api_base, query, text, submode, token=token, timeout=timeout)
118
+ break
119
+ except Exception as e:
120
+ last_error = e
121
+ if attempt < max_retries:
122
+ wait = 3 * (attempt + 1)
123
+ print(f"{prog} 重试 {attempt + 1}/{max_retries},{wait}s 后... - {e}", flush=True)
124
+ time.sleep(wait)
125
+ if res is None:
126
+ print(f"{prog} ✗ 失败(已重试 {max_retries} 次): {submode} | {name} - {last_error}", flush=True)
127
+ record = {"submode": submode, "case": name, "query": query, "error": str(last_error)}
128
+ results.append(record)
129
+ if all_results is not None:
130
+ all_results.append(record)
131
+ completed.add((submode, name))
132
+ print(f"\n⚠ 重试后仍失败,中断后续用例", flush=True)
133
+ return results, True
134
 
135
  di = res.get("debug_info", {})
136
  topk_tokens = di.get("topk_tokens", [])
 
171
  },
172
  }
173
  results.append(record)
174
+ if all_results is not None:
175
+ all_results.append(record)
176
+ completed.add((submode, name))
177
+ if output_path:
178
+ _append_record(output_path, record)
179
+ print(f"{prog} ✓ 完成: {submode} | {name}", flush=True)
180
 
181
+ return results, False
 
 
 
 
 
 
 
 
 
 
182
 
183
 
184
  def main():
185
+ parser = argparse.ArgumentParser(description="评估 semantic analyzer 效果(HTTP)")
186
  parser.add_argument(
187
  "--submode",
188
+ choices=["count", "match_score", "fill_blank"],
189
  nargs="+",
190
  default=None,
191
+ help="instruct 模型子模式(可多个),不指定则依次评估 count/fill_blank;match_score 已废弃",
192
  )
193
  parser.add_argument(
194
  "--output", "-o",
195
  type=Path,
196
  default=None,
197
+ help="结果输出 JSONL 路径(支持断点续跑)",
198
  )
199
  parser.add_argument(
200
  "--url",
 
207
  default=None,
208
  help=f"Hugging Face Token(用于Private Space,也可通过环境变量{HF_TOKEN_ENV}设置)",
209
  )
 
 
 
 
 
 
210
  parser.add_argument(
211
  "--cases", "-c",
212
  type=Path,
 
215
  help="自定义测试用例 JSON 文件,可指定多个,格式 [{name, query, text}, ...]",
216
  )
217
  parser.add_argument(
218
+ "--retries",
219
+ type=int,
220
+ default=3,
221
+ help="失败时自动重试次数,默认 3",
222
+ )
223
+ parser.add_argument(
224
+ "--timeout",
225
+ type=int,
226
+ default=300,
227
+ help="单次请求超时秒数,默认 300",
228
  )
229
  args = parser.parse_args()
230
 
 
235
  test_cases = []
236
  for path in args.cases:
237
  raw = json.loads(path.read_text(encoding="utf-8"))
238
+ # strip() 与浏览器语义分析时的 trim() 保持一致,避免 token 数差异
239
+ test_cases.extend([(c["name"], c["query"], (c["text"] or "").strip()) for c in raw])
240
  print(f"已加载 {len(test_cases)} 个用例,来自 {len(args.cases)} 个文件")
241
  else:
242
  test_cases = TEST_CASES
243
 
244
+ submodes = args.submode if args.submode else ["count", "match_score", "fill_blank"]
245
+ all_results: list = []
246
+ completed: set = set()
247
+ if args.output and args.output.exists():
248
+ all_results = _load_jsonl(args.output)
249
+ completed = {(r["submode"], r["case"]) for r in all_results}
250
+ print(f"已加载 {len(all_results)} 条历史结果,从中断处续跑")
251
  for sm in submodes:
252
+ _, aborted = run_eval(
253
+ api_base, sm, test_cases, token=hf_token,
254
+ output_path=args.output, all_results=all_results,
255
+ completed=completed, max_retries=args.retries, timeout=args.timeout,
256
+ )
257
+ if aborted:
258
+ break
259
  if args.output:
260
+ print(f"\n✅ 结果已写入 {args.output}(共 {len(all_results)} 条)")
 
261
 
262
 
263
  if __name__ == "__main__":
server.yaml CHANGED
@@ -472,7 +472,7 @@ paths:
472
  submode:
473
  type: string
474
  enum: [count, match_score, fill_blank]
475
- description: 可选子模式,不传则用服务端默认
476
  required:
477
  - query
478
  - text
 
472
  submode:
473
  type: string
474
  enum: [count, match_score, fill_blank]
475
+ description: 可选子模式,不传则用服务端默认。match_score 已废弃
476
  required:
477
  - query
478
  - text