使用 Python + LangChain + Vue3 构建 LLM 聊天应用

使用 Python + LangChain + Vue3 构建 LLM 聊天应用

从零搭建一个支持流式对话的全栈 LLM 应用:FastAPI 后端 + Vue3 前端 + DeepSeek API。

目录


项目结构

复制代码
simple-llm-app/
├── test/                          # 学习 & 实验代码
│   ├── test.py                    # 环境变量 + OpenAI 接口测试
│   ├── server.py                  # FastAPI 路由 / Pydantic / CORS 示例
│   ├── llm-app.py                 # LangChain 链式调用入门
│   ├── llm-app-message.py         # LangChain 消息模板
│   └── prompt-template.py         # PromptTemplate 示例
├── backend/                       # 生产后端
│   ├── server.py                  # API 层:路由 + SSE + CORS + 启动入口
│   ├── llm_app.py                 # 业务层:LLM 封装与流式生成
│   ├── models.py                  # 数据层:Pydantic 模型
│   ├── test.py                    # SSE 流式响应实验脚本
│   └── requirements.txt           # Python 依赖
└── frontend/                      # 聊天窗口前端
    └── src/
        ├── App.vue                # 聊天页面
        ├── style.css              # 全局样式
        ├── types/chat.ts          # 类型定义
        ├── api/chat.ts            # API 请求封装
        └── composables/useChat.ts # 聊天逻辑 Hook

技术栈

层级 技术 说明
后端 Python 3 · FastAPI · LangChain · Uvicorn Web 框架 + LLM 编排 + ASGI 服务器
前端 Vue 3 · TypeScript · Vite 组件化 UI + 类型安全 + 构建工具
模型 DeepSeek API 兼容 OpenAI 接口格式

说明:后端也可替换为 Node.js/Java,但 AI 生态在 Python 侧仍具明显优势


技术栈选择

AI Agent 主流框架

框架 语言 特点 适合场景
LangChain Python/JS 生态最全,组件多 快速原型、学习入门
LlamaIndex Python 专注 RAG 和知识检索 知识库类应用
AutoGen Python 微软出品,多 Agent 对话 多 Agent 协作
CrewAI Python 角色化 Agent 团队 任务分工类场景
LangGraph Python 状态机式 Agent 流程 复杂工作流
Dify Python/低代码 国产,可视化编排 快速交付、企业内部
阿里百炼 / 腾讯元器等 托管平台 国内合规,部署简单 国内商业落地

环境配置

1. 安装 Python

  1. Python 官网 下载安装包
  2. 安装时勾选 Add Python to PATH
  3. 验证安装:
bash 复制代码
python --version
pip --version

2. 配置 API 密钥

  1. DeepSeek 控制台 申请 API Key
  2. 在项目根目录创建 .env 文件:
bash 复制代码
DEEPSEEK_API_KEY=sk-xxxxxx
  1. 安装依赖并验证读取:
bash 复制代码
pip install python-dotenv
python test/test.py

完整示例见 test/test.py

3. 编辑器

推荐 VS Code / Cursor,安装 Python 语言扩展。


学习路径

按以下顺序阅读代码,由浅入深:

复制代码
环境变量 → FastAPI → OpenAI 接口 → LangChain → 后端分层 → 前端聊天页

1. Python 基础

Python 适合 AI 开发的核心原因:

特点 说明
简洁语法 接近自然语言,快速验证想法
丰富生态 TensorFlow、PyTorch、LangChain、Hugging Face 等
动态类型 交互式开发,迭代效率高
胶水语言 底层 C/C++/CUDA 计算 + Python 高层编排

语法速览

python 复制代码
name = "张三"       # 无需声明关键字
AGE = 25           # 全大写表示常量(约定)
is_student = True

# 单行注释用 #,多行用 ''' 或 """

GIL 与并发(与 Web 服务相关)

  • CPU 密集型:GIL 限制多线程并行 → 用多进程或 GPU
  • I/O 密集型 (网络请求、LLM 调用):多线程 / asyncio 仍然有效
  • FastAPI + Uvicorn 的异步模型适合 LLM 推理服务

2. FastAPI 入门

核心概念
组件 职责
FastAPI 路由、验证、序列化、依赖注入
Uvicorn HTTP 解析、并发处理、连接管理(ASGI 服务器)

两者配合才能发挥 FastAPI 的异步性能。

快速示例
bash 复制代码
pip install fastapi uvicorn
python test/server.py

访问 http://127.0.0.1:9528 查看响应,访问 /docs 查看自动生成的 API 文档。

完整代码见 test/server.py,包含:

Pydantic 要点
  • 基于类型注解的运行时数据验证
  • FastAPI 自动生成 OpenAPI 文档(/docs
  • 典型场景:API 请求校验、配置管理、JSON 序列化
CORS

跨域指协议、域名、端口任一不同。后端需配置 CORSMiddleware 允许前端跨域访问,详见 test/server.py


3. LLM 与 OpenAI 接口

DeepSeek 兼容 OpenAI API 格式,使用 openai 库即可对接。

bash 复制代码
pip install openai
python test/test.py
核心代码
python 复制代码
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)

response = client.chat.completions.create(
    model="deepseek-chat",
    temperature=0.5,
    messages=[{"role": "user", "content": "你是谁?"}]
)
print(response.choices[0].message.content)
关键概念
概念 说明 详见
choices 字段 模型返回的候选回复列表 test/test.py 注释
流式响应 stream=True 逐 token 输出,打字机效果 test/test.py
temperature 控制随机性:低=确定性,高=创造性 test/test.py 注释
消息角色 system / user / assistant / tool 见下表
消息角色
角色 用途 示例场景
system 设定助手行为规则 "你是专业翻译,只翻译中英文"
user 用户输入(必填) "什么是机器学习?"
assistant 历史回复,保持多轮连贯 上一轮 AI 的回答
tool / function 工具调用结果 Function Calling 场景

4. LangChain 框架

Java 开发者可选 LangChain4j · 实战指南

LangChain 在 OpenAI 原生接口之上提供链式编排,简化 Prompt → LLM → Parser 流程。

安装 & 运行
bash 复制代码
pip install langchain_openai langchain_core python-dotenv
python test/llm-app.py
LCEL 链式语法
python 复制代码
chain = prompt | llm | parser   # 输入 → 模板填充 → AI 处理 → 解析输出
result = chain.invoke({"question": "你是谁?"})

| 是 LangChain 重载的操作符(语法糖),等价于逐步 invoke

相关文件
文件 内容
test/llm-app.py 最简链式调用
test/llm-app-message.py 消息模板系统
test/prompt-template.py PromptTemplate 用法
消息模板对照
LangChain 类 角色 对应 OpenAI
SystemMessagePromptTemplate system system
HumanMessagePromptTemplate human user
AssistantMessagePromptTemplate assistant assistant
AIMessagePromptTemplate ai assistant
ToolMessagePromptTemplate tool tool

5. 后端实现

采用 单一职责 分层架构:
#mermaid-svg-6dZh1Pb1ZqRemuzf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6dZh1Pb1ZqRemuzf .error-icon{fill:#552222;}#mermaid-svg-6dZh1Pb1ZqRemuzf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6dZh1Pb1ZqRemuzf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .marker.cross{stroke:#333333;}#mermaid-svg-6dZh1Pb1ZqRemuzf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6dZh1Pb1ZqRemuzf p{margin:0;}#mermaid-svg-6dZh1Pb1ZqRemuzf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .cluster-label text{fill:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .cluster-label span{color:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .cluster-label span p{background-color:transparent;}#mermaid-svg-6dZh1Pb1ZqRemuzf .label text,#mermaid-svg-6dZh1Pb1ZqRemuzf span{fill:#333;color:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .node rect,#mermaid-svg-6dZh1Pb1ZqRemuzf .node circle,#mermaid-svg-6dZh1Pb1ZqRemuzf .node ellipse,#mermaid-svg-6dZh1Pb1ZqRemuzf .node polygon,#mermaid-svg-6dZh1Pb1ZqRemuzf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .rough-node .label text,#mermaid-svg-6dZh1Pb1ZqRemuzf .node .label text,#mermaid-svg-6dZh1Pb1ZqRemuzf .image-shape .label,#mermaid-svg-6dZh1Pb1ZqRemuzf .icon-shape .label{text-anchor:middle;}#mermaid-svg-6dZh1Pb1ZqRemuzf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .rough-node .label,#mermaid-svg-6dZh1Pb1ZqRemuzf .node .label,#mermaid-svg-6dZh1Pb1ZqRemuzf .image-shape .label,#mermaid-svg-6dZh1Pb1ZqRemuzf .icon-shape .label{text-align:center;}#mermaid-svg-6dZh1Pb1ZqRemuzf .node.clickable{cursor:pointer;}#mermaid-svg-6dZh1Pb1ZqRemuzf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .arrowheadPath{fill:#333333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6dZh1Pb1ZqRemuzf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6dZh1Pb1ZqRemuzf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6dZh1Pb1ZqRemuzf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6dZh1Pb1ZqRemuzf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .cluster text{fill:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf .cluster span{color:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6dZh1Pb1ZqRemuzf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6dZh1Pb1ZqRemuzf rect.text{fill:none;stroke-width:0;}#mermaid-svg-6dZh1Pb1ZqRemuzf .icon-shape,#mermaid-svg-6dZh1Pb1ZqRemuzf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6dZh1Pb1ZqRemuzf .icon-shape p,#mermaid-svg-6dZh1Pb1ZqRemuzf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6dZh1Pb1ZqRemuzf .icon-shape .label rect,#mermaid-svg-6dZh1Pb1ZqRemuzf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6dZh1Pb1ZqRemuzf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6dZh1Pb1ZqRemuzf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6dZh1Pb1ZqRemuzf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTP POST
前端 Vue3
API 层

backend/server.py
业务层

backend/llm_app.py
DeepSeek API
数据层

backend/models.py

层级 文件 职责
API 层 backend/server.py 路由、SSE 流式响应、CORS、Uvicorn 启动
业务层 backend/llm_app.py LLM 交互、对话历史、流式生成
数据层 backend/models.py ChatRequest / ChatMessage 等 Pydantic 模型
实验脚本 backend/test.py 独立验证 SSE 流式逻辑(开发阶段原型)
依赖 backend/requirements.txt 类似前端的 package.json
SSE 流式协议

大模型逐字生成场景首选 Server-Sent Events (SSE)

特性 SSE WebSocket 长轮询
协议 HTTP 自定义 TCP HTTP
方向 单向(服务器→客户端) 双向 单向
复杂度
适用 LLM 流式输出 实时游戏、协作 旧系统兼容

SSE 事件格式:data: {json}\n\n

backend/server.pychat_stream 接口流程(原型见 backend/test.py):

  1. 发送 start 事件
  2. 逐 token 发送 token 事件
  3. 发送 end 事件(含完整回复)
API 接口
接口 方法 说明
/api/chat/stream POST SSE 流式对话
/api/health GET 健康检查

6. 前端实现

创建项目
bash 复制代码
npm create vite@latest frontend -- --template vue-ts
cd frontend && npm install
功能清单
  • 消息列表(用户 / AI 气泡)
  • 流式打字机效果
  • Enter 发送 · Shift+Enter 换行
  • 清空对话 · 自动滚动 · 在线状态
文件说明
文件 职责
frontend/src/types/chat.ts Message · ChatRequest · SSEEvent 类型
frontend/src/api/chat.ts fetch + ReadableStream 处理 SSE(POST 不支持原生 EventSource)
frontend/src/composables/useChat.ts 消息状态、发送、流式更新、取消请求
frontend/src/App.vue 聊天 UI 组件
frontend/src/style.css 全局样式
SSE 前端处理要点
typescript 复制代码
// EventSource 不支持 POST,故用 fetch + ReadableStream
const reader = response.body?.getReader()
// 按 "\n\n" 分割,解析 "data: {...}" 行
// type: start | token | end | error

完整实现见 frontend/src/api/chat.ts


运行与验证

后端

bash 复制代码
cd backend
pip install -r requirements.txt

# 确保 backend/.env 中已配置 DEEPSEEK_API_KEY
python server.py
# → http://0.0.0.0:8000

前端

bash 复制代码
cd frontend
npm install
npm run dev

浏览器打开 Vite 提示的本地地址,输入问题并发送即可。


请求链路

DeepSeek API LangChain FastAPI Vue3 前端 用户浏览器 DeepSeek API LangChain FastAPI Vue3 前端 用户浏览器 #mermaid-svg-qzlsXzVRZrnJZQQg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qzlsXzVRZrnJZQQg .error-icon{fill:#552222;}#mermaid-svg-qzlsXzVRZrnJZQQg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qzlsXzVRZrnJZQQg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qzlsXzVRZrnJZQQg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qzlsXzVRZrnJZQQg .marker.cross{stroke:#333333;}#mermaid-svg-qzlsXzVRZrnJZQQg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qzlsXzVRZrnJZQQg p{margin:0;}#mermaid-svg-qzlsXzVRZrnJZQQg .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qzlsXzVRZrnJZQQg text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qzlsXzVRZrnJZQQg .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-qzlsXzVRZrnJZQQg .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-qzlsXzVRZrnJZQQg #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-qzlsXzVRZrnJZQQg .sequenceNumber{fill:white;}#mermaid-svg-qzlsXzVRZrnJZQQg #sequencenumber{fill:#333;}#mermaid-svg-qzlsXzVRZrnJZQQg #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-qzlsXzVRZrnJZQQg .messageText{fill:#333;stroke:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qzlsXzVRZrnJZQQg .labelText,#mermaid-svg-qzlsXzVRZrnJZQQg .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .loopText,#mermaid-svg-qzlsXzVRZrnJZQQg .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qzlsXzVRZrnJZQQg .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-qzlsXzVRZrnJZQQg .noteText,#mermaid-svg-qzlsXzVRZrnJZQQg .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-qzlsXzVRZrnJZQQg .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qzlsXzVRZrnJZQQg .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qzlsXzVRZrnJZQQg .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qzlsXzVRZrnJZQQg .actorPopupMenu{position:absolute;}#mermaid-svg-qzlsXzVRZrnJZQQg .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-qzlsXzVRZrnJZQQg .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qzlsXzVRZrnJZQQg .actor-man circle,#mermaid-svg-qzlsXzVRZrnJZQQg line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-qzlsXzVRZrnJZQQg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 逐 token 输入问题,点击发送 POST /api/chat/stream stream_chat(message, history) chat.completions (stream=True) chunk token SSE data: {type: token} 打字机效果更新 SSE data: {type: end} 显示完整回复

一句话:前端 → FastAPI → LangChain → DeepSeek API → 流式返回


拓展阅读

主题 链接
CGI / WSGI / ASGI 对比 掘金文章
FastAPI 官方文档 fastapi.tiangolo.com/zh
FastAPI 源码 github.com/fastapi/fastapi
Uvicorn 文档 uvicorn.org
JS → Python 对照学习 langshift.dev
相关推荐
叫我Paul就好1 小时前
RAG 从入门到精通 - 基础版本
人工智能·软件工程·rag
weixin_397574091 小时前
语义鸿沟是企业AI落地的真正卡点
人工智能
蓝创工坊Blue Foundry1 小时前
本地 PDF、图片字段提取到 Excel:用文档工作台的完整流程
python·ocr·vim·paddlepaddle
硅徒1 小时前
蓝队检测规则编写:从告警噪声里捞出真实攻击的工程方法
人工智能
努力进修1 小时前
破除工业 AI 业务落地壁垒:多模时序融合架构重塑设备全维度数据价值
数据库·人工智能·架构
一路向北North1 小时前
Spring AI(2) :AI应用开发技术架构
人工智能
小白说大模型1 小时前
AI Agent 调试实战:链路追踪、Prompt 可视化与异常定位的系统方法
java·人工智能·python·算法·prompt