
最近主力用 Codex 和 WorkBuddy 干活时间长了,感觉到用得越多,项目持续时间越长,就暴露出一些以前用AI编程智能体没有遇到过的问题了。
例如在这篇文章不会发生人工智能导致的就业危机提到:“因为前面塞入了必要的项目约束,上下文比较长,会导致在项目后期执行时,降智的感觉。”
正好看到有个讲解怎么从零开始开发AI编程智能体的项目,想着了解了解其中的原理。
一是后续是不是自己能写一个;
二是即使不写,了解原理,能更好的使用,也许能避免或者解决些日常遇到的问题。
这个就是 shareAI-lab 最近开源的 learn-claude-code 。
早期我记得刚接触 Langchain 这类 LLM 开发应用框架时,主要思考逻辑还是怎么用 if-else 把几次 API 调用串起来。
从产品的变迁来看:大模型刚出来时,都在研究权重、微调和 RLHF;
随后开始关注提示词、检索增强生成(RAG) 和长上下文;
再接下来工具调用、MCP 成了关键词;
到了 2026 年,技能Skill 实现了能力的扩展之后,真正让大模型变得能执行任务,是 Harness。
除模型本身以外的所有工作,都属于 Harness 的范畴。
Harness 负责约定项目规则、搜索代码库、管理上下文;控制开发任务和产品定义,约定边界;
把模型的决策转成 shell 命令、文件编辑和测试执行,再把测试结果、日志输出、浏览器内用户执行放入上下文。
AI Code Agent 是一个“思考—行动—反馈—修正”的长循环。
循环在实际工作场景是否能跑通,靠的就是 Harness。
Claude Code 的核心并不神秘,本质上就是一个 Loop:
调用模型,提供上下文管理,运行工具,拿到反馈,再继续调用模型。
Harness = Tools + Knowledge + Observation + Action + Permissions
Tools: 文件读写、Shell、网络、数据库、浏览器
Knowledge: 产品文档、API 规范、风格指南
Observation: git diff、错误日志、浏览器状态
Action: CLI 命令、API 调用、UI 交互
Permissions: 沙箱隔离、审批流程、信任边界模型做决策,Harness 执行。
模型是驾驶者,Harness 是载具。
核心就是一个 while stop_reason == "tool_use"。
def agent_loop(messages: list):
while True:
response = client.messages.create(
model=MODEL, system=SYSTEM, messages=messages,
tools=TOOLS, max_tokens=8000,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
return
results = []
for block in response.content:
if block.type == "tool_use":
output = TOOL_HANDLERS[block.name](**block.input)
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": output,
})
messages.append({"role": "user", "content": results})循环体外的机制:权限检查、任务规划、子Agent派生、上下文压缩、团队协作、定时任务。
s04 加 Hook,循环体里从 if not check_permission(block) 变成 if trigger_hooks("PreToolUse", block)。
s05 加 TodoWrite,Agent 动手前先列计划。
s06 加子Agent,spawn_subagent(task) 给一个新的 messages[] 让子Agent独立工作,只把结果带回来。
s08 加四层压缩,在 LLM 调用前插入整个压缩管道。
s01-s19 是这个教程的目录。
以前在做项目时,最头疼的就是上下文的问题,直接把多轮对话直接拼接起来都给大模型显然不现实。
做个对话DEMO还可以,但到实际用的时候,还是得设计解决方案:把符合窗口大小要求的内容提交给大模型,最开始就是简单粗暴的给最后的聊天历史。
Claude Code 用四层压缩管道,核心原则是便宜的先跑,贵的后跑:
messages[]
↓
L3 tool_result_budget (大结果写磁盘,0次API调用)
↓
L1 snip_compact (消息数>50时截断中间,0次API调用)
↓
L2 micro_compact (旧工具结果替换为占位符,0次API调用)
↓
[token > 50000 阈值?]
├─ No → 直接调LLM
└─ Yes → L4 auto compact(LLM摘要,1次API调用)
↓
[API 返回 prompt_too_long?]
└─ Yes → reactive_compact(应急,1次API调用)前三层零 API 调用,只有第四层才消耗一次 LLM 请求。
消息超过 50 条时,保留头部 3 条和尾部 47 条,中间插入占位符。
def snip_compact(messages, max_messages=50):
if len(messages) <= max_messages:
return messages
keep_head, keep_tail = 3, max_messages - 3
snipped = len(messages) - keep_head - keep_tail
return (
messages[:keep_head] +
[{"role": "user", "content": f"[snipped {snipped} messages]"}] +
messages[-keep_tail:]
)最简单的压缩,聊了太多轮就直接砍中间,保护最近上下文。
遍历所有 tool_result 块,只保留最近 3 个的完整内容,其余替换为占位字符串。
def micro_compact(messages):
tool_results = collect_tool_results(messages)
if len(tool_results) <= KEEP_RECENT:
return messages
for _, _, block in tool_results[:-KEEP_RECENT]:
if len(block.get("content", "")) > 120:
block["content"] = "[Earlier tool result compacted. Re-run if needed.]"
return messages只替换长度超过 120 字符的结果,短结果(比如 "File not found")保留。
如果最新一条消息里的 tool_result 总字节数超过 20 万,按大小降序排序,超过 3 万字节的结果写入 .task_outputs/tool-results/{id}.txt,消息里只留 2000 字符的预览。
def persist_large_output(tool_use_id, output):
if len(output) <= PERSIST_THRESHOLD: # 30000
return output
path = TOOL_RESULTS_DIR / f"{tool_use_id}.txt"
path.write_text(output)
return (
f"<persisted-output>\n"
f"Full output: {path}\n"
f"Preview:\n{output[:2000]}\n"
f"</persisted-output>"
)避免 Agent 丢数据,大输出存盘了,真要读完整内容可以用 read_file 工具重新载入。
前三层跑完后如果还是超阈值,才调用 LLM 做完整摘要。
摘要前先把完整 transcript 存为 JSONL 文件,然后让 LLM 提取五个关键信息:当前目标、关键发现/决策、读取/修改的文件、剩余工作、用户约束。
def compact_history(messages):
transcript_path = write_transcript(messages)
summary = summarize_history(messages)
return [{"role": "user", "content": f"[Compacted]\n\n{summary}"}]返回的结果只有一条 user 消息,只保留摘要,旧消息全部丢弃。
如果前面四层都跑完了,API 还是返回 prompt_too_long,触发应急压缩:立即写 transcript、调 LLM 摘要、追加最近 5 条原始消息。
def reactive_compact(messages):
transcript = write_transcript(messages)
summary = summarize_history(messages)
return [
{"role": "user", "content": f"[Reactive compact]\n\n{summary}"},
*messages[-5:],
]应急压缩 + 自动压缩都由一个 compact 工具触发,Agent 自己可以在对话中主动调用。
Hook 设计是我最感兴趣的环节。
之前有篇文章讲wow-harness:万字深研 |Harness 工程实践:指令遵从率 20%,Hook 执行率 100%,就是依靠这个 Hook 机制。
课程告诉我不要想成:“往主循环里继续塞 if/else”,也不要把主循环、tool handler、hook side effect 混成一层。
我最开始确实这么以为。
它是事件驱动的回调注册:在工具执行前后挂扩展逻辑。
它让系统可扩展,但不要求主循环理解每个扩展需求。
HOOKS = {
"UserPromptSubmit": [], # 用户输入前触发
"PreToolUse": [], # 工具执行前触发
"PostToolUse": [], # 工具执行后触发
"Stop": [], # Agent 停止时触发
}
def register_hook(event: str, callback):
HOOKS[event].append(callback)
def trigger_hooks(event: str, *args):
for callback in HOOKS[event]:
result = callback(*args)
if result is not None: # 非None = 阻断
return result
return None四个事件,注册回调,触发执行。
trigger_hooks 有一个关键设计:回调返回非 None 值时立即停止,这个返回值作为阻断消息传给 LLM。
PreToolUse 上挂了两个回调:
permission_hook:s03 的权限检查逻辑挪到这里,检查危险命令、工作目录外的文件写入。
def permission_hook(block):
if block.name == "bash":
for pattern in DENY_LIST:
if pattern in block.input.get("command", ""):
return "Permission denied by deny list"
for kw in DESTRUCTIVE:
if kw in block.input.get("command", ""):
choice = input("Allow? [y/N] ")
if choice not in ("y", "yes"):
return "Permission denied by user"log_hook:记录每次工具调用。
PostToolUse 上挂了 large_output_hook,检测超大输出并警告。
UserPromptSubmit 上挂了 context_inject_hook,在用户输入进入 LLM 之前打印当前工作目录。
Stop 上挂了 summary_hook,统计本轮用了多少次工具调用。
主循环里的变化只有一行:if not check_permission(block) 变成 if trigger_hooks("PreToolUse", block)。
# s03: 硬编码
if not check_permission(block):
results.append({"error": "blocked"})
continue
# s04: Hook
blocked = trigger_hooks("PreToolUse", block)
if blocked:
results.append({"type": "tool_result", "content": str(blocked)})
continue这种设计使得 Hook 可组合:想加一个新行为?注册一个新 Hook,不用改主循环。
想在生产环境去掉日志?注释一行 register_hook,不用动循环体。
learn-claude-code 共 20 章,分六个阶段。
还有多 Agent 平台等等更多现代Agent功能的讲解,感兴趣的朋友可以去官网阅读。https://learn.shareai.run/
s01 Agent Loop:理解 while True + stop_reason 的本质。
s04 Hooks:理解怎么用 PreToolUse/PostToolUse 解耦扩展逻辑。
s08 Context Compact:理解四层压缩管道的设计,前三层零 API 调用的策略值得学。
s06 Subagent:理解怎么给子Agent一个干净的上下文好独立工作。
s05 TodoWrite:先计划后执行,和 s12 Task System:任务持久化+依赖图。
s15-s18 :团队协作。
项目地址:http://github.com/shareAI-lab/learn-claude-code
推荐阅读:
Hermes Agent 桌面端:工作台 + Windows/Mac 双端 + 多智能体协作
MemPrivacy:面向端云智能体的隐私保护个性化记忆管理框架
给 AI 装上真实浏览器:camofox-browser 实战
不用一个违禁词 让 Claude 说出炸药配方|红队攻击实录
大模型黑箱揭秘:GPT、Claude、Gemini、Grok、Hermes 系统提示词全公开
jcode 深度解析:纯 Rust 打造,它凭什么号称「最强 Coding Agent」?
Claude Code 写攻击脚本 OpenClaw 自动指挥|900家公司3万密钥外泄