LangChain 与单 Agent
要点
- 还是用「AI 电子伴侣」这个场景
- 做 LLM 应用时,最先碰到的问题通常不是 Prompt,而是「模型怎么接」
- 用户说一句话,系统内部并不是原封不动地把这句话直接丢给模型
- 只要不是最简单的 demo,请求处理过程通常都不止一步
- 单纯调用模型时,系统只能「回答」
内容
1. 先从一个具体需求开始
还是用「AI 电子伴侣」这个场景。
现在我们先不讨论多 Agent,只看一个最常见的需求:用户发来一条消息,系统要在一轮请求里完成下面几件事:
- 读懂用户这句话是什么意思
- 带上当前的人设和对话上下文
- 必要时查一下历史记忆
- 如果需要,再调用某个工具
- 最后把结果整理成一段自然回复
比如用户发来:
NOTE
我下周三下午要去看牙医,你帮我记一下。对了,我上次是不是说过我最怕看牙?
要处理好这条消息,系统至少得做这些事:
- 看懂这是一个「提醒 + 记忆确认」的混合请求
- 带上当前这个伴侣 Agent 的人设设定
- 取出最近的对话记录
- 必要时去查长期记忆
- 调用写日程的工具
- 最后生成一段自然的回复
LangChain 在这里负责的,就是把这一整套事情串起来。
所以这一篇不讲抽象定义,只讲一个很实际的问题:
当我们做一个单 Agent 应用时,LangChain 到底替我们处理了哪些工作。
2. 第一件事:把模型接进应用
做 LLM 应用时,最先碰到的问题通常不是 Prompt,而是「模型怎么接」。
如果不用框架,直接调用模型接口,你很快就会遇到这些细节:
- 不同厂商的 SDK 不一样
- 请求格式不一样
- 返回结果结构不一样
- 流式返回的处理方式也不一样
LangChain 先帮我们把这件事统一了。
在单 Agent 场景里,你最常做的一步就是给 Agent 指定一个模型:
// index.ts
import { createAgent } from 'langchain'
const agent = createAgent({
model: 'openai:gpt-4.1-mini',
})如果你想自己显式创建模型对象,也可以:
// index.ts
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、上下文、记忆,才有地方接进去。
在我们的 AI 伴侣场景里,这一步可以理解成:先把「会说话的大脑」接进来。
3. 第二件事:把输入整理成模型能理解的结构
用户说一句话,系统内部并不是原封不动地把这句话直接丢给模型。
真正送进模型之前,往往还要拼很多东西:
- 当前这轮用户输入
- 系统设定
- 角色背景
- 最近对话历史
- 工具说明
- 外部检索结果
这一层工作,如果手写字符串,也不是不能做,但很快就会乱。
LangChain 在这里负责两类事情:
第一类:消息结构。
聊天模型内部不是只吃一段字符串,而是吃一串有角色的消息。比如:
- system
- user
- assistant
- tool
LangChain 把这些消息组织方式统一起来,这样你在不同模型之间切换时,不用重新设计输入结构。
第二类:Prompt 组织。
Prompt 在项目里不是一句临时文案,而是一个长期维护的输入模板。你会逐步把不同来源的信息填进去,最后形成这一轮请求真正使用的上下文。
在 AI 伴侣场景里,这一步通常包括:
- 固定人设
- 当前情绪设定
- 最近聊天记录
- 用户这次发来的问题
所以从应用层看,LangChain 并不是只负责「调模型」,它还负责把输入整理成可维护的结构。
4. 第三件事:把多个步骤串成一条链
只要不是最简单的 demo,请求处理过程通常都不止一步。
还是刚才那条「下周三看牙」的消息,系统内部很可能会这样走:
- 先整理输入
- 判断是否需要查记忆
- 查询记忆
- 调用提醒工具
- 生成最终回复
如果这些步骤完全散落在普通函数里,代码会越来越像「拼装式脚本」。前一个函数的输出怎么交给下一个函数,哪个阶段失败了,哪里要改,都不够直观。
LangChain 在这里提供的是一套链路组织方式。
你可以把它理解成:把一堆零散动作,整理成一条明确的数据流。
最简单的链可能只有三步:
// index.ts
const chain = prompt.pipe(model).pipe(parser)复杂一点时,这条链里还会加入:
- 历史消息注入
- 检索结果补充
- 工具调用
- 输出解析
在单 Agent 应用里,这件事很重要。因为随着功能一点点加上去,你最先需要的不是更高级的智能,而是更稳定的组织方式。
5. 第四件事:把外部能力接成工具
单纯调用模型时,系统只能「回答」。
一旦接入工具,系统才真正开始「做事」。
在 AI 伴侣场景里,常见工具包括:
- 查询长期记忆
- 写入提醒事项
- 查询天气
- 调用搜索接口
LangChain 在这里负责的是,把这些外部能力接成模型能调用的工具。
比如一个写提醒工具:
// index.ts
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 才有机会在一次请求里决定:
- 现在需不需要创建提醒
- 传什么参数给提醒工具
- 拿到工具结果后,怎么继续回复用户
6. 第五件事:让一个 Agent 处理完整的一轮请求
把模型、输入结构、链路、工具都准备好后,LangChain 最终做的事就是:
把这些东西合成一个能真正接任务的 Agent。
这一层在代码里就体现为 createAgent()。
// index.ts
import { createAgent } from 'langchain'
const agent = createAgent({
model: 'openai:gpt-4.1-mini',
tools: [createReminder, searchMemory],
systemPrompt: '你是一个自然、克制、会照顾用户情绪的陪伴型助手。',
})这个 Agent 建好后,一轮请求就能完整跑起来:
// index.ts
const result = await agent.invoke({
messages: [
{
role: 'user',
content: '帮我记一下下周三下午两点去看牙医,再告诉我我是不是以前提过怕看牙。',
},
],
})这一步里,LangChain 承担的是一个很实际的角色:
- 接住用户输入
- 组织这一轮上下文
- 让模型判断是否要用工具
- 执行工具调用
- 把结果继续送回模型
- 生成最后回复
这个流程如果完全手写,也能做,但会非常散。
LangChain 的价值就在于把这一整轮处理过程变成一种稳定的开发方式。
这里要单独提醒一下,避免把两种东西混在一起。
前面讲 prompt.pipe(model).pipe(parser) 时,我们说的是普通链路。那种链路里,步骤怎么串、什么时候查工具、什么时候结束,通常都由你自己写清楚。
这里讲 createAgent() 时,说的是 agent runtime。它和普通链最大的区别在于:模型可以在运行过程中决定要不要调用工具、先调用哪个工具、拿到工具结果后是否继续。
所以这两种能力不是互相冲突,而是层级不同:
- 普通链更像你手动安排步骤
- Agent 更像运行时自己在模型和工具之间做一轮调度
下图可以把这件事看得更清楚一些:
Drawing canvas 图里从左到右就是一轮常见请求:用户消息进入后,LangChain 先组织上下文,再把模型、工具、记忆这些能力接到同一条链路里,最后输出回复。
7. 第六件事:给单 Agent 应用补上记忆和检索
真实应用里,一个 Agent 很少是完全无状态的。
还是 AI 伴侣这个场景。如果用户说:
NOTE
我是不是以前说过我最怕看牙?
系统不能只看当前这一句话,它得知道过去聊过什么。
这时就会出现两类能力:
第一类是短期记忆,也就是对话上下文。
比如最近几轮消息,要不要带进本轮请求里。
这是短距离的上下文问题。
在最新版本里,这类能力更接近「当前线程里的状态管理」。
如果要跨轮次保留下来,通常会和 agent state、checkpointer 这套机制一起使用。
第二类是长期记忆或外部检索。
比如用户几周前说过的偏好、某次事件、某条固定资料。
这类信息通常不会原封不动一直塞在当前上下文里,而是需要在用到的时候再取出来,所以它更接近检索问题。
LangChain 在这里负责的是把这些能力和单 Agent 主链路接起来。
它不是替你设计记忆系统本身,而是让:
- 历史消息
- 检索结果
- 外部知识片段
都可以作为这一轮输入的一部分,稳定进入 Agent 的处理流程。
所以这里最好把两件事分开看:
- 短期记忆:当前线程里的上下文延续
- 长期记忆 / 检索:需要时再取回来的信息
所以很多时候,LangChain 在单 Agent 应用里做的,正是这种「胶水工作」:
- 把模型接起来
- 把工具接起来
- 把上下文接起来
- 把检索结果接起来
- 再把它们组织成一轮完整的请求处理
8. 总结
到这里为止,LangChain 的位置就比较清楚了
在单 Agent 应用里,它主要负责的是:
- 模型接入
- 输入组织
- 链路编排
- 工具接入
- 一轮请求处理
- 记忆和检索的接入
也就是说,LangChain 这一层最擅长解决的问题是:
怎样把一个单独的 Agent 做成一个真正能工作的应用单元