LoHoSearch 的方法:用知识图谱校准 AI 的能力认知

2026-08-06 38 预计阅读时间: 1 分钟
来源: my.oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

机器出题并不只是批量生成问题。一个问题是否有价值,取决于它对应的知识范围、推理难度和质量标准是否可控。美团开源 LoHoSearch 的思路,是先用知识图谱建立全局视野,再围绕建图、难度控制、质量把关和数据概览,形成一套可检查的机器出题流程。

这套方法对评测集、训练数据和问答系统都很有参考意义:模型不应只“知道答案”,还需要清楚自己在什么知识节点上具备能力,以及哪些相邻能力仍然薄弱。

先建图,再生成问题

知识图谱可以把零散的文档、实体、概念和关系组织成一个可遍历的结构。对机器出题来说,它至少解决了两个问题:

  • 让出题系统知道当前覆盖了哪些主题,减少知识盲区。
  • 让问题能够绑定到具体的知识节点和关系,便于追溯来源与分析错误。

可以把一道题抽象成一条或多条图上的路径。例如,题目可能要求模型从一个实体出发,沿着“属于”“位于”“依赖”等关系完成一步推理,也可以组合多个关系形成多跳问题。

下面是一个不依赖第三方库的最小示例。它用邻接表表示知识图谱,并生成简单的一跳问题。实际系统可以把 triples 替换成从文档抽取或数据库读取的数据。

from collections import defaultdict

triples = [
    ("LoHoSearch", "用于", "机器出题质量控制"),
    ("机器出题质量控制", "依赖", "知识图谱"),
    ("知识图谱", "支持", "全局视野"),
]

graph = defaultdict(list)
for subject, relation, object_ in triples:
    graph[subject].append((relation, object_))

def make_questions(graph):
    questions = []
    for subject, edges in graph.items():
        for relation, object_ in edges:
            questions.append({
                "question": f"{subject}{relation}什么?",
                "answer": object_,
                "anchor": subject,
                "relation": relation,
                "difficulty": 1,
            })
    return questions

for item in make_questions(graph):
    print(item)

关键不在于问题模板本身,而在于每道题都保留了 anchorrelationdifficulty 等结构化信息。这样,后续质量检查可以定位到具体的知识节点,而不是只对一段自然语言做模糊判断。

用图上的路径控制难度

题目难度不应完全交给模型主观判断。一个可操作的办法,是把难度映射到图上的路径特征:

  • 一跳关系适合基础事实识别。
  • 两跳或多跳路径适合组合推理。
  • 多个候选节点之间关系接近时,需要更强的区分能力。
  • 节点信息不完整、存在别名或关系方向容易混淆时,题目风险更高。

可以这样实践:先限定允许的路径长度,再让生成器根据路径生成问题;对于超过最大长度、无法唯一确定答案或依赖低置信度节点的样本,直接进入待审核队列。

def find_paths(graph, start, max_hops=2):
    paths = [(start, [])]
    result = []

    while paths:
        node, edges = paths.pop(0)
        if edges:
            result.append((node, edges))
        if len(edges) >= max_hops:
            continue
        for relation, next_node in graph.get(node, []):
            paths.append((next_node, edges + [(relation, next_node)]))

    return result

for answer, path in find_paths(graph, "LoHoSearch", max_hops=2):
    print("路径:", " -> ".join(["LoHoSearch"] + [f"{r}:{n}" for r, n in path]))
    print("候选答案:", answer)

这个示例只展示了路径遍历,不能替代完整的难度模型。生产环境还应加入答案唯一性、路径置信度、实体类型和问题语言质量等特征,并把这些特征记录到数据集元信息中。

质量把关要检查什么

机器生成的问题常见的缺陷包括:问题与知识节点不匹配、答案不唯一、关系方向写反、问题包含图谱中不存在的事实,以及多个题目只是换了措辞却考查同一件事。

质量把关可以分成几层:

  1. 结构校验:检查实体、关系和答案是否都能在图中找到。
  2. 逻辑校验:检查推理路径是否真实存在,答案是否能由路径推出。
  3. 语言校验:检查问题是否完整、是否有歧义、是否包含无法回答的条件。
  4. 去重与覆盖检查:识别近似问题,并统计知识节点与关系的覆盖情况。
  5. 抽样复核:对高难度、低置信度或异常分布样本进行人工检查。

其中,人工抽样并不是机器流程的失败,而是对自动规则边界的校准。抽样结果可以反过来调整路径规则、难度阈值和生成提示词。

数据概览让问题集可运营

如果只保存问题和答案,数据集很快会变成难以维护的文本文件。更实用的记录方式还应包括:

  • 对应的知识节点和关系。
  • 路径长度与难度等级。
  • 生成模型、生成时间和版本号。
  • 自动检查结果与人工审核状态。
  • 主题、实体类型和错误类型。

这些字段能支持几个重要分析:哪些主题题量不足,哪些关系持续产生错误,难题是否集中在少数节点,训练集与评测集是否发生知识泄漏,以及模型错误是否来自事实缺失还是推理失败。

可以用下面的命令快速查看一个 JSON Lines 数据集的难度分布。假设文件名为 questions.jsonl,每行包含 difficulty 字段:

jq -r '.difficulty' questions.jsonl \
  | sort -n \
  | uniq -c \
  | awk '{print "difficulty=" $2 ", count=" $1}'

如果数据中包含 topic 字段,还可以按主题统计:

jq -r '.topic' questions.jsonl \
  | sort \
  | uniq -c \
  | sort -nr

落地时的取舍

知识图谱能提供全局视野,但它不会自动保证知识正确,也不会自动解决自然语言歧义。图谱构建本身需要处理实体对齐、关系抽取、版本变化和冲突事实。图谱越大,覆盖面越好,但维护成本、错误传播风险和质量评估成本也会同步增加。

比较稳妥的落地顺序是:

  • 先选择一个边界清晰的领域,建立少量高质量节点和关系。
  • 为每条题目保留可追溯的知识路径和版本信息。
  • 先使用规则控制路径长度、答案唯一性和数据去重。
  • 再引入模型评审,并用人工抽样校准评审结果。
  • 最后通过数据概览持续修正覆盖率和难度分布。

机器出题的核心不是让模型一次生成更多问题,而是让每个问题都能回答三个问题:它考查了哪项能力,为什么属于这个难度,以及出现错误时应该回查哪条知识路径。LoHoSearch 所体现的建图、控难度、做质检和看全局,正好构成了这条可追溯的数据生产链。


相关推荐