本文档列出项目用到的所有第三方库,说明每个库的作用、使用场景,以及在本项目中具体用到了哪些 API。
一、后端依赖(server/package.json)
1. express ^4.19.2
Node.js 最流行的 Web 框架,提供路由、中间件、请求/响应处理能力。
本项目用途
- 创建 HTTP 服务,监听 3000 端口
- 注册四个功能路由:
/api/chat、/api/agent、/api/rag、/api/graph - 处理 POST 请求的 JSON 请求体(配合
express.json()中间件) - 实现 SSE(Server-Sent Events)流式响应,通过
res.write()逐块推送数据
用到的 API
import express from 'express';
const app = express();
const router = express.Router();
app.use(express.json()); // 解析请求体
app.use('/api/chat', chatRouter); // 注册路由
app.listen(3000, callback); // 启动服务
router.post('/stream', handler); // 定义路由处理函数
res.setHeader('Content-Type', 'text/event-stream'); // SSE 响应头
res.write(`data: ${data}\n\n`); // 流式推送数据
res.end(); // 结束响应
2. cors ^2.8.5
处理跨域资源共享(CORS)问题。浏览器出于安全策略,默认禁止前端页面向不同域名的服务器发请求。前端运行在 localhost:5173,后端在 localhost:3000,端口不同属于跨域。
本项目用途
- 允许前端 Vue3 应用访问后端 API,开发阶段不限制来源
用到的 API
import cors from 'cors';
app.use(cors()); // 允许所有来源(开发阶段)
// 生产环境应限制来源:
app.use(cors({ origin: 'https://yourdomain.com' }));
3. dotenv ^16.4.5
从 .env 文件读取环境变量并注入到 process.env,避免把 API Key、数据库密码等敏感信息硬编码在代码里。
本项目用途
- 加载
DEEPSEEK_API_KEY、ZHIPU_API_KEY、PG_HOST等所有配置项
用到的 API
import 'dotenv/config'; // ES Module 写法,导入即自动加载 .env
// 之后任意地方可以读取
process.env.DEEPSEEK_API_KEY
process.env.PG_HOST
4. pg ^8.12.0
Node.js 的 PostgreSQL 客户端库(node-postgres),提供连接池和 SQL 查询能力。
本项目用途
- 创建 PostgreSQL 连接池,供 pgvector 向量存储模块使用
- pgvector 存储向量数据时底层调用
pool执行 SQL
用到的 API
import pg from 'pg';
const { Pool } = pg;
export const pool = new Pool({
host: process.env.PG_HOST,
port: parseInt(process.env.PG_PORT),
user: process.env.PG_USER,
password: process.env.PG_PASSWORD,
database: process.env.PG_DATABASE,
});
// Pool 会自动管理连接,空闲时归还,高并发时排队
// PGVectorStore 直接接收 pool 实例,内部调用 pool.query() 执行 SQL
5. zod ^3.23.8
TypeScript 优先的数据结构验证和类型推导库。在 LangChain.js 的 Tool 定义中用于描述工具的参数 Schema,LangChain 会把 Schema 转成 JSON Schema 格式告诉 LLM,让模型知道调用工具时该传什么参数。
本项目用途
- 定义订单查询工具、物流查询工具、用户订单查询工具的参数结构
用到的 API
import { z } from 'zod';
// 定义工具参数 schema
const schema = z.object({
orderId: z.string().describe('订单号,格式为 ORD-xxx,例如 ORD-001'),
});
// z.object() 定义对象结构
// z.string() 字符串类型
// z.number() 数字类型
// .describe() 为字段添加描述,LLM 依靠这段文字理解该传什么值
// z.optional() 可选字段
二、LangChain 生态库
LangChain 拆分为多个 npm 包,各司其职,按需安装。
6. @langchain/core ^0.3.0
LangChain 的核心基础包,定义所有抽象接口和基础类型,其他包都依赖它。不包含任何具体实现,只有接口和工具类。
本项目用到的模块
**@langchain/core/prompts**— Prompt 模板
import { ChatPromptTemplate } from '@langchain/core/prompts';
// fromMessages 定义多角色消息模板
const prompt = ChatPromptTemplate.fromMessages([
['system', '你是客服助手...{current_time}'], // 系统消息,定义角色
['placeholder', '{chat_history}'], // 占位符,插入历史消息数组
['human', '{user_input}'], // 用户消息
]);
// invoke 时传入变量替换占位符
await prompt.invoke({
current_time: '2025-03-26',
chat_history: [...],
user_input: '我的订单在哪里',
});
**@langchain/core/output_parsers**— 输出解析器
import { StringOutputParser } from '@langchain/core/output_parsers';
// LLM 返回的是 AIMessage 对象,StringOutputParser 提取其中的文本内容
const parser = new StringOutputParser();
// 在 LCEL 管道末尾使用:
const chain = prompt | model | parser;
// 最终 invoke 返回字符串,而不是 AIMessage 对象
**@langchain/core/runnables**— 可运行单元
import { RunnableSequence, RunnablePassthrough } from '@langchain/core/runnables';
// RunnableSequence.from([...]) 把多个步骤串联成一个链
// 等价于 LCEL 的 a | b | c 语法,更适合复杂 RAG 流程
const chain = RunnableSequence.from([
{ context: retriever.pipe(formatDocs), question: new RunnablePassthrough() },
prompt,
model,
parser,
]);
// RunnablePassthrough 把输入原封不动传递到下一步
// 在 RAG 中用于把用户问题同时传给检索器和最终 Prompt
**@langchain/core/messages**— 消息类型
import { HumanMessage } from '@langchain/core/messages';
// 把字符串包装成 LangChain 的消息对象
// LangGraph 的 state.messages 要求使用 Message 对象
new HumanMessage('用户输入的文字');
// 其他类型:AIMessage(AI 回复)、SystemMessage(系统消息)
**@langchain/core/documents**— 文档类型
import { Document } from '@langchain/core/documents';
// 向量化之前,文本需要包装成 Document 对象
new Document({
pageContent: '文档内容',
metadata: { source: 'products.md' }, // 可存任意元数据,检索后可引用
});
**@langchain/core/tools**— 工具定义
import { tool } from '@langchain/core/tools';
// 定义一个可被 Agent 调用的工具
export const getOrderInfoTool = tool(
async ({ orderId }) => { // 执行函数
return JSON.stringify(result);
},
{
name: 'getOrderInfo', // 工具名,LLM 用这个名字调用
description: '查询订单详情...', // 工具描述,影响 LLM 是否选择这个工具
schema: z.object({ ... }), // 参数结构
}
);
7. @langchain/openai ^0.3.0
LangChain 的 OpenAI 集成包。DeepSeek 和智谱 AI 都兼容 OpenAI 的 API 协议,所以本项目用这个包对接所有模型,只需替换 baseURL 和 apiKey。
本项目用到的类
**ChatOpenAI**— 对话模型
import { ChatOpenAI } from '@langchain/openai';
const model = new ChatOpenAI({
modelName: 'deepseek-chat',
openAIApiKey: process.env.DEEPSEEK_API_KEY,
configuration: {
baseURL: 'https://api.deepseek.com/v1', // 替换为 DeepSeek 地址
},
temperature: 0.7,
streaming: false,
});
// invoke 发送消息,返回 AIMessage
const response = await model.invoke([new HumanMessage('你好')]);
// stream 流式调用,返回 AsyncIterable
for await (const chunk of await model.stream(messages)) {
process.stdout.write(chunk.content);
}
**OpenAIEmbeddings**— 向量化模型
import { OpenAIEmbeddings } from '@langchain/openai';
const embeddings = new OpenAIEmbeddings({
modelName: 'embedding-3', // 智谱 AI 的 Embedding 模型
openAIApiKey: process.env.ZHIPU_API_KEY,
configuration: {
baseURL: 'https://open.bigmodel.cn/api/paas/v4',
},
});
// embedQuery 把一段文字转成向量(数字数组)
const vector = await embeddings.embedQuery('蓝牙耳机多少钱');
// 返回类似 [0.12, -0.34, 0.87, ...] 的 1536 维向量
// embedDocuments 批量转换,入库时使用
const vectors = await embeddings.embedDocuments(['文档1', '文档2']);
8. @langchain/community ^0.3.0
LangChain 的社区集成包,包含大量第三方工具和数据库的集成实现,官方核心包以外的内容都在这里。
本项目用到的模块
**PGVectorStore**— PostgreSQL 向量存储
import { PGVectorStore } from '@langchain/community/vectorstores/pgvector';
// 入库:把文档切片向量化并存入 PostgreSQL
await PGVectorStore.fromDocuments(chunks, embeddings, {
pool,
tableName: 'knowledge_embeddings',
columns: {
idColumnName: 'id',
vectorColumnName: 'embedding', // 存向量的列
contentColumnName: 'content', // 存原始文本的列
metadataColumnName: 'metadata', // 存元数据的列(来源文件名等)
},
});
// 查询:初始化并创建检索器
const vectorStore = await PGVectorStore.initialize(embeddings, config);
const retriever = vectorStore.asRetriever({ k: 4 }); // 每次返回最相似的 4 条
// 检索器的工作原理:
// 1. 把用户问题用同一个 Embedding 模型转成向量
// 2. 在数据库里用余弦相似度找最近的 k 条向量
// 3. 返回对应的文档片段
9. langchain ^0.3.0
LangChain 主包,包含 Agent、文本切分等高级功能。
本项目用到的模块
**createReactAgent**+ **AgentExecutor** — ReAct Agent
import { createReactAgent, AgentExecutor } from 'langchain/agents';
// createReactAgent 把 LLM + 工具 + Prompt 组装成 Agent
const agent = createReactAgent({
llm: model, // 使用的语言模型
tools: allTools, // 可以调用的工具列表
prompt: agentPrompt,
});
// AgentExecutor 负责运行 Agent 的思考循环
// Thought → Action → Observation → Thought → ... → Final Answer
const executor = new AgentExecutor({
agent,
tools: allTools,
maxIterations: 5, // 最多循环 5 次防止死循环
returnIntermediateSteps: true, // 返回每步的工具调用记录
verbose: true, // 终端打印推理过程,调试用
});
const result = await executor.invoke({ input: '查询订单 ORD-001' });
result.output // 最终回答
result.intermediateSteps // 每步的 tool / toolInput / observation
**RecursiveCharacterTextSplitter**— 文档切分
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 500, // 每个切片最多 500 个字符
chunkOverlap: 50, // 相邻切片重叠 50 个字符,防止语义在边界处断裂
});
// 传入 Document 数组,返回切分后的 Document 数组
const chunks = await splitter.splitDocuments(docs);
// 切分策略(按优先级尝试分隔符):
// 1. 段落(\n\n)
// 2. 换行(\n)
// 3. 句号
// 4. 空格
// 5. 单个字符
// 优先在自然边界切分,保留语义完整性
10. @langchain/langgraph ^0.2.0
LangGraph 是 LangChain 生态里专门用于构建有状态、多步骤、可分支工作流的库,把 AI 工作流建模成有向图。
本项目用到的 API
**StateGraph**— 图结构
import { StateGraph, START, END } from '@langchain/langgraph';
const graph = new StateGraph(GraphState)
.addNode('intentRouter', intentRouterNode) // 注册节点(普通 async 函数)
.addNode('orderAgent', orderAgentNode)
.addEdge(START, 'intentRouter') // 固定边:入口 → 意图识别
.addConditionalEdges( // 条件边:根据状态值分流
'intentRouter',
routeByIntent, // 路由函数,返回下一个节点名
{
orderAgent: 'orderAgent', // 路由函数返回 'orderAgent' → 走这条边
ragNode: 'ragNode',
generalChat: 'generalChat',
}
)
.addEdge('orderAgent', 'answerSynthesizer') // 所有路径汇合
.addEdge('answerSynthesizer', END); // 出口
const compiled = graph.compile(); // 编译,生成可执行图
// 流式执行,每个节点完成后推送一次更新
const stream = await compiled.stream(
{ userInput: '查询订单', messages: [...] },
{ streamMode: 'updates' } // updates 模式:每步只推送变化的字段
);
for await (const update of stream) {
const [nodeName, nodeState] = Object.entries(update)[0];
// nodeName: 刚执行完的节点名
// nodeState: 该节点写入的字段
}
**Annotation**+ **MessagesAnnotation** — 状态定义
import { Annotation, MessagesAnnotation } from '@langchain/langgraph';
export const GraphState = Annotation.Root({
...MessagesAnnotation.spec, // 内置消息列表管理,自动处理消息追加
intent: Annotation({
reducer: (_, next) => next, // reducer 定义更新策略:直接替换
default: () => '', // 初始值
}),
orderResult: Annotation({
reducer: (_, next) => next,
default: () => null,
}),
});
// 每个节点是普通 async 函数,接收完整 State,返回要更新的字段
const myNode = async (state) => {
const { userInput } = state; // 读取已有字段
return { intent: 'order' }; // 只返回需要更新的字段
};
11. nodemon ^3.1.4(devDependency)
开发阶段的文件监听工具,监听 src/ 目录下的文件变化,有改动时自动重启 Node.js 服务,省去手动停止再启动的操作。
本项目用途
pnpm dev实际执行的是nodemon src/index.js- 修改任何后端代码后自动重启,不需要手动操作
仅在开发时使用,生产部署时用 **pnpm start**(直接 node 命令)
三、前端依赖(client/package.json)
12. vue ^3.4.0
Vue 3 前端框架,本项目用 Composition API 风格开发。
本项目用到的 API
import { ref, nextTick } from 'vue';
// ref 创建响应式变量,修改后视图自动更新
const messages = ref([]);
const streaming = ref(false);
// nextTick 在 DOM 更新完成后执行回调
// 用于消息发送后滚动到底部(需等 DOM 渲染新消息后再滚动)
await nextTick();
messagesRef.value.scrollTop = messagesRef.value.scrollHeight;
13. vue-router ^4.3.0
Vue 3 官方路由库,管理前端页面导航,实现单页应用(SPA)的多页面切换,不需要刷新整个页面。
本项目用到的 API
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(), // HTML5 History 模式,URL 不带 #
routes: [
{ path: '/', component: ChatView },
{ path: '/agent', component: AgentView },
{ path: '/rag', component: RagView },
{ path: '/graph', component: GraphView },
],
});
// 在模板中使用
// <router-link to="/agent">订单查询</router-link> 导航链接
// <router-view /> 渲染当前路由对应的组件
// router-link-active 当前路由匹配时自动添加的 CSS 类
14. vite ^5.0.0(devDependency)
前端构建工具,开发时提供极快的热更新服务器,生产时打包成静态文件。
本项目用途
pnpm dev启动开发服务器,端口 5173,修改.vue文件后浏览器自动更新- 处理 Vue SFC(Single File Component)的编译
- 生产打包:
pnpm build输出到dist/目录
15. @vitejs/plugin-vue ^5.0.0(devDependency)
Vite 的 Vue 3 插件,让 Vite 能够理解和编译 .vue 文件(SFC 格式,包含 <template>/<script>/<style> 三段式结构)。
配置
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()], // 注册插件,Vite 处理 .vue 文件时调用
});
四、各库的依赖关系
项目代码
│
├── express ──────────────── HTTP 服务框架
│ └── cors 跨域中间件
│
├── dotenv ───────────────── 环境变量加载
│
├── pg ───────────────────── PostgreSQL 连接
│
├── zod ──────────────────── 工具参数 Schema 校验
│
└── LangChain 生态
│
├── @langchain/core ──────── 抽象接口层(被所有 LC 包依赖)
│ ├── prompts Prompt 模板
│ ├── output_parsers 输出解析
│ ├── runnables LCEL 管道
│ ├── messages 消息类型
│ ├── documents 文档类型
│ └── tools 工具定义
│
├── @langchain/openai ────── 模型接入
│ ├── ChatOpenAI 对话模型(DeepSeek/通用)
│ └── OpenAIEmbeddings 向量化模型(智谱/百炼)
│
├── @langchain/community ─── 第三方集成
│ └── PGVectorStore pgvector 向量存储
│
├── langchain ────────────── 高级功能
│ ├── createReactAgent ReAct Agent 构建
│ ├── AgentExecutor Agent 执行器
│ └── RecursiveCharacterTextSplitter 文档切分
│
└── @langchain/langgraph ─── 有状态工作流
├── StateGraph 图结构
├── Annotation 状态定义
└── MessagesAnnotation 消息状态管理
五、包体积与安装说明
pnpm install 执行后,实际安装的包远不止上面列出的,因为每个包还有自己的依赖(间接依赖)。以下是主要包的间接依赖说明:
| 包名 | 主要间接依赖 | 说明 |
|---|---|---|
@langchain/openai |
openai官方 SDK |
底层调用 OpenAI 兼容接口 |
@langchain/community |
@pinecone-database/pinecone等 |
按需加载,不影响包体积 |
@langchain/langgraph |
@langchain/core |
核心依赖 |
express |
body-parser、 path-to-regexp等 |
路由和请求处理 |
pg |
pg-pool、 pg-protocol等 |
连接池和协议实现 |
pnpm 使用硬链接和符号链接存储包,多个项目共享同一份依赖,磁盘占用比 npm 小很多。