Skip to content

LangChain 与单 Agent

1. 从一个真实场景开始

你有没有直接调用过模型 API,然后发现一件小事就要写很多样板代码?

不同厂商的 SDK 格式不一样,返回结构不一样,流式处理也不一样。等你终于把模型接通了,又发现真正麻烦的是后面的事:怎么把用户输入、系统人设、历史对话、外部检索结果和工具说明拼成一次完整请求?步骤多了之后,代码越来越像“拼装脚本”。

来看一个具体例子。用户发来:

我下周三下午要去看牙医,你帮我记一下。对了,我上次是不是说过我最怕看牙?

要处理好这条消息,系统至少得做:

  1. 识别这是一个“提醒 + 记忆确认”的混合请求。
  2. 带上当前 Agent 的人设设定。
  3. 取出最近的对话记录。
  4. 必要时去查长期记忆。
  5. 调用写日程的工具。
  6. 最后生成一段自然的回复。

LangChain 在这里负责的,就是把这些步骤串成一套稳定、可维护的开发方式。下面我们不讲抽象定义,只回答一个很实际的问题:当我们做一个单 Agent 应用时,LangChain 到底替我们处理了哪些工作

2. LangChain 在单 Agent 里的六件事

可以把 LangChain 在单 Agent 里的作用拆成六层:

层级解决什么问题
模型接入不同厂商的模型用统一方式调用
输入组织把用户输入、人设、历史、检索结果拼成模型能理解的结构
链路编排把多个步骤串成可复用的数据流
工具接入把外部能力封装成模型可调用的标准接口
Agent runtime让模型在一次请求中自主决定要不要调用工具
记忆与检索接入把短期上下文和长期记忆稳定接进处理流程

注意:这里讲的是单 Agent。多 Agent 的编排、分支、持久化和人工确认,通常要交给 LangGraph 负责。LangChain 更像工具箱,LangGraph 更像流程图。这个边界我们在本系列其他文章里已经展开过。

3. 第一件事:把模型接进应用

做 LLM 应用时,最先碰到的问题通常不是 Prompt,而是“模型怎么接”。如果不用框架,直接调用模型接口,你很快会碰到这些细节:

  • 不同厂商的 SDK 不一样。
  • 请求格式不一样。
  • 返回结果结构不一样。
  • 流式返回的处理方式也不一样。

LangChain 先把这件事统一了。在单 Agent 场景里,你最常做的一步就是给 Agent 指定一个模型:

typescript
import { createAgent } from "langchain";

const agent = createAgent({
  model: "openai:gpt-4.1-mini",
});

如果你想显式创建模型对象,也可以:

typescript
import { createAgent } from "langchain";
import { ChatOpenAI } from "@langchain/openai";

const model = new ChatOpenAI({
  model: "gpt-4.1-mini",
  temperature: 0.2,
});

const agent = createAgent({
  model,
});

这一步看起来很普通,但它解决的是最底层的接入问题。模型接进来以后,Prompt、Tool、上下文、记忆才有地方可接。

4. 第二件事:把输入整理成模型能理解的结构

用户说一句话,系统内部并不是原封不动地把它丢给模型。真正送进模型之前,往往还要拼很多东西:

  • 当前这轮用户输入
  • 系统设定
  • 角色背景
  • 最近对话历史
  • 工具说明
  • 外部检索结果

LangChain 在这里负责两类事情。

第一类:消息结构。 聊天模型内部不是只吃一段字符串,而是吃一串有角色的消息,比如 systemuserassistanttool。LangChain 把这些消息组织方式统一起来,这样你在不同模型之间切换时,不用重新设计输入结构。

第二类:Prompt 组织。 Prompt 在项目里不是一句临时文案,而是一个长期维护的输入模板。你会逐步把不同来源的信息填进去,最后形成这一轮请求真正使用的上下文。通常包括:

  • 固定人设
  • 当前任务说明
  • 最近聊天记录
  • 用户这次发来的问题

所以从应用层看,LangChain 不只是“调模型”,它还负责把输入整理成可维护的结构。

5. 第三件事:把多个步骤串成一条链

只要不是最简单的 demo,请求处理过程通常都不止一步。还是刚才那条消息,系统内部很可能会这样走:

  1. 先整理输入
  2. 判断是否需要查记忆
  3. 查询记忆
  4. 调用提醒工具
  5. 生成最终回复

如果这些步骤完全散落在普通函数里,代码会越来越像“拼装式脚本”。前一个函数的输出怎么交给下一个函数,哪个阶段失败了,哪里要改,都不够直观。

LangChain 提供的是一套链路组织方式。你可以把它理解成:把一堆零散动作,整理成一条明确的数据流。

最简单的链可能只有三步:

typescript
const chain = prompt.pipe(model).pipe(parser);

复杂一点时,这条链里还会加入:

  • 历史消息注入
  • 检索结果补充
  • 工具调用
  • 输出解析

在单 Agent 应用里,这件事很重要。因为随着功能一点点加上去,你最先需要的不是更高级的智能,而是更稳定的组织方式。

6. 第四件事:把外部能力接成工具

单纯调用模型时,系统只能“回答”。一旦接入工具,系统才真正开始“做事”。在任务助手场景里,常见工具包括:

  • 查询长期记忆
  • 写入提醒事项
  • 查询天气
  • 调用搜索接口

LangChain 在这里负责的是,把这些外部能力接成模型能调用的工具。比如一个写提醒工具:

typescript
import { tool } from "langchain";
import * as z from "zod";

const createReminder = tool(
  async ({ title, time }) => {
    return `已创建提醒:${time} ${title}`;
  },
  {
    name: "create_reminder",
    description: "创建提醒事项",
    schema: z.object({
      title: z.string(),
      time: z.string(),
    }),
  },
);

这里 LangChain 做的不是帮你实现提醒逻辑。提醒逻辑还是你自己写。它负责的是把这段能力包装成一个标准工具,让 Agent 能知道:

  • 这个工具叫什么
  • 它是干什么的
  • 它接受什么参数
  • 它返回什么结果

这一步做完以后,Agent 才有机会在一次请求里决定:

  • 现在需不需要创建提醒
  • 传什么参数给提醒工具
  • 拿到工具结果后,怎么继续回复用户

7. 第五件事:让一个 Agent 处理完整的一轮请求

把模型、输入结构、链路、工具都准备好后,LangChain 最终做的事就是:把这些东西合成一个能真正接任务的 Agent。这一层在代码里就体现为 createAgent()

typescript
import { createAgent } from "langchain";

const agent = createAgent({
  model: "openai:gpt-4.1-mini",
  tools: [createReminder, searchMemory],
  systemPrompt: "你是一个自然、克制、会照顾用户情绪的助手。",
});

这个 Agent 建好后,一轮请求就能完整跑起来:

typescript
const result = await agent.invoke({
  messages: [
    {
      role: "user",
      content:
        "帮我记一下下周三下午两点去看牙医,再告诉我我是不是以前提过怕看牙。",
    },
  ],
});

这一步里,LangChain 承担的是一个很实际的角色:

  • 接住用户输入
  • 组织这一轮上下文
  • 让模型判断是否要用工具
  • 执行工具调用
  • 把结果继续送回模型
  • 生成最后回复

这个流程如果完全手写,也能做,但会非常散。LangChain 的价值就在于把这一整轮处理过程变成一种稳定的开发方式。

这里要单独区分一下,避免把两种东西混在一起。

前面讲 prompt.pipe(model).pipe(parser) 时,我们说的是普通链路。那种链路里,步骤怎么串、什么时候查工具、什么时候结束,通常都由你自己写清楚。

这里讲 createAgent() 时,说的是 Agent runtime。它和普通链最大的区别是:模型可以在运行过程中决定要不要调用工具、先调用哪个工具、拿到工具结果后是否继续

所以这两种能力不是互相冲突,而是层级不同:

  • 普通链更像你手动安排步骤。
  • Agent 更像运行时自己在模型和工具之间做一轮调度。

8. 第六件事:给单 Agent 应用补上记忆和检索

真实应用里,一个 Agent 很少是完全无状态的。如果用户说:

我是不是以前说过我最怕看牙?

系统不能只看当前这一句话,它得知道过去聊过什么。这时就会出现两类能力:

第一类是短期记忆,也就是对话上下文。 比如最近几轮消息,要不要带进本轮请求里。这是短距离的上下文问题。在最新版本里,这类能力更接近“当前线程里的状态管理”。如果要跨轮次保留下来,通常会和 agent state、checkpointer 这套机制一起使用。

第二类是长期记忆或外部检索。 比如用户几周前说过的偏好、某次事件、某条固定资料。这类信息通常不会原封不动一直塞在当前上下文里,而是需要在用到的时候再取出来,所以它更接近检索问题。

LangChain 在这里负责的是把这些能力和单 Agent 主链路接起来。它不是替你设计记忆系统本身,而是让历史消息、检索结果、外部知识片段都可以作为这一轮输入的一部分,稳定进入 Agent 的处理流程。

所以最好把两件事分开看:

  • 短期记忆:当前线程里的上下文延续。
  • 长期记忆 / 检索:需要时再取回来的信息。

LangChain 在单 Agent 应用里做的,正是这种“胶水工作”:

  • 把模型接起来
  • 把工具接起来
  • 把上下文接起来
  • 把检索结果接起来
  • 再把它们组织成一轮完整的请求处理

9. 总结

到这里为止,LangChain 的位置就比较清楚了。在单 Agent 应用里,它主要负责:

  • 模型接入
  • 输入组织
  • 链路编排
  • 工具接入
  • 一轮请求处理
  • 记忆和检索的接入

也就是说,LangChain 这一层最擅长解决的问题是:怎样把一个单独的 Agent 做成一个真正能工作的应用单元

它不负责多 Agent 的复杂编排。当你需要状态图、条件路由、持久化、人工确认和多 Agent 协作时,就要在 LangChain 之上引入 LangGraph。

一句话总结:LangChain 在单 Agent 里做的是“胶水”——把模型、工具、上下文、检索结果接在一起,并组织成一轮可运行的请求处理。

10. 参考资料

基于 MIT 协议开源