章节解析三层策略与导航决策构建
上一篇讲了三种执行模式的判定,这一篇来深入看 resolveSection 是怎么定位章节的,以及最终的导航决策对象是怎么构建出来的。
resolveSection:章节解析总入口
不管是哪种执行模式,只要需要定位章节,都会走 resolveSection 这个方法:
/**
* 解析问题对应的目标章节。
* 这是“章节解析总入口”,但它自己并不做具体匹配,而是按可靠性从高到低依次尝试三种实现路径:
*
* 1. `resolveBySectionCode(...)`
* 如果问题里显式出现了类似 `1.2.3` 这样的章节编号,就按编号直接精确查找;
* 这是最强、最可靠的结构信号。
*
* 2. `resolveByNavigationIndex(...)`
* 如果没有显式章节编号,就走专门的导航索引检索;
* 这一步适合处理“开户流程属于哪个章节”“异常处理在哪一节”之类的结构语义问题。
*
* 3. `resolveByLocalStructure(...)`
* 如果索引也没有命中,就退回到本地章节树做模糊文本匹配;
* 这一步更像“弱结构兜底”,通过短语和章节标题/路径/正文去估计最可能的章节。
*
* 如果以上三条路径都没有稳定命中,则最后退回到 `graphService.findBestSection(...)` 做 best effort 兜底。
*
* @param documentId 文档 id
* @param originalQuestion 原始问题
* @param rewrittenQuestion 改写问题
* @return 命中的章节;若无法稳定定位,则返回兜底章节或 null
*/
private GraphSection resolveSection(Long documentId, String originalQuestion, String rewrittenQuestion) {
if (documentId == null) {
// 没有文档 id 时,不存在结构图可定位的前提条件。
return null;
}
// 第一层:显式章节编号命中最可靠,因此优先尝试。
GraphSection byCode = resolveBySectionCode(documentId, originalQuestion, rewrittenQuestion);
if (byCode != null) {
return byCode;
}
// 第二层:如果没有显式编号,再尝试走导航索引。
GraphSection indexedMatch = resolveByNavigationIndex(documentId, originalQuestion, rewrittenQuestion);
if (indexedMatch != null) {
return indexedMatch;
}
// 第三层:再退回到本地结构字段模糊匹配。
List<String> phrases = buildSectionPhrases(originalQuestion, rewrittenQuestion);
GraphSection localMatch = resolveByLocalStructure(documentId, phrases);
if (localMatch != null) {
return localMatch;
}
// 最后让 graphService 自己给一个 best effort 的章节兜底结果。
return graphService.findBestSection(documentId, rewrittenQuestion, "");
}
这是一个典型的"可靠性从高到低依次降级"的策略,一共四层:
| 层级 | 方法 | 适用场景 | 可靠性 |
|---|---|---|---|
| 第一层 | resolveBySectionCode | 问题里有"1.2.3"这类章节编号 | 最高 |
| 第二层 | resolveByNavigationIndex | 带结构语义但没有显式编号 | 较高 |
| 第三层 | resolveByLocalStructure | 前两层都没命中 | 一般 |
| 兜底 | graphService.findBestSection | 全部失败时的最后保障 | 弱 |
第一层:显式章节编号精确命中
/**
* 第一种实现:尝试从问题中直接解析章节编号。
* 适合处理类似下面这种问题:
* 1. “1.2.3 章节讲了什么”
* 2. “3.1.4 这一节属于哪个模块”
* 3. “在 2.4 节里提到的步骤是什么”
*
* 这类问题最大的特点是:用户已经显式给出了章节 code,
* 因此不需要再做语义猜测,直接按编号查图结构是最稳的。
*
* @param documentId 文档 id
* @param originalQuestion 原始问题
* @param rewrittenQuestion 改写问题
* @return 命中的章节;若没有显式章节编号则返回 null
*/
private GraphSection resolveBySectionCode(Long documentId, String originalQuestion, String rewrittenQuestion) {
Matcher matcher = SECTION_CODE_PATTERN.matcher((safeText(originalQuestion) + " " + safeText(rewrittenQuestion)).trim());
while (matcher.find()) {
// 只要问题里出现像“1.2.3”这样的章节编号,就直接按编号精确查找。
// 这里同时扫描原问题与改写问题,避免改写阶段补出的结构编号被漏掉。
GraphSection section = graphService.findSectionByCode(documentId, matcher.group(1));
if (section != null) {
return section;
}
}
return null;
}
付费内容提示
该文档的全部内容仅对「码力全开」项目实战&技术讲解 知识星球用户开放
加入星球,一次获得完整项目资料、全栈技术知识库和长期答疑服务。
100万+字全栈技术知识库深入讲解技术核心、数据库、中间件和分布式等内容
8套热门的实战项目持续更新的企业级项目覆盖高并发、微服务、数据中台 和 AI Agent 等方向
AI 技术知识大模型面试详解覆盖 AI 模型原理、Agent、RAG、MCP、Skills、Harness 等核心知识点
文档 + 视频两种讲解形式既能系统阅读,也能跟随视频理解核心业务
完整项目实战资料
每套项目均包含从 0 到 1 讲解文档核心业务讲解视频从基础项目到复杂业务场景,项目资料会持续更新。
- 01Nexus Agent AI 智能体
- 02Nexus Agent Pro 完全版
- 03黑马点评Plus
- 04大麦
- 05大麦Pro
- 06大麦AI
- 07流量切换
- 08数据中台
加入后还能获得
进入星球后,即可享受上述所有服务,保证不会再有其他隐藏费用。从学习、面试到项目启动,都可以继续获得支持。
- 1 对 1 解答项目和技术问题都可以提问
- 针对性补充没有讲清楚的内容会继续补充
- 面试与简历指导梳理回答技巧和项目亮点
- 中间件云环境项目依赖可以直接接入使用
- 面试后复盘被问住的问题可以继续交流
- 远程问题解决项目启动问题可协助排查
