- 人工智能
- 大模型
- AI Agent
- RAG
- 深度研究
- 搜索引擎
- 后端
- 代码智能体
【免费下载链接】deepsearch
openJiuwen DeepSearch是一款知识增强的深度搜索与研究框架,有业界领先的片段级引用和溯源推理能力,提供精准Agentic搜索与研究能力
导读
本文深入剖析 openJiuwen DeepSearch(深度搜索与研究框架)中用于模板驱动研究报告大纲生成的outliner_template系统提示词,说明它如何把用户提供的<reference_report_template>报告模板转译为结构化、可被下游多智能体采集与写作消费的Outline对象。读者将掌握该提示词的角色定位与触发条件、章节契约字段(format_requirements/section_focus/focus_dimensions)、"仅保留两级标题并合并二级子标题"的映射规则、核心章节标记语义,以及从 Prompt 到函数工具调用再到Outline数据模型的完整代码链路与配置项。
关联文档:deepsearch/openjiuwen_deepsearch/algorithm/prompts/outliner_template/system.md,配套用户消息模板见 outliner_template/user.md。
一、角色定位:严格基于给定模板的结构化大纲生成器
outliner_template提示词将模型塑造成一名模板驱动的 Deep Research 大纲规划器("Your responsibility is to generate a complete research report outline strictly based on the given template")。它与普通outliner提示词的核心差异在于:
- 普通
outliner依据用户问题、反馈、检索结果自主构思报告结构; outliner_template则以用户提供的报告模板为绝对骨架,只负责把模板实例化为可执行的大纲,不改变模板结构;- 大纲必须通过函数工具(
generate_outline)返回,且每个章节随后会被分派给专门的智能体团队进行深度数据采集("each section of the outline will later be assigned to specialized agents for in-depth data collection")。
1.1 触发链路:何时启用 outliner_template
在框架主图的 OutlineNode(main_graph_nodes.py) 中,_select_prompt_name依据当前上下文选择提示词:
def _select_prompt_name(self, current_inputs: dict) -> str: report_template = current_inputs.get("report_template", "") outline_interaction_mode = current_inputs.get("outline_interaction_mode", "") feedback = current_inputs.get("user_feedback", "") if report_template and not outline_interaction_mode: return "outliner_template" # ... 其余分支:outliner_interaction / outliner_user_revised / dep_driving_outliner / outliner可见启用条件非常明确:search_context.report_template非空,且当前不在大纲交互轮次。换言之,只要用户上传/指定了报告模板且不是通过交互修订大纲,首版大纲就由outliner_template生成。模板内容来自session.get_global_state("search_context.report_template")(见 main_graph_nodes.py),并被透传进提示词上下文。
1.2 提示词输入变量契约
根据 test_deepresearch_prompt_contracts.py 中的仓库级契约,outliner_template的变量契约如下:
| 类别 | 变量 |
|---|---|
| 必填变量 | current_date、entry_search_results、language、original_query、questions、report_template、user_feedback |
| 可选变量 | current_date(由 Builder 按需注入)、original_query |
其中current_date被列入全局DATE_PROMPTS集合,message_builder.py会在提示词声明该变量时自动注入当前日期。report_template在 user.md 中通过<reference_report_template>{{ report_template }}</reference_report_template>标签注入,这正是提示词正文反复强调的"模板边界"所在。
二、核心原则:全覆盖、深度要求与模板边界
提示词在# Core Principles中定义了三条不可逾越的生成准则:
- Comprehensive Coverage(全面覆盖):大纲必须同时包含主流视角与替代视角("Mainstream + alternative perspectives"),避免单一叙事;
- Depth Requirement(深度要求):每个章节需要"详细数据点 + 多源交叉验证"("Detailed data points + multi-source verification"),杜绝浅尝辄止的章节;
- 模板边界(Template Scope):模板仅指当前用户消息中
<reference_report_template>标签内的内容。原始请求(original request)、研究问题(research question)、反馈(feedback)与入口检索结果(entry search results)都是独立上下文,不属于模板。
最后一条边界尤为重要:模型必须以用户问题/反馈提供的具体实体(如"某城市""某公司""该方法")实例化模板中的泛化术语,同时在生成的大纲中不得遗留未解析的占位符或悬空实体引用("Do not leave generic placeholders or unresolved entity references in the generated outline when the user has supplied a concrete entity")。这一约定与 prompt-template-system.md 中"模板大纲只以reference_report_template标签内的内容为模板,原始请求、反馈、检索结果属于独立上下文"的描述完全一致。
三、函数工具调用协议(STRICT):sections 必须是 JSON 数组
outliner_template对输出形态施加了强制约束:模型调用函数工具而非输出 JSON 文本,且所有工具参数必须是结构化值;其中sections必须是一个 JSON 对象数组,绝不能是字符串,也不得被引号包裹或字符串化。
这背后是 outliner.py 中create_outline_tool(section_num)定义的generate_outline工具:
card = ToolCard( id="generate_outline", name="generate_outline", description="Generating outline for a Systematic Research Report.", input_params={ "type": "object", "properties": { "language": { ... }, # 输出语言,如 'zh-CN' / 'en-US' "title": { ... }, # 最终报告标题 "thought": { ... }, # 生成大纲的详细思考 "sections": { # JSON 对象数组 "type": "array", "description": _section_list_description(section_num), "items": { "type": "object", "properties": { ... } }, }, }, "required": ["language", "title", "thought", "sections"], }, ) outline_tool = LocalFunction(card=card, func=generate_outline)在 Outliner.generate_outline 的执行链路中,LLM 返回的tool_calls会依次经过:
args字符串反序列化(json.loads(normalize_json_output(args)));normalize_sections统一解析(_parse_sections_value容忍 dict 嵌套sections字段或 JSON 字符串,但最终必须得到 list);check_tool_call严格校验:工具名匹配、args为 dict、必填参数齐全、sections为 list 且每个 section 为 dict 且必填字段非空(outliner.py)。
任何一步失败都会抛出StatusCode.OUTLINER_GENERATE_ERROR,并由 OutlineNode._do_invoke 按outliner_max_generate_outline_retry_num预算重试。
四、章节契约字段详解
提示词规定每个 section 对象必须包含以下三个契约字段:
4.1format_requirements(格式要求)
存放模板或用户请求中针对该章节的输出约束,例如:必需的表格、精确列名、行对象、逐项枚举、长度/风格规则、来源使用限制。当某章节无特定格式要求时必须使用空数组[]。
对应 search_context.py 中Section.format_requirements: List[str],并在generate_outline中经_normalize_format_requirements清洗为字符串列表(outliner.py)。
4.2section_focus(分析职责标签)
描述该章节在报告中的分析角色,必须是非空字符串。业务报告场景的示例标签包括:market_size_and_growth、vendors_and_supply、technology_drivers、risks_and_barriers、use_cases_and_commercialization、recommendation_and_ranking;非业务领域(科学、法律、医疗、教育等)应创建贴合其分析目的的标签;无更具体角色时使用兜底值section_specific_analysis。
特别约束:recommendation_and_ranking只能用于承载最终判断/推荐结论的章节,防止标签滥用。
4.3focus_dimensions(主分析维度)
非空数组,包含该章节主要负责的 1–4 个分析维度。每个维度应有且仅有一个主要归属章节,其他章节仅可将其作为辅助上下文引用,避免同一维度被多个章节重复深挖。
这些字段最终映射到 Section 模型 的section_focus与focus_dimensions,并在规划器(planner)、章节写作等下游节点继续发挥作用。
五、执行约束:模板结构优先与章节映射规则
提示词用## Execution Constraints一段集中约束了从模板到大纲的转换规则,是本文档的技术核心:
- 模板结构优先:模板结构优先于一切其他考虑("Template structure takes precedence over all other considerations");
- 禁止逐字复制
> Function:行:不得逐字复制模板中以> Function:开头的行,应改写并概括其含义; - 仅允许两级标题:最终大纲只允许 Level 1 与 Level 2 两级标题;不得为 Level 2 副标题生成独立的 Level 3 标题,必须将其合并进父级 Level 1 章节的
description中; - 描述与格式分流:实质性的 Level 2 范围与功能放进
description;表格、精确列、枚举、长度/风格、来源限制放进format_requirements; - 忽略 Level 3 及更深层级;
- 保留全部 Level 1 章节,摘要类除外:必须保留模板中所有 Level 1 章节,但显式丢弃总结性章节(如"摘要""简介""总结""结论""Summary""Conclusion""Final Remarks"),即使模板中存在;
is_core_section是不可重释的固定指令:模板中的是否核心章节字段是布尔值,必须视为固定指令,不得评估或重新解释;该规则仅作用于 Level 1 标题,子章节继承父级状态;is_core_section: false(非核心):章节必须保留,非核心不等于总结性,只有总结性章节才可删除;is_core_section: true(核心):需要收集更广泛的支撑信息,包括多视角、案例研究、数据来源。
这些规则与 report.py 中按current_outline.sections[index]读取章节标题、逐章写作的消费方式严格对齐——大纲层级一旦混乱,下游 Editor Team / Dependency Writing Team 的章节分派将无法对齐。
六、Description 格式化规范
description必须是单个字符串(非数组),并按如下规则拼接:
- 将该章节下所有 Level 2 副标题连同各自的 Function(功能概述)以项目符号列表风格串联,例如
-Subtitle: Function description; - 一律不得在
description中嵌入其他 section 对象、JSON 片段或诸如"title":、"description":、}, {、\"id\"之类的字符串。
从源码看,Section.description 正是"章节研究步骤详细说明,明确指定需要收集的数据或需要执行的编程步骤",而generate_outline直接透传该字段,因此提示词要求将其格式化为可读、无嵌套结构的纯文本列表,既保证下游规划器可解析,也避免 JSON 污染。
七、工作示例:从模板到结构化大纲 JSON
提示词内置了一个中文产业研究报告示例模板,完整展示了映射规则:
# 简介 > Function: 详细介绍研究对象的整体概况:优势、短板以及发展前景 > 是否核心章节: false # 发展概况 > Function: 提供研究对象的发展历程 > 是否核心章节: false ## 历史演进与产业基础 > Function: 详细介绍研究对象的历史发展历程,按照时间维度列举发展历程中的重要事件,并分析重要事件的标志性影响 ## 产业结构 > Function: 详细分析研究对象的核心结构(例如有哪些环节,每个环节的具体概念) ## 产业核心环节 > Function: 详细介绍产业的核心环节有哪些,并分析研究对象在这些核心环节的发展情况 # 核心环节竞争力分析 > Function: 列举核心环节,并整体分析核心环节的发展历程及标志性事件 > 是否核心章节: true ## 整车制造环节竞争力 > Function: 详细分析研究对象在整车制造环节的竞争力,例如有哪些车企,这些车企各自的详细信息,在整车制造环节的优劣 ## 关键零部件环节竞争力 > Function: 详细分析研究对象在零部件环节的竞争力,例如有哪些零部件,每种零部件的详细信息与重要性,以及当前研究对象有哪些优劣 ## 新能源技术环节竞争力 > Function: 详细分析研究对象在新能源技术环节的竞争力 # 总结 > Function: 整体总结报告上述内容 > 是否核心章节: false按照规则处理后:"简介"与"总结"被丢弃(总结性章节),Level 2 副标题被合并进父级 Level 1 的description,核心章节保留并扩充更丰富的细节。最终应调用generate_outline工具并传入如下结构化参数:
{ "language": "zh-CN", "thought": "The template emphasizes discarding summarizing sections and merging Level 2 subtitles into parent Level 1 descriptions. Core sections are preserved and expanded with richer detail.", "title": "研究报告", "sections": [ { "title": "发展概况", "description": "- 历史演进与产业基础: 详细介绍研究对象的历史发展历程,按照时间维度列举发展历程中的重要事件,并分析重要事件的标志性影响\n- 产业结构: 详细分析研究对象的核心结构(例如有哪些环节,每个环节的具体概念)\n- 产业核心环节: 详细介绍产业的核心环节有哪些,并分析研究对象在这些核心环节的发展情况", "format_requirements": [], "is_core_section": false, "section_focus": "section_specific_analysis", "focus_dimensions": ["development_history", "industry_structure", "core_segments"] }, { "title": "核心环节竞争力分析", "description": "- 整车制造环节竞争力: 详细分析研究对象在整车制造环节的竞争力,例如有哪些车企,这些车企各自的详细信息,在整车制造环节的优劣\n- 关键零部件环节竞争力: 详细分析研究对象在零部件环节的竞争力,例如有哪些零部件,每种零部件的详细信息与重要性,以及当前研究对象有哪些优劣\n- 新能源技术环节竞争力: 详细分析研究对象在新能源技术环节的竞争力", "format_requirements": [], "is_core_section": true, "section_focus": "section_specific_analysis", "focus_dimensions": ["vehicle_manufacturing", "key_components", "new_energy_technology"] } ] }注意示例中的description使用- 副标题: 功能描述的项目符号串联,且不包含任何 JSON 嵌套——这正是"Description 格式化规范"的直观体现。
八、源码链路:从工具调用到 Outline 对象
大纲工具被调用后,generate_outline(outliner.py)负责把工具参数封装为领域模型,并做三道健壮性处理:
- Section 封装与字段归一:将
title、description、format_requirements、is_core_section、section_focus、focus_dimensions、material_bindings映射为Section对象; - ID 修复:
validate_section_id_format校验 ID 必须匹配^\d+(\.\d+)*$,fix_section_ids兜底重排编号并去重parent_ids; - 依赖校验与修复:
validate_section_dependencies检查重复 ID、自依赖、反向依赖(父级 ID 大于当前 ID)、parent_ids与relationships数量不匹配;fix_section_dependency_issues自动剔除非法依赖,最后兜底清空无法修复的依赖关系。
此外,Outliner.generate_outline还会把query_understanding_tools中的运行时 API 工具与默认大纲工具合并(merge_runtime_api_tools),并把用户素材(material_bindings)按known_material_ids归一化——若开启material_first,ensure_material_first_bindings会确保每个素材优先章节至少绑定一条证据(outliner.py)。
依赖驱动场景则使用creat_dep_driving_outline_tool,其 section schema 额外要求parent_ids、relationships字段(父级 ID 必须小于当前章节 ID),支撑依赖驱动的写作编排;但outliner_template明确走普通并行工具(PARALLEL),由 main_graph_nodes.py 中的if prompt_name in {"outliner_template", "outliner_user_revised"}: return prompt_name, False, ExecutionMethod.PARALLEL.value保证。
九、与报告模板生态的衔接
outliner_template的输入report_template并非凭空而来,它由报告模板管理链路产生:
- 模板生成:template_generator.py 的
TemplateGenerator.generate_template接受file_name/file_stream(base64)/is_template/agent_config,将用户上传的样例报告或已有模板转换为 Markdown 模板:样例报告走"结构抽取 → 语义抽取"两阶段 LLM 抽取(template_structure_extract、template_semantic_extract),已有模板(仅.md)走结构保留后处理; - 文件解析与校验:template_utils.py 支持
.md/.html/.pdf/.docx样例报告与.md模板,内置 PDF 页数(≤512)、DOCX 解压大小、XML 大小、文件总大小(≤50MB)等边界限制; - 服务端存储:server/routers/report_template.py 提供模板导入、列表、获取、更新、删除等 REST 接口;
- 报告模板文档:详见 report-template.md 与 prompt-template-system.md。
十、相关配置项与调优建议
模板驱动大纲生成涉及以下配置参数(均在 config.py 中定义):
| 配置项 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|
outliner_max_section_num | 10 | [1, 10] | 大纲章节数量上限(OUTLINER_SECTION_NUM_MAX),普通初始大纲在用户未指定结构时匹配该目标数 |
outliner_max_generate_outline_retry_num | 3 | — | 大纲生成最大重试次数,超限抛出OUTLINER_GENERATE_ERROR |
outline_interaction_enabled | True | — | 大纲交互开关 |
outline_interaction_max_rounds | 3 | [1, 100] | 大纲交互最大轮次 |
template_max_generate_retry_num | 3 | — | 模板生成(两阶段抽取)最大重试次数 |
需要特别区分的语义(与 prompt-template-system.md 的边界说明一致):
- 交互式大纲的
max_section_num是章节数上限,不是要求补足的目标; - 模板驱动初始大纲的
section_num是目标章节数,但模板结构优先——用户模板中的 Level 1 章节数才是最终结构的权威来源; report_template存在且非交互轮次时固定走outliner_template,交互轮次则切换到outliner_interaction/outliner_user_revised,不会因模板存在而强制回跳。
十一、测试与契约保障
仓库通过 tests/algorithm/prompts/test_deepresearch_prompt_contracts.py 以仓库级契约(PromptContract)锁定所有 DeepResearch 提示词的 Jinja 变量:outliner_template的必填变量为current_date、entry_search_results、language、original_query、questions、report_template、user_feedback,可选变量为current_date、original_query。任何对提示词变量的增删改都必须同步该测试文件,否则契约测试失败——这保证了提示词与调用方(OutlineNode._pre_handle)之间的变量对齐。
验证命令(仓库根目录下):
uv run pytest deepsearch/tests/algorithm/prompts小结
outliner_template是 openJiuwen DeepSearch 将"用户自定义报告模板"无缝接入多智能体研究报告流水线的关键枢纽:它通过严格的函数工具协议产出结构化sections数组,以"模板结构优先 + 两级标题映射 + 摘要章节剔除 + 核心章节扩充"的规则集保证大纲忠实于模板,再由 outliner.py 的封装、ID 修复与依赖校验链路转成可被下游规划器、采集智能体与写作团队直接消费的Outline。理解这套提示词协议,即可在自己的集成场景中正确构造模板、配置章节数量与重试预算,并保证生成结果满足模板化研究报告的结构一致性要求。
- 人工智能
- 大模型
- AI Agent
- RAG
- 深度研究
- 搜索引擎
- 后端
- 代码智能体
【免费下载链接】deepsearch
openJiuwen DeepSearch是一款知识增强的深度搜索与研究框架,有业界领先的片段级引用和溯源推理能力,提供精准Agentic搜索与研究能力
相关推荐
openJiuwen DeepSearch Brief 大纲规划器(brief_outliner)提示词模板与运行时实现解析
openJiuwen DeepSearch Brief 大纲规划器(brief_outliner)提示词模板与运行时实现解析 openJiuwen DeepSe
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体openJiuwen DeepSearch brief_outliner 提示词深度解析:从研究请求到决策导向证据计划的精简大纲生成
openJiuwen DeepSearch brief_outliner 提示词深度解析:从研究请求到决策导向证据计划的精简大纲生成 导读 brief_outl
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体Rivet Actors Rust 实战:用 RivetKit 构建共享实时计数器(Hello World Rust 全解析)
Rivet Actors Rust 实战:用 RivetKit 构建共享实时计数器(Hello World Rust 全解析) 导读 本文基于开源仓库中的 ex
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考