主题
LangChain 与单 Agent
1. 从一个真实场景开始
你有没有直接调用过模型 API,然后发现一件小事就要写很多样板代码?
不同厂商的 SDK 格式不一样,返回结构不一样,流式处理也不一样。等你终于把模型接通了,又发现真正麻烦的是后面的事:怎么把用户输入、系统人设、历史对话、外部检索结果和工具说明拼成一次完整请求?步骤多了之后,代码越来越像“拼装脚本”。
来看一个具体例子。用户发来:
我下周三下午要去看牙医,你帮我记一下。对了,我上次是不是说过我最怕看牙?
要处理好这条消息,系统至少得做:
- 识别这是一个“提醒 + 记忆确认”的混合请求。
- 带上当前 Agent 的人设设定。
- 取出最近的对话记录。
- 必要时去查长期记忆。
- 调用写日程的工具。
- 最后生成一段自然的回复。
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 在这里负责两类事情。
第一类:消息结构。 聊天模型内部不是只吃一段字符串,而是吃一串有角色的消息,比如 system、user、assistant、tool。LangChain 把这些消息组织方式统一起来,这样你在不同模型之间切换时,不用重新设计输入结构。
第二类:Prompt 组织。 Prompt 在项目里不是一句临时文案,而是一个长期维护的输入模板。你会逐步把不同来源的信息填进去,最后形成这一轮请求真正使用的上下文。通常包括:
- 固定人设
- 当前任务说明
- 最近聊天记录
- 用户这次发来的问题
所以从应用层看,LangChain 不只是“调模型”,它还负责把输入整理成可维护的结构。
5. 第三件事:把多个步骤串成一条链
只要不是最简单的 demo,请求处理过程通常都不止一步。还是刚才那条消息,系统内部很可能会这样走:
- 先整理输入
- 判断是否需要查记忆
- 查询记忆
- 调用提醒工具
- 生成最终回复
如果这些步骤完全散落在普通函数里,代码会越来越像“拼装式脚本”。前一个函数的输出怎么交给下一个函数,哪个阶段失败了,哪里要改,都不够直观。
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. 参考资料
- LangChain. LangChain Agents 概念,https://js.langchain.com/docs/concepts/agents/
- LangChain. LangGraph 文档,https://langchain.com/docs/langgraph
- LangChain. LangChain 官方文档,https://langchain.com/docs