zhaoxiaozhao07 commited on
Commit
9f61557
·
1 Parent(s): 99ab6ae

feat(core): 更新环境配置示例和文档以支持 GLM-4.6 模型,增强 Token 管理逻辑,可以直接.env中以”,“分割放置多个

Browse files
Files changed (3) hide show
  1. .env.example +3 -3
  2. README.md +99 -5
  3. app/core/token_manager.py +54 -23
.env.example CHANGED
@@ -11,16 +11,16 @@ AUTH_TOKEN=sk-your-api-key
11
  # 跳过客户端认证(仅开发环境使用)
12
  SKIP_AUTH_TOKEN=false
13
 
14
- # Z.ai 备用访问令牌(当匿名模式失败时使用)
15
  # 注意:这是用于访问 Z.ai 服务的令牌,不是客户端认证密钥
16
- BACKUP_TOKEN=eyJhbG.....iyDqkjPGsaiQ
17
 
18
  # ========== 服务器配置 ==========
19
  # 服务监听端口
20
  LISTEN_PORT=8080
21
 
22
  # 调试日志开关
23
- DEBUG_LOGGING=true
24
 
25
  # ========== 功能配置 ==========
26
  # 思考内容处理策略
 
11
  # 跳过客户端认证(仅开发环境使用)
12
  SKIP_AUTH_TOKEN=false
13
 
14
+ # Z.ai 备用访问令牌(当匿名模式失败时使用),可以以','分隔多个令牌,也可以放入到tokens.txt文件中
15
  # 注意:这是用于访问 Z.ai 服务的令牌,不是客户端认证密钥
16
+ BACKUP_TOKEN=token_1,token_2,token_3....
17
 
18
  # ========== 服务器配置 ==========
19
  # 服务监听端口
20
  LISTEN_PORT=8080
21
 
22
  # 调试日志开关
23
+ DEBUG_LOGGING=false
24
 
25
  # ========== 功能配置 ==========
26
  # 思考内容处理策略
README.md CHANGED
@@ -5,7 +5,7 @@
5
  ![FastAPI](https://img.shields.io/badge/framework-FastAPI-009688.svg)
6
  ![Version: 1.2.0](https://img.shields.io/badge/version-1.2.0-brightgreen.svg)
7
 
8
- 轻量级 OpenAI API 兼容代理服务,通过 Claude Code Router 接入 Z.AI,支持 GLM-4.5 系列模型的完整功能。
9
 
10
  ## ✨ 核心特性
11
 
@@ -109,7 +109,7 @@ tools = [{
109
 
110
  # 使用工具
111
  response = client.chat.completions.create(
112
- model="GLM-4.5",
113
  messages=[{"role": "user", "content": "北京天气怎么样?"}],
114
  tools=tools,
115
  tool_choice="auto"
@@ -120,7 +120,7 @@ response = client.chat.completions.create(
120
 
121
  ```python
122
  response = client.chat.completions.create(
123
- model="GLM-4.5-Thinking",
124
  messages=[{"role": "user", "content": "解释量子计算"}],
125
  stream=True
126
  )
@@ -150,7 +150,10 @@ for chunk in response:
150
  | `TOOL_SUPPORT` | `true` | Function Call 功能开关 |
151
  | `SKIP_AUTH_TOKEN` | `false` | 跳过认证令牌验证 |
152
  | `SCAN_LIMIT` | `200000` | 扫描限制 |
153
- | `BACKUP_TOKEN` | `eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...` | Z.ai 固定访问令牌 |
 
 
 
154
 
155
  ### 思考内容处理策略
156
 
@@ -158,6 +161,94 @@ for chunk in response:
158
  - `strip` - 移除思考内容
159
  - `raw` - 保留原始格式
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  ## 🎯 使用场景
162
 
163
  ### 1. AI 应用开发
@@ -174,7 +265,7 @@ client = OpenAI(
174
  # 智能客服
175
  def chat_with_ai(message):
176
  response = client.chat.completions.create(
177
- model="GLM-4.5",
178
  messages=[{"role": "user", "content": message}]
179
  )
180
  return response.choices[0].message.content
@@ -279,6 +370,9 @@ A:
279
  - **GLM-4.5-Thinking**: 需要了解推理过程的场��
280
  - **GLM-4.5-Search**: 需要实时信息的场景
281
  - **GLM-4.5-Air**: 高并发、低延迟要求的场景
 
 
 
282
 
283
  **Q: 如何自定义配置?**
284
  A: 通过环境变量配置,推荐使用 `.env` 文件。
 
5
  ![FastAPI](https://img.shields.io/badge/framework-FastAPI-009688.svg)
6
  ![Version: 1.2.0](https://img.shields.io/badge/version-1.2.0-brightgreen.svg)
7
 
8
+ 轻量级 OpenAI API 兼容代理服务,通过 Claude Code Router 接入 Z.AI,支持 GLM-4.6 系列模型的完整功能。
9
 
10
  ## ✨ 核心特性
11
 
 
109
 
110
  # 使用工具
111
  response = client.chat.completions.create(
112
+ model="GLM-4.6",
113
  messages=[{"role": "user", "content": "北京天气怎么样?"}],
114
  tools=tools,
115
  tool_choice="auto"
 
120
 
121
  ```python
122
  response = client.chat.completions.create(
123
+ model="GLM-4.6-Thinking",
124
  messages=[{"role": "user", "content": "解释量子计算"}],
125
  stream=True
126
  )
 
150
  | `TOOL_SUPPORT` | `true` | Function Call 功能开关 |
151
  | `SKIP_AUTH_TOKEN` | `false` | 跳过认证令牌验证 |
152
  | `SCAN_LIMIT` | `200000` | 扫描限制 |
153
+ | `BACKUP_TOKEN` | `eyJhbGciO...` | 固定访问令牌,多个以','分隔|
154
+ | `TOKEN_FILE_PATH` | `./tokens.txt` | Token文件路径 |
155
+ | `TOKEN_MAX_FAILURES` | `3` | Token最大失败次数 |
156
+ | `TOKEN_RELOAD_INTERVAL`| `60` | Token重载间隔(秒) |
157
 
158
  ### 思考内容处理策略
159
 
 
161
  - `strip` - 移除思考内容
162
  - `raw` - 保留原始格式
163
 
164
+ ## 🔑 Token 轮询管理
165
+
166
+ 系统支持智能 Token 轮询管理,可以在多个 Token 之间自动切换,实现负载均衡和容错处理。
167
+
168
+ ### Token 来源
169
+
170
+ 系统按以下优先级加载 Token:
171
+
172
+ 1. **tokens.txt 文件** - 在项目根目录创建 `tokens.txt` 文件,每行一个 Token
173
+ 2. **BACKUP_TOKEN 环境变量** - 支持多个 Token,以逗号分隔
174
+
175
+ ### tokens.txt 文件格式
176
+
177
+ ```
178
+ # 这是注释,会被忽略
179
+ sk-your-first-token-here
180
+ sk-your-second-token-here
181
+ sk-your-third-token-here
182
+ ```
183
+
184
+ ### BACKUP_TOKEN 环境变量格式
185
+
186
+ ```bash
187
+ # 单个 Token
188
+ BACKUP_TOKEN=sk-your-token-here
189
+
190
+ # 多个 Token(以逗号分隔)
191
+ BACKUP_TOKEN=sk-first-token,sk-second-token,sk-third-token
192
+ ```
193
+
194
+ ### Token 轮询机制
195
+
196
+ - **轮询策略**:采用轮询(Round-Robin)算法,依次使用每个可用 Token
197
+ - **失败处理**:当 Token 失败时,系统会标记失败次数,达到最大失败次数后自动禁用
198
+ - **自动恢复**:禁用的 Token 会在重新加载时重置状态
199
+ - **去重机制**:自动去除重复的 Token,确保每个 Token 只使用一次
200
+ - **状态保持**:保留已有 Token 的失败计数和使用状态
201
+
202
+ ### Token 配置参数
203
+
204
+ | 参数 | 默认值 | 说明 |
205
+ | -------------------- | ------ | ---------------------------- |
206
+ | `TOKEN_FILE_PATH` | `./tokens.txt` | Token 文件路径 |
207
+ | `TOKEN_MAX_FAILURES` | `3` | Token 最大失败次数 |
208
+ | `TOKEN_RELOAD_INTERVAL` | `60` | Token 重载间隔(秒) |
209
+
210
+ ### 使用示例
211
+
212
+ #### 1. 仅使用 tokens.txt
213
+
214
+ 创建 `tokens.txt` 文件:
215
+ ```
216
+ sk-token-1
217
+ sk-token-2
218
+ sk-token-3
219
+ ```
220
+
221
+ #### 2. 仅使用 BACKUP_TOKEN
222
+
223
+ 在 `.env` 文件中配置:
224
+ ```env
225
+ BACKUP_TOKEN=sk-token-1,sk-token-2,sk-token-3
226
+ ```
227
+
228
+ #### 3. 同时使用 tokens.txt 和 BACKUP_TOKEN
229
+
230
+ 系统会合并两个来源的 Token,自动去重:
231
+
232
+ - `tokens.txt` 包含:`sk-token-1`, `sk-token-2`
233
+ - `BACKUP_TOKEN` 包含:`sk-token-2`, `sk-token-3`
234
+ - 最终 Token 池:`sk-token-1`, `sk-token-2`, `sk-token-3`
235
+
236
+ ### Token 状态监控
237
+
238
+ 系统提供了 Token 状态统计接口,可以查看:
239
+
240
+ - Token 总数
241
+ - 活跃 Token 数量
242
+ - 失败 Token 数量
243
+ - 每个 Token 的详细信息(预览、状态、失败次数等)
244
+
245
+ ### 最佳实践
246
+
247
+ 1. **Token 分散**:将 Token 分散存储在 `tokens.txt` 和 `BACKUP_TOKEN` 中
248
+ 2. **定期更新**:定期检查 Token 有效性,及时替换失效的 Token
249
+ 3. **监控状态**:关注 Token 失败情况,及时调整配置
250
+ 4. **合理设置**:根据 API 调用频率调整 `TOKEN_MAX_FAILURES` 和 `TOKEN_RELOAD_INTERVAL`
251
+
252
  ## 🎯 使用场景
253
 
254
  ### 1. AI 应用开发
 
265
  # 智能客服
266
  def chat_with_ai(message):
267
  response = client.chat.completions.create(
268
+ model="GLM-4.6",
269
  messages=[{"role": "user", "content": message}]
270
  )
271
  return response.choices[0].message.content
 
370
  - **GLM-4.5-Thinking**: 需要了解推理过程的场��
371
  - **GLM-4.5-Search**: 需要实时信息的场景
372
  - **GLM-4.5-Air**: 高并发、低延迟要求的场景
373
+ - **GLM-4.6**: 最新模型,性能和效果最佳
374
+ - **GLM-4.6-Thinking**: 模型推理过程
375
+
376
 
377
  **Q: 如何自定义配置?**
378
  A: 通过环境变量配置,推荐使用 `.env` 文件。
app/core/token_manager.py CHANGED
@@ -60,31 +60,62 @@ class TokenManager:
60
  def _load_tokens(self) -> None:
61
  """Load tokens from file"""
62
  try:
63
- if not os.path.exists(self.token_file_path):
64
- debug_log(f"Token文件不存在: {self.token_file_path}")
65
- # Fallback to BACKUP_TOKEN if file doesn't exist
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  try:
67
  from app.core.config import settings
68
  if hasattr(settings, 'BACKUP_TOKEN') and settings.BACKUP_TOKEN:
69
- self.tokens = [TokenInfo(token=settings.BACKUP_TOKEN)]
70
- debug_log("使用配置文件中的BACKUP_TOKEN作为备用")
 
 
71
  except ImportError:
72
  pass
73
- return
74
-
75
- with open(self.token_file_path, 'r', encoding='utf-8') as f:
76
- lines = f.readlines()
77
-
78
- new_tokens = []
79
- for line in lines:
80
- token = line.strip()
81
- if token and not token.startswith('#'): # Skip empty lines and comments
82
- # Check if this token already exists to preserve failure count
83
- existing_token = next((t for t in self.tokens if t.token == token), None)
84
- if existing_token:
85
- new_tokens.append(existing_token)
86
- else:
87
- new_tokens.append(TokenInfo(token=token))
88
 
89
  if new_tokens:
90
  with self._lock:
@@ -94,14 +125,14 @@ class TokenManager:
94
  self.current_index = 0
95
  self.last_reload_time = time.time()
96
 
97
- debug_log(f"成功加载 {len(self.tokens)} 个token")
98
  active_count = sum(1 for t in self.tokens if t.is_active)
99
  debug_log(f"活跃token数量: {active_count}")
100
  else:
101
- debug_log("Token文件为空或无有效token")
102
 
103
  except Exception as e:
104
- debug_log(f"加载token文件失败: {e}")
105
 
106
  def _should_reload(self) -> bool:
107
  """Check if tokens should be reloaded"""
 
60
  def _load_tokens(self) -> None:
61
  """Load tokens from file"""
62
  try:
63
+ new_tokens = []
64
+
65
+ # 首先尝试从tokens.txt文件加载token
66
+ if os.path.exists(self.token_file_path):
67
+ with open(self.token_file_path, 'r', encoding='utf-8') as f:
68
+ lines = f.readlines()
69
+
70
+ for line in lines:
71
+ token = line.strip()
72
+ if token and not token.startswith('#'): # Skip empty lines and comments
73
+ # Check if this token already exists to preserve failure count
74
+ existing_token = next((t for t in self.tokens if t.token == token), None)
75
+ if existing_token:
76
+ new_tokens.append(existing_token)
77
+ else:
78
+ new_tokens.append(TokenInfo(token=token))
79
+
80
+ if new_tokens:
81
+ debug_log(f"从tokens.txt文件加载了 {len(new_tokens)} 个token")
82
+ else:
83
+ debug_log("Token文件为空或无有效token")
84
+
85
+ # 然后尝试从BACKUP_TOKEN环境变量加载token
86
+ try:
87
+ from app.core.config import settings
88
+ if hasattr(settings, 'BACKUP_TOKEN') and settings.BACKUP_TOKEN:
89
+ # 支持多个BACKUP_TOKEN值,以逗号分隔
90
+ backup_tokens = [token.strip() for token in settings.BACKUP_TOKEN.split(',') if token.strip()]
91
+
92
+ # 添加不重复的backup token
93
+ for backup_token in backup_tokens:
94
+ # 检查是否已经存在相同的token
95
+ existing_token = next((t for t in new_tokens if t.token == backup_token), None)
96
+ if not existing_token:
97
+ # 检查是否在原有tokens中存在,以保留失败计数
98
+ old_token = next((t for t in self.tokens if t.token == backup_token), None)
99
+ if old_token:
100
+ new_tokens.append(old_token)
101
+ else:
102
+ new_tokens.append(TokenInfo(token=backup_token))
103
+
104
+ debug_log(f"从BACKUP_TOKEN加载了 {len(backup_tokens)} 个token")
105
+ except ImportError:
106
+ pass
107
+
108
+ # 如果没有任何token,尝试仅使用BACKUP_TOKEN
109
+ if not new_tokens:
110
  try:
111
  from app.core.config import settings
112
  if hasattr(settings, 'BACKUP_TOKEN') and settings.BACKUP_TOKEN:
113
+ # 支持多个BACKUP_TOKEN值,以逗号分隔
114
+ backup_tokens = [token.strip() for token in settings.BACKUP_TOKEN.split(',') if token.strip()]
115
+ new_tokens = [TokenInfo(token=token) for token in backup_tokens]
116
+ debug_log(f"仅使用BACKUP_TOKEN,共{len(backup_tokens)}个token")
117
  except ImportError:
118
  pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
  if new_tokens:
121
  with self._lock:
 
125
  self.current_index = 0
126
  self.last_reload_time = time.time()
127
 
128
+ debug_log(f"总共加载了 {len(self.tokens)} 个token")
129
  active_count = sum(1 for t in self.tokens if t.is_active)
130
  debug_log(f"活跃token数量: {active_count}")
131
  else:
132
+ debug_log("没有找到任何可用的token")
133
 
134
  except Exception as e:
135
+ debug_log(f"加载token失败: {e}")
136
 
137
  def _should_reload(self) -> bool:
138
  """Check if tokens should be reloaded"""