来源:互联网 更新时间:2026-08-02 07:27
你在终端里敲下一句话,按下回车。屏幕上,字一个一个地冒出来——中间还自己跑了几个命令、读了几份文件、改了一两个文件,最后给你一段总结。整个过程可能也就一两秒,也可能几十秒。
好,那这一秒里,到底发生了什么?
是模型一口气把所有东西都想好再吐出来,还是边想边做?
那些“自己跑的命令”是谁、在什么时候决定跑的?
它们和最后那段文字总结又是什么关系?
如果模型中途改主意——本来要读 A 文件,读到一半又想去改 B——这是怎么发生的?
这些问题,恰恰是理解 Claude Code 这类 Agent 的钥匙。那答案是什么呢?
说穿了,答案一点都不神秘。整个流程摊开来看,就是一条再普通不过的流水线,再加上一个 while 循环。这套让模型能动手的脚手架,有个名字叫 Harness。
你的输入先被加工成一条结构化消息,然后送进一个叫 query 的异步生成器;
query 自己几乎不干活,它通过 yield* 把控制权整个交给 queryLoop——一个 while 循环;
循环里,模型和工具来回接力:模型说“我要读这个文件”,工具就跑、把结果塞回去;模型再说、工具再跑,直到模型说“我说完了”;
每一步都通过 yield 把事件流式喷回 REPL,REPL 再用 Ink 把它一个字一个字地画到你的终端上。
一句话概括:一次回合 = 一个 while 循环 + 一条流式事件管道。
这里有两个关键词值得记住。一是“循环”——Agent 的所有“自主性”都来自它;二是“流式”——你看到的打字机效果、工具实时进度、可中断的 Ctrl+C,都建立在 yield 这个字上。下面三节,就是把这句话拆开揉碎来介绍。
要拆开它,最省力的入口不是直接啃源码——src/query.ts 有 1700+ 行,光 queryLoop 就占上千行,啃下去只会迷路。先把骨架剥出来。剥掉 hook、权限校验、压缩、计费、日志这些外壳,剩下的和一个 8 行的玩具 Agent 没有本质区别。
下面这段,就是 Harness 一次回合的最小骨架:
# 极简版: harness 行动回路的最小实现
messages = [{"role": "user", "content": prompt}]
while True:
resp = client.messages.create(model=MODEL, messages=messages, tools=tools)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use": # 模型不再要工具 → 说完了
break
results = run_tools(resp.content) # 执行模型要的工具
messages.append({"role": "user", "content": results}) # 结果塞回去
盯住三个关键点:
while True:没有固定次数的循环。什么时候结束,不靠计数器,靠模型自己说“完了”。这是 Agent “自主性”的源头——而这个“自主”,Harness 一行都没写,它全在模型里。stop_reason:模型每一轮都会给一个停下的理由。要工具就是 tool_use,说完话就是 end_turn。整个 Agent 的行为分支,都挂在这个模型吐出的字段上。messages.append(...):工具结果不是悄悄用的,而是作为新的 user 消息塞回对话历史。对模型来说,它看到的始终是一条连续的对话——工具的“动手”被翻译成了对话里的“该你了”。所以,把这三个点记住,后面做 Harness 工程实践时,就不会被各种 hook、权限、压缩、子 Agent 带跑——它们都是 Harness 给这个骨架添的“器官”。骨架本身,只有这三行。
还有一个细节:这段极简版是“同步”的——create 调完拿到完整 resp 才往下走。而 Claude Code 的真实实现是流式的,模型边吐 token、循环边收。但骨架没变,只是把“一次性 resp”换成了一串时序到达的事件。流式改变的是体验和响应度,不是结构。
有了骨架,我们把 Claude Code 真正的实现叠上去。下面这张图就是一次完整回合的全景——也是 Harness 五脏在这一秒里的速览。每个节点都是一个“器官”,后面都会单独放大;但请先记住这张图,它是后面所有的导览。

逐个节点介绍一下,顺便认认器官:
handlePromptSubmit(src/screens/REPL.tsx),这一回合的“启动按钮”。Message,塞进对话历史。这一步会拼上 system prompt、CLAUDE.md、memory——那是上下文工程这个器官的活,后面详聊,这里只当成“造一条消息”。query(src/query.ts)。注意它声明里的 *——async function*,异步生成器,可以一边跑、一边往外吐事件。query 自己几乎不干活,它通过 yield* queryLoop(...)(src/query.ts)把控制权整个交给 queryLoop(src/query.ts)。这才是行动回路真正的心脏。stop_reason。tool_use 分支——执行工具、把结果塞回消息、回到循环顶继续问模型。这条回路就是 Agent “自己跑命令”的来源,它就是工具系统(Part 2)在行动回路里的接口。end_turn 分支——收尾、把整条路径上累积的事件一路 yield 出去。中间那道 Stop Hook,是安全护栏插进来的拦截点。query 的 yield* 回到 REPL 的 for await (const event of query({ ... }))(src/screens/REPL.tsx),onQueryEvent 把它翻译成 React state,Ink 把新 state 渲染到终端——这是人机交互的一端。一句话总结这张图:回车 → 加工 → query → queryLoop(模型/工具来回接力)→ 流式 yield → 渲染。生产级的所有魔法,都缩在中间那个循环里;而那个循环,就是行动回路。
现在回头看第 1 节留下的那个悬念——“Harness 到底干了什么”。答案就散在这张图的节点上,化作你能看见的三种现象:
yield。模型每生成一个 token、工具每产出一行,都是一帧事件,被 REPL 收到就立刻画到屏幕。你看到的“打字机效果”不是前端动画,是事件真的按时序到达——屏幕显示的速度,就是模型生成的速度。也正因事件是流式的,你按 Ctrl+C 才能随时在某一帧打断它。tool_use 分支。模型判断“我需要读这个文件”,queryLoop 就让对应工具跑、把输出塞回对话历史,再回到循环顶继续问模型。你看到它“自己读了三个文件、改了一个”,其实是这条回路被走了多次,每次都让模型基于新结果再决策一次。模型并不会预先规划“读三个文件”——它每一轮根据最新信息临时决定下一步。end_turn。模型主动给出这个 stop_reason,循环才会退出。在此之前,queryLoop 永远不会“自己决定结束”——Agent 的终点,始终是模型自己选的。发现了吗?这三种现象里,没有一种是 Harness “想”出来的。 Harness 只负责把模型的决策搬运成动作、把动作的结果搬运回模型。智能始终在模型那一边。
把整套 Harness 想成一个值班室。
你是送件人,把一张工单(输入)递进窗口。值班员(queryLoop)拿到工单后只做一件事:打电话问专家(模型):“这个怎么处理?”
专家回:“我需要查一下 X 文件。”值班员不自己查,而是让助理(工具)去查、把结果带回来,再打电话给专家:“查到了,内容是这样,然后呢?”专家又回:“那再看一下 Y。”如此循环。
直到某一次,专家说:“行了,我懂了,答案是这个。”——end_turn。值班员把最终答案整理好,从窗口递回给你。
关键看分工:值班员和助理都是 Harness,专家才是 Agent(模型)。 值班员不思考,只传话和派活(行动回路);助理不判断,只动手(工具系统);真正做决策的只有专家。循环驱动、分工清晰——这就是 Harness 的本质。Claude Code 的 query.ts 那 1700+ 行,大部分都是在给值班员、专家、助理各自添置护栏和助手:给值班员加恢复机制(不让循环崩)、给专家拼好上下文(工作记忆)、给助理加权限审批(护栏)。
还有个容易忽略的细节:值班员和专家之间的电话是双工的——专家一边说,值班员一边往外递(流式 yield),不是等专家挂电话才一次性汇报。这正是你在终端看到字一个一个冒出来的原因。这个比喻背后,正好对应 TypeScript 里 async function* 和 for await 这对语法:它们天生就是为“边产边消费”的流式管道设计的。
回到最开始那个错觉:Claude Code 的智能,不在它的代码里。代码是 Harness, Agent 是模型。一次回合,不过是 Harness 用一个 while 循环把模型的决策变成动作、再流式画到屏幕——query.ts 那 1700+ 行,全是给这个循环配的器官和护栏。
而这套 Harness 的器官,正好就是整部系列的地图:
记住这张地图,这个就是整个 Harness 的五脏六腑。
现在我们回顾一次会话的处理过程,会发现里面藏着一个问题:万一专家一直要工具、永远不说“说完了”怎么办?或者更现实的——对话太长、上下文窗口快爆了、工具失败了、权限拒绝了,这时循环怎么自救?那 8 行的 while True 根本 hold 不住,它会要么无限转下去、要么崩出一个 stack trace。
8 行的 demo 循环,和 1700+ 行的生产级 queryLoop,差就差在“怎么不崩”上。 这正是 Harness 工程的核心难题之一: 可靠性。
下一篇,我们就钻进 queryLoop 这个节点,看它一个循环里的 7 种 continue——每一行 continue 都是一种自救动作:工具失败时怎么重试、上下文将满时怎么压缩、配额超限时怎么降级、模型越界时怎么拉回来。把那 7 条路看明白,你才会真正相信:Agent 不会在半路卡死。
Let's go!
ThinkBook系列最新价格全解析:2026年选购避坑与实时询价指南
Ondo将于今日上线股票永续合约
暗黑4S14野蛮人终局BD攻略
区块链OTC交易所有哪几家比较正规?
Binance新增15种bStocks代币化证券为杠杆抵押资产
Meme币DOGS今晚上线!开局就解锁91%代币是否带来风险?
忍者必须死3极刃血影角色介绍
晶核艾尔莎角色盘点 晶核艾尔莎强度分析与实战表现
余姚的路虎4s店在哪个位置
彩云天气怎么看分钟级降雨预报 彩云天气精准预报方法【技巧】
五千元以下的笔记本几乎消失!经销商:至少一年看不到涨价尽头
Intel喜讯连连:18A工艺良率提升到85%、CPU将涨价15%
遗忘之海密室通关教程 遗忘之海密室全关卡解谜思路与难点解析
华为Mate 70系列首发的红枫镜头下放至千元档:全员普及原色影像
合集38个项目筹集5.406亿美元 Figure融资2亿
国家养老服务消费补贴上线京东
英伟达机器人团队在京沪深招人,聚焦具身智能等四大领域
一站式PDF转Markdown解决方案PDF3MD
硬刚苹果!华为9月新品阵容出炉:Mate 90系列、全新三折叠
微软Copilot AI漏洞可致敏感数据泄露,企业用户需及时更新
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc