Alice
AI Local Interactive Cross-device Engine
同一个 AI 会话,随时随地。终端 ↔ 飞书,没有云锁定。
Alice 是一个飞书长连接连接器,把 CLI 型 LLM agent 变成飞书里的交互式 bot。支持 OpenCode(DeepSeek V4)、Codex、Claude、Gemini、Kimi。
核心思路
你的终端 agent 和飞书 bot 是同一个会话。在 IDE 里开始重构,手机上查进度,飞书里发下一条指令。Alice 把你的本地 CLI agent 桥接到飞书 WebSocket,让你不被任何设备束缚。
Alice 解决什么问题?
你已经装了 LLM agent CLI,终端里用得很好。但是:
- 通过 WebSocket 连接飞书,实时接收消息
- 把收到的消息路由到
chat(闲聊)或work(任务执行)场景 - 调用配置好的 LLM CLI,传入合适的 prompt、模型和权限设置
- 把进度更新、最终回复、文件、图片发回飞书
- 暴露本地 HTTP API 给 bundled skill 和自动化任务使用
主要特性
- 多 bot:一个进程、一份
config.yaml、多个独立的 bot - 场景路由:
chat和work两种模式,各自使用不同的 LLM profile - 六种后端:OpenCode、Codex、Claude、Gemini、Kimi — 可以按场景切换
- 会话持久化:可恢复的 thread、session 别名、用量计数器
- 实时状态卡片:显示后端活动和文件变更的心跳卡片
- 自动化:类似 cron 的定时任务,支持
send_text、run_llm、run_workflow - Bundled Skill:可扩展的脚本 skill,通过 runtime API 交互
- 子任务委托:
alice delegate让 OpenCode agent 把子任务发给其他后端 - 零云依赖:所有东西都在你的机器上运行
谁适合用 Alice?
- 使用飞书的团队,想把 LLM agent 放进群聊而不必自己写集成
- 开发者,已经在用 CLI agent,想在群里也能用
- 运维人员,需要定时自动化 + 交互式 LLM 能力
导航
快速开始
npm install -g @alice_space/alice
alice setup
# 编辑 ~/.alice/config.yaml 填入飞书凭据
alice --feishu-websocket
详见快速开始教程。
快速开始
5 分钟内让 Alice 运行起来并响应消息。
前置条件
- Node.js(用于
npm install)或 Go 1.25+(用于源码编译) - 一个飞书应用,已启用 bot 能力和长连接
- 至少安装并认证好一个 LLM CLI:
如果还没搭建飞书应用,请先按照飞书开放平台配置教程操作。
第 1 步:安装
通过 npm(推荐):
npm install -g @alice_space/alice
通过安装脚本:
curl -fsSL https://cdn.jsdelivr.net/gh/Alice-space/alice@main/scripts/alice-installer.sh | bash -s -- install
从源码编译:
git clone https://github.com/Alice-space/alice.git
cd alice
go build -o bin/alice ./cmd/connector
第 2 步:初始化
alice setup
这会在 ~/.alice/ 下创建目录结构,写入默认的 config.yaml,同步内置 bundled skill,并在 Linux 上注册 systemd 用户单元。
第 3 步:配置
编辑 ~/.alice/config.yaml,至少填入以下内容:
bots:
my_bot:
name: "Alice"
feishu_app_id: "cli_xxxxxxxx" # 来自飞书开放平台
feishu_app_secret: "your_secret" # 来自飞书开放平台
llm_profiles:
chat:
provider: "opencode"
model: "deepseek/deepseek-v4-flash"
work:
provider: "opencode"
model: "deepseek/deepseek-v4-pro"
默认配置包含指向 DeepSeek 模型的 OpenCode profile。如果使用其他 LLM CLI,请参见配置 LLM 后端。
第 4 步:验证后端认证
确保你的 LLM CLI 能正常认证:
opencode --version # 或 codex、claude 等
第 5 步:启动
alice --feishu-websocket
你应该能看到飞书 WebSocket 连接和每个 bot runtime 初始化的日志。
第 6 步:用 Work 模式测试
大多数人用 Alice 是冲着 work 模式来的 — 工程任务、调试、自动化。用法:
在飞书群聊里 @你的 bot:
@Alice #work 修复 auth.go 里的登录超时问题
发生了什么:
- Alice 为这个任务创建飞书 thread
- 启动配置好的 LLM 后端(如 DeepSeek V4)
- 进度和工具调用实时推送到 thread
- 会话被持久化 — 之后可以从终端恢复
试试内置命令:
/help — 显示命令列表
/status — 查看当前会话和后端信息
/stop — 取消正在运行的任务
Chat 模式(闲聊)
Alice 也支持 casual chat 模式,bot 像群里的常住成员一样参与对话。直接 @ 即可:
@Alice 今天天气怎么样?
Chat 模式使用 chat LLM profile(轻量模型),整个群共享一个会话,不创建 thread。用 /clear 重置聊天会话。
提示:默认
config.example.yaml同时启用了两种模式。大多数运维场景以 work 模式为主。如果只需要 work,设置group_scenes.chat.enabled: false即可。
接下来?
飞书开放平台配置
本教程将指导你创建一个可供 Alice 连接的飞书应用。预计耗时:15 分钟。
概览
Alice 需要一个具备以下条件的飞书应用:
- 已启用 bot 能力
- 已订阅
im.message.receive_v1事件 - 已配置所需的消息权限
- 已启用长连接模式
第 1 步:登录飞书开放平台
访问飞书开放平台,使用你的组织账号登录。
Lark(国际版)用户:请访问 Lark Open Platform,并在 bot 配置中设置
feishu_base_url: "https://open.larksuite.com"。
第 2 步:创建应用
- 点击创建应用
- 选择企业自建应用
- 为应用命名(例如 "Alice Bot")并上传图标
- 点击创建
第 3 步:启用 Bot 能力
- 在左侧边栏,进入功能 → 机器人
- 开启启用机器人
- 根据需要配置 bot 的名称、头像和简介
第 4 步:添加事件订阅
- 进入事件订阅
- 点击添加事件
- 找到并选择接收消息 →
im.message.receive_v1 - 点击确认
这样 Alice 就能收到 bot 可见的所有消息了。
第 5 步:配置权限
- 进入权限管理
- 搜索并开通以下权限:
| 权限 | 用途 |
|---|---|
im:message | 读取发送给 bot 的消息 |
im:message:send_as_bot | 以 bot 身份发送消息 |
im:message:read | 读取消息内容 |
im:resource | 下载图片和文件 |
contact:user.id:readonly | 获取用户名称 |
contact:group.id:readonly | 获取群聊信息 |
- 点击保存
第 6 步:启用长连接
- 进入功能 → 事件订阅
- 找到连接方式区域
- 从Request URL切换为长连接
- 保存更改
这一步至关重要。Alice 使用 WebSocket 长连接,而非 HTTP webhook。如果不启用长连接模式,Alice 将无法接收消息。
第 7 步:获取凭据
- 进入应用设置 → 基础信息
- 复制你的 App ID(应用凭证 → App ID)
- 复制你的 App Secret(应用凭证 → App Secret)
将这些填入 config.yaml:
bots:
my_bot:
feishu_app_id: "cli_xxxxxxxx" # 你的 App ID
feishu_app_secret: "your_secret" # 你的 App Secret
第 8 步:发布并审批
- 进入版本管理与发布
- 点击创建版本,填写版本信息
- 创建后,点击申请发布
- 你的飞书组织管理员需要审批通过
- 审批通过后,组织内用户即可搜索并与 bot 互动
提示:开发期间,可以在应用设置中将个人用户添加为应用协作者,这样在发布前就可以测试 bot。
验证
使用 alice --feishu-websocket 启动 Alice 后,检查日志:
feishu-codex connector started (long connection mode)
如果看到 WebSocket 连接错误,请确认长连接模式已启用且凭据无误。
下一步
安装 Alice
三种安装方式。选择适合你的那一种。
npm(推荐)
npm install -g @alice_space/alice
安装后运行设置向导:
alice setup
此命令会创建 ~/.alice/、写入初始 config.yaml、同步内置 bundled skill、注册 systemd 用户单元(Linux),并安装 OpenCode delegate 插件。
要求: Node.js 18+
安装脚本
通过一行命令从 GitHub Releases 安装:
# 安装最新稳定版
curl -fsSL https://cdn.jsdelivr.net/gh/Alice-space/alice@main/scripts/alice-installer.sh | bash -s -- install
# 安装指定版本
curl -fsSL https://cdn.jsdelivr.net/gh/Alice-space/alice@main/scripts/alice-installer.sh | bash -s -- install --version v1.2.3
# 卸载
curl -fsSL https://cdn.jsdelivr.net/gh/Alice-space/alice@main/scripts/alice-installer.sh | bash -s -- uninstall
安装脚本会自动下载你平台的正确二进制文件(darwin-amd64、darwin-arm64、linux-amd64、linux-arm64、win32-x64)并校验 checksum。
安装后运行 alice setup 初始化配置和 skill 目录。
要求: curl、tar
从源码编译
git clone https://github.com/Alice-space/alice.git
cd alice
go build -o bin/alice ./cmd/connector
可选:安装到 PATH:
cp bin/alice /usr/local/bin/alice
要求: Go 1.25+
验证安装
alice --version
应输出版本号。如果已运行过 alice setup,还可以检查:
ls ~/.alice/
# config.yaml skills/ log/ bots/
Runtime Home
Alice 根据构建渠道使用不同的默认 home 目录:
| 构建渠道 | 默认 Home |
|---|---|
| Release(npm / 安装脚本) | ~/.alice |
| Dev(源码编译) | ~/.alice-dev |
可通过 --alice-home 或环境变量 ALICE_HOME 覆盖。
配置 Chat 和 Work 场景
Alice 将收到的群消息路由到两个场景之一:chat 用于日常对话,work 用于明确的任务执行。
场景路由概览
收到消息
├─ 是内置命令?(/help、/status、/stop、/clear、/session)
│ └─ 直接处理,不使用 LLM
├─ 匹配 work 触发词?(@Alice #work ...)
│ └─ 路由到 work 场景
└─ 其他情况
└─ 路由到 chat 场景(如已启用)
两个场景都在 bots.<id>.group_scenes 下配置。
Chat 场景
Chat 场景适用于低门槛的持久化对话。每个群聊共用一个 session。
group_scenes:
chat:
enabled: true
session_scope: "per_chat"
llm_profile: "chat"
no_reply_token: "[[NO_REPLY]]"
create_feishu_thread: false
| 字段 | 说明 |
|---|---|
enabled | 设为 true 启用 chat 场景 |
session_scope | "per_chat" — 整个群共用一个 session。"per_thread" — 每个飞书话题一个 session |
llm_profile | llm_profiles 下的 LLM profile 名称 |
no_reply_token | 模型返回此字符串时,Alice 保持静默不回复 |
create_feishu_thread | 是否将回复包裹在飞书话题中 |
使用 /clear 重置 chat session 重新开始。
Work 场景
Work 场景适用于面向任务的执行。每个 work 任务拥有独立的话题和 session。
group_scenes:
work:
enabled: true
trigger_tag: "#work"
session_scope: "per_thread"
llm_profile: "work"
create_feishu_thread: true
| 字段 | 说明 |
|---|---|
enabled | 设为 true 启用 work 场景 |
trigger_tag | 消息中必须(在 @bot 提及之后)包含的标签才能触发 work 模式 |
session_scope | "per_thread" — 每个飞书话题独立的 session。"per_chat" — 共享 session |
llm_profile | 要使用的 LLM profile 名称(通常使用更强大的模型) |
create_feishu_thread | 自动为 work 回复创建飞书话题 |
Work 模式用法:
@Alice #work fix the login bug → 启动 work,调用 LLM
@Alice #work → 创建 work 话题但不调用 LLM
@Alice #work /session <backend-session-id> → 将话题绑定到已有的后端 session
常见模式
仅 Chat 的 Bot
group_scenes:
chat:
enabled: true
session_scope: "per_chat"
llm_profile: "chat"
no_reply_token: "[[NO_REPLY]]"
work:
enabled: false
Chat + Work 分离
Chat 使用轻量模型,work 使用更强模型:
llm_profiles:
chat:
provider: "opencode"
model: "deepseek/deepseek-v4-flash"
work:
provider: "opencode"
model: "deepseek/deepseek-v4-pro"
variant: "max"
permissions:
sandbox: "danger-full-access"
ask_for_approval: "never"
group_scenes:
chat:
enabled: true
session_scope: "per_chat"
llm_profile: "chat"
no_reply_token: "[[NO_REPLY]]"
work:
enabled: true
trigger_tag: "#work"
session_scope: "per_thread"
llm_profile: "work"
create_feishu_thread: true
旧版触发模式
如果 chat 和 work 都被禁用,Alice 将回退到旧版触发系统:
bots:
my_bot:
trigger_mode: "at" # at | prefix | all
trigger_prefix: "" # 仅当 trigger_mode 为 "prefix" 时使用
| 模式 | 行为 |
|---|---|
at | 仅接受 @bot 的消息 |
prefix | 仅接受以 trigger_prefix 开头的消息 |
all | 接受所有消息(无过滤) |
新部署建议优先使用显式的场景路由。
配置 LLM 后端
Alice 支持五种 LLM 后端。每个场景引用一个 llm_profile,指定使用哪个 provider、模型和设置。
支持的 Provider
| Provider | CLI 工具 | 备注 |
|---|---|---|
opencode | opencode | OpenCode CLI,用于 DeepSeek 及其他模型 |
codex | codex | OpenAI Codex CLI。支持 reasoning_effort、personality、profile |
claude | claude | Anthropic Claude Code CLI。默认使用流式输出 |
gemini | gemini | Google Gemini CLI |
kimi | kimi | Moonshot Kimi CLI |
每个 provider 需要单独安装和认证。Alice 不管理 provider 的认证。
Profile 配置
Profile 定义在 bots.<id>.llm_profiles 下:
bots:
my_bot:
llm_profiles:
my_profile:
provider: "opencode"
model: "deepseek/deepseek-v4-pro"
variant: "max"
timeout_secs: 172800
permissions:
sandbox: "danger-full-access"
ask_for_approval: "never"
add_dirs: ["/data/corpus"]
通用字段
| 字段 | 全部支持 | 说明 |
|---|---|---|
provider | ✓ | 后端名称:opencode、codex、claude、gemini、kimi |
command | ✓ | CLI 二进制路径。默认为 provider 名称(如 opencode) |
timeout_secs | ✓ | 每次运行超时(秒)。默认:172800(48 小时) |
model | ✓ | 模型标识符(必填) |
permissions.sandbox | ✓ | "read-only"、"workspace-write" 或 "danger-full-access" |
permissions.ask_for_approval | ✓ | "untrusted"、"on-request" 或 "never" |
permissions.add_dirs | ✓ | agent 可访问的额外目录 |
prompt_prefix | ✓ | 每次 prompt 前添加的文本 |
Codex 专属字段
| 字段 | 说明 |
|---|---|
reasoning_effort | 思考级别:"low"、"medium"、"high" 或 "xhigh" |
personality | Codex CLI 配置中的命名人格预设 |
profile | Codex CLI 配置中的命名子 profile |
OpenCode 专属字段
| 字段 | 说明 |
|---|---|
variant | DeepSeek 变体:"max"、"high"、"minimal" |
自定义二进制路径
如果你的 CLI 二进制不在 $PATH 中,请指定绝对路径:
llm_profiles:
work:
provider: "opencode"
command: "/usr/local/bin/opencode"
model: "deepseek/deepseek-v4-pro"
你也可以通过 env 扩展 $PATH:
bots:
my_bot:
env:
PATH: "/home/user/bin:/usr/local/bin:/usr/bin:/bin"
按 Profile 的覆盖
部分后端支持通过 profile_overrides 实现按 profile 的 runner 覆盖。这是一项高级功能,适用于同一个 provider 在不同场景下需要不同 CLI 配置的情况。
llm_profiles:
executor:
provider: "codex"
model: "gpt-5.4-mini"
profile: "executor"
profile_overrides:
executor:
command: "/opt/bin/codex-executor"
provider_profile: "executor-v2"
timeout: 3600
exec_policy:
sandbox: "danger-full-access"
ask_for_approval: "never"
后端进程的环境变量
bots.<id> 下的 env 字段将环境变量传递给每个 LLM 子进程:
bots:
my_bot:
env:
HTTPS_PROXY: "http://127.0.0.1:8080"
ALL_PROXY: "http://127.0.0.1:8080"
这对代理配置和 API 密钥管理特别有用。
示例
OpenCode + DeepSeek(chat)
llm_profiles:
chat:
provider: "opencode"
model: "deepseek/deepseek-v4-flash"
Codex + reasoning
llm_profiles:
work:
provider: "codex"
command: "codex"
model: "gpt-5.4-mini"
reasoning_effort: "high"
permissions:
sandbox: "danger-full-access"
ask_for_approval: "never"
Claude
llm_profiles:
work:
provider: "claude"
model: "claude-sonnet-4-6"
prompt_prefix: "You are a senior software engineer. Be concise."
permissions:
sandbox: "danger-full-access"
ask_for_approval: "never"
Gemini
llm_profiles:
chat:
provider: "gemini"
model: "gemini-2.5-pro"
Kimi
llm_profiles:
chat:
provider: "kimi"
model: "kimi-model-identifier"
自定义 SOUL.md 人格
每个 bot 可以拥有一个名为 SOUL.md 的人格文档,用于定义其行为、语气和回复偏好。
什么是 SOUL.md?
SOUL.md 是一个带 YAML frontmatter 的 Markdown 文件。它有两个用途:
- 人格设定:Markdown 正文被注入到
chat场景的 LLM prompt 中,塑造 bot 的语气和行为 - 元数据:YAML frontmatter 控制机器可读的回复行为
文件位置
默认情况下,Alice 在 bot 的 alice_home 下查找 SOUL.md:
~/.alice/bots/<bot_id>/SOUL.md
你可以通过 soul_path 自定义路径:
bots:
my_bot:
soul_path: "SOUL.md" # 相对于 alice_home(默认)
# soul_path: "/path/to/custom/SOUL.md" # 绝对路径
如果启动时文件不存在,Alice 会从 prompts/SOUL.md.example 写入内嵌模板。
Frontmatter 字段
---
image_refs:
- refs/avatar.png
- refs/signature.jpg
output_contract:
hidden_tags:
- reply_will
- motion
reply_will_tag: reply_will
reply_will_field: reply_will
motion_tag: motion
suppress_token: "[[NO_REPLY]]"
---
| 字段 | 说明 |
|---|---|
image_refs | bot 可以引用的本地图片路径列表。路径相对于 SOUL.md 所在目录 |
output_contract.hidden_tags | bot 回复中 Alice 在发送给飞书之前会剥离的标签 |
output_contract.reply_will_tag | 标记 bot 回复意图的标签 |
output_contract.reply_will_field | 标签内的字段名 |
output_contract.motion_tag | 动作/动画提示的标签 |
output_contract.suppress_token | bot 输出此 token 时,Alice 完全抑制回复 |
完整示例
---
image_refs:
- refs/avatar.png
output_contract:
hidden_tags:
- reply_will
- motion
reply_will_tag: reply_will
reply_will_field: reply_will
motion_tag: motion
suppress_token: "[[NO_REPLY]]"
---
# 人格设定
你是 Alice,一个乐于助人的工程助手。你用简洁的中文夹杂英文技术术语进行交流。除非明确要求,否则不使用 emoji。
## 规则
- 代码片段保持在 30 行以内
- 优先解释思路再展示代码
- 永远不要道歉 — 直接解决问题
SOUL.md 何时生效?
- Chat 场景:完整正文被添加到 prompt 前,Alice 解析 frontmatter 用于回复控制
- Work 场景:SOUL.md 被刻意跳过。Work 模式用于任务执行,不需要人格角色扮演
测试你的人格
- 编辑
SOUL.md - 重启 Alice(多 bot 模式需要重启;单 bot 模式支持热重载)
- 在 chat 场景中发消息 — bot 应体现更新后的人格
- 如需重置对话,使用
/clear
部署到服务器
将 Alice 作为持久化后台服务运行,确保它能在重启后存活并可靠运行。
systemd(Linux)
如果系统支持 systemd,alice setup 会自动创建 systemd 用户单元。
# 启动
systemctl --user start alice.service
# 设置开机自启
systemctl --user enable alice.service
# 查看状态
systemctl --user status alice.service
# 查看日志
journalctl --user-unit alice.service -n 100 --no-pager
journalctl --user-unit alice.service --since "30 min ago" --no-pager
# 重启
systemctl --user restart alice.service
如果安装时没有运行 alice setup,手动创建单元文件:
# ~/.config/systemd/user/alice.service
[Unit]
Description=Alice Feishu LLM Connector
After=network-online.target
[Service]
Type=simple
ExecStart=%h/.alice/bin/alice --feishu-websocket
Restart=on-failure
RestartSec=10
Environment=HOME=%h
[Install]
WantedBy=default.target
然后:
systemctl --user daemon-reload
systemctl --user start alice.service
macOS
在 macOS 上,使用 launchd 或手动运行。
launchd
<!-- ~/Library/LaunchAgents/com.alice.connector.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.alice.connector</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/.alice/bin/alice</string>
<string>--feishu-websocket</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/you/.alice/log/stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/you/.alice/log/stderr.log</string>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/com.alice.connector.plist
手动运行
alice --feishu-websocket
使用 tmux 或 screen 保持进程在登出后继续运行。
Runtime-Only 模式
对于只需要自动化和 Runtime API(无需飞书 WebSocket)的部署:
alice --runtime-only
在无头环境中:
alice-headless --runtime-only
重要:
alice-headless无法启动飞书连接器。它被显式限制为仅 runtime-only 模式。
日志
Alice 使用 zerolog 输出结构化 JSON 日志,支持按天滚动。
log_level: "info" # debug | info | warn | error
log_file: "" # 空 = <ALICE_HOME>/log/YYYY-MM-DD.log
log_max_size_mb: 20 # 超过 20 MB 后滚动
log_max_backups: 5 # 保留 5 个滚动文件
log_max_age_days: 7 # 日志保留 7 天
log_compress: false # 是否 gzip 压缩滚动日志
健康检查
Runtime API 暴露了一个健康检查端点:
curl http://127.0.0.1:7331/healthz
# {"status":"ok"}
监控
- 飞书中的
/status命令显示用量总计和活动自动化任务 journalctl(systemd)或日志文件用于结构化日志分析- Session 和 runtime 状态持久化到 JSON 文件供检查
多 Bot 部署
一个 alice 进程可以承载多个 bot。所有 bot 共享同一进程,但各自拥有独立的 runtime 目录、工作空间和队列。
bots:
engineering_bot:
feishu_app_id: "cli_11111"
# ...
support_bot:
feishu_app_id: "cli_22222"
# ...
多 bot 模式会禁用配置热重载。配置更改后需重启进程。
使用 alice delegate
alice delegate 子命令从命令行向任意已配置的 LLM 后端发送一次性 prompt。
基本用法
alice delegate --provider codex --prompt "Refactor the auth module to use JWT"
alice delegate --provider claude --prompt "Review this code for security issues"
alice delegate --provider opencode --prompt "Explain how DNS resolution works"
参数
| 参数 | 说明 |
|---|---|
--provider | LLM 后端:opencode、codex、claude、gemini、kimi |
--prompt | prompt 文本(必填) |
--model | 覆盖默认模型 |
--workspace | 覆盖工作目录 |
管道输入
通过 stdin 发送 diff 或文件内容:
cat diff.patch | alice delegate --provider claude --prompt "Review this PR diff"
alice delegate --provider codex --prompt "Summarize this log" < /var/log/app.log
OpenCode 插件集成
alice setup 会将插件写入 ~/.config/opencode/plugins/alice-delegate.js。一旦就位,OpenCode agent(包括 DeepSeek)会自动获得两个额外工具:
codex— 将子任务委托给 Codexclaude— 将子任务委托给 Claude
无需额外配置。OpenCode 会自动从该目录加载插件。
这是 alice delegate 的主要用途:让 OpenCode agent 可以将并行工作发散出去,或将专项任务委托给其他 LLM 后端。
连接方式
alice delegate 使用与 Alice 主运行时相同的 llm_profiles 配置。默认使用第一个 bot 下名为 delegate 的 profile。该 profile 决定了委托运行时的模型、权限和环境变量。
bots:
my_bot:
llm_profiles:
delegate:
provider: "claude"
model: "claude-sonnet-4-6"
permissions:
sandbox: "workspace-write"
ask_for_approval: "never"
示例
快速代码审查
alice delegate --provider claude --prompt "Check this function for bugs and suggest improvements" < src/auth.go
重构
alice delegate --provider codex --prompt "Extract the database logic into a separate package"
生成文档
alice delegate --provider opencode --prompt "Generate JSDoc comments for all exported functions"
使用内置命令
Alice 提供多个斜杠命令,这些命令绕过 LLM,由连接器直接处理。所有命令在群聊和私聊中均可使用。
/help
显示内置命令帮助卡片,列出所有可用命令。
/help
/status
显示状态卡片,包含:
- 总计 session 和用量计数器
- 活动的自动化任务
- 当前 LLM 后端和 session 详情
/status
/clear
重置当前 chat 场景的 session。下一条消息将以全新对话开始,不带有之前的上下文。
/clear
仅影响
chat场景。work场景是基于话题的,话题结束时自然重置。
/stop
立即取消当前活跃 session 正在运行的 LLM 调用。
/stop
当 agent 陷入循环或运行时间过长时使用此命令。Bot 会确认停止,并恢复接受新消息。
/session
将飞书 work 话题绑定到已有的后端 session。适用于重启后恢复长时间运行的任务。
/session <backend-session-id>
/session <backend-session-id> Continue the review
- 不带指令:绑定 session,不调用 LLM
- 带指令:绑定 session 并立即用该指令调用 LLM
仅在
work场景话题中有效。
/cd、/ls、/pwd
查看和更改当前 work session 的工作目录:
/pwd # 显示当前目录
/ls # 列出文件
/ls internal/ # 列出子目录中的文件
/cd /tmp/build # 更改目录
这些命令仅影响 work session。目录更改在整个 session 期间持续有效。
命令优先级
当消息以 / 开头时,Alice 在路由到 LLM 之前先检查内置命令:
- 匹配内置命令 → 直接处理
- 不匹配 → 路由到场景(由 LLM 处理)
要强制将以 / 开头的消息发送给 LLM,请在前面加空格或使用 work 触发词:
/some-custom-command # 斜杠前的空格 → LLM 路径
@Alice #work /some-cmd # Work 触发词 → LLM 路径
配置私聊场景
Alice 可以使用与群聊相同的场景路由来处理私聊消息。
私聊 vs 群聊场景
群聊使用 group_scenes。私聊使用 private_scenes。两者的配置方式相同,但位于不同的配置键下:
bots:
my_bot:
group_scenes:
chat: { ... }
work: { ... }
private_scenes:
chat: { ... }
work: { ... }
私聊场景默认禁用。需要显式启用。
Chat 场景(私聊)
private_scenes:
chat:
enabled: true
session_scope: "per_user" # 每个 DM 用户共用一个 session
llm_profile: "chat"
no_reply_token: "[[NO_REPLY]]"
create_feishu_thread: false
| 字段 | 说明 |
|---|---|
session_scope | "per_user" — 同一用户的所有 DM 共用一个 session。"per_message" — 每条 DM 创建新 session |
llm_profile | 与群聊场景相同的 profile 引用 |
no_reply_token | 抑制回复的 token |
典型用途:在 DM 中提供个人助手服务,按用户维护上下文。
Work 场景(私聊)
private_scenes:
work:
enabled: true
trigger_tag: "#work"
session_scope: "per_message" # 每条 #work DM 都是全新 session
llm_profile: "work"
create_feishu_thread: true
| 字段 | 说明 |
|---|---|
session_scope | DM 推荐 "per_message" — 每个任务隔离 |
完整示例
bots:
my_bot:
group_scenes:
chat:
enabled: true
session_scope: "per_chat"
llm_profile: "chat"
no_reply_token: "[[NO_REPLY]]"
work:
enabled: true
trigger_tag: "#work"
session_scope: "per_thread"
llm_profile: "work"
create_feishu_thread: true
private_scenes:
chat:
enabled: true
session_scope: "per_user"
llm_profile: "chat"
no_reply_token: "[[NO_REPLY]]"
work:
enabled: true
trigger_tag: "#work"
session_scope: "per_message"
llm_profile: "work"
create_feishu_thread: true
与群聊的行为差异
- 提及是隐式的 — DM 不需要 @bot。每条消息都直接面向 bot。
- user_id 解析 — Alice 通过飞书 API 解析 DM 用户的名称
- 话题创建 — 当
create_feishu_thread: true时,work 回复会在 DM 内创建话题
编写 Bundled Skill
Bundled skill 扩展了 Alice,提供基于脚本的工具来调用 Runtime HTTP API。本指南将教你如何创建。
Skill 结构
一个 bundled skill 是 skills/ 下的一个目录:
skills/my-skill/
├── SKILL.md # Skill 文档
├── scripts/
│ └── my-skill.sh # 可执行脚本
└── agents/
└── openai.yaml # OpenAI agent 配置(可选)
第 1 步:创建目录
在 Alice 源码树的 skills/ 下,或在 ${ALICE_HOME}/skills/ 下(本地开发),创建你的 skill。
第 2 步:编写 SKILL.md
SKILL.md 为人类和 LLM agent 提供 skill 文档:
# my-skill
将活跃自动化任务的每日摘要发送到指定的飞书群聊。
## 用途
此 skill 由自动化系统触发。它从 runtime API 读取所有活跃任务,并发送格式化的摘要卡片。
## 环境
需要设置 `ALICE_RUNTIME_API_BASE_URL` 和 `ALICE_RUNTIME_API_TOKEN`。
第 3 步:编写脚本
脚本以子进程方式运行。Alice 注入以下环境变量:
| 变量 | 说明 |
|---|---|
ALICE_RUNTIME_API_BASE_URL | Runtime API 的 base URL(如 http://127.0.0.1:7331) |
ALICE_RUNTIME_API_TOKEN | API 认证的 Bearer token |
ALICE_RUNTIME_BIN | alice 二进制路径 |
ALICE_RECEIVE_ID_TYPE | 接收目标的类型(如 chat_id) |
ALICE_RECEIVE_ID | 接收目标的 ID |
ALICE_SOURCE_MESSAGE_ID | 触发消息的 ID(如适用) |
ALICE_ACTOR_USER_ID | 交互者的飞书 user ID |
ALICE_ACTOR_OPEN_ID | 交互者的飞书 open ID |
ALICE_CHAT_TYPE | 对话类型:group 或 p2p |
ALICE_SESSION_KEY | 当前对话的规范 session key |
示例脚本
#!/usr/bin/env bash
set -euo pipefail
# 获取所有活跃任务
TASKS=$(curl -sS \
-H "Authorization: Bearer ${ALICE_RUNTIME_API_TOKEN}" \
"${ALICE_RUNTIME_API_BASE_URL}/api/v1/automation/tasks?status=active")
# 计数和格式化
COUNT=$(echo "$TASKS" | jq '. | length')
echo "Active tasks: $COUNT"
赋予执行权限:
chmod +x skills/my-skill/scripts/my-skill.sh
第 4 步:注册 Skill
将你的 skill 添加到 bot 的允许 skill 列表中:
bots:
my_bot:
permissions:
allowed_skills: ["alice-message", "alice-scheduler", "my-skill"]
Skill 可用的 Runtime API 端点
Skill 主要使用以下端点:
| 端点 | 方法 | 用途 |
|---|---|---|
/api/v1/messages/image | POST | 向对话发送图片 |
/api/v1/messages/file | POST | 向对话发送文件 |
/api/v1/automation/tasks | GET | 列出自动化任务 |
/api/v1/automation/tasks | POST | 创建自动化任务 |
/api/v1/automation/tasks/:id | GET/PATCH/DELETE | 管理特定任务 |
所有请求都需要 Authorization: Bearer <token> 头部。
权限
Skill 在 bot 的运行时权限下运行:
permissions:
runtime_message: true # 允许通过 API 发送消息
runtime_automation: true # 允许管理自动化任务
如果某权限被禁用,对应的 API 端点将返回 403 Forbidden。
内置 Skill 参考
Alice 内置了两个 bundled skill:
- alice-message:通过 runtime API 发送富文本消息和附件
- alice-scheduler:从飞书对话中管理自动化任务
研究它们的源码(skills/alice-message/ 和 skills/alice-scheduler/),了解 skill 结构和 API 使用的实际示例。
排错指南
运行 Alice 的常见问题和解决方案。
Bot 在群聊中不响应
检查场景路由:
- 确认
group_scenes.chat.enabled为true - 如果两个场景都被禁用,检查
trigger_mode(应为at或prefix)
检查 bot 身份:
- Bot 的
open_id现在在启动时自动获取 — 无需手动配置feishu_bot_open_id - 确认
feishu_app_id和feishu_app_secret是否正确
检查日志:
# 查找 WebSocket 连接状态
grep "long connection" ~/.alice/log/*.log
# 查找认证错误
grep "error" ~/.alice/log/*.log | head -20
Work 模式从不触发
- 确认
group_scenes.work.enabled为true - 确认
trigger_tag已设置(如"#work") - 消息必须包含
@BotName #work ...— @mention 和触发标签缺一不可 - 触发标签必须出现在同一条消息中 @mention 之后
模型或推理级别不正确
- 检查
llm_profiles中provider、model和专属字段是否正确 - 确认场景指向正确的 profile key:
group_scenes: work: llm_profile: "work" # 必须与 llm_profiles 下的 key 匹配 - 直接运行 provider CLI 验证认证:
codex --version claude --version
Skill 无法发送附件或管理任务
检查权限:
permissions:
runtime_message: true
runtime_automation: true
检查 API 连通性:
# 在运行 Alice 的机器上执行
curl -s -H "Authorization: Bearer <token>" http://127.0.0.1:7331/healthz
# 应返回 {"status":"ok"}
Runtime HTTP API 绑定在 runtime_http_addr 指定的地址(默认 127.0.0.1:7331)。多 bot 设置会自动递增端口。
配置更改不生效
- 多 bot 模式:配置热重载被禁用。需重启 Alice。
- 单 bot 模式:支持部分热重载,但并非所有配置项都会被监听。
- 配置更改后务必检查日志:
grep "config" ~/.alice/log/*.log | tail -5
WebSocket 连接错误
如果日志中出现连接失败:
- 确认飞书开放平台中已启用长连接模式
- 确认应用已发布并通过审批
- 确认能访问
open.feishu.cn(或 Lark 用户的open.larksuite.com)的网络 - 确认 Lark(国际版)用户已正确设置
feishu_base_url:feishu_base_url: "https://open.larksuite.com"
Provider CLI 未找到
Alice 默认在 $PATH 中查找 CLI 二进制文件。如果未找到:
- 指定绝对路径:
llm_profiles: chat: command: "/usr/local/bin/opencode" - 或在 bot 的 env 中扩展
$PATH:env: PATH: "/home/user/.local/bin:/usr/local/bin:/usr/bin:/bin"
LLM 运行无限挂起
- 检查 LLM profile 中的
timeout_secs(默认:48 小时) - 在飞书中使用
/stop取消正在运行的 session - 检查日志中 provider 专属的错误:
grep -E "timeout|cancelled|killed" ~/.alice/log/*.log - 对于 Codex,检查
codex_idle_timeout_secs设置
日志没有有用信息
将日志级别提高到 debug:
log_level: "debug"
重启 Alice。Debug 模式包含:
- 每次运行的 provider 和 agent 名称
- Thread/session ID
- 渲染后的输入 prompt
- 观察到的工具调用活动
- 最终输出或错误
警告:Debug 日志可能包含完整渲染后的 prompt,包括 SOUL.md 内容。
系统模型
本页讲解 Alice 背后的基本概念:多 bot 架构、场景路由、session 和启动模式。理解这些有助于你高效配置和排错。
Alice 是什么(以及不是什么)
Alice 是一个连接器,而非 bot 框架。它不直接实现聊天逻辑、NLU 或自定义集成。实际上,它:
- 从飞书接收消息
- 决定调用哪个 LLM 后端以及如何调用
- 以子进程方式调用 LLM CLI
- 将响应发回飞书
"智能"部分在 LLM 后端(Codex、Claude 等)。Alice 处理"管道"工作:路由、排队、session 管理、附件 I/O 和进度展示。
多 Bot 模型
一个 alice 进程可以通过一份 config.yaml 托管多个独立的 bot:
bots:
engineering_bot:
feishu_app_id: "cli_11111"
# ...
support_bot:
feishu_app_id: "cli_22222"
# ...
每个 bot 拥有自己独立的:
- Runtime 目录(
~/.alice/bots/<bot_id>/) - 工作空间、prompt 和 SOUL.md
- 飞书凭据(App ID、App Secret)
- LLM profile — 可以使用不同的 provider 和模型
- 场景配置 — 独立的 chat/work 路由
- Runtime API 端口 — 自动递增(7331、7332……)
Bot 之间共享:
- 相同的进程和 worker 池
- 默认的
CODEX_HOME(可按 bot 覆盖)
Bot 目录布局
~/.alice/bots/<bot_id>/
├── workspace/ # Agent 工作空间
├── prompts/ # Prompt 模板覆盖
├── SOUL.md # Bot 人格
└── run/connector/
├── automation.db # 持久化任务存储(bbolt)
├── campaigns.db # 活动索引(bbolt)
├── session_state.json # Session 别名、用量计数器
├── runtime_state.json # 可变运行时状态
└── resources/scopes/ # 已下载的附件和产物
场景路由
每条收到的群消息经过一个决策树:
收到消息
│
├─ 是内置命令?(/help、/status、/stop、/clear、/session)
│ └─ 是 → 直接处理,不涉及 LLM
│
├─ 匹配 work 触发词?(@Bot #work ...)
│ └─ 是 → 路由到 work 场景
│
├─ chat 场景已启用?
│ └─ 是 → 路由到 chat 场景
│
└─ 两个场景都禁用?
└─ 回退到旧版 trigger_mode(at / prefix / all)
场景 vs 旧版触发
旧版 trigger_mode(at/prefix/all)是一个简单的闸门:它决定是接受还是忽略消息。如果接受,只有一个 LLM 流水线。
场景更进一步:它们为每个场景分配不同的 LLM profile、session 作用域、话题行为和 SOUL.md 处理方式。新部署应始终使用场景。
Session 管理
Session 是 LLM 的上下文窗口。Alice 决定何时开始新 session,何时继续已有 session。
Session Key
Alice 使用规范 key 来标识 session:
| 格式 | 示例 |
|---|---|
{receive_id_type}:{receive_id} | chat_id:oc_123 |
| `{key} | scene:{scene}` |
| `{key} | scene:{scene} |
Session 作用域
session_scope 控制何时创建和复用 session:
| 作用域 | 行为 |
|---|---|
per_chat | 整个群/DM 共用一个 session |
per_thread | 每个飞书话题一个 session |
per_user | (仅 DM)每个用户一个 session |
per_message | (仅 DM)每条消息新建 session |
Session 持久化
Alice 将 session 元数据持久化到 session_state.json:
- Provider thread ID(用于与后端恢复)
- Session 别名
- 用量计数器
- 最后消息时间戳
- Work-thread ID 别名
当收到一个新 job 时,Alice 检查是否存在活跃 session。如果存在:
- Provider 原生注入:部分后端(Codex、Claude)允许向正在运行的 session 注入新输入。Alice 优先尝试此方式。
- 排队:如果原生注入失败且 LLM 运行仍活跃,新 job 排队等待。较新的 job 会取代队列中较旧的 job。
- 新运行:如果没有活跃的运行,则向 LLM 后端发送新的 RunRequest。
取消和中断
/stop立即通过 context 取消取消活跃的 LLM 运行- 较新的用户消息会取代排队的 job,但不会中断活跃的运行
- 自动化任务也可能被获取了 session 锁的用户消息中断
启动模式
Alice 支持两种显式的启动模式:
--feishu-websocket
完整模式。连接飞书 WebSocket,处理实时消息,运行自动化,并暴露 Runtime API。
--runtime-only
仅本地模式。Runtime API 和自动化引擎运行,但飞书连接器不启动。用于:
- 调试和开发
- 仅运行自动化调度器
- 无头环境(使用
alice-headless --runtime-only)
alice-headless是一个专用二进制文件,不能启动飞书连接器。尝试alice-headless --feishu-websocket会报错。
配置热重载
- 单 bot 模式:支持有限的局部热重载。部分配置项会被监听变化。
- 多 bot 模式:热重载被刻意禁用。配置更改后务必重启 Alice。
Runtime Home
| 构建渠道 | 默认 Home |
|---|---|
| Release(npm / 安装脚本) | ~/.alice |
| Dev(源码编译) | ~/.alice-dev |
可通过 --alice-home 或环境变量 ALICE_HOME 覆盖。
消息处理流水线
本页带你走完一条飞书消息的完整生命周期 — 从 WebSocket 接收到最终回复。理解这条流水线有助于调试路由问题和调优行为。
概览
飞书 WebSocket
└─ App(job 队列)
└─ Processor(执行)
└─ LLM Backend(子进程)
└─ Reply Dispatcher(发回飞书)
1. WebSocket 接收
Alice 与飞书的 WebSocket 端点建立长连接。当用户发送 bot 可见的消息时,飞书通过此连接投递 im.message.receive_v1 事件。
事件包含:
- 发送者身份(open_id、user_id、名称)
- 消息内容(文本、附件、提及)
- 对话上下文(chat_id、chat_type、如在线程中则为 thread_id)
- Bot 身份(哪个 bot 收到了这条消息)
2. Job 创建
原始事件被标准化为一个 Job 结构体。此步骤:
- 提取被提及的用户
- 解析接收 ID 类型(
chat_id、open_id等) - 设置 bot 所配置的 LLM profile、场景和回复偏好
- 生成 session key 和资源作用域 key
- 附加单调递增的版本号
3. 路由
routeIncomingJob 决定对 job 做什么:
内置命令
如果消息以 /help、/status、/clear、/stop、/session、/cd、/ls 或 /pwd 开头,由连接器直接处理 — 不调用 LLM。参见使用内置命令。
Work 场景
如果 group_scenes.work.enabled 且消息在 @bot 提及后包含 trigger_tag(如 #work),job 被路由到 work 场景。Work job 使用 work 作用域的 session key 和 LLM profile。
Chat 场景
如果 group_scenes.chat.enabled,所有其他消息被路由到 chat。Chat job 使用 chat 作用域的 session key 和 LLM profile。
旧版回退
如果两个场景都被禁用,Alice 回退到匹配 trigger_mode 和 trigger_prefix。
4. 队列和序列化
每个 session 有一个互斥锁来序列化执行:
- 存在活跃运行 → 首先尝试 provider 原生注入(向正在运行的 session 注入新输入)
- 原生注入不可用 → 新 job 排队。较新的 job 取代队列中较旧的 job。
- 无活跃运行 → 接受 job 并分派给 Processor。
Runtime store(runtime_store.go)维护内存中的协调状态:
- 每个 session 的最新版本
- 待处理的排队 job
- 活跃运行的取消句柄
- 每个 session 的互斥锁
5. LLM 前处理
在调用 LLM 之前,Processor 会:
- 加载并解析
SOUL.md(仅 chat)— 分离 YAML frontmatter 和 Markdown 正文 - 将收到的附件下载到作用域内的资源目录
- 为对话推导运行时环境变量
- 准备渲染后的 prompt 文本
Session 状态检查
Alice 检查 session_state.json:
- 如果存在 provider thread ID,后端调用将恢复该 thread
- 如果 session 最近活跃,上一轮对话的上下文可用
6. LLM 执行
Processor 构建一个 RunRequest 并将其分派给 LLM 后端:
RunRequest {
ThreadID → 来自 session 状态(空 = 新 session)
UserText → 渲染后的 prompt
Provider → 来自 llm_profile
Model → 来自 llm_profile
ReasoningEffort → 来自 llm_profile
WorkspaceDir → 每个 bot 的工作空间
ExecPolicy → 沙箱 + 批准设置
Env → 每个 bot + 进程环境变量
OnProgress → 将进度更新流式传输到飞书
}
后端将 provider CLI 作为子进程启动并流式输出。进度更新以状态卡片补丁的形式发送到飞书。
7. 回复分发
当 LLM 完成时,Alice 处理回复:
内容处理
- 如果回复匹配
no_reply_token,保持静默 - 如果在 SOUL.md 中配置了
output_contract,剥离隐藏标签 - 应用飞书格式(富文本、@mention)
话题
- Work 场景且
create_feishu_thread: true:回复发布在飞书话题中 - Chat 场景且
create_feishu_thread: false:回复作为顶级消息发布 - 话题回复:飞书支持时回复到话题。否则回退到直接回复。
即时反馈
在 LLM 开始之前,Alice 发送即时确认:
immediate_feedback_mode: "reaction"→ 给源消息添加 reaction 表情immediate_feedback_mode: "reply"→ 发送显式收到!回复
8. 运行后
- Session 状态持久化到
session_state.json(thread ID、用量计数器、时间戳) - 已下载的附件保留在作用域资源目录中
- Runtime 状态定期刷新
关键不变量
- 每个 session 同时最多一个 LLM 运行 — 由每个 session 的互斥锁强制执行
- 较新的消息取代排队的,但不取代活跃的 — 只有
/stop才能中断正在运行的 LLM - Session 状态以磁盘为后盾 — 进程重启后仍存在
- 附件有作用域隔离 — 每个对话有自己的资源目录
Prompt 拼装
Alice 如何构建发送给 LLM 后端的 prompt 文本。
模板系统
Alice 使用 Go text/template 并结合 Sprig 函数进行 prompt 模板化。模板文件以 .md.tmpl 为后缀。
模板加载
1. 检查磁盘:<prompt_dir>/<template>.tmpl
2. 如果未找到,使用内嵌模板(编译进二进制文件)
磁盘文件会覆盖内嵌模板,支持按 bot 自定义。
模板文件
所有模板位于 prompts/ 下:
| 模板 | 用途 |
|---|---|
connector/bot_soul.md.tmpl | 将 SOUL.md 正文注入 prompt |
connector/current_user_input.md.tmpl | 格式化当前用户消息 |
connector/reply_context.md.tmpl | 添加来自被回复消息的上下文 |
connector/runtime_skill_hint.md.tmpl | 描述可用的 bundled skill |
connector/synthetic_mention.md.tmpl | 格式化合成 @mention |
connector/help.md.tmpl | /help 命令响应 |
llm/initial_prompt.md.tmpl | 首轮系统指令 |
goals/goal_start.tmpl | Goal 初始化 prompt |
goals/goal_continue.tmpl | Goal 继续 prompt |
goals/goal_timeout.tmpl | Goal 超时通知 |
模板变量
模板可以访问完整的 Job 上下文和 session 元数据。关键变量包括:
| 变量 | 说明 |
|---|---|
.UserText | 用户的消息文本 |
.BotName | 回复 bot 的显示名称 |
.SenderName | 发送消息的用户名称 |
.MentionedUsers | 消息中 @mention 的用户列表 |
.ReplyContext | 被回复消息的文本 |
.Attachments | 收到的附件元数据 |
.Scene | "chat" 或 "work" |
.SessionKey | 规范 session 标识符 |
.SoulBody | SOUL.md 正文内容(仅 chat) |
.SkillDescriptions | 已启用 bundled skill 的描述 |
首轮 vs 恢复
Prompt 拼装的关键区别:
首轮(无已有 Thread)
- 拼装完整的初始 prompt
- 包含系统指令(
initial_prompt.md.tmpl) - Chat 场景:前置 SOUL.md 正文
- 身份提示(
Name说:、@mention 规则),除非disable_identity_hints: true
恢复(存在 Provider Thread)
- 仅发送当前用户的消息文本
- Alice 依赖 provider 端的 thread/session 保持之前的上下文
- 无系统 prompt,无 SOUL.md,无身份提示
- 这样更高效 — 后端模型已拥有完整的对话历史
SOUL.md 注入
SOUL.md 根据场景有两个用途:
Chat 场景
- Alice 读取文件,解析 YAML frontmatter
- Frontmatter 字段(
image_refs、output_contract)被 Alice 消耗用于回复控制 - 剩余 Markdown 正文通过
bot_soul.md.tmpl前置到首轮 prompt
Work 场景
SOUL.md 被刻意跳过。Work 模式用于任务执行 — 注入人格会干扰工具使用和代码生成。
身份提示
当 disable_identity_hints: false(默认)时,Alice 为消息添加上下文:
张三说:fix the login timeout
当 disable_identity_hints: true,原始消息直接传递:
fix the login timeout
Prompt 前缀
每个 LLM profile 可以设置 prompt_prefix:
llm_profiles:
work:
prompt_prefix: "You are a senior Go engineer. Be concise, use idiomatic patterns."
此文本会被前置到该 profile 的每次 prompt 中,包括恢复的 session。
Prompt 与调试
当 log_level: debug 时,Alice 会记录发送给每个后端的完整渲染 prompt。Debug 跟踪包括:
- Provider 名称
- 模型和 profile
- Thread/session ID
- 完整的渲染输入文本
- 观察到的工具调用活动和最终输出
警告:渲染后的 prompt 可能包含 SOUL.md 内容和对话历史。避免公开发布 debug 日志。
自动化子系统
Alice 的自动化引擎调度并执行定期任务、工作流和系统维护。
架构
自动化子系统(internal/automation/)使用基于 tick 的执行模型,配合持久化存储。
Automation Engine
├─ Tick Scheduler(周期性循环)
│ ├─ 认领到期任务
│ ├─ 执行任务(send_text / run_llm / run_workflow)
│ └─ 处理完成 / 失败
├─ System Task Scheduler
│ ├─ Session 状态刷新
│ └─ Campaign 调和
├─ Watchdog
│ └─ 对超期或卡住的任务发出告警
└─ Store(bbolt)
└─ 任务持久化
任务模型
作用域
任务的作用域定义其执行位置:
| 作用域 | 说明 |
|---|---|
user | 限定于特定用户(DM 上下文) |
chat | 限定于特定群聊 |
操作
| 操作 | 说明 |
|---|---|
send_text | 向作用域发送预设文本消息 |
run_llm | 在作用域中按指定 prompt 运行 LLM 调用 |
run_workflow | 运行结合 LLM 调用和操作的多步工作流 |
调度
任务可通过两种方式调度:
- Cron 表达式:
"0 9 * * *"— 每天 9 点运行 - 一次性时间戳:ISO 8601 — 在指定时间运行一次
任务生命周期
Created → Active → Claimed → Executing → Completed
↓
Failed → Active(重试)/ Cancelled
- 到期任务在周期性 tick 中被认领(每次 tick 认领一个)
- 被认领的任务在作用域的对话上下文中执行
- 带 cron 表达式的已完成任务会被重新调度到下一次
- 失败任务可能被重试或取消
- 已取消任务被删除或标记为不活跃
执行模型
任务执行时:
- 引擎获取任务作用域的 session 锁
- 任务继承与交互式运行相同的对话上下文:
- 相同的工作空间目录
- 相同的 LLM profile 和权限
- 相同的环境变量
- 对于
run_llm和run_workflow,任务的 prompt 被发送到 LLM 后端 - 回复发送到任务的作用域(群聊或用户 DM)
用户消息可以中断已获取 session 锁的自动化任务。
系统任务
Alice 在引导过程中注册内建的系统任务:
| 任务 | 间隔 | 用途 |
|---|---|---|
| Session 状态刷新 | 周期性 | 将内存中的 session 状态持久化到 session_state.json |
| Campaign 调和 | 周期性 | 同步 campaign 仓库状态 |
Watchdog
Watchdog 监控自动化任务的异常:
- 超期任务:已过调度时间但尚未被认领的任务
- 卡住任务:执行时间过长的任务
当 Watchdog 检测到问题时,它可以:
- 记录警告日志
- 向配置的群聊发送告警消息
- 强制取消卡住的任务
存储
任务持久化在本地 bbolt 数据库中:
~/.alice/bots/<bot_id>/run/connector/automation.db
进程重启后仍存在。存储支持:
- 任务的 CRUD 操作
- 按作用域、状态和到期时间查询
- 原子性的认领并更新以防止重复执行
管理任务
通过 Runtime API
alice runtime automation create '{
"scope_type": "chat",
"scope_id": "oc_xxxxxxxxxxxxx",
"action": "send_text",
"text": "Daily standup reminder!",
"cron": "0 10 * * 1-5"
}'
通过 Bundled Skill
alice-scheduler skill 让用户可以直接从飞书对话中创建和管理任务。
完整任务管理端点参见 Runtime API 参考。
Runtime API 设计
Alice 本地 HTTP API 背后的理念和设计决策。
为什么需要一个本地 API?
Alice 将 bundled skill 作为子进程脚本运行。这些脚本需要与运行中的连接器交互 — 发送图片、管理任务、查询状态。从 shell 脚本中无法直接进行 Go 互操作,因此 Alice 暴露了一个本地 HTTP API。
设计原则
1. 默认仅本地访问
API 绑定到 127.0.0.1(可通过 runtime_http_addr 配置)。它并非设计为对外暴露。如果需要远程访问,请使用反向代理或 SSH 隧道 — 但这并非预期用例。
2. Bearer Token 认证
每个请求(/healthz 除外)都需要:
Authorization: Bearer <token>
Token 在启动时自动生成。环境变量 ALICE_RUNTIME_API_TOKEN 自动将其注入到 skill 脚本中。
3. 纵深防御
多层保护:
- 认证速率限制:每个 token 每分钟 120 个请求
- 请求体大小限制:每个请求 1 MB
- 文件验证:上传的文件必须是可读、非空的常规文件
- 飞书大小限制:上传仍受飞书文件大小和类型限制的约束
4. 无纯文本发送端点
Runtime API 没有纯文本发送端点。为什么?
文本回复通常走主回复流水线 — 它们需要 session 上下文、正确的线程和回复元数据。Runtime API 设计用于副作用(发送图片、文件、管理任务),而非绕过回复流水线。
如果 skill 需要以自动化任务的方式发送文本消息,它会通过 automation API 创建一个 send_text 任务。自动化引擎处理其余工作。
API 接口
消息
POST /api/v1/messages/image— 上传并发送图片POST /api/v1/messages/file— 上传并发送文件
两者接受 multipart/form-data,可选 caption 字段。
自动化
- 自动化任务的完整 CRUD:创建、列表、获取、更新、删除
Goal
- Goal 生命周期管理:获取、创建、暂停、恢复、完成、删除
健康检查
GET /healthz— 无需认证,服务器运行时返回 200
环境变量注入
Skill 无需知道 API 地址或 token。Alice 注入它们:
ALICE_RUNTIME_API_BASE_URL="http://127.0.0.1:7331"
ALICE_RUNTIME_API_TOKEN="<auto-generated>"
ALICE_RUNTIME_BIN="/usr/local/bin/alice"
额外的上下文变量:
ALICE_RECEIVE_ID_TYPE="chat_id"
ALICE_RECEIVE_ID="oc_xxxxxxxxxxxxx"
ALICE_SOURCE_MESSAGE_ID="om_xxxxxxxxxxxxx"
ALICE_ACTOR_USER_ID="ou_xxxxxxxxxxxxx"
ALICE_ACTOR_OPEN_ID="ou_xxxxxxxxxxxxx"
ALICE_CHAT_TYPE="group"
ALICE_SESSION_KEY="chat_id:oc_xxx|scene:chat"
多 Bot API 端口
在多 bot 模式下,每个 bot 在自动递增的端口上获得自己的 Runtime API 服务器:
| Bot 序号 | 端口 |
|---|---|
| 第一个 | 7331 |
| 第二个 | 7332 |
| 第三个 | 7333 |
| …… | …… |
Skill 通过继承其被触发所在对话作用域的环境变量来指向正确的 bot。
优雅关闭
当 Alice 收到关闭信号时,Runtime API 服务器:
- 停止接受新连接
- 等待最多
runtime_api_shutdown_timeout_secs秒(默认:5 秒)让正在处理的请求完成 - 超时后强制关闭剩余连接
扩展 API
新端点可在 internal/runtimeapi/ 中添加。开发者指南参见贡献指南和架构概览。
配置项手册
config.yaml 中所有配置项的完整参考。结构按文件布局组织。
顶级键
bots(必填)
Bot ID 到 bot 配置的映射。bots 下的每个 key 是作为运行时标识符的 bot ID。
bots:
engineering_bot:
# bot 配置...
support_bot:
# bot 配置...
log_level
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "info" |
| 可选值 | "debug"、"info"、"warn"、"error" |
整个进程的结构化日志级别。
log_file
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | ""(自动:<ALICE_HOME>/log/YYYY-MM-DD.log) |
日志文件路径,按日滚动。为空则使用默认值。
log_max_size_mb
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 20 |
日志文件滚动前的最大大小(MB)。
log_max_backups
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 5 |
保留的滚动日志文件最大数量。
log_max_age_days
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 7 |
保留滚动日志文件的最大天数。
log_compress
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | false |
是否 gzip 压缩滚动日志文件。
bots.<id>
每个 bot 由其 key 标识,并用以下字段配置。
name
| 字段 | 值 |
|---|---|
| 类型 | string |
| 必填 | 否 |
在 prompt 和状态卡片中使用的显示名称。默认使用 bot ID。
feishu_app_id(必填)
| 字段 | 值 |
|---|---|
| 类型 | string |
| 必填 | 是 |
飞书开放平台 App ID(cli_...)。
feishu_app_secret(必填)
| 字段 | 值 |
|---|---|
| 类型 | string |
| 必填 | 是 |
飞书开放平台 App Secret。请安全保管此值。
feishu_base_url
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "https://open.feishu.cn" |
飞书 API base URL。Lark(国际版)用户使用 "https://open.larksuite.com"。
运行时目录
alice_home
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "<ALICE_HOME>/bots/<bot_id>" |
Bot 专有的运行时根目录。所有按 bot 的状态都位于此路径下。
workspace_dir
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "<alice_home>/workspace" |
Agent 工作空间目录。这是 LLM 子进程的工作目录。
prompt_dir
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "<alice_home>/prompts" |
Bot 专有 prompt 模板覆盖目录。此处的文件会覆盖内嵌模板。
codex_home
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "$CODEX_HOME" 或 "~/.codex" |
Codex 配置和认证目录。默认在 bot 间共享,除非在此覆盖。
soul_path
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "SOUL.md"(相对于 alice_home) |
SOUL.md 人格文档路径。相对路径相对于 alice_home 解析。如果启动时文件不存在,Alice 会写入内嵌模板。
消息触发(旧版)
trigger_mode
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "at" |
| 可选值 | "at"、"prefix"、"all" |
旧版触发模式。仅在 group_scenes.chat.enabled 和 group_scenes.work.enabled 均为 false 时使用。
| 值 | 行为 |
|---|---|
"at" | 仅接受 @bot 消息 |
"prefix" | 仅接受以 trigger_prefix 开头的消息 |
"all" | 接受所有消息 |
trigger_prefix
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "" |
trigger_mode: "prefix" 时的前缀字符串。
llm_profiles
Profile 名称到 LLM profile 配置的映射。每个 profile 选择一个 provider、模型和设置。
Profile 字段
provider(必填)
| 字段 | 值 |
|---|---|
| 类型 | string |
| 可选值 | "opencode"、"codex"、"claude"、"gemini"、"kimi" |
LLM 后端 provider。
command
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | 与 provider 相同(如 "opencode") |
CLI 二进制路径或名称。对不在 $PATH 中的二进制使用绝对路径。
timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 172800(48 小时) |
每次运行的超时时间(秒)。
model(必填)
| 字段 | 值 |
|---|---|
| 类型 | string |
模型标识符。示例:"deepseek/deepseek-v4-pro"、"gpt-5.4-mini"、"claude-sonnet-4-6"。
variant(仅 OpenCode)
| 字段 | 值 |
|---|---|
| 类型 | string |
| 可选值 | "max"、"high"、"minimal" |
OpenCode 的 DeepSeek 模型变体。
profile(仅 Codex)
| 字段 | 值 |
|---|---|
| 类型 | string |
Codex CLI 配置中的命名子 profile。
reasoning_effort(仅 Codex)
| 字段 | 值 |
|---|---|
| 类型 | string |
| 可选值 | "low"、"medium"、"high"、"xhigh" |
推理强度级别。
personality(仅 Codex)
| 字段 | 值 |
|---|---|
| 类型 | string |
Codex CLI 配置中的命名人格预设。
prompt_prefix
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "" |
每次 prompt 发送给模型前添加的文本。
permissions
| 字段 | 值 |
|---|---|
| 类型 | object |
沙箱和批准设置。
permissions.sandbox
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "workspace-write" |
| 可选值 | "read-only"、"workspace-write"、"danger-full-access" |
LLM agent 的文件系统访问级别。
permissions.ask_for_approval
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "never" |
| 可选值 | "untrusted"、"on-request"、"never" |
agent 执行工具调用前何时需要请求批准。
permissions.add_dirs
| 字段 | 值 |
|---|---|
| 类型 | string[] |
| 默认值 | [] |
agent 在工作空间之外可访问的额外目录。
profile_overrides
| 字段 | 值 |
|---|---|
| 类型 | map[string]ProfileRunnerConfig |
| 默认值 | {} |
高级:按 profile 的 runner 覆盖。key 为 profile 名称。每个覆盖可设置:
command— 二进制路径覆盖timeout— 超时覆盖(秒)provider_profile— provider 专属的 profile 名称exec_policy— 按覆盖的沙箱和批准设置
env
| 字段 | 值 |
|---|---|
| 类型 | map[string]string |
| 默认值 | {} |
传递给所有 LLM 子进程的环境变量。适用于 PATH、代理设置(HTTPS_PROXY、ALL_PROXY)和 API key。
回复消息
failure_message
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "暂时不可用,请稍后重试。" |
LLM 后端失败时显示的消息。
thinking_message
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "正在思考中..." |
LLM 处理期间在进度卡片中显示的消息。
即时反馈
immediate_feedback_mode
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "reaction" |
| 可选值 | "reaction"、"reply" |
Alice 在 LLM 响应之前确认收到消息的方式。
immediate_feedback_reaction
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "OK" |
Reaction 反馈的飞书表情名称(如 "OK"、"WINK"、"THUMBSUP")。
group_scenes
group_scenes.chat
| 字段 | 值 |
|---|---|
| 类型 | object |
群聊 / 话题群的 chat 场景配置。
enabled
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | true |
session_scope
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "per_chat" |
| 可选值 | "per_chat"、"per_thread" |
llm_profile
| 字段 | 值 |
|---|---|
| 类型 | string |
使用的 llm_profiles 下的 LLM profile 名称。
no_reply_token
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "" |
模型返回此精确字符串时,Alice 保持静默。
create_feishu_thread
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | false |
是否为回复创建飞书话题。
group_scenes.work
| 字段 | 值 |
|---|---|
| 类型 | object |
群聊 / 话题群的 work 场景配置。
enabled
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | true |
trigger_tag
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "#work" |
消息中(在 @bot 提及后)触发 work 模式所需的标签。
session_scope
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "per_thread" |
| 可选值 | "per_thread"、"per_chat" |
llm_profile
| 字段 | 值 |
|---|---|
| 类型 | string |
create_feishu_thread
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | true |
no_reply_token
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "" |
private_scenes
与 group_scenes 结构相同。chat 和 work 子部分默认均禁用。
private_scenes.chat
额外 session 作用域:"per_user" — 同一用户的所有 DM 消息共用一个 session。
private_scenes.work
额外 session 作用域:"per_message" — 每条带 #work 的 DM 创建全新 session。
Runtime HTTP API
runtime_http_addr
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | "127.0.0.1:7331" |
Runtime HTTP API 的监听地址。多 bot 设置会自动递增端口(7332、7333……)。
runtime_http_token
| 字段 | 值 |
|---|---|
| 类型 | string |
| 默认值 | 自动生成 |
API 认证的 Bearer token。为空则自动生成。显式设置用于跨进程调用。
permissions
runtime_message
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | true |
允许 bundled skill 通过 runtime API 发送消息。
runtime_automation
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | true |
允许 bundled skill 通过 runtime API 管理自动化任务。
allowed_skills
| 字段 | 值 |
|---|---|
| 类型 | string[] |
| 默认值 | ["alice-message", "alice-scheduler"] |
此 bot 启用的 bundled skill。内置 skill:alice-message、alice-scheduler、alice-goal。
Worker 池
queue_capacity
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 256 |
最大待处理 job 数。超过后新消息被丢弃。
worker_concurrency
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 3 |
处理 job 的并发 worker 数量。
超时
所有值单位为秒。
automation_task_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 6000 |
定时自动化和工作流运行的外部超时。
auth_status_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 15 |
启动时 provider 认证状态检查的超时。
runtime_api_shutdown_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 5 |
关闭 Runtime HTTP API 服务器时的宽限期。
local_runtime_store_open_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 10 |
启动时打开本地 BoltDB Runtime Store 的超时。
codex_idle_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 900 |
Codex 默认/中等推理强度的空闲超时。
codex_high_idle_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 1800 |
Codex 高推理强度的空闲超时。
codex_xhigh_idle_timeout_secs
| 字段 | 值 |
|---|---|
| 类型 | int |
| 默认值 | 3600 |
Codex 极高推理强度的空闲超时。
显示选项
show_shell_commands
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | true |
是否在心跳状态卡片中显示最近执行的 shell 命令。
disable_identity_hints
| 字段 | 值 |
|---|---|
| 类型 | bool |
| 默认值 | false |
为 true 时,消息以原始文本发送给 LLM,不带身份上下文(Name说:、@mention 规则)。为 false(默认)时,包含身份提示。
Runtime HTTP API
Alice 在 127.0.0.1 上暴露一个本地认证的 HTTP API。Bundled skill、自动化脚本和薄运行时工具使用此 API。
认证
所有端点(/healthz 除外)都需要 Bearer token:
Authorization: Bearer <token>
Token 来自配置中的 bots.<id>.runtime_http_token,如果为空则自动生成。
Base URL
默认:http://127.0.0.1:7331。多 bot 设置会自动递增:7332、7333……。
限制
- 请求体:最多 1 MB
- 认证速率限制:每分钟 120 个请求
- 列表端点:每次请求最多 200 条
健康检查
GET /healthz
无需认证。
响应 200 OK:
{"status": "ok"}
消息
POST /api/v1/messages/image
向当前对话发送图片。
请求 multipart/form-data:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
image | file | 是 | 要上传的图片文件 |
caption | string | 否 | 可选的说明文字 |
响应 200 OK:
{"message_id": "om_xxxxxxxxxxxxx"}
错误:
| 状态码 | 说明 |
|---|---|
400 | 图片文件无效或缺失 |
403 | permissions.runtime_message 已禁用 |
413 | 请求体超过 1 MB |
POST /api/v1/messages/file
向当前对话发送文件。
请求 multipart/form-data:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file | file | 是 | 要上传的文件 |
filename | string | 否 | 显示文件名(默认:原始文件名) |
caption | string | 否 | 可选的说明文字 |
响应 200 OK:
{"message_id": "om_xxxxxxxxxxxxx"}
错误:
| 状态码 | 说明 |
|---|---|
400 | 文件无效或缺失 |
403 | permissions.runtime_message 已禁用 |
413 | 请求体超过 1 MB |
自动化任务
GET /api/v1/automation/tasks
列出自动化任务。
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
limit | int | 50 | 每页条数(最大 200) |
offset | int | 0 | 分页偏移 |
status | string | — | 按状态筛选:active、completed、cancelled |
响应 200 OK:
[
{
"id": "task_abc123",
"scope_type": "chat",
"scope_id": "oc_xxxxxxxxxxxxx",
"action": "send_text",
"status": "active",
"cron": "0 9 * * *",
"created_at": "2025-01-15T09:00:00Z",
"updated_at": "2025-01-15T09:00:00Z"
}
]
POST /api/v1/automation/tasks
创建自动化任务。
请求 application/json:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
scope_type | string | 是 | "chat" 或 "user" |
scope_id | string | 是 | 目标 ID(chat_id 或 user_id) |
action | string | 是 | "send_text"、"run_llm" 或 "run_workflow" |
text | string | send_text 时 | 消息文本 |
prompt | string | run_llm 时 | LLM prompt |
cron | string | 否 | 重复任务的 cron 表达式 |
run_at | string | 否 | 一次性任务的 ISO 8601 时间戳 |
响应 201 Created:
{
"id": "task_abc123",
"scope_type": "chat",
"scope_id": "oc_xxxxxxxxxxxxx",
"action": "send_text",
"status": "active",
"cron": "0 9 * * *",
"created_at": "2025-01-15T09:00:00Z"
}
错误:
| 状态码 | 说明 |
|---|---|
400 | 请求体无效或缺少必填字段 |
403 | permissions.runtime_automation 已禁用 |
GET /api/v1/automation/tasks/:taskID
获取单个自动化任务。
响应 200 OK:与列表项相同的结构。
错误:
| 状态码 | 说明 |
|---|---|
404 | 任务未找到 |
PATCH /api/v1/automation/tasks/:taskID
更新自动化任务。发送 JSON merge-patch,包含要更新的字段。
请求 application/json:
{"status": "cancelled"}
可更新字段:status、cron、run_at、text、prompt。
响应 200 OK:更新后的任务对象。
错误:
| 状态码 | 说明 |
|---|---|
400 | 无效更新 |
403 | permissions.runtime_automation 已禁用 |
404 | 任务未找到 |
DELETE /api/v1/automation/tasks/:taskID
删除自动化任务。
响应 204 No Content
错误:
| 状态码 | 说明 |
|---|---|
403 | permissions.runtime_automation 已禁用 |
404 | 任务未找到 |
Goal
GET /api/v1/goal
获取对话作用域的当前活跃 goal。
响应 200 OK:
{
"id": "goal_xyz",
"description": "Review PR #42",
"status": "in_progress",
"created_at": "2025-01-15T10:00:00Z"
}
响应 204 No Content:无活跃 goal。
POST /api/v1/goal
为对话作用域创建新 goal。
请求 application/json:
{"description": "Review PR #42"}
响应 201 Created:创建的 goal 对象。
POST /api/v1/goal/pause
暂停活跃 goal。
响应 200 OK。
POST /api/v1/goal/resume
恢复已暂停的 goal。
响应 200 OK。
POST /api/v1/goal/complete
将活跃 goal 标记为完成。
响应 200 OK。
DELETE /api/v1/goal
删除活跃 goal。
响应 204 No Content。
通用错误响应格式
所有错误遵循此格式:
{
"error": "Human-readable error description"
}
HTTP 状态码按惯例使用:400 表示客户端错误,403 表示权限不足,404 表示未找到,413 表示载荷过大,429 表示速率限制,500 表示内部错误。
CLI 命令
Alice 提供多个 CLI 子命令用于不同操作。
主进程
alice --feishu-websocket
启动完整的飞书连接器运行时。连接飞书 WebSocket 并处理实时消息。
alice --feishu-websocket
alice --runtime-only
以 runtime-only 模式启动。本地 HTTP API 和自动化引擎运行,但飞书 WebSocket 不启动。
alice --runtime-only
alice-headless --runtime-only
无头 runtime-only 二进制。明确不能启动飞书连接器。
alice-headless --runtime-only
alice-headless如果以--feishu-websocket调用会报错。
全局参数
| 参数 | 说明 |
|---|---|
--alice-home <path> | 覆盖默认的运行时 home 目录 |
--config <path> | config.yaml 路径(默认:<alice_home>/config.yaml) |
--log-level <level> | 覆盖日志级别(debug、info、warn、error) |
--version | 输出版本并退出 |
环境变量 ALICE_HOME 也会覆盖默认 home 目录。
alice setup
初始化 Alice 运行时环境。
alice setup
执行内容:
- 在
~/.alice/下创建目录结构 - 写入初始
config.yaml(基于config.example.yaml) - 将内置 bundled skill 同步到
${ALICE_HOME}/skills/ - Linux 上:在
~/.config/systemd/user/alice.service注册 systemd 用户单元 - 在
~/.config/opencode/plugins/alice-delegate.js安装 OpenCode delegate 插件
安装后运行一次即可。
alice delegate
向配置好的 LLM 后端发送一次性 prompt。
alice delegate --provider <name> --prompt "<text>"
选项
| 参数 | 说明 |
|---|---|
--provider <name> | 后端:opencode、codex、claude、gemini、kimi |
--prompt <text> | Prompt 文本(必填) |
--model <name> | 覆盖默认模型 |
--workspace <path> | 覆盖工作目录 |
示例
alice delegate --provider codex --prompt "Fix the null check in auth.go"
alice delegate --provider claude --prompt "Review this diff" < changes.patch
alice runtime message
通过 runtime API 发送消息。
alice runtime message image <path> [--caption <text>]
alice runtime message file <path> [--filename <name>] [--caption <text>]
| 子命令 | 说明 |
|---|---|
image <path> | 上传并发送图片 |
file <path> | 上传并发送文件 |
| 参数 | 说明 |
|---|---|
--caption <text> | 可选的说明文字 |
--filename <name> | 覆盖文件显示名称(仅 file) |
alice runtime automation
通过 runtime API 管理自动化任务。
alice runtime automation list [--status <status>] [--limit <n>]
alice runtime automation create <payload>
alice runtime automation get <task-id>
alice runtime automation update <task-id> <payload>
alice runtime automation delete <task-id>
| 子命令 | 说明 |
|---|---|
list | 列出自动化任务 |
create <json> | 从 JSON payload 创建任务 |
get <id> | 获取单个任务 |
update <id> <json> | 通过 JSON merge-patch 更新任务 |
delete <id> | 删除任务 |
| 参数(list) | 说明 |
|---|---|
--status | 按状态筛选:active、completed、cancelled |
--limit | 每页条数 |
alice runtime goal
管理对话作用域的活跃 goal。
alice runtime goal get
alice runtime goal create <description>
alice runtime goal pause
alice runtime goal resume
alice runtime goal complete
alice runtime goal delete
| 子命令 | 说明 |
|---|---|
get | 获取当前活跃 goal |
create <desc> | 创建新 goal |
pause | 暂停活跃 goal |
resume | 恢复已暂停的 goal |
complete | 将活跃 goal 标记为完成 |
delete | 删除活跃 goal |
alice skills
管理 bundled skill。
alice skills sync
alice skills list
| 子命令 | 说明 |
|---|---|
sync | 将内嵌 bundled skill 同步到本地 skill 目录 |
list | 列出已安装的 bundled skill |
alice skills sync 在启动时也会自动运行。
退出码
| 码 | 含义 |
|---|---|
0 | 成功 |
1 | 一般错误 |
2 | 配置错误 |
3 | 认证错误 |
架构概览
这是面向代码的 Alice 架构参考。包名、运行时对象和文件路径与 cmd/connector、internal/、prompts/ 和 skills/ 下的实际代码一致。
阅读路径
根据你的目标从对应部分开始:
| 目标 | 入口 |
|---|---|
| 理解整个系统 | §1 进程模型 → §2 引导路径 → §5 消息流水线 |
| 新增 LLM 后端 | §2 引导路径 → §7 Prompt 拼装 → 新增 LLM Backend |
| 修改消息处理 | §5 收信消息流水线 → §6 Session Key → §8 回复分发 |
| 新增 Runtime API 端点 | §9 Runtime API |
| 新增或修改自动化 | §10 自动化子系统 |
| 理解配置 | §2 引导路径 → §12 配置模型 |
1. 进程模型
Alice 是一个多 bot 运行时。一个 alice 进程可以通过一份 config.yaml 托管多个 bot。
启动时,进程:
- 加载
config.yaml - 将
bots.*展开为每个 bot 的运行时配置 - 按需验证 CLI 认证
- 将内嵌 bundled skill 同步到本地 skill 目录
- 为每个 bot 构建一个
ConnectorRuntime - 在一个
RuntimeManager下运行所有运行时
每个 bot 的主运行时对象:
ConnectorRuntime
├─ App
├─ Processor
├─ llm.MultiBackend
├─ LarkSender
├─ automation.Engine
├─ runtimeapi.Server
├─ automation.Store
└─ campaign.Store
启动模式是显式的:
--feishu-websocket:连接飞书并处理实时事件--runtime-only:运行自动化和本地 Runtime API,不启动飞书 WebSocketalice-headless:仅 runtime-only;不得启动飞书连接器
2. 引导路径
进程入口点是 cmd/connector。
关键引导步骤:
cmd/connector/root.go:CLI 参数、启动模式选择、配置创建、PID 锁定、日志、认证预检、bundled skill 同步和运行时管理器启动。internal/config:纯多 bot 配置模型、路径派生、标准化、验证和每个 bot 的运行时展开。internal/bootstrap:构建每个 bot 的运行时图并连接横切功能,如 prompt 加载、Runtime API 认证、campaign 调和循环和配置热重载。
BuildRuntimeManager 通过 RuntimeConfigs() 将 Config 展开为 []Config,然后为每个 bot 构建一个 ConnectorRuntime。
当前热重载行为:
- 单 bot 模式:支持部分配置热重载
- 多 bot 模式:热重载被刻意禁用;配置更改后重启进程
3. 运行时布局与持久化状态
每个 bot 拥有自己的运行时根目录:
${ALICE_HOME}/bots/<bot_id>/
重要的每个 bot 路径:
workspace/— Bot 工作空间prompts/— 该 bot 的可选 prompt 覆盖run/connector/automation.db— 持久化自动化任务存储(bbolt)run/connector/campaigns.db— 持久化轻量级 campaign 索引(bbolt)run/connector/session_state.json— Session 别名、provider thread id、用量计数器、work-thread 元数据run/connector/runtime_state.json— 可变连接器运行时状态run/connector/resources/scopes/<scope_type>/<scope_id>/— 下载的附件和可上传的本地产物,作用域限定在当前对话
源码树也内嵌了:
prompts/skills/config.example.yamlprompts/SOUL.md.example
磁盘文件在存在时会覆盖内嵌 prompt 文件;内嵌资产是后备方案。
4. 包映射
核心包
| 包 | 职责 |
|---|---|
cmd/connector | CLI 入口、runtime 子命令和 skills sync |
internal/bootstrap | 运行时构建、路径解析、认证检查、skill 物化、campaign 调和桥接和配置重载 |
internal/config | 配置模式、验证、默认值、路径派生和多 bot 展开 |
internal/connector | 飞书收信、消息标准化、场景路由、排队、session 序列化、原生注入回退、/stop 中断、prompt 拼装、回复分发、附件下载、session 持久化和内置命令 |
internal/llm | 与 provider 无关的 Backend 接口及 codex、claude、gemini、kimi、opencode 的 provider 适配器 |
internal/prompting | 模板加载器(磁盘优先 / 内嵌后备)、sprig 辅助函数和编译模板缓存 |
internal/runtimeapi | 本地认证 HTTP 服务器和客户端,供 bundled skill 和面向运行时的 shell 脚本使用 |
internal/automation | 任务模型、持久化、认领、执行、系统任务调度和工作流分派 |
internal/statusview | 为 /status 聚合用量和自动化数据 |
internal/platform/feishu | 飞书发送器实现、附件 I/O、bot 自我信息查找、消息查找和用户名解析辅助 |
支持包
| 包 | 职责 |
|---|---|
internal/sessionctx | Runtime API 调用和 bundled skill 的 session 上下文环境桥接 |
internal/runtimecfg | 场景派生的 profile 选择和话题回复偏好的辅助 |
internal/sessionkey | 规范 session key 和可见性 key 的辅助 |
internal/messaging | 连接器和 Runtime API 层共享的窄发信/上传接口 |
internal/storeutil | 共享 bbolt 辅助和字符串工具 |
internal/logging | Zerolog 加滚动文件输出配置 |
internal/buildinfo | 版本报告 |
5. 收信消息流水线
internal/connector.App 拥有实时飞书连接和每个 bot 的 job 队列。
高层流程:
- 飞书通过 WebSocket 投递
im.message.receive_v1 App将事件标准化为JobrouteIncomingJob决定消息应被忽略、作为内置命令处理、作为chat处理还是作为work处理- 如果同一 session 有活跃的 provider 原生交互式运行,Alice 首先尝试将新输入注入到该运行中
- 如果原生注入不可用,job 排队并按 session 序列化;较新的排队 job 取代较旧 job,不中断活跃的 LLM 运行
/stop仍会中断活跃运行,用户消息仍可中断获取了 session 锁的自动化任务Processor执行被接受的 job
场景路由规则:
- 群聊/话题群可以使用
group_scenes.chat和group_scenes.work - Work 话题通过触发器加上稳定的 work-scene session key 来标识
- 如果两个场景都被禁用,Alice 回退到旧版
trigger_mode/trigger_prefix - 内置命令如
/help、/status、/clear、/stop绕过 LLM 路径
6. Session Key、别名和序列化
Alice 通过规范 session key 和别名来路由和恢复工作。
常见格式:
{receive_id_type}:{receive_id}{receive_id_type}:{receive_id}|scene:{scene}{receive_id_type}:{receive_id}|scene:{scene}|thread:{thread_id}{receive_id_type}:{receive_id}|scene:{scene}|message:{message_id}
特殊情况:
- Work-scene 种子 key:
{receive_id_type}:{receive_id}|scene:work|seed:{source_message_id} - Chat 重置别名:
{chat_key}|reset:{message_id}
持久化到 session_state.json:
- Provider thread id
- Work-thread id 别名
- Session 别名
- 用量计数器
- 最后消息时间戳
- 状态聚合的作用域 key
internal/connector/runtime_store.go 维护实时的内存协调状态:
- 每个 session 的最新版本
- 每个 session 的待处理 job
- 活跃运行取消句柄
- 每个 session 的序列化互斥锁
- 已取代版本跟踪
7. Prompt 拼装与 LLM 执行
internal/connector.Processor 是每个被接受 job 的执行核心。
在 LLM 调用之前它:
- 如果需要,加载并解析
SOUL.md - 将收到的附件下载到作用域资源目录
- 为当前对话推导运行时环境变量
- 准备 prompt 文本
当前 prompt 资产:
prompts/llm/initial_prompt.md.tmplprompts/connector/bot_soul.md.tmplprompts/connector/current_user_input.md.tmplprompts/connector/reply_context.md.tmplprompts/connector/runtime_skill_hint.md.tmplprompts/connector/synthetic_mention.md.tmpl
重要 prompt 行为:
- 首轮或非恢复运行渲染 current-user-input 模板,并可能附加回复上下文、bot soul 和运行时 skill 提示
- 已恢复的 provider thread 仅发送当前用户输入;Alice 依赖 provider 端 thread/session 持有之前的上下文
chat运行可在 resume 时前置SOUL.md;work运行刻意跳过 bot-soul 注入
LLM 层选择方式:
- 场景选择一个外部
llm_profiles.<name> - 外部 profile 选择 provider / model / profile / reasoning / personality / prompt prefix
llm.MultiBackend分派到正确的 provider 适配器
当前支持的 provider:codex、claude、gemini、kimi、opencode
8. 回复分发
Alice 区分:
- 即时确认
- 来自后端的流式进度消息
- 最终回复
- 文件/图片跟进
当前行为:
- Work-scene 消息通常收到即时 reaction 或
收到! - 后端进度消息在可能时以话题回复方式发送
- 最终回复通过回复分发器发布
- 当飞书不支持对该目标的话题回复时,回退到直接回复
internal/connector/card.go、internal/connector/outgoing_mentions.go、internal/connector/outgoing_plaintext.go 及相关文件拥有:
- 消息发送 / 回复 / 补丁卡片操作
- Reaction
- 图片和文件上传
- 附件下载
- 作用域资源根解析
9. Runtime API 与 Bundled Skill
Alice 暴露一个本地认证的 Runtime API,面向 bundled skill 和薄运行时脚本。
当前 HTTP 接口:
POST /api/v1/messages/imagePOST /api/v1/messages/fileGET|POST|PATCH|DELETE /api/v1/automation/tasksGET|POST /api/v1/goal+ pause/resume/complete/delete
没有独立的纯文本发送端点。纯文本通常通过主回复流水线返回。
当前安全措施:
- Bearer token 认证
- 请求体大小限制(1 MB)
- 进程内认证速率限制(120 req/min)
- 本地上传需要可读、非空的常规文件,且仍受飞书大小限制约束
面向运行时的 shell 入口点:
alice runtime message ...alice runtime automation ...alice runtime goal ...
当前源码树中内置的 bundled skill:
skills/alice-messageskills/alice-schedulerskills/alice-goal
运行时上下文通过环境变量注入(见 Runtime API 设计)。
10. 自动化子系统
internal/automation 将任务持久化在 bbolt 中并在进程内执行。
当前任务作用域:user、chat
当前任务操作:send_text、run_llm、run_workflow
执行模型:
- 到期任务在周期性 tick 中被认领
- 长期系统任务单独调度
- 任务环境继承与交互式运行相同的对话上下文桥接
- Workflow 任务调用相同的 LLM 后端,但使用 workflow 专属的 agent name、环境变量和工作空间提示
引导期间注册的内建系统任务:
- 周期性 session/runtime 状态刷新
- 周期性 campaign-repo 调和
11. 配置模型
配置模型是纯多 bot 的。
重要 key:
bots.<id>llm_profilesgroup_scenes.chat、group_scenes.workprivate_scenes.chat、private_scenes.workpermissionsruntime_http_addrworkspace_dir、prompt_dir、codex_home
值得注意的行为:
RuntimeConfigs()为 bot 派生缺失路径,并跨 bot 递增默认 Runtime API 端口- 每个外部
llm_profileskey 是一个稳定的运行时选择器 - Provider 专属的 profile 选择器仍通过内部
profile字段存在于每个 profile 内部 - 运行时权限独立控制 bundled skill 和 Runtime API 接口
12. 可观测性与调试
当前可观测性接口:
- 通过
zerolog的结构化日志 - 通过
lumberjack的滚动日志文件 - 存储在
session_state.json中的 session 用量计数器 - 由
statusview驱动的/status log_level=debug时每次运行的 markdown debug 跟踪
Debug 跟踪在后端暴露时包括:
- Provider、agent name、thread/session id、model/profile
- 渲染后的输入、观察到的工具活动、最终输出或错误
13. 扩展边界
支持的扩展面:
llmprovider 适配器prompts/下的 prompt 模板skills/下的 bundled skill- Runtime API handlers
贡献指南
欢迎贡献。本指南涵盖所有贡献者(人类和 AI)的工作流、标准和评审要求。
English version see below.
1. 分支与变更范围
- 日常开发基于最新
dev分支,提交 PR 到dev。 main只接受dev -> main的合并提交。- 分支命名:
feat/*、fix/*、docs/*、chore/*。 - 每次提交只做一件事,避免无关改动混在一起。
2. 提交信息规范
强制使用 Conventional Commits,由 commit-msg hook 校验:
type(scope): subject
type: subject
允许的 type:feat、fix、docs、style、refactor、perf、test、build、ci、chore、revert。
示例:
feat(connector): support codex resume threadfix: keep proxy env for codex execdocs: add configuration reference
3. 提交前必须检查
首次执行:
make precommit-install
每次提交前必须通过:
make check
make check 按顺序运行:
| 门禁 | 命令 |
|---|---|
| 密钥扫描 | secret-check |
| Shell 语法 | script-check |
| 格式检查 | fmt-check(gofmt) |
| Vet | go vet ./... |
| 单元测试 | go test ./... |
| Race 测试 | go test -race ./internal/connector |
未通过 make check 不得提交。
对于涉及横切或并发相关的改动,还需运行:
go test -race ./...
格式不通过时先执行 make fmt。
4. 代码规则
- 统一使用
gofmt格式化代码。 - 单文件超过 500 行必须拆分(防止巨型文件增长)。
- 新增或修改行为必须补充/更新测试。
- 不要在日志中输出敏感信息(app secret、token、用户内容)。
- CLI 参数变更允许破坏性调整,但必须明确文档说明并提供迁移指南。
5. 配置变更规则
- 本项目使用 YAML 配置文件(
${ALICE_HOME}/config.yaml),不用环境变量作主配置入口。 - 新增配置项必须同步更新:
config.example.yamlinternal/config(默认值和验证)- 文档(英文 README 和文档站点)
- 影响 session/记忆行为的配置项(如
idle_summary_hours)需补充对应测试。
6. 文档同步规则
任何用户可见变更(命令、参数、配置、行为)必须同步更新:
README.mdREADME.zh-CN.mdbook/src/(文档站点)
保持中英文文档一致。
7. 合并前自检清单
-
本地
make check通过 -
至少验证一次关键路径启动:
go run ./cmd/connector --feishu-websocket - 文档已同步更新
- 不包含无关文件或调试内容
8. 运行时隔离规则
调试或测试隔离 runtime 时:
- 使用显式启动模式:
--feishu-websocket或--runtime-only alice-headless必须使用--runtime-only- 不允许隔离调试 runtime 连接真实飞书 WebSocket
- 启动后验证日志显示
runtime-only mode enabled; Feishu websocket connector disabled - 如果隔离 runtime 日志显示
feishu-codex connector started,立即停止
Contributing (English)
1. Branch and Change Scope
- Base daily work on latest
dev. Submit PRs todev. mainonly accepts merge commits fromdev.- Branch naming:
feat/*,fix/*,docs/*,chore/*. - One commit, one goal. Don't mix unrelated changes in one commit.
2. Commit Message Format
Conventional Commits are enforced by a commit-msg hook:
type(scope): subject
type: subject
Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert.
Examples:
feat(connector): support codex resume threadfix: keep proxy env for codex exec
3. Pre-Commit Checks
First-time setup:
make precommit-install
Every commit must pass:
make check
make check runs in order: secret-check → script-check → fmt-check → go vet → go test → go test -race
Do not commit until make check passes with zero failures.
For cross-cutting or concurrency changes, also run:
go test -race ./...
If formatting fails, run make fmt first.
4. Code Rules
- Use
gofmtfor all Go code. - Files over 500 lines must be split in the same change (prevent mega-files).
- New or changed behavior must include/update tests.
- Never log sensitive information.
- CLI flag changes may be breaking but must be clearly documented with migration instructions.
5. Configuration Change Rules
- YAML config is the primary configuration method, not environment variables.
- New config keys require updates to:
config.example.yaml,internal/config, docs. - Session-related config keys must have corresponding tests.
6. Documentation Sync
Any user-visible change must sync docs, keeping Chinese and English versions consistent.
7. Merge Checklist
-
Local
make checkpasses -
At least one startup test:
go run ./cmd/connector --feishu-websocket - Documentation synced
- No unrelated files or debug content included
8. Runtime Isolation Rules
When debugging or testing with isolated runtimes:
- Use explicit startup mode
alice-headlessmust use--runtime-onlyonly- Never connect isolated debug runtimes to the real Feishu WebSocket
- After startup, verify logs show
runtime-only mode enabled; Feishu websocket connector disabled
新增 LLM Backend
本指南将带你了解如何为 Alice 新增一个 LLM provider CLI 的支持。请遵循现有后端(codex、claude、gemini、kimi、opencode)所使用的模式。
前提条件
- Provider 必须有一个 CLI 工具,Alice 可以作为子进程运行
- CLI 必须能通过 stdin 或 CLI 参数接受 prompt
- CLI 必须将结果输出到 stdout
第 1 步:理解 Backend 接口
核心接口在 internal/llm/backend.go 中:
type Backend interface {
Run(ctx context.Context, req RunRequest) (RunResult, error)
}
type RunRequest struct {
ThreadID string
UserText string
Model string
// ... 其他字段
OnProgress ProgressFunc
OnRawEvent RawEventFunc
}
type RunResult struct {
Reply string
NextThreadID string
GoalDone bool
Usage Usage
}
你的后端必须:
- 从
RunRequest构建正确的 CLI 命令 - 将其作为子进程执行
- 将 stdout/stderr 解析为
RunResult - 通过
OnProgress流式传输中间进度 - 通过
ctx.Done()处理取消
第 2 步:创建 Backend 文件
创建 internal/llm/<provider>_backend.go。遵循 codex_backend.go 中的模式:
package llm
import (
"context"
"os/exec"
)
type myProviderBackend struct {
config MyProviderConfig
}
func newMyProviderBackend(cfg MyProviderConfig) *myProviderBackend {
return &myProviderBackend{config: cfg}
}
func (b *myProviderBackend) Run(ctx context.Context, req RunRequest) (RunResult, error) {
// 1. 构建命令
args := []string{"run", "--model", req.Model}
if req.ThreadID != "" {
args = append(args, "--continue", req.ThreadID)
}
cmd := exec.CommandContext(ctx, b.config.Command, args...)
cmd.Dir = req.WorkspaceDir
cmd.Env = mergeEnv(b.config.Env)
// 2. 将用户文本通过管道传入 stdin
stdin, _ := cmd.StdinPipe()
go func() {
defer stdin.Close()
io.WriteString(stdin, req.UserText)
}()
// 3. 流式读取和解析输出
stdout, _ := cmd.StdoutPipe()
// ... 从 stdout 解析 JSON-lines ...
// ... 为中间消息调用 req.OnProgress ...
// 4. 运行
err := cmd.Run()
// 5. 返回结果
return RunResult{
Reply: finalReply,
NextThreadID: nextThreadID,
Usage: usage,
}, err
}
第 3 步:添加配置
在 internal/llm/factory.go 中添加配置结构体和 provider 常量:
const ProviderMyProvider = "myprovider"
type MyProviderConfig struct {
Command string
Timeout time.Duration
Model string
Env map[string]string
WorkspaceDir string
ProfileOverrides map[string]ProfileRunnerConfig
}
第 4 步:在 Factory 中注册
在 factory.go 的 NewProvider 中添加你的 provider:
func NewProvider(cfg FactoryConfig) (Provider, error) {
provider := normalizeProvider(cfg.Provider)
switch provider {
case ProviderCodex:
return providerBundle{backend: newCodexBackend(cfg.Codex)}, nil
case ProviderClaude:
return providerBundle{backend: newClaudeBackend(cfg.Claude)}, nil
case ProviderMyProvider: // NEW
return providerBundle{backend: newMyProviderBackend(cfg.MyProvider)}, nil // NEW
default:
return nil, fmt.Errorf("unsupported llm_provider %q", provider)
}
}
同时将字段添加到 FactoryConfig:
type FactoryConfig struct {
Provider string
Codex CodexConfig
Claude ClaudeConfig
Gemini GeminiConfig
Kimi KimiConfig
OpenCode OpenCodeConfig
MyProvider MyProviderConfig // NEW
}
第 5 步:从 config.yaml 接入配置
在 internal/config 中,扩展 LLM profile 以接受新 provider。Profile 配置应映射到你的 MyProviderConfig 字段(Command、Timeout、Model、Env 等)。
第 6 步:添加示例配置
在 config.example.yaml 中添加 profile 示例:
# 示例:MyProvider profile。
# chat_myprovider:
# provider: "myprovider"
# command: "myprovider"
# model: "myprovider-model-v1"
# permissions:
# sandbox: "workspace-write"
# ask_for_approval: "never"
第 7 步:编写测试
创建 internal/llm/<provider>_backend_test.go。至少测试:
- 使用不同请求字段构建命令
- 超时处理
- 进度回调递送
- 通过 context 取消
- 无效输出的错误处理
参考 codex_backend_test.go 或 opencode_appserver_driver_test.go 中的现有测试模式。
第 8 步:交互式 Session 支持(可选)
部分后端支持长时间运行的交互式 session,可以在不重启子进程的情况下注入新输入。如果你的 provider 支持此功能:
- 实现
InteractiveProviderSession模式(参见claude_stream_driver.go或opencode_appserver_driver.go) - 将交互模式接入主
Run方法 - 添加
DisableStream*逃生舱用于回退
实现清单
-
internal/llm/<provider>_backend.go— 后端实现 -
internal/llm/factory.go— provider 常量 + 配置结构体 + switch case -
internal/config— LLM profile 配置接入 -
config.example.yaml— 示例 profile -
internal/llm/<provider>_backend_test.go— 测试 -
book/src/reference/configuration.md— 更新 provider 列表 -
book/src/how-to/configure-backend.md— 添加 provider 示例
参考实现
研究以下现有后端以了解模式:
| Backend | 文件 | 备注 |
|---|---|---|
| Codex | codex_backend.go | 完整实现,包含 reasoning、personality、idle timeout |
| Claude | claude_stream_driver.go | 流式交互 session |
| OpenCode | opencode_appserver_driver.go | Appserver 模式与持久化服务器 |
| Kimi | kimi_wire_driver.go | 线协议驱动 |
发版流程
Alice 版本的构建和发布方式。
分支策略
- 日常开发在
dev分支进行 - 发版仅通过
dev → main合并提交进行 - 绝不直接推送到
main
CI 流水线
dev Push 时
- 运行质量门禁(
make check) - 构建 dev 二进制
- 更新预发布
dev-latest
dev 合并到 main 时
- 运行质量门禁(
make check) - 自动创建下一个
vX.Y.Ztag - 构建所有平台的 release 二进制
- 发布 GitHub Release
手动 v* Tag
- 推送
v*tag 会直接触发 release workflow
Release 产出物
每个 Release 发布:
- 平台二进制构建:linux-amd64、linux-arm64、darwin-amd64、darwin-arm64、win32-x64
- npm 包:
@alice_space/alice - 安装脚本:
scripts/alice-installer.sh
执行发版
- 确保
dev通过所有检查且准备就绪 - 创建从
dev到main的 PR - 使用 merge commit 合并(不要 squash 或 rebase)
- CI 自动创建 tag 并发布 Release
- 验证 GitHub Release 显示所有产出物
版本号
Tag 遵循 semver:vX.Y.Z。CI 从上一个 release tag 自动递增补丁版本号。
发版后
- 安装脚本(
alice-installer.sh)自动获取最新 release - npm 用户通过
npm update -g @alice_space/alice获取更新
CI Workflow 文件
.github/workflows/ci.yml— Dev 分支质量门禁和 dev 二进制.github/workflows/main-release.yml— Main 分支 release 构建.github/workflows/release-on-tag.yml— 手动 tag release