- AI 应用
- MCP 服务
- AI Agent
- 后端
- 前端
【免费下载链接】NLWeb
Main reference implementation for NLWeb, implemented in Python.
NLWeb 是一个面向 AI Web 的开放协议与开源参考实现,其核心运行依赖两类外接能力:LLM 模型(Model/LLM Provider)与检索后端(Retrieval Provider / 向量数据库)。本文以仓库中的 docs/nlweb-providers.md 为骨架,系统梳理为 NLWeb 贡献新模型、新检索后端时所需完成的全部配置、代码、文档与测试工作,并结合config目录下的真实配置与AskAgent核心源码逐层讲解底层实现原理,帮助开发者完整、正确地完成 Provider 接入。
为什么需要扩展 Provider:NLWeb 的开放标准架构
NLWeb 本身并不绑定任何单一模型或向量数据库。从仓库根目录的 README.md 可以看到,NLWeb 官方支持的向量存储包括 Qdrant、Snowflake、Milvus、Azure AI Search、Elasticsearch、Postgres、Cloudflare AutoRAG,LLM 则支持 OpenAI、DeepSeek、Gemini、Anthropic、Inception、HuggingFace 等,并且这些能力全部通过 YAML 配置与"接口 + 实现"的方式插拔式接入。
这意味着:无论是接入一个新的模型厂商,还是接入一个新的向量数据库,都不需要改动业务主流程,只需遵循一套约定好的清单(Checklist)完成配置、接口实现、文档和测试四件事。这正是 docs/nlweb-providers.md 所要表达的核心思想——NLWeb 通过开放的 Provider 接口层,让社区可以像构建 Web 生态一样持续贡献新能力。
从源码结构看,两条扩展路径分别落在两个关键目录:
- LLM Provider:
AskAgent/python/llm_providers/(各模型实现)与AskAgent/python/core/llm.py(分发入口) - Retrieval Provider:
AskAgent/python/retrieval_providers/(各数据库实现)与AskAgent/python/core/retriever.py(统一路由)
下文分别给出两套完整清单,并在每个步骤中标注对应的仓库文件作为可验证依据。
LLM Provider 接入清单
在 docs/nlweb-providers.md 的 Model LLM Provider Checklist 中,接入一个新模型需要完成文件更新、新文件、测试三个部分的共六类工作。
1. 在 config/config_llm.yaml 中注册端点
首先在 config/config_llm.yaml 的endpoints下新增一个条目,包含:API Key 的环境变量名、API Endpoint 的环境变量名,以及默认的 high / low 双档模型。文档给出的示例为:
openai: api_key_env: OPENAI_API_KEY api_endpoint_env: OPENAI_ENDPOINT models: high: gpt-4.1 low: gpt-4.1-mini需要说明的是,api_key_env/api_endpoint_env既可以填写环境变量名,也可以直接填写字面值。这一行为在 AskAgent/python/core/config.py 的_get_config_value方法中有明确定义:当值以_ENV结尾或全为大写时,被当作环境变量名从os.getenv读取;否则被当作字面字符串直接使用(见config.py中约 226-244 行)。这是理解整套配置系统的关键。
仓库中真实的 config/config_llm.yaml 展示了完整的端点集合(节选),可作为新条目格式的参照:
preferred_endpoint: azure_openai endpoints: anthropic: api_key_env: ANTHROPIC_API_KEY llm_type: anthropic models: high: claude-3-7-sonnet-latest low: claude-3-5-haiku-latest azure_openai: api_key_env: AZURE_OPENAI_API_KEY api_endpoint_env: AZURE_OPENAI_ENDPOINT api_version_env: "2024-12-01-preview" auth_method: AZURE_OPENAI_AUTH_METHOD llm_type: azure_openai models: high: gpt-4.1 low: gpt-4.1-mini gemini: api_key_env: GEMINI_API_KEY llm_type: gemini models: high: gemini-2.5-pro low: gemini-2.0-flash-lite huggingface: api_key_env: HF_TOKEN llm_type: huggingface models: high: Qwen/Qwen2.5-72B-Instruct low: Qwen/Qwen2.5-Coder-7B-Instruct openai: api_key_env: OPENAI_API_KEY api_endpoint_env: OPENAI_ENDPOINT llm_type: openai models: high: gpt-4.1 low: gpt-4.1-mini snowflake: api_key_env: SNOWFLAKE_PAT api_endpoint_env: SNOWFLAKE_ACCOUNT_URL api_version_env: "2024-12-01" llm_type: snowflake models: high: claude-3-5-sonnet low: llama3.1-8b从上述真实配置可以看到,除文档示例中的api_key_env、api_endpoint_env、models.high/low之外,仓库还常用到几个可选项:
| 字段 | 含义 | 是否必需 |
|---|---|---|
api_key_env | API Key 来源(环境变量名或字面值) | 视提供方而定 |
api_endpoint_env | API Endpoint 来源(环境变量名或字面值) | 云端服务通常需要 |
api_version_env | API 版本号 | 部分提供方需要(如 Azure) |
llm_type | 映射到llm_providers/下实现模块的类型标识 | 必需 |
auth_method | 认证方式,默认api_key | 可选 |
models.high | 高质量档模型(用于生成型任务) | 必需 |
models.low | 低质量/低成本档模型(用于轻量任务) | 必需 |
顶部的preferred_endpoint指定默认使用的 LLM 端点;ask_llm在未显式指定 provider 时使用它(见下文 llm.py 说明)。
2. 同步环境变量模板
清单要求把新增的环境变量同步登记到AskAgent/env.template,为默认值合适时填入默认值,让新用户知道需要准备哪些环境变量。需要提示的是:在当前仓库镜像中并未包含该模板文件(find_files未检索到env.template),实际使用时需自行按清单要求创建;仓库同时提供了 AskAgent/example-set-keys.sh 演示脚本,以export OPENAI_API_KEY="your key"的形式展示如何在 shell 中设置这些密钥(该脚本注释明确说明仅用于演示,生产环境建议写入 shell profile 或安全环境)。
3. 实现 LLMProvider 接口
清单要求新建AskAgent/python/llm_providers/<your_model_name>.py,实现 LLMProvider 接口。接口定义位于 AskAgent/python/llm_providers/llm_provider.py,它是一个抽象基类,要求实现三个抽象成员:
get_completion(prompt, schema, model=None, temperature=0.7, max_tokens=2048, timeout=30.0, **kwargs):向 LLM 发送补全请求并返回解析后的 JSON 字典。其中schema用于约束响应符合指定 JSON Schema,model为 None 时使用配置中的默认模型,超时抛出TimeoutError。get_client()(类方法):获取或初始化该提供方的客户端实例,线程安全。clean_response(content)(类方法):清洗并解析原始响应文本为结构化字典,解析失败应抛出ValueError。
仓库中已有多份完整实现可作为新 Provider 的模板,例如 AskAgent/python/llm_providers/openai.py:
get_api_key()从CONFIG.llm_endpoints["openai"].api_key读取密钥;get_client()使用线程锁保证AsyncOpenAI客户端只初始化一次;_build_messages()构造"系统消息中注入 JSON Schema + 用户消息携带 prompt"的消息序列,实现 Schema 约束;get_completion()通过asyncio.wait_for包裹client.chat.completions.create实现超时控制,返回clean_response()的解析结果;clean_response()先用正则剔除 ``` 代码围栏,再提取首个 JSON 对象。
AskAgent/python/llm_providers/anthropic.py 展示了另一种实现风格:其消息序列以assistant角色先声明"我将返回符合该 Schema 的 JSON"、user角色携带 prompt,get_client()使用AsyncAnthropic,文件末尾还提供了get_anthropic_completion兼容别名。两相对照可以看出,不同厂商 SDK 的差异被完全封装在 Provider 内部,对上层(core/llm.py)保持统一接口。
4. 在 llm.py 注册 provider 映射
清单要求将新模型添加到AskAgent/python/llm_providers/llm_provider.py的 provider 映射中。结合源码看,实际的分发映射位于 AskAgent/python/core/llm.py:
_llm_type_packages(约 39-50 行):定义每种llm_type依赖的 pip 包,如"openai": ["openai>=1.12.0"]、"gemini": ["google-cloud-aiplatform>=1.38.0"]、"inception": ["aiohttp>=3.9.1"]。_ensure_package_installed()会先尝试 import,失败则自动pip install。_get_provider(llm_type)(约 96-154 行):通过if llm_type == "openai": from llm_providers.openai import provider ...的分支结构把llm_type映射到具体实现模块的provider单例,并做缓存。新增 Provider 时,必须在此处补充一个llm_type到模块的映射分支,这正是文档所说"Add your model to the provider mapping here"的落点。ask_llm()(约 156-266 行):provider参数缺省时使用CONFIG.preferred_llm_endpoint;开发模式下还支持通过query_params中的llm_provider/llm_level覆盖;随后根据level("low"/"high")从provider_config.models取出对应模型 ID,调用provider_instance.get_completion(prompt, schema, model=model_id, timeout=timeout, max_tokens=max_length)。
5. 编写模型专属文档
清单要求新建docs/setup-<your-model-name>.md,记录模型相关的专属说明。仓库中已有同类文档可参考,例如 docs/setup-ollama.md(讲解如何将preferred_endpoint切换为ollama并填写模型名)、docs/setup-huggingface.md(说明 HF_TOKEN 的用途及多 Inference Provider 路由)、docs/setup-azure.md(涵盖 Azure OpenAI 端点创建、三个模型部署与AZURE_OPENAI_ENDPOINT/AZURE_OPENAI_API_KEY的获取)。
6. 连通性测试
清单要求用连通性检查工具验证集成:配置正确时应通过,API Key 未设置或配置不完整时应失败,并最好给出有助诊断的错误信息。对应脚本为 AskAgent/python/testing/check_connectivity.py,其check_llm_api(llm_name)会向该 provider 发起一个"法国首都是哪里"的测试请求并要求返回符合{"capital": "string"}的 JSON,通过检查输出是否包含 "Paris" 判定成功;错误信息会给出异常类型与详情。针对 LLM 的专项检查还可参考 AskAgent/python/testing/connectivity/azure_connectivity.py 中的check_azure_openai_api/check_openai_api。
Retrieval Provider 接入清单
在 docs/nlweb-providers.md 的 Retrieval Provider Checklist 中,接入一个新的检索提供方/向量数据库同样需要完成文件更新、新文件、测试三类工作。
1. 在 config/config_retrieval.yaml 中注册端点
在 config/config_retrieval.yaml 的endpoints下新增条目,包含索引名(index_name)、数据库类型(db_type),以及两种凭据方式二选一:本地数据库填database_path,云端托管填api_key_env+api_endpoint_env。文档给出的两个示例:
qdrant_local: database_path: "../data/db" index_name: nlweb_collection db_type: qdrant snowflake_cortex_search_1: api_key_env: SNOWFLAKE_PAT api_endpoint_env: SNOWFLAKE_ACCOUNT_URL index_name: SNOWFLAKE_CORTEX_SEARCH_SERVICE db_type: snowflake_cortex_search仓库真实配置中endpoints下的字段比文档示例更丰富,常见字段如下:
| 字段 | 含义 | 说明 |
|---|---|---|
enabled | 是否启用该端点 | 真实配置中每个端点都带此开关(默认 false) |
api_key_env | API Key 环境变量名 | 云端服务使用 |
api_endpoint_env | Endpoint 环境变量名 | 云端服务使用 |
database_path | 本地数据库路径 | 本地服务使用(如qdrant_local的../data/db) |
index_name | 索引/集合/服务名 | 例如 Qdrant 的nlweb_collection、Elasticsearch 的nlweb_embeddings、Snowflake 的SNOWFLAKE_CORTEX_SEARCH_SERVICE |
db_type | 数据库类型标识 | 决定路由到哪个客户端实现 |
vector_type | 向量类型与索引选项 | 如 Elasticsearch 的dense_vector+int8_hnsw字节量化 |
use_knn | 是否使用 k-NN 插件 | OpenSearch 特有 |
此外,文件顶部的write_endpoint指定写入端点(数据加载、文档删除等写操作的目标)。从 AskAgent/python/core/config.py 的load_retrieval_config(约 318-353 行)可以看到,RetrievalProviderConfig会保存api_key_env/api_endpoint_env的原始环境变量名(供诊断),同时通过_get_config_value解析出实际凭据值;每个端点还带有enabled字段,替代了旧的单一preferred_endpoint机制。
2. 同步环境变量模板
与 LLM 侧一致,清单要求把新增环境变量登记到AskAgent/env.template。仓库中各个检索后端的专属 setup 文档都明确了对应变量,例如:
- docs/setup-qdrant.md:
QDRANT_URL(如http://localhost:6333)与可选的QDRANT_API_KEY;若设置database_path则使用本地持久化实例。 - docs/setup-elasticsearch.md:
ELASTICSEARCH_URL、ELASTICSEARCH_API_KEY。 - docs/setup-postgres.md:
POSTGRES_CONNECTION_STRING(如postgresql://<HOST>:<PORT>/<DATABASE>?user=<USERNAME>&sslmode=require)与POSTGRES_PASSWORD。 - docs/setup-cloudflare-autorag.md:
CLOUDFLARE_API_TOKEN、CLOUDFLARE_RAG_ID_ENV、CLOUDFLARE_ACCOUNT_ID。 - docs/setup-snowflake.md:
SNOWFLAKE_ACCOUNT_URL与SNOWFLAKE_PAT(Programmatic Access Token)。
3. 实现 VectorDBClientInterface
清单中的新文件路径写作AskAgent/python/retrieval/<your_retrieval_name>_client.py。需要注意:当前仓库的实际目录名是AskAgent/python/retrieval_providers/(而非retrieval),实现应放在该目录下。
接口定义位于 AskAgent/python/core/retriever.py 的VectorDBClientInterface(约 144-239 行),要求实现五个抽象方法:
| 方法 | 职责 |
|---|---|
delete_documents_by_site(site, **kwargs) -> int | 按站点删除所有文档,返回删除数量 |
upload_documents(documents, **kwargs) -> int | 批量上传文档(含向量) |
search(query, site, num_results=50, **kwargs) -> list[list[str]] | 在指定站点内检索 |
search_by_url(url, **kwargs) -> list[str] \| None | 按 URL 精确取回文档 |
search_all_sites(query, num_results=50, **kwargs) -> list[list[str]] | 跨全部站点检索 |
基类RetrievalClientBase(约 242-348 行)已提供带缓存的默认行为:can_handle_query()判断该后端是否覆盖请求站点(支持 stale-while-revalidate 的站点缓存、5 分钟过期);不实现get_sites()的后端返回None表示"可能拥有任意站点"。新实现推荐继承RetrievalClientBase而非直接实现接口,以免费获得站点缓存与查询路由能力。
仓库中可参考的完整实现包括:
- AskAgent/python/retrieval_providers/qdrant.py:
QdrantVectorClient同时支持 URL 模式(api_endpoint以http(s)://开头时传入url/api_key)与本地模式(database_path经_resolve_path解析为绝对路径传入path),并内置集合创建(COSINE 距离、1536 维)、集合重建与"服务器连接被拒时回退本地存储"的能力。 - AskAgent/python/retrieval_providers/azure_search_client.py:
AzureSearchClient基于 Azure SDK 的SearchIndexClient/SearchClient,构造时校验api_endpoint与api_key缺失即抛ValueError,这正是文档要求的"配置不当时给出有助诊断的错误信息"。 - AskAgent/python/retrieval_providers/snowflake_client.py:
SnowflakeCortexSearchClient通过index_name解析<database>.<schema>.<service>三段式服务名,search委托给retrieval_providers/utils/snowflake.py中的 REST 查询实现。
4. 在 retriever.py 中注册路由
清单要求"在VectorDBClient类中添加逻辑以路由到你的检索提供方"。结合源码,这一步实际涉及 AskAgent/python/core/retriever.py 中三处:
init()(约 31-77 行):遍历CONFIG.retrieval_endpoints,对enabled且db_type非空的端点按db_type预加载对应客户端模块(azure_ai_search→AzureSearchClient、qdrant→QdrantVectorClient、snowflake_cortex_search→SnowflakeCortexSearchClient、elasticsearch→ElasticsearchClient、postgres→PgVectorClient、opensearch→OpenSearchClient、milvus→MilvusVectorClient、cloudflare_autorag→CloudflareAutoRAGClient、bing_search→BingSearchClient、shopify_mcp→ShopifyMCPClient等)。新增db_type时必须在此处补充映射分支。_db_type_packages(约 80-91 行):为每种db_type声明所需 pip 包(如 Qdrant 需要qdrant-client>=1.14.0,Postgres 需要psycopg/pgvector>=0.4.0),由_ensure_package_installed()自动补装。VectorDBClient.get_client(endpoint_name)(约 502-581 行):按db_type+ 端点名做客户端缓存,动态导入并实例化对应的VectorDBClientInterface实现。
VectorDBClient还承担了多端点并行检索与结果聚合:search()会为每个启用且持有目标站点的端点创建异步任务并行查询,_aggregate_results()对重复 URL 合并 JSON 数据(merge_json_array),_deduplicate_by_url()保留内容更长的条目,最后按相关性顺序截断到num_results。这说明新增一个检索后端后,它会自动获得与既有后端并行的多源检索、去重与合并能力。
5. 数据加载工具(可选)
清单说明AskAgent/python/data_loading/<your_retrieval_name>_load.py负责将向量加载进新数据库,并且是可选的——如果能在客户端文件内完成也可省略。仓库中已有 AskAgent/python/data_loading/db_load.py(通用加载工具,支持 CSV、URL、RSS 三种来源,process_line()可解析"URL\tJSON"两列或纯 JSON 单列格式并自动从url/@id/identifier字段提取 URL)与 AskAgent/python/data_loading/qdrant_load.py(示例:命令行参数--path指定含.txt文件的目录、--database覆盖write_endpoint、--site指定站点名、--recreate重建集合;文件名默认作为站点名)。数据加载路径上还有 AskAgent/python/data_loading/rss2schema.py、AskAgent/python/data_loading/process_rss_by_org.py 等配套工具,可一并了解。
6. 检索器专属文档
清单要求新建docs/setup-<your-retriever-name>.md并记录你提供的工具。仓库中已有覆盖绝大多数后端的文档:Qdrant(docs/setup-qdrant.md)、Snowflake(docs/setup-snowflake.md)、Elasticsearch(docs/setup-elasticsearch.md)、Postgres/pgvector(docs/setup-postgres.md,含建表 SQL、HNSW 索引与python misc/postgres_load.py初始化命令)、OpenSearch(docs/setup-opensearch.md,含use_knn两种模式与认证格式说明)、Milvus(docs/setup-milvus.md)、Cloudflare AutoRAG(docs/setup-cloudflare-autorag.md)。这些文档均可作为新后端文档的模板。
7. 连通性测试
与 LLM 侧共用同一工具 AskAgent/python/testing/check_connectivity.py。其check_retriever(retrieval_name)使用get_vector_db_client(retrieval_name)构造指定端点的客户端(而非全局搜索——全局搜索会掩盖单个端点的错误),再执行search("e", site="all", num_results=1),通过判断返回值是否非空且格式符合[url, json, name, site]四元组来判定连通性。专项检查还包括 AskAgent/python/testing/connectivity/azure_connectivity.py 中的check_azure_search_api(创建SearchClient并调用get_document_count())、AskAgent/python/testing/connectivity/snowflake_connectivity.py 中的check_search/check_embedding/check_complete。
用连通性检查工具验证整个配置
接入完成后,按 docs/nlweb-check-connectivity.md 的说明运行验证:
# 在 AskAgent 目录下执行(默认只检查配置文件中已启用的项) python AskAgent/python/testing/check_connectivity.py该脚本默认模式会依次检查preferred_llm_endpoint、preferred_embedding_provider以及所有enabled=true的检索端点,并输出✅ X/Y connections successful汇总;任何失败都会打印带异常类型与详情的错误行。
如需对所有已知配置做全量回归,使用--all参数:
python AskAgent/python/testing/check_connectivity.py --all该模式会遍历CONFIG.llm_endpoints、CONFIG.embedding_providers、CONFIG.retrieval_endpoints中记录的每一个 provider 并发执行检查,适合接入 CI 测试套件。关于三端检查的判定逻辑,可分别对照脚本中的check_llm_api(期望输出包含 "Paris")、check_embedding_api(期望返回浮点列表)与check_retriever(期望返回合法结果格式)。真实配置下,若某端点在config_retrieval.yaml中enabled: false,则默认模式会跳过它——这也是新增后端时建议先把enabled设为false、调试通过后再开启的原因。
接入新 Provider 的源码级要点回顾
综合 docs/nlweb-providers.md 与仓库源码,两条接入路径的共性规律可以归纳为四步:配置声明 → 接口实现 → 路由注册 → 文档与测试。几个容易踩坑的细节:
llm_type/db_type是路由键:LLM 侧必须同时出现在 AskAgent/python/core/llm.py 的_llm_type_packages与_get_provider()分支中;检索侧必须同时出现在 AskAgent/python/core/retriever.py 的_db_type_packages、init()预加载分支与get_client()的创建分支中。遗漏任一分支都会导致运行时 "Unknown LLM type" 或 "Unsupported database type" 错误。_get_config_value的值语义:配置项填的是"环境变量名"还是"字面值",取决于是否以_ENV结尾或全大写(见 AskAgent/python/core/config.py 约 226-244 行)。混用会造成密钥解析为字面字符串或反之的困惑。enabled与凭据校验:VectorDBClient构造时会用_has_valid_credentials()过滤"已启用但缺凭据"的端点(如azure_ai_search需同时有 key 与 endpoint,qdrant有database_path即可,elasticsearch只需 endpoint),并在全部不可用时抛出包含可用端点列表的ValueError——调试时这是最有价值的信息源。- 写操作只走
write_endpoint:upload_documents/delete_documents_by_site只会路由到config_retrieval.yaml顶部的write_endpoint,新后端若需承载写入,务必将其设为write_endpoint(或通过--database参数显式覆盖)。 - 依赖自动安装:
_ensure_package_installed/_ensure_package_installed会在导入失败时自动执行pip install --quiet,因此新 Provider 的依赖只需在映射表里声明即可,无需手动干预。
结语
docs/nlweb-providers.md 以两份精炼的清单定义了 NLWeb 生态扩展的"契约",而本仓库的源码(AskAgent/python/llm_providers/、AskAgent/python/core/、AskAgent/python/retrieval_providers/、AskAgent/python/data_loading/)与文档(docs/setup-*.md系列)则为每一行清单条目提供了可运行、可对照的实现参照。无论是为 NLWeb 接入一个新模型,还是接入一个新的向量数据库,按"配置 → 实现 → 注册 → 文档 → 连通性验证"的顺序推进,即可在保持主流程零改动的前提下完成能力扩展。更高层的贡献原则还可参考仓库根目录的 CONTRIBUTING.md(如清单未覆盖、需要更多新文件的情况,可在 issue 中寻求指导)。
- AI 应用
- MCP 服务
- AI Agent
- 后端
- 前端
【免费下载链接】NLWeb
Main reference implementation for NLWeb, implemented in Python.
相关推荐
Label Studio 支持的基座模型(Base Models)全解析:Provider 模型清单、接入模式与源码实现
Label Studio 支持的基座模型(Base Models)全解析:Provider 模型清单、接入模式与源码实现 本文围绕 Label Studio 官
数据标注人工智能AutoAgent LLM 后端配置全指南:模型选型、Provider 接入与重试机制
AutoAgent LLM 后端配置全指南:模型选型、Provider 接入与重试机制 本指南围绕 AutoAgent(Fully Automated & Ze
人工智能大模型AI AgentAgent 框架工具调用自主智能体RAGpi monorepo 实战指南:向 packages/ai 新增 LLM Provider 的完整清单与源码解析
pi monorepo 实战指南:向 packages/ai 新增 LLM Provider 的完整清单与源码解析 pi 是一个 AI agent toolki
人工智能大模型AI Agent代码智能体AI 应用工具调用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考