首页
/ Vane 贡献指南:本地开发环境搭建与搜索、Widget、模型 Provider 的源码定位地图

Vane 贡献指南:本地开发环境搭建与搜索、Widget、模型 Provider 的源码定位地图

2026-09-05 21:04:54作者:范垣楠Rhoda

本文为想给 Vane(一款具备高级搜索能力的 AI 对话应用)做代码贡献的开发者而写。它会带你完整走一遍本地开发环境的搭建流程(依赖安装、启动、迁移、UI 配置),并给出一张经过源码逐条核对的"改动定位地图":搜索行为在哪个文件、如何注册新的研究工具、Widget 如何与调研并行执行、新模型 Provider 如何接入注册表。读完后,你能够独立判断一个需求应该改在哪里,并了解每一处机制在源码中的真实实现。

本地开发环境搭建

Vane 采用"UI 内配置"的模式:代码本身不要求预先准备 .env 或 API key,核心步骤只有三步(引自 CONTRIBUTING.md):

  1. 安装依赖:npm install
  2. 启动开发服务:npm run dev
  3. 打开 http://localhost:3000,在界面中完成初始设置——填入模型 API key、选择聊天/嵌入模型、配置搜索后端(SearXNG)URL 等

关于脚本的实际定义,可对照 package.jsondev 对应 next devbuild 对应 next build --webpackstart 对应 next start,另有 lintnext lint)和 format:writeprettier . --write)。

数据库迁移:启动时自动应用

CONTRIBUTING.md 明确说明"Database migrations are applied automatically on startup(数据库迁移在启动时自动应用)"。这一行为在源码中有对应实现:Next.js 的 instrumentation 钩子 src/instrumentation.ts 在 Node.js 运行时执行注册时,先导入 src/lib/db/migrate.ts 执行迁移,再导入配置模块:

export const register = async () => {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    try {
      console.log('Running database migrations...');
      await import('./lib/db/migrate');
      console.log('Database migrations completed successfully');
    } catch (error) {
      console.error('Failed to run database migrations:', error);
    }

    await import('./lib/config/index');
  }
};

因此本地开发不需要手动执行迁移命令。迁移 SQL 脚本本身保存在 drizzle 目录(如 drizzle/0000_fuzzy_randall.sql 等,由 drizzle-kit 管理,元数据见 drizzle/meta/_journal.json),ORM 为 drizzle-orm + better-sqlite3,Schema 定义在 src/lib/db/schema.ts

开发模式与 Docker 的分工

CONTRIBUTING.md 特别提示:Docker 配置面向生产环境,npm run dev 用于开发。仓库根目录提供了 DockerfileDockerfile.slimdocker-compose.yamlentrypoint.sh,完整的安装选项(Docker / 非 Docker)以仓库 README 中的安装指南为准,docs/installation/UPDATING.md 则覆盖更新场景。

项目结构总览:UI、路由与后端逻辑的分层

CONTRIBUTING.md 对项目结构的描述可以归纳为三层,以下逐条对照源码核实:

UI 层(src/componentssrc/app

  • 可复用组件src/components 下包含聊天窗口(ChatWindow.tsx)、消息渲染(MessageRenderer/)、设置面板(Settings/)、Widget 渲染(Widgets/,含 Weather、Stock、Calculation 三个组件)等。
  • 页面与路由src/app 采用 Next.js App Router 结构,主路由为首页 /src/app/page.tsx)、聊天 /c/[chatId]src/app/c/[chatId]/page.tsx)、发现页 /discoversrc/app/discover/page.tsx)、库 /librarysrc/app/library/page.tsx),与 CONTRIBUTING.md 列出的路由完全一致。
  • API 路由src/app/api 下的 route handler 包括 chatsearchprovidersweatherimagesvideosdiscoveruploadssuggestionsreconnect 等,分别对应聊天、可编程搜索 API、Provider 管理、Widget 数据源等能力。

后端逻辑层(src/lib

模块 路径 职责
搜索系统 src/lib/agents/search 分类、研究、Widget、写作的完整管线
数据库 src/lib/db schema、迁移、连接
模型 Provider src/lib/models/providers 各厂商的 LLM/Embedding 实现
模型注册表 src/lib/models/registry.ts Provider 加载与实例管理
提示词模板 src/lib/prompts 分类、研究、写作等 prompt
SearXNG 集成 src/lib/searxng.ts 元搜索后端客户端
上传检索 src/lib/uploads 文件解析与语义检索

改动定位地图:搜索行为、研究工具与 Widget

CONTRIBUTING.md 的 "Where to make changes" 一节是贡献者最重要的导航。下面结合源码逐条展开。

搜索行为与推理逻辑在哪里

  • src/lib/agents/search 是核心聊天与搜索管线。
  • 分类器 src/lib/agents/search/classifier.ts 决定"是否需要研究、跑哪些搜索、是否显示 Widget"。它通过 LLM 的结构化输出(generateObject)返回一个 zod schema,字段包括 skipSearchpersonalSearchacademicSearchdiscussionSearch,以及 showWeatherWidgetshowStockWidgetshowCalculationWidget 三个 Widget 开关,外加 standaloneFollowUp——一个把追问改写为独立完整问句的字段。
  • 研究者researcher/)在后台收集信息。src/lib/agents/search/researcher/index.ts 中的 Researcher.research 是一个带工具调用的迭代循环:它按 optimizationMode 设置最大迭代次数(speed 为 2、balanced 为 6、quality 为 25),每轮让 LLM 从 ActionRegistry 获取可用工具并流式产生 toolCallChunk,再批量执行工具并把结果作为 tool 消息回注历史;当模型最后调用 done 工具或不再产生工具调用时退出循环。调研结束后,搜索结果会按 URL 去重(同 URL 的内容合并),并以 source block 的形式推送到会话。

如何添加或修改搜索能力(研究工具)

研究工具(web、academic、social/discussions、uploads、scrape)都位于 src/lib/agents/search/researcher/actions,并在 src/lib/agents/search/researcher/actions/index.ts 中统一注册:

ActionRegistry.register(webSearchAction);
ActionRegistry.register(doneAction);
ActionRegistry.register(planAction);
ActionRegistry.register(scrapeURLAction);
ActionRegistry.register(uploadsSearchAction);
ActionRegistry.register(academicSearchAction);
ActionRegistry.register(socialSearchAction);

添加新工具的路径是:在 actions/(或 actions/search/)下新建工具实现,然后在这里向 ActionRegistry 注册。需要注意工具的实际可用性是动态过滤的——ActionRegistry.getAvailableActionTools 接收 classificationfileIdsmodesources 等参数(见 researcher/index.ts),也就是说分类器的输出、用户是否上传了文件、当前优化模式和来源开关,都会决定哪些工具暴露给模型。新增工具时建议参考 webSearch.tsgetAvailableFor / 描述生成方式来声明自己的可见条件。

如何添加或修改 Widget

Widget 位于 src/lib/agents/search/widgets,注册入口是 src/lib/agents/search/widgets/index.ts:当前注册了 weatherWidgetcalculationWidgetstockWidget 三个。执行器 src/lib/agents/search/widgets/executor.tsexecuteAllPromise.all 并行运行所有 Widget——每个 Widget 先由自身的 shouldExecute(classification) 判断是否需要执行(通常由分类器输出的 showXxxWidget 字段决定),有输出的才会进入结果集。这印证了 CONTRIBUTING.md 中"Widgets run in parallel with research and show structured results in the UI"的说法:Widget 与调研并行,结构化结果直接呈现在界面上(对应 src/components/Widgets/ 下的 Renderer 等组件)。同时依据 docs/architecture/WORKING.md 的说明,Widget 是回答的辅助上下文,但不属于模型应引用的来源。

模型集成:Provider 目录与注册表

CONTRIBUTING.md 指出 Provider 位于 src/lib/models/providers,新增 Provider 后要"接入模型注册表使其在应用中可见"。

src/lib/models/providers/index.ts 维护了类型到 Provider 构造器的映射,当前内置 8 家:

export const providers: Record<string, ProviderConstructor<any>> = {
  openai: OpenAIProvider,
  ollama: OllamaProvider,
  gemini: GeminiProvider,
  transformers: TransformersProvider,
  groq: GroqProvider,
  lemonade: LemonadeProvider,
  anthropic: AnthropicProvider,
  lmstudio: LMStudioProvider,
};

每个 Provider 目录下包含 LLM 实现(如 openaiLLM.ts)、可选的 Embedding 实现(如 openaiEmbedding.ts)与 index.ts 入口,基类在 src/lib/models/base/

注册表 src/lib/models/registry.tsModelRegistry 类是接入的关键:构造时调用 initializeActiveProviders,从配置(getConfiguredModelProviders)读出已配置的 Provider,按 typeproviders 映射中查构造器并 createProviderInstance 实例化,失败的会打印日志但不阻断启动。运行期的增删改(addProvider / removeProvider / updateProvider / addProviderModel)也都经过这里,并与 configManagersrc/lib/config)持久化联动。因此"新增一个 Provider"的完整动作是:在 providers/ 下实现并导出、在 providers/index.ts 的映射表中登记;配置表单字段则由该 Provider 的 getProviderConfigFields() 提供,getModelProvidersUIConfigSection() 会据此生成设置界面的表单。

SearXNG 集成与上传检索

SearXNG。元搜索后端客户端在 src/lib/searxng.tssearchSearxng(query, opts) 从配置读取后端地址(getSearxngURL),请求 ${searxngURL}/search?format=json,支持 categoriesengineslanguagepageno 等查询参数(数组参数以逗号连接),并带 10 秒 AbortController 超时、区分超时与其他错误的处理。仓库内置了配套的 SearXNG 服务端配置(searxng/settings.ymlsearxng/limiter.tomlsearxng/uwsgi.ini),便于自行部署一个可用的搜索后端。可编程搜索 API 的请求与响应格式详见 docs/API/SEARCH.md

上传检索src/lib/uploads 负责用户文件的语义检索。src/lib/uploads/manager.tsUploadManager 以嵌入模型为构造依赖,文件存储于 data/uploads,记录写入 uploaded_files.json;支持的 MIME 类型为 PDF、Word(.docx)与纯文本,分别由 pdf-parse、officeparser 等依赖解析,再经 splitText 分块做语义索引。对应的研究工具是 researcher/actions/uploadsSearch.ts

架构文档与 API 文档入口

CONTRIBUTING.md 指向的两份架构文档是理解全局的最佳起点:

  • 高层组件概览:docs/architecture/README.md —— 列出 UI、API 路由(POST /api/chatPOST /api/searchGET /api/providers)、Agent 编排、搜索后端、LLM、嵌入模型与存储七大组件。
  • 高层流程:docs/architecture/WORKING.md —— 描述"分类 → 研究/Widget 并行 → 带引用的写作"三步,以及 optimizationModespeed / balanced / quality)在速度与质量间的取舍、引用机制、/api/images/api/videos 的图搜/视频搜端点。
  • 搜索 API 文档:docs/API/SEARCH.md

编码与贡献规范

提交改动前的检查清单(引自 CONTRIBUTING.md):

  1. 充分自测:确保代码功能正确后再提交。
  2. 统一格式化:提交前始终运行 npm run format:write(即 prettier . --write,见 package.json),保持代码风格一致;建议同时跑 npm run lintnext lint)。
  3. 社区互动:项目暂无成文的行为准则(code of conduct),作者表示正在制定中;在此之前请以友好的方式参与社区交流。

小结:从需求到改动路径速查

你的改动目标 起始位置
调整搜索行为 / 推理 src/lib/agents/search/classifier.tssrc/lib/agents/search/researcher/index.ts
新增研究工具 src/lib/agents/search/researcher/actions,并在 actions/index.ts 注册
新增/修改 Widget src/lib/agents/search/widgets,并在 widgets/index.ts 注册
接入新模型 Provider src/lib/models/providers + providers/index.ts 映射表,注册表见 src/lib/models/registry.ts
调整提示词 src/lib/prompts(classifier / researcher / writer 等)
调整搜索后端行为 src/lib/searxng.tssearxng/ 服务端配置
数据库表结构 src/lib/db/schema.tsdrizzle 迁移脚本

按这张地图定位、按上述规范提交,你的贡献就能以最小的沟通成本融入 Vane 的代码库。

登录后查看全文
热门项目推荐
相关项目推荐