Bun + TypeScript 零基础实战:从 HTTP 请求到大模型调用,我的 AI 全栈学习路线一、为什么是 Bu

一、为什么是 Bun?

2025 年,Anthropic 收购了 Bun。你没看错,就是那个做出 Claude 的 Anthropic。

Bun 现在是 Claude Code 的底层运行时。这意味着什么?你写的每一行 Bun 代码,和当今最强的 AI 编程工具跑在同一个引擎上。

那 Bun 到底是什么?

Bun 是一个比 Node.js 更快、开箱即用、零配置的 JavaScript / TypeScript 运行时 + 包管理器。

三个关键词:

  • 更快:基于 Zig 语言构建,启动速度、包安装速度数倍于 Node
  • 开箱即用:原生支持 TypeScript,不需要装 ts-node、不需要配 webpack
  • 零配置 :一个 bun run index.ts 直接跑 TypeScript,不需要任何配置文件

安装一行搞定:

bash 复制代码
powershell -c "irm bun.sh/install/windows | iex"

装完就能用,没有 node_modules 地狱,没有 tsconfig 焦虑。

配置不成功就去下bun-windows-x64.zip的安装包,问豆包等llm 去教你


二、TypeScript:给 JavaScript 装上刹车

2.1 JS 弱类型的痛

JavaScript 有一个经典问题------你以为它是数字,它其实是字符串。

打开一个 HTML 页面,写一个 input:

bash 复制代码
<input type="text" id="input">
<script>
  const input = document.getElementById('input')
  input.addEventListener("change", function(event) {
    console.log(event.target.value, typeof event.target.value);
    // 你输入 123,控制台打印:123 string
    // 永远是 string,永远是 string,永远是 string
  })
</script>

浏览器的 input.value 返回的永远是字符串。这不是 bug,这是设计。但问题来了:

bash 复制代码
let a = 1;
let b = "2";
console.log(a + b); // "12" ------ 字符串拼接!

+ 运算符一头是数字、一头是字符串,JS 不会报错,它会悄悄地把数字转成字符串然后拼起来。你期待结果是 3,实际得到 "12"

不报错 + 结果错误 = 线上 Bug 炸弹。这种 bug 可能藏在系统里几个月才爆。

2.2 TypeScript 登场

TypeScript 来自微软,是 JavaScript 的超集 ------所有合法的 JS 代码都是合法的 TS 代码,但 TS 多了类型约束

bash 复制代码
const nickname: string = "9527";
const age: number = 18;
console.log(`我是${nickname},我今年${age}岁`);

当你给变量加了类型,编辑器立刻就能检查出类型错误------不用等到运行时。

2.3 函数类型与类型转换

bash 复制代码
function add(a: number, b: number): number {
  return a + b;
}

let a = 1;
let b = "2";
// add(a, b);  // ❌ 编译报错:类型"string"的参数不能赋给类型"number"的参数

// 方式一:显式转换
let c: number = add(a, Number(b));

// 方式二:隐式转换(+号前置)
console.log(add(a, +b)); // 3 ✅

TS 在编译阶段就把 bug 拦下来了。你不用等用户反馈 "这个计算好像不对",IDE 里直接标红。

这也是为什么 TypeScript 已经成为 AI Agent 的标配------AI 写的代码也需要类型约束来保证质量。


三、异步编程:Promise 和 async/await

调用 AI 接口是网络请求,网络请求是异步的。JS 的异步演进路线是:callback → Promise → async/await。今天你只需要掌握最后一站。

封装一个 sleep 函数:

bash 复制代码
function sleep(t) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, t);
  });
}

async function main() {
  console.log('--start--');
  await sleep(1000);  // 等待 1 秒
  console.log('--end--');
}
main();

核心就两句话:

  • Promise 是一个 "许下诺言" 的对象------它代表一个未来才会完成的操作
  • await 后面跟 Promise,代码会暂停在这里,等 Promise 完成后继续

理解了这个模式,你就能理解所有 AI 接口调用的底层逻辑------它们都是异步的。


四、实战:用 axios 调用 DeepSeek 大模型

4.1 项目搭建

bash 复制代码
bun init axios-demo
cd axios-demo
bun add axios dotenv

Bun 的项目配置极简,package.json 长这样:

bash 复制代码
{
  "name": "axios-demo",
  "module": "index.ts",
  "type": "module",
  "dependencies": {
    "axios": "^1.17.0",
    "dotenv": "^17.4.2"
  },
  "devDependencies": {
    "@types/bun": "latest"
  },
  "peerDependencies": {
    "typescript": "^5"
  }
}

注意 "module": "index.ts"------Bun 原生就跑 .ts 文件,不需要编译。

4.2 理解 HTTP 请求结构

调用 AI API 本质上就是发一个 HTTP POST 请求。一个 HTTP 请求包含三个核心部分:

部分 作用 示例
请求行 URL + Method + HTTP Version POST https://api.deepseek.com/v1/chat/completions
请求头 元信息(认证、格式) Authorization: Bearer sk-xxxContent-Type: application/json
请求体 实际数据 { model: "deepseek-v4-flash", messages: [...] }

4.3 为什么用 POST 而不是 GET?

  • GET 请求有长度限制,URL 最长约 2048 字符
  • API Key 放在 GET 的 URL 参数里?不安全------URL 会被日志、代理、浏览器历史记录
  • AI 对话可能包含图片上传,需要请求体传二进制数据

所以调用 AI 接口,一律用 POST,API Key 放请求头,对话内容放请求体。

4.4 核心代码

bash 复制代码
import axios from "axios";
import dotenv from "dotenv";
dotenv.config();

async function chat() {
  try {
    const res = await axios.post(
      `${process.env.DEEPSEEK_API_URL}`,
      {
        model: "deepseek-v4-flash",
        messages: [
          {
            role: "user",
            content: "你好"
          }
        ]
      },
      {
        headers: {
          'Content-Type': "application/json",
          'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`
        }
      }
    );
    // axios 默认将响应数据包装在 data 属性中
    console.log(res.data.choices[0].message.content);
  } catch (err: any) {
    console.log(err.message);
  }
}

chat();

.env 文件:

bash 复制代码
DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions
DEEPSEEK_API_KEY=sk-你的密钥

4.5 这段代码讲了什么

  1. axios 是对 fetch 的封装,省去了手动处理 JSON、处理超时、处理错误的大量样板代码
  2. dotenv 把 API Key 从代码中分离出来------密钥永远不要硬编码
  3. try/catch 包裹整个请求------LLM 可能超时、可能限流、可能 Key 过期,必须有异常处理
  4. async/await 让异步代码看起来像同步代码,可读性大幅提升

一行 bun run index.ts,你就完成了一次 AI 对话。


五、升华一下:我的AI 全栈学习路线与心得

上面这些代码跑通后,你可能会问:"然后呢?我学会了调用 API,但我能做什么?我怎么成为一个 AI 全栈工程师?"

5.1 AI 全栈 ≠ 调 API

很多人把 AI 全栈理解成"前端 + 后端 + 调 AI API",这是不完整的

真正的 AI 全栈应该是:

bash 复制代码
             ┌─────────────────┐
             │   用户界面层      │  ← React / Vue / 小程序
             └────────┬────────┘
                      │
             ┌────────▼────────┐
             │   API 网关层     │  ← Bun / Node / Go
             └────────┬────────┘
                      │
        ┌─────────────┼─────────────┐
        │             │             │
  ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
  │  业务逻辑  │ │  LLM 调用  │ │  数据层    │
  │  (传统后端)│ │ (Prompt   │ │  (向量库)  │
  └───────────┘ │  Engineering│ └───────────┘
                │   + RAG)   │
                └───────────┘

需要掌握的不只是 axios.post,还包括:

层级 核心能力 关键工具
Prompt Engineering 写出高质量的系统提示词、管理对话上下文 Claude / DeepSeek / GPT
RAG(检索增强生成) 把私有知识喂给大模型 向量数据库(Pinecone / ChromaDB)
Function Calling / Tool Use 让 AI 调用你的 API、操作数据库 Claude Tool Use / OpenAI Function Calling
Agent 编排 多个 AI 协作完成复杂任务 LangChain / Claude Agent SDK
流式输出 SSE / WebSocket 实时返回 AI 回复 Server-Sent Events
安全与合规 API Key 管理、内容审核、速率限制 网关 + 审核中间件

5.2 三条核心心得

心得一:先跑通,再理解

不要先啃完所有理论再动手。第一个 AI 接口调用应该在第一周就完成------就像上面那个 axios 例子。跑通之后会兴奋,兴奋是最好的学习动力。

心得二:TypeScript 是 AI 时代的标配

AI Agent 写代码非常快,但它同样会犯 JS 弱类型的错误。TypeScript 的类型系统是我和 AI 之间的契约------'我'定义好类型,AI 填实现,编译器检查结果。这个协作模式效率极高。

这也是为什么 Claude Code 底层选择了 Bun + TypeScript,而不是纯 JavaScript。

心得三:AI 全栈的核心不是模型,是工程能力

模型层是别人的,工程层是你我们。DeepSeek、Claude、GPT 这些模型你换着用,但如何把它们串进业务系统、如何保证稳定性和用户体验、如何处理边界情况------这些才是我们的护城河。

代码里的 try/catchdotenv 密钥管理、axios 的请求封装......这些看起来 "不 AI" 的工程细节,恰恰是 AI 全栈工程师和 "调包侠" 的分界线。