乐于分享
好东西不私藏

OpenKitty 源码深度解析:122 个核心问题全景图

OpenKitty 源码深度解析:122 个核心问题全景图

基于 E:\openkitty 项目源码(347个 Go 源文件,616 个 Go 文件含测试)深度分析 覆盖 17 大模块,从架构设计到源码实现,一文读懂 AI 数字员工平台


📖 阅读导引

OpenKitty 是一个用 Go 语言编写的 AI 数字员工平台,借鉴了 Claude Code 的架构思想,在单仓库(monorepo)中实现了 Agent 编排、Pipeline 工作流、记忆系统、多渠道通信等完整能力。

本文从源码出发,系统梳理了 120 个核心问题,按模块组织,适合:

  • 🧑‍💻 想深入理解 OpenKitty 架构的开发者
  • 🔍 准备贡献代码的技术同学
  • 📚 学习 AI Agent 系统设计的读者

🗺️ 架构全景

┌─────────────────────────────────────────────────────────┐│                     GatewayService                      ││          (HTTP/WS 入口 · 渠道分发 · 会话管理)              │├─────────────────────────────────────────────────────────┤│  Channel 抽象层                                          ││  ┌──────────┬──────────┬──────────┬──────────┐          ││  │  飞书    │  钉钉    │  AG-UI   │  终端    │  ...     ││  └──────────┴──────────┴──────────┴──────────┘          │├─────────────────────────────────────────────────────────┤│  Agent 工厂 → LLMAgent → Generate() 核心循环             ││       │                                                  ││       ├── plan_task (计划编排)                            ││       ├── sub_agent (子代理并行)                          ││       └── Pipeline (工作流引擎)                           │├─────────────────────────────────────────────────────────┤│  基础设施层                                              ││  ┌────────┬────────┬────────┬────────┬────────┐         ││  │ 记忆   │ 工具   │ RAG    │ Hook   │ 上下文  │         ││  │ 系统   │ 系统   │ 搜索   │ 扩展   │ 管理   │         ││  └────────┴────────┴────────┴────────┴────────┘         │└─────────────────────────────────────────────────────────┘

一、架构与设计理念

Q1: OpenKitty 的整体架构是什么?

OpenKitty 采用单仓库 Go 项目架构,所有代码在 package main 下。核心设计理念:

  • Gateway 模式
    GatewayService(~11500 行)作为中央调度器
  • Channel 抽象
    :统一抽象飞书、钉钉、终端等多种交互渠道
  • Agent 工厂模式
    AgentFactory 负责创建和注入各类 Agent 实例
  • Pipeline 编排
    :步骤化的工作流执行引擎
  • 声明式配置
    :通过 openkitty-config.yaml 声明式定义

Q2: 借鉴了 Claude Code 的哪些设计?

代码注释中明确标注了 "Claude Code 借鉴":

模块
说明
协调者模式
coordinator_engine.go
,系统提示增强
上下文6层防御
Token预算→API微压缩→滑动窗口→自动压缩→手动压缩→紧急截断
压缩边界
SystemCompactBoundaryMessage
 标记压缩点
Hook 系统
PreToolUse/PostToolUse/PreCompact 等生命周期钩子
子代理 Swarm
coordinator mode + sub-agent swarms
会话记忆
session-memory.md 双阈值自动提取
熔断器
API 错误处理 + 重试 + 退避
工具编排
partitionToolCalls
 并发分区

二、Agent Generate 核心流程

Q6: Agent.Generate() 的完整执行流程

LLMAgent.Generate(ctx, input) 是整个 Agent 系统的核心方法,位于 mac.go:753

阶段一:初始化

  • 创建 MemoryEvent,记录 AgentName、UserQuestion、StartTime
  • 构建 System Prompt(~2000+ token)
  • 初始化迭代计数器、Token 追踪器

阶段二:主循环

  • 每轮迭代:发送 messages → 接收 LLM 响应 → 解析工具调用
  • 工具调用分区(只读工具并行、写工具串行)
  • Reflection Checkpoint(每 10 轮)、Rethink(每 15 轮)

阶段三:终止

  • 自然结束(LLM 返回纯文本无工具调用)
  • 达到 maxIterations
  • 用户中断或超时

Q8: plan_task 和 ActivePlan 的工作原理

三个组件协作实现计划-执行模式:

  • plan_task 工具
    :LLM 调用创建计划,steps 转为 []PlanStep
  • ActivePlan 状态机
    pending → in_progress → completed/skipped
  • 注入机制
    :每轮迭代将当前步骤注入 System Prompt

Q12: Reflection 和 Rethink 的区别

维度
Reflection Checkpoint
Rethink
触发频率
每 10 轮迭代
每 15 轮迭代
实现方式
注入反思提示文本
独立 LLM 调用(Supervisor 角色)
成本
零额外 API 调用
有额外 API 调用
作用
让 Agent 自问自答审视进度
外部监督者判断是否偏航

三、Pipeline 管道系统

Q16: Pipeline 系统的核心架构

PipelineService(pipeline.go,~5621 行)是工作流执行引擎:

  • Step 定义
    :每个步骤包含 Name、Prompt、Tools、MaxIterations、Approval
  • 黑名单机制
    pipelineBlacklist 永久禁止 delete_file、shell 等危险工具
  • 条件执行
    :支持 Condition(前置条件)和 SkipOnError
  • 状态追踪
    :running → completed / failed

Q17: Pipeline 的持久化恢复

PipelineDurable 检查点模型:

  • 每步完成后写入检查点(step_name、status、output)
  • 中断恢复时从最后 completed 步骤继续
  • 支持重试失败步骤

Q18: 进化引擎(PipelineEvolver)

基于统计指标的规则引擎:

  • minRuns=5 触发分析
  • 5 种建议类型:步骤合并、工具优化、Prompt 调整、超时调整、并行化
  • 分析指标:AvgDuration、AvgToolCalls、FailureRate、ToolUsage、ToolErrors

四、Agent 系统

Q21: Agent 的加载和发现机制

AgentLoader(agent_loader.go):

  • 目录扫描
    :从 .openkitty/agents/ 发现 Agent 定义
  • 格式支持
    :YAML 和 JSON
  • 热加载
    :autoReload 模式下监控文件变更
  • 最后修改追踪
    :基于文件修改时间的增量加载

Q22: LLMAgent 的核心执行循环

主循环位于 mac.go,核心逻辑:

  1. 构建请求(System Prompt + 历史消息 + 当前输入)
  2. 调用 LLM API(支持流式)
  3. 解析响应(文本 or 工具调用)
  4. 执行工具(并行/串行分区)
  5. 将结果追加到消息历史
  6. 检查终止条件

Q25: SwarmTool 和 SubAgentTool 的区别

维度
SubAgentTool
SwarmTool
触发方式
显式调用 sub_agent 工具
Coordinator 模式自动触发
Agent 角色
独立子 Agent
Swarm 中的 Worker Agent
协调机制
父 Agent 直接管理
Coordinator Engine 统一调度
适用场景
明确子任务拆分
大规模并行探索

五、记忆系统

Q26: 记忆系统的核心数据结构

MemoryEvent(memory.go)是核心记忆表:

  • 标识信息
    :AgentName、AgentType、SessionID、TaskID
  • 内容
    :Role(user/assistant/system/tool)、Content、ToolName、ToolResult
  • Token 统计
    :PromptTokens、CompletionTokens、TotalTokens
  • 状态
    :Status(success/failed)、ErrorType、ErrorMessage

Q27: 记忆衰减算法

基于 Ebbinghaus 遗忘曲线的衰减策略:

  • 近期记忆权重高,远期记忆权重低
  • 支持按重要性(importance)调整衰减速度
  • 检索时综合相关性分数 + 时间衰减权重

Q29: 会话记忆的自动提取

SessionMemory 双阈值自动提取:

  • 重要性阈值
    :超过阈值的记忆自动提取
  • 频率阈值
    :多次出现的主题自动归纳
  • 输出为 session-memory.md 文件

六、工具系统

Q31: 工具接口定义

type Tool interface {    Name() string    Description() string    Parameters() map[string]interface{}  // JSON Schema    Execute(ctx context.Context, params map[string]interface{}) (string, error)    RiskLevel() RiskLevel    IsReadOnly() bool}

Q32: 工具编排器的并发分区策略

ToolOrchestrator.partitionToolCalls

  • 只读工具 → 并行执行(goroutine + WaitGroup)
  • 写工具 → 串行执行(按调用顺序)
  • 混合 → 先并行执行只读组,再串行执行写组

Q34: 安全分级设计

级别
说明
示例
Low
纯只读,无副作用
read_file、grep、glob
Medium
只读但有网络访问
web_fetch、web_search
High
文件写入
write_file、edit_file
Critical
系统级操作
shell、delete_file

七、RAG 与搜索系统

Q36: RAG 搜索系统架构

基于 bleve(Go 原生全文搜索引擎):

  • 分词
    :中文分词 + stopTokens 过滤
  • 多格式支持
    :Markdown、纯文本、代码文件
  • 增量索引
    :文件变更时自动更新
  • 混合检索
    :BM25 全文搜索 + 向量相似度

八、LLM 调用与模型管理

Q41: 重试策略

llmCallPolicy

  • 默认超时:300 秒/次
  • 默认尝试次数:2 次(含初始请求)
  • 安全边界:最小 15 秒,最大 300 秒超时;最大 3 次尝试

Q42: 模型回退链

FallbackChain:主模型失败 → 自动切换到备用模型 → 继续失败则返回错误

Q45: 熔断器状态机

CLOSED → (失败次数达阈值) → OPEN → (冷却时间到) → HALF_OPEN                                                         │                                      ┌──────────────────┤                                      │ 成功 → CLOSED    │ 失败 → OPEN

九、Hook 与扩展系统

Q46: Hook 生命周期事件

事件
触发时机
PreToolUse
工具调用前
PostToolUse
工具调用后
PreCompact
上下文压缩前
PostCompact
上下文压缩后
SessionStart
会话开始
Stop
Agent 停止时

Q48: 技能(Skill)系统

通过 use_skill 工具动态加载技能:

  • 内置技能预加载到运行时上下文
  • 自定义技能从 .openkitty/skills/ 发现
  • 支持 Python 脚本、Shell 命令、内置功能三种类型

十、上下文管理

Q51: 6 层防御体系

ContextManager(context_compressor.go):

第1层:Token 预算 ──→ 70% 警告,阈值时自动续接第2层:API 微压缩 ──→ 输入超阈值时清除旧工具结果第3层:滑动窗口 ──→ 消息数量超限时丢弃最旧消息第4层:自动压缩 ──→ 接近上下文窗口时触发 LLM 摘要第5层:手动压缩 ──→ 用户主动触发 /compact第6层:紧急截断 ──→ 最后手段,强制截断最早消息

十一、测试与质量保证

Q56: 测试策略

  • 616 个 Go 文件,其中 269 个测试文件
    ,测试覆盖率约 44%
  • 单元测试:每个核心模块都有对应的 _test.go
  • 集成测试:Agent 协作、Pipeline 端到端测试
  • 终端测试:action_receipt_test.go 验证工具执行回执

十二、渠道与通信

Q64: 飞书渠道的完整生命周期

FeishuChannel(feishu.go,~1195 行):

  • 初始化:Lark SDK 创建客户端,配置 AppID/AppSecret
  • 事件订阅:dispatcher 注册消息事件处理器
  • WebSocket 长连接:larkws 实现实时通信
  • 审批卡片:ApprovalCard 机制,敏感操作需用户确认

十三、数据存储与持久化

Q74: 数据库架构

存储
职责
SQLite(默认)
MemoryEvent、Agent 配置、Pipeline 状态
gatewayDB
全局数据库实例,由 Gateway 管理
bleve 索引
全文搜索索引,独立于关系数据库
文件系统
Agent 定义(YAML/JSON)、技能脚本、会话记忆

十四、高级特性

Q84: Agent 协作(AE Collaboration)

ae_collaboration.go 实现三种协作模式:

模式
说明
主从模式
主 Agent 分配任务,从 Agent 执行并汇报
对等模式
多个 Agent 平等协商
流水线模式
Agent A 输出 → Agent B 输入 → Agent C 输入

十五、部署与运维

Q96: 构建和部署流程

  • 构建
    go build -o openkitty . 生成单一二进制
  • 交叉编译
    :支持 Linux/macOS/Windows
  • 配置外置
    :二进制与配置文件分离
  • 静态资源嵌入
    :前端资源编译进二进制
  • Docker 支持
    :可容器化部署
  • systemd 集成
    :支持 Linux 服务化

十六、实战场景题

Q106: 如何实现一个"代码审查 Agent"?

  1. Agent 定义
    :创建 YAML 配置,Role 设定为代码审查专家
  2. 工具授权
    :read_file、grep、glob、code_check、git
  3. 技能绑定
    :加载代码审查相关技能
  4. Pipeline 定义
    :检出代码 → 静态分析 → 逻辑审查 → 生成报告

Q107: 如何设计"每日新闻摘要"Pipeline?

Step 1: 采集 → social_trending 多平台抓取Step 2: 筛选 → LLM 过滤高价值内容Step 3: 摘要 → 生成结构化摘要Step 4: 发布 → 推送到飞书/钉钉/邮件

十七、Pipeline 与 Sub-Agent 源码实现(深度篇)

111. Pipeline 是怎么跑起来的?

源码位置pipeline.go(5621 行),核心结构体 PipelineExecutor(L2263)

type PipelineExecutor struct {    agentFactory       *AgentFactory    gateway            *GatewayService    executions         map[string]*PipelineExecution    pipelines          map[string]Pipeline    professionalAgents *ProfessionalAgentRegistry}

Pipeline 的执行不是「一个 Agent 跑完所有步骤」,而是每个 Step 独立启动一个 Agent,通过 pipeline_vars 传递上下文。

112. Pipeline 的持久化恢复

PipelineDurable 检查点模型:

  • 每步完成后写入检查点(step_name、status、output)
  • 中断恢复时从最后 completed 步骤继续
  • 支持重试失败步骤

113. Pipeline 的进化引擎

基于统计指标的规则引擎:

  • minRuns=5 触发分析
  • 5 种建议类型:步骤合并、工具优化、Prompt 调整、超时调整、并行化

114. sub_agent 的完整生命周期

  1. 创建
    :移除递归工具(sub_agent 不能再 spawn sub_agent)
  2. 执行
    :独立 Agent 实例,10 分钟超时
  3. 清理
    :结果返回后释放资源

115. parallel_sub_agent 的并发模型

goroutine + WaitGroup,最多 5 并发,结果有序收集。

116. Pipeline vs sub_agent 本质区别

维度
Pipeline
sub_agent
粒度
粗粒度工作流
细粒度子任务
状态
持久化检查点
无状态
执行者
每步独立 Agent
临时子 Agent
上下文传递
pipeline_vars
输入/输出字符串
审批
步骤级审批
无审批
恢复
支持中断恢复
不支持
并行
步骤串行
多子 Agent 并行
递归
不支持
不支持(被移除)
调度
手动/定时触发
父 Agent 触发
适用
生产工作流
探索性任务

117. 什么时候用哪个?

场景
推荐
每日定时报告生成
Pipeline
代码审查工作流
Pipeline
多源信息并行搜索
sub_agent
多文件并行分析
sub_agent
复杂多步骤业务流程
Pipeline

118. 两者能组合使用吗?

可以。Pipeline Step 内部的 Agent 仍然可以 spawn sub_agents:

Pipeline Step 1 → Agent A(可 spawn sub_agents)Pipeline Step 2 → Agent B(可 spawn sub_agents)Pipeline Step 3 → Agent C(可 spawn sub_agents)

119. Pipeline 的审批机制

三层防御:

  1. 黑名单
    :永久禁止危险工具
  2. 步骤审批
    :Approval 标记的步骤需人工确认
  3. 超时拒绝
    :超时未审批自动拒绝

120. 子 Agent 为什么不能递归 spawn?

三个原因:防组合爆炸、防失控、防资源耗尽。

121. Function Calling 如何保证稳定生成 JSON 结构?

OpenKitty 的函数调用 JSON 稳定性依赖四层防御

第一层:System Prompt 约束。 在每个工具定义的 JSON Schema 中,parameters 字段严格声明类型(string/number/boolean/object/array)、required 字段、enum 约束。LLM 在生成 tool call 时,System Prompt 中的这些 Schema 会引导它输出符合规范的 JSON。

第二层:多策略解析(main.go parseWriteFileArgs)。 即使 LLM 输出的 JSON 有瑕疵,框架也有 4 层解析策略兜底:

策略
方法
说明
1
直接 json.Unmarshal
标准 JSON,一次成功
2
把 \" 替换为 " 后再解析
处理过度转义
3
strconv.Unquote
 去外层引号再解析
处理被字符串包裹的 JSON
4
parseManually
 手动提取
逐字段正则/字符串扫描,兜底

策略4 的 parseManually 通过 extractFieldSmart(正则匹配 "path":)、extractBoolFieldSmart(匹配 "append":)、extractContentField → extractQuotedString(逐字符扫描双引号字符串,处理 \" 转义)来逐字段提取,即使 JSON 整体结构损坏也能恢复关键字段。

第三层:Tool Registry 校验。 解析后的参数会经过 tools.go 中注册的 Tool Schema 校验,required 字段缺失或类型不匹配会直接报错返回给 LLM,让 LLM 重试。

第四层:内容净化(write.go)。 即使 content 字段被 LLM 包了 markdown 代码块(```...```),WriteFileTool.Execute 也会自动剥离;HTML 文件还会提取 <html>...</html> 之间的内容并解码实体。

122. 大模型输出特别长时,如何保证断点续传?

OpenKitty 采用分块写入 + append 模式策略,核心实现在 write.* 的 WriteFileTool.Execute

机制一:分块写入(Chunked Write)。 System Prompt 明确指示:当 content 超过约 6000 字符时,LLM 应分多次调用 write_file,每次设置 append=true。首次调用 append=false 创建文件,后续调用 append=true 追加内容。底层实现是标准 os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)

机制二:JSON 结构增量构建。 对于 JSON 文件,System Prompt 指示:先写一个小的合法骨架(如 {"items":[]}),然后用 json_patch 工具通过 RFC 6901 JSON Pointer 操作(add/replace/remove)逐步添加结构。这避免了拼接无效 JSON 片段的问题。

机制三:格式感知路由。detectFormat 根据扩展名路由到不同 writer。append 模式仅对 FormatTextFormatMarkdown、default 分支生效;JSON/YAML/CSV/HTML/DOCX/XLSX/PDF 不支持 append——这些结构化格式走各自的专用 writer(如 writeJSONFile),保证格式完整性。

机制四:LLM 自主分片。 由于每次 tool call 的 content 参数有 token 限制,LLM 被训练为自动检测内容长度,超过阈值就切分。框架不强制分片大小,而是信任 LLM 的判断——如果某次写入失败,LLM 看到错误后会自行调整策略。


📊 统计一览

指标
数值
Go 源文件
347 个
Go 文件(含测试)
616 个
测试文件
269 个
核心问答
122 个
覆盖模块
17 个
最大单文件
gateway.go(~11500 行)
Pipeline 引擎
pipeline.go(~5621 行)