How to turn Claude Code into a domain specific coding agent

如何将 Claude Code 打造成领域特定的编码代理

阅读 10 分钟

作者:Aliyan Ishfaq

编码代理在编写使用 LLM 广泛训练的流行库的代码方面表现出色。但如果指向自定义库、新版本的库、内部 API 或小众框架,它们的表现就不那么好了。这对于使用领域特定库或企业代码的团队来说是个问题。

作为库(LangGraph、LangChain)的开发者,我们非常关注如何让这些编码代理在编写 LangGraph 和 LangChain 代码方面做得更好。我们尝试了许多上下文工程技术。有些有效,有些无效。在这篇博客文章中,我们将分享我们进行的实验和学到的经验。我们最大的收获是:

高质量、精炼的信息结合按需访问更详细信息的工具产生了最佳结果

赋予代理原始文档访问权限并没有像我们期望的那样提高性能。事实上,上下文窗口填满了更快。以 Claude.md 形式提供的简洁、结构化的指南始终优于简单地连接文档工具。最佳结果来自两者的结合,即代理具有一些基础知识(通过 Claude.md),但如果需要更多信息,它也可以访问文档的特定部分。

在这篇文章中,我们将分享

  • 我们测试过的各种 Claude Code 配置
  • 我们用来评估生成代码的框架(一个您可以为自己的库重复使用的模板)
  • 结果和主要收获

Claude Code 设置

我们测试了四种不同的配置,并使用 Claude 4 Sonnet 作为模型以保持一致性

Claude Vanilla:开箱即用的 Claude Code,无需任何修改。

Claude + MCP:Claude Code 连接到我们的 MCPDoc 服务器以访问文档。

Claude + Claude.md:Claude Code 附带了一个详细的 Claude.md 文件,其中包含 LangGraph 特定的指导。

Claude + MCP + Claude.md:Claude 可以访问详细的 Claude.md 和 MCPDoc 服务器。

用于文档的 MCP 工具

我们构建 MCPDoc 服务器是因为我们希望为编码代理提供访问任何库文档的权限。它是一个开源的 MCP 服务器,公开两个工具:list_doc_sourcesfetch_docs。第一个工具共享可用的 llms.txt 文件的 URL,第二个工具读取指定的 llms.txt 文件。在我们的设置中,我们提供了对 LangGraph 和 LangChain Python 及 JavaScript 文档的访问。通过在 MCP 配置中传入您的库的 llms.txt 文件的 URL,您可以轻松地为您的用例进行改编。

Claude.md

对于 Claude.md,我们创建了一个 LangGraph 库指南。它包含了常见的 LangGraph 项目结构要求的详细说明,例如在创建文件之前强制进行代码库搜索、正确的导出模式以及部署最佳实践。它包含了用于构建单代理和多代理系统的原始代码示例,例如 create_react_agent、supervisor 模式和用于动态切换的 swarm 模式。对于 LLM 难以实现的某些实现,例如用户面向代理的流式传输和人工干预,我们也添加了广泛的指导。

我们发现包含常见陷阱和反模式的综合章节特别有价值。这涵盖了常见的错误,例如不正确的 interrupt() 用法、错误的状态更新模式、类型假设错误以及过于复杂的实现。这些是 LLM 经常犯的错误,原因可能是库已弃用或与其他框架的模式混淆。

我们还包括了 LangGraph 特定的编码标准,如结构化输出验证、正确的消息处理以及其他框架集成调试模式。由于 Claude 可以访问 Web 工具,我们在每个部分的末尾添加了特定的文档 URL 以供进一步参考和导航。

此文件与 llms.txt 的不同之处在于,前者是包含 URL 的页面内容的纯文本文件,而后者包含在从头开始时最重要的精炼信息。正如我们在结果中将看到的,单独传递 llms.txt 并不最有效,因为它有时会让 LLM 因上下文过多而感到困惑,并且没有如何导航和辨别重要信息的说明。

在介绍我们的 Claude Code 配置在不同任务上的表现之前,我们想分享我们用来确定任务完成情况和代码质量的评估框架。

评估

我们的目标是衡量什么最能提高代码质量,而不仅仅是功能性。像 Pass@k 这样的流行指标捕获功能,而不是最佳实践,这因上下文而异。

我们构建了一个特定于任务的评估工具,用于检查技术要求和主观方面,如代码质量、设计选择以及对首选方法的遵循程度。

我们为评估定义了三个类别

冒烟测试

这些用于验证基本功能。测试确认代码能够编译、暴露 .invoke() 方法、处理预期的输入状态,并返回预期的输出结构,如具有必需状态属性的 AIMessage 对象。

我们使用加权求和来计算分数

分数 = Σᵢ wᵢ × cᵢ

 其中 wi 是测试 i 的权重,ci 是测试的二进制结果。

任务要求测试

这些用于验证特定于任务的功能。测试包括验证部署配置文件、验证到外部 API(如网络搜索或 LLM 提供商)的 HTTP 请求,以及每个编码任务的单元测试。评分通过每个测试结果的加权求和完成,与冒烟测试相同。 

代码质量与实现评估

在此类别中,我们使用 LLM 作为评委来捕获二进制测试遗漏的内容。遵循更好方法的实现应该比仅仅编译和运行的代码得分更高。代码质量、设计选择和 LangGraph 抽象的使用都需要细致的评估。

我们审查了每个任务的专家编写的代码,并构建了特定于任务的评分标准。使用 Claude Sonnet 4 (claude-sonnet-4-20250514) 在温度为 0 的情况下,我们根据这些评分标准评估了生成代码,并将专家编写的代码作为参考,并使用人工注释来记录编译和运行时错误。

我们的评分标准包含两种类型的标准

客观检查:这是关于代码的二元事实(例如,特定节点的出现、正确的图结构、模块分离、测试文件的缺失)。LLM 评委对每个检查都返回了布尔响应,我们使用加权求和(与冒烟测试相同)来获得客观检查的分数。

主观评估:这是使用专家编写的代码作为参考的定性代码评估,以及用于记录编译和运行时错误日志的人工注释。LLM 评委识别出问题并按严重性(关键、主要、次要)将它们分类,跨越两个维度:正确性违规和质量问题。

我们使用基于惩罚的评分

分数 = 最高分 - Σₛ (nₛ × pₛ)

其中 最高分 是可能获得的最高分数,ns 是严重性 s 下的违规次数,ps 是该严重性的惩罚权重。 

将客观和主观结果结合起来的总体分数如下:

分数 = Σᵢ wᵢ × cᵢ + Σₛ (最高分ₛ - Σₛ (nₛ × pₛ))

其中第一项代表客观检查,第二项代表所有主观类别的评估。

我们对每个 Claude Code 配置在每个任务上运行了三次,以考虑方差。为保持一致性,所有分数均报告为总可能分数的百分比,然后按任务平均。

您可以使用 LangSmith 平台为自己的库复制此方法,以比较编码代理配置。

成果

我们对三个不同的 LangGraph 任务的分数进行平均,以比较 Claude Code 配置。下表显示了总体分数

对我们来说,最有趣的发现是 Claude + Claude.md 的表现优于 Claude + MCP,尽管 Claude.md 只包含 MCP 服务器可提供的一部分内容。跟踪解释了原因:Claude 调用 MCP 工具的次数不如我们预期的多。即使一个任务需要遵循两个或三个链接页面,它通常也只调用 MCP 一次,然后停在主页面,这只提供了表面描述,而没有提供所需的详细信息。

相比之下,Claude + Claude.md + MCP 更有效地使用了文档。我们在跟踪中观察到它更频繁地调用 MCP 工具,甚至在需要时触发了网络搜索工具。这种行为是由 Claude.md 驱动的,它在每个部分的末尾都包含了参考 URL 以查找更多信息。

这并不意味着 MCP 工具本身就没有帮助。它们将分数提高了约 10 个百分点,主要是通过将代理置于基本语法和概念上。但对于任务完成和代码质量而言,Claude.md 更为重要。该指南包含了要避免的陷阱和要遵循的原则,这有助于 Claude Code 更好地思考并探索库的不同部分,而不是停留在高级描述上。

这些结果为任何配置编码代理的人提供了一些更广泛的经验教训。

主要收获

结果给我们带来了一些收获。如果您正在考虑为自己的库定制编码代理,以下内容可能会有所帮助:

上下文过载:转储文档中的大型 llms.txt 文件会占用上下文窗口。这可能导致性能下降和成本增加。我们的 MCP 服务器实现了获取完整页面内容的朴素实现。即使调用一次,Claude Code 也收到了上下文窗口即将填满的警告。如果您的文档足够广泛,以至于您需要工具来检索特定文档,那么构建更智能的检索工具以仅提取相关片段是值得的。

Claude.md 的回报最高:设置比 MCP 服务器或特定工具更简单,运行成本也更低。在任务 #2 上,Claude + Claude.md 的成本比 Claude MCP 和 Claude + Claude.md + MCP 低约 2.5 倍。它的成本低于 Claude MCP 且性能更好。这是在考虑定制 Claude Code 时的一个很好的起点,并且对于某些用例来说可能已经足够了。

编写好的说明。 Claude.md(或 Agents.md)应重点介绍您库的核心概念、独特功能和常见原始组件。手动审查失败的运行,找出反复出现的陷阱并为其添加指导。对我们来说,这意味着在 LangGraph 中使用 Streamlit 来处理异步任务,代理经常在 asyncio 集成方面失败。我们还添加了用于启动开发服务器的调试步骤,这解决了导入错误,并允许 Claude Code 向服务器发送请求以验证输出。流行的代码生成工具通常使用长系统提示(7-10k token)。在说明上投入精力会带来相当大的回报。

Claude + Claude.md + MCP 获胜:虽然 Claude.md 提供的每 token 收益最高,但最强劲的结果来自将其与允许其详细阅读文档的 MCP 服务器配对。该指南提供了概念上的定向,文档则有助于深入研究。两者结合,可以为领域特定的库产生最佳结果。

在附录中,我们包含了每个任务的结果和类别图表,供读者深入了解每个任务的性能。

附录

任务 #1:文本到 SQL 代理

我们要求每个配置构建一个基于 LangGraph 的文本到 SQL 代理,该代理可以从自然语言生成 SQL 查询,在数据库上执行它,并返回自然语言响应。此任务要求从远程 URL 获取 Chinook SQLite 数据库并设置一个内存数据库。您可以在 此处 阅读我们传递给 Claude Code 实例的提示。

在此任务中,我们的冒烟测试验证了基本的 LangGraph 功能。任务要求检查了数据库设置;简单查询、连接查询、日期范围查询的 SQL 查询处理;LLM 作为评委评估了代码设计选择,如远程 URL 获取、用于 SQL 生成、执行和响应的单独节点。LLM 作为评委的提示可在 此处 获取。

结果显示了 Claude Code 配置和类别之间的性能差异

糟糕的实现通常在连接内存数据库的线程之间遇到困难,在 LLM 提示中下载并硬编码了模式而不是使用带有运行时模式读取的远程 URL,并且未能正确解析 LLM 输出以进行 SQL 执行(当 LLM 生成略有不同的格式化结果时会中断)。

任务 #2:公司研究员

在此任务中,我们要求每个 Claude 配置构建一个多节点 LangGraph 代理,该代理使用 Tavily API 进行网络搜索来研究公司。该代理需要处理结构化数据收集、实现并行搜索执行,并添加一个反思步骤以确保收集所有请求的信息。您可以在 此处 阅读提示。

我们的测试验证了基本功能、Tavily API 集成以及结构化对象类中所有请求属性的存在。 LLM 作为评委 检查了反思逻辑、最小搜索查询限制和并行网络搜索执行等功能的实现。

 以下是此任务的结果

大多数实现失败都与在状态中构建信息以及反思步骤有关。糟糕的实现要么没有功能性的反思节点,要么未能触发额外的搜索。

任务 #3:记忆类别

这是一项编辑任务,我们为每个 Claude Code 配置提供了一个现有的记忆代理作为基础代码。我们要求他们扩展记忆存储方法,以便除了用户 ID 之外,还可以按类型(个人、专业、其他)对记忆进行分类;实现基于消息类别(而不仅仅是用户 ID)的选择性记忆检索;并在保存记忆之前添加人工干预确认步骤。我们还故意添加了语法错误。完整提示可在 此处 获取。

通过测试,我们验证了实现正确地在记忆存储之前添加了中断功能、实现了按类别存储和检索、使用了三个特定类别(个人、专业、其他),并维护了功能性的中断逻辑,该逻辑仅在用户接受时才保存记忆。 LLM 作为评委 评估了实现是否使用了基于 LLM 的分类而不是脆弱的关键字匹配和不必要的文件。

对于编辑任务,我们看到以下结果

大多数实现都难以正确实现中断功能。错误实现要么添加简单的 input() 调用来获取终端输入,要么通过创建单独的节点来过度复杂化解决方案,而不是使用几行正确的中断逻辑。糟糕的实现还依赖于关键字匹配进行分类,而不是基于 LLM 的分类,并且几乎所有实现都未能捕获我们包含的故意语法错误。

© . This site is unofficial and not affiliated with LangChain, Inc.