3K 行代码干翻 Claude Code?从 Agent 架构设计者视角深度拆解 GenericAgent 源码

3K 行代码干翻 Claude Code?从 Agent 架构设计者视角深度拆解 GenericAgent 源码

我是 iuyup,一个专注于 agnet 开发的大三学生。最近在 V2EX 看到一篇帖子,有人说高强度使用半年 Claude Code 后卸载了它,转投一个叫 GenericAgent 的项目。帖子 200+ 回复,热度很高。作为一个整天跟 Agent 架构打交道的人,我决定把源码拉下来彻底读一遍,然后亲手跑了一圈。这篇文章是我读完 3K 行核心代码后的技术拆解。

一、先说结论

GenericAgent(以下简称 GA)是复旦团队开源的通用 Agent 框架,GitHub 10K+ stars,有 arXiv 技术报告支撑。它的核心代码只有约 3000 行,却能实现文件操作、浏览器控制、终端执行、手机 ADB 操控等全系统级能力。

读完源码后我最大的感受是:GA 的厉害不在于它做了什么,而在于它没做什么。

没有 LangGraph,没有 DAG,没有 class 继承链,没有向量数据库,没有 embedding。就是一个 while 循环不断调 LLM,靠 prompt engineering 和极简的工具集驱动一切。而它的论文数据显示,这种极简设计在长程任务上能用 1/3 的 token 预算达到同等甚至更好的效果。

下面从架构层面拆解它为什么能做到这一点。

二、代码全景:3K 行里有什么

先看文件分布:

文件 行数 职责
ga.py 585 核心大脑 --- 工具实现 + 记忆管理 + Working Memory
agent_loop.py 125 Agent Loop --- 执行主循环
agentmain.py 270 入口 + 会话管理 + reflect 模式
llmcore.py 1026 LLM API 统一调用层 + 上下文压缩
TMWebDriver.py 283 浏览器 CDP 控制
simphtml.py 873 HTML 解析压缩引擎

真正需要精读的是 ga.py + agent_loop.py,加起来 710 行,这就是整个系统的灵魂。

三、Key Point 1:9 个原子工具,为什么「少」反而更强

GA 的全部工具集:

css 复制代码
code_run              → 执行 Python / Bash
file_read             → 读文件
file_write            → 写文件
file_patch            → 精确替换文件片段
web_scan              → 获取简化 HTML + 标签页列表
web_execute_js        → 注入 JS 控制浏览器
update_working_checkpoint → 更新工作记忆
ask_user              → 中断问用户
start_long_term_update    → 触发长期记忆结算

就这 9 个。没有 web_search------搜索是通过 web_execute_js 在浏览器里操作 Google 完成的。没有 screenshot------截图是通过 code_run 调 Python 脚本做的。没有 send_telegram------发消息是通过 code_run 调 Telegram Bot API 完成的。

这是一个元工具 vs 专用工具的架构选择。Claude Code 给每类操作设计专用工具,GA 只提供几个"万能执行器"。

这样做的好处很直接:

1. Tool schema 占用的 context 大幅减少。 每轮对话都要把工具描述带上,9 个工具的 schema 和 30 个工具的 schema,token 消耗差距巨大。这就是论文里说的「上下文信息密度最大化」在工具层面的体现。

2. LLM 的工具选择决策更简单。 在 9 个工具里选 vs 在 30 个工具里选,决策空间降了一个量级,出错率自然更低。

3. 不存在"没有对应工具所以做不了"的问题。 code_run 理论上能做任何事------HTTP 请求、图像处理、数据分析,只要 Python 能做的它都能做。

当然代价也存在:它把工具选择的复杂度转移到了代码生成的复杂度上。 Claude Code 调 web_search 只需要传一个 query 参数,GA 要让 LLM 生成一段完整的 JS 去操作搜索引擎。这对模型的代码生成能力要求更高,用弱模型时效果会打折扣。

本质上 GA 是在赌:强模型 + 少 token > 弱模型 + 多 token。 在当前 Sonnet/DeepSeek-V3 这个级别的模型能力下,这个赌注是成立的。

四、Key Point 2:四层记忆架构------task-centric 记忆设计

这是我认为 GA 最值得研究的部分。先看架构:

makefile 复制代码
L0: META-SOP(记忆管理规则本身 ------ memory_management_sop.md)
L1: global_mem_insight.txt(≤30 行的极简索引)
L2: global_mem.txt(环境事实库:路径、配置、凭证)
L3: memory/*.md, *.py(任务级 SOP 和工具脚本)
L4: L4_raw_sessions/(历史会话原始记录)

L1 索引层:30 行的全局导航

这是整个记忆系统最精妙的设计。L1 只有 30 行,硬约束,常驻在 system prompt 里。它的内容是这样的:

css 复制代码
L3: memory_cleanup_sop(记忆整理) | skill_search | ui_detect.py | ...
浏览器特殊操作: tmwebdriver_sop(文件上传/图搜/PDF blob/...)
键鼠: ljqCtrl_sop(禁pyautogui/先activate)
[RULES]
1. 搜索先行: 搜文件名严禁不用es, 搜索一定优先使用web工具的google
2. 交叉验证: 禁信摘要, 数值进详情页核实
...

这意味着 Agent 每一轮都能看到自己的全部能力索引,但不会因为记忆太多而把 context 撑爆。需要细节时再 file_read 去拿 L2/L3。

这就是「分层按需加载」------和操作系统的内存分页是同一个思想。

记忆写入的高门槛

GA 的记忆管理有一条最高优先级公理:

No Execution, No Memory.(无行动,不记忆)

只有工具调用成功验证的信息才能写入记忆。猜测、推理、未执行的计划一律禁止。这从源头避免了记忆污染的问题。

对比我自己做的 Agent Memory System,我用的是 Mem0 风格的提取管道------从对话中自动提取信息写入记忆。这种方式容易引入 LLM 的幻觉。GA 的「只记工具验证成功的信息」是更 robust 的策略,虽然记忆覆盖率低一些,但准确率极高。

Task-centric vs User-centric

传统的 Agent 记忆系统(包括我做的那个)是 user-centric 的------记住用户偏好、历史对话、个人信息。GA 的记忆是 task-centric 的------只关心「这个任务怎么做更高效」。

L3 里的 SOP 文件存的都是类似「用这个方法会踩坑,正确做法是 XXX」这种高度提炼的信息,而不是用户画像。这两种方式各有适用场景,但对于一个「效率工具」定位的 Agent,task-centric 显然是更合理的选择。

五、Key Point 3:Working Memory 注入------长程任务的命脉

这是 Agent Loop 层面最核心的机制。看 _get_anchor_prompt() 的实现:

python 复制代码
def _get_anchor_prompt(self, skip=False):
    h = self.history_info; W = 30
    # 早期历史压缩成一行摘要
    earlier = self._fold_earlier(h[:-W])
    # 最近 30 条完整保留
    h_str = "\n".join(h[-W:])
    prompt = f"[WORKING MEMORY]\n{earlier}\n{h_str}"
    # Agent 自己设置的关键信息
    if self.working.get('key_info'):
        prompt += f"\n<key_info>{self.working.get('key_info')}</key_info>"
    return prompt

每一轮工具调用结束后,都会把这段 Working Memory 注入到下一轮的 user message 中。 它包含压缩过的早期历史、最近 30 条完整记录、以及 Agent 通过 update_working_checkpoint 主动设置的关键信息。

这就是为什么 GA 能在长程任务中保持连贯------它不是靠 LLM 自己记住上下文,而是每轮强制注入一个结构化的「当前状态摘要」。

配合 turn_end_callback 里的多重防护机制:

python 复制代码
if turn % 7 == 0:
    next_prompt += "[DANGER] 禁止无效重试。若无有效进展,必须切换策略。"
if turn % 10 == 0:
    next_prompt += get_global_memory()  # 每 10 轮重新注入全局记忆

每 7 轮强制提醒切换策略、每 10 轮重新注入全局记忆、每 10 轮重置工具描述防止 context 膨胀。这些都是工程层面的细节,但对长程任务的稳定性至关重要。

六、Key Point 4:上下文压缩------两层裁剪

LLM 历史压缩

compress_history_tags 每 5 轮触发一次,把早期消息中的 <thinking><tool_use><tool_result> 标签内容截断到 800 字符:

python 复制代码
def compress_history_tags(messages, keep_recent=10, max_len=800):
    # 保留最近 10 条不压缩
    for i, msg in enumerate(messages):
        if i >= len(messages) - keep_recent: break
        # 截断早期消息中的 thinking/tool_result
        msg['content'] = _trunc(msg['content'])

简单粗暴但逻辑成立------早期的 thinking 过程对当前决策几乎没有价值,但如果不压缩会持续消耗 token。

HTML 压缩

simphtml.py 是 873 行的 HTML 简化引擎。先在浏览器端用 JS 做 DOM 裁剪(移除隐藏元素、浮动元素、广告栏、script/style 标签),然后 Python 端再做 token 级截断。最终送给 LLM 的是高度精简的页面主体内容。

这就是为什么 GA 浏览器操作只用 1/5 预算的核心原因------其他 Agent 把整个 HTML 塞给 LLM,GA 只给简化后的关键内容。

七、Key Point 5:Skill Tree 自进化

GA 的「Skill」本质就是 L3 层的 SOP 文件和 Python 脚本。当 Agent 完成一个复杂任务后,通过 start_long_term_update 触发记忆结算,由 LLM 自己决定是否要把经验写成 SOP 或工具脚本。

没有向量数据库,没有 embedding,就是文件系统 + LLM 自主读写。用几周后,你的 memory/ 目录会积累起一棵独一无二的技能树。

skill_search 模块还支持连接复旦的 API 服务搜索社区共享的 Skill,但核心的个人 Skill Tree 就是本地文件积累。

八、实测体验:3 个任务看 GA 的决策链路

任务 1:创建斐波那契脚本(5 Turn)

创建 hello.py → 运行验证 → 发现执行失败 → 改用 PowerShell → 验证成功

干净利落,展示了基本的工具调用 + 失败升级。

任务 2:查 GitHub Star 数(8 Turn)

这个更有意思:

复制代码
web_scan(尝试浏览器)→ 失败
→ 改用 Google 搜索 → 浏览器还是不行
→ 读 tmwebdriver_sop(查 L3 记忆找方案)→ SOP 也解决不了
→ 最终 fallback 到 code_run 用 PowerShell 调 GitHub API → 成功

8 个 turn 里完整展示了失败升级策略。而且它最终选了 code_run 调 API 而不是继续死磕浏览器------同一个"元工具"既能写文件也能当 HTTP 客户端。

任务 3:发 Telegram 消息(7 Turn)

给了它一句「帮我发一条消息到 Telegram」,它:

  1. 立刻 ask_user 问我要 Bot Token
  2. 我只给了 Token,没给 Chat ID
  3. 它自己用 code_run 调 Telegram Bot API 的 getUpdates 获取到了 Chat ID
  4. 然后 sendMessage 发出去

成功了。整个「Telegram 集成」不需要预置------它用 9 个原子工具现场组合出来的。Claude Code 要做同样的事需要装 MCP Server 或者手动写脚本。

九、GA 的局限性

公平起见,也说说不足:

  1. 前端极其简陋。 开发者自己说了,毛坯房风格,不改。当然我们可以根据自己的需求自己写一个前端。
  2. 安全性粗放。 给 Agent 系统级控制权,一旦 LLM 幻觉,后果不只是代码写错------可能是文件删除或系统误操作。Claude Code 至少有沙箱和权限控制的概念。
  3. 依赖强模型。 元工具设计把工具选择的复杂度转移到了代码生成上,弱模型用 GA 效果会大打折扣。
  4. 生态成熟度不及 CC。 学术团队项目 vs Anthropic 商业产品,长期维护的确定性不同。

十、对 Agent 开发者的启示

读完 GA 源码后,有几个认知升级:

1. 工具数量不是越多越好。 每多一个工具就多占 context、多一层决策复杂度。9 个原子工具覆盖全系统操作,这个设计让我反思自己项目里的工具集是否过度膨胀。

2. 记忆系统需要一个常驻的极简索引层。 GA 的 L1 只有 30 行,但让 Agent 每轮都知道「我有哪些能力」。这比把所有记忆塞进 system prompt 或者依赖检索召回都更高效。

3. 「No Execution, No Memory」是比 Mem0 更 robust 的策略。 从对话中自动提取信息容易引入幻觉,只记工具验证成功的信息更安全。

4. Working Memory 注入是长程任务连贯性的关键。 不能指望 LLM 自己记住 50 轮前的上下文,需要每轮强制注入结构化的状态摘要。

5. 极简不是偷懒,是设计选择。 3K 行代码,没有框架依赖,任何人都能读完。这在 Agent 框架普遍臃肿的现状下是巨大的差异化------也是它能拿到 10K stars 的重要原因。


项目地址: github.com/lsdefine/Ge...

技术报告: arxiv.org/abs/2604.17...

如果你也在做 Agent 相关的开发,推荐花两个小时把 ga.pyagent_loop.py 读一遍。710 行代码,收获会比读很多论文都大。

相关推荐
冬奇Lab3 小时前
一天一个开源项目(97):Hello-Agents——从零构建 AI Native 智能体的实战指南
人工智能·开源·agent
Aloudata4 小时前
构建全场景指标服务:基于 NoETL 语义编织与开放 API/JDBC 生态的实践
大数据·数据分析·agent·指标平台
im_AMBER4 小时前
Browser Agent 开发:从浏览器插件到Electron CDP
前端·javascript·架构·electron·agent
维元码簿4 小时前
Claude Code 深度拆解:远程模式 2 — 环境注册与轮询架构
ai·agent·claude code·ai coding
HIT_Weston5 小时前
76、【Agent】【OpenCode】用户对话提示词(addtionalProperties 属性)
人工智能·agent·opencode
.-Smile-.5 小时前
【开源】Yszen AI:一个开箱即用的 Harness 架构 Agent 脚手架(FastAPI + LangGraph + React)
aigc·agent·harness
阿里-于怀5 小时前
Nacos Skill Registry: 面向个人场景的Skill中心实践
阿里云·云原生·nacos·agent·skills
维元码簿5 小时前
Claude Code 深度拆解:远程模式 1 — 鉴权链与会话生命周期
ai·agent·claude code·ai coding