一、引言
大家好,我是一个源码爱好者。在上一篇文章中,我们了解了 Claude Code 的整体架构和启动流程。今天,让我们深入到核心模块------对话引擎的实现细节。
相信很多人都好奇,当我们在终端输入一个问题时,Claude 是如何理解并给出回答的?这个过程背后隐藏着怎样的技术细节?
在深入源码之前,我想分享一个令人震惊的发现:Claude Code 的对话引擎竟然实现了四层压缩策略来处理长对话上下文!这意味着即便是长达数百轮的对话,系统也能保持高效运行。
二、对话引擎的核心架构
2.1 整体架构概览
让我们先来看一下对话引擎的整体架构:
scss
用户输入
│
▼
┌─────────────────────────────────────┐
│ QueryEngine(对话管理器) │
│ - 会话状态管理 │
│ - 消息流转控制 │
│ - SDK 协议适配 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ query()(核心查询循环) │
│ - 消息压缩处理 │
│ - API 调用管理 │
│ - 工具执行协调 │
│ - 错误恢复机制 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Anthropic API / MCP 服务器 │
│ - 模型调用 │
│ - 工具执行 │
│ - 消息流处理 │
└─────────────────────────────────────┘
2.2 QueryEngine:对话的"大脑"
QueryEngine 是整个对话系统的核心,负责管理对话的完整生命周期:
typescript
export class QueryEngine {
private config: QueryEngineConfig; // 配置信息
private mutableMessages: Message[]; // 消息列表
private abortController: AbortController; // 中断控制器
private permissionDenials: SDKPermissionDenial[]; // 权限拒绝记录
private totalUsage: NonNullableUsage; // API 使用统计
private readFileState: FileStateCache; // 文件读取缓存
}
这里我踩了个大坑! 一开始我以为 QueryEngine 只是一个简单的消息转发器,但深入后发现它其实承担了:
- 会话状态管理
- 权限追踪
- 资源消耗统计
- 文件缓存管理
这四个核心职责!
三、消息处理流程深度剖析
3.1 消息分类与处理策略
QueryEngine 处理多种消息类型,每种类型都有专门的处理逻辑:
| 消息类型 | 处理策略 | 用途 |
|---|---|---|
assistant |
标准化后输出 | AI 助手响应 |
user |
增加回合计数 | 用户输入 |
progress |
立即记录 | 工具执行进度 |
attachment |
提取结构化输出 | 附件和元数据 |
stream_event |
更新使用统计 | 流式事件 |
system |
处理压缩边界 | 系统控制信号 |
3.2 核心方法:submitMessage
这是 QueryEngine 的核心方法,处理用户输入并返回响应:
typescript
async *submitMessage(prompt, options) {
// 1. 包装权限检查函数
const wrappedCanUseTool = async (tool, input, ...) => {
const result = await canUseTool(tool, input, ...);
if (result.behavior !== 'allow') {
this.permissionDenials.push({
tool_name: tool.name,
tool_use_id: toolUseID
});
}
return result;
};
// 2. 获取系统提示和上下文
const { defaultSystemPrompt, userContext, systemContext } =
await fetchSystemPromptParts({ tools, mainLoopModel, ... });
// 3. 处理用户输入
const { messages: messagesFromUserInput, shouldQuery } =
await processUserInput({ input: prompt, mode: 'prompt', ... });
// 4. 持久化消息
if (persistSession && messagesFromUserInput.length > 0) {
await recordTranscript(messages);
}
// 5. 执行查询循环
for await (const message of query({ messages, systemPrompt, ... })) {
// 处理各类消息...
}
}
关键设计点:
- 使用
async*生成器模式,支持流式输出 - 包装权限检查函数,记录所有权限拒绝
- 消息持久化确保会话可恢复
四、四层压缩策略:处理长对话的秘密武器
4.1 压缩层次结构
这是我发现的最令人惊叹的设计!Claude Code 实现了四层压缩策略:
markdown
┌─────────────────────────────────────────────┐
│ 第1层: Snip 压缩(快速清理) │
│ - 移除僵尸消息和陈旧标记 │
│ - 轻量级,快速执行 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 第2层: Microcompact(缓存优化) │
│ - 基于缓存编辑的细粒度压缩 │
│ - 保持对话连贯性 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 第3层: Context Collapse(上下文折叠) │
│ - 基于视图投影的智能折叠 │
│ - 保持对话粒度 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 第4层: Autocompact(自动压缩) │
│ - 基于AI总结的重量级压缩 │
│ - 生成摘要消息 │
└─────────────────────────────────────────────┘
4.2 压缩实现代码
typescript
// Snip 压缩
if (feature('HISTORY_SNIP')) {
const snipResult = snipModule.snipCompactIfNeeded(messages);
messages = snipResult.messages;
}
// Microcompact
const microcompactResult = await deps.microcompact(messages, context);
messages = microcompactResult.messages;
// Context Collapse
if (feature('CONTEXT_COLLAPSE')) {
const collapseResult = await contextCollapse.applyCollapsesIfNeeded(messages);
messages = collapseResult.messages;
}
// Autocompact
const { compactionResult } = await deps.autocompact(messages, context, options);
if (compactionResult) {
const postCompactMessages = buildPostCompactMessages(compactionResult);
messages = postCompactMessages;
}
设计优势:
- 渐进式压缩:从快速到深度,按需选择
- 可配置性:通过 feature flag 控制各层是否启用
- 智能决策:根据上下文情况自动选择压缩策略
五、API 调用与错误恢复机制
5.1 流式处理与工具执行
系统支持工具的流式执行,提升用户体验:
typescript
for await (const message of deps.callModel({
messages: prependUserContext(messagesForQuery, userContext),
systemPrompt: fullSystemPrompt,
tools: toolUseContext.options.tools,
signal: toolUseContext.abortController.signal,
options: {
model: currentModel,
fallbackModel,
fastMode: appState.fastMode,
},
})) {
// 检测工具使用
if (message.type === 'assistant') {
const toolUseBlocks = message.message.content.filter(
content => content.type === 'tool_use'
);
if (toolUseBlocks.length > 0) {
needsFollowUp = true; // 需要执行工具
}
}
}
5.2 多重错误恢复策略
系统实现了多层次的错误恢复:
策略一:模型降级
typescript
if (innerError instanceof FallbackTriggeredError && fallbackModel) {
currentModel = fallbackModel;
yield createSystemMessage(
`Switched to ${fallbackModel} due to high demand...`,
'warning'
);
continue;
}
策略二:响应式压缩
typescript
if (isWithheld413 && reactiveCompact) {
const compacted = await reactiveCompact.tryReactiveCompact({
messages: messagesForQuery,
...
});
if (compacted) {
messages = buildPostCompactMessages(compacted);
continue;
}
}
策略三:输出token限制恢复
typescript
if (maxOutputTokensRecoveryCount < MAX_OUTPUT_TOKENS_RECOVERY_LIMIT) {
const recoveryMessage = createUserMessage({
content: 'Output token limit hit. Resume directly...',
isMeta: true,
});
messages.push(recoveryMessage);
maxOutputTokensRecoveryCount++;
continue;
}
六、会话持久化与数据安全
6.1 消息记录机制
会话持久化是保证用户体验的关键:
typescript
// 消息记录策略
if (persistSession && messagesFromUserInput.length > 0) {
const transcriptPromise = recordTranscript(messages);
// Bare 模式下非阻塞写入
if (isBareMode()) {
void transcriptPromise;
} else {
await transcriptPromise;
// 强制刷新场景
if (isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH)) {
await flushSessionStorage();
}
}
}
记录时机:
- 用户消息接收后立即记录
- 助手消息异步记录
- 压缩边界时刷新
6.2 安全性设计
typescript
// Windows 路径劫持防护
process.env.NoDefaultCurrentDirectoryInExePath = '1';
// Git 命令安全检查
function prefetchSystemContextIfSafe() {
const hasTrust = checkHasTrustDialogAccepted();
if (hasTrust) {
void getSystemContext();
}
}
七、总结与思考
通过深入分析 Claude Code 的对话引擎,我有以下几点深刻体会:
- 分层设计的重要性:QueryEngine 与 query() 的职责分离,使得代码易于维护和扩展
- 压缩策略的精妙:四层压缩策略兼顾了性能和对话质量
- 错误恢复的完整性:多种恢复策略确保系统的鲁棒性
- 安全性的重视:多处安全检查体现了企业级应用的严谨性
下一篇预告: 我们将深入分析 Claude Code 的工具系统设计,揭秘它是如何实现代码执行、文件操作等核心能力的!
八、互动交流
你们觉得这个四层压缩策略设计得怎么样?还有什么更好的方法来处理长对话上下文?欢迎在评论区交流!
如果觉得这篇文章对你有帮助,请点赞关注支持一下,我们下一篇见!🚀
原创不易,点赞关注支持一下!