同一个 Claude,两种表现:Coding Agent 的六个内部零件

你有没有注意到一件事:同一个 Claude 3.7 模型,在普通聊天窗口里写代码,跟在 Claude Code 里写代码,体验差距大得像两个产品。

不是模型不一样------模型权重完全相同。差的是包裹它的那一层工程架构,业界叫它 Agent Harness

这层 harness 到底做了什么?Sebastian Raschka(《Build a Large Language Model From Scratch》作者)上个月发了一篇让我反复看了三遍的长文,把 coding agent 的六个核心组件拆得很透。今天我结合源码,把这六个零件讲清楚。

讲完你会明白一件事:2026 年 AI 编程的真正竞争,不在模型,在 harness 的工程质量。

先搞清楚:LLM / 推理模型 / Agent Harness 是三层不同的东西

很多人混用"大模型""推理模型""AI Agent"这几个词,但它们其实是三个不同的抽象层:

LLM(基础语言模型):接收 token 序列,输出 token 序列。Claude 3.7 Sonnet、GPT-4o、Gemini 2.0 这些都是这层。它们本质上是一个复杂的条件概率函数。

推理模型(Reasoning Model):在 LLM 上叠加了 chain-of-thought 的系统性使用,比如 o3、Claude 3.7 Extended Thinking。不是新模型,是用法的提升。

Agent Harness:包裹模型的工程框架。负责循环调用模型、管理工具、注入上下文、持久化状态。Claude Code、Codex CLI、Cursor 都是这层。

三层的关系大概是这样的:

层级 代表产品 核心工作 改变难度
LLM Claude / GPT-4o token 预测 极高(需要训练)
推理模型 o3 / Extended Thinking 系统性 CoT 高(需要强化学习)
Agent Harness Claude Code / Cursor 工程编排 中(纯工程问题)

这说明什么?Harness 层的改进是纯工程问题,不需要训练,但它的好坏直接决定用户体验。这也是为什么同一个模型,不同 harness 包裹出来的效果天差地别。

第一个零件:Agent Loop(观察-检查-选择-执行循环)

Harness 的核心是一个无限循环,它把 LLM 从"一问一答"变成"持续执行直到任务完成"的自主系统。伪代码大概是这样:

python 复制代码
async def agent_loop(task: str, tools: list[Tool]) -> str:
    messages = [{"role": "user", "content": task}]
    
    while True:
        # 1. OBSERVE: 调用模型
        response = await llm.complete(
            messages=messages,
            tools=tools,
            system_prompt=SYSTEM_PROMPT
        )
        
        # 2. INSPECT: 检查模型意图
        if response.stop_reason == "end_turn":
            return response.content  # 任务完成
        
        if response.stop_reason == "tool_use":
            tool_calls = extract_tool_calls(response)
            
            # 3. CHOOSE & ACT: 执行工具
            tool_results = []
            for call in tool_calls:
                result = await execute_tool(call.name, call.input)
                tool_results.append({
                    "tool_use_id": call.id,
                    "content": result
                })
            
            # 4. 将结果追加到对话历史
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})
        
        # 安全退出条件
        if len(messages) > MAX_TURNS:
            return "达到最大轮次限制"

这个循环看起来简单,但细节里藏着很多工程决策:

• 循环退出的条件是什么?仅仅依赖 stop_reason == "end_turn" 不够,还需要检测模型是否陷入工具调用死循环。

• 工具执行是串行还是并行?Claude Code 对独立的工具调用做并发处理,显著降低延迟。

• 出错了怎么办?工具执行失败需要把错误信息反馈给模型,让它自己决策重试还是换策略------这是 self-correction 能力的来源。

第二个零件:Repo Context 注入(代码库感知)

这是 coding agent 和通用 chatbot 最大的差异点。一个优秀的 coding agent 需要知道:当前仓库的目录结构、目标文件的内容、相关函数的定义、测试用例的期望行为。

但你不能把整个代码库塞进 context------哪怕 Claude 支持 200K token,大型仓库分分钟超限,而且大量无关代码会让模型分心。解决方案是"按需注入":

python 复制代码
class RepoContextManager:
    def __init__(self, repo_root: str):
        self.repo_root = repo_root
        self._file_tree = None
        self._symbol_index = {}  # 函数名 -> 文件路径:行号
    
    def get_initial_context(self) -> str:
        """启动时注入:轻量级目录树 + 关键配置文件"""
        tree = self._build_compact_tree(max_depth=3)
        readme = self._read_if_exists("README.md", max_chars=2000)
        return f"\n{tree}\n\n\n{readme}"
    
    def search_symbol(self, name: str) -> list[dict]:
        """按需工具:搜索函数/类定义"""
        results = []
        for pattern in [f"def {name}", f"class {name}", f"function {name}"]:
            matches = self._grep(pattern)
            results.extend(matches)
        return results
    
    def read_file_chunk(self, path: str, start: int, end: int) -> str:
        """按需工具:读取文件片段,而非整个文件"""
        lines = self._read_lines(path)
        return "\n".join(lines[start-1:end])
    
    def _build_compact_tree(self, max_depth: int) -> str:
        """生成紧凑目录树,自动忽略 node_modules/.git/build 等"""
        ignore_patterns = {'.git', 'node_modules', '__pycache__', 
                          'build', 'dist', '.gradle', 'Pods'}
        # ... 实现省略
        pass

注意这里有个关键设计:初始 context 只放"导航地图"(轻量目录树 + README),真正的代码内容通过工具调用按需获取。这和 RAG 的思路类似------先检索再精读,而不是一次性全量加载。

Claude Code 还做了一个更聪明的事:它会分析 git history,优先展示最近修改过的文件,因为这些文件很可能和当前任务相关。

第三个零件:Tool Use 设计(工具集的精心选型)

工具太少,agent 无法完成任务。工具太多,模型会选错工具("tool confusion"),而且每个工具定义都占 token。Claude Code 的工具集大概是这样分层的:

文件操作层:read_file / write_file / edit_file(注意:edit 比 write 重要,因为大文件只需要发送 diff,不用发送全文)

Shell 执行层:bash(带超时、带输出截断、带沙盒限制)

代码智能层:search_files / grep / find_symbol(语义搜索而非纯字符串匹配)

验证层:run_tests / check_syntax / lint(执行完改动要能自我验证)

其中 edit_file 的设计最值得关注。一个朴素实现是每次都用 write_file 覆盖整个文件,但这有三个问题:上下文 token 消耗大、覆盖时容易引入不相关修改、无法追踪增量变更。更好的设计是基于 unified diff 格式:

python 复制代码
# 工具调用示例:edit_file
{
  "tool": "edit_file",
  "input": {
    "path": "src/auth/login.py",
    "old_string": "def validate_token(token: str) -> bool:\n    return token in VALID_TOKENS",
    "new_string": "def validate_token(token: str) -> bool:\n    if not token:\n        return False\n    return token in VALID_TOKENS and not is_revoked(token)"
  }
}

# 对应的工具实现(简化版)
def edit_file(path: str, old_string: str, new_string: str) -> str:
    content = Path(path).read_text()
    if old_string not in content:
        return f"ERROR: 找不到目标字符串,请重新确认上下文"
    
    # 只替换第一次出现(避免批量误改)
    new_content = content.replace(old_string, new_string, 1)
    Path(path).write_text(new_content)
    
    # 返回 diff 供模型确认
    diff = unified_diff(
        content.splitlines(keepends=True),
        new_content.splitlines(keepends=True),
        fromfile=f"a/{path}", tofile=f"b/{path}"
    )
    return "".join(diff)

让模型用 old_string/new_string 的方式描述修改,是个很聪明的设计:它强迫模型先"看清楚"要改的地方,减少幻觉式覆盖。如果 old_string 找不到,说明模型对文件内容的理解有误,工具直接报错,模型可以重新 read_file 校准。

第四个零件:Prompt Cache 稳定性(省钱的艺术)

这个零件很容易被忽略,但它可能是 Claude Code 在成本控制上最关键的工程优化。

Claude API 提供 prompt caching:如果请求前缀和上一次完全一样,可以复用 KV cache,输入 token 费用降低 90%。问题是,哪些内容构成"稳定前缀"?

• System prompt:完全固定,天然适合缓存。Claude Code 的 system prompt 据估计有数千 token,每次请求都缓存这部分。

• 工具定义(Tool Schemas):JSON 格式的工具描述,内容不变,适合缓存。

• 已完成的对话历史:上一轮的 assistant + user 消息,可以作为缓存前缀的一部分。

要实现稳定缓存,关键是保证前缀内容的顺序和内容不随意变动。一个常见的坑是:如果你的工具列表顺序在不同请求间会变化(比如动态加载工具),缓存就会频繁失效。

ini 复制代码
# 显式标记 cache_control 的请求结构(Anthropic API)
messages = [
    # cache point 1: system + tools(最稳定的部分)
    {
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": SYSTEM_CONTEXT,  # 上万 token 的系统上下文
                "cache_control": {"type": "ephemeral"}  # 标记缓存点
            }
        ]
    },
    # ... 对话历史 ...
    # cache point 2: 截至上一轮的完整对话
    {
        "role": "user", 
        "content": [
            {
                "type": "text",
                "text": "继续执行",
                "cache_control": {"type": "ephemeral"}  # 第二个缓存点
            }
        ]
    },
    # 当前轮次的新消息(不缓存)
    {"role": "user", "content": current_message}
]

实际上 Claude Code 在每次对话结束后,累计 token 的 80-90% 理论上都可以走缓存。对于长会话,这直接决定了产品的经济可行性。

第五个零件:Memory 管理(记住什么,忘掉什么)

Coding agent 的 memory 需求和通用 chatbot 不同。它需要跨轮次记住:当前任务的整体目标、已经做了哪些修改、哪些路径已经探索过但失败了、用户明确表达的约束条件("不要动 tests/ 目录")。

这些东西如果都堆在 message history 里,会有两个问题:token 消耗随对话轮次线性增长;早期的关键信息会因为 context 过长而被"稀释"(模型注意力下降)。

更好的设计是分层 memory:

Working Memory(短期,放在 context 里):当前任务状态、最近几轮工具调用结果

Episodic Memory(中期,动态写入):重要的发现和决策,以结构化形式追加到 system prompt 的专用区域

External Memory(长期,本地文件):CLAUDE.md / .claude/memory.json,持久化跨会话的仓库知识

python 复制代码
# Claude Code 会在项目根目录查找 CLAUDE.md
# 这个文件相当于"仓库级 system prompt"
# 示例 CLAUDE.md 内容:

"""
## 项目约定
- 使用 pytest,不用 unittest
- 所有公开 API 必须有类型注解
- 数据库操作通过 repository pattern,不要直接操作 ORM

## 已知陷阱
- config.py 里的 DATABASE_URL 在测试环境和生产环境格式不同
- migrations/ 目录下的文件名必须按时间戳排序

## 常用命令
- 跑测试:make test
- 格式化:make fmt
- 部署:./scripts/deploy.sh staging
"""

这个设计极其实用:不需要每次都跟 agent 解释项目规范,也不会因为 agent 换了 session 就"失忆"。对于大型项目,一个维护良好的 CLAUDE.md 能把 agent 的有效性提升一个数量级。

第六个零件:长会话 Continuity(不崩溃的工程)

这是最容易被低估的一个零件。当你让 agent 做一个复杂任务("帮我重构整个认证模块"),它可能需要几十轮甚至上百轮工具调用。在这个过程中,有几个工程问题必须解决:

Context 溢出:Claude 的 context window 是有限的,对话历史不能无限增长。解决方案是"滚动压缩"------周期性地让模型对之前的对话做摘要,用摘要替换原始内容。

任务追踪:在长任务中,模型可能忘记最初的目标,陷入局部循环。需要在每次循环开始时显式注入"当前任务目标"。

断点恢复:网络中断、用户手动打断,再恢复时不应该从头开始。需要持久化检查点。

python 复制代码
class LongSessionManager:
    COMPRESS_THRESHOLD = 80000  # token 数超过这个值时触发压缩
    
    async def maybe_compress(self, messages: list, current_tokens: int):
        if current_tokens 
相关推荐
Ztopcloud极拓云视角4 小时前
GPT-6、Claude Opus 4.7、DeepSeek V4同期上线,如何快速搭一个自动选模型的路由网关?
gpt·claude·deepseek
百度Geek说5 小时前
读完 Claude Code 源码才发现:Skills、MCP、Rules 的区别,远没有你想的那么大
claude
suke6 小时前
Claude Opus 4.7 来了:代码能力暴涨,还能“看见”更多细节,关键是没涨价
人工智能·ai编程·claude
javaTodo6 小时前
2026 最新 Claude Code 国内上手教程:从安装到第一次跑通,完整流程一次讲清
claude
davidson14717 小时前
VSCode配置Claude Code
vscode·ai·大模型·claude
xixixi777777 小时前
AI驱动安全变革:Axios零交互劫持云元数据+CVE-2026-40175,Claude Mythos加速至小时级,攻防不对称重构安全架构
人工智能·5g·ai·claude·攻击·多模态·安全架构
AI 赋能7 小时前
Claude Code for VS Code 使用手册
vscode·claude
Hoper.J8 小时前
目前 Claude / GPT 的订阅建议与反代避坑
gpt·claude·反代
与虾牵手1 天前
Claude Opus 4.6 编程实战:2026 最强代码模型的 3 种调用方式与踩坑记录
ai编程·claude