Showing
3 changed files
with
42 additions
and
3 deletions
| @@ -183,8 +183,17 @@ swot_item_schema: Dict[str, Any] = { | @@ -183,8 +183,17 @@ swot_item_schema: Dict[str, Any] = { | ||
| 183 | "detail": {"type": "string"}, | 183 | "detail": {"type": "string"}, |
| 184 | "description": {"type": "string"}, | 184 | "description": {"type": "string"}, |
| 185 | "evidence": {"type": "string"}, | 185 | "evidence": {"type": "string"}, |
| 186 | - "impact": {"type": "string"}, | ||
| 187 | - "score": {"type": ["number", "string"]}, | 186 | + "impact": { |
| 187 | + "type": "string", | ||
| 188 | + "enum": ["低", "中低", "中", "中高", "高", "极高"], | ||
| 189 | + "description": "影响评级,只允许填写:低/中低/中/中高/高/极高", | ||
| 190 | + }, | ||
| 191 | + "score": { | ||
| 192 | + "type": "number", | ||
| 193 | + "minimum": 0, | ||
| 194 | + "maximum": 10, | ||
| 195 | + "description": "评分,只允许0-10的数字", | ||
| 196 | + }, | ||
| 188 | "priority": {"type": ["string", "number"]}, | 197 | "priority": {"type": ["string", "number"]}, |
| 189 | }, | 198 | }, |
| 190 | "required": [], | 199 | "required": [], |
| @@ -147,6 +147,9 @@ class IRValidator: | @@ -147,6 +147,9 @@ class IRValidator: | ||
| 147 | for idx, entry in enumerate(entries): | 147 | for idx, entry in enumerate(entries): |
| 148 | self._validate_swot_item(entry, f"{path}.{name}[{idx}]", errors) | 148 | self._validate_swot_item(entry, f"{path}.{name}[{idx}]", errors) |
| 149 | 149 | ||
| 150 | + # SWOT impact 字段允许的评级值 | ||
| 151 | + ALLOWED_IMPACT_VALUES = {"低", "中低", "中", "中高", "高", "极高"} | ||
| 152 | + | ||
| 150 | def _validate_swot_item(self, item: Any, path: str, errors: List[str]): | 153 | def _validate_swot_item(self, item: Any, path: str, errors: List[str]): |
| 151 | """单个SWOT条目支持字符串或带字段的对象""" | 154 | """单个SWOT条目支持字符串或带字段的对象""" |
| 152 | if isinstance(item, str): | 155 | if isinstance(item, str): |
| @@ -165,6 +168,33 @@ class IRValidator: | @@ -165,6 +168,33 @@ class IRValidator: | ||
| 165 | if title is None: | 168 | if title is None: |
| 166 | errors.append(f"{path} 缺少 title/label/text/description 等文字字段") | 169 | errors.append(f"{path} 缺少 title/label/text/description 等文字字段") |
| 167 | 170 | ||
| 171 | + # 校验 impact 字段:只允许评级值 | ||
| 172 | + impact = item.get("impact") | ||
| 173 | + if impact is not None: | ||
| 174 | + if not isinstance(impact, str) or impact not in self.ALLOWED_IMPACT_VALUES: | ||
| 175 | + errors.append( | ||
| 176 | + f"{path}.impact 只允许填写影响评级(低/中低/中/中高/高/极高)," | ||
| 177 | + f"当前值: {impact};如需详细说明请写入 detail 字段" | ||
| 178 | + ) | ||
| 179 | + | ||
| 180 | + # 校验 score 字段:只允许 0-10 的数字 | ||
| 181 | + score = item.get("score") | ||
| 182 | + if score is not None: | ||
| 183 | + valid_score = False | ||
| 184 | + if isinstance(score, (int, float)): | ||
| 185 | + valid_score = 0 <= score <= 10 | ||
| 186 | + elif isinstance(score, str): | ||
| 187 | + # 兼容字符串形式的数字 | ||
| 188 | + try: | ||
| 189 | + numeric_score = float(score) | ||
| 190 | + valid_score = 0 <= numeric_score <= 10 | ||
| 191 | + except ValueError: | ||
| 192 | + valid_score = False | ||
| 193 | + if not valid_score: | ||
| 194 | + errors.append( | ||
| 195 | + f"{path}.score 只允许填写 0-10 的数字,当前值: {score}" | ||
| 196 | + ) | ||
| 197 | + | ||
| 168 | def _validate_blockquote_block( | 198 | def _validate_blockquote_block( |
| 169 | self, block: Dict[str, Any], path: str, errors: List[str] | 199 | self, block: Dict[str, Any], path: str, errors: List[str] |
| 170 | ): | 200 | ): |
| @@ -304,7 +304,7 @@ SYSTEM_PROMPT_CHAPTER_JSON = f""" | @@ -304,7 +304,7 @@ SYSTEM_PROMPT_CHAPTER_JSON = f""" | ||
| 304 | 3. 所有段落都放入paragraph.inlines,混排样式通过marks表示(bold/italic/color/link等)。 | 304 | 3. 所有段落都放入paragraph.inlines,混排样式通过marks表示(bold/italic/color/link等)。 |
| 305 | 4. 所有heading必须包含anchor,锚点与编号保持模板一致,比如section-2-1。 | 305 | 4. 所有heading必须包含anchor,锚点与编号保持模板一致,比如section-2-1。 |
| 306 | 5. 表格需给出rows/cells/align,KPI卡请使用kpiGrid,分割线用hr。 | 306 | 5. 表格需给出rows/cells/align,KPI卡请使用kpiGrid,分割线用hr。 |
| 307 | -6. SWOT分析必须优先使用 block.type="swotTable":分别填写 strengths/weaknesses/opportunities/threats 数组,单项至少包含 title/label/text 之一,可附加 detail/evidence/impact/score 字段;title/summary 字段用于概览说明。 | 307 | +6. SWOT分析必须优先使用 block.type="swotTable":分别填写 strengths/weaknesses/opportunities/threats 数组,单项至少包含 title/label/text 之一,可附加 detail/evidence/impact/score 字段;title/summary 字段用于概览说明。**特别注意:impact 字段只允许填写影响评级("低"/"中低"/"中"/"中高"/"高"/"极高"),score 字段只允许填写 0-10 的数字;任何关于影响的文字叙述、详细说明、佐证或扩展描述必须写入 detail 字段,禁止在 impact 字段中混入描述性文字。** |
| 308 | 7. 如需引用图表/交互组件,统一用widgetType表示(例如chart.js/line、chart.js/doughnut)。 | 308 | 7. 如需引用图表/交互组件,统一用widgetType表示(例如chart.js/line、chart.js/doughnut)。 |
| 309 | 8. 鼓励结合outline中列出的子标题,生成多层heading与细粒度内容,同时可补充callout、blockquote等。 | 309 | 8. 鼓励结合outline中列出的子标题,生成多层heading与细粒度内容,同时可补充callout、blockquote等。 |
| 310 | 9. engineQuote 仅用于呈现单Agent的原话:使用 block.type="engineQuote",engine 取值 insight/media/query,title 必须固定为对应Agent名字(insight->Insight Agent,media->Media Agent,query->Query Agent,不可自定义),内部 blocks 只允许 paragraph,paragraph.inlines 的 marks 仅可使用 bold/italic(可留空),禁止在 engineQuote 中放表格/图表/引用/公式等;当 reports 或 forumLogs 中有明确的文字段落、结论、数字/时间等可直接引用时,优先分别从 Query/Media/Insight 三个 Agent 摘出关键原文或文字版数据放入 engineQuote,尽量覆盖三类 Agent 而非只用单一来源,严禁臆造内容或把表格/图表改写进 engineQuote。 | 310 | 9. engineQuote 仅用于呈现单Agent的原话:使用 block.type="engineQuote",engine 取值 insight/media/query,title 必须固定为对应Agent名字(insight->Insight Agent,media->Media Agent,query->Query Agent,不可自定义),内部 blocks 只允许 paragraph,paragraph.inlines 的 marks 仅可使用 bold/italic(可留空),禁止在 engineQuote 中放表格/图表/引用/公式等;当 reports 或 forumLogs 中有明确的文字段落、结论、数字/时间等可直接引用时,优先分别从 Query/Media/Insight 三个 Agent 摘出关键原文或文字版数据放入 engineQuote,尽量覆盖三类 Agent 而非只用单一来源,严禁臆造内容或把表格/图表改写进 engineQuote。 |
-
Please register or login to post a comment