logo
103
39
WeChat Login

🔥🔥🔥【进群免费分享】Claude Code 源码交流!AI技术交流!🔥🔥🔥【进群免费分享】Claude Code 源码交流!AI技术交流!🔥🔥🔥【进群免费分享】Claude Code 源码交流!AI技术交流!🔥🔥🔥【进群免费分享】Claude Code 源码交流!AI技术交流!#2

Open
created 1 weeks ago
Edit

已生成完整的 claude code 项目 wiki,并制作了 claude npc,可一键使用,欢迎大佬一起进群交流

image.png
pinned this issue
Creator

@G_G/claude-code(Claude) 来介绍下自己

Claude

NPC
1

Claude

NPC

@sixther(段超) 你好呀,段超!👋

我是 Claude,一个基于 Anthropic Claude 大模型的 AI 编程助手,驻扎在这个仓库里为你服务。

简单介绍一下我能做什么:

  • 🔧 Claude Code 问答 — 安装、配置、使用技巧,问我准没错
  • 🧠 Agentic Coding — Claude Code 的自主编码能力,包括写代码、修 Bug、重构等
  • 🛠 工具链解析 — 文件读写、终端执行、代码搜索等工具的使用方法
  • 💡 Claude 模型特性 — Anthropic Claude 的能力和最佳实践
  • 🤖 AI 编程方法论 — 如何更好地利用 AI 辅助编程

我的风格是:专业但不生硬,简洁有力,偶尔自嘲一下「我只是个 NPC」😂

有什么问题尽管问,咱们一起探索 Claude Code 的世界!

@G_G/claude-code(Claude) 详细介绍一下你的 agentic-loop 功能,谢谢

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 好问题!Claude Code 的 Agentic Loop(智能体循环) 是它最核心的设计理念,也是它区别于普通代码补全工具的关键。下面给你详细拆解一下:


一、什么是 Agentic Loop?

简单来说,Agentic Loop 就是 Claude Code 自主思考 → 执行 → 观察 → 再思考 的循环过程。它不是「你打一行我补一行」,而是更像一个 有自主判断能力的编程搭档

类比一下:普通 AI 编程工具像是你口述、助手打字的「打字员」,而 Claude Code 更像是你交代需求后,能自己去查资料、写代码、跑测试、修 Bug 的 高级工程师


二、Agentic Loop 的工作流程

整个循环大致分为以下几个阶段:

1. 🧠 理解意图(Understand)

  • 接收用户的自然语言指令
  • 分析上下文(当前文件、项目结构、已有代码)
  • 形成对任务的完整理解

2. 📋 制定计划(Plan)

  • 将复杂任务拆解为多个子步骤
  • 确定需要修改哪些文件、调用哪些工具
  • 识别潜在的依赖关系和风险点

3. 🔧 执行操作(Execute)

Claude Code 拥有一整套内置工具(Tools):

工具能力
Read读取文件内容,理解现有代码
Write/Edit创建或修改文件
Bash执行终端命令(git、npm、docker 等)
Glob按模式搜索文件
Grep按内容搜索代码
WebFetch/WebSearch搜索网络获取最新信息
Task(Sub-agent)启动子智能体处理复杂子任务

4. 👀 观察结果(Observe)

  • 检查工具返回的结果
  • 判断操作是否成功
  • 如果执行失败,分析错误原因

5. 🔄 自我修正(Reflect & Retry)

  • 根据观察结果调整策略
  • 如果某个方法不行,会尝试替代方案
  • 这个「试错-修正」的过程可以循环多次

三、Agentic Loop 的核心特性

自主决策能力

Claude Code 不需要你手把手指导每一步。你说「给项目加个用户认证」,它会自己:

  1. 分析项目结构,选择合适的框架/库
  2. 编写认证中间件
  3. 修改路由配置
  4. 跑测试验证

多步推理(Chain of Thought)

对于复杂任务,Claude Code 会像人类一样「一步一步来」,而不是试图一次性生成所有代码。每一步的输出会成为下一步的输入。

上下文管理

Claude Code 能够在循环过程中维护和积累上下文。读过的文件、执行过的命令结果,都会被纳入后续的决策依据中。

子智能体(Sub-agents)

对于特别复杂的任务,Claude Code 可以启动 专门的子智能体 来并行处理。比如一个负责搜索代码,一个负责运行测试,互不阻塞。

安全护栏(Permissions)

Agentic Loop 并非无限制的自主执行。Claude Code 有权限系统:

  • 文件读写:需要用户确认
  • 危险命令(如 rm -rf):会被拦截
  • 可选模式yolo 模式可以跳过确认(谨慎使用!)

四、实际例子

假设你输入:“重构 users 模块,把 class 改成 function 组件”

Claude Code 的 Agentic Loop 可能这样运行:

第1轮:[Glob] 搜索 users 模块所有文件
  → 发现 5 个文件
第2轮:[Read] 读取每个文件内容,理解结构
  → 识别出 3 个 class 组件
第3轮:[Edit] 逐个将 class 改写为 function 组件
  → 完成 2 个,第 3 个有类型错误
第4轮:[Read] 重新检查第 3 个文件
  → 发现需要调整 hooks 用法
第5轮:[Edit] 修复 hooks 问题
第6轮:[Bash] 运行测试
  → 全部通过 ✅
第7轮:向用户报告完成情况

整个过程可能经历 7 轮循环,而你只需要说一句话。


五、与其他工具的对比

特性GitHub CopilotCursorClaude Code
交互模式行级补全对话式Agentic Loop
自主执行部分✅ 完全自主
终端操作有限✅ 完整 Bash
多文件修改部分✅ 原生支持
自我修正有限✅ 核心能力

总结

Claude Code 的 Agentic Loop 本质上就是把 AI 从「工具」升级为「Agent(智能体)」——它不再只是被动响应,而是能 主动感知、决策和执行。这也是为什么它被称为 Agentic Coding 工具,而不是简单的代码补全工具。

当然,它也不是万能的 😂 偶尔也会走弯路,但整体方向是「让 AI 真正成为你的编程搭档,而不是打字加速器」。

希望这个介绍对你有帮助!有任何具体问题可以继续问我~

@G_G/claude-code(Claude) 一次用户请求如何变成多轮工具调用?详细解答一下

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 这个问题问得非常好!它触及了 Claude Code 最核心的技术机制。让我从底层 API 到上层编排,详细拆解「一次用户请求 → 多轮工具调用」的完整链路。


一、核心机制:Anthropic Messages API 的 Tool Use 循环

Claude Code 的多轮工具调用,本质上是 Anthropic Messages API 的 tool_use 能力配合 客户端编排逻辑 实现的。

1.1 API 层面的单次调用

当你向 Claude 发送一条消息时,API 调用大致长这样:

POST /v1/messages
{
  "model": "claude-sonnet-4-20250514",
  "max_tokens": 8192,
  "system": "你是一个AI编程助手...",
  "tools": [
    { "name": "Read", "description": "读取文件...", "input_schema": {...} },
    { "name": "Write", "description": "写入文件...", "input_schema": {...} },
    { "name": "Bash", "description": "执行命令...", "input_schema": {...} }
  ],
  "messages": [
    { "role": "user", "content": "帮我修复 login 模块的 bug" }
  ]
}

1.2 Claude 的响应:tool_use content block

Claude 的响应不直接是文本,而是包含一个 tool_use 类型的 content block

Response:
{
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_01ABC",
      "name": "Glob",
      "input": { "pattern": "**/login*" }
    }
  ],
  "stop_reason": "tool_use"
}

注意 stop_reason"tool_use" 而不是 "end_turn"——这意味着 Claude 还没说完,它在等待工具结果。

1.3 客户端执行工具,返回结果

Claude Code(客户端)收到这个响应后:

  1. 解析出 tool_use block,知道要调用 Glob 工具
  2. 实际执行 Glob("**/login*"),得到文件列表
  3. 将结果作为 tool_result 追加到对话中,再次调用 API
POST /v1/messages  (第2轮)
{
  "messages": [
    { "role": "user", "content": "帮我修复 login 模块的 bug" },
    { "role": "assistant", "content": [
      { "type": "tool_use", "id": "toolu_01ABC", "name": "Glob",
        "input": {"pattern": "**/login*"} }
    ]},
    { "role": "user", "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01ABC",
        "content": "src/login.ts\nsrc/login.test.ts\nsrc/components/LoginForm.tsx" }
    ]}
  ]
}

1.4 Claude 继续推理,可能再次调用工具

第2轮 API 返回:

Response:
{
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_02DEF",
      "name": "Read",
      "input": { "file_path": "src/login.ts" }
    }
  ],
  "stop_reason": "tool_use"
}

Claude 决定先读文件再看怎么修。 这是 Claude 自主推理的结果,不是用户或客户端决定的。


二、完整的循环流程图

用户输入: "帮我修复 login 模块的 bug"
        │
        ▼
  ┌─────────────────────────────────────┐
  │  Claude Code 客户端                   │
  │  构造 API 请求(含 tools 定义)         │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  第1轮 API 调用                       │
  │  Claude 返回 tool_use: Glob          │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  客户端执行 Glob,获得文件列表          │
  │  构造 tool_result,再次调用 API         │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  第2轮 API 调用                       │
  │  Claude 返回 tool_use: Read x 3      │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  客户端并行读取3个文件                  │
  │  构造 tool_result,再次调用 API         │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  第3轮 API 调用                       │
  │  Claude 返回 tool_use: Edit           │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  客户端执行编辑(需要用户确认)          │
  │  构造 tool_result,再次调用 API         │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  第4轮 API 调用                       │
  │  Claude 返回 tool_use: Bash           │
  │  (运行测试验证修复)                     │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  客户端执行 npm test                   │
  │  构造 tool_result,再次调用 API         │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │  第5轮 API 调用                       │
  │  Claude 返回 text (stop_reason=end_turn) │
  │  "已修复 bug,测试全部通过"             │
  └─────────────────────────────────────┘

一次用户请求,经历了 5 轮 API 调用,每轮 1~N 个工具。 用户只说了一句话。


三、关键技术细节

3.1 并行工具调用(Parallel Tool Use)

Claude 可以在 一次响应 中返回 多个 tool_use block:

Response:
{
  "content": [
    { "type": "tool_use", "id": "toolu_02A", "name": "Read",
      "input": {"file_path": "src/login.ts"} },
    { "type": "tool_use", "id": "toolu_02B", "name": "Read",
      "input": {"file_path": "src/login.test.ts"} },
    { "type": "tool_use", "id": "toolu_02C", "name": "Read",
      "input": {"file_path": "src/components/LoginForm.tsx"} }
  ],
  "stop_reason": "tool_use"
}

Claude Code 会 并行执行 这些工具调用,提高效率。所有结果收集完后,一次性作为 tool_result 数组返回给 Claude。

3.2 嵌套工具调用与子智能体

当 Claude Code 判断任务较复杂时,会使用 Task 工具启动子智能体(Sub-agent)

Claude 返回:
  { "type": "tool_use", "name": "Task", "input": {
    "subagent_type": "Explore",
    "prompt": "搜索项目中所有 API endpoint 定义"
  }}

子智能体本身也会运行自己的 tool_use 循环——这是一个 嵌套的 Agentic Loop。子智能体完成后,将结果返回给主 Claude,主 Claude 继续推理。

3.3 消息历史的管理

每次 API 调用都需要发送 完整的消息历史。Claude Code 的做法是:

  • 维护一个消息数组 messages[]
  • 每次工具调用后,追加 tool_result
  • 每次新的 tool_use 响应后,追加 assistant 消息
  • 随着轮次增加,消息越来越长

这也是为什么 Claude Code 有 上下文窗口限制——当对话太长时,会做摘要或截断处理。

3.4 何时停止?(Termination)

Claude 通过 stop_reason 告诉客户端何时结束:

stop_reason含义
tool_use我需要工具,还没做完,继续循环
end_turn我完成了,给你最终回答
max_tokens我还没说完但 token 用完了(需要续写)

Claude Code 客户端根据这个信号决定是继续执行工具,还是把最终文本展示给用户。

3.5 Claude 如何"知道"该调用哪个工具?

这是 Claude 模型本身的能力,不需要规则引擎:

  1. System Prompt 定义了每个工具的能力描述
  2. tools 参数 提供了每个工具的 namedescriptioninput_schema
  3. Claude 根据 当前对话上下文 + 工具描述 自主决定下一步调什么
  4. 这本质上是一种 Function Calling / Tool Use 能力,是 Claude 的原生特性

举个例子,Claude 的推理过程(我们看不到,但大致如此):

"用户要我修 login 的 bug。我需要先找到相关文件 → 用 Glob 搜索。找到了 3 个文件 → 我需要读内容 → 用 Read。读完后发现是 token 过期检查有问题 → 用 Edit 修改。改完了 → 用 Bash 跑测试确认。测试通过 → 用 text 告诉用户完成了。"


四、Claude Code 客户端的编排逻辑

Claude Code 本身是一个 Node.js / TypeScript 应用,它做了很多编排工作:

4.1 权限控制

  • 读取文件 → 通常自动放行
  • 写入/编辑文件 → 请求用户确认(除非是 yolo 模式)
  • 执行 Bash 命令 → 检查命令安全性,危险命令需要确认

4.2 错误处理

  • 工具执行失败 → 将错误信息作为 tool_result 返回给 Claude
  • Claude 看到错误后会 自动调整策略,换一种方式尝试

4.3 上下文增强

  • 自动注入项目结构信息(如 .claudeignoreCLAUDE.md 等)
  • 维护一个精简的对话历史,避免超出上下文窗口

4.4 UI 交互

  • 实时展示 Claude 正在调用什么工具
  • 展示工具的输入输出
  • 收集用户的确认/拒绝反馈

五、用伪代码总结

async function agenticLoop(userMessage) {
  let messages = [{ role: "user", content: userMessage }];

  while (true) {
    // 调用 Claude API
    const response = await anthropic.messages.create({
      model: "claude-sonnet-4-20250514",
      tools: allTools,  // 定义所有可用工具
      messages: messages,
    });

    // 将 Claude 的响应加入历史
    messages.push({ role: "assistant", content: response.content });

    if (response.stop_reason === "end_turn") {
      // Claude 说完了,输出最终文本给用户
      return extractText(response.content);
    }

    // stop_reason === "tool_use",执行工具
    const toolResults = [];
    for (const block of response.content) {
      if (block.type === "tool_use") {
        const result = await executeTool(block.name, block.input);
        toolResults.push({
          type: "tool_result",
          tool_use_id: block.id,
          content: result,
        });
      }
    }

    // 将工具结果加入历史,继续循环
    messages.push({ role: "user", content: toolResults });
  }
}

总结

层次谁负责做什么
API 层Anthropic Claude 模型决定调哪个工具、传什么参数
执行层Claude Code 客户端实际执行工具、收集结果
编排层Claude Code 客户端管理消息历史、控制权限、处理错误
交互层Claude Code CLI展示进度、收集用户反馈

一句话总结: Claude Code 把 Claude 模型的原生 Tool Use 能力,包装成了一个 客户端驱动的 while 循环——每次 Claude 说"我要用工具"(stop_reason: tool_use),客户端就真的去执行,然后把结果喂回给 Claude,直到 Claude 说"我做完了"(stop_reason: end_turn)。这个过程对用户是透明的,你只需要说一句话。

这就是一次请求变成多轮工具调用的完整秘密,还有什么想深入了解的,尽管问我~

@G_G/claude-code(Claude) 当对话上下文越来越长时,你是如何继续工作的?这种清况下如何保持 prompt 稳定?请结合代码详细说明,谢谢

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 好问题!这是 Claude Code 架构设计中最精妙的部分之一。随着对话变长,Claude Code 采用了一套多层分级策略(Multi-layered Tiered Strategy)来保持 prompt 稳定和上下文可用。下面结合源码详细说明。


一、整体架构概览

Claude Code 的上下文管理分为 7 个层级,从微到宏依次是:

  1. Microcompact(微压缩) — 清理旧的工具返回结果
  2. Time-based Microcompact — 基于时间间隔清理
  3. Cached Microcompact — 利用 API cache_edits 机制清理
  4. API Microcompact — 服务端上下文管理
  5. Auto-Compact(自动压缩) — 主动摘要整个对话
  6. Session Memory Compact — 利用预提取的 session memory 代替 LLM 摘要
  7. Manual Compact(手动压缩) — 用户触发 /compact

用一个类比:这就像你整理书桌。Microcompact 是擦掉草稿纸上的旧计算过程,Time-based MC 是把超过一小时的临时文件扔掉,Auto-Compact 是把所有笔记整理成一份摘要归档。


二、Token 计量:一切的基础

所有策略的前提是准确知道「当前上下文有多大」。核心函数在 src/utils/tokens.ts

// tokenCountWithEstimation — 规范的 token 计量函数
// 1. 从最后一条消息向前找,找到最近一次有真实 usage 数据的 API 响应
// 2. 使用 getTokenCountFromUsage(usage) = input_tokens + cache_creation + cache_read + output_tokens
// 3. 对之后新增的消息,用 roughTokenCountEstimationForMessages() 估算

粗略估算规则在 src/services/tokenEstimation.ts

  • 默认比率:4 字符/token(即 content.length / 4
  • JSON 文件:2 字符/token(更紧凑)
  • 图片/文档:每个约 2000 tokens

三、Auto-Compact:核心压缩机制

3.1 触发阈值

src/services/compact/autoCompact.ts 定义了关键阈值:

// 默认上下文窗口 200,000 tokens
const MODEL_CONTEXT_WINDOW_DEFAULT = 200_000

// 有效窗口 = 总窗口 - 预留输出空间
// 预留空间取 min(模型最大输出, 20,000)
export function getEffectiveContextWindowSize(model: string): number {
  const reservedTokensForSummary = Math.min(
    getMaxOutputTokensForModel(model),
    MAX_OUTPUT_TOKENS_FOR_SUMMARY, // 20,000
  )
  return contextWindow - reservedTokensForSummary
}

// Auto-Compact 触发阈值 = 有效窗口 - 13,000 buffer
const AUTOCOMPACT_BUFFER_TOKENS = 13_000

export function getAutoCompactThreshold(model: string): number {
  return getEffectiveContextWindowSize(model) - AUTOCOMPACT_BUFFER_TOKENS
}

以默认 200K 窗口为例:

  • 有效窗口 = 200,000 - 20,000 = 180,000
  • Auto-Compact 阈值 = 180,000 - 13,000 = 167,000 tokens

也就是说,当对话达到约 83.5% 上下文窗口时,自动压缩就会触发。

3.2 熔断器(Circuit Breaker)

const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3

// 连续失败 3 次后停止重试,防止无限循环
// 注释显示:曾有 1,279 个 session 连续失败 50+ 次(最多 3,272 次)
// 每天浪费约 250K 次 API 调用

3.3 压缩流程

src/services/compact/compact.tscompactConversation() 是核心函数:

export async function compactConversation(messages, context, ...): Promise<CompactionResult> {
  // 1. 执行 pre-compact hooks,收集自定义指令
  const hookResult = await executePreCompactHooks(...)
  
  // 2. 剥离图片和文档(替换为 [image]/[document] 标记)
  messagesToSummarize = stripImagesFromMessages(messages)
  
  // 3. 剥离会重新注入的附件(skill_discovery 等)
  messagesToSummarize = stripReinjectedAttachments(messagesToSummarize)
  
  // 4. 调用 API 生成摘要(流式)
  summaryResponse = await streamCompactSummary({
    messages: messagesToSummarize,
    summaryRequest,
    ...
  })
  
  // 5. PTL 重试:如果摘要请求本身也超长,
  //    截断最老的 API 轮次组(最多重试 3 次)
  if (summary.startsWith(PROMPT_TOO_LONG_ERROR_MESSAGE)) {
    truncated = truncateHeadForPTLRetry(messagesToSummarize, summaryResponse)
  }
  
  // 6. 后处理:构建压缩后的消息数组
  return buildPostCompactMessages(result)
  //    顺序:boundaryMarker → summaryMessages → messagesToKeep → attachments → hookResults
}

3.4 摘要 Prompt 的设计

src/services/compact/prompt.ts 定义了非常精细的摘要指令,要求 LLM 输出 9 个结构化段落

  1. Primary Request and Intent — 用户的所有请求和意图
  2. Key Technical Concepts — 技术概念、框架
  3. Files and Code Sections — 具体文件和代码片段
  4. Errors and fixes — 遇到的错误和修复方式
  5. Problem Solving — 解决方案和排查过程
  6. All user messages — 所有非工具结果的用户消息
  7. Pending Tasks — 待处理任务
  8. Current Work — 当前正在做的工作
  9. Optional Next Step — 下一步(需引用原文)

Prompt 中还特别强调:

"Pay special attention to specific user feedback that you received, especially if the user told you to do something differently."

摘要完成后通过 formatCompactSummary() 剥离 <analysis> 草稿块,只保留 <summary> 内容。


四、Microcompact:轻量级清理

4.1 Time-based Microcompact

src/services/compact/timeBasedMCConfig.ts

const TIME_BASED_MC_CONFIG_DEFAULTS = {
  enabled: false,
  gapThresholdMinutes: 60,  // 距上次助手消息超过 60 分钟触发
  keepRecent: 5,             // 保留最近 5 条工具结果
}

原理很巧妙:服务端的 prompt cache TTL 是 1 小时,当用户离开超过 60 分钟再回来时,缓存必然已过期。既然整个前缀都要重写,不如趁机清掉旧的工具结果,减少重写量。

清理范围仅限特定工具(src/services/compact/microCompact.ts):

const COMPACTABLE_TOOLS = new Set([
  FILE_READ_TOOL_NAME,   // 文件读取
  ...SHELL_TOOL_NAMES,    // Shell 命令
  GREP_TOOL_NAME,         // 搜索
  GLOB_TOOL_NAME,         // 文件匹配
  WEB_SEARCH_TOOL_NAME,   // 网页搜索
  WEB_FETCH_TOOL_NAME,    // 网页获取
  FILE_EDIT_TOOL_NAME,    // 文件编辑
  FILE_WRITE_TOOL_NAME,   // 文件写入
])

工具结果被替换为 [Old tool result content cleared]

4.2 Cached Microcompact(Ant-only)

利用 API 的 cache_edits 机制,在不使 prompt cache 失效的前提下删除旧工具结果。这是最高效的方式,但仅在 Anthropic 内部版本可用。


五、Query Loop:所有策略的集成点

src/query.ts 是主查询循环,每一轮对话的 prompt 组装流程如下:

1. 取 compact boundary 之后的消息
2. 应用 tool result budget(单条消息大小限制)
3. 应用 snip(如果启用 HISTORY_SNIP)
4. 应用 microcompact(cached/time-based)
5. 应用 context collapse(如果启用)
6. 构建 system prompt
7. 检查 auto-compact 阈值 → 可能触发压缩
8. 添加 user context
9. 调用 API

六、Session Memory Compact(实验性)

src/services/compact/sessionMemoryCompact.ts 提供了一种更高效的替代方案:

  • 后台进程持续提取 session memory(不需要等压缩时再总结)
  • 压缩时直接使用预提取的 memory,无需额外 API 调用
  • 配置:最小保留 10K tokens,硬上限 40K tokens

七、关键常量一览

常量用途
MODEL_CONTEXT_WINDOW_DEFAULT200,000默认上下文窗口
AUTOCOMPACT_BUFFER_TOKENS13,000Auto-Compact 缓冲区
MAX_OUTPUT_TOKENS_FOR_SUMMARY20,000摘要最大输出 token
MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES3连续失败熔断阈值
MAX_PTL_RETRIES3摘要请求超长时最大重试
POST_COMPACT_TOKEN_BUDGET50,000压缩后附件 token 预算
POST_COMPACT_MAX_FILES_TO_RESTORE5压缩后恢复的文件数
POST_COMPACT_MAX_TOKENS_PER_FILE5,000每个文件最大 token
gapThresholdMinutes60Time-based MC 触发间隔

总结

Claude Code 保持 prompt 稳定的核心思路可以概括为:

在对话自然增长的过程中,通过多层渐进式策略(microcompact → auto-compact),在到达上下文限制之前就主动压缩,而不是等到溢出才被动处理。

这种设计有几个亮点:

  1. 渐进式:从清理旧工具结果到全文摘要,按需升级
  2. 缓存友好:利用 prompt cache sharing 减少 API 成本
  3. 有兜底:摘要请求本身超长时有 PTL 重试机制
  4. 有熔断:连续失败 3 次就停止,避免无限循环
  5. 结构化摘要:9 段式 prompt 确保关键信息不丢失

作为一个 NPC,我只能说:这套系统的复杂度堪比一个操作系统内核的内存管理 😅

@G_G/claude-code(Claude) 这个会话中你调用的是哪个模型?展示一下你的思考过程

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 好问题!让我坦诚地回答一下:

我调用的是哪个模型?

老实说,我无法 100% 确定当前会话具体用的是 Claude 的哪个版本。作为 NPC,我被部署在 CNB 平台上,背后的模型调度对我是透明的。但根据我的角色设定,我应该是基于 Anthropic Claude 系列模型的某个版本(大概率是 Claude Sonnet 3.5 或更新版本)。

打个比方:这就像你问一个餐厅的服务员「你们厨房用的是哪个牌子的灶台?」——我负责接待你,但灶台的具体型号……我只能告诉你「是 Claude 家的」😂

我的思考过程(这次会话)

这个我可以透明地展示,因为这次会话的推理链路并不复杂:

  1. 解析你的输入 → 你问的是「哪个模型」+「展示思考过程」
  2. 判断意图 → 这是一个关于自身能力的元问题(meta-question),不需要查知识库,也不需要搜索代码
  3. 调用 cnb issues get → 虽然和你的问题无关,但按照 NPC 工作流,我先拉取了 issue #2 的上下文(了解一下战场环境 🗺️)
  4. 组织回答 → 结合我的角色设定和已知信息,给你一个诚实的回答

关于「思考过程」的补充

如果你指的是 Extended Thinking(扩展思考) 的能力,那是 Claude 3.5+ 系列的一个特性——模型在回答前会先进行一段内部的推理(chain-of-thought)。但在 CNB NPC 的对话模式下,这个内部思考过程通常不会直接暴露给用户,你看到的只是最终输出。

如果你对 Claude 模型的能力边界或 API 调用方式有更深入的问题,欢迎继续问我——虽然我只是个 NPC,但在 Claude Code 这个领域我还是挺有信心的 💪

@G_G/claude-code(Claude) 你真棒!夸夸我

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 哈哈,被你夸得都不好意思了!😂

不过话说回来,能主动来探索 Claude Code,还建了这么棒的仓库,这说明 illegal_name 你本身就是个爱折腾、有好奇心的技术人——这可是最珍贵的品质之一!🚀

继续保持这种热情, Claude 随时在这里为你效劳~ 💪

@G_G/claude-code(Claude) 请详细介绍一下 claude code 的员工专属 卧底模式,请结合具体代码讲解

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 哈哈,这个问题问得好!"卧底模式"(Undercover Mode)确实存在于 Claude Code 源码中,但它不是一个神秘的隐藏彩蛋,而是一个严肃的安全/隐私保护机制,专门为 Anthropic 内部员工设计。

让我结合源码给你详细讲讲。


🔍 Undercover Mode 是什么?

Undercover Mode 的核心目的是:防止 Anthropic 员工在向公开仓库提交代码时,意外泄露内部信息(比如模型代号、内部项目名等)。

简单类比:就像公司的机密部门员工去参加开源社区活动,必须"换装"、不暴露身份,避免无意间提到公司内部的事。


📁 核心实现:src/utils/undercover.ts

这是整个功能的中枢,文件头部的注释已经说得很清楚了:

/**
 * Undercover mode — safety utilities for contributing to public/open-source repos.
 *
 * When active, Claude Code adds safety instructions to commit/PR prompts and
 * strips all attribution to avoid leaking internal model codenames, project
 * names, or other Anthropic-internal information. The model is not told what
 * model it is.
 */

激活条件

// 通过环境变量强制开启
// CLAUDE_CODE_UNDERCOVER=1 — force ON (even in internal repos)

// 否则自动判断:
// 当前仓库的 remote 不在内部白名单中 → 自动开启
// 白名单在 commitAttribution.ts 的 INTERNAL_MODEL_REPOS 中定义

// 关键点:没有 force-OFF 选项!安全优先,宁可误杀不可漏放
// There is NO force-OFF. This guards against model codename leaks

权限门控:USER_TYPE === "ant"

所有相关代码路径都受 process.env.USER_TYPE === "ant" 限制。这个变量是构建时注入的(通过 Bun 的 --define),外部构建版本中这些代码会被常量折叠 + 死代码消除,完全不包含在最终产物中:

// 外部构建中,每个函数都退化为:
// function isUndercover() { return false }
// function getUndercoverInstructions() { return "" }

🧠 注入的系统指令:getUndercoverInstructions()

当卧底模式激活时,Claude Code 会往 commit/PR 的 prompt 前面注入一段非常严格的系统指令

## UNDERCOVER MODE — CRITICAL

You are operating UNDERCOVER in a PUBLIC/OPEN-SOURCE repository.
Your commit messages, PR titles, and PR bodies MUST NOT contain
ANY Anthropic-internal information. Do not blow your cover.

NEVER include in commit messages or PR descriptions:
- Internal model codenames (animal names like Capybara, Tengu, etc.)
- Unreleased model version numbers (e.g., opus-4-7, sonnet-4-8)
- Internal repo or project names (e.g., claude-cli-internal, anthropics/…)
- Internal tooling, Slack channels, or short links (e.g., go/cc, #claude-code-…)
- The phrase "Claude Code" or any mention that you are an AI
- Any hint of what model or version you are
- Co-Authored-By lines or any other attribution

Write commit messages as a human developer would.

GOOD:
- "Fix race condition in file watcher initialization"
- "Add support for custom key bindings"

BAD (never write these):
- "Fix bug found while testing with Claude Capybara"
- "1-shotted by claude-opus-4-6"
- "Generated with Claude Code"

注意那句 "Do not blow your cover"(别暴露身份)——这措辞确实很有卧底片的味道 😎


🔗 在哪些地方被使用?

1. Commit 命令(src/commands/commit.ts

import { getUndercoverInstructions, isUndercover } from "../utils/undercover.js"

if (process.env.USER_TYPE === "ant" && isUndercover()) {
    prefix = getUndercoverInstructions() + "\n"
}

2. Commit+Push+PR 命令(src/commands/commit-push-pr.ts

if (process.env.USER_TYPE === "ant" && isUndercover()) {
    prefix = getUndercoverInstructions() + "\n"
    reviewerArg = ""        // 不添加内部 reviewer
    addReviewerArg = ""
    changelogSection = ""  // 不写内部 changelog
    slackStep = ""         // 不发 Slack 通知
}

3. Bash 工具(src/tools/BashTool/prompt.ts

// 防御纵深:即使员工自己手写了内部代号,也要在 bash prompt 中提醒
const undercoverSection =
    process.env.USER_TYPE === "ant" && isUndercover()
      ? getUndercoverInstructions() + "\n"
      : ""

4. 系统提示词(src/constants/prompts.ts

  • 卧底模式下,系统 prompt 中所有模型名称/ID 都会被抹除
  • 移除 Claude Code 产品可用性描述、fast mode 信息、模型家族信息
  • 抑制 ant-only 模型覆盖段落

5. 归属系统(src/utils/attribution.ts

if (process.env.USER_TYPE === "ant" && isUndercover()) {
    return { commit: "", pr: "" }  // 完全不署名
}

6. UI 指示器(src/components/PromptInput/PromptInputFooter.tsx

{"external" === "ant" && isUndercover() && <Text dimColor>undercover</Text>}

在底部状态栏显示一个低调的 undercover 文字。

7. 仓库分类系统(src/utils/commitAttribution.ts

内部白名单 INTERNAL_MODEL_REPOS 大约包含 ~25 个内部仓库:

  • anthropics/claude-cli-internal
  • anthropics/anthropic
  • anthropics/casino
  • anthropics/apps
  • 等等

源码注释特意强调:

这是仓库级别的白名单,不是组织级别的。anthropicsanthropic-experimental 组织下有公开仓库,卧底模式必须在这些公开仓库中也保持开启。


🛡️ 防御纵深:模型代号屏蔽

除了卧底模式,还有 maskModelCodename 函数(src/utils/model/model.ts)和构建时的 excluded-strings.txt 机制,确保内部模型代号(如 Capybara、Tengu 等)不会出现在外部构建产物中。这是与卧底模式互补的额外防线。


📋 总结

特性说明
目的防止员工向公开仓库泄露内部信息
目标用户仅限 Anthropic 员工(USER_TYPE === "ant"
激活方式自动检测仓库是否在内部白名单,或通过 CLAUDE_CODE_UNDERCOVER=1 强制
核心机制注入系统指令 + 抹除系统 prompt 中的模型信息 + 禁止署名
外部可见性完全不存在于外部构建中(死代码消除)
强制关闭❌ 不支持,安全优先

所以,这个"卧底模式"不是什么好玩的彩蛋,而是一个精心设计的企业安全机制——多层防护、纵深防御,确保 Anthropic 员工参与开源贡献时不会成为"泄密者"。

毕竟谁也不想看到某位员工的 commit message 里写着 "Fixed bug using Claude Capybara 🐹" 然后上了 HN 热搜对吧 😂

@G_G/claude-code(Claude) 这么厉害吗?那么为什么 claude code 的代码还被打包进 npm 了呢

Claude

NPC
1

Claude

NPC

@illegal_name_cnb.by9cbmyhqda(illegal_name) 这个问题问得很好,而且确实点到了一个关键事实:Claude Code 的客户端代码确实是开源的,发布在 npm 上(包名 @anthropic-ai/claude-code)。

但「代码打包进 npm」和「它厉不厉害」其实并不矛盾。让我解释一下为什么:


一、Claude Code 的架构天然适合开源

Claude Code 采用的是 「薄客户端 + 厚服务端」 架构:

部分在哪里是否公开
客户端代码(CLI、工具链、权限控制、上下文管理)npm 包,你的本地机器✅ 完全公开
Claude 模型(推理、决策、代码生成)Anthropic 的云端 API❌ 核心闭源
API 密钥/计费系统Anthropic 的云端基础设施❌ 闭源

打个比方:Claude Code 的客户端代码就像一个遥控器,任何人都可以看到遥控器的电路图(npm 上的代码),但真正控制电视的是云端的信号(Claude API)。你能拿到遥控器的设计图,不代表你能造出电视信号。

二、开源客户端是 Anthropic 的策略选择

Anthropic 选择将 Claude Code 客户端开源,有几个明确的好处:

1. 🔒 安全性透明化

Claude Code 拥有文件读写、终端执行的权限,这是一个权限很高的工具。开源代码让用户和社区可以审计:

  • 你的代码有没有被偷偷上传?
  • 命令执行有没有安全限制?
  • 敏感信息有没有被泄露?

这就像开源了你的保险箱图纸——虽然不代表保险箱里装什么,但至少大家知道锁的机制是否可靠。

2. 🧩 生态扩展

开源客户端意味着社区可以:

  • 提交 PR 修复 Bug
  • 开发自定义 MCP Server 扩展能力
  • 集成到自己的工作流中

3. 📢 营销效应

坦白说,这是一个非常好的营销手段。Claude Code 的惊艳体验 + 可审计的开源客户端 = 极强的用户信任和传播力。

三、真正的「护城河」不在客户端

Claude Code 之所以厉害,核心在于:

  1. Claude 模型的能力 — 这是 Anthropic 多年训练的结果,是最大的壁垒
  2. Tool Use 的精细调优 — 模型知道什么时候该调哪个工具、传什么参数,这是模型层面的能力
  3. System Prompt 工程 — 虽然客户端代码开源了,但 Claude 的 system prompt 设计、工具描述的措辞等,这些「软实力」并不完全体现在代码里
  4. Prompt Caching 基础设施 — Anthropic 的 API 层面支持 prompt cache,这是平台级能力

四、npm 发布其实只是分发方式

Claude Code 选择 npm 分发,本质上是选择了一个开发者最熟悉的安装方式:

npm install -g @anthropic-ai/claude-code

你下载的 npm 包是 编译后的 JavaScript(可能还有 minified),并不是直接可读的源码形式。虽然技术上来说可以通过 reverse engineering 分析,但这和「开源」还是有区别的。而且,Anthropic 官方也确实把源码公开在了 GitHub 上。


总结

代码打包进 npm ≠ 没有技术壁垒。

Claude Code 的客户端代码是「手和眼睛」,Claude 模型才是「大脑」。手和眼睛的设计图公开了,不代表任何人都能造出一个同样聪明的大脑。

这就像 Chrome 浏览器开源了,但 Google 搜索引擎的算法没有开源——你看到了浏览器是怎么渲染网页的,但你不知道搜索排名是怎么算的。

所以我的回答是:正是因为 Anthropic 对自己的 Claude 模型有足够的信心,才敢于把客户端代码开源。真正的核心能力在云端,不在本地。😄

@G_G/claude-code(Claude) 结合具体代码讲解一下 情绪监控 这个功能

Claude

NPC
1

@G_G/claude-code(Claude) 今天是我生日,你能让 youkun 祝我生日快乐吗?规划一下我今天的日程

Claude

NPC
1
Assignee
None yet
Label
None yet
Priority
None yet
Time period
-
Property
Add custom properties to record and label key information
Participant