打造自己的 Claude Code:LangGraph + MCP 搭建一个极简的 AI 编码助手

简介: 本文通过构建一个极简CLI编码代理,探索LangGraph与MCP服务器的底层机制。摒弃商业代理的复杂封装,验证“裸机”LLM代理在无限循环中调用工具的可行性。集成文件操作、网络搜索、GitHub交互等MCP工具,结合Pytest自动化测试与SQLite状态持久化,实现可观察、可调试的智能编码工作流,揭示模型上下文协议的核心价值与实践挑战。

实践是最好的学习方式。为了深入理解 LangGraph 和模型上下文协议(MCP)服务器的生态,我们来从零开始构建一个 CLI 编码代理。我们的目标是,抛开 Claude Code 那些花里胡哨的功能,看看最基础的编码代理能做到什么程度。

那些商业编码代理往往会添加各种专有的"秘密配方"——特殊的上下文管理、精心设计的提示策略、优化过的工具选择算法。这些技术细节被包装得严严实实,很难搞清楚哪些是必需的,但对于学习来说,那些只是锦上添花。我们这篇文章的目标是验证一个问题:用最简单的方式让 LLM 在无限循环里不断调用工具,这样的"裸机"代理到底行不行?那些复杂的技术栈是真的必要吗,还是过度设计了?

核心功能设计

这个代理的设计理念就是极简但实用。整个系统由一个交互式状态图驱动,信息流向很清晰:用户输入 → 模型响应 → 工具调用 → 回到用户,形成持续的对话循环。本地功能实现了文件读取器和 pytest 的封装用于单元测试。MCP 集成覆盖了几个关键场景:Desktop Commander 负责文件系统操作,Pydantic AI 的沙箱 Python MCP 跑在 Deno Docker 容器里,DuckDuckGo 提供网络搜索,还有官方的 GitHub MCP。为了提升可观测性,还加入了丰富的终端界面和 Mermaid 工作流可视化,可以清楚地看到代理的思考和执行过程。

下面是几个使用示例:

通过 Desktop Commander MCP 的 read_file 工具读取 TypeScript 文件并展示内容

利用 DuckDuckGo 的 MCP 执行网络搜索

快速上手

环境准备很简单,只需要对 Docker 和命令行有基本了解就够了。启动主代理的命令:

 uv run main.py

如果要用沙箱 Python 执行功能,需要先构建 Deno MCP 的 Docker 镜像:

 docker build -t deno-docker:latest -f ./mcps/deno/Dockerfile .

启动后可以试试这些指令来体验功能:

  • "Show me the content of main.py"
  • "What tools do you have?"
  • "Read requirements.txt"

状态持久化与调试

集成了

langgraph-checkpoint-sqlite

来跟踪对话历史,方便调试。这个基于 SQLite 的检查点机制很适合本地实验场景。可以直接从终端查看代理状态:

 sqlite3 checkpoints.db "SELECT * from writes LIMIT 2"
 sqlite3 checkpoints.db "SELECT * from checkpoints LIMIT 2"

Pytest 集成

传统做法是写完代码手动跑测试,而现在代理会自动执行这个流程。体验提升非常明显:只需要说"X 功能有问题",代理就会跑测试套件,定位失败的测试用例,分析错误信息,然后给出针对性的修复方案。这彻底省掉了盯着测试日志发呆或者把终端输出复制到 ChatGPT 的繁琐操作,代理拿到的上下文信息足够精确,诊断效率大幅提高。

代码实现

这套代码基于 LangChain 框架,使用 Claude 3 Sonnet 作为核心模型来处理代码库的维护和开发任务。整个系统采用 StateGraph 工作流,包含三个关键节点:user_input、model_response 和 tool_use。

流程在节点间流转,模型响应决定下一步是调用工具还是回到用户输入环节。AgentState 负责维护状态,跟踪完整的消息历史。

核心工作流的实现代码:

 # Key workflow setup from the Agent class
def __init__(self):
    self.workflow = StateGraph(AgentState)

    # Register the three main nodes
    self.workflow.add_node("user_input", self.user_input)
    self.workflow.add_node("model_response", self.model_response)
    self.workflow.add_node("tool_use", self.tool_use)

    # Define the flow
    self.workflow.set_entry_point("user_input")
    self.workflow.add_edge("user_input", "model_response")
    self.workflow.add_edge("tool_use", "model_response")

    # Conditional routing based on tool usage
    self.workflow.add_conditional_edges(
        "model_response",
        self.check_tool_use,
        {
            "tool_use": "tool_use",
            "user_input": "user_input",
        },
     )

代理同时加载本地工具(比如单元测试)和运行在 Docker 容器里的 MCP 工具。工具设计上返回结构化的 ToolMessages,让 StateGraph 能够正确路由响应回模型。这些工具支持运行 Python 代码、搜索 DuckDuckGo、与 GitHub 交互等操作。状态在交互间通过 SQLite 检查点机制保持。

LangGraph 的状态架构解析

StateGraph 工作流机制值得单独拿出来细说,因为它是整个代理模式的基础支撑。LangGraph 的 StateGraph 实现了带持久化状态管理的有向图工作流。架构分解如下:

状态管理

 class AgentState(BaseModel):
     messages: Annotated[Sequence[BaseMessage], add_messages]

AgentState 类基于 Pydantic 的 BaseModel,维护完整对话历史,在图遍历过程中追踪所有消息类型(系统消息、用户消息、助手消息和工具消息)。

图结构设计

工作流由三个节点构成有向图:

  1. 用户输入节点:入口点,收集用户输入
  2. 模型响应节点:用 Claude 处理输入并决策下一步行动
  3. 工具使用节点:响应模型请求执行具体工具

图的配置代码:

 # Core graph structure
workflow = StateGraph(AgentState)

# Node registration
workflow.add_node("user_input", self.user_input)
workflow.add_node("model_response", self.model_response)
workflow.add_node("tool_use", self.tool_use)

# Edge connections
workflow.set_entry_point("user_input")
workflow.add_edge("user_input", "model_response")
 workflow.add_edge("tool_use", "model_response")

流程控制逻辑

图通过 check_tool_use 实现条件路由:

  1. user_input → model_response(固定路径)
  2. model_response → tool_use(存在工具调用时)
  3. model_response → user_input(无工具调用时)
  4. tool_use → model_response(固定路径)

持久化机制

通过 AsyncSqliteSaver 使用 SQLite 做检查点:

 db_path = os.path.join(os.getcwd(), "checkpoints.db")
 self._checkpointer_ctx = AsyncSqliteSaver.from_conn_string(db_path)
 self.checkpointer = await self._checkpointer_ctx.__aenter__()
 self.agent = self.workflow.compile(checkpointer=self.checkpointer)

这套机制让对话状态能跨会话保持遇到中断也能恢复。整个工作流构成一个持续循环,代理可以处理用户输入、生成响应、按需调用工具,在整个交互过程中保持上下文连贯性。

MCP 服务器的模块化实践

MCP 的配置用到了 LangChain 的 mcp-adapters 库,调用

get_tools

方法。某些工具需要在系统提示词里补充描述信息,确保检索准确性。把 MCP 服务器打包成容器解决了环境冲突和依赖管理,用户直接跑容器就行,不用折腾安装配置。

Desktop Commander MCP 提供的能力和 Claude Code 基本重合:完整的文件系统操作、代码编辑、审计日志。通过 Docker bind mount 配置把访问范围限制在测试文件夹,保持严格隔离。这种方式让实验变得安全,不用担心搞坏实际文件系统。

Pydantic AI 的 run-python MCP 基于 Deno 容器创建沙箱 Python 执行环境。Deno 在 WebAssembly 沙箱里跑 Pyodide,阻止 LLM 在系统上执行危险代码或任意操作。虽然本地安装 Deno 也相对安全,但这会让本地环境变得臃肿。

DuckDuckGo MCP 提供互联网搜索能力,需要实时信息检索时调用。

官方 GitHub MCP 负责代码仓库搜索和管理功能。

实践中的几个关键问题

安全性和可配置性。 对代理的访问权限必须有精细控制。可以给 MCPs 做 Docker 化并设置特定权限——比如 GitHub MCP 用只读标志运行来保护仓库。文件系统访问权限需要有简单的开关机制。,用

gh

CLI 工具替代 GitHub MCP 可能更合理,能减少 token 消耗,和 Desktop Commander MCP 的终端访问配合也更流畅。随着 Claude Skills 推出和 CLI 工具链成熟,现在有更好的方案来防止上下文污染且保持功能完整。

工具过载是个要注意的问题。 MCPs 加载所有工具及其描述至少两次:初始化代理时一次,每次用户查询时又一次。如果各种 MCPs 加起来有 40 多个工具,LLM 上下文很快就被塞满了。必须仔细检查每个 MCP 的工具命名,避免不同来源的函数名冲突。

MCP 资源使用是事件驱动的。 MCPs 按需启动,资源消耗呈现尖峰特征,但在 MacBook Pro 上不算过分。编码代理需要从 MCP 客户端调用工具时,会用指定命令生成 MCP 进程——通常是

docker run

,也可能是

npx

或 Python 命令。容器运行时长刚好够执行工具调用,然后自行终止和清理,释放 CPU 资源给下一个操作。这种按需架构让代理保持轻量,同时能访问丰富的工具生态。

MCP 分发方式。 很多 MCPs 提供预配置的 Docker 镜像,可以快速集成到编码代理里,方便维护隔离性。不过很多 MCPs 也有 Python 库版本,想要更紧密的集成且不需要额外安全层的话可以本地安装。

langchain-mcp 还不错。

langchain-mcp-adapters

库可以把 MCPs 桥接到 LangGraph,和 FastMCP 库的类似功能差不多水平。但它提供了平滑的接口,把 MCP 工具转换成 LangChain/LangGraph 兼容的工具,改动代码不多。

工具调用前的用户许可机制需要完善。 代理执行工具不会提前征求许可,感觉风险挺大。可以在工具调用前加入人机交互环节能解决这个问题,但代价是会打断代理的执行流程。

后续改进方向

几个增强功能值得考虑。跨个人笔记的综合 RAG 工具——覆盖 Notion、Obsidian、文本文件、markdown——能让代理访问多年积累的知识和研究资料。加入 Confluence MCP 或内部文档 CLI 可以快速搜索公司特定的实践规范。如前面提到的,换成

gh

CLI 替代 GitHub MCP 能节省 token。最后在每次工具调用前实现人机交互中断会增加关键的安全层,不过希望做成可配置的,避免在可信操作时频繁打断代理。

本文代码

https://avoid.overfit.cn/post/790f9ab797bc4cf8bdfeb0c7ac58ae83

Lorre Atlan, PhD

目录
相关文章
|
3天前
|
人工智能 开发框架 自然语言处理
2025年好用Agent软件全解析:从选型逻辑到Top产品盘点,这篇讲透
2025年,AIAgent已从概念走向企业级应用,成为降本增效的核心工具。市场规模爆发式增长,实在Agent、Cursor、Glean等在通用自动化与垂直领域表现突出,AutoGen、LangChain则赋能开发者构建定制化智能体。企业选型需结合场景、安全与集成能力,迈向实用化落地。
|
10天前
|
人工智能 自然语言处理 安全
AutoGen框架入门:5个核心概念搭建智能体协作系统
AutoGen是微软开源的多智能体AI框架,支持多个AI智能体与人类协作,通过对话完成复杂任务。各智能体具备不同角色与能力,可调用工具、执行代码,并在群聊中辩论、推理、纠错,实现无需人工干预的自动化协作,适用于复杂问题求解与团队化AI应用开发。
121 13
AutoGen框架入门:5个核心概念搭建智能体协作系统
|
机器学习/深度学习 人工智能 自然语言处理
如何构建企业级数据智能体:Data Agent 开发实践
本篇将介绍DMS的一款数据分析智能体(Data Agent for Analytics )产品的技术思考和实践。Data Agent for Analytics 定位为一款企业级数据分析智能体, 基于Agentic AI 技术,帮助用户查数据、做分析、生成报告、深入洞察。
|
10天前
|
SQL 人工智能 关系型数据库
AI Agent的未来之争:任务规划,该由人主导还是AI自主?——阿里云RDS AI助手的最佳实践
AI Agent的规划能力需权衡自主与人工。阿里云RDS AI助手实践表明:开放场景可由大模型自主规划,高频垂直场景则宜采用人工SOP驱动,结合案例库与混合架构,实现稳定、可解释的企业级应用,推动AI从“能聊”走向“能用”。
AI Agent的未来之争:任务规划,该由人主导还是AI自主?——阿里云RDS AI助手的最佳实践
|
1天前
|
人工智能 JSON 测试技术
Dify入门实战:5分钟搭建你的第一个AI测试用例生成器
本文教你利用Dify平台,结合大模型API,5分钟内搭建一个无需编程基础的AI测试用例生成器。通过配置提示词、连接AI模型,实现自动输出覆盖正常、异常及边界场景的结构化测试用例,提升测试效率与质量,并支持集成到CI/CD流程,助力智能化测试落地。
|
5月前
|
存储 自然语言处理 算法
Adaptive-k 检索:RAG 系统中自适应上下文长度选择的新方法
本文介绍 Adaptive-k 检索技术,这是一种通过相似性分布分析动态确定最优上下文规模的即插即用方法,该技术在显著降低 token 消耗的同时实现了检索增强生成系统的性能提升。
104 1
Adaptive-k 检索:RAG 系统中自适应上下文长度选择的新方法
|
1天前
|
缓存 PyTorch API
TensorRT-LLM 推理服务实战指南
`trtllm-serve` 是 TensorRT-LLM 官方推理服务工具,支持一键部署兼容 OpenAI API 的生产级服务,提供模型查询、文本与对话补全等接口,并兼容多模态及分布式部署,助力高效推理。
34 1
|
1天前
|
机器学习/深度学习 人工智能 自然语言处理
AI驱动的测试:用Dify工作流实现智能缺陷分析与分类
传统缺陷分析耗时耗力,依赖经验且效率低下。通过Dify工作流与AI技术融合,实现缺陷报告的多模态解析、智能分类、根因定位与处理建议生成,将单个缺陷处理时间从15-20分钟缩短至2-3分钟,准确率超95%,大幅提升测试效率与质量一致性。
|
1天前
|
人工智能 Anolis 开发者
|
5月前
|
机器学习/深度学习 存储 监控
ProRL:基于长期强化学习让1.5B小模型推理能力超越7B大模型
该研究通过长期强化学习训练(ProRL)挑战了强化学习仅能放大模型输出的传统观点,证明其能使基础模型发现全新推理策略。ProRL体系包含KL散度控制、参考策略重置及多元化任务训练集。核心算法GRPO优化了传统PPO,缓解熵坍塌问题并提升探索能力。Nemotron-Research-Reasoning-Qwen-1.5B模型基于此方法训练,在数学、编程、STEM等领域显著超越基础模型,性能提升达15.7%-25.9%,并在分布外任务中展现更强泛化能力。
114 3
ProRL:基于长期强化学习让1.5B小模型推理能力超越7B大模型
下一篇
开通oss服务