Skip to content

Commit 8458bbb

Browse files
committed
feat:WaLiAPI - AI LLM LocalGateway 教程系列
1 parent 521b7d8 commit 8458bbb

15 files changed

Lines changed: 1036 additions & 2 deletions

docs/.vuepress/config.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,10 @@ module.exports = {
384384
text: 'OpenAI SDK 组件项目',
385385
link: 'https://bugstack.cn/md/zsxq/project/openai-sdk-java.html'
386386
},
387+
]
388+
},
389+
{
390+
text: '零编码区(VibeCoding)', items: [
387391
{
388392
text: 'AI 新范式(0编码),开发 + 运维(部署、压测、调优)',
389393
link: '/md/project/ai-new-paradigm/ai-new-paradigm.md'
@@ -592,6 +596,7 @@ module.exports = {
592596
"/md/project/ai-agent-scaffold/": getBarAIAgentScaffold(),
593597
"/md/project/walissh/": getBarWaLiSSH(),
594598
"/md/project/walicode/": getBarWaLiCode(),
599+
"/md/project/waliapi/": getBarWaLiAPI(),
595600
"/md/project/ai-mcp-gateway/": getBarAIMCPGateway(),
596601
"/md/project/ai-new-paradigm/": getBarAINewParadigm(),
597602
"/md/project/local-task-message/": getBarLocalTaskMessage(),
@@ -2568,6 +2573,46 @@ function getBarWaLiCode() {
25682573
]
25692574
}
25702575

2576+
function getBarWaLiAPI() {
2577+
return [
2578+
{
2579+
title: "介绍",
2580+
collapsable: false,
2581+
sidebarDepth: 0,
2582+
children: [
2583+
"waliapi.md",
2584+
"part-0/第0-1节:学习指引.md",
2585+
]
2586+
},
2587+
{
2588+
title: "1阶段 - 基础实现",
2589+
collapsable: false,
2590+
sidebarDepth: 0,
2591+
children: [
2592+
"part-1/第1-1节:初始化工程搭建.md",
2593+
"part-1/第1-2节:数据库设计与初始化.md",
2594+
"part-1/第1-3节:渠道适配器模式.md",
2595+
"part-1/第1-4节:多供应商协议适配.md",
2596+
"part-1/第1-5节:负载均衡调度器.md",
2597+
"part-1/第1-6节:API转发代理核心.md",
2598+
"part-1/第1-7节:HTTP服务器与SSE流式.md",
2599+
]
2600+
},
2601+
{
2602+
title: "2阶段 - 综合扩展",
2603+
collapsable: false,
2604+
sidebarDepth: 0,
2605+
children: [
2606+
"part-2/第2-1节:密钥管理与配额控制.md",
2607+
"part-2/第2-2节:安全审计引擎.md",
2608+
"part-2/第2-3节:安全规则与数据脱敏.md",
2609+
"part-2/第2-4节:前端页面开发.md",
2610+
"part-2/第2-5节:设置中心与打包部署.md",
2611+
]
2612+
},
2613+
]
2614+
}
2615+
25712616
function getBarAIAgentScaffold() {
25722617
return [
25732618
{
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
title: 开篇:学习指引
3+
pay: https://t.zsxq.com/tNGdW
4+
---
5+
6+
# 《WaLiAPI - 本地 LLM API 网关》开篇:学习指引
7+
8+
作者:小傅哥
9+
<br/>博客:[https://bugstack.cn](https://bugstack.cn)
10+
<br/>视频:[https://t.zsxq.com/8KuU6](https://t.zsxq.com/8KuU6)
11+
12+
>沉淀、分享、成长,让自己和他人都能有所收获!😄
13+
14+
## 一、项目介绍
15+
16+
大家好,我是技术UP主小傅哥。
17+
18+
今天开启一个 VibeCoding 新项目 ——《WaLiAPI - 本地 LLM API 网关》。该套项目,使用 AI IDE 工具完成,章节内带有开发提示词。帮助大家在一个具体场景下,通过 AI IDE 完成项目实现。
19+
20+
你是否遇到过这样的场景?
21+
22+
- 想用 Claude 的模型,但 Claude 的 API 格式和 OpenAI 不一样,要改代码。
23+
- 想同时用 OpenAI、DeepSeek、Claude、Gemini,但每家 API Key、Base URL、调用方式都不同。
24+
- 想做个负载均衡,让请求自动分配到不同的 API 供应商,一个挂了自动切换。
25+
- 想知道每次 AI 对话花了多少 Token、调用了什么参数、消耗了多少配额。
26+
- 担心发给 AI 的请求中泄露了 API Key、私钥、敏感文件路径。
27+
28+
**WaLiAPI 就是来解决这些问题的!** 它是一个本地运行的 LLM API 网关桌面软件,将各供应商 API 统一转换为 OpenAI 兼容协议,提供多渠道管理、密钥管理、负载均衡、请求日志、安全审计等完整能力。
29+
30+
## 二、项目能做什么
31+
32+
### 2.1 核心功能
33+
34+
**🔌 多渠道管理**
35+
- 支持 OpenAI、DeepSeek、Claude、Gemini、智谱、通义、Moonshot、豆包、Ollama 及自定义渠道
36+
- 优先级 + 权重的负载均衡策略
37+
- 模型映射(渠道级别 model mapping,请求模型名 → 上游模型名)
38+
39+
**🔑 密钥管理**
40+
- 为下游应用生成 `sk-waliapi-*` 格式的本地访问密钥
41+
- 支持配额限制与启用/禁用
42+
- 自定义删除确认弹窗,避免误操作
43+
44+
**📊 仪表盘**
45+
- 请求统计、Token 消耗一览
46+
- 渠道状态与服务可用率
47+
- 平均延迟监控
48+
49+
**📝 请求日志**
50+
- 完整记录每次 API 调用的请求体、模型参数、工具调用、Token 消耗与响应状态
51+
- 支持按关键词、密钥、渠道、模型、日期范围搜索筛选
52+
- 日志详情展示对话构成、工具标签、请求参数、网关路由与原始 JSON
53+
54+
**🛡️ 安全审计中心**
55+
- 风险检测引擎:自动扫描请求中的敏感信息泄露(API Key、私钥、JWT、Cookie、Bearer Token)、敏感文件路径、Unicode 隐写字符、可疑工具调用、网络风险、追踪像素
56+
- 风险等级:clean / info / low / medium / high / critical,综合评分 0-100
57+
- 策略模式:只审计 / 警告 / 脱敏 / 阻断
58+
- 规则管理:内置 25 条风险规则 + 自定义黑白名单
59+
- 日志展示:请求列表新增安全等级 Badge,详情页展示风险摘要
60+
61+
**⚙️ 设置中心**
62+
- 深色 / 浅色 / 跟随系统主题切换
63+
- 最小化到托盘、关闭到托盘、开机自启
64+
- 失败自动重试策略配置
65+
66+
**📡 流式响应**
67+
- 完整 SSE 流式转发,兼容 ChatBox / NextChat / OpenAI SDK 等下游客户端
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
title: 第1-1节:初始化工程搭建
3+
pay: https://t.zsxq.com/jftYn
4+
---
5+
6+
# 《WaLiAPI - 本地 LLM API 网关》第1-1节:初始化工程搭建
7+
8+
作者:小傅哥
9+
<br/>博客:[https://bugstack.cn](https://bugstack.cn)
10+
11+
>沉淀、分享、成长,让自己和他人都能有所收获!😄
12+
13+
14+
大家好,我是技术UP主小傅哥。
15+
16+
从这一节开始,我们将一步步搭建 WaLiAPI 项目的基础框架。WaLiAPI 是一个**本地 LLM API 网关桌面软件**,将各供应商 API 统一转换为 OpenAI 兼容协议,让下游 AI IDE(WaLiCode、ChatBox、NextChat 等)只需一套配置就能调用任意 AI 供应商。
17+
18+
## 一、本章诉求
19+
20+
我们需要完成 WaLiAPI 项目的基础框架搭建:
21+
22+
1. 初始化 Tauri + React + TypeScript 前端工程
23+
2. 配置 Rust 后端依赖(Axum、SQLx、Reqwest、Serde 等)
24+
3. 创建前端项目结构(pages、components、types、lib 等)
25+
4. 创建后端项目结构(server、core、adaptor、db、security 等)
26+
5. 让项目可以正常运行起来(`npm run tauri dev`
27+
28+
## 二、环境说明
29+
30+
### 1.1 软件安装
31+
32+
- **Rust**:使用 rustup 安装 Rust 工具链
33+
- **Node.js**:建议 20+(使用了一些新的特性)
34+
- **VS Code**:配合 Tauri、rust-analyzer 插件开发体验最佳
35+
- **Git**:用于拉取工程代码、管理分支
36+
37+
此外推荐 AI IDE 工具(任何你使用熟练的也都可以),[walicode.xiaofuge.cn](https://walicode.xiaofuge.cn/)。前端页面的代码,基本都是 AI IDE 这样的工具来完成开发即可。
38+
39+
### 1.2 整体架构设计
40+
41+
WaLiAPI 是一个**纯 Tauri 桌面应用**,采用前后端一体化架构:
42+
43+
- **前端(src/)**:React 19 + TypeScript + Vite 7 + Tailwind CSS 4,负责 UI 展示和用户交互
44+
- **后端(src-tauri/)**:Rust + Tauri 2 + Axum + SQLite + Reqwest,负责 API 网关核心逻辑
45+
- **通信方式**:Tauri Command Bridge(invoke_handler),前端通过 `invoke()` 调用后端命令
46+
47+
>为什么选 Tauri 而不是 Electron?Tauri 使用系统 WebView 渲染界面,包体积小(通常只有几 MB)、内存占用低、启动速度快。同时又具备打包成多端的能力,包括 Windows、Mac、Linux,也可以打包成安卓、iOS 应用。
48+
49+
### 1.3 为什么选择这样的技术栈?
50+
51+
**前端技术栈**
52+
- **React 19**:最流行的前端框架之一,组件化开发,配合 Vite 构建速度飞快
53+
- **Tailwind CSS 4**:原子化 CSS 框架,写样式像拼积木一样简单
54+
- **TypeScript**:类型安全,让代码更健壮、更好维护
55+
- **React Router 7**:声明式路由,页面导航清晰
56+
- **Zustand**:轻量级状态管理,比 Redux 简单很多
57+
58+
**后端技术栈**
59+
- **Tauri 2**:比 Electron 更轻量的桌面应用框架,使用 Rust 作为后端
60+
- **Axum**:Tokio 生态的 HTTP 框架,性能极高、类型安全,与 Tokio 异步运行时深度集成
61+
- **SQLx**:Rust 的异步 SQL 库,编译时检查 SQL 语句,类型安全
62+
- **Reqwest**:Rust 的 HTTP 客户端,支持流式请求和响应
63+
- **Serde**:Rust 的序列化/反序列化框架,处理 JSON 数据
64+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: 第1-2节:数据库设计与初始化
3+
pay: https://t.zsxq.com/jftYn
4+
---
5+
6+
# 《WaLiAPI - 本地 LLM API 网关》第1-2节:数据库设计与初始化
7+
8+
作者:小傅哥
9+
<br/>博客:[https://bugstack.cn](https://bugstack.cn)
10+
11+
>沉淀、分享、成长,让自己和他人都能有所收获!😄
12+
13+
大家好,我是技术UP主小傅哥。
14+
15+
上一节我们完成了 WaLiAPI 项目的初始化工程搭建。这一节我们来设计和实现数据库层——这是整个网关的数据基石,渠道配置、API 密钥、请求日志都存储在这里。
16+
17+
## 一、本章诉求
18+
19+
1. 设计数据库表结构(channels、api_keys、request_logs)
20+
2. 编写 SQL migration 迁移脚本
21+
3. 使用 sqlx 建立 SQLite 连接池
22+
4. 定义 Rust 数据模型(Channel、ApiKey、RequestLog)
23+
5. 实现 Repository 数据访问层
24+
6. 实现工具模块(ID 生成、时间格式化)
25+
26+
## 二、技术选型说明
27+
28+
### 2.1 为什么是 SQLite?
29+
30+
WaLiAPI 是一个本地桌面应用,数据库的选择有几个候选:
31+
32+
| 方案 | 优点 | 缺点 |
33+
|---|---|---|
34+
| SQLite | 零配置、单文件、随应用分发、性能好 | 不适合多进程并发写 |
35+
| JSON 文件 | 简单 | 无索引、查询困难、无事务 |
36+
| 嵌入式 RocksDB | 性能极高 | 编译慢、二进制体积大 |
37+
38+
对于桌面应用来说,**SQLite 是最优解**:零配置、单文件存储在应用数据目录、支持 SQL 查询和索引、有成熟的迁移机制。
39+
40+
### 2.2 为什么是 sqlx?
41+
42+
Rust 生态中操作 SQLite 的库主要有两个:
43+
- **rusqlite**:同步 API,简单直接,但在 async 环境中会阻塞线程
44+
- **sqlx**:异步 API,编译时检查 SQL,支持连接池,与 Tokio 深度集成
45+
46+
我们使用 `sqlx` + `runtime-tokio`,配合 `SqlitePoolOptions` 建立连接池。
47+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
title: 第1-3节:渠道适配器模式
3+
pay: https://t.zsxq.com/jftYn
4+
---
5+
6+
# 《WaLiAPI - 本地 LLM API 网关》第1-3节:渠道适配器模式
7+
8+
作者:小傅哥
9+
<br/>博客:[https://bugstack.cn](https://bugstack.cn)
10+
11+
>沉淀、分享、成长,让自己和他人都能有所收获!😄
12+
13+
大家好,我是技术UP主小傅哥。
14+
15+
上一节我们完成了数据库层。这一节进入 WaLiAPI 最核心的设计——**渠道适配器模式**。这是整个网关的灵魂:对外暴露统一的 OpenAI 协议,对内对接 N 家不同的 AI 供应商。
16+
17+
## 一、本章诉求
18+
19+
1. 理解适配器模式(Adaptor Pattern)在 API 网关中的应用
20+
2. 定义 `Adaptor` trait——所有渠道适配器的统一抽象
21+
3. 实现 OpenAI 适配器(透传 + 模型映射)
22+
4. 实现 DeepSeek 适配器(OpenAI 兼容协议的复用)
23+
5. 实现渠道类型的元数据管理(channel_types)
24+
25+
## 二、为什么要用适配器模式?
26+
27+
### 2.1 问题场景
28+
29+
假设不用适配器模式,我们的代码会变成什么样?
30+
31+
```rust
32+
// ❌ 反面教材:if-else 地狱
33+
async fn forward(channel_type: &str, request: &Request) -> Response {
34+
if channel_type == "openai" {
35+
// OpenAI 的请求逻辑
36+
} else if channel_type == "claude" {
37+
// Claude 的请求逻辑:x-api-key 头、anthropic-version、消息格式转换...
38+
} else if channel_type == "gemini" {
39+
// Gemini 的请求逻辑:URL 带 key 参数、contents/parts 格式...
40+
} else if channel_type == "deepseek" {
41+
// ...
42+
}
43+
}
44+
```
45+
46+
这样的代码有几个致命问题:
47+
- **违反开闭原则**:每加一个供应商就要改核心转发函数
48+
- **职责不单一**:一个函数要懂所有供应商的协议细节
49+
- **无法独立测试**:想测 Claude 的逻辑必须把整个函数跑起来
50+
51+
### 2.2 适配器模式解法
52+
53+
每家供应商是一个独立的"适配器",实现统一的接口:
54+
55+
```
56+
┌─────────────────┐
57+
统一 OpenAI 请求 │ Proxy 代理层 │ 统一 OpenAI 响应
58+
──────────→ │ │ ──────────→
59+
│ get_adaptor() │
60+
└────────┬────────┘
61+
│ trait Adaptor
62+
┌──────────┬─────────┼─────────┬──────────┐
63+
↓ ↓ ↓ ↓ ↓
64+
┌─────────┐┌─────────┐┌────────┐┌────────┐┌────────┐
65+
│ OpenAI ││DeepSeek ││ Claude ││ Gemini ││ Custom │
66+
│ Adaptor ││ Adaptor ││Adaptor ││Adaptor ││Adaptor │
67+
└────┬────┘└────┬────┘└───┬────┘└───┬────┘└───┬────┘
68+
↓ ↓ ↓ ↓
69+
api.openai deepseek anthropic google 任意兼容端点
70+
```
71+
72+
Proxy 层只依赖 `Adaptor` trait 这个抽象,不关心具体是哪家供应商。新增供应商 = 新增一个实现 trait 的结构体 + 在工厂函数中注册一行。
73+

0 commit comments

Comments
 (0)