随着大语言模型(LLM)应用的普及,围绕 AI Agent 的开发生态愈发成熟。现今已有诸多高度抽象化的框架和工具,开发者只需传入系统提示词(system prompt)和具体任务(task),即可快速搭建可用的智能体。然而,相较于依赖封装完备的框架,我更倾向于从底层出发,构建一个可控性更强、逻辑更清晰的完整 Agent 系统。

起初,我以“设计一个能帮助自己决定自驾游目的地的 Agent”为契机,着手开展这项探索。在过程中,我不仅梳理了从零开发 Agent 的关键路径,同时也深入分析了当前框架选型的利弊及实践中遇到的问题。


框架选型:LangChainGo 的初体验与挑战

由于希望了解 Agent 框架中 Prompt 构建、节点间数据流转等底层机制,我主动避开了过于抽象的解决方案,而是选择使用 Go 语言搭建系统。

曾经我写过一些与 LangChain 和 LangGraph 相关的项目,因此在语言选择上,我决定借此机会深入掌握 Go。然而,这也让我遭遇了不少“新手开发者常见的陷阱”:虽然 LangChain Go 在 GitHub 上拥有约 7000 颗 star,但文档严重缺失,示例代码难以正常运行,我甚至提交了两个 PR 来修复 tutorial 与 quickstart 中的错误。

此外,由于该项目演进迅速,API 结构频繁调整,加上 Gemini 或 OpenAI 等 AI 模型对这些代码库的学习大多基于历史版本,这导致 AI 在协助开发时容易输出过时或混乱的代码示例,进一步加剧了新手开发者的入门门槛。


流式返回之困:LangGraph 与 LangChain 设计理念的差异

我原计划使用 LangChain Go 完成整个项目。但出于稳定性和社区活跃度的考虑,起初并未考虑使用 LangGraph Go。直到回顾自己最初通过 LangGraph Academy 学习 AGI 编程的经历后,我意识到自己对其底层机制有更深入的理解,便开始重新评估这一框架的可行性。

我在转向 LangGraph 开发后遇到的第一个问题是对“流式返回”的误解。在多数应用中,LLM 的返回结果通常以流式方式呈现,因此我理所当然地期望在 Agent 的节点间也能实现类似机制。

但实践中我发现:

  1. 当调用 Reasoning 模型时,无法获取其思考过程的流式输出;
  2. 即便调用完成,也无法及时获得 ReasoningContent,只能在 invoke 全部结束后一次性返回结果。

这一问题令我反复权衡是否要放弃思考链的展示逻辑。虽然对“推荐旅游路线”这类应用场景而言,过程并非关键,但我仍希望在架构上实现更高的透明度和控制力。

深入对比之后我意识到:这是 LangChain 与 LangGraph 在设计理念上的核心分歧。LangGraph 将每个节点视为独立计算单元,因此天然支持思考过程的流式输出;而 LangChain 更强调完整性和结构化,不适合拆解中间状态。

如果开发者对过程可视化、流式反馈有明确需求,LangGraph 无疑是更优的选择。


ReAct 节点的应用:提升效率,也埋下隐患

在 LangChain 的使用过程中,我曾为以下问题耗费大量精力:

  • 工具(Tool)如何注册并调度?
  • 多任务如何分发至不同子 Agent?
  • 节点失败时如何恢复?

这些调度逻辑极大增加了代码复杂性,直到我开始使用 LangGraph 的 ReAct Node。该节点通过封装推理与工具调用逻辑,有效减少了样板代码,使我得以将精力集中在业务规则与 ToolNode 的开发上。

我原本预想:一个 ReAct 节点可以执行一个小型子图,例如包含“交通推荐”与“景点规划”的双 Agent 架构,并借助 MCP Server 实现信息获取与处理的自动化。然而实践中仍面临两个显著问题:

1. 输入信息冗余带来的上下文污染

在 ReAct 节点内部,所有上下文会被一并传入模型调用。这种“过载输入”常导致 AI 对任务的理解失真,尤其在缺乏对场景进行精细 prompt 调优时,容易出现回答偏离、任务失败等问题。

2. 输出行为不确定性带来的流程错误

ReAct 节点的最后返回始终是一个 AI Message,若 prompt 指定应返回 ToolCall,则 AI 可能返回空对象。这与多数框架中使用 message.getType === 'tool' 的判断逻辑相悖,进而使 Router 无法正确读取下一个行动指令。

由于这一点,我曾尝试反复通过 Gemini 修改生成代码以适配预期逻辑,但始终无法解决问题。这很可能是由于 ReAct 节点内部结构在持续演变,加之 AI 的幻觉干扰,导致行为不可预测。

直到我在阅读文档时看到一条关键提示:

ReAct 节点本质上是一个封装的 SubGraph,开发者无需关注中间每一步工具调用或 AI Message,只需处理最终返回的 AI Message。

这个认识的转变,彻底改变了我对 LangGraph 开发中子图划分与流程组织的认知。


关于 AI 编程的几点反思

作为 Cursor 的早期用户,我清晰感受到 LLM 在代码生成方面的持续进化。在简单场景中,如天气卡片等任务,AI 已可实现“一次返回、即可运行”。

但这也引发了我对自身开发效率的反思:

  1. 代码能力的退化:过去一两周,我几乎不再主动编写代码,仅在 Gemini 输出错误时才调试修复,逐渐失去了对代码细节的敏感度。

  2. 开发周期的延长:尽管 AI 编码减少了敲键时间,但由于生成内容常不符合业务对象设计原则,冗余和重复不可避免。即使使用 memory-bank 或协定协议,也难以彻底解决上下文飘移与接口不一致的问题。

在实践中,我逐渐意识到:借助 Copilot 提供函数签名,自己完成实现逻辑,往往才是效率与质量的平衡点。


结语:从框架、AI 到人自身的演进

Agent 无疑是未来的重要方向。无论是工具层框架,还是 AI 编码助手,当前仍处于“混沌期”,距离真正的“开发流程托管”还有很长的路要走。

对我而言,这段从底层动手、再到框架重选、再到交互与调度优化的旅程,是一次深刻的能力沉淀。在未来的实践中,我会更加重视:

  • 框架设计理念的适配性;
  • 人与 AI 分工边界的动态调整;
  • Prompt 与数据结构的通用化与控制能力。

也期待未来能出现更加稳健、透明、可控的 AI Agent 构建方案。LOL