从记忆体系、交互架构到安全管线,全方位剖析这个 AI 编程智能体的内部运作机制
"一千个读者就有一千个哈姆雷特" — 本文只是提供一些解读 cc 源码、窥探智能体开发的视角
先从两个角度直观简略感受 cc 的工程体系:时序角度与目录架构角度
分流到 commands.ts。其中 local 命令直接执行;local-jsx 渲染交互 UI;prompt 型命令(如 /review、/diff)先展开提示词再走 query 逻辑。
commands.ts组织上下文、当前消息、工具列表,请求大模型。返回纯文本则直接显示;返回 tool_use 则进入 toolOrchestration 编排执行。
query.ts · claude.tscc 是一个以 agent 运行内核为中心,外挂了命令、工具、任务、UI、协议等功能的架构体系。从大模型一层层封装、由内而外分析如下:
最内层,驱动请求大模型。文本走 HTTP 流,语音走 WebSocket。
query.ts · service/api控制暴露什么信息给大模型:上下文压缩、记忆、策略限制、远程配置、全局状态。
services/compact · memdir/拓展大模型能力的 Function Calling 层。抽象定义在 Tool.ts/Task.ts,由 toolOrchestration 调度。
tools/ · tasks/将内建命令、skills、plugins、工作流命令统一装配为用户入口。
commands/通过 bridge、server、cli、bootstrap 桥接运行环境,管理会话生命周期,抹平 OS 差异。
bridge/ · cli/通过 Ink 实现终端实时渲染,包含组件库、屏幕、键绑定和 Vim 模式。
components/ · ink/记忆在智能体开发中最为关键——直接关系到大模型对使用者的了解程度、上下文拼接和注意力机制。cc 的记忆会随着时间在不同阶段以不同姿势渗入上下文。
getMemoryFiles() 扫描所有可用记忆:Managed(组织级)→ User(全局)→ Project/Local(从根向当前目录递归扫描 CLAUDE.md)→ AutoMem/TeamMem(长期记忆 MEMORY.md)processMemoryFile() 像一条流水线:候选路径 → 去重/排除 → 解析内容 → 提取 @include → DFS 递归展开 include 树(MAX_DEPTH=5,倡导扁平化可预测的记忆体系)→ 输出 MemoryFileInfo[]getNestedMemoryAttachmentsForFile(),按文件路径召回相关 rules 和 nested memory
handleStopHooks() 启动后台 bookkeeping。subAgent 无法直接影响主记忆,只有回流主线程后才能被沉淀lastMemoryMessageUuid)runForkedAgent() 跑后台 agent,复用主会话 cache 但限制权限,不阻塞主任务、防止污染上下文
sessionMemory.ts 在主线程每轮结束后按阈值后台维护"当前会话笔记文件"。权限极窄,只允许对唯一的 notes 文件做 Edit,保持模板结构(Current State、Files and Functions、Errors & Corrections)trySessionMemoryCompaction 优先使用 session memory,只有在其无法使用或为空时才 fallback 到传统摘要式压缩
将 cc 视为 CLI 产品,从三层出发:命令与模式分流层、终端渲染层、状态层。
关注如何从外部进入 cc 并被分流到正确执行模式。核心学习点:如何尽可能多实现复用。
实现入口收敛复用。在 main() 前期解析特殊输入,把信息存进 _pendingConnect / _pendingSSH / _pendingAssistantChat,必要时改写 process.argv,然后继续走默认主流程。
用 program.hook('preAction', ...) 把所有外层命令共享的前置步骤挂成统一生命周期:init()、logging、migration、remote settings 预热、entrypoint 标记。
整个外层 CLI 只有一个 CommanderCommand 根对象,命令层只做组织和分发,复杂执行交给专门处理器(handler 模块)。Single 单一职责原则。
跨阶段共享数据装进统一对象(Pending* / sessionConfig / resumeContext),多模式分支共用同一套启动接口:createRoot → showSetupScreens → launchRepl
从终端进入对话后的渲染管线。cc 的 TUI 走的是:
在 reconcile 阶段 React 用同一套 Fiber 机制计算更新;commit 阶段由 Ink 的 HostConfig 作为适配器,把 mutation 映射为 Ink DOM 操作并同步 Yoga 节点状态。
通过 dirty 标记 + measure 函数细化重渲染粒度。dirty=false 允许 blit 快路径(块拷贝复用上一帧像素),只有文本节点变动才"打穿"触发昂贵的 measure。
LogUpdate 计算 prevFrame → frame.screen 的最小 patch 序列。writeDiffToTerminal 按终端能力决定是否包裹 DEC 2026 同步输出(BSU/ESU)避免闪烁/撕裂。
核心思想和虚拟树一样:先在内存中处理避免频繁触碰终端 I/O。diff 副作用压缩成少量 write,支持时用同步输出保证原子性,不支持时跳过避免徒增开销。
cc 将状态按频率和职责拆分为三级,实现高频脏数据与低频共享壳层的区分。
承载权限模式、MCP、插件、任务视图、footer、通知等。AppStateProvider 放入 Context 的是稳定的 store 引用而非不断变化的 state,避免整棵树级联重渲。底层基于观察者模式:setState → 通知订阅者 → useSyncExternalStore + selector → 只有切片真正变化的组件才重渲。
messages、streaming text、输入框、overlay、滚动等。通过 useState + useRef 双重维护:messages 给 React 渲染,messagesRef 给"同步立即读取最新值"的逻辑用。确保高频更新时不必等 React batching。
命令队列、QueryGuard、文件 watcher 等。通过 createSignal() 维护 listener 集合(观察者模式),再包一层自己的状态和 getSnapshot()。React 侧用 useSyncExternalStore 订阅,非 React 代码直接调用同步 API。
cc 不是"把模型关进隔离盒子",而是"在真实环境里,让每次动作都经过足够细粒度、可回退、可审计的权限决策"。
不是"六层线性防御",而是一个包含若干可提前返回的 gate 的 DAG 式决策系统。
权限规则不只是布尔表,还记录来源。规则来源不同后续行为也不同:有的可持久化编辑、有的是 policy 下发不能删、有的只在 session 内临时生效。用户可见的 shell 规则形态为 exact / prefix / wildcard 三种。
外层规则只知道"该不该放行",真正理解工具语义的是工具自己的 checkPermissions()。Bash 是最复杂的——继续分析 subcommand、operator、redirection、path、sandbox、compound command。通用规则层 + 工具内语义层的组合。
某些风险即使在 bypass 模式下也不能绕过:.git/、.claude/、shell config、危险删除路径。有些风险属于系统级硬边界,模式只能影响大多数流程,不能抹掉全部边界。
进入 auto mode 时主动剥离会绕过 classifier 的危险 allow 规则(如 Bash(*)、Agent(*)),离开后恢复。系统不仅防模型,也防"过去为了方便留下的过宽策略"。
Bash 是整个系统里最接近"把宿主机直接交给模型"的能力,所以用了双轨分析。
核心问题不是"解析语法树",而是"能否可信提取 argv[]"。如果能可信提取,做更强的安全分析;如果不能,直接走 too-complex → ask。关键词:allowlist、fail-closed、trustworthy argv extraction。
AST 不可用或 shadow mode 下不生效时,继续使用 bashSecurity.ts 的 regex / shell quote / pattern battery。先让新路径成为主判断,再用 shadow mode 和 fallback 保持迁移安全性。
echo hi | xargs printf '%s' >> file — 局部子命令安全 ≠ 整体命令安全(危险在原始命令的 >> file)cd malicious && git status — 组合命令上下文改变了原本工具语义
审批过程更像一个并发编排系统——本地终端 UI、CCR remote bridge、channel relay、PermissionRequest hooks、异步 Bash classifier。这些通道不是串行排队而是 race:谁先给出有效决策谁就赢。
没法弹 prompt 时:先跑 PermissionRequest hooks 看有没有自动 allow/deny,如果 hooks 也没结论就直接 fail-closed。不是"尽量让 agent 跑下去",而是"在不越线的前提下让 agent 跑下去"。
召唤独属于你的宠物!支持抚摸(飘爱心)、改名、戴帽子(皇冠、巫师帽等8种)、切换物种。输入宠物名字即可对话。
持久化助手模式——长会话中记忆存在按日期的追加式日志中。/dream 会在低活跃期将原始日志蒸馏成结构化主题文件。
检测用户负面情绪的方式不是通过 side agent,而是直接进行最原始的正则匹配关键词。简单但有效。
深度、长期规划命令。做复杂任务时可以用它生成超详细执行计划,包含子任务分解和依赖分析。
分布式任务执行命令——将任务分配到多个智能体并行处理。需要 TORCH feature flag。
语音输入模式,支持语音交互。需要 VOICE_MODE feature flag。
| 指令 | 功能 | 所需 Flag |
|---|---|---|
| /proactive | 切换主动模式,AI 主动发起对话和建议 | PROACTIVE / KAIROS |
| /brief | 生成项目简报,总结当前会话关键信息 | KAIROS_BRIEF |
| /assistant | Kairos 助理模式,后台持续运行 | KAIROS |
| /subscribe-pr | 订阅 GitHub PR,更新时自动通知 | KAIROS_GITHUB_WEBHOOKS |
| /fork | 分叉子智能体处理独立任务 | FORK_SUBAGENT |
| /ultraplan | 超详细执行计划 + 子任务分解 | ULTRAPLAN |
| /torch | 分布式多智能体并行执行 | TORCH |
| /peers | 查看和管理对等智能体实例 | UDS_INBOX |
| /workflows | 管理和执行自定义工作流脚本 | WORKFLOW_SCRIPTS |
| /web | 远程环境配置,支持 Web 界面访问 | CCR_REMOTE_SETUP |
| /buddy | AI 伙伴精灵模式 | BUDDY |
| /voice | 语音输入模式 | VOICE_MODE |
| /ctx-viz | 上下文可视化,展示 Token 分布 | 内部调试 |
| /force-snip | 强制裁剪历史对话 | HISTORY_SNIP |
| /force-compact | 强制压缩上下文 | REACTIVE_COMPACT |
| /clear-skill-cache | 清理技能搜索缓存 | EXPERIMENTAL_SKILL_SEARCH |
根据源码得到的特性,启发的日常使用技巧。宗旨:规则写小、任务锚到文件、记忆显式说、长会话尽早主动 compact。
CLAUDE.md 写到"只保留 Claude 真会做错的事"这个程度。/init 就是按"删掉这一行会不会让 Claude 犯错"来生成的,太大会被标 warning。CLAUDE.md / .claude/rules/,个人习惯放 CLAUDE.local.md 或 ~/.claude/CLAUDE.md。CLAUDE.md,或把 .claude/rules/*.md 做成按 paths 命中的局部规则。CLAUDE.md,改成 @path/to/file 按需引入。src/foo.ts 里的 X" 比 "帮我改下这块逻辑" 更容易触发对的局部规则。/memory,它会打开 memory 文件让你改,走的是 $EDITOR / $VISUAL。autocompact 开启。session memory 的后台维护尊重 auto-compact 开关,关掉后连续性能力会弱很多。/compact。不给自定义总结指令时会走 session-memory compaction;写成 /compact 请重点总结... 就会回退到传统 compact。/compact,长任务最好在掌控上下文时主动压一次。claude -p 适合脚本和一次性任务。要接别的程序时优先用 --output-format json。claude -c 继续最近会话,claude -r 搜索恢复,--fork-session 分叉新思路。claude -n "支付链路排查" 后面 /resume 时非常省时间。/clear 或新开会话。