Skip to content

Commit d3c98a5

Browse files
hao65103940OpenClaw
andauthored
Feat/support subpath deployment (#2)
* feat: 支持 MaxKB 子路径部署并优化配置说明 主要改进: 1. 新增 MAXKB_API_PREFIX 环境变量,支持子路径部署(如 /mk) 2. 修复 _build_api_path 函数,正确处理 /chat/ 路径(不需要 API 前缀) 3. 更新 .env.example 添加详细配置说明和示例 4. 所有 HTTP 请求函数统一使用 _build_api_path 处理路径 修复问题: - 修复了子路径部署时 /chat/api/ 路径错误添加前缀的问题 - 修复了登录 API 路径硬编码问题 - 优化了环境变量配置的文档说明 测试验证: - ✅ /api/... 路径正确添加前缀 → /mk/api/... - ✅ /chat/... 路径保持原样 → /chat/... - ✅ 智能体列表获取正常 - ✅ 对话功能正常 * docs: 在 README 中补充 MAXKB_API_PREFIX 配置说明 - 新增 MAXKB_API_PREFIX 环境变量的详细说明 - 添加子路径部署场景的配置示例 - 说明路径处理规则(/chat/ 路径不添加前缀) - 更新快速开始中的配置示例 * feat: 优化 MAXKB_API_PREFIX 默认值为 /admin - 将 MAXKB_API_PREFIX 默认值从空字符串改为 /admin - 更新 .env.example 配置示例 - 更新 README 文档说明 - 添加 4 种部署场景的配置示例 适用场景: - 标准 MaxKB 部署:使用默认值 /admin - 子路径部署:配置为子路径(如 /mk) - 根路径无前缀:配置为空字符串 * docs: 优化 README 环境变量说明 - 添加必填/选填标记(✅/❌/⚠️) - 明确 MAXKB_API_PREFIX 为选填参数 - 说明认证方式的优先级 - 更新 .env 配置示例,分类为必填/选填/认证 - 添加更清晰的配置提示 * 修复登录 API 路径,支持子路径部署 --------- Co-authored-by: OpenClaw <openclaw@local>
1 parent f5d93c9 commit d3c98a5

3 files changed

Lines changed: 124 additions & 19 deletions

File tree

.env.example

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
1+
# MaxKB 服务地址(必填)
2+
# 示例:http://localhost:8080 或 https://maxkb.example.com
13
MAXKB_DOMAIN=<maxkb_domain>
4+
5+
# MaxKB API 前缀(可选)
6+
# 默认值:/admin(标准 MaxKB 部署)
7+
# 如果 MaxKB 部署在子路径下(如 http://example.com/mk),配置此项为 /mk
8+
# 如果 MaxKB 部署在根路径且无 /admin 前缀,留空即可
9+
MAXKB_API_PREFIX=/admin
10+
11+
# MaxKB 认证 Token(二选一:Token 或 用户名密码)
12+
# 优先级:用户名密码 > Token
213
MAXKB_TOKEN=
3-
MAXKB_WORKSPACE_ID=default
14+
15+
# MaxKB 登录用户名(二选一:Token 或 用户名密码)
416
MAXKB_USERNAME=admin
5-
MAXKB_PASSWORD=admin123
17+
18+
# MaxKB 登录密码(二选一:Token 或 用户名密码)
19+
MAXKB_PASSWORD=admin123
20+
21+
# MaxKB 工作空间 ID(可选,默认为 default)
22+
MAXKB_WORKSPACE_ID=default

README.md

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,36 @@ cp .env.example .env
7171
编辑 `.env`
7272

7373
```env
74-
MAXKB_DOMAIN=<maxkb_domain>
74+
# ==================== 必填配置 ====================
75+
76+
# MaxKB 服务地址(必填)
77+
MAXKB_DOMAIN=http://localhost:8080
78+
79+
# ==================== 选填配置 ====================
80+
81+
# MaxKB API 前缀(选填,默认 /admin)
82+
# - 标准 MaxKB 部署:无需配置(默认 /admin)
83+
# - 子路径部署(如 http://example.com/mk):配置为 /mk
84+
# - 根路径无前缀:配置为空字符串 ""
85+
MAXKB_API_PREFIX=/admin
86+
87+
# MaxKB 工作空间 ID(选填,默认 default)
88+
MAXKB_WORKSPACE_ID=default
89+
90+
# ==================== 认证配置(二选一)====================
91+
92+
# 方式 1:用户名 + 密码(优先级高)
7593
MAXKB_USERNAME=admin
7694
MAXKB_PASSWORD=admin123
77-
MAXKB_WORKSPACE_ID=default
95+
96+
# 方式 2:Token(如果配置了用户名密码,此项被忽略)
97+
# MAXKB_TOKEN=your_token_here
7898
```
7999

80-
> **提示**:用户名/密码与 Token 可同时配置,用户名/密码优先级更高。
100+
> **提示**
101+
> - `MAXKB_API_PREFIX`:标准部署无需修改,只有非标准部署才需要配置
102+
> - 认证方式:推荐配置用户名密码,系统会自动登录获取 Token
103+
> - 如果同时配置了用户名密码和 Token,系统会使用用户名密码登录
81104
82105
### 2. 列出已发布智能体
83106

@@ -113,13 +136,57 @@ python3 scripts/main.py "Python 里如何读取文件?" "代码助手"
113136

114137
## 环境变量
115138

116-
| 变量 | 说明 | 默认值 |
117-
|----------------------|-----------------------------------|---------------------------|
118-
| `MAXKB_DOMAIN` | MaxKB 服务地址 | `<maxkb_domain>` |
119-
| `MAXKB_TOKEN` | Bearer Token(管理员 API Key) ||
120-
| `MAXKB_WORKSPACE_ID` | 工作空间 ID | `default` |
121-
| `MAXKB_USERNAME` | 登录用户名(优先于 `MAXKB_TOKEN`||
122-
| `MAXKB_PASSWORD` | 登录密码(优先于 `MAXKB_TOKEN`||
139+
| 变量 | 必填 | 说明 | 默认值 |
140+
|----------------------|------|-----------------------------------|---------------------------|
141+
| `MAXKB_DOMAIN` | ✅ 是 | MaxKB 服务地址 | `<maxkb_domain>` |
142+
| `MAXKB_API_PREFIX` | ❌ 否 | API 路径前缀,适用于子路径部署 | `/admin` |
143+
| `MAXKB_TOKEN` | ⚠️ 二选一 | Bearer Token(管理员 API Key) ||
144+
| `MAXKB_USERNAME` | ⚠️ 二选一 | 登录用户名(优先于 `MAXKB_TOKEN`||
145+
| `MAXKB_PASSWORD` | ⚠️ 二选一 | 登录密码(优先于 `MAXKB_TOKEN`||
146+
| `MAXKB_WORKSPACE_ID` | ❌ 否 | 工作空间 ID | `default` |
147+
148+
**说明**
149+
- `MAXKB_API_PREFIX`:标准 MaxKB 部署无需配置(默认 `/admin`),子路径部署需配置(如 `/mk`
150+
- 认证方式:配置 `MAXKB_USERNAME` + `MAXKB_PASSWORD` **** `MAXKB_TOKEN`,前者优先级更高
151+
152+
### MAXKB_API_PREFIX 使用说明
153+
154+
**使用场景**:当 MaxKB 部署在子路径下时(非根路径),需要配置此项。
155+
156+
**默认值**`/admin`(标准 MaxKB 部署)
157+
158+
**示例**
159+
160+
```bash
161+
# 场景 1:标准 MaxKB 部署(默认值)
162+
# http://localhost:8080/admin/api/...
163+
MAXKB_DOMAIN=http://localhost:8080
164+
MAXKB_API_PREFIX=/admin
165+
166+
# 场景 2:MaxKB 部署在子路径
167+
# http://example.com/mk/api/...
168+
MAXKB_DOMAIN=http://example.com
169+
MAXKB_API_PREFIX=/mk
170+
171+
# 场景 3:MaxKB 部署在根路径且无 /admin 前缀
172+
# http://localhost:8080/api/...
173+
MAXKB_DOMAIN=http://localhost:8080
174+
MAXKB_API_PREFIX=""
175+
176+
# 场景 4:MaxKB 部署在多级子路径
177+
# http://example.com/ai/maxkb/api/...
178+
MAXKB_DOMAIN=http://example.com
179+
MAXKB_API_PREFIX=/ai/maxkb
180+
```
181+
182+
**路径处理规则**
183+
184+
| API 类型 | 原始路径 | 配置 `MAXKB_API_PREFIX=/mk`|
185+
|----------|----------|-------------------------------|
186+
| 数据 API | `/api/workspace/...` | `/mk/api/workspace/...` |
187+
| 对话 API | `/chat/api/...` | `/chat/api/...` (不变) |
188+
189+
> **注意**`/chat/` 开头的路径是 MaxKB 前端路由,不会添加 API 前缀。
123190
124191
**认证优先级**:若同时配置了 `MAXKB_USERNAME` + `MAXKB_PASSWORD``MAXKB_TOKEN`,系统将使用用户名/密码登录获取 Token,忽略 `MAXKB_TOKEN`
125192

scripts/main.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,29 @@ def load_dotenv(dotenv_path=None):
4040
load_dotenv(ENV_FILE)
4141

4242
MAXKB_DOMAIN = os.environ.get("MAXKB_DOMAIN", "<maxkb_domain>")
43+
# MaxKB API 路径前缀,默认为 /admin(标准 MaxKB 部署)
44+
# 如果 MaxKB 部署在子路径下(如 http://example.com/mk),配置为 /mk
45+
# 如果 MaxKB 部署在根路径且无 /admin 前缀,留空即可
46+
MAXKB_API_PREFIX = os.environ.get("MAXKB_API_PREFIX", "/admin").rstrip("/")
4347
MAXKB_TOKEN = os.environ.get("MAXKB_TOKEN", "")
4448
MAXKB_WORKSPACE_ID = os.environ.get("MAXKB_WORKSPACE_ID", "default")
4549
MAXKB_USERNAME = os.environ.get("MAXKB_USERNAME", "")
4650
MAXKB_PASSWORD = os.environ.get("MAXKB_PASSWORD", "")
4751

52+
def _build_api_path(path: str) -> str:
53+
"""Build full API path with optional prefix (e.g. /mk)
54+
55+
注意:/chat/ 开头的路径是 MaxKB 前端路由,不需要添加 API 前缀
56+
- /api/... → /mk/api/...
57+
- /chat/... → /chat/... (不变)
58+
"""
59+
if MAXKB_API_PREFIX and not path.startswith(MAXKB_API_PREFIX):
60+
# /chat/ 路径不需要前缀(MaxKB 特殊设计)
61+
if path.startswith("/chat/"):
62+
return path
63+
return f"{MAXKB_API_PREFIX}{path}"
64+
return path
65+
4866

4967
# ── 内部 HTTP 工具 ────────────────────────────────────────────────────
5068

@@ -63,7 +81,8 @@ def _chat_headers(token: str) -> dict:
6381

6482

6583
def _get(path: str, token: str = None) -> dict:
66-
url = f"{MAXKB_DOMAIN}{path}"
84+
api_path = _build_api_path(path)
85+
url = f"{MAXKB_DOMAIN}{api_path}"
6786
headers = _headers() if token is None else _chat_headers(token)
6887
req = request.Request(url=url, headers=headers, method="GET")
6988
try:
@@ -78,7 +97,8 @@ def _get(path: str, token: str = None) -> dict:
7897

7998

8099
def _post_json(path: str, body: dict, token: str = None) -> dict:
81-
url = f"{MAXKB_DOMAIN}{path}"
100+
api_path = _build_api_path(path)
101+
url = f"{MAXKB_DOMAIN}{api_path}"
82102
data = json.dumps(body).encode("utf-8")
83103
headers = _headers() if token is None else _chat_headers(token)
84104
req = request.Request(url=url, data=data, headers=headers, method="POST")
@@ -98,7 +118,8 @@ def _post_sse(path: str, body: dict, token: str) -> str:
98118
发送 POST 请求并逐行解析 SSE(Server-Sent Events)流。
99119
收集所有 operate==true 的 content 片段,直到 is_end==true。
100120
"""
101-
url = f"{MAXKB_DOMAIN}{path}"
121+
api_path = _build_api_path(path)
122+
url = f"{MAXKB_DOMAIN}{api_path}"
102123
data = json.dumps(body).encode("utf-8")
103124
req = request.Request(url=url, data=data, headers=_chat_headers(token), method="POST")
104125
chunks = []
@@ -129,7 +150,7 @@ def _post_sse(path: str, body: dict, token: str) -> str:
129150
def _login() -> str:
130151
if MAXKB_USERNAME and MAXKB_PASSWORD:
131152
resp = _post_json(
132-
"/admin/api/user/login",
153+
"/api/user/login",
133154
{"username": MAXKB_USERNAME, "password": MAXKB_PASSWORD},
134155
)
135156
token = resp.get("data", {}).get("token", "")
@@ -145,7 +166,7 @@ def _login() -> str:
145166
def get_published_agents() -> list:
146167
"""返回所有已发布智能体,每条包含 id / name / desc。"""
147168
resp = _get(
148-
f"/admin/api/workspace/{MAXKB_WORKSPACE_ID}/application/1/10000"
169+
f"/api/workspace/{MAXKB_WORKSPACE_ID}/application/1/10000"
149170
)
150171
records = resp.get("data", {}).get("records", [])
151172
agents = [
@@ -185,10 +206,10 @@ def chat_with_agent(agent_id: str, question: str) -> str:
185206
对指定智能体发起一次对话并返回回答文本。
186207
"""
187208
# 获取 access_token(匿名会话)
188-
token_resp = _get(f"/admin/api/workspace/{MAXKB_WORKSPACE_ID}/application/{agent_id}/access_token")
209+
token_resp = _get(f"/api/workspace/{MAXKB_WORKSPACE_ID}/application/{agent_id}/access_token")
189210
access_token = token_resp.get("data", {}).get("access_token", "")
190211

191-
# 创建会话
212+
# 创建会话(注意:chat API 路径不以 /api 开头)
192213
chat_resp = _post_json(
193214
f"/chat/api/auth/anonymous",
194215
{"access_token": access_token},

0 commit comments

Comments
 (0)