mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
docs: 新增 openspec 规范文档
- abp.md: ABP (AstrBot Plugin) 插件协议规范 - api.md: API 规范 - agent-message.md: Agent 消息格式规范 - config.md: 配置系统规范 (含 GPG 安全配置) - env.md: 环境变量规范 - path.md: XDG 路径规范
This commit is contained in:
415
openspec/abp.md
415
openspec/abp.md
@@ -5,7 +5,10 @@
|
||||
ABP 是 AstrBot 的插件通信协议,用于插件的注册、消息处理、工具调用和生命周期管理。
|
||||
ABP 采用**插件作为独立服务**的设计,插件通过配置加载,可使用任意编程语言实现。
|
||||
|
||||
**核心定位**:ABP 定义了 AstrBot 编排器与插件之间的交互接口,支持进程内和跨进程两种加载模式。
|
||||
**核心原则**:
|
||||
- **主进程不读取插件配置文件**:插件配置通过协议获取
|
||||
- **数据目录由主进程分配**:插件的数据存储目录由主进程在握手时告知
|
||||
- **零侵入性**:插件无需了解 AstrBot 内部结构
|
||||
|
||||
## 与 MCP 的关系
|
||||
|
||||
@@ -13,46 +16,22 @@ ABP 采用**插件作为独立服务**的设计,插件通过配置加载,可
|
||||
|------|-----|-----|
|
||||
| 定位 | 插件(功能扩展) | 工具/数据源连接 |
|
||||
| 通信模式 | 双向(消息+工具+事件) | 单向(工具调用+资源访问) |
|
||||
| 配置获取 | 通过协议握手获取 | 通过配置文件声明 |
|
||||
| 数据目录 | 主进程分配 | 插件自行管理 |
|
||||
| 消息处理 | 支持 | 不支持 |
|
||||
| 生命周期 | 完整 | 轻量 |
|
||||
| 编程语言 | 任意 | 任意 |
|
||||
|
||||
## 加载方式
|
||||
## 插件加载配置
|
||||
|
||||
### 1. 进程内加载(In-Process)
|
||||
|
||||
- **直接函数调用**:无序列化开销,零拷贝
|
||||
- **适用场景**:内置插件、高频调用、对延迟敏感
|
||||
|
||||
### 2. 跨进程加载(Out-of-Process)
|
||||
|
||||
- **独立进程运行**:插件崩溃不影响主进程
|
||||
- **协议**:JSON-RPC 2.0 over Unix Socket / HTTP
|
||||
- **适用场景**:第三方插件、需要资源隔离
|
||||
|
||||
## 插件配置
|
||||
|
||||
类似 MCP 服务器配置,在 AstrBot 配置文件中声明插件:
|
||||
AstrBot 配置文件声明插件基本信息(不包含插件配置):
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"name": "weather-plugin",
|
||||
"version": "1.0.0",
|
||||
"load_mode": "out_of_process",
|
||||
"command": "python",
|
||||
"args": ["/path/to/weather_server.py"],
|
||||
"env": {
|
||||
"API_KEY": "xxx"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "code-analysis",
|
||||
"load_mode": "out_of_process",
|
||||
"command": "./code-analysis-server",
|
||||
"transport": "http",
|
||||
"url": "http://localhost:9001"
|
||||
"args": ["/path/to/weather_server.py"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -63,20 +42,183 @@ ABP 采用**插件作为独立服务**的设计,插件通过配置加载,可
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | 是 | 插件名称 |
|
||||
| `version` | string | 否 | 插件版本 |
|
||||
| `load_mode` | string | 是 | `in_process` 或 `out_of_process` |
|
||||
| `command` | string | 跨进程时必填 | 启动命令 |
|
||||
| `args` | array | 跨进程时可选 | 命令参数 |
|
||||
| `env` | object | 否 | 环境变量 |
|
||||
| `transport` | string | 跨进程时可选 | `stdio` / `unix_socket` / `http` |
|
||||
| `url` | string | HTTP 传输时必填 | 服务器地址 |
|
||||
|
||||
## 初始化握手
|
||||
|
||||
插件配置通过 `initialize` 握手交换,**主进程不读取插件的配置文件**。
|
||||
|
||||
### Initialize(主进程 → 插件)
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "1.0.0",
|
||||
"clientInfo": {
|
||||
"name": "astrbot",
|
||||
"version": "4.16.0"
|
||||
},
|
||||
"capabilities": {
|
||||
"streaming": true,
|
||||
"events": true
|
||||
},
|
||||
"pluginConfig": {
|
||||
"user_config": {}
|
||||
},
|
||||
"dataDirs": {
|
||||
"root": "/var/lib/astrbot",
|
||||
"plugin_data": "/var/lib/astrbot/data/plugins/my-plugin",
|
||||
"temp": "/var/cache/astrbot/temp"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Initialize Response(插件 → 主进程)
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"protocolVersion": "1.0.0",
|
||||
"serverInfo": {
|
||||
"name": "weather-plugin",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"capabilities": {
|
||||
"tools": true,
|
||||
"handlers": true,
|
||||
"events": true,
|
||||
"resources": false
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"description": "Weather API Key",
|
||||
"required": true
|
||||
},
|
||||
"default_location": {
|
||||
"type": "string",
|
||||
"description": "默认查询城市",
|
||||
"default": "北京"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"display_name": "天气插件",
|
||||
"description": "提供天气查询功能",
|
||||
"author": "Author",
|
||||
"support_platforms": ["telegram", "discord"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 握手参数说明
|
||||
|
||||
**主进程 → 插件(Initialize params)**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `pluginConfig.user_config` | object | 用户配置(来自 secrets.yaml 等) |
|
||||
| `dataDirs.root` | string | AstrBot 数据根目录 |
|
||||
| `dataDirs.plugin_data` | string | 插件专用数据目录 |
|
||||
| `dataDirs.temp` | string | 插件临时文件目录 |
|
||||
|
||||
**插件 → 主进程(Initialize result)**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `configSchema` | object | 插件配置 Schema(用于 UI 生成配置表单) |
|
||||
| `metadata.*` | object | 插件元数据 |
|
||||
|
||||
## 数据目录
|
||||
|
||||
插件的数据存储目录由主进程分配,插件通过握手获取:
|
||||
|
||||
```
|
||||
dataDirs.plugin_data/
|
||||
├── config.json # 插件配置(主进程写入)
|
||||
├── data/ # 插件业务数据
|
||||
└── cache/ # 插件缓存
|
||||
```
|
||||
|
||||
**原则**:
|
||||
- 插件不自行决定数据目录
|
||||
- 配置由主进程管理,插件通过 `dataDirs.plugin_data/config.json` 读取
|
||||
- 插件只需读写自己的目录,无需了解 AstrBot 目录结构
|
||||
|
||||
## 配置传递
|
||||
|
||||
### 1. 用户配置(主进程 → 插件)
|
||||
|
||||
用户通过 WebUI 或配置文件设置的配置,通过握手传递给插件:
|
||||
|
||||
```json
|
||||
{
|
||||
"pluginConfig": {
|
||||
"user_config": {
|
||||
"api_key": "xxx",
|
||||
"default_location": "上海"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 配置更新(主进程 → 插件)
|
||||
|
||||
配置变更时,主进程通知插件:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "plugin.config_update",
|
||||
"params": {
|
||||
"user_config": {
|
||||
"api_key": "yyy"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 配置 Schema(插件声明)
|
||||
|
||||
插件声明配置 Schema,用于主进程生成配置 UI:
|
||||
|
||||
```json
|
||||
{
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"description": "API Key",
|
||||
"secret": true
|
||||
},
|
||||
"default_location": {
|
||||
"type": "string",
|
||||
"description": "默认城市"
|
||||
}
|
||||
},
|
||||
"required": ["api_key"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 传输协议
|
||||
|
||||
### Stdio(进程启动)
|
||||
|
||||
用于进程内加载或通过 stdio 启动的外部插件:
|
||||
|
||||
```
|
||||
{"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}
|
||||
{"jsonrpc":"2.0","method":"plugin.handle_event","params":{...}}
|
||||
@@ -96,71 +238,7 @@ Content-Length: <字节数>\r\n
|
||||
|
||||
## 消息格式
|
||||
|
||||
所有消息均为 JSON-RPC 2.0:
|
||||
|
||||
### 1. 初始化(initialize)
|
||||
|
||||
**请求**:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "1.0.0",
|
||||
"clientInfo": {
|
||||
"name": "astrbot",
|
||||
"version": "4.16.0"
|
||||
},
|
||||
"capabilities": {
|
||||
"streaming": true,
|
||||
"events": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"protocolVersion": "1.0.0",
|
||||
"serverInfo": {
|
||||
"name": "weather-plugin",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"capabilities": {
|
||||
"tools": true,
|
||||
"handlers": true,
|
||||
"events": true
|
||||
},
|
||||
"metadata": {
|
||||
"display_name": "天气插件",
|
||||
"description": "提供天气查询功能",
|
||||
"author": "Author"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 插件能力
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities": {
|
||||
"tools": true, // 支持工具调用
|
||||
"handlers": true, // 支持消息处理器
|
||||
"events": true, // 支持事件订阅
|
||||
"resources": false // 是否提供资源
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 工具调用(跨进程)
|
||||
### 1. 工具调用
|
||||
|
||||
**请求**:
|
||||
|
||||
@@ -186,16 +264,13 @@ Content-Length: <字节数>\r\n
|
||||
"id": "req-001",
|
||||
"result": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "北京天气:晴,25°C"
|
||||
}
|
||||
{ "type": "text", "text": "北京天气:晴,25°C" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 消息处理
|
||||
### 2. 消息处理
|
||||
|
||||
**请求**:
|
||||
|
||||
@@ -210,13 +285,8 @@ Content-Length: <字节数>\r\n
|
||||
"message_id": "msg-123",
|
||||
"unified_msg_origin": "telegram:private:12345",
|
||||
"message_str": "/weather 北京",
|
||||
"sender": {
|
||||
"user_id": "12345",
|
||||
"nickname": "用户"
|
||||
},
|
||||
"message_chain": [
|
||||
{ "type": "plain", "text": "/weather 北京" }
|
||||
]
|
||||
"sender": { "user_id": "12345", "nickname": "用户" },
|
||||
"message_chain": [{ "type": "plain", "text": "/weather 北京" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,29 +300,25 @@ Content-Length: <字节数>\r\n
|
||||
"id": "req-002",
|
||||
"result": {
|
||||
"handled": true,
|
||||
"results": [
|
||||
{ "type": "plain", "text": "北京天气:晴,25°C" }
|
||||
],
|
||||
"results": [{ "type": "plain", "text": "北京天气:晴,25°C" }],
|
||||
"stop_propagation": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 事件订阅
|
||||
### 3. 事件订阅
|
||||
|
||||
**通知**(客户端 → 插件):
|
||||
**通知**(主进程 → 插件):
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "plugin.subscribe",
|
||||
"params": {
|
||||
"event_type": "llm_request"
|
||||
}
|
||||
"params": { "event_type": "llm_request" }
|
||||
}
|
||||
```
|
||||
|
||||
**通知**(插件 → 客户端):
|
||||
**通知**(插件 → 主进程):
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -260,80 +326,23 @@ Content-Length: <字节数>\r\n
|
||||
"method": "plugin.notify",
|
||||
"params": {
|
||||
"event_type": "tool_called",
|
||||
"data": {
|
||||
"tool": "get_weather",
|
||||
"args": { "location": "北京" }
|
||||
}
|
||||
"data": { "tool": "get_weather", "args": { "location": "北京" } }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 工具列表
|
||||
|
||||
**请求**:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"method": "tools/list",
|
||||
"params": {}
|
||||
}
|
||||
```
|
||||
|
||||
**响应**:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"result": {
|
||||
"tools": [
|
||||
{
|
||||
"name": "get_weather",
|
||||
"description": "获取天气信息",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "城市名称"
|
||||
}
|
||||
},
|
||||
"required": ["location"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 资源(可选)
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "resources/list",
|
||||
"params": {}
|
||||
}
|
||||
```
|
||||
|
||||
## 核心方法
|
||||
|
||||
### 初始化
|
||||
|
||||
| 方法 | 方向 | 描述 |
|
||||
|------|------|------|
|
||||
| `initialize` | C→P | 初始化连接 |
|
||||
| `initialized` | P→C | 初始化完成通知 |
|
||||
|
||||
### 生命周期
|
||||
|
||||
| 方法 | 方向 | 描述 |
|
||||
|------|------|------|
|
||||
| `initialize` | C→P | 初始化连接,交换配置和数据目录 |
|
||||
| `initialized` | P→C | 初始化完成通知 |
|
||||
| `plugin.start` | C→P | 启动插件 |
|
||||
| `plugin.stop` | C→P | 停止插件 |
|
||||
| `plugin.reload` | C→P | 重载插件 |
|
||||
| `plugin.config_update` | C→P | 配置更新通知 |
|
||||
|
||||
### 工具
|
||||
|
||||
@@ -341,7 +350,6 @@ Content-Length: <字节数>\r\n
|
||||
|------|------|------|
|
||||
| `tools/list` | C→P | 列出可用工具 |
|
||||
| `tools/call` | C→P | 调用工具 |
|
||||
| `tools/metadata` | P→C | 工具元数据更新 |
|
||||
|
||||
### 消息处理
|
||||
|
||||
@@ -361,7 +369,7 @@ Content-Length: <字节数>\r\n
|
||||
|
||||
## 插件元数据
|
||||
|
||||
插件通过 `initialize` 响应返回元数据:
|
||||
插件在 `initialize` 响应中返回元数据:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -374,13 +382,17 @@ Content-Length: <字节数>\r\n
|
||||
"handlers": true,
|
||||
"events": true
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"api_key": { "type": "string", "secret": true }
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"display_name": "天气插件",
|
||||
"description": "提供天气预报功能",
|
||||
"author": "Author Name",
|
||||
"homepage": "https://github.com/author/weather-plugin",
|
||||
"support_platforms": ["telegram", "discord"],
|
||||
"astrbot_version": ">=4.16,<5"
|
||||
"description": "提供天气查询功能",
|
||||
"author": "Author",
|
||||
"support_platforms": ["telegram", "discord"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -409,13 +421,14 @@ Content-Length: <字节数>\r\n
|
||||
|
||||
## 进程内插件
|
||||
|
||||
对于进程内插件(load_mode: in_process),编排器直接调用插件方法,无需序列化:
|
||||
对于进程内插件(load_mode: in_process),主进程直接调用插件方法:
|
||||
|
||||
```python
|
||||
# 插件直接实现为类
|
||||
class MyPlugin:
|
||||
def __init__(self, context):
|
||||
def __init__(self, context, user_config: dict, data_dirs: dict):
|
||||
self.context = context
|
||||
self.user_config = user_config
|
||||
self.data_dir = data_dirs["plugin_data"]
|
||||
|
||||
async def handle_event(self, event):
|
||||
return [PlainResult("Hello!")]
|
||||
@@ -427,19 +440,15 @@ class MyPlugin:
|
||||
return {
|
||||
"name": "my-plugin",
|
||||
"version": "1.0.0",
|
||||
"capabilities": {
|
||||
"tools": True,
|
||||
"handlers": True,
|
||||
"events": False
|
||||
}
|
||||
"capabilities": {"tools": True, "handlers": True, "events": False},
|
||||
"configSchema": {...}
|
||||
}
|
||||
```
|
||||
|
||||
## 实现注意事项
|
||||
## 设计原则
|
||||
|
||||
- 插件是独立服务,通过配置声明式加载
|
||||
- 支持任意编程语言实现(Python、Go、Rust、JavaScript 等)
|
||||
- 跨进程插件使用标准 JSON-RPC 2.0 通信
|
||||
- 插件元数据通过 `initialize` 响应动态获取
|
||||
- 支持热重载:配置更新后可在线重载插件
|
||||
- 事件通知采用异步机制,不阻塞主流程
|
||||
1. **主进程不读取插件配置**:插件配置通过协议传递
|
||||
2. **数据目录由主进程分配**:插件通过握手获取 `dataDirs`
|
||||
3. **配置 Schema 声明**:插件声明配置结构,主进程生成 UI
|
||||
4. **插件无侵入性**:插件无需了解 AstrBot 内部结构
|
||||
5. **热重载支持**:配置更新通过 `plugin.config_update` 通知
|
||||
|
||||
2127
openspec/agent-message.md
Normal file
2127
openspec/agent-message.md
Normal file
File diff suppressed because it is too large
Load Diff
651
openspec/api.md
Normal file
651
openspec/api.md
Normal file
@@ -0,0 +1,651 @@
|
||||
# HTTP API 服务器规范
|
||||
|
||||
## 概述
|
||||
|
||||
AstrBot 提供 HTTP API 服务器,用于第三方应用集成。支持 API Key 认证,采用 RESTful 风格设计。
|
||||
|
||||
**特性**:
|
||||
- API Key 认证
|
||||
- SSE 流式响应
|
||||
- 文件上传/下载
|
||||
- 主动消息推送
|
||||
|
||||
## 服务器配置
|
||||
|
||||
### 启动参数
|
||||
|
||||
| 参数 | 环境变量 | 说明 |
|
||||
|------|----------|------|
|
||||
| `--host` | `ASTRBOT_HOST` | 绑定地址,默认 `0.0.0.0` |
|
||||
| `--port` | `ASTRBOT_PORT` | 绑定端口,默认 `6185` |
|
||||
| `--ssl` | `ASTRBOT_SSL_ENABLE` | 启用 SSL/TLS |
|
||||
| `--ssl-cert` | `ASTRBOT_SSL_CERT` | SSL 证书路径 |
|
||||
| `--ssl-key` | `ASTRBOT_SSL_KEY` | SSL 私钥路径 |
|
||||
|
||||
### 配置示例
|
||||
|
||||
```yaml
|
||||
# system.yaml
|
||||
api:
|
||||
host: "0.0.0.0"
|
||||
port: 6185
|
||||
ssl:
|
||||
enable: true
|
||||
cert: "/etc/astrbot/certs/fullchain.pem"
|
||||
key: "/etc/astrbot/certs/privkey.pem"
|
||||
# API 请求超时(秒)
|
||||
timeout: 60
|
||||
# 最大请求体大小(MB)
|
||||
max_body_size: 100
|
||||
```
|
||||
|
||||
## 认证
|
||||
|
||||
### API Key 认证
|
||||
|
||||
所有 `/api/v1/*` 端点需要 API Key 认证:
|
||||
|
||||
| 方式 | 头部 | 示例 |
|
||||
|------|------|------|
|
||||
| Header | `X-API-Key` | `X-API-Key: sk-xxxxx` |
|
||||
| Bearer | `Authorization` | `Authorization: Bearer sk-xxxxx` |
|
||||
|
||||
**API Key 配置**:
|
||||
|
||||
```yaml
|
||||
# secrets.yaml
|
||||
api:
|
||||
keys:
|
||||
- id: "my-app"
|
||||
key: "sk-xxxxxxxxxxxx"
|
||||
name: "My Application"
|
||||
permissions:
|
||||
- "chat"
|
||||
- "file"
|
||||
- "message"
|
||||
rate_limit:
|
||||
requests: 100
|
||||
period: 60 # seconds
|
||||
```
|
||||
|
||||
### 权限说明
|
||||
|
||||
| 权限 | 说明 |
|
||||
|------|------|
|
||||
| `chat` | 聊天功能(发送消息、查询会话) |
|
||||
| `file` | 文件上传/下载 |
|
||||
| `message` | 主动消息推送 |
|
||||
| `admin` | 管理功能(预留) |
|
||||
|
||||
## 错误响应
|
||||
|
||||
### 错误格式
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"code": 401,
|
||||
"message": "Invalid API key",
|
||||
"request_id": "req-abc123"
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP 状态码
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| `200` | 请求成功 |
|
||||
| `400` | 请求参数错误 |
|
||||
| `401` | 未授权(API Key 无效) |
|
||||
| `403` | 禁止访问(权限不足) |
|
||||
| `404` | 资源不存在 |
|
||||
| `429` | 请求过于频繁(限流) |
|
||||
| `500` | 服务器内部错误 |
|
||||
| `503` | 服务不可用 |
|
||||
|
||||
### 错误码
|
||||
|
||||
| 码值 | 说明 |
|
||||
|------|------|
|
||||
| `invalid_api_key` | API Key 无效 |
|
||||
| `expired_api_key` | API Key 已过期 |
|
||||
| `insufficient_permissions` | 权限不足 |
|
||||
| `rate_limit_exceeded` | 请求频率超限 |
|
||||
| `invalid_parameter` | 参数错误 |
|
||||
| `session_not_found` | 会话不存在 |
|
||||
| `config_not_found` | 配置不存在 |
|
||||
| `file_not_found` | 文件不存在 |
|
||||
| `upload_failed` | 文件上传失败 |
|
||||
| `platform_error` | 平台错误 |
|
||||
|
||||
## 端点列表
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| `GET` | `/api/v1/im/bots` | 获取机器人列表 |
|
||||
| `POST` | `/api/v1/file` | 上传文件 |
|
||||
| `GET` | `/api/v1/file` | 下载文件 |
|
||||
| `POST` | `/api/v1/chat` | 发送聊天消息(SSE) |
|
||||
| `GET` | `/api/v1/chat/sessions` | 获取会话列表 |
|
||||
| `POST` | `/api/v1/im/message` | 发送主动消息 |
|
||||
| `GET` | `/api/v1/configs` | 获取配置列表 |
|
||||
|
||||
---
|
||||
|
||||
## API 端点详情
|
||||
|
||||
### GET /api/v1/im/bots
|
||||
|
||||
获取已配置的机器人/平台 ID 列表。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
GET /api/v1/im/bots
|
||||
X-API-Key: sk-xxxxx
|
||||
```
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"bot_ids": [
|
||||
"telegram:bot:123456789",
|
||||
"discord:bot:987654321",
|
||||
"webchat:FriendMessage:openapi_probe"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/v1/file
|
||||
|
||||
上传文件,获取 `attachment_id` 供后续使用。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
POST /api/v1/file
|
||||
X-API-Key: sk-xxxxx
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
file: <binary>
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `file` | binary | 是 | 上传的文件 |
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"attachment_id": "9a2f8c72-e7af-4c0e-b352-111111111111",
|
||||
"filename": "document.pdf",
|
||||
"type": "application/pdf",
|
||||
"size": 102400
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**限制**:
|
||||
- 最大文件大小:100MB
|
||||
- 支持格式:图片、音频、视频、文档等
|
||||
|
||||
---
|
||||
|
||||
### GET /api/v1/file
|
||||
|
||||
下载已上传的文件。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
GET /api/v1/file?attachment_id=9a2f8c72-e7af-4c0e-b352-111111111111
|
||||
X-API-Key: sk-xxxxx
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `attachment_id` | string | 是 | 上传时返回的附件 ID |
|
||||
|
||||
**响应**
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
<binary>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/v1/chat
|
||||
|
||||
发送聊天消息,支持 SSE 流式响应。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
POST /api/v1/chat
|
||||
X-API-Key: sk-xxxxx
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"message": "Hello, how are you?",
|
||||
"username": "alice",
|
||||
"session_id": "my_session_001",
|
||||
"enable_streaming": true,
|
||||
"selected_provider": "openai_chat_completion",
|
||||
"selected_model": "gpt-4.1-mini"
|
||||
}
|
||||
```
|
||||
|
||||
**请求体参数**
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `message` | string \| array | 是 | 消息内容或消息链 |
|
||||
| `username` | string | 是 | 用户名 |
|
||||
| `session_id` | string | 否 | 会话 ID,不提供则自动创建 UUID |
|
||||
| `conversation_id` | string | 否 | `session_id` 的别名 |
|
||||
| `selected_provider` | string | 否 | 指定 LLM 提供商 |
|
||||
| `selected_model` | string | 否 | 指定模型 |
|
||||
| `enable_streaming` | boolean | 否 | 启用 SSE 流式响应,默认 `true` |
|
||||
| `config_id` | string | 否 | 指定配置文件 ID |
|
||||
| `config_name` | string | 否 | 指定配置文件名称(当 config_id 未提供时) |
|
||||
|
||||
**消息链格式**
|
||||
|
||||
```json
|
||||
{
|
||||
"message": [
|
||||
{ "type": "plain", "text": "Please analyze this file" },
|
||||
{ "type": "file", "attachment_id": "9a2f8c72-e7af-4c0e-b352-111111111111" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**消息类型**
|
||||
|
||||
| 类型 | 说明 | 字段 |
|
||||
|------|------|------|
|
||||
| `plain` | 文本消息 | `text` |
|
||||
| `reply` | 回复消息 | `text`, `message_id` |
|
||||
| `image` | 图片 | `attachment_id` 或 `url` |
|
||||
| `file` | 文件 | `attachment_id`, `filename` |
|
||||
| `record` | 语音 | `attachment_id` |
|
||||
| `video` | 视频 | `attachment_id` |
|
||||
|
||||
**SSE 流式响应**
|
||||
|
||||
```
|
||||
200 OK
|
||||
Content-Type: text/event-stream
|
||||
|
||||
event: message
|
||||
data: {"type": "message", "content": "Hello"}
|
||||
|
||||
event: message
|
||||
data: {"type": "message", "content": " world"}
|
||||
|
||||
event: done
|
||||
data: {"type": "done", "message_id": "msg-123"}
|
||||
|
||||
event: error
|
||||
data: {"type": "error", "message": "Error description"}
|
||||
```
|
||||
|
||||
**SSE 事件类型**
|
||||
|
||||
| 事件 | 说明 | 数据格式 |
|
||||
|------|------|----------|
|
||||
| `message` | 消息片段 | `{"type": "message", "content": "..."}` |
|
||||
| `tool_call` | 工具调用 | `{"type": "tool_call", "tool": "name", "args": {...}}` |
|
||||
| `tool_result` | 工具结果 | `{"type": "tool_result", "tool": "name", "result": {...}}` |
|
||||
| `done` | 完成 | `{"type": "done", "message_id": "..."}` |
|
||||
| `error` | 错误 | `{"type": "error", "message": "..."}` |
|
||||
|
||||
**完整响应(非流式)**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"message_id": "msg-123",
|
||||
"content": "Hello! How can I help you today?",
|
||||
"sender": {
|
||||
"user_id": "alice",
|
||||
"nickname": "Alice"
|
||||
},
|
||||
"timestamp": "2026-03-26T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### GET /api/v1/chat/sessions
|
||||
|
||||
获取用户的会话列表(分页)。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
GET /api/v1/chat/sessions?username=alice&page=1&page_size=20
|
||||
X-API-Key: sk-xxxxx
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `username` | string | 是 | 用户名 |
|
||||
| `page` | integer | 否 | 页码,默认 `1` |
|
||||
| `page_size` | integer | 否 | 每页数量,默认 `20`,最大 `100` |
|
||||
| `platform_id` | string | 否 | 平台过滤器 |
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"sessions": [
|
||||
{
|
||||
"session_id": "my_session_001",
|
||||
"platform_id": "webchat:FriendMessage:openapi_probe",
|
||||
"creator": "alice",
|
||||
"display_name": "Alice",
|
||||
"is_group": 0,
|
||||
"created_at": "2026-03-26T10:00:00Z",
|
||||
"updated_at": "2026-03-26T10:30:00Z"
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/v1/im/message
|
||||
|
||||
向平台机器人发送主动消息。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
POST /api/v1/im/message
|
||||
X-API-Key: sk-xxxxx
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"umo": "webchat:FriendMessage:openapi_probe",
|
||||
"message": "ping from api"
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `umo` | string | 是 | 统一消息源地址 |
|
||||
| `message` | string \| array | 是 | 消息内容或消息链 |
|
||||
|
||||
**UMO 格式**
|
||||
|
||||
```
|
||||
platform:message_type:session_id
|
||||
```
|
||||
|
||||
| 平台 | 示例 |
|
||||
|------|------|
|
||||
| `webchat` | `webchat:FriendMessage:openapi_probe` |
|
||||
| `telegram` | `telegram:private:123456789` |
|
||||
| `telegram` | `telegram:group:-123456789` |
|
||||
| `discord` | `discord:channel:987654321` |
|
||||
|
||||
**消息类型**
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| `private` | 私聊 |
|
||||
| `group` | 群聊 |
|
||||
| `FriendMessage` | WebChat 好友消息 |
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"message": "Message sent successfully"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### GET /api/v1/configs
|
||||
|
||||
获取可用的聊天配置文件列表。
|
||||
|
||||
**请求**
|
||||
|
||||
```
|
||||
GET /api/v1/configs
|
||||
X-API-Key: sk-xxxxx
|
||||
```
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"configs": [
|
||||
{
|
||||
"id": "default",
|
||||
"name": "默认配置",
|
||||
"path": "/var/lib/astrbot/data/configs/default.yaml",
|
||||
"is_default": true
|
||||
},
|
||||
{
|
||||
"id": "coding-assistant",
|
||||
"name": "编程助手",
|
||||
"path": "/var/lib/astrbot/data/configs/coding-assistant.yaml",
|
||||
"is_default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 速率限制
|
||||
|
||||
| 等级 | 请求数 | 窗口 |
|
||||
|------|--------|------|
|
||||
| 默认 | 100 | 60 秒 |
|
||||
| 高级 | 1000 | 60 秒 |
|
||||
|
||||
**限流响应**
|
||||
|
||||
```
|
||||
429 Too Many Requests
|
||||
X-RateLimit-Limit: 100
|
||||
X-RateLimit-Remaining: 0
|
||||
X-RateLimit-Reset: 1742992060
|
||||
|
||||
{
|
||||
"status": "error",
|
||||
"code": 429,
|
||||
"message": "Rate limit exceeded. Try again in 30 seconds."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Webhook 回调
|
||||
|
||||
### 配置
|
||||
|
||||
```yaml
|
||||
# system.yaml
|
||||
callback_api_base: "https://your-server.com/callback"
|
||||
```
|
||||
|
||||
### 回调事件
|
||||
|
||||
| 事件 | 说明 |
|
||||
|------|------|
|
||||
| `message.received` | 收到消息 |
|
||||
| `message.sent` | 消息发送成功 |
|
||||
| `session.created` | 会话创建 |
|
||||
| `session.updated` | 会话更新 |
|
||||
| `error` | 错误发生 |
|
||||
|
||||
### 回调签名
|
||||
|
||||
```
|
||||
X-AstrBot-Signature: sha256=xxxxx
|
||||
X-AstrBot-Timestamp: 1742992060
|
||||
```
|
||||
|
||||
验证签名:
|
||||
|
||||
```python
|
||||
import hmac
|
||||
import hashlib
|
||||
|
||||
def verify_signature(payload: bytes, timestamp: str, signature: str, secret: str) -> bool:
|
||||
expected = hmac.new(
|
||||
secret.encode(),
|
||||
f"{timestamp}.".encode() + payload,
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
return hmac.compare_digest(f"sha256={expected}", signature)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 健康检查
|
||||
|
||||
### GET /health
|
||||
|
||||
```
|
||||
GET /health
|
||||
```
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"version": "4.16.0",
|
||||
"uptime": 3600
|
||||
}
|
||||
```
|
||||
|
||||
### GET /ready
|
||||
|
||||
```
|
||||
GET /ready
|
||||
```
|
||||
|
||||
**响应**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ready",
|
||||
"components": {
|
||||
"api": "ok",
|
||||
"platforms": {
|
||||
"telegram": "ok",
|
||||
"discord": "ok"
|
||||
},
|
||||
"llm_providers": {
|
||||
"openai": "ok"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 客户端 SDK
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
from astrbot.api.http import AstrBotClient
|
||||
|
||||
client = AstrBotClient(api_key="sk-xxxxx", base_url="http://localhost:6185")
|
||||
|
||||
# 发送消息
|
||||
async def main():
|
||||
async for event in client.chat("Hello!", username="alice", session_id="test"):
|
||||
print(event)
|
||||
|
||||
# 或非流式
|
||||
result = await client.chat_one("Hello!", username="alice")
|
||||
print(result)
|
||||
```
|
||||
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
import { AstrBotClient } from "@astrbot/sdk";
|
||||
|
||||
const client = new AstrBotClient({
|
||||
apiKey: "sk-xxxxx",
|
||||
baseUrl: "http://localhost:6185"
|
||||
});
|
||||
|
||||
// 流式
|
||||
for await (const event of client.chat({ message: "Hello!", username: "alice" })) {
|
||||
console.log(event);
|
||||
}
|
||||
|
||||
// 非流式
|
||||
const result = await client.chatOne({ message: "Hello!", username: "alice" });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
$XDG_CONFIG_HOME/astrbot/
|
||||
├── config.yaml # 主配置入口
|
||||
├── secrets.yaml # 安全配置(包含 API Keys)
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全建议
|
||||
|
||||
1. **API Key 安全**
|
||||
- API Key 仅通过 HTTPS 传输
|
||||
- 定期轮换 API Key
|
||||
- 不同应用使用不同 Key
|
||||
|
||||
2. **网络隔离**
|
||||
- 生产环境使用 SSL/TLS
|
||||
- 限制 API 服务器访问范围
|
||||
- 使用防火墙或 VPN
|
||||
|
||||
3. **权限控制**
|
||||
- 按最小权限原则分配 API Key 权限
|
||||
- 避免使用 `admin` 权限
|
||||
- 记录 API 调用日志
|
||||
|
||||
4. **限流配置**
|
||||
- 根据业务需求调整限流参数
|
||||
- 监控限流触发情况
|
||||
- 合理设置不同等级的限流策略
|
||||
565
openspec/config.md
Normal file
565
openspec/config.md
Normal file
@@ -0,0 +1,565 @@
|
||||
# 配置规范
|
||||
|
||||
## 概述
|
||||
|
||||
AstrBot 配置系统遵循以下原则:
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **分离关注点** | 按功能域分离配置 |
|
||||
| **敏感信息隔离** | 密钥、密码存储在独立的安全文件中 |
|
||||
| **环境变量优先** | 密钥通过环境变量注入,不写入配置文件 |
|
||||
| **分层配置** | 系统配置 → 平台配置 → 插件配置 |
|
||||
|
||||
## 配置分类
|
||||
|
||||
### 配置域
|
||||
|
||||
| 域 | 配置文件 | 说明 |
|
||||
|---|----------|------|
|
||||
| **安全配置** | `secrets.yaml` | API keys、密码、JWT secrets、GPG 密钥 |
|
||||
| **平台配置** | `platform.yaml` | 平台适配器设置 |
|
||||
| **提供商配置** | `providers.yaml` | LLM 提供商设置(不含密钥) |
|
||||
| **Agent 配置** | `agent.yaml` | Agent 行为参数 |
|
||||
| **系统配置** | `system.yaml` | 日志、调试、代理、API 服务器等 |
|
||||
| **GPG 配置** | `gpg.yaml` | GPG 安全配置(可选) |
|
||||
| **插件配置** | `plugins/` | 各插件独立配置 |
|
||||
|
||||
## GPG 安全配置(可选)
|
||||
|
||||
### 概述
|
||||
|
||||
AstrBot 提供可选的 GPG 安全功能,用于配置文件的签名与验签,防止配置被篡改。
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| **配置签名** | 对配置文件进行签名,确保完整性 |
|
||||
| **配置验签** | 启动时验证配置文件签名,检测篡改 |
|
||||
| **插件签名** | 验证插件包的 GPG 签名 |
|
||||
|
||||
### gpg.yaml(GPG 配置)
|
||||
|
||||
```yaml
|
||||
# GPG 安全配置
|
||||
# 可选功能,不启用时不影响正常功能
|
||||
|
||||
security:
|
||||
# GPG 功能开关
|
||||
enable: false
|
||||
|
||||
# 验签模式
|
||||
# - none: 不验签
|
||||
# - warn: 验签失败仅警告
|
||||
# - enforce: 验签失败阻止启动
|
||||
verify_mode: "warn"
|
||||
|
||||
# 信任的公钥指纹列表
|
||||
trusted_keys:
|
||||
- "ABCDEF1234567890..."
|
||||
- "FEDCBA0987654321..."
|
||||
|
||||
# 签名的配置文件模式
|
||||
signed_configs:
|
||||
- "secrets.yaml"
|
||||
- "agent.yaml"
|
||||
- "platform.yaml"
|
||||
|
||||
# 签名文件后缀
|
||||
signature_suffix: ".sig"
|
||||
|
||||
# GPG 主目录(默认使用系统配置)
|
||||
gnupg_home: ""
|
||||
```
|
||||
|
||||
### secrets.yaml 中的 GPG 密钥
|
||||
|
||||
```yaml
|
||||
# GPG 密钥配置
|
||||
gpg:
|
||||
# 私钥(用于签名)
|
||||
# 使用空字符串表示不配置
|
||||
private_key: ""
|
||||
passphrase: ""
|
||||
|
||||
# 或使用 GPG Keybox 格式
|
||||
# keybox: "/path/to/s.gpg-keybox"
|
||||
|
||||
# 公钥指纹(用于验签)
|
||||
fingerprint: "ABCDEF1234567890..."
|
||||
```
|
||||
|
||||
### 配置签名与验签流程
|
||||
|
||||
#### 签名流程
|
||||
|
||||
```bash
|
||||
# 1. 首次签名
|
||||
astrbot gpg sign --config secrets.yaml
|
||||
astrbot gpg sign --config agent.yaml
|
||||
|
||||
# 2. 生成签名文件
|
||||
# secrets.yaml.sig
|
||||
# agent.yaml.sig
|
||||
|
||||
# 3. 签名文件内容(JSON 格式)
|
||||
{
|
||||
"config_file": "secrets.yaml",
|
||||
"signature": "-----BEGIN PGP SIGNATURE-----...",
|
||||
"signed_at": "2026-03-26T10:00:00Z",
|
||||
"issuer": "AstrBot/1.0"
|
||||
}
|
||||
```
|
||||
|
||||
#### 验签流程
|
||||
|
||||
```
|
||||
启动时:
|
||||
1. 检查 gpg.yaml 中 verify_mode
|
||||
2. 对 signed_configs 中的每个文件:
|
||||
a. 读取配置文件
|
||||
b. 读取对应的 .sig 签名文件
|
||||
c. 使用 trusted_keys 中的公钥验签
|
||||
3. 根据 verify_mode 处理结果:
|
||||
- none: 跳过验签
|
||||
- warn: 验签失败记录警告日志
|
||||
- enforce: 验签失败阻止启动并报错
|
||||
```
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
$XDG_CONFIG_HOME/astrbot/
|
||||
├── gpg.yaml # GPG 安全配置
|
||||
├── secrets.yaml # 包含 GPG 密钥
|
||||
├── secrets.yaml.sig # 配置文件签名
|
||||
├── agent.yaml
|
||||
├── agent.yaml.sig
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 命令行接口
|
||||
|
||||
```bash
|
||||
# 签名配置文件
|
||||
astrbot gpg sign --config <file> [--output <dir>]
|
||||
|
||||
# 验签配置文件
|
||||
astrbot gpg verify --config <file>
|
||||
|
||||
# 验签所有已签名配置
|
||||
astrbot gpg verify --all
|
||||
|
||||
# 导出公钥
|
||||
astrbot gpg export --keyring <fingerprint> [--output <file>]
|
||||
|
||||
# 生成新密钥对
|
||||
astrbot gpg generate --name "AstrBot" --email "astrbot@example.com"
|
||||
```
|
||||
|
||||
### 安全原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **私钥保护** | 私钥仅存储在 secrets.yaml 中,不提交到版本控制 |
|
||||
| **密钥分离** | GPG 签名密钥与 API 密钥分离存储 |
|
||||
| **验签优先** | 生产环境建议使用 `verify_mode: enforce` |
|
||||
| **密钥轮换** | 定期更换签名密钥并重新签名配置文件 |
|
||||
|
||||
## 敏感信息隔离
|
||||
|
||||
### 原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **密钥不上传** | `secrets.yaml` 必须在 `.gitignore` 中 |
|
||||
| **环境变量注入** | 生产环境通过环境变量注入密钥 |
|
||||
| **不记录日志** | 配置值不写入日志 |
|
||||
|
||||
### secrets.yaml
|
||||
|
||||
```yaml
|
||||
# 安全配置 - 请勿提交到版本控制
|
||||
# Security config - DO NOT commit to version control
|
||||
|
||||
# Dashboard 凭证
|
||||
dashboard:
|
||||
password: "your-hashed-password"
|
||||
jwt_secret: "your-jwt-secret"
|
||||
|
||||
# LLM Provider API Keys
|
||||
providers:
|
||||
openai:
|
||||
api_key: "sk-..."
|
||||
anthropic:
|
||||
api_key: "sk-ant-..."
|
||||
dashscope:
|
||||
api_key: "..."
|
||||
|
||||
# 平台凭证
|
||||
platforms:
|
||||
telegram:
|
||||
bot_token: "12345:ABC..."
|
||||
discord:
|
||||
bot_token: "..."
|
||||
|
||||
# 第三方服务
|
||||
third_party:
|
||||
baidu_aip:
|
||||
app_id: ""
|
||||
api_key: ""
|
||||
secret_key: ""
|
||||
moonshotai:
|
||||
api_key: ""
|
||||
coze:
|
||||
api_key: ""
|
||||
bot_id: ""
|
||||
|
||||
# API Keys(HTTP API 服务认证)
|
||||
api:
|
||||
keys:
|
||||
- id: "my-app"
|
||||
key: "sk-xxxxxxxxxxxx"
|
||||
name: "My Application"
|
||||
permissions:
|
||||
- "chat"
|
||||
- "file"
|
||||
- "message"
|
||||
rate_limit:
|
||||
requests: 100
|
||||
period: 60
|
||||
```
|
||||
|
||||
### 环境变量注入
|
||||
|
||||
敏感配置通过环境变量覆盖:
|
||||
|
||||
```bash
|
||||
# .env 或系统环境变量
|
||||
ASTRBOT_DASHBOARD_PASSWORD=xxx
|
||||
ASTRBOT_DASHBOARD_JWT_SECRET=xxx
|
||||
ASTRBOT_PROVIDER_OPENAI_API_KEY=sk-xxx
|
||||
ASTRBOT_PROVIDER_ANTHROPIC_API_KEY=sk-ant-xxx
|
||||
ASTRBOT_PLATFORM_TELEGRAM_BOT_TOKEN=xxx
|
||||
```
|
||||
|
||||
## 配置文件结构
|
||||
|
||||
### 1. system.yaml(系统配置)
|
||||
|
||||
```yaml
|
||||
# 系统配置
|
||||
|
||||
log:
|
||||
level: INFO # DEBUG, INFO, WARNING, ERROR
|
||||
file_enable: false
|
||||
file_path: logs/astrbot.log
|
||||
file_max_mb: 20
|
||||
disable_access_log: true
|
||||
|
||||
proxy:
|
||||
http_proxy: ""
|
||||
https_proxy: ""
|
||||
no_proxy:
|
||||
- localhost
|
||||
- 127.0.0.1
|
||||
|
||||
trace:
|
||||
enable: false
|
||||
log_enable: false
|
||||
log_path: logs/astrbot.trace.log
|
||||
|
||||
temp:
|
||||
dir_max_size: 1024 # MB
|
||||
|
||||
timezone: Asia/Shanghai
|
||||
|
||||
pypi_index_url: https://mirrors.aliyun.com/pypi/simple/
|
||||
pip_install_arg: ""
|
||||
|
||||
# 回调配置
|
||||
callback_api_base: ""
|
||||
|
||||
# API 服务器配置
|
||||
api:
|
||||
host: "0.0.0.0"
|
||||
port: 6185
|
||||
timeout: 60
|
||||
max_body_size: 100
|
||||
rate_limit:
|
||||
default:
|
||||
requests: 100
|
||||
period: 60
|
||||
high:
|
||||
requests: 1000
|
||||
period: 60
|
||||
```
|
||||
|
||||
### 2. platform.yaml(平台配置)
|
||||
|
||||
```yaml
|
||||
# 平台配置
|
||||
|
||||
# 通用平台设置
|
||||
platform_settings:
|
||||
unique_session: false
|
||||
rate_limit:
|
||||
time: 60
|
||||
count: 30
|
||||
strategy: "stall" # stall, reject
|
||||
reply_prefix: ""
|
||||
forward_threshold: 1500
|
||||
enable_id_white_list: true
|
||||
id_whitelist: []
|
||||
id_whitelist_log: true
|
||||
wl_ignore_admin_on_group: true
|
||||
wl_ignore_admin_on_friend: true
|
||||
reply_with_mention: false
|
||||
reply_with_quote: false
|
||||
path_mapping: []
|
||||
segmented_reply:
|
||||
enable: false
|
||||
only_llm_result: true
|
||||
interval_method: "random"
|
||||
interval: "1.5,3.5"
|
||||
words_count_threshold: 150
|
||||
split_mode: "regex"
|
||||
regex: ".*?[。?!~…]+|.+$"
|
||||
split_words: ["。", "?", "!", "~", "…"]
|
||||
no_permission_reply: true
|
||||
empty_mention_waiting: true
|
||||
empty_mention_waiting_need_reply: true
|
||||
friend_message_needs_wake_prefix: false
|
||||
ignore_bot_self_message: false
|
||||
ignore_at_all: false
|
||||
|
||||
# 平台列表
|
||||
platforms: []
|
||||
|
||||
# 平台特定配置
|
||||
platform_specific:
|
||||
lark:
|
||||
pre_ack_emoji:
|
||||
enable: false
|
||||
emojis: ["Typing"]
|
||||
telegram:
|
||||
pre_ack_emoji:
|
||||
enable: false
|
||||
emojis: ["✍️"]
|
||||
discord:
|
||||
pre_ack_emoji:
|
||||
enable: false
|
||||
emojis: ["🤔"]
|
||||
```
|
||||
|
||||
### 3. providers.yaml(提供商配置)
|
||||
|
||||
```yaml
|
||||
# LLM 提供商配置
|
||||
|
||||
provider_settings:
|
||||
enable: true
|
||||
default_provider_id: ""
|
||||
fallback_chat_models: []
|
||||
default_image_caption_provider_id: ""
|
||||
image_caption_prompt: "Please describe the image using Chinese."
|
||||
provider_pool: ["*"]
|
||||
|
||||
# API Keys 在 secrets.yaml 中配置
|
||||
# providers:
|
||||
# openai:
|
||||
# api_key: "sk-..." # 在 secrets.yaml 中
|
||||
# model: "gpt-4"
|
||||
# base_url: "" # 可选,自定义 endpoint
|
||||
```
|
||||
|
||||
### 4. agent.yaml(Agent 配置)
|
||||
|
||||
```yaml
|
||||
# Agent 配置
|
||||
|
||||
agent_settings:
|
||||
wake_prefix: ["/"]
|
||||
default_personality: "default"
|
||||
persona_pool: ["*"]
|
||||
prompt_prefix: "{{prompt}}"
|
||||
|
||||
# 上下文配置
|
||||
context_limit_reached_strategy: "truncate_by_turns"
|
||||
llm_compress_instruction: "..."
|
||||
llm_compress_keep_recent: 6
|
||||
llm_compress_provider_id: ""
|
||||
max_context_length: -1
|
||||
dequeue_context_length: 1
|
||||
|
||||
# 输出配置
|
||||
streaming_response: false
|
||||
show_tool_use_status: false
|
||||
show_tool_call_result: false
|
||||
sanitize_context_by_modalities: false
|
||||
max_quoted_fallback_images: 20
|
||||
|
||||
# Web Search
|
||||
web_search: false
|
||||
websearch_provider: "default"
|
||||
# websearch_tavily_key: 在 secrets.yaml 中
|
||||
# websearch_bocha_key: 在 secrets.yaml 中
|
||||
web_search_link: false
|
||||
|
||||
# 标识
|
||||
identifier: false
|
||||
group_name_display: false
|
||||
datetime_system_prompt: true
|
||||
|
||||
# Agent Runner
|
||||
agent_runner_type: "local" # local, dify, coze, dashscope, deerflow
|
||||
dify_agent_runner_provider_id: ""
|
||||
coze_agent_runner_provider_id: ""
|
||||
dashscope_agent_runner_provider_id: ""
|
||||
deerflow_agent_runner_provider_id: ""
|
||||
|
||||
# 工具配置
|
||||
unsupported_streaming_strategy: "realtime_segmenting"
|
||||
reachability_check: false
|
||||
max_agent_step: 30
|
||||
tool_call_timeout: 60
|
||||
tool_schema_mode: "full"
|
||||
|
||||
# 安全模式
|
||||
llm_safety_mode: true
|
||||
safety_mode_strategy: "system_prompt"
|
||||
|
||||
# 主动能力
|
||||
proactive_capability:
|
||||
add_cron_tools: true
|
||||
|
||||
# Computer Use
|
||||
computer_use_runtime: "none"
|
||||
computer_use_require_admin: true
|
||||
|
||||
# 图片压缩
|
||||
image_compress_enabled: true
|
||||
image_compress_options:
|
||||
max_size: 1024
|
||||
quality: 95
|
||||
|
||||
# 子 Agent 编排
|
||||
subagent_orchestrator:
|
||||
main_enable: false
|
||||
remove_main_duplicate_tools: false
|
||||
router_system_prompt: "..."
|
||||
agents: []
|
||||
|
||||
# STT/TTS
|
||||
provider_stt_settings:
|
||||
enable: false
|
||||
provider_id: ""
|
||||
|
||||
provider_tts_settings:
|
||||
enable: false
|
||||
provider_id: ""
|
||||
dual_output: false
|
||||
use_file_service: false
|
||||
trigger_probability: 1.0
|
||||
|
||||
# LTM
|
||||
provider_ltm_settings:
|
||||
group_icl_enable: false
|
||||
group_message_max_cnt: 300
|
||||
image_caption: false
|
||||
image_caption_provider_id: ""
|
||||
active_reply:
|
||||
enable: false
|
||||
method: "possibility_reply"
|
||||
possibility_reply: 0.1
|
||||
whitelist: []
|
||||
```
|
||||
|
||||
### 5. plugins/(插件配置)
|
||||
|
||||
各插件配置在 `plugins/` 目录下,文件名与插件名对应:
|
||||
|
||||
```
|
||||
plugins/
|
||||
├── _conf_schema.json # 插件配置 schema
|
||||
├── my_plugin.yaml # my_plugin 插件配置
|
||||
└── another_plugin.yaml # another_plugin 插件配置
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
$XDG_CONFIG_HOME/astrbot/
|
||||
├── config.yaml # 主配置入口
|
||||
├── secrets.yaml # 安全配置(不提交)
|
||||
├── system.yaml # 系统配置
|
||||
├── platform.yaml # 平台配置
|
||||
├── providers.yaml # 提供商配置
|
||||
├── agent.yaml # Agent 配置
|
||||
├── gpg.yaml # GPG 安全配置(可选)
|
||||
├── plugins/ # 插件配置
|
||||
│ ├── _conf_schema.json # 插件 schema
|
||||
│ └── *.yaml # 各插件配置
|
||||
└── mcp_servers.json # MCP 服务器配置
|
||||
```
|
||||
|
||||
## 配置加载优先级
|
||||
|
||||
```
|
||||
环境变量 > secrets.yaml > config.yaml > 默认值
|
||||
```
|
||||
|
||||
| 优先级 | 来源 | 说明 |
|
||||
|--------|------|------|
|
||||
| 最高 | 环境变量 | `ASTRBOT_*` 前缀 |
|
||||
| 高 | secrets.yaml | 敏感信息 |
|
||||
| 中 | config.yaml | 用户配置 |
|
||||
| 低 | 默认值 | 代码中的默认值 |
|
||||
|
||||
## 配置迁移
|
||||
|
||||
旧版 `cmd_config.json` 迁移到新版:
|
||||
|
||||
| 旧字段 | 新配置文件 | 说明 |
|
||||
|--------|------------|------|
|
||||
| `dashboard.*` | `secrets.yaml` | 密码、JWT secret |
|
||||
| `provider_settings.websearch_*_key` | `secrets.yaml` | API keys |
|
||||
| `platform_settings.*` | `platform.yaml` | 平台设置 |
|
||||
| `provider_settings.*` | `providers.yaml` + `agent.yaml` | 提供商和 Agent |
|
||||
| `provider_stt/tts_settings.*` | `agent.yaml` | STT/TTS |
|
||||
| `content_safety.baidu_aip.*` | `secrets.yaml` | 安全密钥 |
|
||||
| `log_level`, `http_proxy` | `system.yaml` | 系统配置 |
|
||||
| `plugin_set`, `kb_*` | `plugins/` | 插件配置 |
|
||||
|
||||
## 不规范示例
|
||||
|
||||
❌ **旧方式** - 所有配置混在一起:
|
||||
|
||||
```json
|
||||
{
|
||||
"dashboard": {
|
||||
"password": "plain-text-or-hashed",
|
||||
"jwt_secret": "secret-in-config"
|
||||
},
|
||||
"provider_settings": {
|
||||
"openai_api_key": "sk-xxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
✅ **新方式** - 分离关注点:
|
||||
|
||||
```
|
||||
config/
|
||||
├── secrets.yaml # 密码、密钥
|
||||
├── system.yaml # 日志、代理
|
||||
├── platform.yaml # 平台设置
|
||||
├── providers.yaml # 提供商配置
|
||||
└── agent.yaml # Agent 配置
|
||||
```
|
||||
|
||||
## 实施建议
|
||||
|
||||
1. **新增配置**:新功能应按域分类到对应文件
|
||||
2. **敏感信息**:绝不写入 `config.yaml`,使用 `secrets.yaml` 或环境变量
|
||||
3. **默认值**:在代码中设置默认值,配置文件仅覆盖需要修改的项
|
||||
4. **Schema 验证**:使用 JSON Schema 验证配置文件格式
|
||||
114
openspec/env.md
114
openspec/env.md
@@ -155,6 +155,58 @@
|
||||
|
||||
---
|
||||
|
||||
## API 服务器配置 / API Server
|
||||
|
||||
### `ASTRBOT_API_ENABLE`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | 启用 HTTP API 服务器 |
|
||||
| 类型 | boolean |
|
||||
| 默认 | `true` |
|
||||
|
||||
### `ASTRBOT_API_TIMEOUT`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | API 请求超时时间(秒) |
|
||||
| 类型 | integer |
|
||||
| 默认 | `60` |
|
||||
|
||||
### `ASTRBOT_API_MAX_BODY_SIZE`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | API 最大请求体大小(MB) |
|
||||
| 类型 | integer |
|
||||
| 默认 | `100` |
|
||||
|
||||
### `ASTRBOT_API_KEY`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | 默认 API Key(用于开发环境) |
|
||||
| 类型 | string |
|
||||
| 注意 | 建议通过 secrets.yaml 配置 |
|
||||
|
||||
### `ASTRBOT_CALLBACK_API_BASE`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | Webhook 回调基础 URL |
|
||||
| 类型 | url |
|
||||
| 示例 | `https://your-server.com/callback` |
|
||||
|
||||
### `ASTRBOT_CALLBACK_SECRET`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | Webhook 回调签名密钥 |
|
||||
| 类型 | string |
|
||||
| 注意 | 用于验证回调请求签名 |
|
||||
|
||||
---
|
||||
|
||||
## SSL/TLS 配置
|
||||
|
||||
### `ASTRBOT_SSL_ENABLE`
|
||||
@@ -268,6 +320,67 @@
|
||||
|
||||
---
|
||||
|
||||
## GPG 安全配置 / GPG Security
|
||||
|
||||
### `ASTRBOT_GPG_ENABLE`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | 启用 GPG 配置签名与验签功能 |
|
||||
| 类型 | boolean |
|
||||
| 默认 | `false` |
|
||||
|
||||
### `ASTRBOT_GPG_VERIFY_MODE`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | 验签模式 |
|
||||
| 类型 | enum |
|
||||
| 默认 | `warn` |
|
||||
| 可选值 | `none` (不验签), `warn` (仅警告), `enforce` (阻止启动) |
|
||||
|
||||
### `ASTRBOT_GPG_TRUSTED_KEYS`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | 信任的 GPG 公钥指纹列表(逗号分隔) |
|
||||
| 类型 | string |
|
||||
| 示例 | `ABCDEF1234567890...,FEDCBA0987654321...` |
|
||||
|
||||
### `ASTRBOT_GPG_SIGNED_CONFIGS`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | 需要验签的配置文件列表(逗号分隔) |
|
||||
| 类型 | string |
|
||||
| 示例 | `secrets.yaml,agent.yaml,platform.yaml` |
|
||||
|
||||
### `ASTRBOT_GPG_GNUPG_HOME`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | GPG 主目录路径(默认使用系统配置) |
|
||||
| 类型 | path |
|
||||
| 示例 | `/home/user/.gnupg` |
|
||||
|
||||
### `ASTRBOT_GPG_PRIVATE_KEY`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | GPG 私钥(ASCII Armor 格式),用于签名 |
|
||||
| 类型 | string |
|
||||
| 注意 | 建议通过 secrets.yaml 配置,优先使用环境变量 |
|
||||
|
||||
### `ASTRBOT_GPG_PASSPHRASE`
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 说明 | GPG 私钥密码短语 |
|
||||
| 类型 | string |
|
||||
| 注意 | 建议通过 secrets.yaml 配置,优先使用环境变量 |
|
||||
|
||||
---
|
||||
|
||||
## 命名规范
|
||||
|
||||
### 前缀规则
|
||||
@@ -276,6 +389,7 @@
|
||||
|------|------|
|
||||
| `ASTRBOT_` | AstrBot 核心配置 |
|
||||
| `ASTRBOT_SSL_` | SSL/TLS 配置 |
|
||||
| `ASTRBOT_GPG_` | GPG 安全配置 |
|
||||
| `ASTRBOT_INSTANCE_` | 实例相关 |
|
||||
| `http_proxy`, `https_proxy`, `no_proxy` | 标准代理变量(无前缀) |
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ AstrBot 遵循 [XDG Base Directory Specification](https://specifications.freedes
|
||||
```
|
||||
/var/lib/astrbot/
|
||||
├── config/ # 配置文件
|
||||
│ └── mcp_servers.json # MCP 服务器配置
|
||||
├── data/ # 插件、skills 等
|
||||
│ ├── plugins/
|
||||
│ ├── plugin_data/
|
||||
@@ -62,6 +63,36 @@ AstrBot 遵循 [XDG Base Directory Specification](https://specifications.freedes
|
||||
└── pid # PID 文件
|
||||
```
|
||||
|
||||
### MCP 服务器配置
|
||||
|
||||
MCP 服务器配置位于 `config/mcp_servers.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"filesystem": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"],
|
||||
"env": {}
|
||||
},
|
||||
"http-server": {
|
||||
"url": "http://localhost:3000/mcp",
|
||||
"transport": "sse"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**配置字段**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `command` | string | 启动命令(stdio 传输) |
|
||||
| `args` | array | 命令参数 |
|
||||
| `env` | object | 环境变量 |
|
||||
| `url` | string | 服务器 URL(HTTP 传输) |
|
||||
| `transport` | string | 传输类型:`stdio` / `sse` / `streamable_http` |
|
||||
|
||||
## 平台差异
|
||||
|
||||
| 平台 | 配置目录 | 数据目录 | 缓存目录 | 运行时目录 |
|
||||
@@ -86,7 +117,6 @@ AstrBot 遵循 [XDG Base Directory Specification](https://specifications.freedes
|
||||
```
|
||||
$XDG_DATA_HOME/astrbot/
|
||||
├── data/ # 应用数据
|
||||
│ ├── config/ # 配置文件
|
||||
│ ├── plugins/ # 插件目录
|
||||
│ ├── plugin_data/ # 插件数据
|
||||
│ ├── skills/ # Skills 目录
|
||||
@@ -101,7 +131,8 @@ $XDG_DATA_HOME/astrbot/
|
||||
|
||||
$XDG_CONFIG_HOME/astrbot/
|
||||
├── .env # 环境变量
|
||||
└── config.yaml # 主配置文件
|
||||
├── config.yaml # 主配置文件
|
||||
└── mcp_servers.json # MCP 服务器配置
|
||||
```
|
||||
|
||||
## 路径映射
|
||||
@@ -283,6 +314,47 @@ $XDG_DATA_HOME/astrbot/<instance_name>/
|
||||
|
||||
所有平台统一使用 `ASTRBOT_*` 环境变量覆盖默认路径,优先级最高。
|
||||
|
||||
## 与 Claude Code 目录对比
|
||||
|
||||
Claude Code 使用 `~/.claude/` 作为根目录,**不遵循 XDG 规范**:
|
||||
|
||||
```
|
||||
~/.claude/ # Claude Code 根目录
|
||||
├── backups/ # 备份
|
||||
├── cache/ # 缓存
|
||||
├── downloads/ # 下载
|
||||
├── file-history/ # 文件历史
|
||||
├── paste-cache/ # 粘贴缓存
|
||||
├── plans/ # 计划
|
||||
├── plugins/ # 插件
|
||||
├── projects/ # 项目会话
|
||||
├── session-env/ # 会话环境
|
||||
├── sessions/ # 会话
|
||||
├── shell-snapshots/ # Shell 快照
|
||||
├── skills/ # Skills
|
||||
├── tasks/ # 任务
|
||||
├── teams/ # 团队
|
||||
├── history.jsonl # 对话历史
|
||||
├── settings.json # 设置
|
||||
└── settings.local.json # 本地设置
|
||||
```
|
||||
|
||||
### 关键差异
|
||||
|
||||
| 维度 | Claude Code | AstrBot |
|
||||
|------|-------------|---------|
|
||||
| 规范 | 非标准(固定 `~/.claude/`) | XDG 规范 |
|
||||
| 配置 | 根目录直接放配置文件 | 分离到 `$XDG_CONFIG_HOME/` |
|
||||
| 缓存 | 根目录下 `cache/` | `$XDG_CACHE_HOME/` |
|
||||
| 数据 | 根目录直接放数据文件 | 分离到 `$XDG_DATA_HOME/` |
|
||||
| 会话 | `sessions/`, `session-env/` | `$XDG_STATE_HOME/` |
|
||||
| 项目 | `projects/` | 内嵌在数据目录 |
|
||||
|
||||
### 设计哲学
|
||||
|
||||
- **Claude Code**:简单直接,所有内容在 `~/.claude/` 下
|
||||
- **AstrBot**:遵循 XDG,数据分类清晰(配置/数据/缓存/状态分离)
|
||||
|
||||
## 已知限制
|
||||
|
||||
- Windows 平台**不遵循** XDG 规范,使用 Windows 标准路径
|
||||
|
||||
Reference in New Issue
Block a user