Octop 源码深潜-第 00 篇:导读与全景地图

1 阅读4分钟

第 00 篇:导读与全景地图

本系列基于 Octop 1.0.2b6 源码。这一篇不深入任何模块,只做三件事:界定问题、画出地图、给出阅读路径。已经熟悉项目可直接跳到 第 01 篇。

1. 一句话定义

Octop 是腾讯云开源的自托管 AI 助手平台:一个 Python wheel,内含 FastAPI 后端、React 前端、Click CLI、IM 渠道桥接、定时调度、知识库、插件系统与 MCP 连接器。整个平台以单进程运行在你自己的机器上,数据全部落在 ~/.octop/。

它的差异化不在"能聊天",而在于把下面四个约束同时满足:

约束含义
多用户一个部署,多个用户;JWT 隔离,共享专家与知识库
多智能体每个用户可拥有多个 Agent(专家);Agent 之间可协作(AgentTeams)
多渠道Web / CLI / 飞书 / 钉钉 / QQ / 微信 / Telegram / Discord / 企业微信 / Cron 全部汇入一条管线
自托管零外部依赖(除 LLM provider 外无 Redis/MQ/worker),单进程、单端口

2. 四条贯穿全局的设计主线

带着这四条主线读代码,能解释绝大多数"为什么这样写":

主线一:单进程,无外部队列

见 ADR 001。没有 Redis、Celery、独立 worker。所有 surface 通过进程内的 HarnessProcessor 汇流。后果是"所有阻塞调用必须 run_in_executor",且没有任何跨进程一致性难题——进程状态可以完全从数据库重建。

主线二:双数据库后端

见 ADR 002。控制面可跑在 SQLite(默认,WAL)或 PostgreSQL(psycopg3 连接池)上。同一套 Repo 代码,靠池边界的 ? → %s 重写与 _CompatRow 抹平方言差异。存储被明确划分为三层:Octop 控制面、harness checkpoint、agent memory,三者不许混为一谈。

主线三:依赖只向内流动

dashboard/ ──HTTP──► api/ ──► infra/ ──► infra/utils/, octop.config
cli/ ──► launch.py ──► api/ + infra/

infra/ 永不 import api/ / cli/ / launch.py;api/ 不 import cli/;infra/db/repos/ 只依赖 _base 与 utils。这些不是建议,而是 AGENTS.md §5 的硬禁令,并有"唯一例外"——只有 launch.py 能同时看到 infra.server 与 api.app。

主线四:一张数据库,一个进程,一次重启

OctopServer.start() 每次按依赖顺序重建整棵运行时树。进程内没有"不可恢复的隐性状态"。这也是为什么 replace_services() 能把所有单例热重绑到新库——状态本来就是"可从库重建"的。

3. 运行时全景

OctopServer
 ├─ DatabasePool            SQLite (WAL) 或 PostgreSQL (psycopg 池)
 ├─ SharedServices           DI 根:paths + config + RepoBundle
 ├─ ExpertCatalog            启动时扫描 agents/experts/library/
 ├─ UserManager
 │   └─ AgentManager(全局注册表,一个进程一个)
 │       └─ HarnessAgentRuntime(每个 agent)
 │           ├─ HarnessAgent      智能体运行时(octop-harness / LangGraph)
 │           ├─ GlobalProcessor   IM / Web / CLI / Cron 统一入口
 │           ├─ ChannelManager    IM 连接(octop-gateway)
 │           └─ BackendWorkspace  可插拔文件 I/O
 ├─ Gateway(ChannelManager + WebSocketHub + Cron 触发器)
 ├─ CronManager(进程级 APScheduler)
 ├─ TrajectoryService(轨迹投影 + 实时总线)
 └─ FastAPI app(uvicorn)

4. 一次对话的完整路径(玻璃盒)

以"用户在 Web 里发一句话"为例,把本系列的章节串起来:

用户输入
  │  WebSocket /api/agents/{aid}/chat/ws      ← 第 11 篇(前端)
  ▼
api/routers/chat/ws.py  →  gateway/ws/ws_channel.py   ← 第 03 篇
  │  组装 InboundMessage,解析 session_key
  ▼
GlobalProcessor.iter_turn_chunks(msg)          ← 第 03 篇
  │  ① 解析用户/locale/session_key  ② 处理 slash  ③ HITL 分支
  │  ④ 构造 harness request         ⑤ 订阅轨迹
  ▼
AgentManager.stream() → HarnessAgent         ← 第 02 篇
  │  LangGraph 执行,逐 chunk 产出
  ▼
TrajectoryService.observe_chunk()            ← 第 04 篇
  │  投影为 assistant / tool / user 事件,聚合 token,落库 + 实时发布
  ▼
WebSocketHub.push_to_thread()  →  浏览器渲染     ← 第 11 篇

同一路径换成 IM 渠道时,ws_channel 换成对应 ChannelManager,iter_turn_chunks 换成 __call__ → project_stream → MessageEvent,下游完全复用。这正是"统一管线"的价值。

5. 关键术语表

术语定义主要源码
surface消息入口:Web / CLI / IM / Croninfra/gateway/*
turn一次用户→助手的完整往返history/trajectory/*
session_key全局会话寻址键 agent:channel:subject:chat_typegateway/threads.py:31
threadsession_key 绑定的具体会话线程(含历史元数据)gateway/threads.py
chunkharness 产出的流式事件(token / tool_call_chunk / tool_result / …)gateway/process/stream_project.py
trajectory由 chunk 投影出的、可持久化可回放的事件流history/trajectory/*
TaskRouter / ProcessorGlobalProcessor,把 InboundMessage 路由到正确 Agentgateway/process/processor.py:135
expert面向用户的 Agent 概念(一个 Agent = 一个专家)infra/agents/*
workspaceAgent 的文件空间,可插拔后端infra/backend/*

6. 技术栈速查

层技术
语言Python 3.12+(asyncio,无线程池除非 run_in_executor)
WebFastAPI + uvicorn;Scalar 文档在 /api/docs(默认关)
Agent 运行时octop-harness(LangGraph)
渠道桥接octop-gateway
记忆octop-memory(分层召回 + FTS)
浏览器octop-browser(CDP + 持久 profile)
控制面 DBSQLite(WAL,默认)或 PostgreSQL(psycopg3)
前端React 18 + TypeScript + Vite + Ant Design
调度APScheduler(AsyncIOScheduler)
包管理uv(uv run pytest,禁止裸 pytest)
质量门hatchling · ruff · mypy --strict · pytest(跨 Linux/Windows)

7. 阅读路径建议

  • 架构向:01(组合根)→ 02(运行时)→ 03(管线)→ 04(投影)→ 05(历史)。
  • 集成向:03(管线)→ 10(连接器/MCP)→ 11(前端)。
  • 运维/存储向:06(双库)→ 08(工作区后端)→ 12(定时)。
  • 安全向:09(安全体系)单读。

准备好了就从 第 01 篇:单进程架构的抉择 开始。