- 人工智能
- 大模型
- AI Agent
- RAG
- 深度研究
- 搜索引擎
- 后端
- 代码智能体
【免费下载链接】deepsearch
openJiuwen DeepSearch是一款知识增强的深度搜索与研究框架,有业界领先的片段级引用和溯源推理能力,提供精准Agentic搜索与研究能力
openJiuwen DeepSearch 在报告生成后需要通过全局溯源为正文句子追加来源引用,而溯源链路的第一步——"内容识别"(content recognition)决定了一篇报告最终会有哪些句子进入 citation 覆盖范围。本文以deepsearch/openjiuwen_deepsearch/algorithm/prompts/content_recognition/下的 Prompt 模板为骨架,结合content_analyzer.py、source_tracer.py、source_tracer_preprocessors.py等源码与对应测试,完整讲解该模块的输入输出契约、系统指令设计、LLM 调用链、相似度兜底校验与降级策略,帮助读者掌握如何让模型精准、可复用地从研究报告中抽取出"必须加引用"的句子。
一、内容识别在全局溯源链路中的定位
全局溯源(global source trace)负责在报告生成后为句子添加来源引用,并把引用信息整理为前端可展示的 citation data。其主流程(见 source-trace.md)为:
SourceTracer接收报告、classified content 和 LLM 模型名;- 前置覆盖率检查判断是否需要生成新引用;
- 报告和搜索记录预处理,移除参考文献区并裁剪过长内容;
- 内容识别模块找出需要引用的句子;
- 来源匹配模块按 source type 调用 LLM 或匹配算法生成候选引用;
add_source将引用插入报告并生成 data items;- citation checker 校验并重建段落,只保留有效引用;
- 参考文献区被追加或更新,前端 citation data 被组织输出。
内容识别是第 4 步,也是整个链路的第一步。它的职责是把完整报告收敛为"需要溯源的候选句子",避免后续来源匹配对整篇报告做无差别处理,因此直接决定了 citation 的覆盖范围(详见 content-recognition.md)。该步骤基于deepsearch/openjiuwen_deepsearch/algorithm/prompts/content_recognition/目录下的双文件 Prompt 模板实现:system.md定义角色、识别规则与输出格式,user.md定义输入载体。
二、Prompt 模板的双文件结构:system 与 user 的职责分离
内容识别采用稳定的 system/user 双模板结构,位于 prompts/content_recognition/:
- system.md:静态系统指令,不含任何运行时变量;
- user.md:仅承载报告正文这一输入变量,模板内容为:
# Input Research report (Markdown format): <report> {{ report }} </report>{{ report }}是唯一的 Jinja 变量,运行时由调用方注入预处理后的报告正文。这一约定在 test_deepresearch_prompt_contracts.py 中被固化:"content_recognition": ("report",),即该 Prompt 对外暴露且必须提供的变量只有report一个;message_builder.py 在渲染时会校验变量契约、拒绝预留键(messages、history、prior_messages、images),并保证 system 模板中不出现任何运行时变量,从而保证指令稳定、可复现、可单测。
这种"system 固定 + user 注入"的拆分带来两个直接收益:一是识别规则与待识别文本解耦,指令部分不会随每次调用波动;二是便于在测试中验证 system 中不泄漏报告正文(见下文测试章节)。
三、system.md 指令详解:识别什么、排除什么
system.md 首先为模型设定角色:"You are a professional content recognition assistant",任务是识别研究报告中**需要引用(requires citations)**的内容,具体包括三大类:
| 类别 | 说明 | 正向示例 | 反向示例 |
|---|---|---|---|
| 数值数据(Numerical Data) | 具体数字、百分比、价格等 | China's GDP grew by 5.2% | Economic growth has been relatively fast in recent years |
| 具体事实(Specific Facts) | 特定事件、日期、地点等 | On October 15, 2023, Tesla built a factory in Shanghai | —— |
| 专家观点(Expert Opinions) | 引用或转述的专家看法 | According to World Bank forecasts... | —— |
同时,模板明确列出了必须排除的四类内容:
- Markdown 表格内的数据(Data within markdown tables);
- 常识性描述(Common knowledge descriptions);
- 章节标题(Section headings);
- 已带引用的句子——即以
[citation:x]结尾的句子(Sentences with references added); - 参考文献区内容(Content in references)。
这一排除清单与代码侧的过滤逻辑互相呼应:预处理阶段已经移除参考文献区,覆盖率计算阶段也会过滤标题、表格分隔行、代码块标记等非正文内容(详见第六节),形成"模板约束 + 代码兜底"的双层防护。
四、输出契约:严格的 JSON 格式与句子级保真要求
system.md 对模型输出提出了严格的结构化要求,输出必须为如下 JSON:
{ "sentences": [ "Original sentence 1", "Original sentence 2", ... ] }关键约束逐条拆解如下(这些约束共同保证了后续相似度校验和来源匹配的可行性与可追溯性):
- 句子必须存在于原文:
sentences字段输出的必须是报告正文中真实存在的单句,且严格遵循原文的行边界;不得把不同行的内容合并成一句; - 标点零改动:不得修改、新增或删除原文的任何标点;
- 格式保真:必须完整保留原文的加粗、斜体、引号、括号、标点等 Markdown 格式信息;
- 数量上限:最多选择 10 条句子(Select up to 10 sentences);
- 引号规范:每条输出句子必须用英文双引号包裹;
- 纯净输出:直接输出正确的 JSON,不得附带任何额外字符,包括
```json代码块标记。
这一"纯净 JSON"要求非常关键。虽然代码侧在解析前会调用normalize_json_output(位于 llm_utils.py)做兜底,剥离开头的```json/```ts代码块标记,但模板层面仍然要求模型直接输出纯 JSON,以减少解析歧义。若解析后结果不是 dict 或缺少sentences键,content_analyzer.py 会安全地回退为空列表,而不是中断整篇报告的溯源流程。
五、源码级调用链:从模板渲染到句子落库
内容识别的完整调用链由 content_analyzer.py 中的recognize_content_to_cite驱动,其核心步骤如下:
- 构建上下文:
source_tracer_context = dict(report=modified_report),其中modified_report是预处理后的报告正文; - 渲染消息:调用
build_prompt_messages("content_recognition", source_tracer_context)(message_builder.py),从prompts/content_recognition/目录加载system.md与user.md,渲染出[{role: "system"}, {role: "user"}]两条消息; - 调用 LLM 并埋点:通过
ainvoke_llm_with_stats执行推理,并使用AgentLlmName.SOURCE_TRACER_CONTENT_RECOGNITION(定义于 node_constants.py,取值为"source_tracer_content_recognition")作为埋点标识,便于在遥测与日志中区分该次调用; - 规范化输出:
normalize_json_output清理代码块标记等杂质; - 验证与增强:
validate_and_enhance_sentences对模型输出的每条句子做"报告内定位"校验(详见第六节); - 返回:得到最终需要引用的句子列表
List[str];若 LLM 调用抛异常,函数捕获后仅在非敏感日志模式下打印错误细节,并返回空列表,实现整链路降级。
该函数被 source_tracer.py 的research_trace_source调用,调用时传入的关键参数为:
preprocessed_report:调用preprocess_report移除参考文献区后的报告;self._similarity_threshold:默认0.9(source_tracer.py);self._llm_model_name:当前使用的 LLM 模型名,从llm_context中按名取出对应模型实例。
识别结果非空后,才进入下一步的match_sources来源匹配,因此内容识别是来源匹配的前置闸门。
六、相似度兜底:让模型输出"落回"原文
LLM 在复述句子时难免出现增删字词、标点漂移,若直接信任模型输出,后续来源匹配将无法在报告中精确定位句子。因此validate_and_enhance_sentences承担了"模型输出 → 报告原文"的对齐职责,算法分两档处理:
第一档:完全匹配(精确命中)若模型输出的句子sentence in report(Python 子串包含判断),则直接采用原句并去重(seen_sentences集合保证重复句子只保留一条)。
第二档:相似度匹配(模糊兜底)若无法精确匹配,则调用find_similar_sentence在报告中寻找最相似句子。其实现要点(content_analyzer.py):
- 先用
split_into_sentences将报告切分为句子列表; - 再对每句用
difflib.SequenceMatcher(None, sentence, report_sent).ratio()计算相似度; - 取相似度不低于阈值(默认 0.9)且最高的句子作为结果;
- 无句子达到阈值时返回空串,该条候选被丢弃。
分句器split_into_sentences(text_utils.py)以中文标点。!?;及换行符为分界,并在末尾保留无标点句子——这也是 system.md 强调"严格遵循原文行边界"的原因:代码侧的对齐逻辑完全依赖句子级切分。
该兜底逻辑在 test_content_analyzer.py 中有系统覆盖:
test_validate_and_enhance_sentences_basic/..._with_exact_matches:精确匹配场景,句子应原样保留;test_validate_and_enhance_sentences_no_matches:报告中完全找不到的句子应被丢弃(返回空列表);test_validate_and_enhance_sentences_duplicate_handling:重复句子去重后仅保留一条;test_validate_and_enhance_sentences_empty_json/..._no_sentences_key:空 JSON 或缺sentences键时安全返回空列表;test_find_similar_sentence_*:覆盖精确命中、高相似命中、低于阈值返回空串、空报告/空句子等边界;test_recognize_content_to_cite_llm_invoke_error:LLM 调用抛异常时整体返回空列表。
七、前置的文本预处理:参考文献区移除与内部标记转换
内容识别的输入并非原始报告全文。在调用 Prompt 之前,source_tracer_preprocessors.py 已完成两项关键预处理:
1. 参考文献区移除(_remove_reference_section/preprocess_report)通过正则^#{1,6}\s.+$(多行模式)定位所有 Markdown 标题,从后向前查找标题文字匹配(?:参考文献|参考文章|Reference Articles)(忽略大小写)的最后一个标题,将该标题之后的所有内容作为参考文献区整体剔除。无匹配时返回原文与空字符串。这样既符合 system.md"排除参考文献内容"的要求,也避免参考文献影响后续的引用提取与来源匹配。
2. 已有引用的内部标记转换(generate_origin_report_data)对报告正文中已存在的[citation:X]标记,通过正则r'\[\s*citation:\s*(\d+)\s*\]'定位(source_tracer_preprocessors.py),并结合 classified content 构建的引用映射(按编号映射到 title/url/content),将其替换为[source_tracer_result]title链接格式,同时记录每个引用前的一句话作为 chunk 与句内位置。这与 system.md"排除已带引用句子"的规则配套:已被原文引用的句子在后续合并时会被当作既有引用处理,而不是重复溯源。
此外,全局溯源入口还会对报告正文做"有意义句子"过滤(_filter_meaningful_sentences,source_tracer.py),剔除空行、#开头的标题行、```开头的代码块标记行、仅含| - : 空格的表格分隔行等非正文内容——覆盖识别阶段同样的过滤目标,保证覆盖率统计与候选句子的质量。
八、覆盖率检查与降级策略
内容识别并非每次溯源都会执行。SourceTracer.pre_check_origin_coverage会在正式流程前做前置判断(source_tracer.py):
- 空报告:直接返回
need_generate=False,不进入识别; - 无 classified content:无法生成新引用,跳过溯源;
- 覆盖率已足够:通过
_calculate_coverage检测带[citation:X]标记的句子占比,当被引用覆盖的唯一句子数 ≥_min_origin_coverage_count(默认 10)且覆盖率 ≥_min_origin_coverage_ratio(默认 0.3)时,判定need_generate=False,避免重复溯源; - 覆盖率不足:进入
research_trace_source,此时才真正调用内容识别。
即便进入识别,若 LLM 返回空列表、预处理搜索记录失败或后续来源匹配无结果,research_trace_source都会逐级警告并退出,保证整篇报告不会被溯源流程中断。同时,敏感日志模式下(LogManager.is_sensitive())不会输出完整报告正文与识别出的句子明细,只记录数量级信息,兼顾可观测性与数据安全。
九、测试与验证:如何本地复现该模块行为
仓库为内容识别模块提供了可直接运行的单测,推荐命令(基于uv):
uv run pytest deepsearch/tests/source_tracer/test_content_analyzer.py uv run pytest deepsearch/tests/source_tracer/test_source_tracer_preprocessors.py uv run pytest deepsearch/tests/algorithm/prompts/test_deepresearch_prompt_contracts.py其中 test_deepresearch_prompt_contracts.py 对 Prompt 契约做了仓库级校验:声明content_recognition只暴露report变量,并配合 test_build_prompt_messages 验证报告正文只出现在 user 消息中、不泄漏进 system 消息、且不含CURRENT_TIME等意外占位符。这意味着任何对system.md或user.md的修改都会先经过契约测试的约束,保证指令稳定性。
十、扩展指南:自定义识别规则与阈值调优
基于上述实现,开发者可从三个层面定制内容识别行为:
- 识别规则:修改 system.md 中的"识别三类内容"与"排除清单"即可改变模型关注范围。例如增加"机构名称、统计口径、法律条文"等新类别,或补充新的排除条件(如公式、脚注)。注意需保持输出 JSON 契约不变,以免破坏
content_analyzer.py的解析逻辑。 - 输入注入:
user.md目前只接收report一个变量;若要同时注入领域提示、语言指令或用户画像,需扩展模板变量并同步更新 test_deepresearch_prompt_contracts.py 中的变量契约,因为build_prompt_messages会按契约校验上下文键。 - 相似度阈值:
SourceTracer默认阈值为0.9(source_tracer.py)。阈值越高,对模型输出的句子与原文一致性要求越严,候选越保守;调低可容忍更多转述差异,但会增加将"改写句"误对齐到原文句的风险。实际调优时应配合test_find_similar_sentence_with_threshold_0、test_validate_and_enhance_sentences_with_similar_sentences等测试观察匹配行为。 - 输出规模:system.md 将候选句上限固定为 10 条;如需放宽或收紧,直接修改该数值,同时注意来源匹配阶段对候选数量的处理成本。
结语
内容识别是 openJiuwen DeepSearch 全局溯源的第一道闸门,其价值在于"以 Prompt 规则收敛候选、以代码逻辑校准输出"的双层设计:system.md给出数值数据、具体事实、专家观点三大识别目标与明确的排除清单,user.md以{{ report }}单一变量注入正文,content_analyzer.py则在模型输出后用精确匹配 +difflib相似度匹配把每条句子拉回原文并去重,配合参考文献区移除、已有引用标记转换、覆盖率前置检查与多级降级,最终产出高质量、可对齐、可追溯的待引用句子列表,为后续来源匹配与 citation 校验奠定基础。理解这套 Prompt 与代码的协作机制,可以帮助开发者在保持输出契约稳定和测试约束的前提下,灵活定制属于自己的溯源识别策略。
- 人工智能
- 大模型
- AI Agent
- RAG
- 深度研究
- 搜索引擎
- 后端
- 代码智能体
【免费下载链接】deepsearch
openJiuwen DeepSearch是一款知识增强的深度搜索与研究框架,有业界领先的片段级引用和溯源推理能力,提供精准Agentic搜索与研究能力
相关推荐
openJiuwen DeepSearch 溯源内容识别:将报告收敛为待溯源候选句子的第一道关卡
openJiuwen DeepSearch 溯源内容识别:将报告收敛为待溯源候选句子的第一道关卡 导读 本文深入讲解 openJiuwen DeepSearch
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体openJiuwen DeepSearch 图表数据溯源校验 Prompt 深度解析:从字段级溯源到 Mermaid 可视化前验证
openJiuwen DeepSearch 图表数据溯源校验 Prompt 深度解析:从字段级溯源到 Mermaid 可视化前验证 openJiuwen Dee
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体openJiuwen DeepSearch 全局溯源(Source Trace)技术指南:从引用识别到 Citation 校验的完整链路
openJiuwen DeepSearch 全局溯源(Source Trace)技术指南:从引用识别到 Citation 校验的完整链路 导读 本文聚焦 ope
人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考