Files
GraphRAGAgent/docs/langextract_specification.md
plf b02d3378fc GraphRAG Studio — initial commit: multimodal RAG system with KG visualization
Full-stack application for document-to-knowledge-graph pipeline:
- Backend: FastAPI + LangGraph ReAct agent + DeepSeek + MinerU parsing
- Frontend: React 19 + Vite + D3.js + shadcn/ui
- Pipeline: MinerU parsing → LangExtract entity extraction → KG building

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 17:30:04 +08:00

23 KiB
Raw Permalink Blame History

LangExtract Pipeline 规范文档

基于 google/langextract 源码分析 版本基线2026-03-04 main 分支


目录


一、输入规范

1.1 核心入口函数签名

文件路径:langextract/extraction.py

def extract(
    text_or_documents: typing.Any,
    prompt_description: str | None = None,
    examples: typing.Sequence[typing.Any] | None = None,
    model_id: str = "gemini-2.5-flash",
    api_key: str | None = None,
    language_model_type: typing.Type[typing.Any] | None = None,  # 已废弃
    format_type: typing.Any = None,
    max_char_buffer: int = 1000,
    temperature: float | None = None,
    fence_output: bool | None = None,
    use_schema_constraints: bool = True,
    batch_length: int = 10,
    max_workers: int = 10,
    additional_context: str | None = None,
    resolver_params: dict | None = None,
    language_model_params: dict | None = None,
    debug: bool = False,
    model_url: str | None = None,
    extraction_passes: int = 1,
    context_window_chars: int | None = None,
    config: typing.Any = None,
    model: typing.Any = None,
    *,
    fetch_urls: bool = True,
    prompt_validation_level: PromptValidationLevel = PromptValidationLevel.WARNING,
    prompt_validation_strict: bool = False,
    show_progress: bool = True,
    tokenizer: Tokenizer | None = None,
) -> list[AnnotatedDocument] | AnnotatedDocument

关键参数说明:

参数 类型 默认值 说明
text_or_documents Any 必填 纯文本字符串、URL、或 Document 对象的可迭代集合
prompt_description str | None None 抽取提示词,描述需要抽取什么实体
examples Sequence[Any] | None None 必填 — Few-shot 示例列表(为空则抛出 ValueError
model_id str "gemini-2.5-flash" 模型标识符,用于自动路由到对应 Provider
api_key str | None None LLM API Key也可通过环境变量设置
max_char_buffer int 1000 每个文本分块的最大字符数
temperature float | None None 采样温度(None 使用模型默认值)
use_schema_constraints bool True 是否启用结构化输出约束
batch_length int 10 每批处理的文本分块数量
max_workers int 10 最大并行工作线程数
additional_context str | None None 附加到推理提示词中的上下文信息
resolver_params dict | None None 对齐解析器参数(见 3.5 节
extraction_passes int 1 抽取轮次(>1 时多次抽取并合并非重叠结果)
context_window_chars int | None None 前一分块的上下文窗口字符数(用于指代消解)
model_url str | None None 自托管模型的 API 端点 URL
fetch_urls bool True 是否自动下载 http(s) URL 内容

1.2 支持的输入类型

LangExtract 仅接受纯文本作为输入,支持以下 4 种传入方式:

输入方式 示例 说明
纯文本字符串 extract("这是一段文本...") 直接传入文本内容
URL extract("https://example.com/article.txt") 自动下载 URL 文本内容(fetch_urls=True
Document 对象 extract([Document(text="...", document_id="doc1")]) 传入 Document 可迭代集合
CSV 文件 通过 Dataset 类加载后传入 指定 text 列和 id 列

1.3 Document 数据结构

文件路径:langextract/core/data.py

@dataclasses.dataclass
class Document:
    text: str                                    # 必填 — 原始文本内容
    additional_context: str | None = None        # 可选 — 附加上下文
    document_id: str                             # 自动生成 — 格式 "doc_{uuid_hex[:8]}"
    tokenized_text: TokenizedText                # 惰性计算 — 分词后的文本

字段说明:

  • text必填,原始文本内容,类型为 str
  • additional_context:可选,会附加到推理提示词中
  • document_id:通过 property 访问,未设置时自动生成格式为 doc_{uuid_hex[:8]} 的唯一 ID
  • tokenized_text:通过 property 惰性计算,使用配置的 Tokenizer 进行分词

1.4 CSV Dataset 输入

文件路径:langextract/io.py

@dataclasses.dataclass(frozen=True)
class Dataset:
    input_path: pathlib.Path   # CSV 文件路径
    id_key: str                # 文档 ID 对应的列名
    text_key: str              # 文本内容对应的列名

    def load(self, delimiter: str = ',') -> Iterator[Document]:
        """仅支持 .csv 后缀文件,其他格式抛出 NotImplementedError"""

CSV 文件要求:

  • 文件后缀必须为 .csv
  • 必须包含 text_key 指定的文本列和 id_key 指定的 ID 列
  • 默认分隔符为逗号(,),可通过 delimiter 参数修改
  • 其他文件格式会直接抛出 NotImplementedError

1.5 URL 文本下载

文件路径:langextract/io.py

def download_text_from_url(
    url: str,
    timeout: int = 30,           # 默认超时 30 秒
    show_progress: bool = True,
    chunk_size: int = 8192,
) -> str

URL 要求:

  • 必须以 http://https:// 开头
  • 仅下载文本内容(response.text),不解析 HTML/PDF 等
  • 需要 fetch_urls=True(默认开启)

1.6 分块参数配置

文件路径:langextract/chunking.py

LangExtract 使用基于句子边界的确定性分块策略(非语义分块),核心类为 ChunkIterator

class ChunkIterator:
    def __init__(
        self,
        text: str | TokenizedText | None,
        max_char_buffer: int,           # 每个分块最大字符数
        tokenizer_impl: Tokenizer,      # 分词器实例
        document: Document | None = None,
    )

分块策略:

  1. 如果单个句子超过 max_char_buffer,按换行符拆分,同时尊重 token 边界
  2. 如果单个 token 超过 max_char_buffer,该 token 独占一个分块
  3. 如果多个句子可以放入 max_char_buffer,合并为一个分块

TextChunk 输出结构:

@dataclasses.dataclass
class TextChunk:
    token_interval: TokenInterval       # 在源文档中的 token 区间
    document: Document | None = None    # 源文档引用

    # 属性
    chunk_text: str                     # 重建的文本内容
    sanitized_chunk_text: str           # 标准化空白的文本
    char_interval: CharInterval         # 在源文档中的字符区间
    document_id: str | None             # 源文档 ID

1.7 不支持的输入格式

以下格式 不被支持,需要在 LangExtract 之前通过外部工具预处理为纯文本:

格式 状态 预处理方案
PDF 不支持 使用 MinerU / PyMuPDF 先转文本
DOCX 不支持 使用 python-docx 先转文本
HTML 不支持 使用 BeautifulSoup 先提取文本
图片 不支持 使用 OCR 工具先识别文本
Markdown含媒体 不支持 需提取纯文本部分
Excel / JSON 不支持 需序列化为纯文本

二、模型接入规范

2.1 模型路由机制

文件路径:langextract/providers/patterns.py

LangExtract 通过 正则匹配 model_id 自动路由到对应的 Provider

Provider 匹配模式 优先级 示例模型
Gemini ^gemini 10 gemini-2.5-flash, gemini-1.5-pro
OpenAI ^gpt-4, ^gpt4., ^gpt-5, ^gpt5. 10 gpt-4o, gpt-4o-mini
Ollama gemma, llama, mistral, phi, qwen, deepseek 10 gemma2:2b, llama3.2:1b

Ollama 额外支持 HuggingFace 格式的模型名:meta-llama/Llama*, google/gemma*, mistralai/*, microsoft/phi* 等。


2.2 Gemini Provider

文件路径:langextract/providers/gemini.py

class GeminiLanguageModel(BaseLanguageModel):
    def __init__(
        self,
        model_id: str = 'gemini-2.5-flash',
        api_key: str | None = None,
        vertexai: bool = False,
        credentials: Any | None = None,
        project: str | None = None,
        location: str | None = None,
        http_options: Any | None = None,
        gemini_schema: GeminiSchema | None = None,
        format_type: FormatType = FormatType.JSON,
        temperature: float = 0.0,
        max_workers: int = 10,
        fence_output: bool = False,
        **kwargs,
    )
参数 默认值 说明
model_id gemini-2.5-flash Gemini 模型标识
api_key None 环境变量:GEMINI_API_KEYLANGEXTRACT_API_KEY
vertexai False 是否使用 Vertex AI 企业认证
temperature 0.0 采样温度(确定性输出)
format_type JSON 输出格式

运行时可配参数: temperature, max_output_tokens, top_p, top_k

额外参数白名单: response_schema, response_mime_type, safety_settings, system_instruction, tools, stop_sequences, candidate_count


2.3 OpenAI Provider

文件路径:langextract/providers/openai.py

class OpenAILanguageModel(BaseLanguageModel):
    def __init__(
        self,
        model_id: str = 'gpt-4o-mini',
        api_key: str | None = None,
        base_url: str | None = None,
        organization: str | None = None,
        format_type: FormatType = FormatType.JSON,
        temperature: float | None = None,
        max_workers: int = 10,
        **kwargs,
    )
参数 默认值 说明
model_id gpt-4o-mini OpenAI 模型标识
api_key None 环境变量:OPENAI_API_KEYLANGEXTRACT_API_KEY
base_url None 自定义 API 端点(用于兼容接口)
organization None OpenAI 组织 ID
temperature None 采样温度

运行时可配参数: temperature, max_output_tokens, top_p, frequency_penalty, presence_penalty, seed, stop, logprobs, top_logprobs, reasoning_effort, reasoning, response_format


2.4 Ollama Provider

文件路径:langextract/providers/ollama.py

class OllamaLanguageModel(BaseLanguageModel):
    def __init__(
        self,
        model_id: str,                                    # 必填
        model_url: str = 'http://localhost:11434',
        base_url: str | None = None,
        format_type: FormatType | None = None,
        constraint: Constraint = Constraint(),
        timeout: int | None = None,
        **kwargs,
    )
参数 默认值 说明
model_id 必填 Ollama 模型名(如 gemma2:2b
model_url http://localhost:11434 Ollama 服务地址
timeout 120 请求超时(秒)
format_type JSON 输出格式

内部默认常量:

常量 说明
_DEFAULT_TEMPERATURE 0.1 默认温度
_DEFAULT_TIMEOUT 120 默认超时(秒)
_DEFAULT_KEEP_ALIVE 300 模型保活时间(秒)
_DEFAULT_NUM_CTX 2048 默认上下文窗口大小

认证支持: 可配置 api_keyauth_scheme(默认 Bearer)、auth_header(默认 Authorization)用于代理 Ollama 实例。


2.5 OpenAI 兼容接口适配DeepSeek 等)

LangExtract 的 OpenAI Provider 支持 base_url 参数,因此可以接入任何 OpenAI 兼容 API

# DeepSeek 接入示例
result = lx.extract(
    text_or_documents="...",
    model_id="gpt-4o-mini",               # 触发 OpenAI Provider 路由
    api_key="sk-your-deepseek-key",
    examples=[...],
    language_model_params={
        "base_url": "https://api.deepseek.com",
    },
)

注意: 由于路由基于 model_id 正则匹配,使用 DeepSeek 等兼容接口时 model_id 仍需使用 gpt-* 前缀来命中 OpenAI Provider或通过 config 参数显式指定 Provider。


2.6 模型优先级与配置覆盖关系

模型配置的优先级从高到低:

model预配置的模型实例 > configModelConfig 实例) > model_id + api_key

ModelConfig 结构langextract/factory.py

@dataclasses.dataclass(slots=True, frozen=True)
class ModelConfig:
    model_id: str | None = None                              # 模型标识
    provider: str | None = None                              # 显式指定 Provider 名称
    provider_kwargs: dict[str, Any] = field(default_factory=dict)  # Provider 构造参数

2.7 关于 Embedding 模型

LangExtract 不使用也不依赖任何 Embedding 模型。

  • 文本分块使用基于句子边界的确定性分割算法,不涉及语义相似度计算
  • 没有向量索引或向量检索功能
  • 整个代码库中没有任何 Embedding 相关的调用

三、输出数据格式规范

3.1 AnnotatedDocument 结构

文件路径:langextract/core/data.py

@dataclasses.dataclass
class AnnotatedDocument:
    extractions: list[Extraction] | None = None    # 抽取结果列表
    text: str | None = None                        # 原始文本
    document_id: str                               # 文档唯一标识(自动生成)
    tokenized_text: TokenizedText                   # 分词后文本(惰性计算)

序列化后的 JSON 顶层字段:

字段 类型 说明
document_id string 文档唯一标识,格式 doc_{uuid_hex[:8]}
text string | null 原始输入文本
extractions array[Extraction] | null 抽取的实体列表

3.2 Extraction 结构

文件路径:langextract/core/data.py

@dataclasses.dataclass(init=False)
class Extraction:
    extraction_class: str                                      # 实体类型
    extraction_text: str                                       # 实体文本
    char_interval: CharInterval | None = None                  # 字符位置锚点
    alignment_status: AlignmentStatus | None = None            # 对齐状态
    extraction_index: int | None = None                        # 抽取顺序索引
    group_index: int | None = None                             # 分组索引
    description: str | None = None                             # 实体描述
    attributes: dict[str, str | list[str]] | None = None       # 附加属性
    token_interval: TokenInterval | None = None                # Token 位置锚点

字段详细说明:

字段 类型 必填 说明
extraction_class str 实体类型/分类名称(如 PERSON, ORGANIZATION
extraction_text str 抽取的文本内容(应为原文的子串)
char_interval CharInterval | null 在原文中的字符偏移位置
alignment_status string | null 文本对齐质量(见 3.4 节
extraction_index int | null 在结果列表中的顺序位置
group_index int | null 分组归属(用于关联抽取)
description string | null 对该实体的补充描述
attributes dict | null 键值对形式的附加属性
token_interval TokenInterval | null 在原文中的 token 偏移位置

3.3 CharInterval 字符锚点

文件路径:langextract/core/data.py

@dataclasses.dataclass
class CharInterval:
    start_pos: int | None = None    # 起始位置包含0-indexed
    end_pos: int | None = None      # 结束位置(不包含)

语义: source_text[start_pos:end_pos] 即为抽取的文本在原文中的精确位置。


3.4 AlignmentStatus 对齐状态枚举

文件路径:langextract/core/data.py

class AlignmentStatus(enum.Enum):
    MATCH_EXACT   = "match_exact"
    MATCH_GREATER = "match_greater"
    MATCH_LESSER  = "match_lesser"
    MATCH_FUZZY   = "match_fuzzy"
状态值 序列化值 含义 可信度
MATCH_EXACT "match_exact" LLM 输出与原文 token 序列完全匹配 最高
MATCH_GREATER "match_greater" LLM 输出的 token 序列短于匹配到的原文(找到最佳重叠)
MATCH_LESSER "match_lesser" LLM 输出长于匹配到的原文(部分精确匹配)
MATCH_FUZZY "match_fuzzy" 模糊匹配,重叠率达到阈值(默认 ≥0.75
None null 未找到任何对齐 不可信

对齐流程:

1. 尝试精确 token 级别匹配difflib
   ├── 成功且长度相等 → MATCH_EXACT
   ├── 成功但 LLM 输出更长 → MATCH_LESSER
   └── 成功但匹配区域更大 → MATCH_GREATER
2. 精确匹配失败且 enable_fuzzy_alignment=True
   ├── 最佳重叠窗口 ≥ fuzzy_alignment_threshold → MATCH_FUZZY
   └── 低于阈值 → None
3. 精确匹配失败且 enable_fuzzy_alignment=False → None

3.5 Resolver 对齐参数

文件路径:langextract/resolver.py

通过 extract()resolver_params 字典传入:

result = lx.extract(
    ...,
    resolver_params={
        "enable_fuzzy_alignment": True,       # 是否启用模糊对齐(默认 True
        "fuzzy_alignment_threshold": 0.75,    # 模糊匹配最低重叠率(默认 0.75
        "accept_match_lesser": True,          # 是否接受 MATCH_LESSER默认 True
        "suppress_parse_errors": False,       # 是否忽略 JSON 解析错误(默认 False
    },
)
参数 类型 默认值 说明
enable_fuzzy_alignment bool True 精确匹配失败后是否尝试模糊匹配
fuzzy_alignment_threshold float 0.75 模糊匹配的最低 token 重叠比率0.0~1.0
accept_match_lesser bool True 是否接受部分精确匹配结果
suppress_parse_errors bool False JSON 解析失败时是否继续而非报错

3.6 JSONL 输出文件格式

文件路径:langextract/io.py

def save_annotated_documents(
    annotated_documents: Iterator[AnnotatedDocument],
    output_dir: pathlib.Path | str | None = None,
    output_name: str = 'data.jsonl',
    show_progress: bool = True,
) -> None

输出规范:

  • 文件格式:JSONLJSON Lines每行一个完整的 JSON 对象
  • 默认文件名:data.jsonl
  • 序列化规则:
    • Enum 值转为字符串(如 AlignmentStatus.MATCH_EXACT"match_exact"
    • NumPy / integral 数值类型转为 int
    • _ 开头的私有字段被排除

3.7 完整输出 JSON Schema 示例

单条 JSONL 记录的完整结构:

{
  "document_id": "doc_a1b2c3d4",
  "text": "GraphRAG is a technique developed by Microsoft Research that combines knowledge graphs with retrieval-augmented generation.",
  "extractions": [
    {
      "extraction_class": "TECHNOLOGY",
      "extraction_text": "GraphRAG",
      "char_interval": {
        "start_pos": 0,
        "end_pos": 8
      },
      "alignment_status": "match_exact",
      "extraction_index": 0,
      "group_index": null,
      "description": "A technique combining knowledge graphs with RAG",
      "attributes": {
        "category": "AI/ML",
        "developer": "Microsoft Research"
      },
      "token_interval": {
        "start_index": 0,
        "end_index": 1
      }
    },
    {
      "extraction_class": "ORGANIZATION",
      "extraction_text": "Microsoft Research",
      "char_interval": {
        "start_pos": 46,
        "end_pos": 64
      },
      "alignment_status": "match_exact",
      "extraction_index": 1,
      "group_index": null,
      "description": null,
      "attributes": null,
      "token_interval": {
        "start_index": 7,
        "end_index": 9
      }
    }
  ]
}

3.8 HTML 可视化输出

文件路径:langextract/visualization.py

def visualize(doc: AnnotatedDocument) -> HTML

功能特性:

  • extraction_class 进行颜色编码高亮10 色调色板)
  • 交互式 tooltip 显示实体类型和属性
  • 动画导航控件,支持多实体浏览
  • 进度滑块
  • 响应式 HTML/CSS/JavaScript 嵌入
  • 支持 Jupyter / IPython 环境直接渲染

附录:环境变量与常量速查

环境变量

变量名 适用 Provider 说明
LANGEXTRACT_API_KEY 所有 通用 API Key 后备
GEMINI_API_KEY Gemini Gemini API Key
OPENAI_API_KEY OpenAI OpenAI API Key
OLLAMA_BASE_URL Ollama Ollama 服务地址(默认 http://localhost:11434

FormatType 枚举

class FormatType(enum.Enum):
    YAML = 'yaml'
    JSON = 'json'

结构化输出支持

Provider Schema 类型 结构化输出模式
Gemini GeminiSchema 严格结构化输出
OpenAI JSON Mode 通过 response_format 约束
Ollama FormatModeSchema JSON 模式(非严格)

Fence Output 逻辑

Provider 默认值 说明
Gemini False 有 Schema 时不需要 fence
OpenAI False JSON Mode 返回原始 JSON
Ollama False 返回原始 JSON