Logo
概览
Building a Local Coding Agent with LangGraph: State, Tools, and Routing

Building a Local Coding Agent with LangGraph: State, Tools, and Routing

2026年5月22日
2 分钟阅读

使用 LangGraph 构建本地编码 Agent:状态、工具与路由

在 AI 辅助编程的场景中,一个可靠的本地编码 Agent 需要能够理解项目结构、搜索代码、读取文件、执行命令并安全地修改代码。LangGraph 作为工作流编排框架,非常适合管理这种多步骤、有状态的 agent 流程。本文将从状态设计、图构建、LLM 调用、工具调用机制到路径分叉,逐步展示如何用 LangGraph 搭建一个可控的本地编码 agent。

设计工作流状态

在 LangGraph 中,状态 (State) 是工作流的数据载体。定义状态字段时,可以通过以下几个问题判断是否需要记录:

  • 该数据是否被多个节点共享?
  • 是否需要从前一个节点传给后一个节点?
  • 是否会影响后续流程的走向?
  • 最终结果中是否需要该数据?

例如,对于一个编码 agent,状态可能需要包含:任务描述、已收集的文件列表、工具调用历史、中间分析结果等。

构建工作流图

LangGraph 的图由节点 (Node) 和边 (Edge) 构成,节点代表具体的处理步骤,边定义执行顺序。一个典型的图文件通常包含:

  • 多个节点函数,每个节点处理一个业务步骤(如 search、read、analyze、fix)。
  • 一个 build_graph() 函数,用于创建 StateGraph 并注册节点和边。
  • 通过 add_edge 定义固定流转,通过 add_conditional_edges 实现动态分支。

图本身只表达流程骨架,具体的业务逻辑应放在独立的 services 模块中,prompts 负责提示词管理,llm 模块封装模型调用。这样的分层让 project 清晰易维护。

真实的 LLM 调用

在 agent 中真正调用 LLM 时,需要考虑多种细节。

调用方式

可以选择云端 API(OpenAI、DeepSeek、通义千问等)、本地模型(Ollama、vLLM)、或通过 LangChain 的封装统一接口。

输入契约

每个节点应明确定义它需要读取哪些文本、返回什么结构,保证节点间解耦。

错误处理

必须处理 API key 缺失、网络失败、余额不足、超时、模型名错误、限流、返回空内容等异常。

成本与上下文

输入文本过长会增加费用和 token 消耗;模型上下文窗口有限;反复运行会累加成本。可通过截断、摘要或使用本地模型控制。

隐私

如果文本包含敏感信息,需在节点中脱敏。需要评估是否允许原文上传第三方,或采用本地模型方案。

同步/流式

根据交互需求选择同步调用或流式输出,流式可提升用户体验,同步便于后处理。

配置扩展

将 API key、模型名、超时等配置集中管理,预留扩展空间。

工具调用:释放 Agent 的能力

工具调用的本质是:LLM 负责“想做什么”,程序负责“能不能做、怎么做、做完返回什么”。LLM 本身无法读取文件或执行命令,它只能生成结构化的 tool_call,由程序安全执行并返回结果。

基本流程

用户任务 → Agent Host 将任务和可用工具描述发给 LLM → LLM 返回普通回复或 tool_call → Host 校验安全性并执行工具 → 结果作为 observation 返回 LLM → 循环直到给出最终回答。

核心工具定义

一个本地编码 agent 通常需要以下五个核心工具:

  1. list_files(path):列出项目文件,让模型了解项目结构。
  2. read_file(path, start_line, limit):分段读取文件,避免上下文爆炸。
  3. search_text(query, path):内部调用 ripgrep 搜索代码,快速定位相关片段。
  4. run_command(cmd, cwd, timeout):执行命令(如测试、构建),根据真实报错迭代修复。必须严格校验命令安全性。
  5. apply_patch(patch):用 patch 方式修改文件,方便审计和回滚,避免直接覆盖整个文件。

工具通过 JSON Schema 定义参数类型和约束,模型只能生成符合该 schema 的结构化请求,程序负责解析、校验、执行并截断输出。

安全沙箱

所有文件操作必须限定在 workspace 内。实现时,将 workspace 和请求路径都解析为绝对路径,检查目标路径是否仍在 workspace 下,否则拒绝。此外可禁止访问某些敏感文件(如 .env、密钥文件)。命令执行同样需要设置超时、最大输出长度,并记录退出码和 stderr,帮助模型分析失败原因。

最小实现循环

下面是一个简化的 agent 主循环代码框架(Python 伪代码):

messages = [
{"role": "system", "content": "你是一个本地编码 agent。"},
{"role": "user", "content": "帮我修复测试失败的问题"}
]
while True:
response = call_llm(messages, tools=[...])
if response.type == "final":
print(response.text)
break
for tool_call in response.tool_calls:
if not permission_allowed(tool_call):
result = {"error": "Permission denied"}
else:
result = execute_tool(tool_call)
messages.append({"role": "assistant", "tool_call": tool_call})
messages.append({"role": "tool", "content": json.dumps(result)})

注意,LLM 本身是无状态的,所谓“记忆”是应用在每次请求前将历史、工具结果等组织进上下文。

提示词示例

agent 的系统提示词应该简洁且定义边界:

你是一个本地编码 agent。你可以使用工具读取文件、搜索文本、运行命令、应用 patch。在修改代码前,必须先理解现有代码。优先使用 search_text 和 read_file,不要猜测文件内容。不要访问 workspace 外的文件。执行破坏性命令前必须请求用户确认。命令失败时,要根据 exit_code、stdout、stderr 分析原因。修改代码后,尽量运行相关测试。

完整示例:修复登录失败

假设用户报告“登录失败”,agent 可能执行以下步骤:

  1. search_text("login") 找到 login 相关文件。
  2. read_file("src/auth.ts")read_file("tests/auth.test.ts") 理解逻辑。
  3. run_command("npm test -- auth.test.ts") 运行测试,得到错误:Expected token to be defined, received undefined
  4. 分析后通过 apply_patch 修改 src/auth.ts,让函数返回 token。
  5. 再次运行测试验证通过。
  6. 输出最终回答。

每一步都由清晰的 tool_call 驱动,安全可控。

路径分叉与条件路由

LangGraph 支持条件边,可根据状态动态选择下一个节点。使用 add_conditional_edges 注册路由:

graph.add_conditional_edges(
"start_node",
route_after_start_node,
{
"next": "next_node",
"stop": END,
}
)

路由函数根据 state 返回逻辑标签(如 "next""stop"),路由表将标签映射为实际节点。这样就能实现“如果状态 ok 则继续,否则结束”等分支逻辑。整个流程如下:

flowchart TD
A["start_node"] --> B["route_after_start_node(state)"]
B -->|"返回 next"| C["next_node"]
B -->|"返回 stop"| D["END"]

结语

通过 LangGraph,我们可以将编码 agent 的思考与执行分离,用清晰的图结构管理流程,用工具调用赋予模型与本地环境交互的能力,并通过条件路由实现智能化决策。在设计自己的 agent 时,请始终把安全放在第一位:路径沙箱、命令校验、输出截断、人工确认,都是不可或缺的环节。

希望本文的思路能为你构建下一款本地 AI 助手提供参考。