LobeHub CLI 会话管理实战:lh topic 与 lh message 全命令详解
本文基于 LobeHub 仓库中 CLI 技能的会话管理参考文档 conversation.md 展开,系统讲解 LobeHub CLI(@lobehub/cli,命令别名 lh/lobe/lobehub)中 lh topic 与 lh message 两组会话管理命令的完整用法、参数默认值与输出格式。读完本文,你可以直接在终端或 Agent 工作流中管理对话主题(Topic)与消息(Message):列表、搜索、创建、编辑、批量删除、统计、字数统计与活跃度热力图,并理解这些命令背后的 tRPC 调用链与服务端路由实现。
1. 命令定位与源码位置
LobeHub CLI 是基于 Commander.js + TypeScript 构建的命令行工具,位于 apps/cli/ 目录,入口为 apps/cli/src/index.ts,详细开发指南见 SKILL.md。会话管理由两个命令组承担,源码各占一个文件:
| 命令组 | 源码文件 | 职责 |
|---|---|---|
lh topic |
topic.ts | 管理对话主题(threads),即会话容器 |
lh message |
message.ts | 管理主题内的聊天消息 |
两个命令组的所有操作都通过 getTrpcClient() 获取类型安全的 tRPC 客户端,再调用后端的 topic.* / message.* 过程。服务端对应实现分别在 topic.ts 与 message.ts 两个 tRPC 路由中。
从源码结构看,lh topic 组还挂载了一个子命令文件 view.ts(topic view 转录查看),下文会一并覆盖。
2. 主题管理(lh topic)
2.1 列表:lh topic list
lh topic list [--agent-id <id>] [-L <n>] [--page <n>] [--json [fields]]
| 选项 | 说明 | 默认值 |
|---|---|---|
--agent-id <id> |
按 Agent ID 过滤 | - |
-L, --limit <n> |
每页大小 | 30 |
-P, --page <n> |
页码(从 1 开始) | 1 |
--json [fields] |
输出 JSON,可选逗号分隔字段过滤 | - |
表格模式下输出 ID / TITLE / FAV / UPDATED 四列,收藏主题在 FAV 列显示 ★,UPDATED 列用相对时间(timeAgo)展示。
从 topic.ts 的实现可以看到分页参数的换算逻辑:CLI 的 --limit 映射为 tRPC 的 pageSize,而 --page 会减一后作为 current 传给 topic.getTopics(即第 1 页对应 current: 0)。因此 lh topic list --agent-id <id> -L 10 --page 2 --json id,title 即可拿到某 Agent 主题的第二页、仅保留 id 与 title 字段的 JSON,便于管道处理。
2.2 搜索:lh topic search
lh topic search <keywords> [--agent-id <id>] [--json [fields]]
全量按关键词搜索主题,表格输出 ID / TITLE 两列。底层调用 topic.searchTopics;在服务端 topic.ts 中,topicSearchProcedure 专门注入了 createFtsSearchRepo(usage 为 topic_search)来构建带全文检索能力的 TopicModel——也就是说该命令走的是数据库 FTS 全文搜索通道,而非普通 LIKE 匹配。
2.3 创建:lh topic create
lh topic create -t <title> [--agent-id <id>] [--favorite]
| 选项 | 说明 | 必填 |
|---|---|---|
-t, --title <title> |
主题标题 | 是 |
--agent-id <id> |
关联的 Agent ID | 否 |
--favorite |
创建时即标记为收藏 | 否 |
成功后调用 topic.createTopic 并打印新建主题 ID:✓ Created topic <id>。
2.4 编辑:lh topic edit
lh topic edit <id> [-t <title>] [--favorite] [--no-favorite]
-t, --title <title>:修改标题;--favorite/--no-favorite:收藏 / 取消收藏(Commander 的--no-*约定,两者会写入favorite: true/false)。
源码中的关键行为:若未指定任何变更(--title、--favorite 都缺省),命令会以 No changes specified. 报错退出(exit code 1),不会发起空更新请求。
2.5 删除:lh topic delete
lh topic delete <id1> [id2...] [--yes]
- 支持一次传入多个 ID 批量删除;
- 加
--yes跳过交互式确认,适合脚本与 Agent 自动化场景; - 未加
--yes时会弹出Are you sure you want to delete N topic(s)?确认提示,取消则打印Cancelled.。
从 topic.ts 的实现看,实际源码比参考文档更进一步:
- 支持
--file <path>从文件读取 ID:文件内容可以是一行一个 ID 的纯文本,也可以是 JSON 数组;与命令行位置参数合并后自动去重; - 单条与批量走不同端点:只有 1 个 ID 时调用
topic.removeTopic,多个 ID 时调用topic.batchDelete,与后端批量语义对齐。
2.6 最近主题:lh topic recent
lh topic recent [-L <n>] [--json [fields]]
| 选项 | 说明 | 默认值 |
|---|---|---|
-L, --limit <n> |
条数 | 10 |
调用 topic.recentTopics,表格输出 ID / TITLE / UPDATED。
2.7 转录查看:lh topic view
参考文档未列出该子命令,但 view.ts 是 lh topic 组的核心读操作,用于查看主题详情及其消息转录:
lh topic view <id> [-L <n>] [--from <n>] [--to <n>] [--no-messages] [--json]
-L, --limit <n>:本页消息数,默认50,上限500(源码常量MAX_LIMIT = 500,超限直接报错);--from <n>/--to <n>:基于 1 的消息下标区间,二者不能与--limit同时使用,且--to必须不小于--from;--no-messages:只输出主题元数据(标题、收藏、更新时间、状态、模型与 Provider);--json:输出{ topic, messages, pagination }完整结构。
该子命令的工程细节值得注意:终端渲染前会对消息内容做规范化——剥离终端控制字符、删除孤立代理项(保留 emoji)、把 base64 data URL 脱敏为 [base64 data omitted],单条消息内容超过 20000 字符或工具参数超过 8000 字符时自动截断并提示 use --json for full output;工具调用会以 ⚙ identifier.apiName 加缩进参数的方式渲染。看完当前页后,末尾会打印 Next: --from <n> -L <n> 提示下一页参数,方便人工分页。
2.8 克隆与分享:clone / share / unshare / share-info / import
同样源自 topic.ts,这些命令把主题做成了可复制、可分享的资源:
# 克隆主题(可重命名)
lh topic clone <id> [-t <new-title>]
# 开启分享(默认 link 可见性,也支持 private)
lh topic share <id> [--visibility link|private]
# 关闭分享
lh topic unshare <id>
# 查看分享信息(Topic ID / Share ID / Visibility / Created)
lh topic share-info <id> [--json]
# 导入主题:--agent-id 与 --data 均为必填
lh topic import --agent-id <id> --data '<json>' [--group-id <id>] [--json]
share 成功后会打印 Share ID(调用 topic.enableSharing 返回);share-info 未开启分享时提示 Sharing not enabled for this topic.;import 通过 topic.importTopic 把 JSON 主题数据落到指定 Agent 下,可选挂到某个群(--group-id)。
3. 消息管理(lh message)
3.1 列表:lh message list
lh message list [--topic-id <id>] [--agent-id <id>] [--role <role>] [--start <date>] [--end <date>] [-L <n>] [--page <n>] [--user] [--json [fields]]
| 选项 | 说明 | 默认值 |
|---|---|---|
--topic-id <id> |
按主题过滤 | - |
--agent-id <id> |
按 Agent 过滤 | - |
--role <role> |
按角色过滤(user / assistant / tool / system) | - |
--start <date> / --end <date> |
创建时间范围(ISO 或 YYYY-MM-DD) |
- |
-L, --limit <n> |
每页大小 | 50(源码默认值,参考文档标注为 30,以当前仓库源码为准) |
--page <n> |
页码 | 1 |
--user |
等价于 --role user 的简写 |
- |
表格列(源码实际输出)为 ID / ROLE / AGENT / CONTENT / TOPIC/THREAD / CREATED,其中 CONTENT 截断至 60 字符,TOPIC/THREAD 列在存在 thread 时以 <topicId> › <threadId> 形式展示分支上下文。
参考文档提到"提供 --topic-id 或 --agent-id 时用 message.getMessages,否则用 message.listAll";而当前 message.ts 的实现已统一走 client.message.listAll.query,并把过滤条件(topicId、agentId、role、startDate/endDate、pageSize/current)一次性传入。可以推断这是后端 listAll 过程吸收了原 getMessages 的过滤语义后的简化,命令行用法不受影响。
3.2 搜索:lh message search
lh message search <keywords> [--json [fields]]
跨所有消息做全文搜索(底层 message.searchMessages),表格输出 ID / ROLE / CONTENT(内容截断 60 字符)。
3.3 删除:lh message delete
lh message delete <id1> [id2...] [--yes]
与主题删除一致的交互约定:默认确认提示,--yes 跳过。源码中 1 个 ID 走 message.removeMessage,多个 ID 走 message.removeMessages。
3.4 计数:lh message count
lh message count [--topic-id <id>] [--agent-id <id>] [--role <role>] [--start <date>] [--end <date>] [--group-by topic] [--json]
| 选项 | 说明 |
|---|---|
--start <date> / --end <date> |
时间范围(ISO 格式,如 2024-01-01) |
--group-by <field> |
按字段分组,目前仅支持 topic(其他取值会报错退出) |
两种输出形态:
- 默认:
Messages: <n>(调用message.count); --group-by topic:表格 TOPIC / COUNT(调用message.countByTopic);--json:{"count": n}或分组结果数组。
3.5 分布统计:lh message stats
参考文档未提及、但源码中已实现的分析型命令,用于回答"每个主题平均多少轮对话"这类问题:
lh message stats [--agent-id <id>] [--role <role>] [--all-roles] [--start <date>] [--end <date>] [--json]
- 默认只统计
user角色的消息("每主题多少轮"的常见口径),--all-roles改为统计全部角色; - 输出指标表:Topics、Total messages、Mean、Median、P90、P99、Min、Max,以及 One-shot(单条消息主题的绝对数与占比,如
12 (3.4%)),底层调用message.topicStats。
3.6 创建与编辑消息:create / edit
# 创建:-r 与 -c 必填
lh message create -r <role> -c <content> [--agent-id <id>] [--topic-id <id>] [--session-id <id>] [--json]
# 编辑:至少指定 --content 或 --role 之一
lh message edit <id> [-c <content>] [--role <role>]
create 通过 message.createMessage 落库并打印新消息 ID;edit 与 topic edit 同样的防护:无任何变更字段时以 No changes specified. 退出。
3.7 附属分析命令
message.ts 还提供了一批数据运维向的子命令:
# 给消息附加文件(文件 ID 逗号分隔)
lh message add-files <id> --file-ids <id1,id2,...>
# 时间段内消息总字数
lh message word-count [--start <date>] [--end <date>] [--json]
# 按消息量对模型排名
lh message rank-models [--json] # 表格列:MODEL / COUNT
# 按助手上下文删除消息(--agent-id 与 --session-id 至少其一)
lh message delete-by-assistant [--agent-id <id>] [--session-id <id>] [--topic-id <id>] [--yes]
# 按群组删除消息
lh message delete-by-group <groupId> [--topic-id <id>] [--yes]
所有删除类命令均遵循统一的 confirm + --yes 约定(见 SKILL.md 中的 Confirmation Prompts 规范)。
3.8 活跃度热力图:lh message heatmap
lh message heatmap [--json]
调用 message.getHeatmaps,展示消息随时间的频率分布;终端模式下按 date: count 逐行打印,--json 输出原始结构。适合在终端里快速判断哪些日期是活跃会话高峰。
4. 底层调用链与输出约定
把所有命令串起来看,lh topic / lh message 的执行链路是:
- 认证:
getTrpcClient()自动解析 token(flag > 本地加密存储~/.lobehub/credentials.json,AES-256-GCM),详见apps/cli/src/api/client.ts与apps/cli/src/auth/; - 类型安全请求:Commander 解析后的选项被组装成 tRPC 输入对象(注意 CLI 的
--limit/--page会换算为pageSize/current),通过client.topic.<proc>.query/mutate或client.message.<proc>.query/mutate发起; - 服务端路由:进入 topic.ts / message.ts 中的 lambda 过程,其中 topic 路由统一挂了工作区鉴权(
wsCompatProcedure+serverDatabase)并注入TopicModel、MessageModel、TopicShareModel等数据模型;搜索类过程额外注入 FTS 检索仓储; - 输出渲染:format.ts 提供
printTable/outputJson/timeAgo/truncate/confirm等工具,保证人工可读表格与脚本可解析 JSON 两种输出形态。
统一约定(与 SKILL.md 的 Output Patterns 一致):
--json [fields]:所有查询类命令支持 JSON 输出,可附逗号分隔字段名做投影;--yes:破坏性操作的免确认开关,自动化脚本必须显式使用;-L, --limit:分页/条数控制,不同子命令默认值不同(topic list为 30,message list为 50,topic view为 50 且上限 500,topic recent为 10)。
5. 典型工作流示例
结合上述命令,一个完整的"体检 → 清理"流程可以是:
# 1. 查看最近活跃的主题
lh topic recent -L 5
# 2. 查看某个主题的完整转录(分页)
lh topic view <topicId> -L 50 --from 1
lh topic view <topicId> -L 50 --from 51
# 3. 全库关键词检索消息
lh message search "部署失败"
# 4. 统计近 30 天消息量与按主题分布
lh message count --start 2026-08-01 --end 2026-08-31
lh message count --group-by topic --json
# 5. 批量清理:导出 ID 后确认删除
lh message list --topic-id <topicId> --json id | jq -r '[]' > /tmp/ids.json
lh message delete --yes $(cat /tmp/ids.json | tr -d '[]" ' | xargs) 2>/dev/null || true
(最后一行的实际用法取决于导出的 JSON 形态;lh message delete 也接受多个位置参数,--yes 用于跳过确认。)
6. 参考与延伸阅读
- 会话命令参考文档:.agents/skills/cli/references/conversation.md
- CLI 开发总纲(架构、新增命令步骤、存储位置):.agents/skills/cli/SKILL.md
- 主题命令实现:apps/cli/src/commands/topic.ts;转录查看:apps/cli/src/commands/topic/view.ts
- 消息命令实现:apps/cli/src/commands/message.ts
- 服务端 tRPC 路由:apps/server/src/routers/lambda/topic.ts、apps/server/src/routers/lambda/message.ts
注意:本文命令参数以当前仓库源码为准。参考文档中个别默认值(如 message list 的 limit 默认值、list 的表格列)与源码存在出入,且部分命令(view、stats、clone、share 系列、create/edit/word-count/rank-models 等)在源码中已实现但参考文档尚未收录——以 lh <command> --help 的实际输出为最终依据。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00