Hotdry.
ai-systems

从零构建 Nano 级 Claude Code Agent Harness:基于 Bash 的轻量级实现

以约 1000 行 Bash 代码实现类 Claude Code 的 Agent 框架,掌握工具调用、持久会话与任务编排的核心工程参数。

当我们讨论 AI Agent 框架时,往往会想到 LangChain、AutoGen 这些重量级选手。它们功能完备,但学习曲线陡峭,调试困难,对于只是想理解 Agent 核心机制的学习者或需要轻量级集成的开发者而言,性价比并不高。Learn Claude Code 项目提供了一个极简 alternatives:仅用约 1000 行代码,基于 Bash 构建了一个完整的类 Claude Code Agent Harness。这个实现剥离了所有干扰项,直指 Agent 的本质 —— 工具调用与任务编排。

核心设计:三足鼎立的极简架构

整个框架由三个核心组件构成,每个组件的职责边界非常清晰。第一部分是工具定义,通过声明式 schema 告知大语言模型哪些能力可供调用;第二部分是持久会话管理器,负责维持一个长期运行的 Bash 进程,使多次调用之间共享工作目录、环境变量和文件状态;第三部分是最关键的主循环,负责将用户输入发送给模型、解析工具调用、执行工具、并将结果反馈给模型进行下一轮推理。这三者加在一起,就是一个最小可行的 Agent。

理解这个架构的关键在于认识到 Agent 并不是什么神秘的东西,它本质上是一个受控的推理 - 执行循环。大语言模型在这个循环中扮演决策者的角色,它决定何时调用工具、传入什么参数;而框架扮演执行者的角色,它负责安全地运行工具并把结果如实返回。这种设计模式被 Anthropic 官方称为 Tool Use 范式,也是 Claude Code 能够执行复杂多步骤任务的技术基础。

工具定义:告诉模型你能做什么

在 Claude Code 的设计哲学中,工具的数量应该被严格控制,每个工具都应该是功能完备且正交的。对于这个轻量级实现,我们只需要暴露一个核心工具:bash。这个工具的本质是一个包装了持久 Bash 会话的执行器,模型可以通过它调用任意命令行工具来完成文件操作、代码执行 Git 操作等任务。

工具定义的代码非常简洁,使用 Claude API 原生的 bash_20250124 类型即可。值得注意的参数是 description 字段,这个字段的写作质量直接影响模型是否能够正确理解工具的用途并生成合适的调用参数。一个好的 description 应该明确说明工具的功能、输入格式以及典型的使用场景。例如,可以描述为 “在持久的 Shell 会话中执行命令,会话会保持当前工作目录和环境变量,适合需要多步骤操作的复杂任务”。这种描述方式帮助模型理解会话的持久性特性,从而更有效地规划跨步骤的任务。

持久会话:Agent 记忆的关键实现

如果每次执行命令都启动一个新的 Bash 进程,Agent 就无法记住之前的工作状态,比如切换到的目录、安装的依赖或者修改的文件。持久会话机制解决了这个问题,它通过 subprocess 模块维持一个长期运行的 /bin/bash 进程,所有命令都通过标准输入输出与这个进程交互。

实现持久会话时有一个关键的技术细节:输出读取必须是非阻塞的。因为命令的执行时间不可预测,如果使用阻塞式读取,框架可能会在等待长耗时命令时卡死。常见的做法是使用独立线程持续读取 stdout 和 stderr,将输出放入队列,主线程则通过带超时的队列获取方式来模拟非阻塞读取。具体的工程参数建议如下:输出读取超时设置为 10 秒,队列检查间隔为 50 毫秒,这两个参数在大多数场景下能够平衡响应性与资源消耗。如果需要处理更长的命令,可以将超时参数暴露给用户或根据上下文动态调整。

会话重启功能也是必需的。当模型检测到环境被破坏(比如误删了关键文件或安装了冲突的依赖),它可以请求重启 Bash 会话来获得一个干净的环境。这个功能通过终止现有进程并重新创建 subprocess 来实现,重启后所有状态会被清空。

Agent 循环:推理与执行的螺旋上升

主循环是整个框架的灵魂,它实现了 Tool Use 的核心逻辑。循环的每一次迭代都遵循相同的模式:先发送包含历史消息的请求给大语言模型,然后检查返回内容中是否包含工具调用。如果有工具调用,就解析命令参数、执行工具、并将结果作为新的用户消息追加到历史记录中,然后继续下一轮循环;如果没有工具调用,说明模型已经完成了任务,直接输出最终回复并退出循环。

这个循环中有一个容易被忽视的工程细节:消息历史的管理。随着对话的进行,消息列表会不断增长,当达到模型的上下文窗口限制时,需要进行适当的截断。一种常见的策略是保留系统提示和最近的几轮对话,删除中间部分的工具调用结果。另外,温度参数(temperature)和最大令牌数(max_tokens)也需要根据具体场景调整。对于需要精确执行的代码生成任务,建议将温度设为 0 或很低的值;对于需要创意的问题求解,可以适当提高。

生产级参数:让轻量框架也能跑在线上

虽然这是一个教学级的实现,但它采用的设计模式与生产环境中的 Agent 系统完全一致。如果要将它部署到生产环境,以下几个工程参数值得关注。

隔离与安全是首要考量。Bash 工具拥有完整的系统权限,绝不能直接暴露给不可信的输入。推荐的做法是在 Docker 容器或虚拟机中运行 Agent,为其分配有限的资源配额(CPU、内存、存储),并通过 ulimit 或 cgroups 限制危险操作。对于高敏感场景,可以在工具执行前增加人工确认环节,由用户决定是否允许执行特定命令。

超时与重试机制决定了框架的鲁棒性。每个工具调用都应该设置最大执行时间,防止命令无限挂起。Learn Claude Code 中使用的 10 秒超时是一个不错的起点,但对于编译大型项目或运行完整测试套件等任务,需要相应延长。重试策略方面,建议对非确定性错误(如网络超时、临时文件缺失)设置最多 3 次重试,对确定性错误(如语法错误、权限不足)则直接返回失败。

日志与审计是生产环境的必备能力。所有执行的命令、返回的结果、执行时间都应该被完整记录,以便事后分析和问题排查。如果 Agent 处理的是敏感操作,日志中可能需要脱敏处理,去除密码、密钥等敏感信息。

写在最后

Learn Claude Code 项目的价值不在于代码量的大小,而在于它揭示了 Agent 系统的本质。一个有效的 Agent 并不依赖于复杂的框架或庞大的生态,它只需要三个东西:一个清晰的工具定义告诉模型能做什么,一个可靠的执行器来运行工具,以及一个循环机制来连接推理与行动。这个 1000 行的实现证明了这一点,也为后续的定制和扩展提供了坚实的起点。当你理解了这些核心概念之后,无论是接入更多的工具、添加多 Agent 协作、还是对接到更复杂的任务规划系统,都会变得水到渠成。

资料来源:GitHub - shareAI-lab/learn-claude-code: Bash is all you need - A nano claude code–like 「agent harness」, built from 0 to 1

查看归档