LangExtract 后端 Provider 指南:Gemini / OpenAI / Ollama 路由机制、ModelConfig 进阶配置与自定义 Provider 插件开发
2026/9/10 22:11:55 网站建设 项目流程

LangExtract 后端 Provider 指南:Gemini / OpenAI / Ollama 路由机制、ModelConfig 进阶配置与自定义 Provider 插件开发

【免费下载链接】langextractA Python library for extracting structured information from unstructured text using LLMs with precise source grounding and interactive visualization.项目地址: https://gitcode.com/GitHub_Trending/la/langextract

LangExtract 是面向 LLM 的非结构化文本抽取库,其“抽取能力落在哪个模型后端上”由一套松耦合的 Provider 体系决定。本文以 Provider 参考文档 为主体,结合仓库内的路由注册、工厂解析与插件加载源码,系统讲解内置的 Gemini、OpenAI、Ollama 三个 Provider 的接入方式与各自行为差异、ModelConfig的高级用法,以及如何通过@router.register+ 入口点(entry point)注册一个可被 LangExtract 自动发现的自定义 Provider 插件。读完本文,你将能够在多后端之间按model_id自动路由、为私有端点与兼容接口显式指定 Provider,并独立开发、发布一个第三方 Provider。

Provider 体系一览:三个内置后端与插件扩展

LangExtract 默认内置三个 Provider,均通过“正则模式 → Provider 类”的映射被路由选中:

Provider代表模型是否内置依赖鉴权方式
Geminigemini-*系列是(google-genai为常驻依赖)GEMINI_API_KEY,回退LANGEXTRACT_API_KEY
OpenAIgpt-4*gpt-5*否,需pip install langextract[openai]OPENAI_API_KEY,回退LANGEXTRACT_API_KEY
Ollamagemma2:2bllama3.2qwen等本地模型是(通过 HTTP 访问本地服务)无需 API Key,需运行中的 Ollama 服务

在代码层面,三种 Provider 都继承自 langextract/core/base_model.py 中的抽象基类BaseLanguageModel,通过infer()把批量 prompt 转换为ScoredOutput,随后由 resolver/annotation 层解析成带字符级定位的结构化结果。因此无论是公有云、本地模型还是自定义后端,对上层lx.extract()暴露的都是同一套接口。

一个值得注意的实现细节是:模型的“自动路由规则”并不散落在 Provider 代码里,而是集中在 langextract/providers/patterns.py 中集中定义,再由 langextract/providers/builtin_registry.py 统一注册。内置注册表把每个 Provider 绑定为一组正则模式和优先级(priority),例如:

  • GEMINI_PATTERNS = (r'^gemini',),即任何以gemini开头的model_id都会命中 Gemini;
  • OPENAI_PATTERNS = (r'^gpt-4', r'^gpt4\.', r'^gpt-5', r'^gpt5\.')
  • OLLAMA_PATTERNS覆盖gemmallamamistralmixtralphiqwendeepseekcommand-r等常见本地模型前缀,以及meta-llama/Llama-3.2-1B-Instruct这类 Hugging Face 风格 ID。

三个内置 Provider 的注册优先级相同(均为 10)。当优先级相同时,langextract/providers/router.py 中的resolve()会按注册顺序取第一个模式命中的 Provider 类;如果模型 ID 同时命中多个 Provider 或需要强制指定某个后端,就应使用下文的ModelConfig(provider=...)显式选择。

lx.extract()到 Provider:一次调用内部的解析链路

理解 Provider 的用法前,先看它如何被创建。以最典型的写法为例:

result = lx.extract( text_or_documents=text, prompt_description=prompt, examples=examples, model_id="gemini-2.5-flash", # 以 gemini 开头 → 自动路由到 Gemini Provider )

在 langextract/extraction.py 中,extract()会把顶层参数整理成一个factory.ModelConfig,然后调用factory.create_model();而 langextract/factory.py 的create_model()内部分两步完成 Provider 选择:

  1. 依次执行providers.load_builtins_once()providers.load_plugins_once(),保证内置 Provider 和第三方插件的注册表都已就绪;
  2. config.provider为空,调用router.resolve(model_id),按优先级对model_id做正则搜索,返回第一个命中的 Provider 类;随后把model_idprovider_kwargs、以及从环境变量补齐的默认值一起传入该类完成实例化。

这一步解释了参考文档反复强调的“让extract()与 factory/provider 层自动决定”的含义:只要model_id命中某个 Provider 的模式,你并不需要手动导入 Provider 模块,也不需要关心 provider 内部的初始化细节,LangExtract 的工厂会自动完成“路由 → 实例化 → 注入配置”的全过程。

Gemini Provider:默认且推荐的后端

Gemini 是lx.extract()的默认 Provider——在 langextract/extraction.py 中model_id的默认值即gemini-3.5-flash,而 langextract/providers/gemini.py 的类默认值_DEFAULT_MODEL_ID = 'gemini-3.5-flash'与此一致。参考文档中的示例(gemini-2.5-flash/gemini-2.5-pro)属于面向不同任务的推荐取值:日常任务用 flash 类模型,复杂推理场景改用 pro 类模型。只要 ID 以gemini开头,路由都会命中GeminiLanguageModel

result = lx.extract( text_or_documents=text, prompt_description=prompt, examples=examples, model_id="gemini-2.5-flash", # 复杂推理可换 "gemini-2.5-pro" )

鉴权方面,GEMINI_API_KEY为第一优先,未设置时回退到LANGEXTRACT_API_KEY。这一回退逻辑由 langextract/factory.py 的_kwargs_with_environment_defaults()实现:它按model_id中是否包含"gemini"前缀决定查找哪组环境变量;当GEMINI_API_KEYLANGEXTRACT_API_KEY同时存在时,会发出一个UserWarning并采用前者。

从源码结构看,Gemini Provider 还内置了丰富的结构化输出能力与容错参数:get_schema_class()返回schemas.gemini.GeminiSchema,会把 few-shotexamples转换成 Gemini 原生支持的response_schemaresponse_mime_type='application/json',从而保证模型直接输出合法 JSON(langextract/providers/schemas/gemini.py);同时支持max_retriesretry_delaymax_retry_delay等重试参数(默认 3 次重试、指数退避),并可通过language_model_params={"http_options": ...}传入 SDK 级选项。批量 prompt 在max_workers > 1时同样使用ThreadPoolExecutor并行发送(langextract/providers/gemini.py)。

OpenAI Provider:JSON 模式、并行批处理与自动路由边界

基础用法与鉴权

OpenAI Provider 需要额外安装 SDK(pip install langextract[openai],见 pyproject.toml 的 extras),然后即可直接用 GPT 系列模型:

result = lx.extract( text_or_documents=text, examples=examples, prompt_description=prompt, model_id="gpt-4o", )

环境变量解析与 Gemini 对称:先查OPENAI_API_KEY,未设置再回退LANGEXTRACT_API_KEY

JSON mode、fence 自动推断与并行度

参考文档明确说明了 OpenAI Provider 的几个实现特征,它们都能在源码中得到印证:

  • JSON mode:当输出格式为 JSON 且未配置结构化 schema 时,Provider 会向 Chat Completions API 发送response_format={"type": "json_object"}(见 langextract/providers/openai.py 的_build_chat_completions_params()),并要求模型以“You are a helpful assistant that responds in JSON format.”作为系统提示。
  • requires_fence_output=False:由于 OpenAI 原生返回裸 JSON 而非```json围栏包裹,Provider 覆盖了requires_fence_output属性,在 JSON 格式下恒为False。因此参考文档建议不要手动设置fence_output——extract()会读取该属性自动配置 resolver,显式传值反而可能破坏自动推断。
  • 并行批处理:当max_workers > 1且批量 prompt 数大于 1 时,OpenAI Provider 用ThreadPoolExecutor并行发送请求(langextract/providers/openai.py 中infer()的实现),并行度取min(max_workers, len(prompts))。此外它还支持 OpenAI Batch API 的批处理模式(通过batchkwarg 或BatchConfig开启),此处不再展开。

关于use_schema_constraints的版本说明

参考文档提到“OpenAI Provider 不暴露 schema 类,因此use_schema_constraints是 no-op”。需要指出,这句话与当前仓库源码(版本 1.6.0,见 pyproject.toml)并不完全一致:当前OpenAILanguageModel.get_schema_class()实际返回 langextract/providers/schemas/openai.py 中的OpenAISchema,tests/provider_schema_test.py 也明确断言了这一行为。也就是说,当调用extract()时若保持默认的use_schema_constraints=True并传入examples,OpenAI 实际会走 strict JSON Schema(response_format={"type": "json_schema", ...})的结构化输出路径,且requires_raw_output=True;只有在显式关闭 schema 或未传入 examples 时,才退回到上文最朴素的json_object模式。这一差异并不影响参考文档给出的推荐写法——两者都无需你手动设置fence_outputuse_schema_constraints——但在排查“为什么 OpenAI 输出比预期更严格”时,理解这条底层路径会很有帮助。

自动路由边界:OpenAI 兼容端点与非 GPT 模型

内置 OpenAI Provider 的自动路由存在两个限制:

  1. 它只自动匹配 GPT 风格模型 ID,即^gpt-4^gpt4\.^gpt-5^gpt5\.四个模式;
  2. 工厂层做环境变量默认值补齐时,是按model_id中是否出现"gpt"(而非"openai")来决定查找OPENAI_API_KEY的。

因此,如果你接入的是OpenAI 兼容端点(LiteLLM、本地服务器、自定义base_url)或非 GPT 命名的模型model_id不会命中内置 OpenAI Provider 的模式,直接传model_id="my-model"会得到“No provider registered”类的InferenceConfigError。正确做法是通过ModelConfig显式指定 Provider 并透传端点参数:

from langextract.factory import ModelConfig result = lx.extract( text_or_documents=text, examples=examples, prompt_description=prompt, config=ModelConfig( model_id="my-openai-compatible-model", provider="openai", provider_kwargs={"api_key": "sk-...", "base_url": "https://..."}, ), )

Ollama Provider:本地模型,无 Key 推理

Ollama Provider 面向完全本地化的场景,无需任何 API Key,前置条件仅仅是运行中的 Ollama 服务,以及已ollama pull到本地的模型:

result = lx.extract( text_or_documents=text, examples=examples, prompt_description=prompt, model_id="gemma2:2b", model_url="http://localhost:11434", )

其中model_url指定 Ollama 服务地址(默认即http://localhost:11434)。从 langextract/providers/ollama.py 的源码可见,extract()model_url参数最终以base_url别名传入 Provider 构造器,因此两种写法等价;同时 Ollama Provider 也支持base_url参数,方便与其它 Provider 保持一致的调用习惯。

Ollama Provider 与另外两个 Provider 的关键差异包括:

  • Schema 能力不同:它的get_schema_class()返回FormatModeSchema(langextract/core/schema.py)。这类 schema 不约束字段级结构,只在生成时请求format='json',让 Ollama 原生保证输出是合法 JSON——对无法做严格 schema 约束的本地模型而言这是最务实的选择。同理,requires_raw_output在 JSON 下为True,所以fence_outputuse_schema_constraints同样应保持默认、交由上层根据 Provider schema 自动决定。
  • 批处理是串行的:参考文档特别提醒“max_workers > 1不会带来并行”。核对源码确实如此——infer()for prompt in batch_prompts:逐个请求,没有线程池(langextract/providers/ollama.py)。
  • 推理参数默认值:Ollama 请求默认temperature=0.1、超时 120 秒、keep_alive5 分钟、上下文num_ctx=2048;并默认以think=False发起请求,避免思维链模型只返回 reasoning trace 而导致空响应。

由于 Ollama 支持大量开源模型 ID(如llama3.2:1bmistral:7bqwen2.5:7b甚至meta-llama/Llama-3.2-1B-Instruct这样的 HF 风格命名),当某个本地模型名与其它 Provider 的模式冲突时,推荐用ModelConfig(provider="OllamaLanguageModel")显式指定。仓库中的 examples/ollama 目录还提供了可运行的演示脚本与 docker-compose 配置,适合快速做端到端验证。

ModelConfig 进阶:多 Provider 歧义消解与参数透传

当需要为 Provider 传专属 kwargs(自定义base_url、显式api_key等)、或者model_id可能命中多个 Provider 时,lx.extract()支持通过config参数传入ModelConfig

from langextract.factory import ModelConfig result = lx.extract( text_or_documents=text, examples=examples, config=ModelConfig( model_id="gpt-4o", provider_kwargs={"api_key": "your_key", "base_url": "https://..."}, ), )

参考文档总结了ModelConfig的三个字段,对应 langextract/factory.py 中 dataclass 的声明:

  • model_id:目标模型标识,如"gemini-3.5-flash""gpt-4o"。当只传provider而不传model_id时,会使用 Provider 自身的默认模型。
  • provider:可选。用于在多个 Provider 的模式都命中同一个model_id时做歧义消解,取值既可以是类名("OpenAILanguageModel"),也可以是"gemini""openai""ollama"这类大小写不敏感的名称——router.resolve_provider()会先尝试精确模式,再按类名做子串匹配。
  • provider_kwargs:Provider 专属关键字参数,例如自定义端点的base_url、显式传入的api_key、Ollama 的model_url,以及生成参数temperaturemax_output_tokens等。

需要注意的是,configmodel(已实例化的 Provider)都传入时,model优先级最高;而config又优先于model_id等顶层参数。另外参考文档中“自定义 base URL 就需要手动传provider_kwargs”的提示,对应的是工厂层环境变量补齐逻辑的边界:当model_id里既不含gemini也不含gpt时,LangExtract 不会自动从OPENAI_API_KEY/GEMINI_API_KEY读取凭据,因此访问兼容端点必须像上文那样显式提供api_key

自定义 Provider 插件:让任意模型后端接入 LangExtract

当内置 Provider 覆盖不了你的后端时,参考文档给出的方案是:继承BaseLanguageModel,并用@router.register把一段正则模式绑定到你自己的 Provider 类上:

from langextract.core.base_model import BaseLanguageModel from langextract.providers import router @router.register(r"^my-model") class MyProvider(BaseLanguageModel): ...

这样,任何以my-model开头的model_id在被router.resolve()命中时,都会实例化你的 Provider。如果插件要发布为独立的第三方包,则需要在pyproject.toml中声明入口点,让 LangExtract 在模型创建时自动发现它:

[project.entry-points."langextract.providers"] my-model = "my_package.provider:MyProvider"

关于插件生命周期,参考文档点出了两个容易被忽略的事实:

  1. 插件加载是惰性的load_plugins_once()只在第一次通过工厂创建模型时运行(langextract/providers/init.py 与 langextract/factory.py 都会调用它),而不是在import langextract时执行。该函数基于importlib.metadata枚举langextract.providers组的全部入口点并逐个加载——模块顶层的@router.register装饰器正是在这一刻触发、把模式写入路由器。加载完成后,凡是模式命中的model_id都会被自动路由到该插件。若想彻底关闭插件发现机制,可以设置环境变量LANGEXTRACT_DISABLE_PLUGINS=1(tests/provider_plugin_test.py 对该开关有专门用例)。
  2. 旧导入路径仅作兼容langextract.inferencelangextract.providers.registry仍然存在,作为向后兼容别名;新代码应如上例所示,从langextract.core.base_modellangextract.providers.router导入。

仓库在 examples/custom_provider_plugin 提供了一个可直接运行的最小示例插件,完整覆盖了 Provider 实现、schema 集成与测试脚本三部分:

  • provider.py:CustomGeminiProvider继承BaseLanguageModel并用@router.register(r'^gemini')注册(与内置 Gemini 模式相同,因此使用时必须显式provider="CustomGeminiProvider"),实现了__init__get_schema_class()apply_schema()infer()
  • schema.py:CustomProviderSchema继承core.schema.BaseSchema,通过from_examples()把 few-shot examples 分析成 JSON Schema,由to_provider_config()转换为 Provider 构造参数,并用requires_raw_output告诉上层输出是否为无围栏裸 JSON;
  • pyproject.toml:声明[project.entry-points."langextract.providers"]入口点,使插件能被自动发现;
  • test_example_provider.py:插件安装(pip install -e .)后运行python test_example_provider.py即可验证。

如果你不想从零手抄模板,仓库还提供了脚手架脚本 scripts/create_provider_plugin.py,一条命令即可生成带 schema 支持的插件骨架:

python scripts/create_provider_plugin.py MyProvider --with-schema

为自定义 Provider 添加 schema 约束支持的完整方法链是:实现get_schema_class()返回自己的BaseSchema子类 → 在 schema 中实现from_examples()(从 examples 学习结构)与to_provider_config()(转成 Provider kwargs)→ 在 Provider 的__init__/apply_schema()中接收并消费这些 kwargs → 实现requires_raw_output以配合fence_output的自动推断。可参考 langextract/providers/README.md 中“Adding Schema Support”一节的完整清单。

小结与进一步阅读

Provider 层的核心设计可概括为三条:模式驱动路由model_id正则命中即选定 Provider)、优先级 + 显式指定ModelConfig.provider用于歧义消解)、惰性插件发现(入口点 + 首次工厂调用时加载)。内置 Gemini / OpenAI / Ollama 分别覆盖默认云推理、GPT 系 JSON 结构化输出与完全本地的推理场景,三者都可保持fence_outputuse_schema_constraints默认状态,由extract()依据 Provider schema 自动配置;自定义后端则只需实现BaseLanguageModel、注册模式并声明入口点即可无缝融入。

仓库内可继续深入的材料包括:Provider 参考文档(本文主体)、Provider 系统架构说明(含模式注册时序图与完整开发 checklist)、用法技能文档(覆盖多 Provider 的选择建议)、自定义插件完整示例、路由与插件测试用例 router 解析、插件发现 以及 Provider schema 能力。

【免费下载链接】langextractA Python library for extracting structured information from unstructured text using LLMs with precise source grounding and interactive visualization.项目地址: https://gitcode.com/GitHub_Trending/la/langextract

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询