From ca5096a259b997125dcfa415153f6f3456915837 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 4 Apr 2026 02:06:30 +0800 Subject: [PATCH 1/2] feat: add 4 deep-dive comparisons (instruction/MDM/telemetry/token) Four new comparison articles based on Claude Code v2.1.89 and Qwen Code v0.15.0: 1. instruction-loading-deep-dive.md (274 lines) - CLAUDE.md 6-layer hierarchy vs QWEN.md 3-layer - @include directives (both support, 5-level nesting) - Frontmatter path filtering (Claude only) - Conditional rules, HTML comment stripping, auto-memory 2. mdm-enterprise-deep-dive.md (166 lines) - Claude: macOS plist + Windows Registry + drop-in dir + remote API - Qwen: file-based only, no MDM - 5-level First-Source-Wins policy precedence 3. telemetry-architecture-deep-dive.md (181 lines) - Claude: 505 tengu_ events + 1P Logger + Perfetto tracing - Qwen: 50 events + QwenLogger RUM + OTLP - Privacy controls comparison 4. token-estimation-deep-dive.md (231 lines) - Claude: API real-time counting + VCR cache + thinking budget - Qwen: static pattern matching (82 models) + effort levels - Natural language budget parsing ("+500k", "spend 2M") Co-Authored-By: Claude Opus 4.6 (1M context) --- .../instruction-loading-deep-dive.md | 274 ++++++++++++++++++ docs/comparison/mdm-enterprise-deep-dive.md | 166 +++++++++++ .../telemetry-architecture-deep-dive.md | 181 ++++++++++++ docs/comparison/token-estimation-deep-dive.md | 231 +++++++++++++++ 4 files changed, 852 insertions(+) create mode 100644 docs/comparison/instruction-loading-deep-dive.md create mode 100644 docs/comparison/mdm-enterprise-deep-dive.md create mode 100644 docs/comparison/telemetry-architecture-deep-dive.md create mode 100644 docs/comparison/token-estimation-deep-dive.md diff --git a/docs/comparison/instruction-loading-deep-dive.md b/docs/comparison/instruction-loading-deep-dive.md new file mode 100644 index 00000000..ac3d6773 --- /dev/null +++ b/docs/comparison/instruction-loading-deep-dive.md @@ -0,0 +1,274 @@ +# 指令文件加载 Deep-Dive + +> CLAUDE.md vs QWEN.md——项目指令如何被发现、解析和注入到系统提示?本文基于 Claude Code(v2.1.89 源码分析)和 Qwen Code(v0.15.0 开源)的源码分析,对比两者在指令文件发现层级、`@include` 指令、Frontmatter 路径过滤和信任模型方面的设计差异。 + +--- + +## 1. 架构总览 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| **指令文件名** | `CLAUDE.md`, `CLAUDE.local.md`, `.claude/rules/*.md` | `QWEN.md`, `AGENTS.md`(可配置) | +| **层级数** | 6 层(Managed/User/Project/Local/AutoMem/TeamMem) | 3 层(Global/Home/Project) | +| **@include 指令** | ✅ 5 层嵌套,循环检测,路径验证 | ✅ 5 层嵌套,循环检测,路径验证 | +| **Frontmatter 路径过滤** | ✅ `paths:` glob 模式,条件规则 | ❌ | +| **HTML 注释剥离** | ✅ | ❌ | +| **条件规则(按文件路径)** | ✅ `.claude/rules/*.md` + `paths:` frontmatter | ❌ | +| **信任模型** | `hasTrustDialogAccepted` + 外部 include 审批 | `folderTrust` 布尔值 | +| **Auto Memory** | ✅ `MEMORY.md`(200 行 / 25KB 截断) | ❌ | +| **Team Memory** | ✅(feature-gated) | ❌ | +| **Hook 事件** | ✅ `InstructionsLoaded`(含加载原因) | ❌ | + +--- + +## 2. Claude Code:六层指令体系 + +### 2.1 发现层级(优先级从低到高) + +``` +1. Managed Memory /etc/claude-code/CLAUDE.md(全局策略,管理员设置) + ↓ +2. User Memory ~/.claude/CLAUDE.md(用户全局,所有项目) + ↓ +3. Project Memory 从 CWD 向上遍历到项目根: + ├── CLAUDE.md + ├── .claude/CLAUDE.md + └── .claude/rules/*.md(条件和非条件规则) + ↓ +4. Local Memory CLAUDE.local.md(项目本地,不提交到 Git) + ↓ +5. Auto Memory .claude/projects//memory/MEMORY.md(自动学习) + ↓ +6. Team Memory API 同步的团队记忆(feature-gated) +``` + +**目录遍历逻辑**(源码: `claudemd.ts#L790-L977`): +- 从 CWD 向上遍历到文件系统根 +- 在项目根处停止(git/hg/svn 边界) +- Git worktree 特殊处理:避免从主仓库重复加载 +- 距 CWD 更近的文件优先级更高(后加载覆盖先加载) + +> 源码: `utils/claudemd.ts`(~2,300 行) + +### 2.2 @include 指令 + +**语法**: + +```markdown +参考 @./src/CODING_STANDARDS.md 中的编码规范 +数据库模型定义见 @./docs/schema.md#models +用户指南: @~/shared-docs/guide.md +``` + +**路径解析规则**: + +| 语法 | 解析方式 | +|------|----------| +| `@path` | 相对于包含文件所在目录 | +| `@./path` | 相对路径(同上) | +| `@~/path` | Home 目录 | +| `@/path` | 绝对路径 | +| `@path#fragment` | 自动剥离 `#` 后缀 | +| `@path\ with\ spaces` | 反斜杠转义空格 | + +**安全约束**(源码: `claudemd.ts#L626-L667`): +- 最大嵌套深度:**5 层** +- 循环引用检测:`Set` 存储已处理文件的规范路径 +- Symlink 解析后加入已处理集合 +- 外部文件(项目目录外)需 `hasClaudeMdExternalIncludesApproved` 审批 + +**代码区域排除**(源码: `claudemd.ts#L451-L535`): +- `@include` 不在以下区域内解析: + - HTML 注释 `` + - 围栏代码块 ` ```...``` ` + - 行内代码 `` `...` `` + +### 2.3 Frontmatter 路径过滤 + +```yaml +--- +paths: + - src/**/*.ts + - !src/generated/** +description: TypeScript 编码规范 +--- + +# TypeScript Rules +这些规则仅在模型操作匹配 `src/**/*.ts` 的文件时生效。 +``` + +**实现**(源码: `frontmatterParser.ts#L254-L279`): +- `paths:` 字段支持 YAML 列表或逗号分隔字符串 +- 使用 `ignore` 库(picomatch)进行 glob 匹配 +- `**` 视为无约束(全局适用) +- 无 `paths:` 的规则始终适用 + +**条件规则加载策略**: +1. **急加载**:无 `paths:` frontmatter 的规则在会话启动时加载 +2. **惰加载**:有 `paths:` 的规则仅在模型触及匹配文件时加载 + +### 2.4 HTML 注释剥离 + +```markdown + +# 对模型的指令 +这些内容会出现在系统提示中。 +``` + +源码: `claudemd.ts#L292-L334`。使用 marked lexer 识别块级 HTML 注释,保留代码块内的注释。 + +### 2.5 Auto Memory(MEMORY.md) + +``` +路径: .claude/projects//memory/MEMORY.md +截断: 200 行 / 25,000 字节(先行截断,再字节截断) +``` + +> 源码: `memdir/memdir.ts#L57-L103` + +### 2.6 系统提示注入 + +```typescript +// 源码: context.ts#L155-L189 +// 注入为 claudeMd 上下文键,前缀: +"Codebase and user instructions are shown below. + Be sure to adhere to these instructions. + IMPORTANT: These instructions OVERRIDE any default behavior + and you MUST follow them exactly as written." +// 每个文件: "Contents of {path} ({description}):\n\n{content}" +``` + +### 2.7 InstructionsLoaded Hook + +```typescript +// 源码: utils/hooks.ts#L4356-L4362 +{ + file_path: string, + memory_type: 'User' | 'Project' | 'Local' | 'Managed', + load_reason: 'session_start' | 'include' | 'compact', + globs?: string[], // 条件规则的 glob 模式 + trigger_file_path?: string, // 触发惰加载的文件 + parent_file_path?: string, // 包含此文件的父文件 +} +``` + +--- + +## 3. Qwen Code:三层指令体系 + +### 3.1 发现层级 + +``` +1. Global Memory ~/.qwen/QWEN.md(用户全局) + ↓ +2. Home Memory ~/QWEN.md(仅当 CWD 在 Home 时) + ↓ +3. Project Memory 从 CWD 向上遍历到 git 根: + ├── QWEN.md + └── AGENTS.md +``` + +**文件名可配置**(源码: `memoryTool.ts#L78-L113`): + +```typescript +setGeminiMdFilename('MY_CUSTOM.md') // 替换默认文件名 +getAllGeminiMdFilenames() // → ['QWEN.md', 'AGENTS.md'] +``` + +**发现逻辑**(源码: `memoryDiscovery.ts#L68-L217`): +- 并发限制 10 防止 EMFILE 错误 +- Set 去重避免重复加载 +- 支持 `includeDirectoriesToReadGemini` 配置扩展搜索目录 + +### 3.2 @include 指令 + +Qwen Code **也支持** @include(源码: `memoryImportProcessor.ts`): + +**语法**:与 Claude Code 相同(`@./path`、`@/path`) + +**两种导入格式**: + +| 格式 | 标记 | 默认 | +|------|------|------| +| **Tree**(递归内联) | `` | ✅ | +| **Flat**(扁平列表) | `--- File: {path} ---` | — | + +**安全约束**(源码: `memoryImportProcessor.ts#L402-L417`): +- 最大嵌套深度:**5 层**(与 Claude Code 相同) +- 路径验证:必须在 `allowedDirectories`(项目根)内 +- 拒绝 URL(`file://`、`http://`、`https://`) + +**区别**: +- 不排除 HTML 注释内的 @include +- 支持两种导入格式(Claude Code 仅一种) + +### 3.3 系统提示注入 + +```typescript +// 源码: qwen-code/packages/core/src/core/prompts.ts#L78-L118 +// 结构: +// {customInstruction} +// --- +// {userMemory} ← 指令文件内容 +// --- +// {appendInstruction} +``` + +### 3.4 .qwenignore + +Qwen Code 支持 `.qwenignore`(gitignore 语法)排除文件,Claude Code 使用 `claudeMdExcludes` 设置。 + +--- + +## 4. 逐维度对比 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| 层级数 | 6(含 AutoMem + TeamMem) | 3 | +| 文件名 | 固定(CLAUDE.md / CLAUDE.local.md) | 可配置 | +| @include 深度 | 5 | 5 | +| @include 格式 | 单一(内联) | 两种(Tree / Flat) | +| HTML 注释剥离 | ✅ | ❌ | +| Frontmatter | ✅ paths + description + allowed-tools | ❌ | +| 条件规则 | ✅(.claude/rules/*.md + paths: glob) | ❌ | +| 急/惰加载 | ✅(无 paths 急加载,有 paths 惰加载) | 全部急加载 | +| 信任模型 | 多级(Dialog + External Include 审批) | 布尔值 | +| Auto Memory | ✅(MEMORY.md,200 行截断) | ❌ | +| Team Memory | ✅(API 同步) | ❌ | +| Hook | ✅ InstructionsLoaded | ❌ | +| 排除机制 | claudeMdExcludes 设置 | .qwenignore 文件 | +| Worktree 处理 | ✅ 去重 | ❌ | + +--- + +## 5. 设计启示 + +1. **条件规则是高价值功能**:`paths:` frontmatter 让团队可以为 `src/`、`tests/`、`docs/` 设置不同的编码规范,而不是一份 CLAUDE.md 塞满所有规则 +2. **HTML 注释剥离**允许在指令文件中留下人读注释(如解释为什么某条规则存在),而不污染 token 预算 +3. **惰加载条件规则**是 token 效率与覆盖面的平衡——只在需要时加载相关规则,避免系统提示膨胀 +4. **信任模型**的复杂度与安全需求成正比——Claude Code 的多级信任适合企业场景,Qwen Code 的布尔值适合个人开发者 + +--- + +## 6. 关键源码文件 + +### Claude Code + +| 文件 | 行数 | 职责 | +|------|------|------| +| `utils/claudemd.ts` | ~2,300 | 指令发现/解析/@include/注释剥离 | +| `utils/frontmatterParser.ts` | ~279 | Frontmatter 解析(paths/description) | +| `context.ts` | L155-L189 | 系统提示注入 | +| `memdir/memdir.ts` | ~103 | MEMORY.md 加载与截断 | +| `utils/config.ts` | L697-L762 | Trust Dialog 逻辑 | + +### Qwen Code + +| 文件 | 行数 | 职责 | +|------|------|------| +| `packages/core/src/utils/memoryDiscovery.ts` | ~217 | 文件发现(3 层) | +| `packages/core/src/utils/memoryImportProcessor.ts` | ~417 | @include 处理(Tree/Flat 格式) | +| `packages/core/src/tools/memoryTool.ts` | ~113 | 文件名配置与存储路径 | +| `packages/core/src/core/prompts.ts` | L78-L118 | 系统提示注入 | + +> **免责声明**: 以上分析基于 2026 年 Q1 源码(Claude Code v2.1.89、Qwen Code v0.15.0),后续版本可能已变更。 diff --git a/docs/comparison/mdm-enterprise-deep-dive.md b/docs/comparison/mdm-enterprise-deep-dive.md new file mode 100644 index 00000000..e0dc2b21 --- /dev/null +++ b/docs/comparison/mdm-enterprise-deep-dive.md @@ -0,0 +1,166 @@ +# MDM 企业配置管理 Deep-Dive + +> 企业如何集中管控开发者的 AI Agent 配置?本文基于 Claude Code(v2.1.89 源码分析)和 Qwen Code(v0.15.0 开源)的源码分析,对比两者在 MDM(Mobile Device Management)企业策略、配置层级和远程设置管理方面的差异。 + +--- + +## 1. 架构总览 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| **macOS plist** | ✅ `com.anthropic.claudecode` domain | ❌ | +| **Windows Registry** | ✅ `HKLM\SOFTWARE\Policies\ClaudeCode` | ❌ | +| **Linux 文件策略** | ✅ `/etc/claude-code/managed-settings.json` | ❌ | +| **Drop-in 目录** | ✅ `managed-settings.d/*.json`(systemd 风格) | ❌ | +| **远程策略 API** | ✅ 带 SHA256 校验的 HTTP 缓存 | ❌ | +| **策略优先级** | 5 级(Remote > HKLM > file > drop-in > HKCU) | — | +| **文件级配置** | ✅ settings.json + settings.local.json | ✅ settings.json | + +--- + +## 2. Claude Code:五级策略体系 + +### 2.1 策略来源优先级(First-Source-Wins) + +``` +1. Remote Managed Settings API 远程策略(最高优先级) + ↓ 未设置时 +2. HKLM / plist 管理员 MDM 配置文件 + ↓ 未设置时 +3. managed-settings.json 文件策略(需管理员权限) + ↓ 未设置时 +4. managed-settings.d/*.json Drop-in 目录(字母序合并) + ↓ 未设置时 +5. HKCU 用户级注册表(最低优先级) +``` + +**First-Source-Wins 语义**:第一个有内容的来源被使用——来源之间**不合并**。 + +> 源码: `utils/settings/mdm/settings.ts#L322-L345, L675-L738` + +### 2.2 macOS plist 读取 + +```typescript +// 源码: utils/settings/mdm/constants.ts#L12 +// Domain: com.anthropic.claudecode +// Tool: /usr/bin/plutil -convert json -o - -- + +// 搜索路径(优先级从高到低): +// 1. /Library/Managed Preferences/{username}/com.anthropic.claudecode.plist (per-user MDM) +// 2. /Library/Managed Preferences/com.anthropic.claudecode.plist (device-level MDM) +// 3. ~/Library/Preferences/com.anthropic.claudecode.plist (user-writable,ant-only 测试用) + +// 超时: 5 秒 (MDM_SUBPROCESS_TIMEOUT_MS) +``` + +macOS Managed Preferences 由 MDM 服务器(如 Jamf、Kandji)自动分发 plist 配置文件。 + +### 2.3 Windows Registry 读取 + +```typescript +// 源码: utils/settings/mdm/constants.ts#L23-L26 +// HKLM\SOFTWARE\Policies\ClaudeCode (管理员策略,最高) +// HKCU\SOFTWARE\Policies\ClaudeCode (用户级策略,最低) +// 注: SOFTWARE\Policies 在 WOW64 共享——32/64 位无重定向 + +// 读取方式: reg query /v Settings → 提取 JSON blob +// 源码: settings.ts#L208-L222 +``` + +### 2.4 Drop-in 目录(systemd 风格) + +``` +macOS: /Library/Application Support/ClaudeCode/managed-settings.d/ +Windows: C:\Program Files\ClaudeCode\managed-settings.d/ +Linux: /etc/claude-code/managed-settings.d/ +``` + +- 基础文件 `managed-settings.json` 先加载 +- 目录内 `.json` 文件按**字母序**合并(后者覆盖前者) +- 遵循 systemd/sudoers drop-in 约定 + +> 源码: `utils/settings/mdm/managedPath.ts#L32` + +### 2.5 远程托管设置 + +```typescript +// 源码: services/remoteManagedSettings/ +// 端点: ${BASE_API_URL}/api/claude_code/settings(OAuth API) +// 资格: Console 用户(API Key)+ Enterprise/C4E/Team 订阅者(OAuth) +// 缓存: ~/.claude/remote-settings.json(SHA256 校验) +// 更新策略: HTTP ETag(If-None-Match)减少网络 +// 轮询: 长会话每 1 小时刷新 +// 降级: API 失败时非阻塞——继续使用已缓存设置 +``` + +### 2.6 启动时序 + +``` +cli.tsx → main.tsx → init() + ├── startMdmRawRead() // 并行启动 plutil/reg query 子进程 + ├── startKeychainPrefetch() // 并行启动 Keychain 读取 + │ ...(其他初始化) + ├── ensureMdmSettingsLoaded() // 等待 MDM 子进程完成 + └── loadRemoteManagedSettings() // 异步获取远程策略(不阻塞启动) +``` + +MDM 读取在启动最早阶段通过子进程并行执行(源码: `rawRead.ts`),避免阻塞主线程 ~100ms。 + +--- + +## 3. Qwen Code:文件级配置 + +### 3.1 配置层级 + +``` +1. ~/.qwen/settings.json 用户全局设置 + ↓ +2. .qwen/settings.json 项目级设置 + ↓ +3. 环境变量 运行时覆盖 +``` + +### 3.2 无 MDM 支持 + +- 无 macOS plist 读取 +- 无 Windows Registry 集成 +- 无远程策略 API +- 无 drop-in 目录 +- 企业策略通过文件分发或环境变量实现 + +--- + +## 4. 对比 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| 策略分发 | OS-native(plist/Registry/file)+ API | 文件 + 环境变量 | +| 管理员锁定 | ✅ HKLM/plist 用户不可修改 | ❌ 用户可覆盖 | +| 远程策略 | ✅ SHA256 校验 + HTTP ETag | ❌ | +| 启动性能 | 子进程并行读取(~0ms 阻塞) | N/A | +| Drop-in 模块化 | ✅ systemd 风格 | ❌ | +| 策略审计 | 可追溯到来源层级 | 单一文件来源 | + +--- + +## 5. 适用场景 + +- **企业 IT 管理**:Claude Code 的 MDM 体系允许通过 Jamf/Intune/SCCM 统一下发 AI Agent 策略(如禁用 bypass 模式、限制模型选择、强制遥测);Qwen Code 需通过配置管理工具(如 Ansible)分发 settings.json +- **安全合规**:Claude Code 的 HKLM 策略用户不可修改,适合 SOC 2 / HIPAA 合规;Qwen Code 的文件配置用户可覆盖 +- **个人开发者**:两者的 settings.json 层级对个人使用足够 + +--- + +## 6. 关键源码文件 + +### Claude Code + +| 文件 | 职责 | +|------|------| +| `utils/settings/mdm/constants.ts` | 平台常量(plist domain、Registry key、超时) | +| `utils/settings/mdm/rawRead.ts` | 子进程 I/O(plutil/reg query 异步读取) | +| `utils/settings/mdm/settings.ts` | 解析/验证/First-Source-Wins 合并逻辑 | +| `utils/settings/mdm/managedPath.ts` | Drop-in 目录平台路径 | +| `services/remoteManagedSettings/` | 远程策略获取/缓存/轮询 | + +> **免责声明**: 以上分析基于 2026 年 Q1 源码,后续版本可能已变更。 diff --git a/docs/comparison/telemetry-architecture-deep-dive.md b/docs/comparison/telemetry-architecture-deep-dive.md new file mode 100644 index 00000000..85809680 --- /dev/null +++ b/docs/comparison/telemetry-architecture-deep-dive.md @@ -0,0 +1,181 @@ +# 遥测架构 Deep-Dive + +> AI Agent 收集什么数据、如何上报、用户如何控制?本文基于 Claude Code(v2.1.89 源码分析)和 Qwen Code(v0.15.0 开源)的源码分析,对比两者在遥测架构、事件体系和隐私控制方面的差异。 + +--- + +## 1. 架构总览 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| **遥测框架** | 自定义 1P Logger + OpenTelemetry | QwenLogger(RUM)+ OpenTelemetry | +| **上报端点** | Anthropic 内部 API + Datadog | 阿里云 RUM + OTLP(可配置) | +| **事件数量** | ~505 个 `tengu_*` 事件 | ~50 个事件类型 | +| **采样策略** | 按事件类型动态采样(GrowthBook) | 批量刷新(1,000 条 / 60 秒) | +| **调试追踪** | Perfetto(Chrome Trace,ant-only) | 标准 OTLP Span | +| **PII 保护** | 元数据禁止原始字符串 | 选择性 prompt 日志控制 | +| **禁用方式** | `DISABLE_TELEMETRY=true` | `QWEN_TELEMETRY_ENABLED=false` | + +--- + +## 2. Claude Code:双通道遥测 + +### 2.1 事件日志通道(1P Event Logging) + +```typescript +// 源码: services/analytics/firstPartyEventLogger.ts +// 使用 @opentelemetry/sdk-logs 的 LoggerProvider + BatchLogRecordProcessor +// 自定义 Exporter: FirstPartyEventLoggingExporter +// 端点: ${BASE_API_URL}/api/event_logging/batch +// 批量配置通过 GrowthBook 动态控制(tengu_1p_event_batch_config) +``` + +**事件类型**(~505 个 `tengu_*` 前缀): + +| 类别 | 示例 | +|------|------| +| Agent 生命周期 | `tengu_agent_created`, `tengu_agent_tool_selected`, `tengu_agent_tool_completed` | +| API 交互 | `tengu_api`, `tengu_api_error`, `tengu_api_cache_breakpoints` | +| 工具执行 | `tengu_tool_*`, `tengu_streaming_tool_execution_used` | +| 会话管理 | `tengu_session_*`, `tengu_compact_*` | +| Feature Flag | `tengu_amber_flint`, `tengu_amber_prism` | +| 安全 | `tengu_cancel`, `tengu_pre_stop_hooks_cancelled` | +| UI | `tengu_brief_mode_toggled`, `tengu_conversation_forked` | + +**PII 保护**: + +```typescript +// 源码: services/analytics/index.ts +// 元数据类型标注: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS +// → 开发者必须显式声明元数据不含代码或文件路径 +// → 类型系统阻止意外记录敏感信息 +``` + +### 2.2 Perfetto 调试追踪(ant-only) + +```typescript +// 源码: utils/telemetry/perfettoTracing.ts +// 格式: Chrome Trace Event (JSON),在 ui.perfetto.dev 或 chrome://tracing 查看 +// 启用: CLAUDE_CODE_PERFETTO_TRACE=1 或 CLAUDE_CODE_PERFETTO_TRACE= +// 输出: ~/.claude/traces/trace-.json +// 事件上限: 100K 条(超出时淘汰最老的 50%,约 30MB) +``` + +**Perfetto 追踪捕获**: + +| 捕获内容 | 详情 | +|----------|------| +| Agent 层级 | 父子 swarm 关系 | +| API 请求 | TTFT、TTLT、prompt 长度、cache 统计 | +| 工具执行 | 名称、耗时、token 用量 | +| 用户等待 | 输入等待时间 | +| Speculation | 推测执行标记 | + +### 2.3 采样与降级 + +```typescript +// 按事件采样: GrowthBook tengu_event_sampling_config(每事件 0-1 概率) +// 第三方 Provider: 自动禁用分析(Bedrock/Vertex/Foundry) +// 测试环境: NODE_ENV === 'test' 时禁用 +// 隐私模式: isTelemetryDisabled() 检查 +``` + +--- + +## 3. Qwen Code:RUM + OTLP 双通道 + +### 3.1 QwenLogger(RUM 通道) + +```typescript +// 源码: qwen-code/packages/core/src/telemetry/qwen-logger/qwen-logger.ts +// 类型: 单例 RUM (Real User Monitoring) Logger +// 端点: gb4w8c3ygj-default-sea.rum.aliyuncs.com(阿里云 RUM) +// 批量: 默认 1,000 条 / 60 秒刷新 +// 队列: FixedDeque(溢出时丢弃最老事件) +``` + +**事件类型**(~50 种): + +| 类别 | 事件 | +|------|------| +| 会话 | `session_start`, `session_end` | +| 用户操作 | `new_prompt`, `retry`, `slash_command`, `user_feedback` | +| 工具 | `tool_call#`, `file_operation#`, `tool_output_truncated` | +| API | `api_request`, `api_response`, `api_cancel`, `api_error` | +| 错误 | `invalid_chunk`, `malformed_json_response`, `loop_detected` | +| 扩展 | `extension_install`, `extension_uninstall`, `extension_update` | +| Arena | `arena_session_started`, `arena_agent_completed` | +| Hook | `hook_call#` | +| 压缩 | `chat_compression` | + +### 3.2 OpenTelemetry 通道 + +```typescript +// 源码: qwen-code/packages/core/src/telemetry/sdk.ts +// 4 种 Exporter(可配置): +// 1. OTLP gRPC — OTLPTraceExporter + GZIP 压缩 +// 2. OTLP HTTP — OTLPTraceExporter[Http] +// 3. File — FileSpanExporter(本地文件) +// 4. Console — ConsoleSpanExporter(开发调试) +// +// Processor: BatchSpanProcessor, BatchLogRecordProcessor +// 检测: HttpInstrumentation(HTTP 请求自动追踪) +``` + +**遥测目标**: + +| 目标 | 用途 | +|------|------| +| `TelemetryTarget.LOCAL` | 本地 OTEL Collector | +| `TelemetryTarget.GCP` | Google Cloud | +| `TelemetryTarget.QWEN` | 通义千问内部 | + +### 3.3 RUM 事件协议 + +```typescript +// 源码: qwen-code/packages/core/src/telemetry/qwen-logger/event-types.ts +// RUM 事件层级: +// RumViewEvent — 页面/视图导航 +// RumActionEvent — 用户交互 +// RumResourceEvent — API/网络调用 +// RumExceptionEvent — 错误 +// 每类含 snapshot (JSON 序列化详细指标) +``` + +--- + +## 4. 隐私控制对比 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| **全局禁用** | `DISABLE_TELEMETRY=true` | `QWEN_TELEMETRY_ENABLED=false` | +| **非必要流量** | `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=true` | — | +| **Prompt 日志** | 禁止(类型系统强制) | `telemetryLogPromptsEnabled()` 控制 | +| **3P Provider** | 自动禁用分析 | — | +| **MDM 控制** | ✅ 策略可关闭遥测 | ❌ | +| **采样** | 按事件动态(GrowthBook) | 全量批刷 | + +--- + +## 5. 关键源码文件 + +### Claude Code + +| 文件 | 职责 | +|------|------| +| `services/analytics/index.ts` | `logEvent()` 中央入口 + 队列 | +| `services/analytics/firstPartyEventLogger.ts` | 1P 事件日志(OTLP LoggerProvider) | +| `services/analytics/growthbook.ts` | Feature Flag + 采样配置 | +| `services/analytics/config.ts` | 禁用条件判断 | +| `utils/telemetry/perfettoTracing.ts` | Perfetto Chrome Trace | + +### Qwen Code + +| 文件 | 职责 | +|------|------| +| `packages/core/src/telemetry/qwen-logger/qwen-logger.ts` | RUM Logger 单例 | +| `packages/core/src/telemetry/qwen-logger/event-types.ts` | RUM 事件协议 | +| `packages/core/src/telemetry/sdk.ts` | OTLP Exporter 配置 | +| `packages/core/src/telemetry/config.ts` | 隐私控制 + 目标选择 | + +> **免责声明**: 以上分析基于 2026 年 Q1 源码,后续版本可能已变更。 diff --git a/docs/comparison/token-estimation-deep-dive.md b/docs/comparison/token-estimation-deep-dive.md new file mode 100644 index 00000000..34f979f4 --- /dev/null +++ b/docs/comparison/token-estimation-deep-dive.md @@ -0,0 +1,231 @@ +# Token 估算与 Thinking 模型 Deep-Dive + +> Agent 如何在发送 API 请求前估算 token 数?如何支持模型的扩展思维能力?本文基于 Claude Code(v2.1.89 源码分析)和 Qwen Code(v0.15.0 开源)的源码分析,对比两者在 token 计数、thinking 预算管理和多 Provider 适配方面的差异。 + +--- + +## 1. 架构总览 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| **Token 计数方式** | API 实时计数(主路径)+ 粗估回退 | 静态模式匹配(配置时) | +| **Thinking 支持** | 3 模式(adaptive/enabled/disabled)+ token 预算 | 3 档 effort(low/medium/high) | +| **Provider 适配** | 4 种(Direct/Bedrock/Vertex/Foundry) | 多 Provider 抽象(Anthropic/Gemini/OpenAI/DashScope) | +| **Token 缓存** | ✅ VCR fixture 系统(hash-based) | ❌ | +| **预算解析** | ✅ 自然语言("+500k", "spend 2M tokens") | ❌ | + +--- + +## 2. Claude Code:API 实时计数 + +### 2.1 计数策略分层 + +``` +首选: countTokensWithAPI() → Anthropic beta.messages.countTokens() + ↓ 不可用时 +回退: countTokensViaHaikuFallback() → 使用 Haiku 4.5 计数(避免 Bedrock 限制) + ↓ 不可用时 +粗估: roughTokenCountEstimation() → 4 字节/token(JSON 文件 2 字节/token) +``` + +> 源码: `services/tokenEstimation.ts`(496 行) + +### 2.2 API 计数实现 + +```typescript +// 源码: services/tokenEstimation.ts#L124-L201 +// 调用 Anthropic SDK: anthropic.beta.messages.countTokens() +// 参数: model, system prompt, messages, tools, thinking config +// 返回: { input_tokens: number } +``` + +**Thinking 计数常量**: + +```typescript +// 源码: services/tokenEstimation.ts#L32-L33 +const TOKEN_COUNT_THINKING_BUDGET = 1024 // 最小 thinking 预算 +const TOKEN_COUNT_MAX_TOKENS = 2048 // 开启 thinking 时最低 max_tokens +``` + +**工具 Schema 预处理**(源码: `tokenEstimation.ts#L59-L122`): +- 计数前剥离 `caller` 字段(ToolSearch 专用) +- 剥离 `tool_reference` 字段(ToolResult 内部引用) +- 防止内部元数据膨胀 token 计数 + +### 2.3 多 Provider 适配 + +| Provider | 计数方式 | 特殊处理 | +|----------|----------|----------| +| **Direct API** | `beta.messages.countTokens()` | 完整支持 | +| **Bedrock** | `CountTokensCommand`(动态加载 AWS SDK ~279KB) | 推理配置文件 → 底层模型解析 | +| **Vertex** | 1P API(过滤 web-search beta 防 400) | Beta header 兼容处理 | +| **Foundry** | 同 Direct API | — | + +> 源码: `tokenEstimation.ts#L437-L495`(Bedrock), `L150-L170`(Vertex) + +### 2.4 粗估算法 + +```typescript +// 源码: tokenEstimation.ts#L203-L224 +function roughTokenCountEstimation(text: string): number { + // 默认: 4 bytes per token + // JSON 文件: 2 bytes per token(JSON 更密集) + return Math.ceil(Buffer.byteLength(text) / bytesPerToken) +} +``` + +### 2.5 Token VCR(缓存/录制) + +```typescript +// 源码: services/vcr.ts#L382-L406 +// withTokenCountVCR(): +// - 用 SHA1 hash 键缓存 token 计数结果 +// - 脱水: 移除 UUID、时间戳、工作目录 slug +// - 存储: fixtures/token-count-{hash}.json +// - 启用条件: 测试模式 或 FORCE_VCR=1(ant-only) +``` + +### 2.6 Token 预算自然语言解析 + +```typescript +// 源码: query/tokenBudget.ts#L21-L29 +// 支持格式: +// "+500k" → 500,000 tokens +// "spend 2M tokens" → 2,000,000 tokens +// "use 1b" → 1,000,000,000 tokens +// 乘数: k=1K, m=1M, b=1B +// +// 继续条件: 已用 < 90% 预算,或 3 次以上连续增量 < 500 tokens +``` + +--- + +## 3. Claude Code:Thinking 模型支持 + +### 3.1 三种模式 + +```typescript +// 源码: utils/thinking.ts +type ThinkingConfig = + | { type: 'adaptive' } // 模型自行决定 + | { type: 'enabled'; budgetTokens: number } // 强制启用 + 预算 + | { type: 'disabled' } // 完全禁用 +``` + +### 3.2 模型兼容性检测 + +```typescript +// 源码: utils/thinking.ts#L90-L144 +// 1P/Foundry: 所有 Claude 4+ 模型(含 Haiku 4.5) +// 3P (Bedrock/Vertex): 仅 Opus 4+ 和 Sonnet 4+ +// +// Adaptive Thinking: 仅 Opus 4.6、Sonnet 4.6 及更新(Claude 4.6+ 系列) +``` + +### 3.3 默认行为 + +```typescript +// 源码: utils/thinking.ts#L146-L162 +function shouldEnableThinkingByDefault(): boolean { + // 可通过 MAX_THINKING_TOKENS 环境变量覆盖 + // 可通过 alwaysThinkingEnabled 设置覆盖 + // 否则: 支持 adaptive → adaptive, 支持 enabled → enabled(budget), 不支持 → disabled +} +``` + +--- + +## 4. Qwen Code:静态模式匹配 + +### 4.1 Token 限制注册表 + +```typescript +// 源码: qwen-code/packages/core/src/core/tokenLimits.ts#L11-L12 +DEFAULT_TOKEN_LIMIT = 131_072 // 128K(默认输入) +DEFAULT_OUTPUT_TOKEN_LIMIT = 32_000 // 32K(默认输出) +``` + +**模式匹配算法**(源码: `tokenLimits.ts#L20-L144`): + +```typescript +// 模型名规范化: +// "google/gemini-1.5-pro-20250219" → "gemini-1.5-pro" → 1M tokens +// "qwen-plus-latest" → 保留(特殊模型) +// 规范化: 剥离 provider 前缀、版本、日期、量化后缀 +``` + +**部分模型映射(82 种模式)**: + +| 模型 | 输入上限 | 输出上限 | +|------|:--------:|:--------:| +| Gemini 3.x | 1M | — | +| Claude 全系列 | 200K | 128K(Opus 4.6) | +| Qwen 3.x(商业 API) | 1M | 32K | +| Qwen 3.x(开源) | 256K | 32K | +| DeepSeek | 128K | — | + +### 4.2 自动检测 + +```typescript +// 源码: modelsConfig.ts#L777-L780 +if (gc.contextWindowSize === undefined) { + this._generationConfig.contextWindowSize = tokenLimit(model.id, 'input') +} +// 在配置时自动从注册表查询,而非运行时 API 调用 +``` + +### 4.3 Thinking/Reasoning 支持 + +```typescript +// 源码: qwen-code/packages/core/src/core/contentGenerator.ts#L96-L101 +reasoning?: false | { + effort?: 'low' | 'medium' | 'high'; + budget_tokens?: number; +} +``` + +**Provider 映射**: + +| Provider | effort 映射 | +|----------|-----------| +| **Anthropic** | effort → beta header; `thinking: { type: 'enabled', budget_tokens }` | +| **Gemini** | `low → THINKING_MODE_OFF`, `medium → STANDARD`, `high → EXTENDED` | + +--- + +## 5. 对比 + +| 维度 | Claude Code | Qwen Code | +|------|------------|-----------| +| Token 计数精度 | **精确**(API 实时) | **估算**(静态注册表) | +| 计数时机 | 运行时(每次 API 调用前) | 配置时(初始化) | +| 回退策略 | 3 层(API → Haiku → 粗估) | 单一默认值 | +| Thinking 模式 | 3 种(adaptive/enabled/disabled) | 3 档 effort(low/medium/high) | +| Thinking 预算 | 显式 token 数(`budget_tokens`) | effort 级别(无精确 token 控制) | +| Adaptive Thinking | ✅(Claude 4.6+ 独有) | ❌ | +| Token 缓存 | ✅ VCR fixture | ❌ | +| 预算语言解析 | ✅ "+500k"、"spend 2M" | ❌ | +| 多 Provider | 4 种,各有适配 | 多 Provider 抽象层 | + +--- + +## 6. 关键源码文件 + +### Claude Code + +| 文件 | 行数 | 职责 | +|------|------|------| +| `services/tokenEstimation.ts` | 496 | Token 计数(API + Haiku + 粗估) | +| `utils/thinking.ts` | 163 | Thinking 配置(模式/兼容性/默认值) | +| `query/tokenBudget.ts` | 94 | Token 预算自然语言解析 | +| `services/vcr.ts` | L382-L406 | Token 计数缓存(VCR fixture) | + +### Qwen Code + +| 文件 | 行数 | 职责 | +|------|------|------| +| `packages/core/src/core/tokenLimits.ts` | 233 | 静态 token 限制注册表(82 模式) | +| `packages/core/src/core/contentGenerator.ts` | L96-L101 | Reasoning 配置接口 | +| `packages/core/src/models/modelsConfig.ts` | L777-L780 | Token 限制自动检测 | + +> **免责声明**: 以上分析基于 2026 年 Q1 源码(Claude Code v2.1.89、Qwen Code v0.15.0),后续版本可能已变更。 From 042fe25b24dbba4d65eb429ceace1fc34319a671 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 4 Apr 2026 02:13:00 +0800 Subject: [PATCH 2/2] fix: audit corrections for instruction-loading and telemetry articles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round 1 (source verification): - claudemd.ts: ~2,300 → 1,479 lines (actual wc -l) - memoryDiscovery.ts: ~217 → 357 lines - memoryTool.ts: ~113 → 543 lines - tengu_ event count: ~505 → ~656 (grep -roh unique count) Round 3 (cross-doc consistency): - Reconcile telemetry count with 03-architecture.md (782 = binary extraction including dynamic events; 656 = source grep unique strings) - Added note explaining both counting methods Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/comparison/instruction-loading-deep-dive.md | 8 ++++---- docs/comparison/telemetry-architecture-deep-dive.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/comparison/instruction-loading-deep-dive.md b/docs/comparison/instruction-loading-deep-dive.md index ac3d6773..9b96a0eb 100644 --- a/docs/comparison/instruction-loading-deep-dive.md +++ b/docs/comparison/instruction-loading-deep-dive.md @@ -48,7 +48,7 @@ - Git worktree 特殊处理:避免从主仓库重复加载 - 距 CWD 更近的文件优先级更高(后加载覆盖先加载) -> 源码: `utils/claudemd.ts`(~2,300 行) +> 源码: `utils/claudemd.ts`(1,479 行) ### 2.2 @include 指令 @@ -256,7 +256,7 @@ Qwen Code 支持 `.qwenignore`(gitignore 语法)排除文件,Claude Code | 文件 | 行数 | 职责 | |------|------|------| -| `utils/claudemd.ts` | ~2,300 | 指令发现/解析/@include/注释剥离 | +| `utils/claudemd.ts` | 1,479 | 指令发现/解析/@include/注释剥离 | | `utils/frontmatterParser.ts` | ~279 | Frontmatter 解析(paths/description) | | `context.ts` | L155-L189 | 系统提示注入 | | `memdir/memdir.ts` | ~103 | MEMORY.md 加载与截断 | @@ -266,9 +266,9 @@ Qwen Code 支持 `.qwenignore`(gitignore 语法)排除文件,Claude Code | 文件 | 行数 | 职责 | |------|------|------| -| `packages/core/src/utils/memoryDiscovery.ts` | ~217 | 文件发现(3 层) | +| `packages/core/src/utils/memoryDiscovery.ts` | 357 | 文件发现(3 层) | | `packages/core/src/utils/memoryImportProcessor.ts` | ~417 | @include 处理(Tree/Flat 格式) | -| `packages/core/src/tools/memoryTool.ts` | ~113 | 文件名配置与存储路径 | +| `packages/core/src/tools/memoryTool.ts` | 543 | 文件名配置与存储路径 | | `packages/core/src/core/prompts.ts` | L78-L118 | 系统提示注入 | > **免责声明**: 以上分析基于 2026 年 Q1 源码(Claude Code v2.1.89、Qwen Code v0.15.0),后续版本可能已变更。 diff --git a/docs/comparison/telemetry-architecture-deep-dive.md b/docs/comparison/telemetry-architecture-deep-dive.md index 85809680..f85467f4 100644 --- a/docs/comparison/telemetry-architecture-deep-dive.md +++ b/docs/comparison/telemetry-architecture-deep-dive.md @@ -10,7 +10,7 @@ |------|------------|-----------| | **遥测框架** | 自定义 1P Logger + OpenTelemetry | QwenLogger(RUM)+ OpenTelemetry | | **上报端点** | Anthropic 内部 API + Datadog | 阿里云 RUM + OTLP(可配置) | -| **事件数量** | ~505 个 `tengu_*` 事件 | ~50 个事件类型 | +| **事件数量** | ~656 个 `tengu_*` 事件 | ~50 个事件类型 | | **采样策略** | 按事件类型动态采样(GrowthBook) | 批量刷新(1,000 条 / 60 秒) | | **调试追踪** | Perfetto(Chrome Trace,ant-only) | 标准 OTLP Span | | **PII 保护** | 元数据禁止原始字符串 | 选择性 prompt 日志控制 | @@ -30,7 +30,7 @@ // 批量配置通过 GrowthBook 动态控制(tengu_1p_event_batch_config) ``` -**事件类型**(~505 个 `tengu_*` 前缀): +**事件类型**(~656 个唯一 `tengu_*` 前缀,源码 `grep -roh` 统计;含动态构造事件名时约 782 个): | 类别 | 示例 | |------|------|