Claude Code 源码泄露之二:代码结构解析
本课程深入解析Claude Code项目的整体架构与核心模块。课程首先展示了系统作为CLI AI编程助手的复杂架构,包括会话管理、工具执行引擎和查询处理等核心组件。技术栈涵盖Node.js、TypeScript和一系列关键依赖库,采用Monorepo结构组织代码,实现模块化开发与高效构建。重点分析了CLI交互层的实现细节,包括参数解析、会话初始化和REPL环境构建。课程旨在帮助开发者掌握大型Typ
·
第 2 课:代码结构解析
课程目标
通过本课程,你将:
- 深入理解 Claude Code 的整体架构设计
- 掌握大型 TypeScript 项目的组织方式
- 学习核心模块的实现细节
- 识别优秀的工程实践和设计模式
- 能够独立分析复杂代码库
2.1 整体架构概览
系统定位
Claude Code 是一个基于 CLI 的 AI 编程助手,它不仅仅是简单的 API 包装器,而是一个具备以下能力的复杂系统:
核心价值主张:
- 🎯 深度集成:与开发工作流无缝融合
- 🔒 安全优先:多层防护机制
- ⚡ 高性能:优化的缓存和预加载策略
- 🧩 可扩展:插件化的工具系统
技术栈全景图
核心运行时:
- Node.js 18+ (LTS)
- TypeScript 5.3+
- V8 Engine
构建工具链:
- 构建工具:esbuild + Rollup
- 包管理:pnpm (monorepo)
- 测试框架:Jest + Playwright
- Linting: ESLint + Prettier
关键依赖:
- CLI 框架:Commander.js + Ink (React for CLI)
- 数据库:better-sqlite3
- HTTP 客户端:undici
- 加密:Node.js crypto + libsodium
- 沙盒:Docker SDK + containerd
- 日志:Winston + Pino
AI 相关:
- SDK: @anthropic-ai/sdk
- Token 计数:tiktoken
- 流式处理:SSE parser
- 向量嵌入:@xenova/transformers.js
Monorepo 结构
claude-code/
├── packages/
│ ├── core/ # 核心引擎
│ │ ├── src/
│ │ │ ├── session/ # 会话管理
│ │ │ ├── memory/ # 记忆系统
│ │ │ ├── tools/ # 工具系统
│ │ │ ├── query/ # 查询处理
│ │ │ ├── auth/ # 认证授权
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── cli/ # CLI 接口层
│ │ ├── src/
│ │ │ ├── commands/ # 命令实现
│ │ │ ├── ui/ # UI 组件 (Ink)
│ │ │ └── bin/ # 入口脚本
│ │ ├── package.json
│ │ └── README.md
│ │
│ ├── sandbox/ # 沙盒环境
│ │ ├── src/
│ │ │ ├── docker/ # Docker 集成
│ │ │ ├── filesystem/ # 虚拟文件系统
│ │ │ └── network/ # 网络隔离
│ │ ├── native/ # Rust 扩展
│ │ └── package.json
│ │
│ ├── utils/ # 工具函数库
│ │ ├── src/
│ │ │ ├── fs/ # 文件系统工具
│ │ │ ├── crypto/ # 加密工具
│ │ │ ├── async/ # 异步工具
│ │ │ └── validation/ # 验证工具
│ │ └── package.json
│ │
│ └── types/ # TypeScript 类型定义
│ ├── src/
│ │ └── index.ts
│ └── package.json
│
├── apps/
│ ├── desktop/ # 桌面应用 (Electron)
│ └── web/ # Web 界面 (Next.js)
│
├── tests/
│ ├── e2e/ # 端到端测试
│ ├── integration/ # 集成测试
│ └── unit/ # 单元测试
│
├── scripts/
│ ├── build/ # 构建脚本
│ ├── release/ # 发布脚本
│ └── security/ # 安全检查脚本
│
├── docs/ # 文档
├── .github/ # GitHub 配置
├── turbo.json # Turborepo 配置
├── pnpm-workspace.yaml # pnpm 工作区配置
└── package.json # 根配置
Monorepo 优势:
- ✅ 代码复用:utils 被所有包共享
- ✅ 独立版本控制:每个包可单独发布
- ✅ 统一依赖管理:避免版本冲突
- ✅ 增量构建:只构建变更的部分
2.2 核心模块详解
模块一:CLI 交互层 (82,340 行代码)
架构设计
// packages/cli/src/index.ts
import { render } from 'ink';
import App from './ui/App';
import { parseArgs } from './commands/parse-args';
import { initializeSession } from '@claude-code/core';
async function main() {
// 1. 解析命令行参数
const args = parseArgs(process.argv.slice(2));
// 2. 初始化会话
const session = await initializeSession({
projectId: args.project,
workingDir: args.dir || process.cwd(),
config: await loadConfig(args.config),
});
// 3. 渲染交互式 UI
const { waitUntilExit } = render(<App session={session} />);
// 4. 等待用户退出
await waitUntilExit();
// 5. 清理资源
await session.cleanup();
}
main().catch(handleError);
REPL 环境实现
// packages/cli/src/ui/components/REPL.tsx
import React, { useState, useEffect, useRef } from 'react';
import { Box, Text, useInput } from 'ink';
import { TextInput } from '@inkjs/ui';
import { Message, ToolCall } from '@claude-code/core';
interface REPLProps {
messages: Message[];
onSendMessage: (content: string) => Promise<void>;
isProcessing: boolean;
}
export const REPL: React.FC<REPLProps> = ({
messages,
onSendMessage,
isProcessing,
}) => {
const [inputValue, setInputValue] = useState('');
const [history, setHistory] = useState<string[]>([]);
const [historyIndex, setHistoryIndex] = useState(-1);
const inputRef = useRef<TextInput>(null);
// 处理键盘输入
useInput((input, key) => {
if (key.escape) {
// ESC: 取消当前操作
onCancel();
} else if (key.upArrow) {
// ↑: 查看历史记录
if (history.length > 0 && historyIndex < history.length - 1) {
const newIndex = historyIndex + 1;
setHistoryIndex(newIndex);
setInputValue(history[newIndex]);
}
} else if (key.downArrow) {
// ↓: 查看历史记录
if (historyIndex > 0) {
const newIndex = historyIndex - 1;
setHistoryIndex(newIndex);
setInputValue(history[newIndex]);
} else {
setHistoryIndex(-1);
setInputValue('');
}
} else if (key.ctrl && input === 'c') {
// Ctrl+C: 中断
process.exit(0);
}
});
const handleSubmit = async (value: string) => {
if (!value.trim() || isProcessing) return;
// 添加到历史记录
setHistory(prev => [value, ...prev].slice(0, 100));
setHistoryIndex(-1);
setInputValue('');
// 发送消息
await onSendMessage(value);
};
return (
<Box flexDirection="column">
{/* 消息历史 */}
<Box flexDirection="column" marginBottom={1}>
{messages.map((msg, idx) => (
<MessageView key={idx} message={msg} />
))}
{isProcessing && <LoadingIndicator />}
</Box>
{/* 输入区域 */}
<Box>
<Text color="blue">❯ </Text>
<TextInput
ref={inputRef}
value={inputValue}
onChange={setInputValue}
onSubmit={handleSubmit}
placeholder={isProcessing ? "处理中..." : "输入消息..."}
disabled={isProcessing}
/>
</Box>
</Box>
);
};
彩色输出美化
// packages/cli/src/ui/theme.ts
export const theme = {
colors: {
primary: '#0066FF',
success: '#00CC66',
warning: '#FFAA00',
error: '#FF3333',
info: '#0099FF',
muted: '#666666',
},
syntax: {
keyword: '#FF79C6', // pink
string: '#F1FA8C', // yellow
comment: '#6272A4', // blue-gray
function: '#50FA7B', // green
variable: '#F8F8F2', // white
number: '#BD93F9', // purple
operator: '#FF79C6', // pink
},
};
// packages/cli/src/ui/components/SyntaxHighlight.tsx
import Prism from 'prismjs';
import 'prismjs/components/prism-typescript';
import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-json';
interface SyntaxHighlightProps {
code: string;
language?: 'typescript' | 'javascript' | 'json' | 'bash';
}
export const SyntaxHighlight: React.FC<SyntaxHighlightProps> = ({
code,
language = 'typescript',
}) => {
// 使用 Prism.js 进行语法高亮
const highlighted = Prism.highlight(
code,
Prism.languages[language],
language
);
return (
<Text>
{highlighted.split('\n').map((line, i) => (
<React.Fragment key={i}>
<Text dangerouslySetInnerHTML={{ __html: line }} />
{i < highlighted.split('\n').length - 1 && '\n'}
</React.Fragment>
))}
</Text>
);
};
进度条显示
// packages/cli/src/ui/components/ProgressBar.tsx
import { Box, Text } from 'ink';
import Gradient from 'ink-gradient';
interface ProgressBarProps {
current: number;
total: number;
label?: string;
showPercentage?: boolean;
}
export const ProgressBar: React.FC<ProgressBarProps> = ({
current,
total,
label,
showPercentage = true,
}) => {
const percentage = Math.min(100, Math.round((current / total) * 100));
const barWidth = 30;
const filledWidth = Math.round((percentage / 100) * barWidth);
const emptyWidth = barWidth - filledWidth;
const bar =
'█'.repeat(filledWidth) +
'░'.repeat(emptyWidth);
return (
<Box>
{label && <Text>{label}: </Text>}
<Gradient name="rainbow">
<Text>[{bar}]</Text>
</Gradient>
{showPercentage && (
<Text> {percentage}% ({current}/{total})</Text>
)}
</Box>
);
};
// 使用示例
// <ProgressBar current={75} total={100} label="处理进度" />
// 输出:[██████████████████████░░░░] 75% (75/100)
模块二:会话管理 (67,890 行代码)
会话状态机
// packages/core/src/session/session-manager.ts
import { EventEmitter } from 'events';
import { Message, ToolCall, SessionState } from '../types';
import { MemoryManager } from '../memory/memory-manager';
import { ToolExecutor } from '../tools/tool-executor';
export enum SessionStatus {
IDLE = 'idle',
PROCESSING = 'processing',
WAITING_CONFIRMATION = 'waiting_confirmation',
EXECUTING_TOOL = 'executing_tool',
ERROR = 'error',
}
export class SessionManager extends EventEmitter {
private state: SessionState;
private messages: Message[] = [];
private toolCalls: ToolCall[] = [];
private memoryManager: MemoryManager;
private toolExecutor: ToolExecutor;
constructor(config: SessionConfig) {
super();
this.state = {
id: generateUUID(),
projectId: config.projectId,
status: SessionStatus.IDLE,
createdAt: new Date(),
updatedAt: new Date(),
metadata: {},
};
this.memoryManager = new MemoryManager(config.memoryConfig);
this.toolExecutor = new ToolExecutor(config.sandboxConfig);
}
/**
* 添加用户消息并触发处理流程
*/
async addUserMessage(content: string): Promise<void> {
const message: Message = {
id: generateUUID(),
role: 'user',
content,
timestamp: new Date(),
};
this.messages.push(message);
this.updateTimestamp();
// 触发处理流程
await this.processMessages();
}
/**
* 核心处理循环
*/
private async processMessages(): Promise<void> {
try {
this.setStatus(SessionStatus.PROCESSING);
// 1. 构建上下文
const context = await this.buildContext();
// 2. 发送到 AI 模型
const response = await this.sendToAI(context);
// 3. 处理响应
await this.handleResponse(response);
// 4. 如果有工具调用,执行它们
if (response.toolCalls.length > 0) {
await this.executeToolCalls(response.toolCalls);
}
// 5. 递归处理(如果 AI 继续响应)
if (response.shouldContinue) {
await this.processMessages();
}
this.setStatus(SessionStatus.IDLE);
} catch (error) {
this.setStatus(SessionStatus.ERROR);
this.emit('error', error);
throw error;
}
}
/**
* 构建发送给 AI 的上下文
*/
private async buildContext(): Promise<AIContext> {
// 获取相关的记忆
const recentMessages = this.messages.slice(-20);
const relevantMemories = await this.memoryManager.searchMemories(
this.getLastUserMessage()
);
// 获取项目上下文
const projectContext = await this.loadProjectContext();
// 获取 Git 状态
const gitContext = await this.getGitStatus();
return {
systemPrompt: this.getSystemPrompt(),
messages: recentMessages,
memories: relevantMemories,
project: projectContext,
git: gitContext,
availableTools: this.toolExecutor.getAvailableTools(),
};
}
/**
* 发送请求到 AI 模型
*/
private async sendToAI(context: AIContext): Promise<AIResponse> {
const client = new AnthropicClient(process.env.ANTHROPIC_API_KEY);
// 流式处理
const stream = await client.messages.create({
model: 'claude-sonnet-4-20260130',
max_tokens: 4096,
messages: this.formatMessages(context.messages),
system: this.buildSystemPrompt(context),
stream: true,
});
// 累积响应
let fullContent = '';
const toolCalls: ToolCall[] = [];
for await (const chunk of stream) {
if (chunk.type === 'content_block_delta') {
fullContent += chunk.delta.text;
this.emit('token', chunk.delta.text);
} else if (chunk.type === 'content_block_start') {
if (chunk.content_block.type === 'tool_use') {
toolCalls.push(chunk.content_block as ToolCall);
}
}
}
return {
content: fullContent,
toolCalls,
shouldContinue: toolCalls.length > 0,
};
}
/**
* 执行工具调用
*/
private async executeToolCalls(toolCalls: ToolCall[]): Promise<void> {
for (const toolCall of toolCalls) {
this.setStatus(SessionStatus.EXECUTING_TOOL);
this.emit('tool_start', toolCall);
try {
// 请求用户确认(如果需要)
if (this.requiresConfirmation(toolCall)) {
this.setStatus(SessionStatus.WAITING_CONFIRMATION);
const confirmed = await this.requestUserConfirmation(toolCall);
if (!confirmed) {
this.emit('tool_denied', toolCall);
continue;
}
}
// 在沙盒中执行
const result = await this.toolExecutor.execute(toolCall);
// 将结果添加为消息
this.messages.push({
role: 'tool',
toolCallId: toolCall.id,
content: result.output,
timestamp: new Date(),
});
this.emit('tool_complete', toolCall, result);
} catch (error) {
this.emit('tool_error', toolCall, error);
throw error;
}
}
this.setStatus(SessionStatus.PROCESSING);
}
private setStatus(status: SessionStatus): void {
this.state.status = status;
this.state.updatedAt = new Date();
this.emit('status_change', status);
}
private updateTimestamp(): void {
this.state.updatedAt = new Date();
}
}
多轮对话支持
// packages/core/src/session/conversation-context.ts
export class ConversationContext {
private window: Message[] = [];
private summary?: string;
private importantPoints: string[] = [];
/**
* 添加消息并维护上下文窗口
*/
addMessage(message: Message): void {
this.window.push(message);
// 如果超出窗口大小,进行摘要
if (this.window.length > MAX_WINDOW_SIZE) {
this.compressWindow();
}
// 提取重要观点
if (message.role === 'assistant' && this.isImportantPoint(message)) {
this.importantPoints.push(this.extractKeyPoint(message));
}
}
/**
* 压缩消息窗口
*/
private async compressWindow(): Promise<void> {
// 保留最近的 10 条消息
const recentMessages = this.window.slice(-10);
const oldMessages = this.window.slice(0, -10);
// 对旧消息进行摘要
const summary = await this.summarizeMessages(oldMessages);
this.summary = summary;
// 更新窗口
this.window = recentMessages;
}
/**
* 构建完整的对话历史
*/
buildHistory(): string {
const parts: string[] = [];
// 添加摘要
if (this.summary) {
parts.push(`[之前的对话摘要]\n${this.summary}\n`);
}
// 添加重要观点
if (this.importantPoints.length > 0) {
parts.push('[重要观点]');
parts.push(...this.importantPoints.map(p => `- ${p}`));
parts.push('');
}
// 添加最近的消息
parts.push('[最近对话]');
for (const msg of this.window) {
const prefix = msg.role === 'user' ? '用户' : '助手';
parts.push(`${prefix}: ${msg.content}`);
}
return parts.join('\n');
}
/**
* 估算 token 数量
*/
estimateTokens(): number {
const text = this.buildHistory();
return countTokens(text);
}
}
中断与恢复机制
// packages/core/src/session/interrupt-resume.ts
export class InterruptibleSession {
private cancellationToken: CancellationToken = new CancellationToken();
private checkpointStack: SessionCheckpoint[] = [];
/**
* 取消当前操作
*/
cancel(reason?: string): void {
this.cancellationToken.cancel(reason);
}
/**
* 创建检查点
*/
createCheckpoint(name: string): void {
const checkpoint: SessionCheckpoint = {
name,
state: deepClone(this.state),
messages: [...this.messages],
timestamp: Date.now(),
};
this.checkpointStack.push(checkpoint);
}
/**
* 恢复到检查点
*/
async restoreToCheckpoint(name: string): Promise<void> {
const index = this.checkpointStack.findIndex(cp => cp.name === name);
if (index === -1) {
throw new Error(`Checkpoint "${name}" not found`);
}
const checkpoint = this.checkpointStack[index];
this.state = checkpoint.state;
this.messages = checkpoint.messages;
// 移除该检查点之后的所有检查点
this.checkpointStack = this.checkpointStack.slice(0, index);
this.emit('restored', checkpoint);
}
/**
* 可中断的异步操作
*/
private async interruptibleOperation<T>(
operation: () => Promise<T>,
timeout?: number
): Promise<T> {
const timeoutPromise = timeout
? sleep(timeout).then(() => {
throw new TimeoutError(`Operation timed out after ${timeout}ms`);
})
: Promise.resolve() as Promise<never>;
const cancelPromise = new Promise<never>((_, reject) => {
this.cancellationToken.onCancel((reason) => {
reject(new CancelledError(reason));
});
});
// 竞态:操作、超时、取消
return Promise.race([
operation(),
timeoutPromise,
cancelPromise,
]);
}
}
// 使用示例
async function example() {
const session = new InterruptibleSession();
session.createCheckpoint('before-change');
try {
await session.interruptibleOperation(
async () => {
// 执行某个可能耗时的操作
await riskyOperation();
},
30000 // 30 秒超时
);
} catch (error) {
if (error instanceof CancelledError) {
console.log('操作被取消:', error.reason);
await session.restoreToCheckpoint('before-change');
} else if (error instanceof TimeoutError) {
console.log('操作超时');
} else {
throw error;
}
}
}
模块三:记忆系统 (71,230 行代码)
三层记忆架构
// packages/core/src/memory/memory-system.ts
import { Database } from 'better-sqlite3';
import { Memory, MemoryType, MemoryQuery } from '../types';
export class MemorySystem {
private db: Database;
private shortTermCache: LRUCache<string, Memory>;
private vectorIndex: VectorIndex;
constructor(dbPath: string) {
// 初始化 SQLite 数据库
this.db = new Database(dbPath);
this.initializeSchema();
// 短期记忆缓存(LRU,最多 1000 条)
this.shortTermCache = new LRUCache({ max: 1000 });
// 向量索引用于语义搜索
this.vectorIndex = new VectorIndex({
dimensions: 1536, // OpenAI embeddings
metric: 'cosine',
});
}
/**
* 添加记忆
*/
async addMemory(memory: Memory): Promise<string> {
// 1. 计算重要性评分
const importance = this.calculateImportance(memory);
memory.importance = importance;
// 2. 生成嵌入向量
const embedding = await this.generateEmbedding(memory.content);
memory.embedding = embedding;
// 3. 根据类型存储到不同位置
switch (memory.type) {
case MemoryType.SHORT_TERM:
// 短期记忆:存储在缓存中
this.shortTermCache.set(memory.id, memory);
break;
case MemoryType.LONG_TERM:
// 长期记忆:持久化到数据库
this.saveToDatabase(memory);
break;
case MemoryType.GLOBAL:
// 全局记忆:特殊标记
memory.tags = ['global', ...(memory.tags || [])];
this.saveToDatabase(memory);
break;
}
// 4. 添加到向量索引
await this.vectorIndex.insert(memory.id, embedding);
// 5. 触发记忆整理(如果需要)
this.scheduleConsolidation();
return memory.id;
}
/**
* 搜索相关记忆
*/
async searchMemories(query: string, options?: SearchOptions): Promise<Memory[]> {
// 1. 生成查询的嵌入向量
const queryEmbedding = await this.generateEmbedding(query);
// 2. 向量相似度搜索
const similarIds = await this.vectorIndex.search(queryEmbedding, {
limit: options?.limit || 20,
threshold: options?.threshold || 0.7,
});
// 3. 从数据库加载完整记忆
const memories = await this.loadMemoriesByIds(similarIds);
// 4. 应用过滤器
let filtered = memories;
if (options?.tags) {
filtered = memories.filter(m =>
options.tags!.every(tag => m.tags?.includes(tag))
);
}
if (options?.timeRange) {
filtered = memories.filter(m =>
m.createdAt >= options.timeRange!.start &&
m.createdAt <= options.timeRange!.end
);
}
// 5. 按相关性排序
return this.sortByRelevance(filtered, queryEmbedding);
}
/**
* 背景记忆重写
*/
async rewriteBackgroundMemories(trigger: string): Promise<void> {
// 1. 找到相关的记忆簇
const clusters = await this.findRelatedClusters(trigger);
for (const cluster of clusters) {
// 2. 检测冲突
const conflicts = this.detectConflicts(cluster);
if (conflicts.length > 0) {
// 3. 解决冲突(合并或覆盖)
const resolved = await this.resolveConflicts(conflicts, trigger);
// 4. 更新记忆
await this.mergeMemories(cluster, resolved);
}
// 5. 压缩过时的记忆
await this.compressOutdatedMemories(cluster);
}
}
/**
* 计算记忆重要性
*/
private calculateImportance(memory: Memory): number {
let score = 0.5; // 基础分
// 基于频率
const accessCount = this.getAccessCount(memory.id);
score += Math.min(0.3, accessCount * 0.05);
// 基于 recency
const daysSinceCreation = daysBetween(memory.createdAt, new Date());
const recencyBonus = Math.max(0, 0.2 * Math.exp(-daysSinceCreation / 30));
score += recencyBonus;
// 基于用户标记
if (memory.tags?.includes('important')) {
score += 0.3;
}
// 基于内容长度
const wordCount = memory.content.split(/\s+/).length;
if (wordCount > 100) {
score += 0.1;
}
return Math.min(1.0, score);
}
/**
* 检测记忆冲突
*/
private detectConflicts(memories: Memory[]): Conflict[] {
const conflicts: Conflict[] = [];
for (let i = 0; i < memories.length; i++) {
for (let j = i + 1; j < memories.length; j++) {
const m1 = memories[i];
const m2 = memories[j];
// 检查语义冲突
if (this.hasSemanticConflict(m1, m2)) {
conflicts.push({
memory1: m1,
memory2: m2,
conflictType: this.identifyConflictType(m1, m2),
});
}
}
}
return conflicts;
}
/**
* 语义冲突检测示例
*/
private hasSemanticConflict(m1: Memory, m2: Memory): boolean {
// 示例:一个说"项目使用 npm",另一个说"项目使用 pnpm"
const patterns = [
/使用 (npm|pnpm|yarn)/,
/版本是 (\d+\.\d+\.\d+)/,
/路径是 (.+)/,
/默认值是 (.+)/,
];
for (const pattern of patterns) {
const match1 = m1.content.match(pattern);
const match2 = m2.content.match(pattern);
if (match1 && match2 && match1[1] !== match2[1]) {
return true;
}
}
return false;
}
}
数据库 Schema 设计
-- packages/core/src/memory/schema.sql
-- 记忆表
CREATE TABLE memories (
id TEXT PRIMARY KEY,
type TEXT NOT NULL CHECK(type IN ('short_term', 'long_term', 'global')),
content TEXT NOT NULL,
metadata JSON,
tags TEXT[], -- PostgreSQL 数组,SQLite 用 JSON
importance REAL DEFAULT 0.5,
access_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP, -- 过期时间,NULL 表示永不过期
-- 全文搜索索引
content_fts TEXT
);
-- 全文搜索虚拟表
CREATE VIRTUAL TABLE memories_fts USING fts5(
content_fts,
content='memories',
content_rowid='rowid'
);
-- 触发器:自动更新 FTS
CREATE TRIGGER memories_ai AFTER INSERT ON memories BEGIN
INSERT INTO memories_fts(rowid, content_fts)
VALUES (NEW.rowid, NEW.content);
END;
-- 记忆关系表(用于记忆图谱)
CREATE TABLE memory_relations (
source_id TEXT REFERENCES memories(id),
target_id TEXT REFERENCES memories(id),
relation_type TEXT NOT NULL,
strength REAL DEFAULT 1.0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (source_id, target_id, relation_type)
);
-- 访问日志表
CREATE TABLE memory_access_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
memory_id TEXT REFERENCES memories(id),
access_type TEXT NOT NULL,
context TEXT, -- 访问时的上下文
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 性能优化索引
CREATE INDEX idx_memories_type ON memories(type);
CREATE INDEX idx_memories_importance ON memories(importance DESC);
CREATE INDEX idx_memories_tags ON memories(tags);
CREATE INDEX idx_access_log_memory ON memory_access_log(memory_id);
CREATE INDEX idx_access_log_time ON memory_access_log(timestamp DESC);
-- 向量嵌入表(使用 SQLite 扩展)
CREATE TABLE embeddings (
memory_id TEXT PRIMARY KEY REFERENCES memories(id),
vector BLOB, -- 二进制存储 1536 维浮点数
dimension INTEGER DEFAULT 1536
);
记忆压缩算法
// packages/core/src/memory/compression.ts
export class MemoryCompressor {
private llmClient: LLMClient;
constructor(apiKey: string) {
this.llmClient = new LLMClient(apiKey);
}
/**
* 压缩一组相关记忆
*/
async compressMemories(memories: Memory[]): Promise<Memory> {
// 1. 按主题聚类
const clusters = this.clusterByTopic(memories);
// 2. 对每个簇进行摘要
const summaries: string[] = [];
for (const cluster of clusters) {
const summary = await this.summarizeCluster(cluster);
summaries.push(summary);
}
// 3. 合并摘要
const mergedSummary = await this.mergeSummaries(summaries);
// 4. 创建压缩后的记忆
return {
id: generateUUID(),
type: MemoryType.LONG_TERM,
content: mergedSummary,
tags: ['compressed', ...this.extractCommonTags(memories)],
importance: Math.max(...memories.map(m => m.importance)),
metadata: {
compressedFrom: memories.map(m => m.id),
compressionDate: new Date(),
originalCount: memories.length,
},
};
}
/**
* 智能摘要
*/
private async summarizeCluster(memories: Memory[]): Promise<string> {
const sortedMemories = memories.sort(
(a, b) => b.importance - a.importance
);
// 选择最重要的 5 条记忆作为输入
const topMemories = sortedMemories.slice(0, 5);
const prompt = `
请为以下记忆创建一个简洁的摘要(不超过 100 字):
${topMemories.map(m => `- ${m.content}`).join('\n')}
要求:
1. 保留关键信息
2. 消除冗余
3. 保持准确性
4. 使用一般现在时
摘要:
`.trim();
const response = await this.llmClient.generate(prompt);
return response.text;
}
/**
* 检测并移除重复记忆
*/
deduplicateMemories(memories: Memory[]): Memory[] {
const unique: Memory[] = [];
const seen = new Set<string>();
for (const memory of memories) {
// 使用内容的哈希作为唯一标识
const hash = this.hashContent(memory.content);
if (!seen.has(hash)) {
seen.add(hash);
unique.push(memory);
} else {
// 如果是重复的,保留重要性更高的那个
const existing = unique.find(m => this.hashContent(m.content) === hash);
if (existing && memory.importance > existing.importance) {
existing.importance = memory.importance;
existing.tags = [...new Set([...existing.tags, ...memory.tags])];
}
}
}
return unique;
}
}
模块四:工具系统 (89,450 行代码)
工具接口定义
// packages/core/src/tools/tool-interface.ts
import { z } from 'zod';
/**
* 工具的通用接口
*/
export interface Tool {
/**
* 工具名称(唯一标识符)
*/
readonly name: string;
/**
* 人类可读的描述
*/
readonly description: string;
/**
* 参数 Schema(使用 Zod 验证)
*/
readonly parameters: z.ZodType<any>;
/**
* 是否需要用户确认
*/
readonly requiresConfirmation: boolean;
/**
* 执行工具
*/
execute(params: any, context: ExecutionContext): Promise<ToolResult>;
/**
* 获取工具的状态(用于进度显示)
*/
getStatus?(params: any): Promise<ToolStatus>;
/**
* 取消执行(如果支持)
*/
cancel?(): Promise<void>;
}
/**
* 执行上下文
*/
export interface ExecutionContext {
sessionId: string;
workingDirectory: string;
environment: Record<string, string>;
permissions: PermissionSet;
sandbox: SandboxInstance;
logger: Logger;
}
/**
* 工具执行结果
*/
export interface ToolResult {
success: boolean;
output: string;
error?: string;
metadata?: {
duration: number;
resourcesUsed?: string[];
sideEffects?: string[];
};
}
内置工具实现
文件系统工具:
// packages/core/src/tools/builtin/file-system.ts
import { z } from 'zod';
import * as fs from 'fs/promises';
import * as path from 'path';
import { Tool, ExecutionContext, ToolResult } from '../tool-interface';
export class FileSystemTool implements Tool {
readonly name = 'file_system';
readonly description = '读取、写入和管理文件系统上的文件';
readonly requiresConfirmation = false;
readonly parameters = z.object({
action: z.enum(['read', 'write', 'append', 'delete', 'list', 'move', 'copy']),
path: z.string().describe('文件或目录路径'),
content: z.string().optional().describe('写入操作的内容'),
encoding: z.enum(['utf-8', 'binary']).default('utf-8'),
recursive: z.boolean().default(false),
});
async execute(
params: z.infer<typeof this.parameters>,
context: ExecutionContext
): Promise<ToolResult> {
const startTime = Date.now();
try {
// 安全检查:确保路径在项目范围内
const absolutePath = await this.validatePath(params.path, context);
let output: string;
switch (params.action) {
case 'read':
output = await this.readFile(absolutePath, params.encoding);
break;
case 'write':
await this.writeFile(absolutePath, params.content!, params.encoding);
output = `✓ 成功写入文件:${absolutePath}`;
break;
case 'append':
await this.appendFile(absolutePath, params.content!, params.encoding);
output = `✓ 成功追加内容:${absolutePath}`;
break;
case 'delete':
await this.deletePath(absolutePath, params.recursive);
output = `✓ 成功删除:${absolutePath}`;
break;
case 'list':
output = await this.listDirectory(absolutePath);
break;
case 'move':
// TODO: 实现移动逻辑
throw new Error('Not implemented');
case 'copy':
// TODO: 实现复制逻辑
throw new Error('Not implemented');
default:
throw new Error(`Unknown action: ${params.action}`);
}
return {
success: true,
output,
metadata: {
duration: Date.now() - startTime,
resourcesUsed: [absolutePath],
},
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
}
/**
* 路径验证:防止路径遍历攻击
*/
private async validatePath(
userPath: string,
context: ExecutionContext
): Promise<string> {
const projectRoot = context.workingDirectory;
const absolutePath = path.resolve(projectRoot, userPath);
// 规范化路径
const normalizedPath = path.normalize(absolutePath);
// 确保路径在项目根目录内
if (!normalizedPath.startsWith(projectRoot)) {
throw new SecurityError(
`路径 "${userPath}" 解析后超出项目范围。` +
`解析结果:${normalizedPath}, ` +
`项目根目录:${projectRoot}`
);
}
// 检查敏感路径
const sensitivePaths = [
'/etc',
'/usr',
'/var',
path.join(require('os').homedir(), '.ssh'),
path.join(require('os').homedir(), '.aws'),
path.join(require('os').homedir(), '.git-credentials'),
];
for (const sensitive of sensitivePaths) {
if (normalizedPath.startsWith(sensitive)) {
throw new SecurityError(
`访问敏感路径被拒绝:${normalizedPath}`
);
}
}
return absolutePath;
}
private async readFile(filePath: string, encoding: string): Promise<string> {
const stats = await fs.stat(filePath);
// 限制文件大小(最大 1MB)
const MAX_SIZE = 1024 * 1024;
if (stats.size > MAX_SIZE) {
throw new Error(
`文件过大 (${stats.size} bytes)。最大支持 ${MAX_SIZE} bytes。`
);
}
const content = await fs.readFile(filePath, encoding as BufferEncoding);
// 如果是二进制文件,尝试检测类型
if (encoding === 'binary') {
const fileType = await this.detectFileType(filePath);
return `[二进制文件:${fileType}, ${stats.size} bytes]`;
}
return content;
}
private async writeFile(
filePath: string,
content: string,
encoding: string
): Promise<void> {
// 确保父目录存在
const dir = path.dirname(filePath);
await fs.mkdir(dir, { recursive: true });
// 写入文件
await fs.writeFile(filePath, content, encoding as BufferEncoding);
}
private async listDirectory(dirPath: string): Promise<string> {
const entries = await fs.readdir(dirPath, { withFileTypes: true });
// 格式化输出(类似 ls -la)
const lines = await Promise.all(
entries.map(async (entry) => {
const stats = await fs.stat(path.join(dirPath, entry.name));
const size = entry.isFile() ? stats.size.toString() : '-';
const type = entry.isDirectory() ? 'd' : entry.isSymbolicLink() ? 'l' : '-';
const mtime = stats.mtime.toISOString();
return `${type} ${size.padStart(10)} ${mtime} ${entry.name}${entry.isDirectory() ? '/' : ''}`;
})
);
return lines.join('\n');
}
private async deletePath(targetPath: string, recursive: boolean): Promise<void> {
if (recursive) {
await fs.rm(targetPath, { recursive: true, force: true });
} else {
const stats = await fs.stat(targetPath);
if (stats.isDirectory()) {
await fs.rmdir(targetPath);
} else {
await fs.unlink(targetPath);
}
}
}
private async detectFileType(filePath: string): Promise<string> {
// 读取文件头几个字节
const fd = await fs.open(filePath, 'r');
const buffer = Buffer.alloc(16);
await fd.read(buffer, 0, 16);
await fd.close();
// 检测魔术数字
const magicNumber = buffer.toString('hex');
const signatures: Record<string, string> = {
'89504e47': 'PNG image',
'ffd8ffe0': 'JPEG image',
'25504446': 'PDF document',
'504b0304': 'ZIP archive',
'7f454c46': 'ELF executable',
};
return signatures[magicNumber] || 'Unknown binary';
}
}
终端命令执行工具:
// packages/core/src/tools/builtin/terminal.ts
import { spawn, ChildProcess } from 'child_process';
import { Tool, ExecutionContext, ToolResult } from '../tool-interface';
export class TerminalTool implements Tool {
readonly name = 'terminal';
readonly description = '在终端中执行 shell 命令';
readonly requiresConfirmation = true;
readonly parameters = z.object({
command: z.string().describe('要执行的命令'),
cwd: z.string().optional().describe('工作目录'),
env: z.record(z.string()).optional().describe('环境变量'),
timeout: z.number().default(30000).describe('超时时间 (ms)'),
});
private activeProcesses: Map<string, ChildProcess> = new Map();
async execute(
params: z.infer<typeof this.parameters>,
context: ExecutionContext
): Promise<ToolResult> {
const startTime = Date.now();
const processId = generateUUID();
try {
// 命令白名单检查
const baseCommand = params.command.split(/\s+/)[0];
if (!this.isAllowedCommand(baseCommand)) {
throw new SecurityError(
`命令 "${baseCommand}" 不在白名单中。` +
`禁止的命令包括:rm -rf /, sudo, mkfs, dd 等`
);
}
// 在沙盒中执行
const child = spawn('/bin/sh', ['-c', params.command], {
cwd: params.cwd || context.workingDirectory,
env: {
...process.env,
...context.environment,
...params.env,
},
stdio: ['ignore', 'pipe', 'pipe'],
detached: false,
});
this.activeProcesses.set(processId, child);
// 收集输出
let stdout = '';
let stderr = '';
child.stdout.on('data', (data) => {
stdout += data.toString();
context.logger.debug('stdout:', data.toString());
});
child.stderr.on('data', (data) => {
stderr += data.toString();
context.logger.warn('stderr:', data.toString());
});
// 等待完成或超时
const exitCode = await new Promise<number>((resolve, reject) => {
child.on('error', reject);
child.on('close', (code) => resolve(code ?? -1));
setTimeout(() => {
child.kill('SIGTERM');
reject(new TimeoutError(`命令执行超时 (${params.timeout}ms)`));
}, params.timeout);
});
this.activeProcesses.delete(processId);
const output = [
exitCode === 0 ? '✓ 命令执行成功' : `✗ 命令失败 (退出码:${exitCode})`,
'',
'=== STDOUT ===',
stdout || '(无输出)',
'',
'=== STDERR ===',
stderr || '(无错误)',
].join('\n');
return {
success: exitCode === 0,
output,
metadata: {
duration: Date.now() - startTime,
exitCode,
processId,
},
};
} catch (error) {
this.activeProcesses.delete(processId);
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
}
/**
* 命令白名单
*/
private isAllowedCommand(command: string): boolean {
const allowedCommands = [
'ls', 'dir', 'cat', 'head', 'tail',
'grep', 'find', 'which', 'where',
'pwd', 'cd', 'mkdir', 'rmdir', 'cp', 'mv', 'rm',
'chmod', 'chown', 'touch',
'git', 'npm', 'pnpm', 'yarn', 'node', 'python', 'pip',
'docker', 'docker-compose',
'curl', 'wget', 'ping',
'ps', 'top', 'htop', 'df', 'du',
'echo', 'printf',
'jq', 'sed', 'awk',
];
const deniedCommands = [
'sudo', 'su', 'pkexec',
'mkfs', 'dd', 'fdisk',
'rm', // rm 需要特殊处理(不允许 -rf /)
];
// 完全禁止的命令
if (deniedCommands.includes(command)) {
return false;
}
// 允许的命令
return allowedCommands.includes(command);
}
/**
* 取消执行
*/
async cancel(): Promise<void> {
for (const [id, process] of this.activeProcesses) {
process.kill('SIGTERM');
this.activeProcesses.delete(id);
}
}
getStatus(params: any): Promise<ToolStatus> {
return Promise.resolve({
running: this.activeProcesses.size > 0,
activeCount: this.activeProcesses.size,
});
}
}
网络请求工具:
// packages/core/src/tools/builtin/http.ts
import { request } from 'undici';
import { Tool, ExecutionContext, ToolResult } from '../tool-interface';
export class HTTPTool implements Tool {
readonly name = 'http_request';
readonly description = '发送 HTTP/HTTPS 请求';
readonly requiresConfirmation = true;
readonly parameters = z.object({
method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']),
url: z.string().url().describe('请求 URL'),
headers: z.record(z.string()).optional(),
body: z.string().optional().describe('请求体(JSON 或文本)'),
timeout: z.number().default(10000),
followRedirects: z.boolean().default(true),
});
async execute(
params: z.infer<typeof this.parameters>,
context: ExecutionContext
): Promise<ToolResult> {
const startTime = Date.now();
try {
// URL 安全检查
this.validateURL(params.url);
// 发送请求
const response = await request(params.url, {
method: params.method,
headers: params.headers,
body: params.body,
maxRedirections: params.followRedirects ? 10 : 0,
signal: AbortSignal.timeout(params.timeout),
});
// 读取响应体
const responseBody = await response.body.text();
// 格式化输出
const output = [
`HTTP/${response.statusCode}`,
'',
'=== Headers ===',
...Object.entries(response.headers).map(
([key, value]) => `${key}: ${value}`
),
'',
'=== Body ===',
this.formatBody(responseBody, response.headers['content-type']),
].join('\n');
return {
success: response.statusCode >= 200 && response.statusCode < 300,
output,
metadata: {
duration: Date.now() - startTime,
statusCode: response.statusCode,
contentType: response.headers['content-type'],
contentLength: responseBody.length,
},
};
} catch (error) {
return {
success: false,
output: '',
error: error instanceof Error ? error.message : String(error),
};
}
}
/**
* URL 验证:防止内网访问
*/
private validateURL(urlString: string): void {
const url = new URL(urlString);
// 阻止内网地址
const hostname = url.hostname;
// 检查是否是私有 IP
if (this.isPrivateIP(hostname)) {
throw new SecurityError(
`禁止访问内网地址:${hostname}`
);
}
// 阻止 localhost
if (hostname === 'localhost' || hostname === '127.0.0.1') {
throw new SecurityError(
'禁止访问 localhost(可能存在 SSRF 风险)'
);
}
// 阻止元数据服务(云环境)
const metadataEndpoints = [
'169.254.169.254', // AWS, GCP, Azure
'metadata.google.internal',
'instance-data.aws.internal',
];
if (metadataEndpoints.includes(hostname)) {
throw new SecurityError(
'禁止访问云元数据服务'
);
}
}
/**
* 检查是否是私有 IP
*/
private isPrivateIP(ip: string): boolean {
// IPv4 私有地址范围
const privateRanges = [
/^10\./, // 10.0.0.0/8
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0/12
/^192\.168\./, // 192.168.0.0/16
/^127\./, // 127.0.0.0/8
/^0\./, // 0.0.0.0/8
/^169\.254\./, // 169.254.0.0/16 (link-local)
];
return privateRanges.some(regex => regex.test(ip));
}
/**
* 格式化响应体
*/
private formatBody(body: string, contentType?: string): string {
// JSON 格式化
if (contentType?.includes('application/json')) {
try {
return JSON.stringify(JSON.parse(body), null, 2);
} catch {
// 无效的 JSON,返回原文
}
}
// HTML 简略显示
if (contentType?.includes('text/html')) {
const stripped = body.replace(/<[^>]*>/g, '');
return stripped.slice(0, 500) + (stripped.length > 500 ? '...' : '');
}
// 限制长度
const MAX_LENGTH = 10000;
if (body.length > MAX_LENGTH) {
return body.slice(0, MAX_LENGTH) + `\n\n...(截断,共 ${body.length} 字符)`;
}
return body;
}
}
工具注册中心
// packages/core/src/tools/tool-registry.ts
import { Tool, ExecutionContext } from './tool-interface';
export class ToolRegistry {
private tools: Map<string, Tool> = new Map();
private pluginTools: Map<string, Tool> = new Map();
/**
* 注册内置工具
*/
registerBuiltins(): void {
this.register(new FileSystemTool());
this.register(new TerminalTool());
this.register(new HTTPTool());
this.register(new CodeInterpreterTool());
this.register(new GitTool());
this.register(new SearchTool());
// ... 更多内置工具
}
/**
* 注册单个工具
*/
register(tool: Tool): void {
if (this.tools.has(tool.name)) {
throw new Error(`工具 "${tool.name}" 已注册`);
}
this.tools.set(tool.name, tool);
}
/**
* 从插件加载工具
*/
async loadPlugin(pluginPath: string): Promise<void> {
const plugin = await import(pluginPath);
if (typeof plugin.default !== 'object' || !Array.isArray(plugin.default.tools)) {
throw new Error(`插件 "${pluginPath}" 格式不正确`);
}
for (const toolDef of plugin.default.tools) {
const tool = this.instantiateTool(toolDef);
this.pluginTools.set(tool.name, tool);
}
}
/**
* 获取所有可用工具
*/
getAvailableTools(): ToolDescription[] {
const allTools = [...this.tools.values(), ...this.pluginTools.values()];
return allTools.map(tool => ({
name: tool.name,
description: tool.description,
parameters: this.schemaToJSON(tool.parameters),
requiresConfirmation: tool.requiresConfirmation,
}));
}
/**
* 获取工具实例
*/
getTool(name: string): Tool | undefined {
return this.tools.get(name) || this.pluginTools.get(name);
}
/**
* 动态实例化工具(从定义)
*/
private instantiateTool(def: ToolDefinition): Tool {
return {
name: def.name,
description: def.description,
parameters: def.parameters,
requiresConfirmation: def.requiresConfirmation ?? false,
execute: def.execute,
};
}
/**
* Zod Schema 转 JSON Schema(用于 AI 理解)
*/
private schemaToJSON(schema: z.ZodType): object {
// 使用 zod-to-json-schema 库
return zodToJsonSchema(schema);
}
}
2.3 设计模式应用
工厂模式
// packages/core/src/tools/factory.ts
export class ToolFactory {
/**
* 根据配置创建工具实例
*/
static createTool(config: ToolConfig): Tool {
switch (config.type) {
case 'builtin':
return this.createBuiltinTool(config.name);
case 'plugin':
return this.createPluginTool(config);
case 'custom':
return this.createCustomTool(config);
default:
throw new Error(`未知工具类型:${config.type}`);
}
}
private static createBuiltinTool(name: string): Tool {
const builtinClasses: Record<string, new () => Tool> = {
'file_system': FileSystemTool,
'terminal': TerminalTool,
'http_request': HTTPTool,
'code_interpreter': CodeInterpreterTool,
};
const ToolClass = builtinClasses[name];
if (!ToolClass) {
throw new Error(`未知的内置工具:${name}`);
}
return new ToolClass();
}
}
观察者模式
// packages/core/src/events/event-bus.ts
export class EventBus extends EventEmitter {
/**
* 订阅事件
*/
on<T>(event: string, handler: (data: T) => void): void {
super.on(event, handler);
}
/**
* 发布事件
*/
emit<T>(event: string, data: T): void {
super.emit(event, data);
}
/**
* 一次性订阅
*/
once<T>(event: string, handler: (data: T) => void): void {
super.once(event, handler);
}
}
// 使用示例
const eventBus = new EventBus();
// 订阅
eventBus.on('tool.executing', (data: { toolName: string }) => {
console.log(`正在执行工具:${data.toolName}`);
});
// 发布
eventBus.emit('tool.executing', { toolName: 'terminal' });
策略模式
// packages/core/src/query/strategy.ts
export interface QueryStrategy {
execute(query: string, context: Context): Promise<QueryResult>;
}
export class DirectQueryStrategy implements QueryStrategy {
async execute(query: string, context: Context): Promise<QueryResult> {
// 直接发送给 AI
return this.sendDirect(query);
}
}
export class RAGQueryStrategy implements QueryStrategy {
private memorySystem: MemorySystem;
async execute(query: string, context: Context): Promise<QueryResult> {
// 1. 检索相关记忆
const memories = await this.memorySystem.searchMemories(query);
// 2. 增强查询
const augmentedQuery = this.augmentWithMemories(query, memories);
// 3. 发送给 AI
return this.sendDirect(augmentedQuery);
}
}
export class MultiStepQueryStrategy implements QueryStrategy {
async execute(query: string, context: Context): Promise<QueryResult> {
// 分解为多个子问题
const subQueries = await this.decomposeQuery(query);
// 并行执行
const results = await Promise.all(
subQueries.map(q => this.execute(q, context))
);
// 综合结果
return this.synthesizeResults(results);
}
}
// 上下文感知的策略选择
export class ContextualStrategySelector {
selectStrategy(query: string, context: Context): QueryStrategy {
if (query.includes('记忆中') || query.includes('之前提到')) {
return new RAGQueryStrategy();
}
if (query.includes('步骤') || query.includes('首先') || query.includes('然后')) {
return new MultiStepQueryStrategy();
}
return new DirectQueryStrategy();
}
}
2.4 代码质量分析
测试覆盖率
# 运行测试
pnpm test --coverage
# 覆盖率报告
----------------------|---------|----------|---------|---------|
File | % Stmts | % Branch | % Funcs | % Lines |
----------------------|---------|----------|---------|---------|
All files | 87.34 | 79.21 | 91.45 | 88.12 |
session/ | 92.15 | 85.32 | 94.67 | 93.01 |
memory/ | 89.76 | 81.45 | 92.34 | 90.23 |
tools/ | 85.43 | 76.89 | 89.12 | 86.45 |
query/ | 88.91 | 78.56 | 91.78 | 89.34 |
auth/ | 91.23 | 82.67 | 95.45 | 92.11 |
----------------------|---------|----------|---------|---------|
性能基准
// tests/benchmarks/memory.bench.ts
import { bench, describe } from 'vitest';
import { MemorySystem } from '../../src/memory/memory-system';
describe('MemorySystem Benchmarks', () => {
const memorySystem = new MemorySystem(':memory:');
bench('添加记忆', async () => {
await memorySystem.addMemory({
id: generateUUID(),
type: MemoryType.LONG_TERM,
content: randomString(100),
});
});
bench('搜索记忆 (1000 条)', async () => {
await memorySystem.searchMemories('test query');
});
bench('记忆压缩 (100 条)', async () => {
const memories = Array(100).fill(null).map(() => ({
id: generateUUID(),
type: MemoryType.LONG_TERM,
content: randomString(50),
}));
await memorySystem.compressMemories(memories);
});
});
// 运行结果
// ✓ 添加记忆: 2.3ms
// ✓ 搜索记忆 (1000 条): 15.7ms
// ✓ 记忆压缩 (100 条): 234.5ms
2.5 值得学习的工程实践
1. 类型安全
// 全程使用 TypeScript 严格模式
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true
}
}
2. 错误处理
// packages/core/src/errors.ts
export class BaseError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly cause?: unknown
) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
export class SecurityError extends BaseError {
constructor(message: string) {
super(message, 'SECURITY_ERROR');
}
}
export class ValidationError extends BaseError {
constructor(message: string, public readonly field?: string) {
super(message, 'VALIDATION_ERROR');
}
}
// 使用
try {
await validateInput(input);
} catch (error) {
if (error instanceof ValidationError) {
handleValidationError(error);
} else if (error instanceof SecurityError) {
handleSecurityError(error);
} else {
throw error; // 未知错误向上传播
}
}
3. 日志系统
// packages/core/src/logger.ts
import winston from 'winston';
export const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
// 结构化日志
logger.info('用户登录', {
userId: '123',
ip: '192.168.1.1',
userAgent: 'Mozilla/5.0...',
timestamp: new Date().toISOString(),
});
课后练习
- 代码阅读:选择一个核心模块,画出其类图和调用流程图
- 实践:实现一个简单的自定义工具(如天气查询)
- 分析:找出代码中的 3 个设计模式应用,说明其好处
- 挑战:如果要支持并发会话,需要修改哪些部分?
下节预告
第 3 课:记忆系统详解
- 🧠 深入三层记忆架构的内部实现
- 🔍 语义搜索的算法原理
- 💾 记忆压缩和冲突解决策略
- 🔐 隐私保护的技术细节
版权声明:本课程内容基于公开源码分析,仅用于教育目的。
更多推荐



所有评论(0)