从 Bun 到 DeepSeek:用 TypeScript 构建你的第一个 AI Agent
🚀 AI Agent 时代已来,作为前端/全端开发者,你准备好入场了吗?本文带你从零搭建 Bun + TypeScript 环境,一步步调通 DeepSeek 大模型接口,构建属于你的第一个 AI Agent。
前言
2026 年,AI Agent 成为最火热的技术方向之一。无论是 Claude Code、Cursor 还是各种自主 Agent 框架,底层都离不开一个高性能的运行时。
而 Bun,这个被 Claude Code 选为底层运行时的 JS/TS 引擎,正在成为 AI Agent 开发的标配。
本文适合有一定 JS/TS 基础的开发者,你将学到:
- 为什么 AI Agent 选择 Bun + TypeScript?
- 如何用 Bun 调用 DeepSeek 大模型?
- 如何从单次调用进化到多轮对话 + 流式输出 + Tool Calling?
一、为什么 AI Agent 选择 Bun + TypeScript?
1.1 Bun 是什么?
一句话:Bun 是比 Node.js 更快、开箱即用、零配置的 JS/TS 运行时 + 包管理器。
| 特性 | Node.js | Bun |
|---|---|---|
| 启动速度 | 较慢 | ⚡ 极快 |
| TypeScript 支持 | 需要编译 ts → js | ✅ 原生支持,零配置 |
| 包管理器 | npm / pnpm | 内置 bun install,快 10-100 倍 |
| 内置 fetch | 需要 node-fetch | ✅ 原生支持 |
| 环境变量 | 需要 dotenv | ✅ 原生 --env-file |
1.2 为什么 Claude Code 选择 Bun?
Claude Code 的底层运行时就是 Bun。 当你使用 Claude Code 写代码、跑测试时,背后就是 Bun 在驱动。
原因很明确:
- 启动快 --- Agent 需要频繁启停进程,启动速度至关重要
- 原生 TS --- AI Agent 项目几乎都用 TypeScript,零配置直接跑
- 轻量级 --- 资源占用少,适合大规模部署
1.3 为什么 AI Agent 必须用 TypeScript?
AI Agent 涉及大量数据结构(消息列表、工具调用、API 响应),JavaScript 的弱类型会让 bug 藏在系统里很久:
html
<!-- 浏览器 input 输入框,你以为输入的是数字?其实是字符串! -->
<input type="text" id="ipt">
<script>
const ipt = document.getElementById('ipt');
ipt.addEventListener('change', function(event) {
console.log(event.target.value, typeof event.target.value);
// "123" + 1 = "1231" 而不是 124
});
</script>
TypeScript 的静态类型检查,让你在编码阶段就能发现 80% 的错误:
typescript
function add(a: number, b: number): number {
return a + b;
}
add(1, "2"); // ❌ 编译报错!类型不匹配
add(1, Number("2")); // ✅ 显式类型转换
这就是为什么几乎所有主流 AI Agent 框架都选择 TypeScript。
二、环境搭建
bash
# 安装 Bun(Windows)
powershell -c "irm bun.sh/install/windows | iex"
# 或者通过 npm/pnpm 安装
npm i -g bun
pnpm i -g bun
# 初始化项目
bun init
项目结构:
bash
my-ai-agent/
├── .env # 环境变量(API Key)
├── .gitignore # 忽略 .env 和 node_modules
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts # 入口文件
│ ├── chat.ts # 对话逻辑
│ ├── tools/ # 工具定义
│ │ └── weather.ts
│ └── types.ts # 类型定义
└── bun.lock
环境变量配置:
env
# .env
DEEPSEEK_BASE_URL=https://api.deepseek.com/chat/completions
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxx
⚠️ 模型名变更提醒 :
deepseek-chat与deepseek-reasoner将于 2026/07/24 弃用,统一合并为deepseek-v4-flash(通过非思考/思考模式区分)。本文已使用新模型名。
同时确保 .gitignore 中包含 .env,防止密钥泄露。
💡 Bun 小技巧 :Bun 原生支持
--env-file参数,无需安装 dotenv:
bashbun run --env-file=.env index.ts
三、异步编程速览
AI Agent 的核心是异步 --- 发送请求、等待响应、处理流式数据,全部是异步操作。
Promise 三种状态
| 状态 | 含义 | 触发方式 |
|---|---|---|
pending |
进行中 | 初始状态 |
fulfilled |
已成功 | 调用 resolve(value) |
rejected |
已失败 | 调用 reject(error) |
async/await:让异步代码像同步一样
javascript
function sleep(t) {
return new Promise((resolve) => setTimeout(resolve, t));
}
async function main() {
console.log('--start--');
await sleep(2000); // 暂停 2 秒,等待 Promise 完成
console.log('--end--');
}
main();
await 会暂停当前 async 函数的执行,等 Promise 完成后拿到结果继续往下走。
Promise.all:并行执行多个异步任务
AI Agent 经常需要同时调用多个 Tool,用 Promise.all 可以并行执行:
javascript
// ❌ 串行 --- 总耗时 = 2s + 3s = 5s
const weather = await getWeather('北京');
const news = await getNews('科技');
// ✅ 并行 --- 总耗时 = max(2s, 3s) = 3s
const [weather, news] = await Promise.all([
getWeather('北京'),
getNews('科技')
]);
💡 实战场景 :当 Agent 需要同时调用多个 Tool(查天气 + 查日程 + 搜索),
Promise.all能显著减少等待时间。
四、实战:调用 DeepSeek 大模型
4.1 方式一:Bun 内置 fetch(零依赖,推荐)
typescript
// fetch-demo.ts
// 运行:bun run --env-file=.env fetch-demo.ts
async function chat() {
try {
// 1. 环境变量校验
const baseUrl = process.env.DEEPSEEK_BASE_URL;
const apiKey = process.env.DEEPSEEK_API_KEY;
if (!baseUrl || !apiKey) {
throw new Error('请检查 .env 文件中的 DEEPSEEK_BASE_URL 和 DEEPSEEK_API_KEY');
}
// 2. 超时控制:30 秒无响应自动取消
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
const res = await fetch(baseUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'deepseek-v4-flash',
messages: [{
role: 'user',
content: '你好,介绍一下Bun'
}]
}),
signal: controller.signal
});
clearTimeout(timeout);
// 3. 检查 HTTP 状态码
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${await res.text()}`);
}
// 4. 防御性取值
const data = await res.json();
const content = data?.choices?.[0]?.message?.content;
if (!content) {
console.error('响应格式异常:', JSON.stringify(data, null, 2));
return;
}
console.log(content);
} catch (err: any) {
if (err.name === 'AbortError') {
console.error('请求超时,请检查网络或稍后重试');
} else {
console.error('请求失败:', err.message);
}
}
}
chat();
为什么推荐 fetch? 零依赖、更轻量、符合 Web 标准。
4.2 方式二:Axios(企业级方案)
如果你需要拦截器、自动重试、请求取消等高级功能,Axios 是更好的选择:
typescript
// index.ts
import axios from "axios";
import dotenv from "dotenv";
dotenv.config();
async function chat() {
try {
const baseUrl = process.env.DEEPSEEK_BASE_URL;
const apiKey = process.env.DEEPSEEK_API_KEY;
if (!baseUrl || !apiKey) {
throw new Error('请检查 .env 文件中的 DEEPSEEK_BASE_URL 和 DEEPSEEK_API_KEY');
}
const res = await axios.post(
baseUrl,
{
model: 'deepseek-v4-flash',
messages: [{
role: 'user',
content: '你好,介绍一下Bun'
}]
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
timeout: 30000
}
);
const content = res.data?.choices?.[0]?.message?.content;
if (!content) {
console.error('响应格式异常:', JSON.stringify(res.data, null, 2));
return;
}
console.log(content);
} catch (err: any) {
if (err.response) {
console.error(`HTTP ${err.response.status}:`, err.response.data);
} else {
console.error('请求失败:', err.message);
}
}
}
chat();
bash
bun run index.ts
五、从"能调用"到"会对话":三个进阶能力
单次 API 调用只是起点,真正的 AI Agent 需要以下三个能力:
5.1 多轮对话:维护消息列表
AI 模型是无状态的,每次请求都需要带上完整的历史消息:
typescript
const messages: Array<{role: string; content: string}> = [
{ role: 'system', content: '你是一个友好的AI助手' },
{ role: 'user', content: '你好!' },
// 模型回复后,把回复也加入 messages
// { role: 'assistant', content: '你好!有什么可以帮你的?' },
// { role: 'user', content: '介绍一下Bun' },
];
每次用户发消息,把新消息追加到 messages 数组,然后把整个数组发给模型。这就是多轮对话的秘密。
5.2 流式输出(SSE)
大模型生成回复需要时间,如果等全部生成完再显示,用户体验很差。流式输出让模型边生成边输出:
typescript
const res = await fetch(url, {
method: 'POST',
headers: { /* ... */ },
body: JSON.stringify({
model: 'deepseek-v4-flash',
messages: messages,
stream: true // 开启流式输出
})
});
// 逐块读取响应
const reader = res.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.startsWith('data: '));
for (const line of lines) {
const data = line.replace('data: ', '');
if (data === '[DONE]') break;
const parsed = JSON.parse(data);
process.stdout.write(parsed.choices[0]?.delta?.content || '');
}
}
5.3 Tool Calling:让 AI 具备"动手能力"
真正的 AI Agent 不只是聊天,它能调用工具:
typescript
const tools = [{
type: 'function',
function: {
name: 'get_weather',
description: '获取指定城市的天气',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: '城市名称' }
}
}
}
}];
这就是 AI Agent 的核心循环:
用户输入 → 模型理解意图 → 选择工具 → 执行工具 → 将结果反馈给模型 → 继续推理
六、总结
| 知识点 | 作用 |
|---|---|
| Bun | 高性能运行时,AI Agent 的底层引擎 |
| TypeScript | 类型约束,减少 80% 的运行时错误 |
| async/await | 异步编程基石,处理网络请求 |
| fetch / axios | 调用 LLM API 的两种方式 |
| 消息列表 | 多轮对话的核心数据结构 |
| 流式输出 | 提升用户体验的关键技术 |
| Tool Calling | 从"聊天机器人"进化为"AI Agent" |
Bun + TypeScript 正在成为 AI Agent 开发的黄金组合。Claude Code 选择 Bun 作为底层运行时,已经证明了这条技术路线的正确性。
现在就开始你的第一个 AI Agent 吧!🎯
七、学习资源
🔧 运行时 & 工具
- Bun 官方文档 --- 安装、API、配置全覆盖
- TypeScript 官方手册 --- 类型系统深入学习
- Axios 官方文档 --- HTTP 请求库进阶用法
🤖 AI & LLM
- DeepSeek 开放平台 --- API 文档、模型列表、价格说明
- DeepSeek API 对话示例 --- 多轮对话、流式输出、Tool Calling 官方示例
- OpenAI API 规范 --- DeepSeek 兼容 OpenAI 格式,可参考其文档
📚 AI Agent 开发
- Anthropic Claude Code --- 了解 Bun 在 AI Agent 中的实际应用
- Vercel AI SDK --- 前端友好的 AI 流式输出方案
- LangChain.js --- TypeScript AI Agent 框架
📖 推荐阅读
- Bun vs Node.js 性能对比 --- 官方基准测试
- MDN Fetch API --- Web 标准请求 API
- SSE 协议详解 --- 流式输出底层原理
📌 本文代码仓库 :gitee.com/zhou-wenqia...
觉得有帮助的话,点个赞 👍 收藏 ⭐ 支持一下!