AI全栈之旅 · 第一周总结

前言

你有没有过这种感觉:看了无数教程,收藏了上百个"必学路线图",但真正动手时却不知从何下手?

我就是这样。直到一周前,我给自己定了一个小目标:不管结果如何,先亲手做出一个能用的AI应用。

于是有了这篇周报。它不仅记录了我的学习轨迹,更是一个普通开发者从0到1的真实写照。


项目概况

项目名称: ​ AI流式对话助手

技术栈:

复制代码
纯文本
后端:Python 3.10 + FastAPI + SQLAlchemy + SQLite + DeepSeek API
前端:Vue 3 + TypeScript + Vite + Marked(Markdown渲染)
工具:Git + GitHub + Postman + NVM + pnpm
源码:[[week1](https://github.com/qishuixian/ai-fullstack-journey/tree/main/week1)]

已完成功能:

  • ✅ 流式输出(打字机效果)
  • ✅ 停止生成 / 清空对话
  • ✅ 消息时间显示(年月日时分)
  • ✅ localStorage本地持久化
  • ✅ Markdown渲染(代码块、列表等)
  • ✅ SQLite数据库永久存储

Day1-3:环境配置与API调用(痛苦但必要)

虚拟环境:第一个拦路虎

第一天就给了我一个下马威。Python虚拟环境这个概念对我来说完全是陌生的。

踩坑记录:

复制代码
bash
# 错误做法:直接在全局环境安装
pip install fastapi uvicorn openai

# 正确做法:先创建虚拟环境
python -m venv venv
.\venv\Scripts\Activate  # Windows
pip install fastapi uvicorn openai python-dotenv

为什么需要虚拟环境?

  • 每个项目可以有独立的依赖版本
  • 不会污染全局Python环境
  • 便于项目迁移和部署

API调用:模型名称的陷阱

当我终于写好了第一个接口,满心欢喜地测试时,迎接我的是冰冷的500错误。

复制代码
json
{
  "detail": "Error code: 400 - {'error': {'message': 'The supported API model names are deepseek-v4-pro or deepseek-v4-flash, but you passed deepseek-chat.'}}"
}

教训: ​ AI模型更新太快,教程里的deepseek-chat早已废弃。从此我养成了一个习惯:遇到API报错,先去查官方文档确认最新参数。

环境变量管理

使用.env文件管理API Key是个好习惯,但初学者容易犯的错误:

  • 等号两边不能有空格:KEY=value ✅,KEY = value
  • 变量名要跟代码里os.getenv()的参数完全一致
  • .env文件要添加到.gitignore,避免泄露密钥

Day4:前端项目搭建(从零到有)

选择Vite的理由

相比Webpack,Vite的开发服务器启动速度快了不止一个量级。对于频繁调试的前端开发来说,这简直是福音。

复制代码
bash
npm create vite@latest frontend --template vue-ts
cd frontend
npm install
npm run dev

Node版本兼容问题

一开始我用Node 18创建项目,结果create-vite报错。后来通过NVM安装了Node 20 LTS才解决问题。

复制代码
bash
nvm install 20
nvm use 20
nvm alias default 20

小贴士: ​ 推荐使用Node 20 LTS,兼容性最好,生态最成熟。


Day5:流式输出(高光时刻)

什么是SSE?

SSE(Server-Sent Events)是一种服务器向客户端推送数据的技术。与WebSocket不同,它是单向的(服务器→客户端),非常适合AI流式回复的场景。

后端核心代码:

复制代码
python
async def generate():
    for chunk in stream:
        if chunk.choices[0].delta.content is not None:
            content = chunk.choices[0].delta.content
            yield f"data: {json.dumps({'content': content})}\n\n"
    yield "data: [DONE]\n\n"

return StreamingResponse(generate(), media_type="text/event-stream")

前端核心代码:

复制代码
javascript
const reader = response.body.getReader()
const decoder = new TextDecoder()

while (true) {
  const { done, value } = await reader.read()
  if (done) break
  
  const chunk = decoder.decode(value, { stream: true })
  // 解析SSE数据,更新UI
}

跨域问题(CORS)

前后端分离架构下,跨域是绕不开的坎。我的解决方案是Vite代理

复制代码
typescript
// vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://127.0.0.1:8000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^/api/, '')
      }
    }
  }
})

这样前端请求/api/chat/stream,Vite会自动转发到后端8000端口,浏览器以为是同源请求,完美绕过CORS。

异步生成器的坑

最初我天真地写了async def generate(),结果报错连连。原因是openai库的流式响应是同步迭代器,不能在异步生成器里直接用for循环。

解决方案: ​ 改为同步生成器def generate()


Day6:体验优化(打磨细节)

消息时间显示

给每条消息加上时间戳,让对话更有真实感。

复制代码
typescript
function nowTime(): string {
  const d = new Date()
  const h = d.getHours().toString().padStart(2, '0')
  const m = d.getMinutes().toString().padStart(2, '0')
  return `${h}:${m}`
}

localStorage持久化

watch监听messages的变化,自动保存到本地存储。

复制代码
typescript
watch(messages, (newVal) => {
  localStorage.setItem('chat', JSON.stringify(newVal))
}, { deep: true })

Markdown渲染

安装marked库,让AI回复中的代码块、列表能正确显示。

复制代码
bash
pnpm add marked

typescript
import { marked } from 'marked'
const html = marked.parse(fullReply)

停止生成的实现

AbortController控制fetch请求的中断,这个设计模式在很多场景下都适用。

复制代码
typescript
const controller = new AbortController()

// 发送请求时绑定signal
fetch(url, { signal: controller.signal })

// 点击停止时中断
controller.abort()

注意: ​ 中断后要在catch中处理AbortError,保留已输出的内容。


Day7:数据库持久化(质的飞跃)

为什么需要数据库?

之前的数据存在localStorage里,换个设备或清缓存就没了。引入数据库后,数据真正做到了"永久存储"。

SQLAlchemy ORM入门

ORM(对象关系映射)让你用Python对象操作数据库,不用写SQL语句。

复制代码
python
class ChatMessage(Base):
    __tablename__ = "chat_messages"
    
    id = Column(Integer, primary_key=True)
    role = Column(String(10))
    content = Column(Text)
    session_id = Column(String(36))
    created_at = Column(DateTime, default=datetime.now)

安装依赖的教训

复制代码
纯文本
ModuleNotFoundError: No module named 'sqlalchemy'

这个错误困扰了我很久。原因是包安装到了全局环境,而不是虚拟环境

正确姿势:

复制代码
bash
# 先激活虚拟环境
.\venv\Scripts\Activate

# 再安装
pip install sqlalchemy aiosqlite

数据库写入时机

流式接口中,数据库写入要放在流结束后、发送[DONE]之前。

复制代码
python
async def generate():
    full_reply = ""
    for chunk in stream:
        if chunk.choices[0].delta.content:
            content = chunk.choices[0].delta.content
            full_reply += content
            yield f"data: {json.dumps({'content': content})}\n\n"
    
    # 流结束后写入数据库
    async with async_session() as session:
        session.add(ChatMessage(role="user", content=request.message))
        session.add(ChatMessage(role="assistant", content=full_reply))
        await session.commit()
    
    yield "data: [DONE]\n\n"

遇到的坑 & 解决方案(完整版)

问题 原因 解决方式 花费时间
500 Internal Server Error 模型名称错误 改为deepseek-v4-flash 2小时
CORS跨域报错 前后端端口不同 配置Vite代理 1小时
流式输出不逐字 异步生成器与同步迭代器混用 改为同步生成器 3小时
点击停止后出现空白AI气泡 AbortError未正确处理 在catch中保存已收到的内容 1小时
ModuleNotFoundError: sqlalchemy 包安装到了全局环境 在虚拟环境中重新安装 30分钟
点击发送出现两个AI消息 事件冒泡导致重复调用 添加.stop修饰符 30分钟
清空对话后残留空白消息 状态未完全重置 同时重置controller和isLoading 20分钟

技术成长与认知升级

1. 从"复制代码"到"理解原理"

初期我习惯于直接复制AI生成的代码,结果出了问题完全不知道从哪里排查。后来我强迫自己:

  • 每段代码至少读三遍
  • 不理解的地方先查文档再问AI
  • 亲手敲一遍,而不是复制粘贴

2. 调试能力的提升

以前看到报错就慌,现在学会了:

  • 先看错误类型和堆栈信息
  • 定位到具体的文件和行号
  • console.logprint输出中间变量
  • 查阅官方文档或搜索引擎

3. 工程化思维的建立

从一个简单的脚本到一个完整的项目,需要考虑:

  • 目录结构如何组织
  • 环境变量如何管理
  • 错误如何处理
  • 代码如何提交和版本控制

下周计划

  • Day8-9:深入学习FastAPI高级特性(依赖注入、中间件、WebSocket)
  • Day10-11:前端UI框架集成(Element Plus或Naive UI)
  • Day12-13:多会话支持(用户可以创建多个对话)
  • Day14:部署上线(Docker + 云服务器)

写在最后

这一周,我从一个只会写简单脚本的初学者,成长为能独立搭建前后端分离AI应用的开发者。

虽然过程中充满了挫折和困惑,但每当解决一个问题,那种成就感是无法言喻的。

送给正在学习的你:

  • 不要害怕犯错,每个错误都是进步的阶梯
  • 不要追求完美,先完成再优化
  • 不要闭门造车,多写博客多交流

如果你也在学习AI全栈开发,欢迎在评论区留言交流。让我们一起成长,共同进步!

如果你也在学习AI全栈开发,欢迎在评论区留言交流。让我们一起成长,共同进步!


如果你对我的项目感兴趣,欢迎访问GitHub仓库:[ai-fullstack-journey](https://github.com/qishuixian/ai-fullstack-journey)

相关推荐
slacker-kian15 分钟前
HuggingFace API加载模型超时:用 ModelScopeAPI 替代
人工智能·python·transformer·huggingface·blip·modelscope·blipprocessor
七夜zippoe41 分钟前
DolphinDB 高可用部署实战:从容灾设计到故障自动转移
开发语言·python·高可用·容灾·dolphindb
l12586542 分钟前
# LangGraph Deep Research Agent 全流程设计:多轮研究、人机协同与真实来源管理
数据库·人工智能·python·算法·自然语言处理·oracle·langchain
青少儿编程课堂1 小时前
图形化编程实战:智能交通灯调度台,一个作品讲透循环、条件与广播
c++·python·算法·bfs·信息学竞赛
HAPPY酷1 小时前
python的对象和方法
开发语言·python
the局外人2 小时前
别再背 Chain、Agent、Memory 了:用一条“智能流水线”学会 LangChain
python·langchain·llm
Zane19942 小时前
你以为的性能瓶颈,未必是真的瓶颈:用 cProfile 找到真凶
后端·python
铁手飞鹰2 小时前
VSCode Python .embed 嵌入式环境黄色波浪线问题
ide·vscode·python
辰辉创聚2 小时前
重组蛋白表达不出来怎么办?蛋白表达失败、低表达及异常原因解析
python·oracle·eclipse·重组蛋白·蛋白·western blot