AI Agent 开发学习指南

基于 Node.js / TypeScript + Vercel AI SDK + DeepSeek

1. 核心概念理解

在写代码之前,先把几个核心概念理解清楚,后续所有代码都是围绕这些概念展开的。

1.1 什么是 LLM

LLM(Large Language Model,大语言模型)就是 ChatGPT、Claude、DeepSeek 这类模型。 它的本质是一个函数:输入一段文字(Prompt),输出一段文字(Response)。

输入(Prompt)→ [LLM] → 输出(Response)

1.2 消息角色(Role)

每条消息都有一个角色,这是和 LLM 沟通的基本结构:

角色 说明 示例
system 给 AI 的"人设说明书",定义它的行为方式 "你是一个代码助手,只用中文回复"
user 用户发送的消息 "帮我写一个排序函数"
assistant AI 的回复(也可以手动填入,用于多轮对话) "好的,这是一个冒泡排序..."

💡 重要:LLM 本身没有记忆。每次调用都是全新的,多轮对话需要你手动把历史消息带上。

1.3 Token 是什么

Token 是 LLM 计费和计算的基本单位,大约:

  • 1 个英文单词 ≈ 1-2 个 token
  • 1 个中文字 ≈ 1-2 个 token
  • 1000 个 token ≈ 750 个英文单词

DeepSeek 的 deepseek-chat 模型价格(2025年):

  • 输入:¥0.001 / 1K tokens(约 750 个汉字)
  • 输出:¥0.002 / 1K tokens

学习阶段花费极低,10 块钱能跑几千次对话。

1.4 什么是 AI Agent

普通 LLM 调用:用户问 → AI 答,一问一答结束。

AI Agent:AI 可以自主决策调用工具多步执行,直到完成目标。

用户:"帮我查一下明天北京的天气,如果下雨就帮我发邮件提醒同事"

Agent 执行过程:
  步骤1:调用天气 API 查询北京天气 → 结果:明天有雨
  步骤2:调用邮件 API 发送提醒邮件 → 结果:发送成功
  步骤3:回复用户:已查到明天有雨,已发邮件通知同事

这种"思考 → 行动 → 观察 → 再思考"的循环叫 ReAct 循环,是 Agent 的核心模式。


2. 环境搭建

2.1 初始化项目

mkdir my-ai-agent
cd my-ai-agent
npm init -y

# 安装核心依赖
npm install ai @ai-sdk/deepseek zod

# 安装开发工具
npm install -D tsx typescript @types/node dotenv

2.2 配置 TypeScript

创建 tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "outDir": "./dist"
  }
}

2.3 配置环境变量

创建 .env 文件(不要提交到 git!):

DEEPSEEK_API_KEY=你的DeepSeek API Key

创建 .gitignore

.env
node_modules/
dist/

2.4 获取 DeepSeek API Key

  1. 访问 platform.deepseek.com
  2. 注册账号,进入 API Keys 页面
  3. 创建新的 API Key,复制填入 .env 文件

2.5 运行方式

# 直接运行 ts 文件(推荐开发阶段使用)
npx tsx index.ts

3. 基础:LLM 调用

3.1 最简单的文本生成

import { generateText } from 'ai'
import { createDeepSeek } from '@ai-sdk/deepseek'
import 'dotenv/config'

const deepseek = createDeepSeek({
    apiKey: process.env.DEEPSEEK_API_KEY,
});

async function main() {
    // 非流式交流、适合需要完整响应的场景(如摘要生成)
    const result = await generateText({
        model: deepseek('deepseek-v4-flash'),
        system: '你是一个代码助手,回答要简洁,用中文回复。',
        messages: [
            // 另一种传递 system 信息的方法
            // {
            //     role: 'system',
            //     content: '你是一个代码助手,回答要简洁,用中文回复。',
            // },
            {
                role: 'user',
                content: '用一句话解释什么是Nodejs?',
            },
        ],
    })
    console.log(result);
    console.log(result.text);
}

main();

3.2 流式输出(Streaming)

流式输出让 AI 的回复像"打字机"一样逐字出现,而不是等全部生成完再显示。 做聊天界面时必须使用流式,否则用户体验很差。

import { streamText } from 'ai'
import { createDeepSeek } from '@ai-sdk/deepseek'
import 'dotenv/config'

const deepseek = createDeepSeek({
    apiKey: process.env.DEEPSEEK_API_KEY,
});

async function main() {
    // 流式输出
    const result = streamText({
        model: deepseek('deepseek-v4-flash'),
        // 使用 system 选项 进行编写,安全性更高
        system: '你是一个技术博主,擅长写通俗易懂的技术文章。',
        messages: [
            {
                role: 'user',
                content: '用100字介绍一下 RAG 是什么',
            },
        ],
    });

    // 字一个个打印出来,模拟打字机效果
    for await (const chunk of result.textStream) {
        process.stdout.write(chunk)
    }

    // 流结束后获取完整信息
    console.log(await result.output);

    const usage = await result.usage
    console.log('输入 tokens:', usage.raw.prompt_tokens);
    console.log('输出 tokens:', usage.raw.completion_tokens);

}

main();

3.3 generateText vs streamText 的选择

场景 推荐方式
后台批量处理、提取信息 generateText
用户界面、聊天对话 streamText
生成结构化数据 generateText + Output
import { generateText, Output } from 'ai'
import { createDeepSeek } from '@ai-sdk/deepseek'
import { z } from 'zod'
import 'dotenv/config'

const deepseek = createDeepSeek({
    apiKey: process.env.DEEPSEEK_API_KEY,
});


async function main() {
    // 待分析的用户评论文本
    // 这是一条关于耳机的真实评论,包含优点、缺点和总体结论
    const userReview = `
    这款耳机音质很棒,低音够劲,佩戴也舒适。
    但是续航只有6小时,有点短,而且价格偏贵。
    总体来说还是值得买的。
  `

    // 调用 AI 生成文本(这里实际是生成结构化对象)
    const result = await generateText({
        // 指定使用的模型:DeepSeek 的 v4 flash 版本(速度快,适合简单任务)
        model: deepseek('deepseek-v4-flash'),
        // 配置输出格式:要求 AI 输出符合 Zod Schema 定义的 JSON 对象
        output: Output.object({
            // 使用 Zod 定义期望的结构
            schema: z.object({
                // 情感倾向:只能是 '正面', '负面', '中性' 之一
                sentiment: z.enum(['正面', '负面', '中性']).describe('整体情感倾向'),
                // 评分:1 到 5 的整数
                score: z.number().min(1).max(5).describe('评分 1-5 分'),
                // 优点:字符串数组
                pros: z.array(z.string()).describe('优点列表'),
                // 缺点:字符串数组
                cons: z.array(z.string()).describe('缺点列表'),
                // 一句话总结:字符串
                summary: z.string().describe('一句话总结'),
            })
        }),
        // 提示词:告诉 AI 需要做什么,并将用户评论内容传入
        prompt: `分析以下用户评论,提取结构化信息:\n\n${userReview}`
    });
    // 打印 AI 返回的解析后的对象(会自动符合上面定义的 schema)
    console.log(result.output);
}

main()