尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Agent Harness:从Claude Code源码拆解智能体运行框架

Agent Harness:从Claude Code源码拆解智能体运行框架 你第一次跑通 Claude Code 那条命令的时候大概会有一种感觉它不像一个普通问答工具更像一个能自己读文件、改代码、执行命令的“数字员工”。它为什么能连续干活它靠的是什么把模型、工具、终端、权限串在一起这些问题背后的答案就是 Agent Harness。很多人装了 Claude Code、用上了 Skill、配好了 VSCode 插件但对它内部怎么组织逻辑仍然是一团黑。这篇文章我会围绕 Claude Code 的实际运行方式从源码视角拆解 Agent Harness 到底是什么顺便聊聊这类工具真正值得理解的部分以及你怎么用一套通用框架去读懂它。先给一个贯穿全文的主判断真正让 Agent 连续工作的往往不是模型本身而是模型外面那层“框架”。Claude Code 只是这类框架的一个具体产品实例Agent Harness 才是值得投入时间去理解的东西。理解了它你才算真正“从零开始”读懂了 Claude Code 这一类工具。1. 为什么看源码之前先要理解 Harness 这个词1.1 Harness 不是“智能体”它是绑在智能体外围的控制系统英文里 Harness 原意是“马具、安全带、线束”引申一下就是“绑定、约束、把力量传导出去的工具”。这个名字放在 Agent 领域里其实非常传神Agent 负责产生意图、生成决策但意图要变成实际动作需要有一层东西去接收、校验、执行、反馈。这层东西就是 Harness。一句话区分Agent负责“想怎么做”输出决策或计划。Harness负责“怎么动起来”把决策翻译成命令行、文件修改、工具调用再把执行结果送回模型。很多人看到“Harness 和 Agent 区别”的讨论时会绕晕其实本质就是一个边界问题Agent 在模型生成的内容里工作Harness 在模型之外做编排。模型是发动机Harness 是变速箱、方向盘和仪表盘。单一的话模型跑不出完整任务少了 Harness模型每次输出的只是一段文本不会变成真实动作。1.2 Claude Code 就是 Agent Harness 的一个实例Claude Code 是 Anthropic 出品的终端 Agent 工具它能读项目、改文件、执行命令看起来像“模型很聪明”。但从产品实现的方式去反推你会发现它内部必须承载这几件事命令行入口、会话状态、工具注册表、权限控制、上下文管理、循环调用。这些东西拼在一起就是一个典型的 Agent Harness。这也是为什么只把 Claude Code 当成对话工具用会浪费它的原因。它真正的价值不在于“多聊几轮”而在于把“模型—工具—文件系统—终端命令”串成一个可以反复执行的工作闭环。这个闭环不是模型自带的而是 Harness 设计出来的。如果你关注过 Claude Code 的分发方式会看到它更像一个封装好的 CLI 分发包。所谓“手撕源码”很多时候不是去读一份开放仓库里的漂亮代码而是去读分发产物里的实际逻辑、依赖关系和调用链。这种方式反而更接近工程现场你看到的是产品真正跑起来的代码不是整理过供人阅读的代码。2. 从源码视角拆解 Claude Code 的运行骨架2.1 一条命令跑起来之后内部到底经历了什么假设你在项目根目录执行claude接下来几十毫秒内一个 Agent Harness 大致完成了五件事读取 CLI 参数和配置文件确定工作目录、模型、权限策略、输出格式。组装初始上下文系统提示、当前目录结构、关键文件内容、工具说明、对话历史。调用模型把“可以做什么”“现在是什么状态”一并交给模型。解析模型输出。如果输出里有工具调用意图Harness 会校验并分发执行。把工具执行结果拼接回上下文进入下一轮循环直到满足终止条件。这段流程里最容易被忽略的是第 4 步。很多人以为模型“调用工具”像人调用函数一样直接实际上模型只会输出一段结构化文本比如 JSON 格式的调用意图。真正解析、鉴权、执行、把结果返回给模型的是 Harness 代码。我把这套结构理解成一张职责表模块核心职责如果你不实现它会发生什么CLI 入口读取参数、环境变量、配置文件工具无法持久化配置每次使用都要重复指定上下文组装决定模型“看得见”哪些信息模型看不到项目结构生成的代码往往跑不通主循环控制“模型—工具—结果”的往复节奏Agent 只能单次回答无法完成多步任务工具注册表声明可用工具和参数格式模型不知道怎么发起文件读写或命令执行权限管理判断哪类操作可以直接执行Agent 可能随意执行危险命令或反之无法做任何操作输出渲染把内部过程转成终端结果用户只能看到最终文本不清楚中间发生了什么这六块合起来才是“Agent Harness”的基本盘。你平时感受到的“这个工具好用”其实是这六块协同的结果。2.2 工具调用不是魔法是“模型一句话 框架一整套流程”Claude Code 里最常做的一类事情是让模型帮忙改文件、执行测试、查日志。但模型本身并不直接和文件系统交互它只负责输出“调用某工具、参数是什么”的结构化数据。Harness 收到这份数据后要做的事包括校验工具名是否在允许列表里。校验参数类型、文件路径、命令是否命中权限策略。执行真正的读写操作或命令。把标准输出、标准错误、退出码收集起来。将结果格式化成模型能理解的文本追加到上下文里。这中间任何一个环节出错都可能导致模型“胡说”。比如工具结果太长被截断模型后续判断就会失真权限策略太紧工具调用直接失败模型会尝试换个说法绕开限制。所以源码级调试时先定位“调用是否到达工具层”和“结果是否正确回流”往往比改提示词更有效。2.3 上下文管理才是 Harness 最难做好的部分Agent 任务越复杂上下文就越是核心。Harness 需要调和三份信息系统提示、对话历史、工具执行结果。这三份信息会拼成一个非常长的文本送入模型。问题也随之而来历史越长模型注意力越容易被稀释工具结果越多越容易把真正目标冲淡。Claude Code 这类工具会在产品层给出“查看上下文、压缩历史、重置会话”的入口本质就是为了应对这个问题。底层 Harness 要做的事情也很直接决定哪些内容进上下文、哪些不进、哪些可以折叠、哪些必须实时拼接。源码级别的差异往往就体现在这个决策逻辑上。3. 先跑通一个最小的 Agent Harness再回到 Claude Code3.1 一个最简主循环长什么样要理解哈里斯的原理动手写一个最小实现比读半天文档更有效。下面的代码不是 Claude Code 的真实实现而是一个通用的最小骨架用来展示核心循环的四个环节调模型、解析意图、执行工具、把结果塞回消息记录。一个极简 Agent Harness 骨架用于理解核心循环。 import json from dataclasses import dataclass, field dataclass class ToolResult: name: str output: str dataclass class Message: role: str content: str tool_calls: list field(default_factorylist) def run_agent(model, tools, messages, max_steps10): 最小主循环模型 - 工具执行 - 结果回流 - 再调用模型。 for _ in range(max_steps): resp model.chat(messages) # 1. 模型没有工具调用意图说明任务结束 if not resp.tool_calls: return resp.content # 2. 模型只给出调用意图真正执行要交给 Harness for call in resp.tool_calls: tool_name call[name] tool_args call[arguments] if tool_name not in tools: messages.append(Message(roletool, contentjson.dumps({ error: funknown tool: {tool_name} }))) continue # 3. 执行工具捕获结果 output tools[tool_name](**tool_args) messages.append(Message( roletool, contentjson.dumps({name: tool_name, output: output}) )) return Reached max steps, stop.这个版本只有三十行左右但它已经是一个完整的主循环。模型输出里带着一堆tool_calls框架负责分发。没有模型调用、没有执行器、没有循环的“Agent”本质上只是一次聊天。真正的 Claude Code 主循环远远复杂于这个示例但精神内核是一样的模型输出 - 工具执行 - 结果回流 - 再次模型输出。你在源码里找“主循环”时找的就是这一段往复结构。3.2 从最小骨架到真实产品的差距最简骨架能跑但离可用还差很远。从一个教育示例到一个能装机使用的 Harness中间缺的东西包括工具注册机制工具要用 JSON Schema 描述参数模型才能正确生成调用。权限策略哪些命令可以直接跑哪些需要用户确认哪些直接禁止。会话持久化退出终端后历史对话和工具状态还要能恢复。流式输出模型生成过程中用户需要实时看到内容。异常恢复工具执行失败、模型返回格式不合法、网络中断时怎么处理。成本控制每轮上下文长度、工具调用次数、模型带宽都要受限。这也是为什么“看起来很简单”的 Agent Harness实际工程里是一大块复杂代码。复杂度不在于“调模型”本身而在于把模型安全、可控、持续地接进真实环境。Claude Code 这类工具能让人产生“它在帮我干活”的体感正是因为这层工程框架足够成熟。4. 拿到源码之后按什么顺序读才能不被带偏4.1 四个关键词入口、循环、工具表、权限策略无论是读 Claude Code 的分发包还是读任何一个开源 Agent 项目我都会按同一个顺序去摸结构先找入口再找主循环再找工具注册表最后找权限策略。这个顺序背后的逻辑是依赖关系入口负责初始化循环依赖入口准备的环境工具注册表被循环调用权限又约束工具执行。按依赖先后顺序读才能在脑子里构建出“运行时链路”而不是陷入一堆零散函数名里。阅读顺序要回答的问题常见线索1. CLI 入口命令行参数怎么变成运行时配置main、cli、command、parse_args2. 主循环Agent 怎么反复推进任务agent_loop、run、while、max_steps3. 工具注册表模型能调用哪些工具tools、function、tool_call、register4. 权限策略哪些操作被放行、哪些被拦截permission、deny、confirm、policy5. 上下文组装模型每一轮看到的内容从哪里来system_prompt、context、history6. 输出渲染执行过程和结果怎么展示给用户render、output、format、stream第一次读源码时最忌讳一上来就钻到某个工具实现或某个提示词构造函数里。你会失去对整体结构的把握。先画一张“谁调用了谁”的链路图再往细节里填内容效率会高很多。4.2 从报错信息反查调用链是手感最快的来源读源码不只是为了读更是为了能排查问题。你可能会在接第三方模型时看到类似 “xxx is not a model this version of claude code recognizes” 的报错也可能会遇到 529 这类数字型错误。这些报错背后其实都对应着源码里的一处校验逻辑和一个调用链。以模型名不被识别为例排查的思路应该是看配置里填的模型名是不是当前版本支持的名称。看 Claude Code 版本和模型名之间的关系旧版本往往不认识新增的模型名。看是否有环境变量或配置文件把模型名映射成了别的名字。看请求发出时实际传给模型网关的model字段到底是什么。如果是走自定义网关或转发层还要确认网关是否原样透传了模型名。这个过程就是“从报错反查调用链”。源码里每个报错字符串都是一个入口它能帮你定位到具体校验逻辑所在的位置。读源码的能力本质上是建立这种“现象到代码位置”的映射。5. 高频报错背后其实都指向同一个地方配置和运行环境5.1 模型名不识别先别急着怪模型先看版本和上下文“deepseek-v4-pro is not a model this version of claude code recognizes” 这类报错在社区里讨论度很高。它至少透露出几个关键信息Agent Harness 本身维护一份可识别模型名的列表或校验逻辑。当你配置的模型名不在列表里Harness 会在请求发出之前拦截。模型名是否被识别和当前安装的版本强相关。换句话说这更像是“版本兼容”问题而不一定是模型本身不存在。遇到它时先看本机 Claude Code 版本再看官方支持列表然后确认自己用的模型名、别名、版本后缀是否一致。不要一上来就以为是密钥或网络问题。在接入第三方模型时这种报错会更常见。因为网关背后的模型列表可能和 Harness 内置列表不一致。此时你不是在“使用模型”而是在“适配 Harness 的校验规则”。理解这一点会大大减少排查焦虑。5.2 529 这类错误码先看现象再看请求链路的每一环搜索 Claude Code 常见问题时你会频繁看到 529 这类数字错误码。不同来源的解释可能都不一样有说是服务繁忙、有说是请求受限、也有说是网关层拦截。我不会在这里断言 529 一定是什么因为它的真实含义要以官方错误说明为准。但从排查链路的视角看它指向的永远是“请求没有正常完成”这个事实。你可以按这个顺序排查看现象是完全失败还是偶发重试后成功。看时间点是否集中在某个高峰期。看请求量批任务或并发任务是否同时打满。看中间层有没有自建网关、透明转发层或统一出口改变了状态码。看日志Harness 是否保留了请求响应时间、重试次数和原始返回体。这种事最忌讳“搜到一个帖子说某个原因就直接照着改配置”。因为数字型状态码在多层架构里可能被不同的中间层语义化。没有日志支撑的猜测解决不了根本问题。5.3 当你总是被环境问题绊住时大概率是没理解 Harness 的运行条件Claude Code 能跑起来不是因为有一条命令就够了。它需要满足这些前置条件一个能访问模型的 API 配置或网关配置。明确的工作目录Harness 会基于这个目录做文件操作和命令执行。工具命令可用比如 git、shell 命令、语言运行时。权限策略允许 Harness 执行相应动作。上下文容量能装下必要的项目和任务信息。很多人卡在“安装了但跑不顺”的状态问题往往不在模型能力而在于 Harness 运行环境没准备好。你自己接入一个模型、配一个工作目录、跑一次最小任务会比反复修改提示词更能定位问题。6. 理解 Harness 之后最该带走的是什么6.1 从 Claude Code 迁移到其他 Agent 工具时你已经不再是新手理解了 Harness你就获得了迁移能力。市面上能见到的 Agent 类 CLI 工具无论是 Claude Code、开源的 Agent 框架还是其他基于模型的命令行工具骨架都是相似的。它们都要处理入口、循环、工具调用、权限、上下文和输出。你会更快看懂新工具因为你在找的是同一个主线主循环在哪里工具怎么注册权限怎么卡上下文怎么组装。这些结构能力比记住某个工具的具体用法更重要。工具会更新API 会变但一套稳健的“Harness 心智模型”能让你面对新东西时快速重建理解。6.2 什么情况下你其实不需要读源码什么情况下必须读读源码不是所有使用者的必选项。如果只是把 Claude Code 当命令行助手用日常改改文件、跑跑命令那么读源码的投入产出比很低你更需要的是文档、示例和良好配置习惯。但如果你遇到下面这些情况源码阅读就变成必要手段你想给 Claude Code 接入自有网关、私有模型或定制工具。你想给团队设计一套可控的 Agent 工作流需要做权限和边界设计。你频繁遇到报错文档已经不能解释调用链细节。你想从 Claude Code 迁移到自研或开源的 Agent Harness 上。你在做安全审查需要判断每个工具调用的权限边界。读源码不是目的理解运行边界才是。源码只是告诉你“它为什么能跑”和“它会怎么出问题”的最终依据。6.3 真正的长期价值是你看问题的角度变了当你看过一个 Agent Harness 的主循环和工具调用链再回头看 Claude Code你看到的不再是一个“神奇工具”而是一个有清晰层次的技术系统。系统里有入口、有循环、有权限、有上下文管理、有输出渲染。每一层都有可能出问题也都可以被调试和优化。这种视角才是“从零理解 Agent Harness”的长期收益。下一次你再听到某个 Agent 工具多强你不会只关心它能不能完成任务还会想它的 Harness 靠什么实现连续性、靠什么控制权限、靠什么管理上下文。这才是技术人真正该沉淀的判断力。如果你现在正打算深入 Claude Code我希望你先从一个最小任务开始跑通一次文件修改开启权限确认观察工具调用的过程然后再打开代码找主循环。把“模型”的优先级放低一点把“框架”的优先级拉高一点。你会发现世界突然清晰了。
返回列表