@hwchase17: "用 Deep Agents 构建你自己的 Claude Code" 社区的一篇好文章,展示了如何构建一个类似 Claude Code 的代理……

X AI KOLs Timeline 工具

摘要

一篇解释如何使用 LangChain 的 Deep Agents 库构建类似 Claude Code 的编码代理的文章,涵盖了架构和实现。

"用 Deep Agents 构建你自己的 Claude Code" 社区的一篇好文章,展示了如何使用 Deep Agents 构建类似 Claude Code 的代理。鉴于 GLM-5.2 看起来如此强大,这一点尤其相关!https://pub.towardsai.net/build-your-own-claude-code-using-langchin-a-deepdive-into-langchains-deep-agents-9ef98d98a69a…
查看原文
查看缓存全文

缓存时间: 2026/06/22 03:35

“用 Deep Agents 构建你自己的 Claude Code” 社区的一篇好文章,展示了如何使用 Deep Agents 构建一个类似 Claude Code 的代理。尤其考虑到 GLM-5.2 看起来非常强大,这篇文章更显相关!https://pub.towardsai.net/build-your-own-claude-code-using-langchin-a-deepdive-into-langchains-deep-agents-9ef98d98a69a…


使用 Langchin 构建你自己的 Claude Code:深入理解 LangChain 的 Deep Agents

来源:https://pub.towardsai.net/build-your-own-claude-code-using-langchin-a-deepdive-into-langchains-deep-agents-9ef98d98a69a?gi=af3339d982f6

如果你使用过 Claude Code,你可能会想,“哇,这个模型在编码方面真是太聪明了。”

Sreejith Sreejayan (https://medium.com/@the-sreejith?source=post_page—byline–9ef98d98a69a—————————————)

但这其实是一种错误的思维模式。一个编码代理不仅仅是一个更智能的聊天机器人。Claude Code 的神奇之处不仅仅在于模型本身,更在于包裹在它周围的代理框架(agentic harness)。

这个框架就是控制平面。它是一个隐形的系统,赋予模型读取文件的工具、运行代码的环境、记住所做事情的记忆,以及保持任务进度的检查清单。没有这个框架,语言模型只是一个文本生成器。有了它,模型就变成了一个能干、自主的软件工程师。

在这篇文章中,我们将打开这个黑盒子。我们将精确地分析 Claude Code 在幕后是如何工作的。然后,对于发现的每一个部分,我们将使用 LangChain 的 deepagents 库来重建它。到最后,你将理解编码代理是如何工作的,因为你将知道如何自己构建一个。

编码代理的架构

在我们深入细节之前,先看一下我们正在探索的系统的整体架构图:

整个引擎就是这个循环,并且它从你开始。一切都始于用户的问题或请求——从快速的“这个文件夹里有什么文件?”到大型的“重构登录系统并更新测试”——模型首先读取这条消息,然后决定下一步做什么。然后,会发生以下两种情况之一。如果模型需要行动,它会调用一个工具,结果被反馈回来,然后循环继续——无论任务需要一步还是五十步,都是同一个循环。当模型回复纯文本而不是工具调用时,循环退出,你得到答案。这个退出条件(“没有工具调用”)字面上就是代理知道任务完成的方式。

按回车或点击查看全尺寸图片

图中的“决定下一步做什么”这个盒子实际上融合了研究中的三个阶段:模型不断在收集上下文(读取文件)、采取行动(编辑、运行命令)和验证结果(运行测试),所有这些都通过同一个循环进行。这些阶段并没有独立的“模式”——它们只是不同的工具调用。

然而,有一个值得注意的刻意切换:计划模式(plan mode)。通常,代理在计划和行动是同时进行的。计划模式会在循环前设置一个门控——你要求代理在不改变任何内容的情况下进行调查并提出计划,所以它会读取文件并思考,但在你批准之前不会进行编辑和命令操作。然后正常的循环接管并执行。对于大型或高风险任务来说,这是一个安全阀。这与自动化的待办事项列表(代理在每项任务中为自己编写的)不同;计划模式是一个用户触发的暂停,需要你明确批准。

图中仍然遗漏的是围绕循环的其余机制——当内存溢出时的上下文压缩、运行自己私有循环的子代理,以及“运行工具”与实际系统之间的权限/沙箱层。这些不会改变循环本身;它们只是包裹着循环。

按回车或点击查看全尺寸图片

框架内部的四个部分构成了使循环可靠而非不稳定的能力。规划让代理在行动前思考。工具赋予它双手。上下文管理防止它在长时间的任务中被自己的记忆淹没。子代理允许它在自己的私有循环中处理支线任务,从而保持主对话的整洁。这些都不会改变循环——它们只是为循环提供支持。

现在是最重要的部分:底层。当代理决定在现实世界中实际执行某些操作时——编辑文件、运行 shell 命令、访问网络——该操作不会直接发送到你的机器。它必须首先通过权限和沙箱层。这是整个系统中最重要的安全理念。

一个常见的陷阱是,你认为可以通过在指令中写上“请不要删除任何重要内容”来保证代理的安全。那不是一堵墙——它只是一张便利贴,模型可以忽略它、误读它,或者被说服绕开它。真正的安全性存在于这一层,在模型之外,在这里,一个权限规则可以直接阻止一个工具调用,而一个沙箱可以在操作系统层面阻止任何危险命令,无论模型想要什么。

理论已经足够。让我们来构建它。

第 0 部分:从零开始的循环——没有框架,没有魔法

在接触任何库之前,我们先看看这个引擎的裸核。这是一个完整的、可工作的代理循环:

def run_agent_loop(client, user_message, tools, tool_functions, max_turns=20): messages = [{"role": "user", "content": user_message}] for _ in range(max_turns): # 1. 询问模型下一步做什么。 response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, tools=tools, messages=messages ) messages = [*messages, {"role": "assistant", "content": response.content}] # 2. 如果是纯文本且没有工具请求?任务完成。 tool_uses = [b for b in response.content if b.type == "tool_use"] if not tool_uses: return "".join(b.text for b in response.content if b.type == "text") # 3. 运行每个请求的工具并将结果返回。 4. 重复。 results = [ {"type": "tool_result", "tool_use_id": call.id, "content": tool_functions[call.name](**call.input)} for call in tool_uses ] messages = [*messages, {"role": "user", "content": results}] raise RuntimeError(f"agent loop did not finish within {max_turns} turns")

就是这样。大约三十行代码,本文其余部分的所有概念都是这个循环的增强版:更好的工具插入到 tool_functions 中,一个规划器在 messages 中为自己写下笔记,一个压缩器在 messages 膨胀时缩小它,子代理只是用新的 messages 列表递归调用同一个函数,以及在模型请求工具和调用工具的那行代码之间插入的权限检查。max_turns 这个后盾是每个真实框架都不会省略的偏执一环——一个无限循环的模型会无限地烧钱。

第 1 部分:循环——驱动一切的引擎

每个编码代理都有一个跳动的心脏,称为代理循环。它是将“说话”转化为“行动”的循环。它也非常简单得令人尴尬:

  1. 询问模型下一步做什么。
  2. 模型要么回复普通文本,要么要求使用一个工具。
  3. 如果它要求使用工具,系统运行该工具并将结果返回给模型。
  4. 从第 1 步重复。
  5. 当模型回复纯文本且没有工具请求时,任务完成。停止并向用户显示答案。

这就是整个引擎。读取文件、运行命令、编辑代码——每一个操作都通过这个完全相同的循环进行。

把它想象成一个承包商: 你交给他一份工作和一个检查清单。他看看下一步是什么,执行它,检查结果,然后决定下一步做什么。只有当清单上没有剩余事项时,他才会回来和你沟通。代理循环就是这个承包商的头脑。

有一个值得欣赏的优雅细节:这个循环会自然地根据任务大小伸缩。一个快速问题(“这个文件夹里有什么文件?”)可能只需要一轮。一个大规模请求(“重构登录系统”)可能会在多轮中串联数十个工具调用。没有人需要硬编码任务需要多少步。

使用 Deep Agents 构建

好消息是:你不需要自己编写这个 while 循环。当你创建一个 Deep Agent 时,你会免费得到一个完整的工作循环。

首先,安装库和一个模型提供者:

pip install deepagents langchain-anthropic

然后,创建一个最简单的代理:

`` from deepagents import create_deep_agent

def get_weather(city: str) -> str: “”“Get the weather for a given city.”“” return f“It’s always sunny in {city}!“

agent = create_deep_agent( model=“anthropic:claude-sonnet-4-6”, tools=[get_weather], system_prompt=“You are a helpful assistant.”, )

result = agent.invoke( {“messages”: [{“role”: “user”, “content”: “What’s the weather in San Francisco?”}]} ) ``

这个 create_deep_agent 调用返回一个准备好运行的代理,并且循环已经连接好。当你调用 .invoke() 时,它就会运行我们刚才描述的精确循环。这个框架不在乎你接入哪个模型——OpenAI、Google 还是 Anthropic——循环都是一样的。

第 2 部分:工具——给代理双手

如果说循环是引擎,那么工具就是双手。一个没有工具的模型只能说话。一个有好工具的模型可以读取你的代码库、修改它并检查自己的工作。真正的编码工具可以分为四大类:

读取工具——在不改变任何东西的情况下进行查看:

  • read_file 用于打开文件。
  • glob 用于按名称模式查找文件(例如,所有以 .py 结尾的文件)。
  • grep 用于在文件内部搜索特定文本。
  • (一个常见的初学者混淆点:glob 按名称查找文件;grep 按内容查找文件。)

编辑工具——安全地修改内容:write_file 用于新文件,edit_file 用于修改现有文件的部分内容。

一个执行工具——运行 shell 命令,和你在终端里输入的一样。

一个委托工具——task,用于将子任务交给一个辅助代理。

为什么不让模型直接运行任何命令?

难道代理不能直接用 cat 来读取,用 sed 来编辑吗?它可以,但专用工具有两大优势:

  • Token 预算控制: 一个专门构建的读取工具可以在将文件内容倾入内存之前测量其大小,并在必要时进行截断。而原始的 cat 会一股脑地倾入所有内容,可能撑爆上下文窗口。
  • 更清晰的权限管理: 当代理使用已知的 edit_file 工具时,框架清楚地知道正在发生什么,并可以应用安全规则。而一个自由格式的 shell 命令是一个危险的黑盒子。

这里有一个有趣的实际现象:模型是从公共互联网上学习的,互联网上充满了使用 cat 和 sed 的 Stack Overflow 答案。因此,即使是最先进的模型也会习惯性地使用原始 shell 命令。你的系统提示必须坚定地提醒它使用真正的工具,而不是 shell 快捷方式。

使用 Deep Agents 构建

Deep Agents 内置了整个工具套件——包括规划、文件系统工具、执行和委托。你可以通过一个装饰函数在其基础上添加自定义工具:

`` import subprocess from langchain_core.tools import tool

MAX_OUTPUT_CHARS = 20_000 # 大约 5k tokens

@tool def run_tests(path: str = “.”) -> str: “”“运行项目的 pytest 套件并返回其输出。 输出会被截断到最后 20k 个字符(失败信息通常出现在末尾)。 运行会在 5 分钟后被终止。 “”“ try: result = subprocess.run([“pytest”, path], capture_output=True, text=True, check=False, timeout=300) except subprocess.TimeoutExpired: return “pytest timed out after 300s” output = result.stdout + result.stderr if len(output) > MAX_OUTPUT_CHARS: return (“[… output truncated to the last 20,000 characters …]\n” + output[-MAX_OUTPUT_CHARS:]) return output

agent = create_deep_agent( model=“anthropic:claude-sonnet-4-6”, tools=[run_tests], # 与内置工具合并 system_prompt=“You are a coding assistant. Always run tests after editing.”, ) ``

@tool 装饰器将一个普通函数转变为模型可以调用的东西。这个文档字符串至关重要——模型将其视为说明书,以了解何时以及如何使用该工具。

第 3 部分:规划——先思考再行动

将一个复杂的请求直接丢给一个裸模型,它往往会手忙脚乱。它可能会先调用一个工具,再调用另一个,缺乏整体规划,有时甚至会原地打转。一个好的编码代理通过先规划来避免这种情况。

在接触任何代码之前,代理会编写一个结构化的待办事项列表。它将任务分解成清晰的步骤,然后逐步执行这个列表,并在执行过程中将项目标记为“进行中”和“已完成”。

把它想象成一个厨师: 一个好厨师在打开炉子之前会阅读整个食谱。他们不会在第三步正在烧焦的时候才去琢磨第四步该怎么做。

在您的收件箱中获取 Sreejith Sreejayan 的故事

免费加入 Medium,以获取这位作者的最新动态。

记住我以便更快地登录

这背后隐藏着一个巧妙的工程技巧。在长时间会话中,模型会忘记其最初的目标,因为它们的指令被埋没在数页的工具输出之下。为了解决这个问题,框架在工具调用之后悄悄地将当前的待办事项列表重新注入到对话中。这就像一位同事轻轻地把检查清单滑回你面前,这样你就不会忘记重点。

使用 Deep Agents 构建

这个特性被称为 write_todos 工具,并且在 Deep Agents 中它是内置的。你不需要配置任何东西——默认的系统提示会自动教会代理在执行前进行规划,并在整个循环中保持待办事项列表的更新。

第 4 部分:上下文管理——突破记忆极限

这里是最艰难的工程所在。每个模型都有一个上下文窗口——对其短期记忆的硬性限制。读取几个大文件,运行一些命令,你很快就会把它填满。当它溢出时,代理就会忘记事情,包括你最初的指令。

编码代理通过一个两部分的策略来解决这个问题:

  1. 文件作为外部记忆: 框架不会将巨大的搜索结果塞进对话中,而是将其保存到一个文件中,并只记住文件名。如果以后需要详细信息,它会读取该文件。
  2. 压缩: 当对话内容接近窗口上限的危险边缘时,框架会自动暂停循环。它会总结对话中较早的部分,将这些重要事实存入长期存储,并清理膨胀的短期记忆。

把它想象成研究一份庞大的报告: 你不会试图把每一本书都记在脑子里。你会做笔记,把书归档,并在桌子上保留一页纸的摘要。

使用 Deep Agents 构建

这两个部分都是内置的。Deep Agents 自带了一个虚拟文件系统来卸载大型结果,还内置了自动摘要中间件。你创建代理的那一刻起,就免费获得了这种内存管理功能。

第 5 部分:子代理——分而治之

有些任务对于一个对话来说太大了。搜索一个庞大的代码库可能涉及读取五十个文件——而你肯定不想让五十个文件堵塞主代理整洁的记忆。

解决方案是子代理。主代理创建一个帮手,交给它一个非常具体的任务(“搜索代码库,告诉我认证逻辑在哪里”),然后帮手在其自己的、独立的、空白的上下文窗口中完成这项工作。完成后,它会返回一个简洁的摘要。

把它想象成一个经理: 经理将一项研究任务委托给初级员工。初级员工阅读一堆文档后,回来提供一段式摘要。经理的桌面保持整洁。

安全护栏: 子代理被严格禁止生成自己的子代理。如果它们可以,一个混乱的代理可能会创建一个无限的嵌套帮手循环,导致一个失控的进程,烧掉你的 API 预算。严格的深度限制可以防止这种情况。

相似文章

自己动手打造一个 Claude Code

Reddit r/AI_Agents

16岁的巴西开发者 Kauan 发布了 Tiny Agents——一个 Python 框架,可以轻松构建 AI 智能体运行框架,支持多供应商模型、上下文窗口管理、异步工作线程、工具执行以及可自定义的终端 UI,仅用 103 行代码就实现了一个类似 Claude Code 的助手。

深入Claude Code:当前与未来AI代理系统的设计空间

Hugging Face Daily Papers

本文分析了Claude Code作为代理编程工具的架构,识别出影响其实现的五种人类价值观和十三项设计原则,包括安全系统、上下文管理和可扩展机制。研究将Claude Code与OpenClaw进行比较,展示了不同的部署环境如何针对常见的AI代理设计挑战产生不同的架构解决方案。