← 返回博客
2026-10-02 08:00:02

Agent 开发框架对比:LangChain vs 原生实现,生产环境到底该选哪个

Agent 开发框架对比:LangChain vs 原生实现,生产环境到底该选哪个

一个电商客服 Agent,需要查订单、算退款、发邮件。团队用 LangChain 两天跑通 demo,上线后却卡在三件事:链路里某一步超时找不到是哪一层、想换成自研的向量检索要改十几处、并发一上来 token 消耗翻倍还说不清花在哪。这不是 LangChain 的锅,是选型时没想清楚边界。

先看两条路的骨架

LangChain 的价值在于把「LLM 调用 + 工具调用 + 记忆 + 检索」抽象成 Chain 和 AgentExecutor,配套大量现成集成。原生实现就是自己写循环:调模型 → 解析 tool_calls → 执行工具 → 把结果塞回 messages → 再调模型,直到模型不再请求工具。

LangChain 适合快速验证和多模型/多工具拼装;原生适合链路固定、对可观测性和成本敏感的线上服务。判断标准很简单:这个 Agent 的工具集会不会频繁变?如果半年内基本固定,原生实现的维护成本反而更低。

用 Java 写一个原生 Agent 循环

Java 生态里 LangChain4j 是主流选择,但很多团队最终回到原生,因为循环本身不复杂。下面是一个最小可用的 Agent 循环,用 OpenAI 兼容接口:

public String runAgent(String userInput, List<Tool> tools) {
    List<Map<String, Object>> messages = new ArrayList<>();
    messages.add(Map.of("role", "user", "content", userInput));

    for (int step = 0; step < MAX_STEPS; step++) {
        Map<String, Object> req = Map.of(
            "model", "gpt-4o-mini",
            "messages", messages,
            "tools", tools.stream().map(Tool::schema).toList()
        );
        JsonNode resp = httpPost("/v1/chat/completions", req);
        JsonNode msg = resp.at("/choices/0/message");
        messages.add(toMap(msg));

        JsonNode toolCalls = msg.get("tool_calls");
        if (toolCalls == null || toolCalls.isEmpty()) {
            return msg.get("content").asText();
        }
        for (JsonNode call : toolCalls) {
            String name = call.at("/function/name").asText();
            String args = call.at("/function/arguments").asText();
            String result = executeTool(name, args, tools);
            messages.add(Map.of(
                "role", "tool",
                "tool_call_id", call.get("id").asText(),
                "content", result
            ));
        }
    }
    throw new IllegalStateException("超过最大步数,疑似死循环");
}

关键点在三个地方。MAX_STEPS 必须设,否则模型反复调同一个工具会烧光额度;tool_call_id 必须原样回传,漏了 OpenAI 会直接报 400,这是最常见的坑;messages 要保留完整历史,包括 assistant 那条带 tool_calls 的消息,只回传 tool 结果会让模型丢失上下文。这套代码不到 40 行,没有任何框架依赖,出问题打日志一眼能定位。

那 LangChain 什么时候值得用

当工具超过 15 个、需要按语义动态筛选工具、或者要接 RAG + 多轮记忆 + 流式输出时,自己维护这些编排逻辑会失控。LangChain 的 create_react_agent 加 ToolNode 能省掉大量胶水代码,LangGraph 还能把状态机画出来,调试多分支 Agent 时确实省心。

代价是抽象层变厚。想换检索实现、加自定义重试、按业务埋点,都得顺着框架的接口走。生产环境最常见的做法是混合:用框架做编排和工具注册,把核心的检索、计费、限流做成独立服务,通过一个薄工具接口接进去。这样框架升级不影响业务逻辑。

踩坑总结

第一,别用框架的默认 memory。多数默认实现把所有历史塞进 context,长会话 token 爆炸。自己按轮次截断或做摘要更可控。第二,工具执行要加超时和幂等。模型可能对同一个订单查两次,写操作必须带幂等键。第三,可观测性优先于功能。每一步的输入输出、耗时、token 数都要落日志,否则线上出问题只能靠猜——这也是原生实现在生产环境更受欢迎的真正原因。第四,流式输出和工具调用在部分框架里兼容性差,上线前一定压测。

结论

Demo 阶段用 LangChain 提速度,链路稳定后评估是否收敛到原生循环。核心循环不到 50 行,掌控权在自己手里比省那点胶水代码更值钱。

下一步建议:拿现有 Agent 的完整调用日志,统计工具数量和分支复杂度,超过阈值再上框架,否则先手写。

本文关键词:Agent、LangChain、LangChain4j、工具调用、上下文管理