- 人工智能
- 大模型
- AI Agent
- RAG
- 深度研究
- 搜索引擎
- 后端
- 代码智能体
【免费下载链接】deepsearch
openJiuwen DeepSearch是一款知识增强的深度搜索与研究框架,有业界领先的片段级引用和溯源推理能力,提供精准Agentic搜索与研究能力
导读
本文深入剖析 openJiuwen DeepSearch 报告中「子小节可视化数据单位归一化」提示词模板 system.md 及其配套 user.md。该提示词是报告生成链路中图表数据从「原始抽取」到「可渲染归一化」的关键一环:它要求 LLM 将来自不同来源、携带不同量纲(如 万、亿、Thousand、Million)的数值记录统一为同一基准单位与全局显示刻度,并输出严格的 JSON。读完本文,你将掌握该提示词的完整规则体系、5 步执行流程、输入输出契约,以及它在 visualization.py 中的实际调用链、服务端 schema 校验与本地快速路径的源码实现。
一、提示词在报告链路中的定位
1.1 两级可视化数据流水线
openJiuwen DeepSearch 的子报告可视化生成遵循「先抽取、再归一化、后渲染」的两级流水线:
- 抽取阶段:
sub_section_visualization_content提示词从章节原始文本(origin_content)中抽取可制图的结构化数据,输出形如["x_or_category", "value_string", "unit_string"]的三元组记录。此阶段允许保留原始量纲差异(例如 "yuan" 与 "10k yuan"、万辆与万元)。 - 归一化阶段:本文主角
sub_section_visualization_normalize_units提示词负责把上一步输出中量纲不统一、刻度混杂的记录,统一为同一基准单位 + 单一全局显示刻度,最终输出可直接喂给 Mermaid 生成器的干净 JSON。
这一分工在抽取提示词 sub_section_visualization_content/system.md 中有明确说明:"Simple scale variants of the same base unit are allowed when copied verbatim fromorigin_content, for example 'vehicle' vs '10k vehicles', 'yuan' vs '10k yuan', 'USD' vs 'million USD'. The later normalization step will unify scales."——即抽取阶段刻意保留量纲差异,由归一化阶段统一。
1.2 模板加载机制
与仓库中所有提示词一样,该提示词通过统一的消息构建器加载渲染。在 message_builder.py 中,build_prompt_messages(prompt_name, context)会:
- 加载
prompts/<prompt_name>/system.md作为system消息,并做静态模板树校验(system 模板不允许含运行时变量,见_assert_static_template_tree); - 加载
prompts/<prompt_name>/user.md,用传入的context变量(通过 Jinja2)渲染为user消息; - 若模板缺失或渲染失败,抛出
CustomValueException对应的状态码。
提示词契约测试 test_deepresearch_prompt_contracts.py 中登记了该模板的变量契约:"sub_section_visualization_normalize_units": ("language", "records_json"),即调用方只需提供这两个变量。
二、输入输出契约
2.1 输入格式(user.md)
user.md 全文极简,只有一行模板:
Input format: language: {{language}}, records_json: {{records_json}}两个变量均由调用方注入:
| 变量 | 类型 | 含义 | 源码默认值 |
|---|---|---|---|
language | str | 报告语言,如zh-CN、en-US | 调用点默认"zh-CN" |
records_json | str | 抽取阶段的 JSON 字符串 | 由抽取结果序列化而来 |
在 visualization.py 中,调用方这样构造上下文:
records_json = json.dumps({"records": extracted_records}, ensure_ascii=False) normalize_context = { "language": visualization_dict.get("language", "zh-CN"), "records_json": records_json, } normalize_input = build_prompt_messages( "sub_section_visualization_normalize_units", normalize_context )即records_json必须是{"records": [[x_or_category, value_string, unit_string], ...]}结构。
2.2 输出 Schema(固定)
system.md 中定义输出必须是且只能是如下结构:
{ "unit": "string", "records": [ ["category1", 123], ["category2", 456.78] ] }关键约束:
records中每个元素是[x_or_category, 数值]二元组,数值必须是合法的 JSON number(不能是 NaN、Infinity,不能是科学计数法);unit是归一化后的统一单位字符串;- 输出只能是纯 JSON,不允许额外文本、空格、换行、注释或 markdown 代码块;
- 若输入
records_json为{}(空对象),直接输出{}; - 若任何一步校验失败,输出
{}(由下游代码决定是否重试)。
这一 schema 与服务端校验函数validate_visualization_normalization_schema严格对应,见下文 5.2 节。
三、角色定义与核心目标
system.md 将模型角色定义为"High-Precision Unit & Scale Normalization Engine"(高精度单位与刻度归一化引擎),并强调是 "a strict, deterministic engine"——即要求模型扮演严格、确定性的处理引擎,而非自由发挥的写作助手。
其核心目标(Core Purpose)分四步:
- 解析并校验所有输入值与单位;
- 将所有数值转换到共同基准单位(消除 万、亿、Thousand、Million 等刻度差异);
- 基于最大绝对值与语言选择一个最优的全局显示刻度;
- 输出单位一致、数值已按刻度缩放的干净归一化 JSON。
四、全局规则(Strict Global Rules)
system.md 列出的全局规则是归一化质量的硬约束,逐条展开:
- 保留原始顺序与类别:
x_or_category及记录顺序不得改动、不得新增、不得删除(对应源码中"record count unchanged (prompt contract)"的强校验,见 5.3 节); - 禁止捏造:不编造数据、不推断缺失值、不给没有单位的记录默认单位;
- 数值合法性:所有最终值必须是合法 JSON number(无 NaN、Infinity、科学计数法);
- 舍入规则唯一:分数/比率类数值保留 2 位小数,除此之外不允许任何其他舍入;
- 输出纯净性:只输出合法 JSON,无多余文本、空格、换行、注释或 markdown;
- 失败即空:任何一步校验失败,输出
{}。
五、5 步执行流程(Strict Order)
system.md 规定了严格顺序的 5 步执行流程,这是全文的技术核心,逐层拆解如下。
Step 1:解析与校验数值/单位
- 合法数值形式:纯数字、带千分位逗号的数字(如
1,286.6)、分数(a/b)、比率(a:b); - value_string 中禁止出现:
~、约、≥、>、≤、<、大概以及任何非结构化的附加文本; - 单位字符串:trim 后不得为空;允许货币符号(
¥、$等); - 任一检查失败 → 输出
{}。
Step 2:统一基准单位并计算总刻度乘数
这是最核心的一步,system.md 给出统一刻度乘数表:
| 刻度 token | 乘数 |
|---|---|
| 千 / Thousand | 1000 |
| 万 | 10000 |
| 百万 / Million | 1000000 |
| 千万 | 10000000 |
| 亿 | 100000000 |
| Billion | 1000000000 |
| 无 / None | 1 |
处理流程:
- 标准化空白:trim 首尾空格,连续空格合并为一个;
- 抽取所有刻度 token:从
unit_string中提取全部已定义的刻度 token,支持任意组合(如百万亿、千万亿这类复合刻度); - 累乘:将所有抽取刻度的乘数相乘,得到该记录的总刻度乘数(total scale multiplier);
- 剩余部分作基准单位:移除所有刻度 token 后,剩余部分标准化为基准单位;全部记录必须共享同一规范基准单位(拉丁字符忽略大小写);
- 标准单位映射:
RMB/CNY/¥/人民币/元 → 元USD/US$/$/美元 → USD%/百分比 → %
- 任一检查失败 → 输出
{}。
Step 3:转换为基准单位数值
- 基准单位值 = 解析后的数值 × 总刻度乘数;
- 若任一结果为 NaN/Infinity → 输出
{}。
Step 4:选择全局显示刻度与单位
- 若基准单位是
%,直接使用%且不带刻度; - 否则按最大绝对值选择显示刻度,且规则随语言不同:
| 语言 | 阈值区间 | 显示刻度 |
|---|---|---|
| 中文 | < 10000 | 无 |
| 中文 | 10000 ≤ x < 100000000 | 万 |
| 中文 | ≥ 100000000 | 亿 |
| 英文 | < 1000 | None |
| 英文 | 1000 ≤ x < 1000000 | Thousand |
| 英文 | 1000000 ≤ x < 1000000000 | Million |
| 英文 | ≥ 1000000000 | Billion |
- 最终单位格式:
- 中文:
[刻度][基准单位],例如万元、亿元; - 英文:
[刻度] [基准单位],例如Thousand USD。
- 中文:
Step 5:转换为最终显示值
- 最终值 = 基准单位值 ÷ 显示刻度乘数;
- 分数/比率保持恰好 2 位小数;
- 若任一最终值需要科学计数法表示 → 输出
{}。
六、源码级实现证据
6.1 调用链与重试机制
在 visualization.py 中,_normalize_visualization_content是归一化提示词的直接调用方。完整链路为:
_generate_content_for_visualization └─ _process_visualization_task └─ _extract_visualization_data(抽取 + 溯源 + 合规校验) └─ _build_visualization_mermaid └─ _normalize_visualization_content ├─ timeline 特殊处理(直接转 schema) ├─ _normalize_same_unit_records_locally(本地快速路径) └─ build_prompt_messages("sub_section_visualization_normalize_units", ...)(LLM 归一化) └─ _generate_mermaid_code → _precheck_value_variation归一化调用发生在抽取 schema 校验通过之后。调用时以AgentLlmName.SUB_REPORTER_VISUALIZATION_NORMALIZE(sub_reporter_visualization_normalize,见 node_constants.py)作为 agent 名记录 LLM 统计。
重试逻辑为for j in range(max_attempt_num)(默认max_attempt_num = 3,来自visualization_dict.get("max_attempt_num", 3)):
- 调用 LLM 并取
content; - 用
normalize_json_output清理输出后 strip; - 若结果为
"{}"则跳过继续重试; json.loads失败则记录 warning 后继续;- 通过
validate_visualization_normalization_schema校验; - 校验记录条数与抽取记录数一致("Keep record count unchanged (prompt contract)");
- 全部通过后组装
final_obj(补上image_title与image_type),写入sub_section_visualization_content。
若全部尝试失败,置rs_success=False、error_msg="normalize_failed",下游不再生成 Mermaid。
6.2 本地快速路径:同单位记录不调 LLM
为提高效率与确定性,源码实现了本地快速路径_normalize_same_unit_records_locally(visualization.py):
- 仅当
image_type为bar/line/pie,且所有记录的单位字符串完全一致时启用; - 数值解析
_parse_visualization_number使用Decimal处理千分位逗号(兼容中英文逗号),拒绝非有限值; - 若统一单位以
万开头且最大绝对值>= 10000,自动升级为亿并除以 10000 缩放(对应提示词 Step 4 中文阈值规则); - 缩放运算
_scale_visualization_value同样用Decimal保证精度,能整除则输出int,否则输出float。
例如 test_visualization.py 中的测试用例:输入[["万达电影","647690","万元"], ...]输出{"unit": "亿元", "records": [["万达电影", 64.769], ...]}——这正是"万元→亿元"阈值升级的本地实现。
而test_visualization_normalization_uses_local_same_unit_fast_path(test_visualization.py)验证:当记录同为万辆且最大绝对值< 10000时,直接走本地路径输出unit: "万辆"、数值不做缩放,且LLM 完全不被调用(mocked_llm.assert_not_awaited())。也就是说,只有记录间单位不一致、或本地路径无法处理时,才真正触发本提示词调用 LLM。
6.3 服务端双重 schema 校验
归一化结果在写入可视化内容前,还要经过 report_utils.py 中validate_visualization_normalization_schema的严格校验:
unit必须是非空字符串,且不得包含混合单位分隔符(或、/、|、,、;、and,见_has_mixed_unit_separators);- 每条记录必须是
[str, int|float]二元组,数值必须有限(math.isfinite); - 饼图(
pie)数值不允许为负; - 该函数只接受
bar/line/pie三种类型——timeline 在归一化入口被单独转成最终 schema(unit置空,records降为二元组),不进入本提示词。
此外,抽取阶段的validate_visualization_extraction_schema(report_utils.py)在归一化之前就已经阻止了"混合/歧义单位"进入本流程:非 timeline 记录unit_string为空或含混合分隔符即判失败。
6.4 与相邻校验节点的协同
归一化只是可视化质量保障链的一环。在完整流程中,_extract_visualization_data(visualization.py)在归一化之前还会执行:
chart_data_traceability_check:校验抽取数据可回溯到原文;chart_compliance_validate:校验图表与章节大纲的相关性/合规性;- 任一失败都会把错误信息作为
retry_feedback反馈给抽取提示词重试。
归一化完成后,_precheck_value_variation会检查bar/line图数值变异度(去重后数值种类< 3则拒绝渲染,防止"平直无意义"图表),最后才由XYChartMermaidGenerator/PieChartMermaidGenerator/TimelineChartMermaidGenerator生成 Mermaid 代码(见 report_utils.py 中的生成器实现)。
七、实战注意事项与建议
基于 system.md 规则与源码实现,在使用或改造该提示词时需注意以下几点:
- language 变量驱动刻度选择:同一组数据在不同语言下会得到不同的显示刻度(
万/亿vsThousand/Million),调用方必须正确传入报告语言,否则图表单位可能与读者预期不符。 - 复合刻度的乘数逻辑:
百万亿、千万亿等复合 token 在 Step 2 中按"所有 token 乘数累乘"处理,设计上覆盖了中文里罕见的复合量纲写法;如遇此类输入,可预期数值会按 100 万亿/1000 万亿 的倍数放大。 - 分数与比率保留 2 位小数:只有分数/比率(
a/b、a:b)才允许 2 位小数舍入,普通整数/小数不得舍入——这是为了保证条形图/折线图数值不被 LLM 随意"取整美化"。 - 失败降级路径明确:归一化失败不会阻塞整个子报告,而是置
rs_success=False跳过该图;若某章节数据过于复杂(混合量纲过多),上游抽取阶段就可能已返回{}。 - 服务端 schema 是最后防线:不要信任 LLM 输出,
validate_visualization_normalization_schema+ 记录数一致性校验(len(normalized_obj.get("records", [])) != len(extracted_records))保证了进入 Mermaid 的数据结构与条数与抽取阶段严格一致。
八、小结
sub_section_visualization_normalize_units是 openJiuwen DeepSearch 报告可视化链路中承上启下的确定性引擎:它接收抽取阶段保留原始量纲的三元组记录,通过"解析校验 → 统一基准单位 → 换算基准值 → 按语言选全局刻度 → 换算显示值"的严格 5 步流程,产出单位统一、刻度最优、结构固定的 JSON。源码中 visualization.py 的同单位本地快速路径、Decimal精度控制、记录数一致性契约与 report_utils.py 的双重 schema 校验,共同保证了图表数据"可追踪、可归一、可渲染";配套测试 test_visualization.py 与提示词契约测试 test_deepresearch_prompt_contracts.py 则为这一契约提供了可回归的工程保障。理解该提示词,即可深入掌握 DeepSearch 报告图表数据从原始文本到 Mermaid 渲染之间的全部量纲处理逻辑。
- 人工智能
- 大模型
- AI Agent
- RAG
- 深度研究
- 搜索引擎
- 后端
- 代码智能体
【免费下载链接】deepsearch
openJiuwen DeepSearch是一款知识增强的深度搜索与研究框架,有业界领先的片段级引用和溯源推理能力,提供精准Agentic搜索与研究能力
相关推荐
PinchTab iFrame 自动化实战:从读取嵌入内容到表单交互的 frame scope 完整指南
PinchTab iFrame 自动化实战:从读取嵌入内容到表单交互的 frame scope 完整指南 导读 本文围绕 PinchTab 优化测试任务 Gro
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体openJiuwen DeepSearch 图表合规验证:chart_compliance_validate 提示词机制与校验规则深度解析
openJiuwen DeepSearch 图表合规验证:chart_compliance_validate 提示词机制与校验规则深度解析 导读 在 openJ
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体openJiuwen DeepSearch Markdown Mermaid 可视化全链路:图表数据抽取、单位归一化与报告插入实践指南
openJiuwen DeepSearch Markdown Mermaid 可视化全链路:图表数据抽取、单位归一化与报告插入实践指南 本文围绕 openJiu
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考