首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从零开发AI编程智能体:主循环、上下文压缩与Hook设计

从零开发AI编程智能体:主循环、上下文压缩与Hook设计

作者头像
勇哥AI笔记
发布2026-05-26 14:58:00
发布2026-05-26 14:58:00
800
举报
文章被收录于专栏:技术人生黄勇技术人生黄勇

最近主力用 Codex 和 WorkBuddy 干活时间长了,感觉到用得越多,项目持续时间越长,就暴露出一些以前用AI编程智能体没有遇到过的问题了。

例如在这篇文章不会发生人工智能导致的就业危机提到:“因为前面塞入了必要的项目约束,上下文比较长,会导致在项目后期执行时,降智的感觉。”

正好看到有个讲解怎么从零开始开发AI编程智能体的项目,想着了解了解其中的原理。

一是后续是不是自己能写一个;

二是即使不写,了解原理,能更好的使用,也许能避免或者解决些日常遇到的问题。

这个就是 shareAI-lab 最近开源的 learn-claude-code 。

Model + Harness = Agent

早期我记得刚接触 Langchain 这类 LLM 开发应用框架时,主要思考逻辑还是怎么用 if-else 把几次 API 调用串起来。

从产品的变迁来看:大模型刚出来时,都在研究权重、微调和 RLHF;

随后开始关注提示词、检索增强生成(RAG) 和长上下文;

再接下来工具调用、MCP 成了关键词;

到了 2026 年,技能Skill 实现了能力的扩展之后,真正让大模型变得能执行任务,是 Harness。

除模型本身以外的所有工作,都属于 Harness 的范畴。

Harness 负责约定项目规则、搜索代码库、管理上下文;控制开发任务和产品定义,约定边界;

把模型的决策转成 shell 命令、文件编辑和测试执行,再把测试结果、日志输出、浏览器内用户执行放入上下文。

AI Code Agent 是一个“思考—行动—反馈—修正”的长循环。

循环在实际工作场景是否能跑通,靠的就是 Harness。

Claude Code 的核心并不神秘,本质上就是一个 Loop:

调用模型,提供上下文管理,运行工具,拿到反馈,再继续调用模型。

代码语言:javascript
复制
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"

代码语言:javascript
复制
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 用四层压缩管道,核心原则是便宜的先跑,贵的后跑

代码语言:javascript
复制
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 请求。

L1:snip_compact — 消息数量截断

消息超过 50 条时,保留头部 3 条和尾部 47 条,中间插入占位符。

代码语言:javascript
复制
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:]
    )

最简单的压缩,聊了太多轮就直接砍中间,保护最近上下文。

L2:micro_compact — 旧工具结果占位

遍历所有 tool_result 块,只保留最近 3 个的完整内容,其余替换为占位字符串。

代码语言:javascript
复制
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")保留。

L3:tool_result_budget — 大结果写磁盘

如果最新一条消息里的 tool_result 总字节数超过 20 万,按大小降序排序,超过 3 万字节的结果写入 .task_outputs/tool-results/{id}.txt,消息里只留 2000 字符的预览。

代码语言:javascript
复制
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 工具重新载入。

L4:compact_history — LLM 完整摘要

前三层跑完后如果还是超阈值,才调用 LLM 做完整摘要。

摘要前先把完整 transcript 存为 JSONL 文件,然后让 LLM 提取五个关键信息:当前目标、关键发现/决策、读取/修改的文件、剩余工作、用户约束。

代码语言:javascript
复制
def compact_history(messages):
    transcript_path = write_transcript(messages)
    summary = summarize_history(messages)
    return [{"role": "user", "content": f"[Compacted]\n\n{summary}"}]

返回的结果只有一条 user 消息,只保留摘要,旧消息全部丢弃。

应急压缩:reactive_compact

如果前面四层都跑完了,API 还是返回 prompt_too_long,触发应急压缩:立即写 transcript、调 LLM 摘要、追加最近 5 条原始消息。

代码语言:javascript
复制
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设计:把扩展逻辑从主循环中抽离

Hook 设计是我最感兴趣的环节。

之前有篇文章讲wow-harness:万字深研 |Harness 工程实践:指令遵从率 20%,Hook 执行率 100%,就是依靠这个 Hook 机制。

课程告诉我不要想成:“往主循环里继续塞 if/else”,也不要把主循环、tool handler、hook side effect 混成一层。

我最开始确实这么以为。

它是事件驱动的回调注册:在工具执行前后挂扩展逻辑。

它让系统可扩展,但不要求主循环理解每个扩展需求。

代码语言:javascript
复制
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 的权限检查逻辑挪到这里,检查危险命令、工作目录外的文件写入。

代码语言:javascript
复制
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)

代码语言:javascript
复制
# 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

推荐阅读:

这个开源工具把 token 消耗节省了98%

Hermes Agent 桌面端:工作台 + Windows/Mac 双端 + 多智能体协作

MemPrivacy:面向端云智能体的隐私保护个性化记忆管理框架

Multica:让 AI 智能体变为你的员工

Anthropic 百万行代码库的官方最佳实践

给 AI 装上真实浏览器:camofox-browser 实战

不用一个违禁词 让 Claude 说出炸药配方|红队攻击实录

大模型黑箱揭秘:GPT、Claude、Gemini、Grok、Hermes 系统提示词全公开

jcode 深度解析:纯 Rust 打造,它凭什么号称「最强 Coding Agent」?

Claude Code 写攻击脚本 OpenClaw 自动指挥|900家公司3万密钥外泄

没人整理过的 DeepSeek 进化史:25篇论文里的技术蜕变

免 API Key 使用 Claude Code

AI 让我更累了,这不是错觉

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术人生黄勇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Model + Harness = Agent
  • 主循环不变,变的是循环体外的机制
  • 上下文压缩:四层管道 + 应急重试
    • L1:snip_compact — 消息数量截断
    • L2:micro_compact — 旧工具结果占位
    • L3:tool_result_budget — 大结果写磁盘
    • L4:compact_history — LLM 完整摘要
    • 应急压缩:reactive_compact
  • Hook设计:把扩展逻辑从主循环中抽离
  • 推荐阅读路线
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档