AI 时代必备技能指南:从 Prompt 新手到 AI 专家的进阶路

AI 时代必备技能指南:从 Prompt 新手到 AI 专家的进阶路线

在 AI 重塑工作的时代,掌握这些技能让你从”被替代”变成”不可替代”

引言:AI 技能的新时代

当 ChatGPT 发布时,很多人担心”AI 会取代我的工作吗?”

一年半后,答案变得清晰:AI 不会取代你,但会用 AI 的人会取代你。

据 LinkedIn 2026 年报告显示:

  • 📈 AI 相关技能需求增长 450%
  • 💰 掌握 AI 技能的开发者薪资溢价 30-50%
  • 🚀 90% 的科技公司将 AI 技能列为核心要求

本文将系统性地介绍 AI 时代的必备技能,并提供清晰的学习路径。

一、AI 技能图谱

                    AI 技能金字塔

                      ▲ AI 架构师
                     /|\
                    / | \  构建 AI 系统
                   /  |  \
              ────────────────
             /    AI 工程师   \
            /                  \
           /  模型微调 / Agent开发 \
          /________________________\
         /    Prompt Engineering    \
        /     工具集成 / API 使用      \
       /______________________________\
      /         AI 素养基础              \
     /  理解原理 / 工具使用 / 场景判断    \
    /____________________________________\

1.1 技能分级

L1 - AI 使用者(AI User)🌱

核心能力: 能够有效使用现有 AI 工具

  • ✅ 会写有效的 Prompt
  • ✅ 了解各类 AI 工具的应用场景
  • ✅ 能将 AI 集成到日常工作流

适用人群: 所有职场人士
学习时间: 1-2 周

L2 - AI 整合者(AI Integrator)🌿

核心能力: 能够将 AI 能力整合到产品中

  • ✅ 掌握 AI API 调用
  • ✅ 会处理 Prompt 模板和优化
  • ✅ 能构建简单的 AI 应用

适用人群: 开发者、产品经理
学习时间: 1-3 个月

L3 - AI 开发者(AI Developer)🌳

核心能力: 能够开发复杂的 AI 应用

  • ✅ 掌握多种 AI 框架(LangChain 等)
  • ✅ 会构建 AI Agent 和工作流
  • ✅ 能进行模型微调和优化

适用人群: 高级开发者、AI 工程师
学习时间: 3-6 个月

L4 - AI 架构师(AI Architect)🏔️

核心能力: 能够设计和搭建企业级 AI 系统

  • ✅ AI 系统架构设计
  • ✅ 模型选型和优化策略
  • ✅ 成本控制和性能调优

适用人群: 技术负责人、架构师
学习时间: 6-12 个月

二、核心技能详解

2.1 Prompt Engineering(提示工程)

这是 AI 时代的”新编程语言”。

基础技能:写出有效的 Prompt

❌ 差劲的 Prompt

写一个登录页面

✅ 优秀的 Prompt

创建一个现代化的登录页面组件:

技术栈:
- React 18 + TypeScript
- Tailwind CSS
- React Hook Form + Zod 验证

功能要求:
1. 邮箱和密码输入(带实时验证)
2. "记住我"复选框
3. "忘记密码"链接
4. 社交登录按钮(Google, GitHub)
5. 响应式设计(移动端友好)

设计风格:
- 简洁现代
- 柔和的阴影和圆角
- 主色调:#3B82F6

代码要求:
- 完整的 TypeScript 类型定义
- 组件化(可复用的 Input 组件)
- 包含错误处理
- 添加注释说明关键逻辑

进阶技能:Prompt 模式库

1. Chain of Thought(思维链)
# 标准 Prompt
计算:如果一个商店打 7 折,再用 50 元优惠券,买 500 元的商品最终多少钱?

# CoT Prompt(更准确)
计算:如果一个商店打 7 折,再用 50 元优惠券,买 500 元的商品最终多少钱?

请一步步思考:
1. 首先计算打折后的价格
2. 然后减去优惠券金额
3. 给出最终价格

让我们开始:

效果提升: 准确率从 65% → 92%

2. Role Prompting(角色扮演)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
const rolePrompts = {
codeReviewer: `
你是一位有 15 年经验的高级软件工程师,专精于代码审查。
你的审查标准包括:
- 代码质量和可维护性
- 性能优化
- 安全性
- 架构设计
- 最佳实践

你的审查风格:
- 客观专业,不带个人偏见
- 既指出问题,也认可优点
- 提供具体的改进建议和示例
- 考虑项目的实际情况(时间、资源)
`,

dataAnalyst: `
你是一位资深数据分析师,拥有统计学和商业分析背景。

你的分析方法:
1. 数据探索(EDA)
2. 假设验证
3. 统计推断
4. 可视化呈现
5. 商业洞察

你总是:
- 从数据中讲故事
- 关注可执行的洞察
- 考虑统计显著性
- 用可视化辅助说明
`,

technicalWriter: `
你是一位技术写作专家,擅长将复杂技术概念转化为清晰易懂的文档。

你的写作原则:
- 受众导向(考虑读者的技术水平)
- 结构清晰(标题、列表、代码示例)
- 循序渐进(从简单到复杂)
- 实用性强(可操作的步骤)
- 视觉辅助(图表、流程图)
`
};

// 使用
const prompt = `
${rolePrompts.codeReviewer}

现在,请审查以下代码:
[代码内容]
`;
3. Few-Shot Learning(少样本学习)
任务:将产品评论分类为"正面"、"负面"或"中性"

示例 1:
输入:"这个产品质量很好,物超所值!"
输出:正面

示例 2:
输入:"收到商品有破损,很失望"
输出:负面

示例 3:
输入:"还行吧,没有特别惊艳"
输出:中性

现在,请分类以下评论:
输入:"快递很快,但是功能比较一般"
输出:
4. Self-Consistency(自我一致性)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
async function solveWithSelfConsistency(problem, attempts = 5) {
const solutions = [];

// 生成多个解答
for (let i = 0; i < attempts; i++) {
const response = await ai.chat([{
role: 'user',
content: `
问题:${problem}

请仔细思考并给出答案。使用不同的思路解决。
`
}], {
temperature: 0.7 + (i * 0.1), // 增加多样性
});

solutions.push(response.content);
}

// 寻找最一致的答案
const finalAnswer = await ai.chat([{
role: 'user',
content: `
我对同一个问题得到了多个答案:

${solutions.map((s, i) => `答案 ${i+1}: ${s}`).join('\n\n')}

请分析这些答案,找出最合理和一致的答案,并说明原因。
`
}]);

return finalAnswer.content;
}
5. Tree of Thoughts(思维树)
问题:设计一个高并发的秒杀系统

让我们用思维树的方法来解决:

第一层:主要挑战
├─ 1A. 高流量冲击
├─ 1B. 数据一致性
└─ 1C. 用户体验

第二层:针对 1A(高流量冲击)的方案
├─ 2A1. 前端限流
│   ├─ 3A1a. 按钮防抖
│   └─ 3A1b. 验证码
├─ 2A2. CDN 加速
└─ 2A3. 服务端限流
    ├─ 3A3a. 令牌桶
    └─ 3A3b. 漏桶算法

第二层:针对 1B(数据一致性)的方案
├─ 2B1. 悲观锁
├─ 2B2. 乐观锁
└─ 2B3. Redis 原子操作

第二层:针对 1C(用户体验)的方案
├─ 2C1. 队列排队
├─ 2C2. 实时反馈
└─ 2C3. 降级方案

现在,请详细分析每个分支的优劣,并推荐最佳组合方案。

高级技能:Prompt 优化技巧

1. 分隔符使用
分析以下用户反馈,提取关键问题和情感倾向:

用户反馈开始 >>>
我购买的笔记本电脑使用两周就出现了蓝屏问题,
联系客服后等了三天才回复,维修又花了一周时间。
虽然最后修好了,但这个过程让我很不满意。
不过客服态度还算可以。
<<< 用户反馈结束

请输出:
1. 主要问题列表
2. 情感倾向(正面/负面/中性)
3. 改进建议

优势: 清晰界定输入内容,避免 prompt injection

2. 输出格式控制
# JSON 格式输出
请分析这段代码的复杂度,并严格按照以下 JSON 格式输出:

{
  "timeComplexity": "O(n) 的说明",
  "spaceComplexity": "O(1) 的说明",
  "issues": [
    {
      "type": "performance|readability|security",
      "severity": "high|medium|low",
      "description": "问题描述",
      "suggestion": "改进建议"
    }
  ],
  "score": 1-10
}

代码:
[代码内容]

输出(仅 JSON,无其他文字):
1
2
3
4
5
6
7
8
9
// 代码中使用
const response = await ai.chat([{ role: 'user', content: prompt }]);
const result = JSON.parse(response.content);

// 现在可以直接使用结构化数据
console.log(`代码评分: ${result.score}`);
result.issues.forEach(issue => {
console.log(`[${issue.severity}] ${issue.description}`);
});
3. 多步骤分解
任务:为一个电商网站创建完整的数据库设计

请按以下步骤完成:

## 第 1 步:需求分析
列出电商网站的核心功能模块(如用户、商品、订单等)

## 第 2 步:实体识别
为每个功能模块识别主要实体和属性

## 第 3 步:关系定义
定义实体之间的关系(一对一、一对多、多对多)

## 第 4 步:表设计
创建详细的表结构(包括主键、外键、索引)

## 第 5 步:优化建议
提供性能优化和扩展性建议

请严格按照步骤顺序完成,每一步都要详细说明。

2.2 AI Tools 精通(Tool Mastery)

快速上手矩阵

工具类型 入门工具 进阶工具 精通标志
文本生成 ChatGPT Free ChatGPT Plus + Claude 能写出最优 Prompt、懂得模型选择、会成本优化
代码辅助 GitHub Copilot Cursor + Copilot 多文件上下文理解、对话式重构、测试生成
图像生成 DALL-E Midjourney 精通提示词、风格控制、一致性参数
API 集成 OpenAI Playground 多模型 API 错误处理、流式响应、成本监控、缓存策略
Agent 开发 Zapier LangChain/AutoGPT 复杂工作流、自定义工具、记忆管理

工具链组合策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// 「内容创作」最佳工具链
const contentCreationStack = {
research: [
'Perplexity AI', // 深度搜索
'ChatGPT', // 信息整理
],

writing: [
'Claude', // 长文创作主力
'ChatGPT', // 内容优化
'Grammarly', // 语法检查
],

visuals: [
'Midjourney', // 配图生成
'Canva AI', // 排版设计
],

workflow: [
'Notion AI', // 内容管理
'Zapier', // 自动化发布
]
};

// 「软件开发」最佳工具链
const developmentStack = {
coding: [
'Cursor', // 主力编辑器
'GitHub Copilot', // 代码补全
'Codeium', // 备用方案
],

review: [
'ChatGPT-4', // 代码审查
'CodeRabbit', // PR 自动审查
],

testing: [
'ChatGPT', // 单元测试生成
'Testim', // E2E 测试
],

documentation: [
'Mintlify', // API 文档
'Notion AI', // 技术文档
]
};

// 「数据分析」最佳工具链
const dataAnalysisStack = {
exploration: [
'Julius AI', // 对话式分析
'ChatGPT Code Interpreter', // 快速分析
],

advanced: [
'Python + Copilot', // 深度分析
'Hex', // 协作分析
],

visualization: [
'ChatGPT', // 图表生成
'Tableau', // 专业可视化
],

reporting: [
'Claude', // 报告撰写
'Gamma', // PPT 生成
]
};

工具使用效率提升

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// 1. 快捷键和自动化
const productivityTips = {
chatgpt: {
shortcuts: {
'Cmd/Ctrl + /': '新对话',
'Cmd/Ctrl + Shift + ;': '切换侧边栏',
},
tips: [
'使用 Custom Instructions 设置默认角色',
'创建常用 Prompt 的快捷方式',
'利用 GPTs 创建专用助手'
]
},

cursor: {
shortcuts: {
'Cmd/Ctrl + K': 'AI 编辑',
'Cmd/Ctrl + L': 'AI 对话',
'Cmd/Ctrl + Shift + K': 'AI 终端',
},
tips: [
'使用 @codebase 引用整个项目',
'使用 @file 引用特定文件',
'使用 @docs 查询文档',
'创建 .cursorrules 文件自定义行为'
]
},

midjourney: {
tips: [
'保存常用风格参数到 --style 中',
'使用 --seed 保持一致性',
'学习权重语法 (thing:1.5) 控制元素',
'利用 /describe 反向工程提示词'
]
}
};

// 2. Prompt 模板库
class PromptLibrary {
constructor() {
this.templates = new Map();
}

add(name, template) {
this.templates.set(name, template);
}

get(name, vars = {}) {
let template = this.templates.get(name);
if (!template) throw new Error(`Template ${name} not found`);

// 变量替换
for (const [key, value] of Object.entries(vars)) {
template = template.replace(new RegExp(`{{${key}}}`, 'g'), value);
}

return template;
}

list() {
return Array.from(this.templates.keys());
}
}

// 使用
const library = new PromptLibrary();

library.add('codeReview', `
审查以下 {{language}} 代码,关注:

1. 代码质量
2. 性能
3. 安全性
4. 最佳实践

代码:
\`\`\`{{language}}
{{code}}
\`\`\`
`);

library.add('bugFix', `
以下代码出现错误:

错误信息:
{{error}}

代码:
\`\`\`{{language}}
{{code}}
\`\`\`

请:
1. 分析错误原因
2. 提供修复方案
3. 给出修复后的完整代码
4. 解释为什么会出现这个问题
`);

// 调用
const prompt = library.get('codeReview', {
language: 'TypeScript',
code: '...'
});

2.3 编程 + AI 融合能力

技能点 1:AI-Assisted Coding(AI 辅助编程)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Level 1: 代码补全
// 只是让 Copilot 自动补全

// Level 2: 对话式编程(✨ 推荐)
// 在 Cursor 中使用 AI 对话

/*
你:创建一个 React 组件,显示用户列表,支持搜索和分页

AI:[生成代码]

你:添加加载状态和错误处理

AI:[更新代码]

你:优化性能,使用 useMemo

AI:[优化代码]
*/

// Level 3: 测试驱动 + AI
// 先写测试,让 AI 实现

describe('UserService', () => {
it('should fetch users with pagination', async () => {
const service = new UserService();
const result = await service.getUsers({ page: 1, limit: 10 });

expect(result.users).toHaveLength(10);
expect(result.total).toBeGreaterThan(0);
expect(result.page).toBe(1);
});

it('should handle fetch errors', async () => {
const service = new UserService();
// Mock API error

await expect(
service.getUsers({ page: 1, limit: 10 })
).rejects.toThrow();
});
});

// 现在让 AI 实现 UserService 类
// Prompt: "根据上面的测试用例,实现 UserService 类"

技能点 2:AI Code Review 自动化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// .github/workflows/ai-review.yml
name: AI Code Review

on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: AI Review
uses: coderabbitai/openai-pr-reviewer@latest
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
openai_api_key: ${{ secrets.OPENAI_API_KEY }}

- name: Custom Analysis
run: |
# 使用自定义脚本深度分析
node scripts/ai-analyze.js

// scripts/ai-analyze.js
import { AIClient } from './lib/ai-client.js';
import { execSync } from 'child_process';

async function analyzeChanges() {
const diff = execSync('git diff main').toString();

const ai = new AIClient();
const analysis = await ai.chat([{
role: 'user',
content: `
分析这次 PR 的影响范围和风险:

变更内容:
${diff}

输出:
1. 影响的模块
2. 风险等级(高/中/低)
3. 需要特别注意的点
4. 建议的测试重点
`
}]);

console.log(analysis.content);
}

技能点 3:AI 驱动的重构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// 重构工作流
class AIRefactoringWorkflow {
async refactor(filePath) {
// 1. 读取代码
const code = await fs.readFile(filePath, 'utf-8');

// 2. AI 分析问题
const analysis = await this.analyzeCode(code);

// 3. 生成重构方案
const plan = await this.generateRefactoringPlan(code, analysis);

// 4. 人工确认
console.log('重构计划:');
console.log(plan);
const confirmed = await this.getUserConfirmation();

if (!confirmed) return;

// 5. 执行重构
const refactoredCode = await this.applyRefactoring(code, plan);

// 6. 运行测试验证
await this.runTests();

// 7. 保存结果
await fs.writeFile(filePath, refactoredCode);

console.log('✅ 重构完成');
}

async analyzeCode(code) {
const response = await ai.chat([{
role: 'user',
content: `
分析以下代码,找出可以改进的地方:

\`\`\`javascript
${code}
\`\`\`

关注:
1. 代码重复
2. 过长的函数
3. 复杂的条件逻辑
4. 命名不清晰
5. 缺少类型定义
6. 性能问题

以 JSON 格式输出:
{
"issues": [
{
"type": "duplication|complexity|naming|...",
"location": "行号或函数名",
"description": "问题描述",
"priority": "high|medium|low"
}
]
}
`
}]);

return JSON.parse(response.content);
}

async generateRefactoringPlan(code, analysis) {
const response = await ai.chat([{
role: 'user',
content: `
基于以下问题,生成详细的重构方案:

代码:
\`\`\`javascript
${code}
\`\`\`

问题列表:
${JSON.stringify(analysis, null, 2)}

输出:
1. 重构步骤(优先级排序)
2. 每步的具体改动
3. 预期效果
`
}]);

return response.content;
}

async applyRefactoring(code, plan) {
const response = await ai.chat([{
role: 'user',
content: `
执行以下重构方案:

原始代码:
\`\`\`javascript
${code}
\`\`\`

重构方案:
${plan}

输出重构后的完整代码(仅代码,无解释):
`
}], {
temperature: 0.1, // 低温度确保一致性
});

// 提取代码块
const match = response.content.match(/```javascript\n([\s\S]*?)\n```/);
return match ? match[1] : response.content;
}
}

// 使用
const workflow = new AIRefactoringWorkflow();
await workflow.refactor('./src/legacy-code.js');

2.4 数据思维 + AI

技能点 1:数据驱动的 Prompt 优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
class PromptOptimizer {
constructor() {
this.experiments = [];
}

async runABTest(basePrompt, variations, testCases) {
console.log(`🧪 Running A/B test with ${variations.length} variations`);

const results = [];

for (const [index, variation] of variations.entries()) {
console.log(`\n📝 Testing variation ${index + 1}...`);

const scores = [];

for (const testCase of testCases) {
const response = await ai.chat([{
role: 'user',
content: variation.replace('{{input}}', testCase.input)
}]);

// 评分
const score = await this.scoreResponse(
response.content,
testCase.expectedOutput
);

scores.push(score);
}

const avgScore = scores.reduce((a, b) => a + b, 0) / scores.length;

results.push({
variation: index + 1,
prompt: variation,
avgScore,
scores,
});
}

// 排序找出最佳
results.sort((a, b) => b.avgScore - a.avgScore);

console.log('\n📊 Results:');
results.forEach(r => {
console.log(` Variation ${r.variation}: ${r.avgScore.toFixed(2)}/10`);
});

return results[0];
}

async scoreResponse(actual, expected) {
const response = await ai.chat([{
role: 'user',
content: `
评估 AI 回答的质量(1-10 分):

期望答案:
${expected}

实际答案:
${actual}

评分标准:
- 准确性(40%)
- 完整性(30%)
- 清晰度(20%)
- 实用性(10%)

只输出数字分数:
`
}], {
temperature: 0,
});

return parseFloat(response.content);
}
}

// 使用示例
const optimizer = new PromptOptimizer();

const variations = [
// 变体 1: 简单直接
'{{input}}',

// 变体 2: 加上思维链
'{{input}}\n\n让我们一步步思考:',

// 变体 3: 加上角色
'你是一个专家。{{input}}',

// 变体 4: 加上格式要求
'{{input}}\n\n请按照以下格式输出:\n1. ...\n2. ...',
];

const testCases = [
{
input: '解释什么是闭包',
expectedOutput: '包含定义、示例、应用场景'
},
{
input: '实现一个防抖函数',
expectedOutput: '包含代码、注释、使用示例'
},
];

const best = await optimizer.runABTest(null, variations, testCases);
console.log('\n🏆 最佳 Prompt:');
console.log(best.prompt);

技能点 2:AI 辅助数据分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# AI 数据分析助手
import pandas as pd
from openai import OpenAI

class AIDataAnalyst:
def __init__(self):
self.client = OpenAI()

def analyze(self, df, question):
"""对话式数据分析"""
# 1. 生成数据摘要
summary = self._summarize_dataframe(df)

# 2. AI 生成分析代码
code = self._generate_analysis_code(summary, question)

# 3. 执行代码
result = self._execute_code(code, df)

# 4. AI 解释结果
explanation = self._explain_results(result, question)

return {
'code': code,
'result': result,
'explanation': explanation
}

def _summarize_dataframe(self, df):
return {
'shape': df.shape,
'columns': df.columns.tolist(),
'dtypes': df.dtypes.to_dict(),
'head': df.head().to_dict(),
'describe': df.describe().to_dict()
}

def _generate_analysis_code(self, summary, question):
response = self.client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[{
"role": "user",
"content": f"""
数据集信息:
{summary}

问题:{question}

生成 Python/Pandas 代码来回答这个问题。
代码应该:
1. 使用 df 变量(已定义好的 DataFrame)
2. 存储结果到 'result' 变量
3. 包含注释

只输出代码,不要解释:
```python
# your code here

“””
}]
)

    # 提取代码
    code = response.choices[0].message.content
    code = code.replace('```python', '').replace('```', '').strip()

    return code

def _execute_code(self, code, df):
    """安全执行代码"""
    local_vars = {'df': df, 'pd': pd}
    exec(code, {'pd': pd}, local_vars)
    return local_vars.get('result')

def _explain_results(self, result, question):
    response = self.client.chat.completions.create(
        model="gpt-4-turbo-preview",
        messages=[{
            "role": "user",
            "content": f"""

问题:{question}

分析结果:
{result}

请用简洁的语言解释这个结果,包括:

  1. 主要发现

  2. 数据含义

  3. 可能的洞察
    “””
    }]
    )

      return response.choices[0].message.content

使用

analyst = AIDataAnalyst()

加载数据

df = pd.read_csv(‘sales_data.csv’)

对话式分析

result = analyst.analyze(
df,
“哪个产品类别的销售额最高?请展示前 5 名”
)

print(“生成的代码:”)
print(result[‘code’])

print(“\n分析结果:”)
print(result[‘result’])

print(“\nAI 解释:”)
print(result[‘explanation’])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

## 三、学习路径规划

### 3.1 30 天 AI 技能速成

#### Week 1: AI 基础认知

**Day 1-2: 理解 AI 工作原理**
- 📚 学习:LLM 基础概念(Token、Temperature、上下文窗口)
- 🎯 实践:使用 ChatGPT 完成 10 个不同类型任务
- ✅ 目标:理解 AI 能做什么、不能做什么

**Day 3-4: Prompt Engineering 入门**
- 📚 学习:Prompt 的结构(角色、任务、格式、示例)
- 🎯 实践:重写 20 个烂 Prompt,对比效果
- ✅ 目标:会写清晰有效的 Prompt

**Day 5-7: 工具探索**
- 📚 学习:主流 AI 工具介绍
- 🎯 实践:试用 5 个不同类别的工具
- ✅ 目标:了解各类工具的应用场景

#### Week 2: 工具精通

**Day 8-10: ChatGPT/Claude 深度使用**
- 📚 学习:高级特性(Custom GPTs、Projects、Code Interpreter)
- 🎯 实践:创建 3 个专用 GPT
- ✅ 目标:成为 ChatGPT 高级用户

**Day 11-12: AI 编程助手**
- 📚 学习:GitHub Copilot / Cursor使用
- 🎯 实践:用 AI 完成一个小项目
- ✅ 目标:掌握 AI 辅助编程

**Day 13-14: 图像生成工具**
- 📚 学习:Midjourney / DALL-E 提示词技巧
- 🎯 实践:生成 20 张不同风格的图片
- ✅ 目标:会写图像生成提示词

#### Week 3: API 集成

**Day 15-17: API 基础**
```javascript
// Day 15: 第一个 API 调用
import OpenAI from 'openai';

const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});

const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [
{ role: 'user', content: 'Hello!' }
]
});

console.log(response.choices[0].message.content);

// Day 16: 构建聊天应用
// Day 17: 添加流式响应

Day 18-20: 实战项目

  • 🎯 项目 1:AI 摘要工具(输入长文本,输出摘要)
  • 🎯 项目 2:代码解释器(输入代码,输出解释)
  • 🎯 项目 3:智能问答机器人

Day 21: 成本优化

  • 📚 学习:Token 计算、缓存策略、模型选择
  • 🎯 实践:优化前面的项目,降低 50% 成本

Week 4: 高级应用

Day 22-24: LangChain 入门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Day 22: 第一个 Chain
from langchain import OpenAI, LLMChain, PromptTemplate

template = """
你是一个 {role}。

用户问题:{question}

请回答:
"""

prompt = PromptTemplate(
input_variables=["role", "question"],
template=template
)

llm = OpenAI(temperature=0.7)
chain = LLMChain(llm=llm, prompt=prompt)

result = chain.run(
role="Python 专家",
question="如何优化 for 循环性能?"
)

# Day 23: RAG 实现
# Day 24: Agent 开发

Day 25-27: 完整项目

  • 🎯 项目:构建一个 AI 内容创作系统
    • 搜索最新信息
    • 生成文章大纲
    • 撰写内容
    • 生成配图
    • SEO 优化

Day 28-29: 部署上线

  • 📚 学习:API 安全、限流、监控
  • 🎯 实践:将项目部署到生产环境

Day 30: 总结回顾

  • ✍️ 写一篇技术博客分享学习心得
  • 📊 整理自己的 Prompt 库和工具箱
  • 🎯 制定下一阶段学习计划

3.2 进阶学习路线(3-6 个月)

Month 1-2: 深度工具使用
├─ Week 1-2: 多模型对比和选择
├─ Week 3-4: Fine-tuning 实践
├─ Week 5-6: Embedding 和向量数据库
└─ Week 7-8: 构建 RAG 系统

Month 3-4: AI Agent 开发
├─ Week 9-10: Agent 架构设计
├─ Week 11-12: 工具集成和编排
├─ Week 13-14: 记忆系统实现
└─ Week 15-16: 多 Agent 协作

Month 5-6: 生产化部署
├─ Week 17-18: 性能优化
├─ Week 19-20: 成本控制
├─ Week 21-22: 监控和日志
└─ Week 23-24: 安全和合规

四、实战技能训练

4.1 Prompt Engineering 刻意练习

练习 1: Prompt 改进挑战

原始 Prompt(烂):
"写一个排序算法"

改进步骤:
1. 明确语言和复杂度要求
2. 指定输入输出格式
3. 添加测试用例
4. 要求代码注释

最终 Prompt(好):
"用 TypeScript 实现快速排序算法

要求:
1. 时间复杂度 O(n log n)
2. 原地排序(空间复杂度 O(log n))
3. 完整的类型定义
4. 详细的代码注释
5. 包含 3 个测试用例

输入:number[]
输出:排序后的 number[]

请提供:
1. 完整的函数实现
2. 时间复杂度分析
3. 测试用例和预期结果"

每天练习: 找 5 个烂 Prompt,改进并对比效果

练习 2: 角色扮演大师

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 创建 20 个不同领域的专家角色
const expertRoles = {
securityExpert: `
你是一位 15 年经验的安全专家,专注于 Web 安全。
你熟悉 OWASP Top 10、渗透测试、安全编码实践。
你审查代码时会关注:SQL 注入、XSS、CSRF、不安全的依赖等。
`,

performanceEngineer: `
你是一位性能优化专家,擅长前端和后端性能调优。
你的分析方法:
1. 识别瓶颈(CPU、内存、网络、I/O)
2. 测量基准性能
3. 应用优化策略
4. 验证改进效果
`,

uxDesigner: `
你是一位 UX 设计师,专注于用户体验和交互设计。
你评估产品时关注:
- 用户旅程的流畅性
- 信息架构的合理性
- 交互反馈的及时性
- 可访问性(a11y)
- 错误处理的友好性
`,

// ... 添加更多角色
};

// 每天用不同角色分析同一个问题

4.2 实战项目库

初级项目(1-3 天)

项目 1: AI 翻译助手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 特色:支持多种翻译风格
const translator = {
async translate(text, targetLang, style = 'formal') {
const styles = {
formal: '正式商务风格',
casual: '日常口语风格',
technical: '技术文档风格',
literary: '文学翻译风格'
};

const prompt = `
将以下文本翻译成${targetLang},使用${styles[style]}

${text}

翻译要求:
1. 准确传达原意
2. 符合目标语言习惯
3. 保留专有名词
4. ${style === 'technical' ? '保留技术术语的准确性' : ''}
`;

return await ai.chat([{ role: 'user', content: prompt }]);
}
};

项目 2: 代码注释生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 自动为代码添加详细注释
async function addComments(code, language) {
const response = await ai.chat([{
role: 'user',
content: `
为以下${language}代码添加详细注释:

\`\`\`${language}
${code}
\`\`\`

注释要求:
1. 函数功能说明
2. 参数解释
3. 返回值说明
4. 关键逻辑的行内注释
5. 复杂算法的步骤说明

输出完整的带注释代码:
`
}]);

return response.content;
}

项目 3: 智能邮件回复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 根据邮件内容生成合适的回复
async function generateEmailReply(email, tone = 'professional') {
const response = await ai.chat([{
role: 'user',
content: `
收到以下邮件:

---
${email}
---

请生成一封${tone}风格的回复邮件。

回复要求:
1. 针对邮件中的每个问题
2. 语气${tone === 'professional' ? '专业礼貌' : '友好随和'}
3. 简洁清晰
4. 包含适当的问候和结束语

邮件格式:
主题:Re: [原主题]
正文:
[回复内容]
`
}]);

return response.content;
}

中级项目(1-2 周)

项目 4: AI 代码审查机器人

  • 集成 GitHub API
  • 自动审查 PR
  • 提供修改建议
  • 生成审查报告

项目 5: 智能文档问答系统

  • RAG 架构
  • 向量数据库存储
  • 语义搜索
  • 对话式交互

项目 6: AI 内容创作平台

  • 多种内容类型(博客、社媒、邮件)
  • SEO 优化
  • 配图生成
  • 定时发布

高级项目(1 个月+)

项目 7: AI Agent 开发框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 完整的 Agent 框架
class AgentFramework:
def __init__(self):
self.llm = ChatOpenAI()
self.tools = ToolRegistry()
self.memory = ConversationMemory()
self.planner = TaskPlanner()

async def execute(self, goal):
# 1. 分析目标
analysis = await self.analyze_goal(goal)

# 2. 制定计划
plan = await self.planner.create_plan(analysis)

# 3. 执行步骤
for step in plan.steps:
result = await self.execute_step(step)

# 4. 自我反思
if not result.success:
await self.reflect_and_replan(step, result)

# 5. 总结
return await self.summarize_results()

async def execute_step(self, step):
tool = self.tools.get(step.tool)
return await tool.execute(step.params)

async def reflect_and_replan(self, step, result):
reflection = await self.llm.analyze_failure(step, result)
new_plan = await self.planner.replan(reflection)
return new_plan

项目 8: 企业级 AI 助手

  • 多用户管理
  • 权限控制
  • 数据隔离
  • 成本追踪
  • 审计日志

##五、进阶资源

5.1 必读书籍

基础级

  • 📚 《ChatGPT 提示工程》- 快速入门
  • 📚 《AI 超级个体》- 提升个人效率
  • 📚 《Prompt Engineering for Developers》(DeepLearning.AI 课程)

进阶级

  • 📚 《Building LLM Applications》- 实战开发
  • 📚 《Designing Machine Learning Systems》- 系统设计
  • 📚 《The AI Engineer’s Handbook》- 工程实践

5.2 在线课程

免费课程

付费课程

  • 🎓 Udemy: “The Complete AI & Machine Learning Bootcamp”
  • 🎓 Coursera: “AI For Everyone” (Andrew Ng)

5.3 实践平台

Prompt 练习

代码练习

5.4 社区和资源

中文社区

  • 🌐 AI 研习社
  • 🌐 掘金 AI 专区
  • 🌐 知乎 AI 话题

英文社区

Newsletter

  • 📧 The Batch (deeplearning.ai)
  • 📧 AI Breakfast (中文)
  • 📧 Ben’s Bites

六、职业发展建议

6.1 AI 时代的职业方向

1. AI 应用开发工程师

技能要求:

  • ✅ LLM API 集成
  • ✅ Prompt Engineering
  • ✅ RAG 系统开发
  • ✅ Agent 框架使用

薪资范围: ¥30-80K/月
需求程度: ⭐⭐⭐⭐⭐

2. AI 产品经理

技能要求:

  • ✅ AI 能力边界理解
  • ✅ 场景判断
  • ✅ Prompt 设计
  • ✅ 体验优化

薪资范围: ¥25-60K/月
需求程度: ⭐⭐⭐⭐

3. Prompt Engineer

技能要求:

  • ✅ 深度 Prompt 优化
  • ✅ 多模型对比
  • ✅ 场景适配
  • ✅ 效果评估

薪资范围: ¥20-50K/月
需求程度: ⭐⭐⭐

4. AI 内容创作者

技能要求:

  • ✅ AI 工具组合使用
  • ✅ 内容策划
  • ✅ 质量把控
  • ✅ SEO 优化

薪资范围: ¥15-40K/月
需求程度: ⭐⭐⭐⭐

6.2 技能认证

OpenAI 认证

  • ChatGPT Power User
  • OpenAI API Developer

云厂商认证

  • AWS Machine Learning Specialty
  • Google Cloud ML Engineer
  • Azure AI Engineer

行业认证

  • AI Product Manager (AIPM)
  • Prompt Engineering Professional

6.3 个人品牌建设

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 建立个人 AI 品牌的路线图
const personalBrandRoadmap = {
phase1: {
duration: '1-3 个月',
goals: [
'每周发布 2-3 篇技术文章',
'在 GitHub 开源 2-3 个 AI 项目',
'建立个人工具库和 Prompt 库'
],
platforms: ['掘金', '知乎', 'GitHub']
},

phase2: {
duration: '3-6 个月',
goals: [
'成为某个 AI 工具/领域的专家',
'制作教程视频或课程',
'参与技术会议分享',
'贡献开源项目'
],
platforms: ['B站', 'YouTube', 'Twitter']
},

phase3: {
duration: '6-12 个月',
goals: [
'出版技术书籍或付费课程',
'建立个人技术产品',
'成为行业 KOL',
'接商业咨询项目'
],
platforms: ['个人网站', '付费社群', '咨询服务']
}
};

七、常见问题解答

Q1: 我不是程序员,能学 AI 技能吗?

A: 完全可以!AI 技能不等于编程。

非程序员的学习路线:

  1. 第一步:学会使用 ChatGPT/Claude(1 周)
  2. 第二步:掌握 Prompt Engineering(2-4 周)
  3. 第三步:使用 No-Code 工具(Zapier、Make)(1-2 个月)
  4. 第四步:学习基础的 API 集成(可选,3 个月+)

推荐工具:

  • ChatGPT、Claude(日常使用)
  • Notion AI(笔记管理)
  • Jasper(内容创作)
  • Zapier(工作流自动化)

Q2: 学习 AI 需要数学和算法基础吗?

A: 看你的目标:

  • 使用 AI 工具:不需要 ❌
  • API 集成开发:不需要 ❌
  • Fine-tuning 模型:需要基础 ⚠️
  • 从零训练模型:需要深厚基础 ✅

大部分人的目标是前两者,所以不用担心数学。

Q3: 应该先学哪个 AI 工具?

A: 推荐顺序:

  1. ChatGPT(必学,基础中的基础)
  2. GitHub Copilot(如果你是程序员)
  3. Claude(长文本处理)
  4. Midjourney(如果需要图像)

不要贪多,精通 1-2 个工具比浅尝 10 个工具更有价值。

Q4: AI 会取代我的工作吗?

A: 更准确的说法是:

❌ AI 不会直接取代你
会用 AI 的人会取代不会用的人

应对策略:

  1. 学习使用 AI 提升效率
  2. 专注 AI 难以替代的能力(创造力、同理心、判断力)
  3. 成为 AI + 你的领域的复合型人才

Q5: 学习 AI 技能要花多少钱?

A: 完全可以零成本起步:

免费资源:

  • ChatGPT Free
  • Claude Free
  • Codeium(代码助手)
  • 各种开源教程和课程

付费推荐(可选):

  • ChatGPT Plus: $20/月(性价比最高)
  • GitHub Copilot: $10/月(程序员必备)
  • 在线课程: ¥99-999(一次性投入)

总计:¥0-300/月

结语:AI 技能是这个时代的”新英语”

还记得 20 年前,”会不会用电脑”是一个区分职场人的重要标准吗?

今天,AI 技能正在成为新的分界线。

但好消息是:学习 AI 技能比学英语容易得多

你不需要:

  • ❌ 多年的积累
  • ❌ 天赋或背景
  • ❌ 昂贵的投入

你只需要:

  • ✅ 开始使用
  • ✅ 持续练习
  • ✅ 实际应用

今天就开始,三个月后的你会感谢现在的决定。


附录:快速参考

AI 工具速查表

场景 首选工具 备选工具 成本
文本创作 ChatGPT Claude $0-20/月
代码开发 Cursor GitHub Copilot $10-20/月
图像生成 Midjourney DALL-E $10-60/月
数据分析 ChatGPT Code Interpreter Julius AI $0-20/月
自动化 Zapier Make $0-30/月

Prompt 快速模板

【代码审查】
审查以下{language}代码,关注{关注点}:
[代码]

【文案改写】
将以下内容改写为{风格}风格,目标受众是{受众}:
[内容]

【数据分析】
分析以下数据,找出{分析目标}:
[数据]

【问题解决】
问题:{问题描述}
限制条件:{限制}
期望输出:{输出格式}

开始你的 AI 技能之旅吧!🚀

关注我,持续分享 AI 实战经验和技巧!


深入理解 Model Context Protocol:从零构建 AI 知识库服务

深入理解 Model Context Protocol:从零构建 AI 知识库服务

本文通过一个真实的 MCP Server 项目,详细介绍 Model Context Protocol 的核心概念、架构设计和最佳实践。

引言:AI 交互的新范式

在与 ChatGPT、Claude 等 AI 助手交互时,我们常常遇到一个问题:AI 无法访问我们的私有数据、企业知识库或实时信息。虽然 RAG(Retrieval-Augmented Generation)技术提供了一种解决方案,但实现起来往往需要复杂的向量数据库、Embedding 模型和检索系统。

Model Context Protocol (MCP) 提供了一个更加优雅的解决方案——一个开放的标准协议,让 AI 应用能够安全、可控地访问外部数据源和工具。

什么是 MCP?

Model Context Protocol(模型上下文协议)是由 Anthropic 推出的开放标准,用于连接 AI 应用与外部数据源。它的核心思想很简单:

AI 应用 ←→ MCP 协议 ←→ MCP Server ←→ 数据源

核心优势:

  1. 标准化通信:统一的协议规范,无需为每个 AI 应用单独开发接口
  2. 工具化能力:将复杂的数据查询封装为简单的工具调用
  3. 安全可控:Server 端控制数据访问权限和范围
  4. 可扩展性:轻松添加新的数据源和功能

实战:构建一个知识库 MCP Server

让我以一个真实项目为例——Jue 知识库 MCP Server,展示如何从零构建一个功能完整的 MCP 服务。

项目架构

Claude Desktop / AI Agent
      ↓
   MCP Protocol (stdio)
      ↓
   MCP Server (Node.js)
    ├── Tools Router         # 工具路由
    ├── Services Layer       # 业务逻辑层
    │   ├── articleService   # 文章服务
    │   ├── userService      # 用户服务
    │   └── analyticsService # 分析服务
    └── HTTP Client          # 远程 API 调用

第一步:初始化 MCP Server

首先安装 MCP SDK:

1
npm install @modelcontextprotocol/sdk dotenv

创建服务器实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

// 创建 MCP 服务器
const server = new Server(
{
name: 'jue-knowledge-base',
version: '1.0.0',
},
{
capabilities: {
tools: {}, // 声明支持工具能力
},
}
);

关键点:

  • 使用 StdioServerTransport 进行标准输入输出通信
  • MCP 采用 JSON-RPC 协议进行消息传递
  • 服务器通过 stdio 与 AI 应用通信,无需网络端口

第二步:定义工具(Tools)

MCP 的核心概念是”工具”——AI 可以调用的函数。每个工具需要定义:

  1. 名称(name):工具的唯一标识符
  2. 描述(description):告诉 AI 这个工具能做什么
  3. 参数模式(inputSchema):使用 JSON Schema 定义参数

示例:定义”按作者搜索文章”工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const TOOLS = [
{
name: 'search_articles_by_author',
description: '根据作者昵称或用户ID查找该作者发表的所有文章,支持分页',
inputSchema: {
type: 'object',
properties: {
author: {
type: 'string',
description: '作者的昵称或用户ID',
},
page: {
type: 'number',
description: '页码,默认为1',
default: 1,
},
limit: {
type: 'number',
description: '每页数量,默认为20',
default: 20,
},
sortBy: {
type: 'string',
enum: ['latest', 'popular', 'views'],
description: '排序方式: latest(最新), popular(最受欢迎), views(阅读量)',
default: 'latest',
},
},
required: ['author'],
},
},
];

设计技巧:

  • 描述要清晰明确,让 AI 能理解何时使用这个工具
  • 使用 enum 限制参数值范围,避免无效调用
  • 合理设置 default 值,简化 AI 的调用
  • 标注 required 字段,确保必要参数不缺失

第三步:注册请求处理器

MCP Server 需要处理两类请求:

1. 工具列表请求(List Tools)

当 AI 需要知道有哪些可用工具时:

1
2
3
4
5
6
7
import { ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';

server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: TOOLS,
};
});

2. 工具调用请求(Call Tool)

当 AI 实际调用某个工具时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';

server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;

try {
switch (name) {
case 'search_articles_by_author': {
const result = await articleService.searchByAuthor(
args.author,
args.page || 1,
args.limit || 20,
args.sortBy || 'latest'
);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}

// ... 其他工具的处理逻辑

default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error.message,
stack: error.stack,
}),
},
],
isError: true,
};
}
});

最佳实践:

  • 使用 switch 语句清晰地路由不同的工具调用
  • 统一的错误处理,返回结构化的错误信息
  • 返回 JSON 格式数据,便于 AI 理解和处理

第四步:实现业务逻辑层

将数据获取逻辑封装到独立的服务模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// services/articleService.js
import * as http from './httpClient.js';

export async function searchByAuthor(author, page = 1, limit = 20, sortBy = 'latest') {
try {
// 1. 获取用户信息
const userData = await http.get('/view/users', {});
const user = userData.users.find(u =>
u.nickname.toLowerCase().includes(author.toLowerCase()) ||
u._id === author
);

if (!user) {
return {
success: false,
message: '未找到该作者',
data: [],
};
}

// 2. 获取文章列表
const articleData = await http.get('/user/getArticleList', {
userId: user._id,
page,
});

// 3. 排序处理
let articles = articleData || [];
switch (sortBy) {
case 'popular':
articles.sort((a, b) => (b.likeNum || 0) - (a.likeNum || 0));
break;
case 'views':
articles.sort((a, b) => (b.readNum || 0) - (a.readNum || 0));
break;
case 'latest':
default:
articles.sort((a, b) =>
new Date(b.meta?.updatedAt || 0) - new Date(a.meta?.updatedAt || 0)
);
break;
}

return {
success: true,
data: {
author: {
id: user._id,
nickname: user.nickname,
headImg: user.headImg,
articleNum: user.articleNum,
totalLikes: user.like,
},
articles: articles.slice(0, limit),
pagination: {
page,
limit,
total: articles.length,
pages: Math.ceil(articles.length / limit),
},
},
};
} catch (error) {
console.error('searchByAuthor error:', error);
return {
success: false,
message: error.message,
data: [],
};
}
}

架构优势:

  • 分层清晰:MCP Server 只负责协议处理,业务逻辑在 Service 层
  • 易于测试:Service 函数可以独立单元测试
  • 可复用:业务逻辑可以被其他接口复用

第五步:HTTP 客户端封装

为了访问远程 API,我们需要一个简洁的 HTTP 客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// services/httpClient.js
const BASE_URL = 'https://jue.leheavengame.com/api';

async function request(method, path, data = null) {
const url = `${BASE_URL}${path}`;

const options = {
method,
headers: {
'Content-Type': 'application/json',
'User-Agent': 'MCP-Server/1.0',
},
};

if (data && method === 'GET') {
const params = new URLSearchParams(data);
const fullUrl = `${url}?${params}`;
const response = await fetch(fullUrl, options);
return await handleResponse(response);
} else if (data) {
options.body = JSON.stringify(data);
const response = await fetch(url, options);
return await handleResponse(response);
}

const response = await fetch(url, options);
return await handleResponse(response);
}

async function handleResponse(response) {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const result = await response.json();

if (result.code !== 200) {
throw new Error(result.message || 'API request failed');
}

return result.data;
}

export async function get(path, params = null) {
return request('GET', path, params);
}

export async function post(path, data = null) {
return request('POST', path, data);
}

设计考虑:

  • 统一的错误处理和响应格式
  • 自动处理 GET 参数和 POST body
  • 添加自定义 User-Agent 标识

第六步:启动 MCP Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
async function main() {
try {
console.error('🚀 Jue MCP Server starting...');
console.error('📡 Using API endpoint: https://jue.leheavengame.com/api');

// 创建 stdio 传输层
const transport = new StdioServerTransport();

// 连接服务器和传输层
await server.connect(transport);

console.error('✅ Jue MCP Server running on stdio');
} catch (error) {
console.error('❌ Failed to start server:', error);
process.exit(1);
}
}

// 优雅关闭
process.on('SIGINT', async () => {
console.error('\n⏹️ Shutting down...');
process.exit(0);
});

main();

注意事项:

  • 日志输出使用 console.error,因为 stdout 用于 MCP 通信
  • 监听 SIGINT 信号,实现优雅关闭
  • 使用 async/await 处理异步操作

配置 Claude Desktop 使用 MCP Server

1. 配置文件位置

Windows: %APPDATA%\Claude\claude_desktop_config.json
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

2. 添加配置

1
2
3
4
5
6
7
8
{
"mcpServers": {
"jue-knowledge-base": {
"command": "node",
"args": ["E:\\D盘\\github\\mcp-server-jue-article\\index.js"]
}
}
}

3. 重启 Claude Desktop

配置完成后重启 Claude,就可以看到新的工具出现在界面上。

实际使用场景

场景 1:研究作者内容

用户:帮我查找"张三"写的所有文章,按阅读量排序

Claude:
[调用 search_articles_by_author 工具]
参数:
- author: "张三"
- sortBy: "views"
- limit: 20

结果:
找到该作者共发表 25 篇文章,按阅读量排序前 5 篇为:
1. 《深入理解 React Hooks》- 5.2万阅读
2. 《前端性能优化实战》- 4.8万阅读
...

场景 2:内容趋势分析

用户:分析一下这周的内容表现如何

Claude:
[调用 get_content_summary 工具]
参数:
- timeRange: "week"

[调用 get_trending_tags 工具]
参数:
- limit: 10

综合分析:
本周共产出 156 篇文章,总阅读量达到 280万...
热门标签包括:前端开发、人工智能、架构设计...

场景 3:用户画像分析

用户:查询用户"李四"的创作情况

Claude:
[调用 get_user_stats 工具]
参数:
- userId: "李四"

该用户是活跃创作者:
- 累计发表:42 篇文章
- 总阅读量:15.8万
- 总获赞数:3,200
- 粉丝数量:580
- 最热文章:《微服务架构实践》(1.2万阅读)

项目中的高级工具设计

1. 多参数智能路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
name: 'get_article_recommendations',
description: '根据文章ID或标签获取推荐的相关文章',
inputSchema: {
type: 'object',
properties: {
articleId: {
type: 'string',
description: '参考文章ID',
},
tagId: {
type: 'string',
description: '标签ID(如果不提供articleId)',
},
limit: {
type: 'number',
description: '推荐数量,默认为5',
default: 5,
},
},
},
}

这个工具展示了灵活的参数设计:

  • 支持两种推荐方式:基于文章或基于标签
  • AI 会根据上下文自动选择合适的参数
  • 不强制要求所有参数,提高可用性

2. 数据分析工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
name: 'analyze_engagement',
description: '分析文章的互动数据,包括点赞、评论、阅读等指标',
inputSchema: {
type: 'object',
properties: {
articleId: {
type: 'string',
description: '文章ID',
},
},
required: ['articleId'],
},
}

返回结构化的分析结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
success: true,
data: {
article: { ... },
metrics: {
views: 5000,
likes: 200,
comments: 50
},
rates: {
engagementRate: 5.0, // 互动率
likeRate: 4.0, // 点赞率
commentRate: 1.0 // 评论率
},
performance: {
isHot: true, // 是否热门
isPopular: true, // 是否受欢迎
isActive: true // 是否活跃
}
}
}

设计亮点:

  • 不仅返回原始数据,还提供计算后的指标
  • 布尔值判断(isHot、isPopular)让 AI 更容易理解
  • 结果分层清晰,便于后续处理

3. 时间范围过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
name: 'get_top_articles_by_views',
description: '获取阅读量最高的文章列表,可按标签筛选,可指定时间范围',
inputSchema: {
type: 'object',
properties: {
limit: {
type: 'number',
description: '返回文章数量,默认为10',
default: 10,
},
tagId: {
type: 'string',
description: '标签ID,可选,不填则查询所有标签',
},
timeRange: {
type: 'string',
enum: ['all', 'today', 'week', 'month', 'year'],
description: '时间范围筛选',
default: 'all',
},
},
},
}

使用 enum 提供预定义的时间范围选项,AI 能够理解用户的自然语言意图(”本周”、”最近一个月”)并映射到正确的参数值。

MCP vs RAG:何时选择哪种方案?

维度 MCP RAG
适用场景 结构化数据查询、API 调用、工具集成 非结构化文本、语义搜索、知识库问答
实现复杂度 低(无需向量化) 高(需要 Embedding + 向量数据库)
数据实时性 实时(直接调用 API) 延迟(需要定期索引)
精确度 精确匹配 语义相似
成本 高(存储和计算成本)

建议:

  • 选择 MCP:API 接口、数据库查询、第三方服务集成、实时数据
  • 选择 RAG:文档问答、长文本理解、语义搜索、历史数据
  • 组合使用:先用 RAG 找到相关文档,再用 MCP 获取精确数据

开发中的调试技巧

1. 使用 MCP CLI 工具测试

安装官方 CLI:

1
npm install -g @modelcontextprotocol/cli

查看工具列表:

1
npx @modelcontextprotocol/cli inspect --stdio -- node index.js

调用工具:

1
2
3
npx @modelcontextprotocol/cli call --stdio -- node index.js \
search_articles_by_author \
--arg author="测试用户"

2. 日志调试

1
2
3
4
// 使用 console.error 输出日志,不干扰 stdio 通信
console.error('📝 Tool called:', name);
console.error('📦 Arguments:', JSON.stringify(args, null, 2));
console.error('✅ Result:', JSON.stringify(result, null, 2));

3. 错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
try {
const result = await someService.getData();
return {
content: [{
type: 'text',
text: JSON.stringify(result, null, 2),
}],
};
} catch (error) {
// 返回友好的错误信息
return {
content: [{
type: 'text',
text: JSON.stringify({
success: false,
error: error.message,
tip: '请检查参数是否正确或稍后重试',
}),
}],
isError: true,
};
}

性能优化建议

1. 实现缓存机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const cache = new Map();

export async function getUserStats(userId) {
const cacheKey = `user_stats_${userId}`;

// 检查缓存
if (cache.has(cacheKey)) {
const cached = cache.get(cacheKey);
if (Date.now() - cached.timestamp < 5 * 60 * 1000) { // 5分钟
return cached.data;
}
}

// 获取数据
const data = await fetchUserStats(userId);

// 写入缓存
cache.set(cacheKey, {
data,
timestamp: Date.now(),
});

return data;
}

2. 并发请求优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export async function getContentSummary(timeRange) {
// 并发获取多个数据源
const [articles, tags, users] = await Promise.all([
http.get('/view/articles'),
http.get('/view/tags'),
http.get('/view/users'),
]);

// 汇总分析
return {
success: true,
data: {
articleCount: articles.length,
tagCount: tags.length,
userCount: users.length,
...summarizeData(articles, tags, users)
}
};
}

3. 分页和限制

1
2
3
4
5
6
7
8
9
10
11
12
export async function searchByKeyword(keyword, searchIn, page = 1, limit = 20) {
// 限制每页最大数量
const maxLimit = 100;
const safeLimit = Math.min(limit, maxLimit);

// 分页逻辑
const startIndex = (page - 1) * safeLimit;
const endIndex = startIndex + safeLimit;

// 只返回当前页数据
return results.slice(startIndex, endIndex);
}

安全性考虑

1. 参数验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;

// 验证必需参数
if (name === 'search_articles_by_author' && !args.author) {
return {
content: [{
type: 'text',
text: JSON.stringify({
success: false,
error: 'Parameter "author" is required',
}),
}],
isError: true,
};
}

// 验证参数类型和范围
if (args.page && (typeof args.page !== 'number' || args.page < 1)) {
return {
content: [{
type: 'text',
text: JSON.stringify({
success: false,
error: 'Parameter "page" must be a positive number',
}),
}],
isError: true,
};
}

// 执行工具逻辑
// ...
});

2. 限流控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const rateLimiter = new Map();

function checkRateLimit(toolName) {
const now = Date.now();
const limit = rateLimiter.get(toolName) || { count: 0, resetAt: now };

if (now > limit.resetAt) {
// 重置计数
rateLimiter.set(toolName, { count: 1, resetAt: now + 60000 }); // 1分钟
return true;
}

if (limit.count >= 60) { // 每分钟最多60次
return false;
}

limit.count++;
return true;
}

3. 数据脱敏

1
2
3
4
5
6
7
8
9
10
11
function sanitizeUserData(user) {
return {
id: user._id,
nickname: user.nickname,
headImg: user.headImg,
articleNum: user.articleNum,
// 移除敏感信息
// email: user.email, ❌
// phone: user.phone, ❌
};
}

扩展思路

1. 添加新工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 定义工具
{
name: 'export_article_report',
description: '导出文章数据报告',
inputSchema: {
type: 'object',
properties: {
format: {
type: 'string',
enum: ['json', 'csv', 'markdown'],
default: 'markdown'
},
includeStats: {
type: 'boolean',
default: true
}
}
}
}

// 实现逻辑
case 'export_article_report': {
const report = await analyticsService.generateReport(
args.format,
args.includeStats
);
return {
content: [{
type: 'text',
text: report,
}],
};
}

2. 集成更多数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// services/githubService.js
export async function searchRepositories(query) {
const response = await fetch(
`https://api.github.com/search/repositories?q=${query}`,
{
headers: {
'Authorization': `token ${process.env.GITHUB_TOKEN}`,
}
}
);
return await response.json();
}

// 添加到工具列表
{
name: 'search_github_repos',
description: '搜索 GitHub 仓库',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: '搜索关键词' }
},
required: ['query']
}
}

3. 支持 Resources(未来功能)

MCP 协议还支持 Resources 和 Prompts,未来可以扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 提供文章内容作为 Resource
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: 'jue://articles/123',
name: '文章标题',
mimeType: 'text/markdown',
}
]
};
});

// 提供预设 Prompt
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: 'analyze_article',
description: '深度分析文章',
arguments: [
{ name: 'articleId', required: true }
]
}
]
};
});

最佳实践总结

✅ 做什么

  1. 工具描述要详细:让 AI 能准确理解工具的用途和场景
  2. 使用 enum 限制参数:避免无效值,提升调用成功率
  3. 返回结构化数据:使用一致的 JSON 格式
  4. 错误处理友好:返回清晰的错误信息和建议
  5. 分层架构:MCP Server、Service、HTTP Client 职责分离
  6. 添加日志:使用 console.error 输出关键信息
  7. 实现缓存:减少不必要的 API 调用
  8. 参数验证:在服务端验证所有输入

❌ 不要做什么

  1. 不要用 console.log:会污染 stdio 通信
  2. 不要返回过大数据:合理使用分页和限制
  3. 不要暴露敏感信息:脱敏处理用户数据
  4. 不要阻塞主线程:使用 async/await 处理异步操作
  5. 不要忽略错误:所有异常都要捕获和处理
  6. 不要假设参数存在:使用默认值和可选链
  7. 不要硬编码配置:使用环境变量
  8. 不要跳过参数验证:验证类型、范围和格式

未来展望

MCP 协议还在快速发展中,未来可能的方向:

  1. Resources 支持:让 AI 直接访问文件、数据库记录等资源
  2. Prompts 功能:提供预设的 Prompt 模板
  3. 流式响应:支持大数据量的流式传输
  4. 双向通信:Server 主动推送通知
  5. 权限系统:细粒度的访问控制
  6. 监控和日志:标准化的可观测性

总结

Model Context Protocol 为 AI 应用提供了一个优雅的扩展能力框架。通过本文的实战项目,我们看到:

  1. 简单灵活:相比 RAG,MCP 实现更简单,适合结构化数据
  2. 标准协议:一套代码,多个 AI 应用复用
  3. 可扩展性:轻松添加新工具和数据源
  4. 生产就绪:通过合理的架构设计,可以支撑生产环境

如果你正在构建 AI 应用,需要访问私有数据或第三方 API,MCP 是一个值得尝试的方案。

参考资源


关注我,获取更多 AI 开发实战内容!

本文项目代码已开源,欢迎 Star 和 PR。

  

从零打造一个跨框架通用的 AI Agent 插件

📝 前言

在 AI 大模型时代,越来越多的 Web 应用需要集成智能对话功能。然而,前端技术栈的多样性(Vue、React、jQuery 等)给开发者带来了一个难题:如何开发一个一次编写、到处运行的 AI 对话插件?

本文记录了 AI Agent Plugin 项目从诞生到完成的全过程,分享技术选型、架构设计、核心实现以及遇到的挑战与解决方案。


🎯 项目背景与目标

痛点分析

在实际项目中,我们遇到以下问题:

  1. 技术栈碎片化:公司不同项目使用 Vue 2、Vue 3、React、jQuery 等不同技术栈
  2. 重复开发成本高:每个技术栈都要单独开发一套 AI 对话组件
  3. 维护困难:功能更新需要同步修改多个版本
  4. 样式冲突:插件样式容易被宿主项目覆盖

设计目标

基于以上痛点,我们确定了以下核心目标:

  • 跨框架兼容:一套代码支持 Vue、React、jQuery 等任意前端框架
  • 零依赖:不依赖任何第三方框架,纯原生实现
  • 样式隔离:避免与宿主项目样式冲突
  • TypeScript 支持:提供完整的类型定义
  • 主题定制:支持浅色/深色主题和自定义配色
  • 灵活配置:支持流式/普通响应、四角定位等

🏗️ 技术选型与架构设计

1. 模块化规范:UMD

为了实现跨框架兼容,我们选择了 UMD (Universal Module Definition) 规范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// UMD 模式可以同时支持多种加载方式
// 1. AMD (RequireJS)
// 2. CommonJS (Node.js)
// 3. 全局变量 (浏览器直接引入)
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory); // AMD
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(); // CommonJS
} else {
root.AIAgent = factory(); // 全局变量
}
}(typeof self !== 'undefined' ? self : this, function () {
// 插件代码
}));

通过 Webpack 的 output.library 配置,我们可以自动生成 UMD 格式的代码:

1
2
3
4
5
6
7
8
9
10
11
// webpack.config.js
output: {
filename: 'ai-agent.js',
path: path.resolve(__dirname, 'dist'),
library: {
name: 'AIAgent',
type: 'umd',
export: 'default'
},
globalObject: 'this'
}

2. 开发语言:TypeScript

使用 TypeScript 开发带来的优势:

  1. 类型安全:编译时捕获错误,减少运行时 bug
  2. 智能提示:IDE 提供完整的代码提示和自动补全
  3. 可维护性:接口定义即文档,代码意图清晰

核心类型定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export interface AIAgentOptions {
host?: string; // 后端域名
secret?: string; // API 密钥
stream?: boolean; // 流式响应
theme?: 'light' | 'dark'; // 主题
colors?: { // 自定义配色
primary?: string;
background?: string;
text?: string;
aiMessageBg?: string;
// ... 更多颜色配置
};
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
placeholder?: string;
title?: string;
}

3. 样式隔离:命名空间 + CSS 变量

为了避免样式冲突,我们采用了两种策略:

策略一:命名空间隔离

所有 CSS 类名添加 ai-agent- 前缀:

1
2
3
.ai-agent-panel { /* 面板 */ }
.ai-agent-btn { /* 按钮 */ }
.ai-agent-msg { /* 消息 */ }

策略二:CSS 变量动态主题

使用 CSS 变量实现主题定制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
:root {
--ai-agent-primary: #4096ff;
--ai-agent-primary-hover: #2e80ff;
--ai-agent-bg: #ffffff;
--ai-agent-text: #333333;
/* ... 更多变量 */
}

/* 浅色主题 */
.ai-agent-theme-light {
--ai-agent-bg: #ffffff;
--ai-agent-text: #333333;
}

/* 深色主题 */
.ai-agent-theme-dark {
--ai-agent-bg: #1e1e1e;
--ai-agent-text: #f0f0f0;
}

通过 JavaScript 动态注入自定义颜色:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private injectStyles(): void {
const style = document.createElement('style');
let colorVars = '';

if (this.options.colors) {
if (this.options.colors.primary) {
colorVars += `--ai-agent-primary: ${this.options.colors.primary};\n`;
}
// ... 注入更多颜色变量
}

style.textContent = `
${colorVars ? `.ai-agent-theme-${this.options.theme} {\n${colorVars}}` : ''}
`;

document.head.appendChild(style);
}

🔧 核心功能实现

1. 插件生命周期管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class AIAgent {
constructor(options: AIAgentOptions) {
// 1. 参数验证
this.validateOptions(options);

// 2. 配置合并
this.options = { /* 默认配置 + 用户配置 */ };

// 3. 计算端点 URL
this.endpoints = this.calculateEndpoints();

// 4. 初始化 UI
this.init();
}

private init(): void {
this.createTriggerButton(); // 创建触发按钮
this.createChatPanel(); // 创建对话面板
this.injectStyles(); // 注入样式
}

public destroy(): void {
// 清理 DOM 元素
if (this.buttonEl) this.buttonEl.remove();
if (this.panelEl) this.panelEl.remove();

// 清理事件监听器
// 清理内存引用
this.chatHistory = [];
}
}

2. 双模式 API 调用

插件支持普通模式流式模式两种 API 调用方式:

普通模式(一次性返回)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private async sendNormalMessage(text: string): Promise<void> {
const response = await fetch(this.endpoints.completion, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.options.secret}`
},
body: JSON.stringify({
content: text,
messages: this.chatHistory
})
});

const data: ApiResponse = await response.json();
this.appendMessage(data.data.content, 'ai');
}

流式模式(SSE 实时推送)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private async sendStreamMessage(text: string): Promise<void> {
const response = await fetch(this.endpoints.stream, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.options.secret}`
},
body: JSON.stringify({
messages: this.chatHistory
})
});

const reader = response.body!.getReader();
const decoder = new TextDecoder();
let aiMessage = '';

const messageEl = this.createMessageElement('', 'ai');

while (true) {
const { done, value } = await reader.read();
if (done) break;

const chunk = decoder.decode(value);
const lines = chunk.split('\n');

for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6));
aiMessage += data.content;
messageEl.textContent = aiMessage;
}
}
}
}

3. 智能端点路由

根据配置自动选择合适的 API 端点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private calculateEndpoints() {
const baseHost = this.options.host || 'http://localhost:8080';
const normalize = (path: string) =>
baseHost.replace(/\/+$/, '') + '/' + path.replace(/^\/+/, '');

const chatBase = normalize('api/ai/chat');

return {
completion: chatBase + '/completion', // 普通模式
stream: chatBase + '/stream', // 流式模式
streamSimple: chatBase + '/stream-simple',
streamConfig: chatBase + '/stream-config',
session: normalize('api/ai/session'),
platforms: normalize('api/ai/platforms'),
fileExtraction: normalize('api/ai/file/extraction')
};
}

private sendMessage(text: string): void {
if (this.options.stream) {
this.sendStreamMessage(text); // 流式模式
} else {
this.sendNormalMessage(text); // 普通模式
}
}

🎨 主题定制系统

渐进式主题方案

我们设计了三层主题定制方案:

第一层:预设主题

1
2
3
new AIAgent({
theme: 'light' // 或 'dark'
});

第二层:自定义颜色

1
2
3
4
5
6
7
8
new AIAgent({
theme: 'light',
colors: {
primary: '#ff6b6b', // 主色调
background: '#f0f0f0', // 背景色
text: '#2c3e50' // 文本颜色
}
});

第三层:完整配色方案

1
2
3
4
5
6
7
8
9
10
11
12
new AIAgent({
colors: {
primary: '#ff6b6b',
primaryHover: '#ff5252',
background: '#f0f0f0',
text: '#2c3e50',
border: '#e0e0e0',
aiMessageBg: '#e8f5e9',
userMessageBg: '#ff6b6b',
headerBg: '#fafafa'
}
});

CSS 变量的优势

使用 CSS 变量而非直接修改样式的好处:

  1. 性能更好:浏览器原生支持,无需 JavaScript 逐个修改元素
  2. 优先级明确:CSS 变量继承机制清晰
  3. 响应式支持:可以配合媒体查询实现响应式主题
  4. 易于维护:修改一处,全局生效

🚀 打包与发布

Webpack 多产物输出

为了满足不同场景的需求,我们配置了三种输出格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// webpack.config.js
module.exports = [
// 1. UMD 格式(未压缩)
{
output: {
filename: 'ai-agent.js',
library: { name: 'AIAgent', type: 'umd' }
}
},
// 2. UMD 格式(压缩)
{
output: {
filename: 'ai-agent.min.js',
library: { name: 'AIAgent', type: 'umd' }
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin()]
}
},
// 3. ESM 格式(现代构建工具)
{
output: {
filename: 'ai-agent.esm.js',
library: { type: 'module' }
},
experiments: {
outputModule: true
}
}
];

TypeScript 类型声明

使用 ts-loader 自动生成类型声明文件:

1
2
3
4
5
6
7
8
9
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}

生成的类型文件结构:

dist/
├── ai-agent.js           # UMD 格式(未压缩)
├── ai-agent.min.js       # UMD 格式(压缩)
├── ai-agent.esm.js       # ESM 格式
└── types/
    ├── ai-agent.d.ts     # 主入口类型声明
    └── types/
        └── index.d.ts    # 类型定义

NPM 包配置

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "ai-agent-plugin",
"version": "0.0.1",
"main": "dist/ai-agent.js", // CommonJS 入口
"module": "dist/ai-agent.esm.js", // ESM 入口
"types": "dist/types/ai-agent.d.ts", // TypeScript 类型
"files": [
"dist/",
"README.md",
"LICENSE"
]
}

🎯 跨框架使用实践

1. jQuery 项目

1
2
3
4
5
6
7
8
9
10
11
12
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="path/to/ai-agent.min.js"></script>

<script>
$(document).ready(function() {
const aiAgent = new AIAgent({
host: 'http://localhost:8080',
secret: 'your-api-key',
theme: 'light'
});
});
</script>

2. React 项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React, { useEffect } from 'react';
import AIAgent from 'ai-agent-plugin';

function App() {
useEffect(() => {
const aiAgent = new AIAgent({
host: 'http://localhost:8080',
secret: process.env.REACT_APP_AI_SECRET,
theme: 'dark',
stream: true
});

return () => aiAgent.destroy();
}, []);

return <div>My App</div>;
}

3. Vue 3 项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div>My App</div>
</template>

<script setup>
import { onMounted, onUnmounted } from 'vue';
import AIAgent from 'ai-agent-plugin';

let aiAgent = null;

onMounted(() => {
aiAgent = new AIAgent({
host: 'http://localhost:8080',
secret: import.meta.env.VITE_AI_SECRET,
position: 'bottom-left',
colors: {
primary: '#42b883' // Vue 绿
}
});
});

onUnmounted(() => {
aiAgent?.destroy();
});
</script>

🐛 踩坑与解决方案

问题 1:TypeScript 类型不兼容

现象:使用 Required<AIAgentOptions> 导致可选属性变必选

1
2
3
4
5
6
7
8
9
// ❌ 错误写法
private options: Required<AIAgentOptions>;

// 构建报错:colors 是可选的,但 Required 让它变成必选
this.options = {
host: '...',
secret: '...',
// colors 未提供,报错!
};

解决方案:直接使用原接口类型

1
2
// ✅ 正确写法
private options: AIAgentOptions;

问题 2:端口占用导致开发服务器无法启动

现象Error: listen EADDRINUSE: address already in use :::9000

解决方案:PowerShell 脚本清理占用端口

1
2
3
4
# 查找并停止占用 9000 端口的进程
Get-NetTCPConnection -LocalPort 9000 -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty OwningProcess |
ForEach-Object { Stop-Process -Id $_ -Force }

问题 3:CSS 变量在 IE 中不生效

现象:IE 11 不支持 CSS 变量

解决方案:提供回退方案

1
2
3
4
.ai-agent-btn {
background: #4096ff; /* 回退值 */
background: var(--ai-agent-primary); /* CSS 变量 */
}

或者使用 PostCSS 插件自动生成回退:

1
2
3
4
5
6
7
8
// postcss.config.js
module.exports = {
plugins: [
require('postcss-custom-properties')({
preserve: false // 移除 CSS 变量,只保留回退值
})
]
};

问题 4:流式响应解析错误

现象:SSE 数据格式不规范导致解析失败

解决方案:增强容错处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (const line of lines) {
if (!line.trim() || !line.startsWith('data: ')) continue;

try {
const jsonStr = line.slice(6).trim();
if (jsonStr === '[DONE]') break; // 结束标记

const data = JSON.parse(jsonStr);
if (data.content) {
aiMessage += data.content;
}
} catch (err) {
console.warn('解析 SSE 数据失败:', line, err);
}
}

📊 性能优化

1. 代码分割与按需加载

虽然插件本身较小(~20KB),但仍可优化:

1
2
3
4
5
// 懒加载 Markdown 渲染库
private async renderMarkdown(text: string): Promise<string> {
const { marked } = await import('marked');
return marked(text);
}

2. 防抖与节流

输入框添加防抖,避免频繁触发:

1
2
3
4
5
6
7
8
9
10
11
private handleInput = debounce((text: string) => {
// 处理输入
}, 300);

function debounce(fn: Function, delay: number) {
let timer: number;
return function(...args: any[]) {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}

3. 虚拟滚动(未来规划)

对话消息过多时,使用虚拟滚动:

1
2
3
4
5
6
7
8
9
10
// 只渲染可视区域的消息
private renderVisibleMessages() {
const scrollTop = this.messagesEl.scrollTop;
const visibleHeight = this.messagesEl.clientHeight;

const startIndex = Math.floor(scrollTop / MESSAGE_HEIGHT);
const endIndex = Math.ceil((scrollTop + visibleHeight) / MESSAGE_HEIGHT);

return this.chatHistory.slice(startIndex, endIndex);
}

🔮 未来规划

短期目标(v0.1.0)

  • [ ] 支持 Markdown 渲染
  • [ ] 代码高亮显示
  • [ ] 消息历史持久化(LocalStorage)
  • [ ] 消息重发/编辑功能
  • [ ] 多语言支持(i18n)

中期目标(v0.2.0)

  • [ ] 语音输入/输出
  • [ ] 文件上传(图片、文档)
  • [ ] 多会话管理
  • [ ] 自定义快捷指令
  • [ ] WebSocket 支持

长期目标(v1.0.0)

  • [ ] 插件市场(第三方扩展)
  • [ ] AI 能力扩展(绘画、搜索、代码执行)
  • [ ] 团队协作功能
  • [ ] 移动端适配(React Native)
  • [ ] Electron 桌面应用

💡 经验总结

技术层面

  1. 选择合适的模块化规范:UMD 确实能实现跨框架兼容
  2. TypeScript 提升开发体验:类型安全减少 80% 的运行时错误
  3. CSS 变量是主题定制的最佳实践:灵活、高效、易维护
  4. 流式响应提升用户体验:实时反馈比加载动画更友好

工程层面

  1. 文档优先:README 写得好,issue 减少一半
  2. 示例丰富:提供 jQuery/React/Vue 示例,降低使用门槛
  3. 语义化版本:严格遵循 SemVer,避免破坏性更新
  4. 自动化测试(规划中):保证多框架环境下的稳定性

产品层面

  1. 保持简单:不要过度设计,先满足核心需求
  2. 渐进增强:功能分层,让用户自由选择
  3. 用户反馈驱动:根据 issue 和 PR 优化功能
  4. 社区运营:开源项目需要持续的社区互动

🙏 致谢

感谢以下开源项目的启发:

感谢所有给项目提 issue 和 PR 的开发者!


📚 参考资料


结语

从零打造一个跨框架通用插件是一次有趣的技术实践,它让我们深入理解了:

  • 模块化规范的本质
  • TypeScript 的工程化价值
  • CSS 架构的设计思想
  • 前端构建工具的工作原理

希望这篇文章能给正在开发跨框架组件的开发者一些启发。如果你有任何问题或建议,欢迎在 GitHub 上提 issue 讨论!

项目地址https://github.com/hujinbin/ai-agent
NPM 包npm install ai-agent-plugin
开源协议:MIT License


觉得有帮助?给个 ⭐ Star 吧!

AI Tools 完全指南:从选择到集成的全链路实践

AI Tools 完全指南:从选择到集成的全链路实践

一篇帮你快速掌握 AI 工具生态、选型决策和集成开发的实战手册

引言:AI 工具的爆发式增长

2023 年 ChatGPT 爆火后,AI 工具市场迎来了井喷式增长。据统计,目前市面上有超过 10,000+ 款 AI 工具,涵盖从文本生成、图像创作、代码开发到数据分析的各个领域。

作为开发者,我们面临的问题不再是”有没有 AI 工具可用”,而是:

  • 😵 选择困难:这么多工具,该用哪个?
  • 🔧 集成复杂:如何将 AI 能力集成到自己的应用中?
  • 💰 成本控制:免费还是付费?API 调用费用如何?
  • 🎯 效果评估:哪个工具真正好用?

本文将系统性地解决这些问题,帮你建立完整的 AI 工具知识体系。

一、AI Tools 全景图

1.1 按功能分类

📝 文本生成类

对话型

  • ChatGPT:OpenAI 出品,最强大的通用对话模型

    • 优势:理解能力强、知识面广
    • 适用:写作、编程、分析、翻译
    • 成本:$20/月(Plus)或按 Token 计费
  • Claude:Anthropic 出品,擅长长文本理解

    • 优势:200K 上下文窗口、安全性高
    • 适用:文档分析、长篇创作
    • 成本:免费 / Pro $20/月
  • Gemini:Google 出品,多模态能力强

    • 优势:与 Google 生态整合
    • 适用:搜索增强、多语言任务
    • 成本:免费 / Advanced $20/月
  • 文心一言:百度出品,中文优化

    • 优势:中文理解好、本地化
    • 适用:中文内容创作
    • 成本:基础免费

写作辅助

  • Jasper / Copy.ai:营销文案生成
  • Notion AI:笔记和文档协作
  • Grammarly:语法检查和改进

🎨 图像生成类

文生图

  • Midjourney:艺术性最强的 AI 绘画工具
    • 风格:艺术感强、细节丰富
    • 成本:$10-60/月
    • 使用:Discord 界面
  • DALL-E 3:OpenAI 出品,理解力强
    • 风格:准确理解复杂描述
    • 集成:ChatGPT Plus 内置
  • Stable Diffusion:开源社区驱动
    • 优势:免费、可本地部署、可微调
    • 适用:需要定制化的场景
  • Leonardo.ai:游戏和设计专用
    • 风格:适合游戏资产、角色设计

图像处理

  • Remove.bg:智能抠图
  • Topaz Photo AI:照片增强
  • ClipDrop:图像清理和编辑

💻 编程开发类

代码生成

  • GitHub Copilot:代码补全神器
    • 集成:VS Code、JetBrains
    • 成本:$10/月
    • 适用:日常编程
  • Cursor:AI-first 代码编辑器
    • 特色:多文件理解、对话式编程
    • 成本:$20/月
  • Codeium:免费的 Copilot 替代
    • 优势:完全免费
    • 支持:40+ 编程语言

代码审查

  • CodeRabbit:PR 自动审查
  • SonarCloud:代码质量分析

调试工具

  • Tabnine:智能代码补全
  • Pieces:代码片段管理

📊 数据分析类

数据处理

  • ChatGPT Code Interpreter:数据分析和可视化
  • Julius AI:对话式数据分析
  • Hex:协作数据分析平台

SQL 生成

  • Text2SQL.ai:自然语言转 SQL
  • AI2sql:SQL 查询生成
  • SQLAI.ai:数据库查询助手

🎥 音视频类

视频制作

  • Runway:AI 视频编辑
  • Descript:视频转录和编辑
  • HeyGen:AI 虚拟人视频

音频处理

  • ElevenLabs:AI 语音合成
  • Adobe Podcast:音频增强
  • Whisper:语音转文字

🔍 搜索增强类

AI 搜索引擎

  • Perplexity AI:对话式搜索
  • You.com:AI 驱动的搜索
  • Phind:开发者专用搜索

🤖 AI Agent 平台

无代码平台

  • Zapier AI:工作流自动化
  • **Make (Integromat)**:场景自动化
  • n8n:开源工作流

开发框架

  • LangChain:Agent 开发框架
  • AutoGPT:自主 AI Agent
  • GPT Engineer:AI 软件工程师

1.2 按技术栈分类

🔌 API 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
// OpenAI API
import OpenAI from 'openai';

const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});

const completion = await openai.chat.completions.create({
model: "gpt-4-turbo-preview",
messages: [
{ role: "user", content: "写一个快速排序算法" }
]
});

主流 API 服务:

  • OpenAI API
  • Anthropic Claude API
  • Google Gemini API
  • Cohere API
  • Mistral AI
  • Replicate(模型托管)

🖥️ 本地部署

开源模型:

  • Llama 3:Meta 开源大模型
  • Mistral:欧洲开源项目
  • Qwen:阿里巴巴通义千问
  • ChatGLM:清华开源模型

部署工具:

1
2
3
4
5
6
7
8
9
10
11
# Ollama - 最简单的本地 LLM 运行方式
ollama pull llama3
ollama run llama3 "写一个 Python 爬虫"

# LM Studio - GUI 界面
# 下载安装后直接运行各种开源模型

# vLLM - 高性能推理服务器
pip install vllm
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-2-7b-chat-hf

🌐 Web 应用

直接使用的在线工具:

  • ChatGPT Web
  • Claude.ai
  • Poe(多模型聚合)
  • HuggingChat(开源模型)

二、AI Tools 选型决策树

2.1 根据需求选工具

场景 1:写技术博客

需求:撰写一篇技术博客文章

决策流程:
1. 内容深度?
   - 入门级 → ChatGPT
   - 深度技术 → Claude (长上下文)

2. 语言?
   - 中文 → 文心一言 / ChatGPT
   - 英文 → ChatGPT / Claude

3. 需要图表?
   - 是 → ChatGPT (Code Interpreter)
   - 否 → 任意文本工具

推荐组合:
- 主写作:Claude(长文档理解好)
- 代码生成:GitHub Copilot
- 配图:Midjourney / Leonardo.ai
- 排版:Notion AI

场景 2:开发一个功能

需求:为项目添加新功能

决策流程:
1. 代码复杂度?
   - 简单 → GitHub Copilot 补全
   - 复杂 → Cursor 对话式开发

2. 预算?
   - 有预算 → Cursor / GitHub Copilot
   - 无预算 → Codeium

3. 需要理解整个项目?
   - 是 → Cursor(多文件上下文)
   - 否 → GitHub Copilot

推荐组合:
- 编码:Cursor
- 代码审查:CodeRabbit
- 测试用例:ChatGPT
- 文档:Notion AI

场景 3:数据分析任务

需求:分析业务数据并生成报告

决策流程:
1. 数据规模?
   - 小(< 100MB)→ ChatGPT Code Interpreter
   - 大(> 100MB)→ 专业工具(Hex / Julius)

2. 技术能力?
   - 会编程 → Jupyter + Copilot
   - 不会编程 → Julius AI(对话式)

3. 协作需求?
   - 需要 → Hex(团队协作)
   - 不需要 → ChatGPT

推荐组合:
- 数据分析:Julius AI / ChatGPT
- SQL 查询:Text2SQL.ai
- 可视化:ChatGPT Code Interpreter
- 报告撰写:Claude

场景 4:内容创作

需求:社交媒体内容批量生成

决策流程:
1. 内容类型?
   - 文字 → ChatGPT / Jasper
   - 图片 → Midjourney / DALL-E
   - 视频 → Runway / HeyGen

2. 批量程度?
   - 个位数 → 手动使用
   - 批量 → API 集成

3. 风格一致性?
   - 需要 → Midjourney(保存风格参数)
   - 不需要 → 随意选择

推荐组合:
- 文案:ChatGPT + Jasper
- 配图:Midjourney
- 视频:Runway
- 排期:Zapier(自动化发布)

2.2 成本效益分析

免费方案(适合个人/小团队)

方案 A:完全免费
- LLM:Claude Free / ChatGPT Free
- 代码:Codeium
- 图像:Stable Diffusion(本地)
- 搜索:Perplexity Free

总成本:$0/月
限制:有调用次数限制、无高级功能

经济型方案($20-50/月)

方案 B:性价比高
- LLM:ChatGPT Plus ($20)
- 代码:GitHub Copilot ($10)
- 图像:Midjourney Basic ($10)

总成本:$40/月
适合:个人开发者、自由职业者

专业方案($100-300/月)

方案 C:全功能
- LLM:ChatGPT Plus + Claude Pro ($40)
- 代码:Cursor ($20) + GitHub Copilot ($10)
- 图像:Midjourney Standard ($30)
- 自动化:Zapier ($30)
- 其他工具:$50

总成本:$180/月
适合:专业团队、高频使用

企业方案(按需定制)

方案 D:企业级
- API 调用:按 Token 计费(弹性)
- 私有部署:本地 LLM
- 定制模型:Fine-tuning
- 数据安全:企业级保障

总成本:$500-5000+/月
适合:大型企业、严格数据安全要求

三、AI Tools 集成开发

3.1 API 集成最佳实践

基础封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// lib/ai-client.js
class AIClient {
constructor() {
this.providers = {
openai: new OpenAI({ apiKey: process.env.OPENAI_API_KEY }),
anthropic: new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),
};

this.cache = new Map();
}

async chat(messages, options = {}) {
const {
provider = 'openai',
model = 'gpt-4-turbo-preview',
temperature = 0.7,
maxTokens = 2000,
useCache = true,
} = options;

// 缓存键
const cacheKey = this.generateCacheKey(messages, options);

// 检查缓存
if (useCache && this.cache.has(cacheKey)) {
console.log('💾 Using cached response');
return this.cache.get(cacheKey);
}

// 调用 API
const response = await this.callProvider(provider, model, messages, {
temperature,
max_tokens: maxTokens,
});

// 缓存结果
if (useCache) {
this.cache.set(cacheKey, response);
}

return response;
}

async callProvider(provider, model, messages, params) {
try {
switch (provider) {
case 'openai':
return await this.callOpenAI(model, messages, params);
case 'anthropic':
return await this.callAnthropic(model, messages, params);
default:
throw new Error(`Unknown provider: ${provider}`);
}
} catch (error) {
// 错误处理和重试
return await this.handleError(error, provider, model, messages, params);
}
}

async callOpenAI(model, messages, params) {
const completion = await this.providers.openai.chat.completions.create({
model,
messages,
...params,
});

return {
content: completion.choices[0].message.content,
usage: completion.usage,
model: completion.model,
};
}

async callAnthropic(model, messages, params) {
const message = await this.providers.anthropic.messages.create({
model,
messages,
max_tokens: params.max_tokens,
...params,
});

return {
content: message.content[0].text,
usage: message.usage,
model: message.model,
};
}

async handleError(error, provider, model, messages, params, retries = 3) {
console.error(`❌ Error calling ${provider}:`, error.message);

// 速率限制 - 等待后重试
if (error.status === 429 && retries > 0) {
const waitTime = Math.pow(2, 4 - retries) * 1000; // 指数退避
console.log(`⏳ Rate limited, waiting ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
return this.callProvider(provider, model, messages, params, retries - 1);
}

// 模型不可用 - 降级到备用模型
if (error.status === 503) {
console.log('🔄 Falling back to alternative model...');
return this.fallback(provider, model, messages, params);
}

throw error;
}

async fallback(provider, model, messages, params) {
// 定义降级策略
const fallbackMap = {
'gpt-4-turbo-preview': 'gpt-3.5-turbo',
'claude-3-opus': 'claude-3-sonnet',
};

const fallbackModel = fallbackMap[model];
if (fallbackModel) {
console.log(`↪️ Using fallback model: ${fallbackModel}`);
return this.callProvider(provider, fallbackModel, messages, params);
}

throw new Error('No fallback available');
}

generateCacheKey(messages, options) {
return JSON.stringify({ messages, options });
}

clearCache() {
this.cache.clear();
}
}

// 使用示例
const ai = new AIClient();

const response = await ai.chat([
{ role: 'user', content: '解释什么是闭包' }
], {
provider: 'openai',
model: 'gpt-4-turbo-preview',
temperature: 0.7,
useCache: true,
});

console.log(response.content);
console.log(`Token 使用: ${response.usage.total_tokens}`);

流式响应处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 流式输出 - 用户体验更好
async function streamChat(messages, onChunk) {
const stream = await openai.chat.completions.create({
model: 'gpt-4-turbo-preview',
messages: messages,
stream: true,
});

let fullContent = '';

for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content || '';
fullContent += delta;

// 实时回调
onChunk(delta, fullContent);
}

return fullContent;
}

// 使用示例
await streamChat(
[{ role: 'user', content: '写一个排序算法' }],
(delta, full) => {
// 逐字打印,类似 ChatGPT 效果
process.stdout.write(delta);
}
);

成本监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class AIUsageTracker {
constructor() {
this.usage = {
requests: 0,
tokens: 0,
cost: 0,
};

this.pricing = {
'gpt-4-turbo-preview': {
input: 0.01 / 1000, // $0.01 per 1K tokens
output: 0.03 / 1000, // $0.03 per 1K tokens
},
'gpt-3.5-turbo': {
input: 0.0015 / 1000,
output: 0.002 / 1000,
},
'claude-3-opus': {
input: 0.015 / 1000,
output: 0.075 / 1000,
},
};
}

track(model, inputTokens, outputTokens) {
this.usage.requests++;
this.usage.tokens += inputTokens + outputTokens;

const pricing = this.pricing[model];
if (pricing) {
const cost = (inputTokens * pricing.input) + (outputTokens * pricing.output);
this.usage.cost += cost;
}
}

getReport() {
return {
totalRequests: this.usage.requests,
totalTokens: this.usage.tokens,
totalCost: ````math
{this.usage.cost.toFixed(4)}`,
avgTokensPerRequest: Math.round(this.usage.tokens / this.usage.requests),
avgCostPerRequest: `

{(this.usage.cost / this.usage.requests).toFixed(4)}`,
};
}

reset() {
this.usage = { requests: 0, tokens: 0, cost: 0 };
}
}

// 集成到 AIClient
class AIClientWithTracking extends AIClient {
constructor() {
super();
this.tracker = new AIUsageTracker();
}

async callProvider(provider, model, messages, params) {
const response = await super.callProvider(provider, model, messages, params);

// 记录使用情况
this.tracker.track(
  model,
  response.usage.prompt_tokens,
  response.usage.completion_tokens
);

return response;

}

getUsageReport() {
return this.tracker.getReport();
}
}

// 使用
const ai = new AIClientWithTracking();

// … 多次调用 …

console.log(ai.getUsageReport());
// {
// totalRequests: 150,
// totalTokens: 45230,
// totalCost: ‘$2.3450', // avgTokensPerRequest: 301, // avgCostPerRequest: '$0.0156’
// }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

### 3.2 多工具编排

```javascript
// 工具编排器 - 组合多个 AI 能力
class AIOrchestrator {
constructor() {
this.tools = {
llm: new AIClient(),
image: new ImageGenerator(),
search: new WebSearchTool(),
code: new CodeExecutor(),
};
}

async createBlogPost(topic) {
console.log(`📝 Creating blog post about: ${topic}\n`);

// 1. 搜索最新信息
console.log('[1/5] 🔍 Researching topic...');
const searchResults = await this.tools.search.search(topic, { limit: 5 });

// 2. 生成大纲
console.log('[2/5] 📋 Generating outline...');
const outline = await this.tools.llm.chat([
{
role: 'user',
content: `基于以下信息,为"${topic}"创建博客大纲:\n${searchResults}`
}
]);

// 3. 撰写内容
console.log('[3/5] ✍️ Writing content...');
const content = await this.tools.llm.chat([
{
role: 'user',
content: `根据这个大纲写一篇详细的博客文章:\n${outline.content}`
}
], {
model: 'gpt-4-turbo-preview',
maxTokens: 4000,
});

// 4. 生成配图
console.log('[4/5] 🎨 Generating cover image...');
const imagePrompt = await this.tools.llm.chat([
{
role: 'user',
content: `为这篇文章生成一个 Midjourney 提示词(英文):\n${content.content.slice(0, 500)}`
}
]);

const coverImage = await this.tools.image.generate(imagePrompt.content);

// 5. 如果有代码,运行测试
console.log('[5/5] 🧪 Testing code samples...');
const codeBlocks = this.extractCodeBlocks(content.content);
const testedCode = await this.testCodeSamples(codeBlocks);

return {
title: this.extractTitle(content.content),
outline: outline.content,
content: content.content,
coverImage: coverImage.url,
codeBlocks: testedCode,
metadata: {
wordCount: content.content.split(' ').length,
readingTime: Math.ceil(content.content.split(' ').length / 200),
generatedAt: new Date().toISOString(),
}
};
}

extractCodeBlocks(content) {
const regex = /```(\w+)\n([\s\S]*?)```/g;
const blocks = [];
let match;

while ((match = regex.exec(content)) !== null) {
blocks.push({
language: match[1],
code: match[2],
});
}

return blocks;
}

async testCodeSamples(codeBlocks) {
const results = [];

for (const block of codeBlocks) {
if (['javascript', 'python'].includes(block.language)) {
try {
const result = await this.tools.code.execute(block.code, block.language);
results.push({
...block,
tested: true,
output: result.output,
error: result.error,
});
} catch (error) {
results.push({
...block,
tested: true,
error: error.message,
});
}
} else {
results.push({
...block,
tested: false,
});
}
}

return results;
}

extractTitle(content) {
const match = content.match(/^#\s+(.+)$/m);
return match ? match[1] : 'Untitled';
}
}

// 使用示例
const orchestrator = new AIOrchestrator();

const blogPost = await orchestrator.createBlogPost('React Server Components');

console.log('\n✅ Blog post created!');
console.log(`📄 Title: ${blogPost.title}`);
console.log(`📊 Word count: ${blogPost.metadata.wordCount}`);
console.log(`⏱️ Reading time: ${blogPost.metadata.readingTime} min`);
console.log(`🖼️ Cover: ${blogPost.coverImage}`);
console.log(`💻 Code blocks: ${blogPost.codeBlocks.length}`);

3.3 本地模型部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 使用 Ollama 部署本地模型
import requests
import json

class LocalLLM:
def __init__(self, base_url="http://localhost:11434"):
self.base_url = base_url

def chat(self, messages, model="llama3", stream=False):
"""调用本地 LLM"""
url = f"{self.base_url}/api/chat"

payload = {
"model": model,
"messages": messages,
"stream": stream
}

response = requests.post(url, json=payload, stream=stream)

if stream:
return self._handle_stream(response)
else:
return response.json()

def _handle_stream(self, response):
"""处理流式响应"""
for line in response.iter_lines():
if line:
data = json.loads(line)
if not data.get('done'):
yield data['message']['content']

def list_models(self):
"""列出可用模型"""
url = f"{self.base_url}/api/tags"
response = requests.get(url)
return response.json()

# 使用
llm = LocalLLM()

# 列出模型
models = llm.list_models()
print("Available models:", [m['name'] for m in models['models']])

# 对话
response = llm.chat([
{"role": "user", "content": "写一个快速排序"}
], model="llama3")

print(response['message']['content'])

# 流式输出
print("Streaming response:")
for chunk in llm.chat([
{"role": "user", "content": "解释什么是闭包"}
], stream=True):
print(chunk, end='', flush=True)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 本地部署脚本
#!/bin/bash

# 安装 Ollama
curl -fsSL https://ollama.com/install.sh | sh

# 下载模型
ollama pull llama3 # 8B 参数,约 4.7GB
ollama pull codellama # 代码专用
ollama pull mistral # 7B 参数,快速

# 启动服务
ollama serve

# 测试
curl http://localhost:11434/api/generate -d '{
"model": "llama3",
"prompt": "Why is the sky blue?"
}'

四、实战案例

4.1 自动化代码审查系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// code-review-bot.js
import { Octokit } from '@octokit/rest';
import { AIClient } from './lib/ai-client.js';

class CodeReviewBot {
constructor(githubToken) {
this.github = new Octokit({ auth: githubToken });
this.ai = new AIClient();
}

async reviewPullRequest(owner, repo, pullNumber) {
// 1. 获取 PR 变更
const { data: files } = await this.github.pulls.listFiles({
owner,
repo,
pull_number: pullNumber,
});

console.log(`📝 Reviewing PR #${pullNumber} with ${files.length} files`);

const reviews = [];

// 2. 逐文件审查
for (const file of files) {
if (this.shouldReview(file)) {
console.log(` 🔍 Reviewing ${file.filename}`);
const review = await this.reviewFile(file);
reviews.push(review);
}
}

// 3. 生成总结
const summary = await this.generateSummary(reviews);

// 4. 发布评论
await this.postReview(owner, repo, pullNumber, summary, reviews);

return { summary, reviews };
}

shouldReview(file) {
// 只审查代码文件
const codeExtensions = ['.js', '.ts', '.py', '.java', '.go', '.rs'];
return codeExtensions.some(ext => file.filename.endsWith(ext))
&& file.changes < 500; // 避免太大的文件
}

async reviewFile(file) {
const prompt = `
你是一个资深代码审查专家。请审查以下代码变更:

文件: ${file.filename}
变更内容:
\`\`\`
${file.patch}
\`\`\`

请从以下角度审查:
1. 代码质量和可读性
2. 潜在的 bug
3. 性能问题
4. 安全隐患
5. 最佳实践

格式化输出:
- ✅ 优点
- ⚠️ 建议
- ❌ 问题
`;

const response = await this.ai.chat([
{ role: 'user', content: prompt }
], {
model: 'gpt-4-turbo-preview',
temperature: 0.3, // 低温度确保一致性
});

return {
filename: file.filename,
review: response.content,
changes: file.changes,
additions: file.additions,
deletions: file.deletions,
};
}

async generateSummary(reviews) {
const totalChanges = reviews.reduce((sum, r) => sum + r.changes, 0);

const prompt = `
基于以下各文件的审查结果,生成一个 PR 的总体评估:

${reviews.map(r => `
## ${r.filename}
${r.review}
`).join('\n')}

请生成:
1. 整体评价(1-2 句话)
2. 主要优点(3 条)
3. 需要改进的地方(3 条)
4. 建议(是否批准 PR)
`;

const response = await this.ai.chat([
{ role: 'user', content: prompt }
]);

return response.content;
}

async postReview(owner, repo, pullNumber, summary, reviews) {
const body = `
## 🤖 AI Code Review

${summary}

---

### 📂 详细审查

${reviews.map(r => `
<details>
<summary>${r.filename} (+${r.additions} -${r.deletions})</summary>

${r.review}

</details>
`).join('\n')}

---
*Generated by AI Code Review Bot*
`;

await this.github.issues.createComment({
owner,
repo,
issue_number: pullNumber,
body,
});
}
}

// GitHub Webhook 处理
import express from 'express';

const app = express();
app.use(express.json());

const bot = new CodeReviewBot(process.env.GITHUB_TOKEN);

app.post('/webhook', async (req, res) => {
const { action, pull_request, repository } = req.body;

if (action === 'opened' || action === 'synchronize') {
// 新 PR 或更新时触发审查
const { owner, repo } = repository;
const pullNumber = pull_request.number;

// 异步处理,立即返回
bot.reviewPullRequest(owner.login, repo.name, pullNumber)
.catch(console.error);

res.status(200).send('Review queued');
} else {
res.status(200).send('Ignored');
}
});

app.listen(3000, () => {
console.log('🤖 Code Review Bot listening on :3000');
});

4.2 智能客服系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// customer-support-ai.js
class CustomerSupportAI {
constructor() {
this.ai = new AIClient();
this.knowledgeBase = new VectorDatabase();
this.ticketSystem = new TicketAPI();
}

async handleCustomerQuery(userId, message) {
console.log(`💬 New query from ${userId}: ${message}`);

// 1. 检索相关知识
const context = await this.knowledgeBase.search(message, { topK: 3 });

// 2. 检查历史对话
const history = await this.ticketSystem.getHistory(userId);

// 3. 生成回复
const response = await this.ai.chat([
{
role: 'system',
content: `你是一个专业的客服人员。根据知识库回答用户问题。

知识库内容:
${context.map(c => c.content).join('\n\n')}

注意:
- 态度友好耐心
- 答案准确专业
- 如果不确定,建议联系人工客服
- 提供具体步骤
`
},
...history,
{ role: 'user', content: message }
], {
model: 'gpt-4-turbo-preview',
temperature: 0.7,
});

// 4. 判断是否需要人工介入
const needsHuman = await this.assessComplexity(message, response.content);

if (needsHuman) {
// 创建工单
await this.ticketSystem.createTicket({
userId,
message,
aiResponse: response.content,
priority: 'normal',
});

return {
message: response.content + '\n\n已为您创建工单,客服人员会尽快联系您。',
ticketCreated: true,
};
}

// 5. 记录对话
await this.ticketSystem.logConversation(userId, message, response.content);

return {
message: response.content,
ticketCreated: false,
};
}

async assessComplexity(query, response) {
// 使用 AI 判断是否需要人工
const assessment = await this.ai.chat([
{
role: 'user',
content: `
判断这个客服对话是否需要人工介入:

用户问题: ${query}
AI 回答: ${response}

如果满足以下条件之一,回答 YES:
- 涉及退款或账户问题
- AI 回答不确定或模糊
- 用户情绪激动或投诉
- 需要特殊权限处理

只回答 YES 或 NO。
`
}
], {
temperature: 0.1,
maxTokens: 10,
});

return assessment.content.trim().toUpperCase() === 'YES';
}
}

// 向量数据库集成
class VectorDatabase {
constructor() {
this.pinecone = new PineconeClient();
// 初始化连接...
}

async search(query, options = {}) {
const { topK = 3 } = options;

// 1. 生成查询向量
const embedding = await this.getEmbedding(query);

// 2. 向量搜索
const results = await this.pinecone.query({
vector: embedding,
topK,
includeMetadata: true,
});

return results.matches.map(match => ({
content: match.metadata.text,
score: match.score,
source: match.metadata.source,
}));
}

async getEmbedding(text) {
const response = await openai.embeddings.create({
model: "text-embedding-3-small",
input: text,
});

return response.data[0].embedding;
}

async addDocument(text, metadata) {
const embedding = await this.getEmbedding(text);
const id = generateId();

await this.pinecone.upsert([{
id,
values: embedding,
metadata: { text, ...metadata },
}]);

return id;
}
}

// 使用示例
const support = new CustomerSupportAI();

// 添加知识库文档
await support.knowledgeBase.addDocument(
"退款流程:登录账户 → 我的订单 → 选择订单 → 申请退款。处理时间 3-5 个工作日。",
{ category: 'refund', source: 'help_center' }
);

// 处理用户咨询
const result = await support.handleCustomerQuery(
'user_12345',
'我想退款,怎么操作?'
);

console.log(result.message);
// "您好!退款操作很简单:
// 1. 登录您的账户
// 2. 进入"我的订单"
// 3. 选择需要退款的订单
// 4. 点击"申请退款"
//
// 退款会在 3-5 个工作日内处理完成,款项将原路返回。
// 如有其他问题,随时联系我!"

4.3 AI 内容创作工作流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// content-pipeline.js
class ContentCreationPipeline {
async createMarketingCampaign(product, targetAudience) {
console.log('🚀 Starting content creation pipeline...\n');

const campaign = {
product,
targetAudience,
assets: {},
};

// 1. 市场调研
console.log('[1/6] 📊 Market research...');
campaign.marketInsights = await this.conductMarketResearch(product);

// 2. 内容策略
console.log('[2/6] 🎯 Content strategy...');
campaign.strategy = await this.developContentStrategy(
product,
targetAudience,
campaign.marketInsights
);

// 3. 文案创作
console.log('[3/6] ✍️ Copywriting...');
campaign.assets.copy = await this.generateCopy(campaign.strategy);

// 4. 视觉设计
console.log('[4/6] 🎨 Visual design...');
campaign.assets.visuals = await this.generateVisuals(campaign.strategy);

// 5. 社交媒体内容
console.log('[5/6] 📱 Social media content...');
campaign.assets.social = await this.generateSocialContent(campaign);

// 6. 发布计划
console.log('[6/6] 📅 Publishing schedule...');
campaign.schedule = await this.createPublishingSchedule(campaign);

console.log('\n✅ Campaign ready!');
return campaign;
}

async conductMarketResearch(product) {
// 使用搜索 + AI 分析
const searches = [
`${product} market trends 2026`,
`${product} competitor analysis`,
`${product} customer reviews`,
];

const results = await Promise.all(
searches.map(q => this.search.search(q))
);

const analysis = await this.ai.chat([
{
role: 'user',
content: `分析以下市场数据,提供洞察:\n${results.join('\n\n')}`
}
]);

return analysis.content;
}

async generateCopy(strategy) {
const variants = {};

// A. 网站主标题(5 个变体)
variants.headlines = await this.generateVariants(
`为${strategy}创建 5 个吸引人的主标题`,
5
);

// B. 产品描述
variants.productDescription = await this.ai.chat([
{
role: 'user',
content: `写一段 150 字的产品描述,基于策略:${strategy}`
}
]);

// C. CTA 按钮文案
variants.cta = await this.generateVariants(
`创建 3 个不同的 CTA 按钮文案`,
3
);

// D. 邮件营销文案
variants.email = await this.ai.chat([
{
role: 'user',
content: `写一封营销邮件,包含主题、正文、CTA`
}
]);

return variants;
}

async generateVariants(prompt, count) {
const variants = [];

for (let i = 0; i < count; i++) {
const response = await this.ai.chat([
{ role: 'user', content: prompt }
], {
temperature: 0.9, // 高温度增加多样性
});

variants.push(response.content);
}

return variants;
}

async generateVisuals(strategy) {
// 使用 Midjourney / DALL-E
const prompts = await this.ai.chat([
{
role: 'user',
content: `为以下策略生成 3 个 Midjourney 图像提示词:\n${strategy}`
}
]);

const imagePrompts = this.parseImagePrompts(prompts.content);

const images = await Promise.all(
imagePrompts.map(prompt => this.imageGen.generate(prompt))
);

return {
prompts: imagePrompts,
images,
};
}

async generateSocialContent(campaign) {
const platforms = ['twitter', 'linkedin', 'instagram', 'facebook'];
const content = {};

for (const platform of platforms) {
content[platform] = await this.createPlatformContent(
platform,
campaign.strategy,
campaign.assets.copy
);
}

return content;
}

async createPlatformContent(platform, strategy, copy) {
const constraints = {
twitter: '280 字符,话题标签 2-3 个',
linkedin: '专业语气,1000 字符以内',
instagram: '2200 字符,emoji 丰富,话题标签 5-10 个',
facebook: '500 字符,互动性强',
};

const response = await this.ai.chat([
{
role: 'user',
content: `
${platform} 创建营销内容。

策略: ${strategy}
参考文案: ${copy.productDescription}

要求: ${constraints[platform]}

生成 3 个不同版本。
`
}
]);

return this.parseVariants(response.content);
}
}

// 使用
const pipeline = new ContentCreationPipeline();

const campaign = await pipeline.createMarketingCampaign(
'AI 驱动的项目管理工具',
'科技公司的产品经理和开发团队'
);

console.log('\n📦 Campaign deliverables:');
console.log(` Headlines: ${campaign.assets.copy.headlines.length}`);
console.log(` Images: ${campaign.assets.visuals.images.length}`);
console.log(` Social posts: ${Object.keys(campaign.assets.social).length} platforms`);

五、进阶话题

5.1 Fine-tuning 自定义模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# OpenAI Fine-tuning 示例
import openai
import json

# 准备训练数据
training_data = [
{
"messages": [
{"role": "system", "content": "你是一个代码审查专家"},
{"role": "user", "content": "审查这段代码:[code]"},
{"role": "assistant", "content": "这段代码有以下问题:..."}
]
},
# 更多训练样本...
]

# 保存为 JSONL
with open('training_data.jsonl', 'w') as f:
for item in training_data:
f.write(json.dumps(item) + '\n')

# 上传文件
file = openai.files.create(
file=open('training_data.jsonl', 'rb'),
purpose='fine-tune'
)

# 创建 fine-tuning 任务
job = openai.fine_tuning.jobs.create(
training_file=file.id,
model="gpt-3.5-turbo"
)

# 等待完成
print(f"Fine-tuning job created: {job.id}")

# 使用自定义模型
response = openai.chat.completions.create(
model="ft:gpt-3.5-turbo:my-org:custom_suffix:id",
messages=[
{"role": "user", "content": "审查代码"}
]
)

5.2 Prompt Engineering 最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Prompt 模板系统
class PromptTemplate {
constructor(template, variables) {
this.template = template;
this.variables = variables;
}

render(values) {
let prompt = this.template;

for (const [key, value] of Object.entries(values)) {
prompt = prompt.replace(new RegExp(`{{${key}}}`, 'g'), value);
}

return prompt;
}

static codeReview = new PromptTemplate(`
你是一个资深的 {{language}} 开发专家。

请审查以下代码:

\`\`\`{{language}}
{{code}}
\`\`\`

从以下方面进行评估:
1. 代码质量(可读性、可维护性)
2. 性能优化
3. 安全性
4. 最佳实践

输出格式:
### 优点
- [列举优点]

### 问题
- [列举问题]

### 建议
- [改进建议]
`, ['language', 'code']);

static dataAnalysis = new PromptTemplate(`
角色:数据分析专家

任务:分析以下数据并提供洞察

数据描述:
{{dataDescription}}

数据样本:
{{dataSample}}

分析维度:
{{dimensions}}

输出要求:
1. 数据概览(统计摘要)
2. 关键发现(Top 3)
3. 趋势分析
4. 行动建议
`, ['dataDescription', 'dataSample', 'dimensions']);

static contentGeneration = new PromptTemplate(`
角色:专业{{contentType}}创作者

目标受众:{{audience}}
语气风格:{{tone}}
关键信息:{{keyPoints}}

要求:
- 长度:{{length}}
- 包含:{{mustInclude}}
- 避免:{{avoid}}

现在请创作内容:
`, ['contentType', 'audience', 'tone', 'keyPoints', 'length', 'mustInclude', 'avoid']);
}

// 使用
const prompt = PromptTemplate.codeReview.render({
language: 'JavaScript',
code: 'function add(a, b) { return a + b; }'
});

console.log(prompt);

5.3 AI 安全与合规

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 内容审核系统
class ContentModerator {
async moderate(content) {
const checks = await Promise.all([
this.checkToxicity(content),
this.checkPII(content),
this.checkCopyright(content),
this.checkBias(content),
]);

return {
safe: checks.every(c => c.passed),
issues: checks.filter(c => !c.passed),
report: this.generateReport(checks),
};
}

async checkToxicity(content) {
// 使用 Perspective API 或类似服务
const response = await this.ai.chat([
{
role: 'user',
content: `
评估以下内容是否包含有害内容(仇恨、暴力、成人内容等):

"${content}"

只回答 SAFE 或 UNSAFE,并说明原因。
`
}
], { temperature: 0 });

const safe = response.content.includes('SAFE');

return {
category: 'toxicity',
passed: safe,
details: response.content,
};
}

async checkPII(content) {
// 检测个人身份信息
const piiPatterns = {
email: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
phone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,
ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
creditCard: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
};

const found = {};
let hasPII = false;

for (const [type, pattern] of Object.entries(piiPatterns)) {
const matches = content.match(pattern);
if (matches) {
found[type] = matches.length;
hasPII = true;
}
}

return {
category: 'pii',
passed: !hasPII,
details: hasPII ? `Found: ${JSON.stringify(found)}` : 'No PII detected',
};
}
}

// 使用
const moderator = new ContentModerator();

const result = await moderator.moderate(
"联系我:[email protected] 或 555-123-4567"
);

if (!result.safe) {
console.warn('⚠️ Content moderation failed:');
result.issues.forEach(issue => {
console.log(` - ${issue.category}: ${issue.details}`);
});
}

六、未来趋势

6.1 多模态 AI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 未来:统一的多模态接口
const multimodal = new MultimodalAI();

const result = await multimodal.process({
inputs: [
{ type: 'image', url: 'screenshot.png' },
{ type: 'text', content: '这个界面有什么问题?' },
{ type: 'audio', url: 'voice_note.mp3' }
],
task: 'ui_review',
outputs: ['text', 'image', 'code']
});

// result.text: 文字分析
// result.image: 标注图片
// result.code: 修复代码

6.2 Edge AI

1
2
3
4
5
6
7
8
9
10
11
12
// 浏览器内运行 AI 模型
import { pipeline } from '@xenova/transformers';

const classifier = await pipeline(
'sentiment-analysis',
'Xenova/distilbert-base-uncased-finetuned-sst-2-english'
);

const result = await classifier('I love this product!');
// [{ label: 'POSITIVE', score: 0.9998 }]

// 无需服务器,隐私更好,延迟更低

6.3 AI Agents 生态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 未来:AI Agent Marketplace
const agentMarketplace = new AgentMarketplace();

// 发布你的 Agent
await agentMarketplace.publish({
name: 'CodeReviewBot',
description: 'Automated code review',
capabilities: ['code_analysis', 'best_practices'],
pricing: { model: 'usage', rate: 0.01 }
});

// 使用他人的 Agent
const seoAgent = await agentMarketplace.import('SEOOptimizer');
const analysis = await seoAgent.analyzePage('https://example.com');

七、总结与建议

选择 AI Tools 的黄金法则

  1. 明确需求:不要为了用 AI 而用 AI
  2. 小步试错:从免费版开始,验证价值后再付费
  3. 关注 ROI:计算时间节省 vs 工具成本
  4. 数据安全:敏感数据谨慎使用云服务
  5. 持续学习:AI 工具迭代快,保持关注

推荐学习路径

初学者(0-3 个月)

  • ✅ 熟练使用 ChatGPT / Claude
  • ✅ 尝试 GitHub Copilot 编程
  • ✅ 体验 Midjourney 图像生成
  • ✅ 理解 Prompt Engineering 基础

进阶(3-6 个月)

  • ✅ 学习 API 集成(OpenAI API)
  • ✅ 部署简单的 AI 应用
  • ✅ 了解 LangChain / 类似框架
  • ✅ 实践成本优化策略

高级(6+ 个月)

  • ✅ 本地模型部署(Ollama / vLLM)
  • ✅ Fine-tuning 自定义模型
  • ✅ 构建 AI Agent 系统
  • ✅ 多工具编排和优化

资源推荐

学习资源

工具导航

社区


结语

AI Tools 正在重塑我们的工作方式。作为开发者,掌握这些工具不仅能提升个人效率,更能在团队中成为 AI 赋能的推动者。

记住:工具是手段,解决问题才是目的。选择合适的工具,用好现有的能力,持续学习新的可能性。

AI 时代已来,让我们一起拥抱变化!🚀


  

Web3.js v4 完整使用指南

Web3.js v4 完整使用指南


一、什么是 Web3.js?

Web3.js 是以太坊官方维护的 JavaScript 库,让前端/Node.js 应用能够:

  • 连接以太坊节点(本地或远程)
  • 读取链上数据(区块信息、账户地址)
  • 调用智能合约只读方法,查询链上状态
  • 使用内置工具函数处理地址、哈希、编码等

v4 是一次重大重写,完全用 TypeScript 实现,支持 ES Module,体积更小,API 更现代化。


二、安装

1
npm install web3

注意:v4 不再捆绑 web3-providers-http 等子包,所有提供者均已内置。


三、连接节点(Provider)

Web3 需要一个”提供者”来与以太坊网络通信,常见的有以下三种:

3.1 浏览器钱包(MetaMask)

这是 DApp 开发中最常用的方式,MetaMask 会在 window.ethereum 上注入提供者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Web3 from 'web3';

async function connectWallet(): Promise<string> {
if (!window.ethereum) {
throw new Error('请先安装 MetaMask');
}

// 实例化 Web3,传入 MetaMask 提供者
const web3 = new Web3(window.ethereum);

// 弹出授权弹窗,请求用户账户权限
const accounts: string[] = await window.ethereum.request({
method: 'eth_requestAccounts',
});

console.log('已连接账户:', accounts[0]);
return accounts[0];
}

3.2 HTTP RPC 节点

适合服务端脚本或只读查询(不需要签名)。

1
2
3
4
5
6
import Web3 from 'web3';

// 使用公共节点(Infura / Alchemy / 本地 Hardhat)
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');
// 或本地开发节点
// const web3 = new Web3('http://127.0.0.1:8545');

3.3 WebSocket 节点

实时监听链上事件时使用 WebSocket 提供者:

1
const web3 = new Web3('wss://mainnet.infura.io/ws/v3/YOUR_PROJECT_ID');

四、获取账户地址

4.1 获取当前连接账户

1
2
3
4
const accounts = await web3.eth.getAccounts();
const myAccount = accounts[0];
console.log('当前账户:', myAccount);
// 0x742d35Cc6634C0532925a3b844Bc454e4438f44e

4.2 获取网络信息

1
2
3
4
5
6
7
// 获取当前链 ID(v4 返回 BigInt)
const chainId = await web3.eth.getChainId();
console.log('Chain ID:', chainId.toString()); // 例:1n(以太坊主网)

// 获取当前节点的网络 ID
const networkId = await web3.eth.net.getId();
console.log('Network ID:', networkId.toString());

五、查询区块信息

5.1 获取最新区块

1
2
3
4
5
6
7
8
9
const latestBlock = await web3.eth.getBlockNumber();
console.log('最新区块高度:', latestBlock.toString());
// 例:19800000n (v4 返回 BigInt)

const block = await web3.eth.getBlock(latestBlock);
console.log('区块时间戳:', block.timestamp);
console.log('区块哈希:', block.hash);
console.log('矿工地址:', block.miner);
console.log('交易数量:', block.transactions.length);

5.2 按区块号或哈希查询

1
2
3
4
5
6
7
8
9
// 按区块号查询
const block = await web3.eth.getBlock(19000000n);

// 按哈希查询
const blockByHash = await web3.eth.getBlock('0xabc123...');

// 获取特定区块中的交易哈希列表
const blockWithTxs = await web3.eth.getBlock('latest', false);
console.log('交易哈希列表:', blockWithTxs.transactions);

六、与智能合约交互(只读)

合约只读查询需要:

  1. 合约地址:已部署合约在区块链上的地址
  2. ABI:合约接口描述(JSON 格式)

6.1 实例化合约

1
2
3
4
5
6
7
8
import Web3 from 'web3';
import PetCoinABI from './abis/PetCoinABI.json';

const web3 = new Web3(window.ethereum);
const CONTRACT_ADDRESS = '0x1234567890abcdef...';

// 创建合约实例
const contract = new web3.eth.Contract(PetCoinABI as any, CONTRACT_ADDRESS);

6.2 调用只读方法(call)

call 不消耗 Gas,不改变链上状态,适合所有数据查询场景:

1
2
3
4
5
6
7
8
9
10
11
// 查询代币余额
const balance = await contract.methods.balanceOf(myAccount).call();
console.log('代币余额:', balance);

// 查询代币名称
const name = await contract.methods.name().call();
console.log('代币名称:', name); // 'PetCoin'

// 查询代币总量
const totalSupply = await contract.methods.totalSupply().call();
console.log('总发行量:', totalSupply);

6.3 并发查询多个数据

使用 Promise.all 并发请求,减少等待时间:

1
2
3
4
5
6
7
8
const [name, symbol, decimals, totalSupply] = await Promise.all([
contract.methods.name().call(),
contract.methods.symbol().call(),
contract.methods.decimals().call(),
contract.methods.totalSupply().call(),
]);

console.log(`${name} (${symbol}),精度: ${decimals},总量: ${totalSupply}`);

6.4 查询历史事件日志

通过 getPastEvents 读取合约过去发出的事件(只读,无需签名):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 查询所有历史事件(指定区块范围)
const events = await contract.getPastEvents('PetAdopted', {
filter: {
owner: myAccount, // 按字段过滤
},
fromBlock: 0,
toBlock: 'latest',
});

events.forEach((event) => {
const { petId, name, owner } = event.returnValues as any;
console.log(`宠物 #${petId} "${name}" 被 ${owner} 领养`);
console.log('所在区块:', event.blockNumber);
});

七、实用工具函数

Web3.js 内置了大量工具函数,无需引入额外依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const { utils } = web3;

// 地址校验与格式化
utils.isAddress('0xabc...'); // 检查是否合法以太坊地址
utils.toChecksumAddress('0xabc...'); // 转换为 EIP-55 校验和地址

// 哈希计算
utils.keccak256('Hello Web3'); // Keccak-256 哈希
utils.sha3('Hello Web3'); // 同上(别名)

// 十六进制编解码
utils.utf8ToHex('Hello'); // '0x48656c6c6f'
utils.hexToUtf8('0x48656c6c6f'); // 'Hello'
utils.numberToHex(255); // '0xff'
utils.hexToNumber('0xff'); // 255
utils.hexToBytes('0xff'); // Uint8Array([255])

// 大数运算(避免 JavaScript 精度问题,v4 原生支持 BigInt)
const a = BigInt('999999999999999999');
const b = BigInt('1');
console.log((a + b).toString()); // '1000000000000000000'

八、React + TypeScript 中的最佳实践

在 React 项目中使用 Web3.js,推荐封装为自定义 Hook 或 Redux Slice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// hooks/useWeb3.ts
import { useState, useEffect, useCallback } from 'react';
import Web3 from 'web3';

interface Web3State {
web3: Web3 | null;
account: string | null;
chainId: bigint | null;
isConnecting: boolean;
error: string | null;
}

export function useWeb3() {
const [state, setState] = useState<Web3State>({
web3: null,
account: null,
chainId: null,
isConnecting: false,
error: null,
});

const connect = useCallback(async () => {
if (!window.ethereum) {
setState((s) => ({ ...s, error: '请安装 MetaMask' }));
return;
}

setState((s) => ({ ...s, isConnecting: true, error: null }));

try {
const web3 = new Web3(window.ethereum);
const accounts: string[] = await window.ethereum.request({
method: 'eth_requestAccounts',
});
const chainId = await web3.eth.getChainId();

setState({
web3,
account: accounts[0],
chainId,
isConnecting: false,
error: null,
});
} catch (err: any) {
setState((s) => ({
...s,
isConnecting: false,
error: err.message ?? '连接失败',
}));
}
}, []);

// 监听账户/网络切换
useEffect(() => {
if (!window.ethereum) return;

const handleAccountsChanged = (accounts: string[]) => {
setState((s) => ({ ...s, account: accounts[0] ?? null }));
};

const handleChainChanged = () => {
// 官方建议网络切换后刷新页面
window.location.reload();
};

window.ethereum.on('accountsChanged', handleAccountsChanged);
window.ethereum.on('chainChanged', handleChainChanged);

return () => {
window.ethereum?.removeListener('accountsChanged', handleAccountsChanged);
window.ethereum?.removeListener('chainChanged', handleChainChanged);
};
}, []);

return { ...state, connect };
}

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { useWeb3 } from './hooks/useWeb3';

function App() {
const { account, chainId, isConnecting, error, connect } = useWeb3();

return (
<div>
{account ? (
<p>已连接:{account}(Chain ID: {chainId?.toString()})</p>
) : (
<button onClick={connect} disabled={isConnecting}>
{isConnecting ? '连接中...' : '连接钱包'}
</button>
)}
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
);
}

九、常见错误与解决方案

错误信息 原因 解决方案
window.ethereum is undefined 未安装 MetaMask 或在 Node.js 环境 检测环境后给用户提示
User rejected the request 用户点击了”拒绝” catch 后给出友好提示,不要重复弹出
execution reverted 合约 require 条件不满足 检查合约方法参数是否正确
Cannot read properties of null web3 未初始化就调用方法 确保先 await connect() 后再调用
invalid address 传入地址格式有误 使用 utils.isAddress() 校验后再传入

十、安全注意事项

  1. 绝不在前端存储私钥:前端代码对用户可见,私钥一旦暴露资产即丢失。
  2. 校验地址格式:使用 web3.utils.isAddress() 验证用户输入的地址,防止注入攻击。
  3. 校验网络 ID:合约只部署在特定网络,连接前验证 chainId 防止在错误网络操作。
  4. 避免信任链下数据:链上 call() 返回的数据是可信的,但前端显示时仍需做基础类型校验。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 网络校验示例
const EXPECTED_CHAIN_ID = 11155111n; // Sepolia 测试网

const chainId = await web3.eth.getChainId();
if (chainId !== EXPECTED_CHAIN_ID) {
throw new Error(`请切换到正确的网络(当前 Chain ID: ${chainId})`);
}

// 地址输入校验示例
function safeGetContract(address: string) {
if (!web3.utils.isAddress(address)) {
throw new Error('非法合约地址');
}
return new web3.eth.Contract(ABI, address);
}

总结

功能 API
连接 MetaMask new Web3(window.ethereum)
请求账户 ethereum.request({ method: 'eth_requestAccounts' })
获取账户列表 web3.eth.getAccounts()
获取链 ID web3.eth.getChainId()
查询区块 web3.eth.getBlock(blockNumber)
合约实例化 new web3.eth.Contract(ABI, address)
只读调用 contract.methods.xxx().call()
查询历史事件 contract.getPastEvents(name, options)
地址校验 web3.utils.isAddress(addr)
哈希计算 web3.utils.keccak256(data)

Web3.js v4 配合 TypeScript 使用体验极佳,ABI 类型推断、BigInt 原生支持,让 DApp 数据查询更安全可靠。


参考资料:Web3.js 官方文档 | 以太坊开发文档

Three.js 入门实战:基于 Vue3 做一个可拖拽的 3D 编辑器

Three.js 入门实战:基于 Vue3 做一个可拖拽的 3D 编辑器

前言

如果你是第一次接触 Three.js,这篇文章会带你从 0 到 1 建立完整认知:

  1. Three.js 到底是什么。
  2. 核心概念有哪些。
  3. 怎么在真实项目里用起来。
  4. 新手最容易踩哪些坑。

本文不是纯理论,而是结合我自己写的一个真实项目 drag-3D-three 来讲解。这个项目是一个 3D/2D 可视化大屏编辑器,Three.js 部分支持拖拽创建几何体、加载模型、选择元素、修改属性和保存案例。

技术栈:Vue 3 + TypeScript + Vite + Three.js + Pinia


一、Three.js 是什么

Three.js 是一个运行在浏览器中的 3D 图形库,它基于 WebGL 做了高级封装。

你可以把它理解成:

  1. WebGL 是底层图形 API,能力强但很底层。
  2. Three.js 是更易用的“3D 开发工具箱”。
  3. 你不需要直接写复杂着色器,也能快速搭建 3D 场景。

Three.js 适合做什么:

  1. 3D 数据可视化。
  2. 数字孪生大屏。
  3. 在线 3D 编辑器。
  4. 模型展示页。
  5. 小型网页 3D 互动。

二、先记住 7 个核心概念(新手必会)

1. Scene(场景)

所有 3D 对象都放在 Scene 里。它相当于“舞台”。

1
const scene = new THREE.Scene()

2. Camera(相机)

相机决定你从哪里看场景。

常用的是透视相机:PerspectiveCamera

1
2
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
camera.position.z = 50

3. Renderer(渲染器)

渲染器负责把场景画到 canvas 上。

1
2
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true })
renderer.setSize(width, height)

4. Geometry + Material + Mesh

一个能看到的 3D 物体通常由三部分组成:

  1. Geometry:形状(立方体、球体等)。
  2. Material:材质(颜色、金属感、粗糙度等)。
  3. Mesh:几何体 + 材质的组合。
1
2
3
4
const geometry = new THREE.BoxGeometry(5, 5, 5)
const material = new THREE.MeshStandardMaterial({ color: '#4F46E5' })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

5. Light(光照)

如果你用的是标准材质(MeshStandardMaterial),必须有光,不然会很黑。

1
2
3
4
scene.add(new THREE.AmbientLight(0xffffff, 0.5))
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
directionalLight.position.set(1, 1, 1)
scene.add(directionalLight)

6. Controls(控制器)

项目里使用 OrbitControls,让用户能旋转、缩放、平移视角。

7. Animation Loop(动画循环)

Three.js 渲染通常放在循环里持续执行:

1
2
3
4
5
6
function animate() {
requestAnimationFrame(animate)
controls.update()
renderer.render(scene, camera)
}
animate()

只要你掌握这 7 点,已经能做出基础可交互场景。


三、基于我这个项目看 Three.js 怎么“落地”

下面结合我项目 drag-3D-three 的核心文件 src/components/ThreeDWorkspace.vue 看实战。

1. 初始化 3D 工作区

initThreeJS 里完成了完整初始化流程:

  1. 创建 scenecamerarenderer
  2. 注册 OrbitControls
  3. 添加环境光、平行光、网格辅助线 GridHelper
  4. 初始化 Raycaster 用于点击选中。
  5. 绑定 resizeclickdragoverdrop 等事件。

这就是一个标准的 Three.js 工程启动模板。

2. 元素数据结构(非常关键)

项目定义了统一元素结构,类似:

1
2
3
4
5
6
7
8
9
10
interface Element {
id: string
name: string
type: 'cube' | 'sphere' | 'cylinder' | 'pyramid' | 'custom'
position: { x: number; y: number; z: number }
size: { width: number; height: number; depth: number; radius: number }
color: string
number: string
modelUrl?: string
}

为什么新手要重视这一步:

  1. 数据结构统一后,渲染逻辑可复用。
  2. 能轻松做保存、撤销、模板化。
  3. 后续扩展动画、材质、权限都更顺。

3. 创建基础几何体

项目按 type 分发创建几何体:

  1. cube -> BoxGeometry
  2. sphere -> SphereGeometry
  3. cylinder -> CylinderGeometry
  4. pyramid -> ConeGeometry

然后统一材质和位置设置,最后 scene.add(mesh)

4. 加载自定义模型(GLTF/OBJ/FBX/STL)

项目支持多种模型格式,按扩展名选择对应 Loader:

  1. GLTFLoader
  2. OBJLoader
  3. FBXLoader
  4. STLLoader

加载后通过 Box3 计算模型包围盒,自动缩放到目标尺寸。这一步很实用,能避免不同模型源比例不一致的问题。

5. 用 Raycaster 做“点击选中”

点击画布后,先把鼠标坐标转换到标准化设备坐标,再发射射线检测相交对象。命中后通过 userData.elementId 找到业务元素。

这个思路是 Three.js 交互的基础技能。

6. 拖拽放置:把 HTML 拖拽和 3D 场景打通

项目中左侧元素卡片可拖拽,拖拽数据通过 dataTransfer 传入画布:

  1. 工具栏组件写入 application/json
  2. 工作区 handleDrop 解析 JSON。
  3. 根据鼠标位置生成 3D 元素并发出 element-created

这就是“低代码编辑器”的核心路径。


四、新手从零跑起来(实操步骤)

1. 安装和启动

1
2
npm install
npm run dev

2. 使用路径

  1. 进入编辑页。
  2. 左侧拖一个“立方体”到中间画布。
  3. 鼠标右键/滚轮配合 OrbitControls 调整视角。
  4. 点击元素,在右侧修改位置、尺寸、颜色、编号。
  5. 点击保存,写入案例库。

3. 你会学到什么

完成以上步骤后,你会自然掌握:

  1. Scene/Camera/Renderer 的协作关系。
  2. Three.js 和 Vue 组件的通信方式。
  3. 基础几何体与外部模型的统一管理。
  4. 射线拾取和拖拽交互。
  5. Three.js 项目中的状态持久化思路。

五、常见问题与避坑清单

1. 场景里什么都看不见

排查顺序:

  1. 相机是否对着物体。
  2. 是否有光照。
  3. 物体是否被加到 scene。
  4. 动画循环是否在执行。
  5. canvas 尺寸是否正确。

2. 模型加载失败

排查顺序:

  1. 模型路径是否可访问。
  2. 文件扩展名是否匹配 Loader。
  3. 是否有跨域问题。
  4. 控制台错误信息是否显示解析失败。

3. 拖拽位置不准

当前项目使用屏幕坐标线性映射,新手阶段够用;如果你追求更精确,建议升级为“射线与地面平面求交”方案。

4. 画面卡顿

常见原因:

  1. 每次数据变化都全量重建 mesh。
  2. 几何体分段数设置太高。
  3. 频繁创建对象但没有释放资源。

六、进阶建议:从教程走向实战

如果你已经跑通我这个项目,下一步建议按这个顺序升级:

  1. TransformControls(选中后可视化移动/旋转/缩放)。
  2. 实现元素分组和层级管理。
  3. 增加材质面板(透明度、贴图、发光)。
  4. 加载压缩模型(Draco)优化首屏。
  5. 增量更新渲染,减少全量重建。
  6. 引入截图功能生成案例缩略图。

七、总结

Three.js 入门最怕两件事:

  1. 只看 API,不做项目。
  2. 直接做复杂效果,基础不稳。

这篇教程给你的路径是:

  1. 先吃透核心概念(场景、相机、渲染器、光照、Mesh)。
  2. 用真实项目练习交互(拖拽、选中、更新、持久化)。
  3. 再逐步走向工程化(性能、架构、可扩展性)。

当你能独立搭出一个可拖拽编辑器时,就已经不再是 Three.js 初学者了。


项目求个 Star

如果这篇文章或这个项目对你有帮助,欢迎访问仓库并点一个 Star:

https://github.com/hujinbin/drag-3D-three

你的每一个 Star,都会让我更有动力持续更新:

  1. 新手友好的 Three.js 示例。
  2. 更完整的编辑器能力(变换控制、材质系统、分组层级)。
  3. 更实用的工程化优化(性能、资源管理、可维护性)。

也欢迎提 Issue 或 PR,一起把这个项目打磨成更好用的 Three.js 学习模板。

AI Agent:从对话工具到智能助手的进化之路

AI Agent:从对话工具到智能助手的进化之路

从 ChatGPT 到 AI Agent,人工智能正在经历从”被动回答”到”主动执行”的范式转变

前言

当你打开 ChatGPT,输入”帮我写一份项目报告”,它会给你一份精美的文本输出。但如果你说”帮我把这份报告发给团队,并安排明天下午的会议”,ChatGPT 就无能为力了。

这正是 AI Agent 诞生的原因——我们需要的不只是一个会说话的 AI,而是一个能真正帮我们做事情的智能助手。

什么是 AI Agent?

定义

AI Agent(人工智能代理) 是一个能够自主感知环境、做出决策并采取行动以实现特定目标的智能系统。

用更简单的话说:

  • ChatGPT 像是一位博学的顾问,你问什么它答什么
  • AI Agent 像是一位能干的助理,你给它一个目标,它会自己想办法完成

核心特征

AI Agent 具备以下五大核心能力:

1. 自主性(Autonomy)

能够在没有持续人工干预的情况下独立运作。

例子:

你:帮我分析一下竞品的最新动态
Agent:
  ✓ 搜索竞品官网
  ✓ 查看最近的新闻报道
  ✓ 分析社交媒体讨论
  ✓ 对比数据变化
  ✓ 生成分析报告

2. 感知能力(Perception)

能够通过工具访问和理解外部环境的信息。

例子:

  • 读取文件系统
  • 访问数据库
  • 调用 API
  • 获取实时信息

3. 行动能力(Action)

能够执行具体操作,改变环境状态。

例子:

  • 发送邮件
  • 创建文件
  • 修改代码
  • 执行命令

4. 推理能力(Reasoning)

能够分析问题、制定计划并做出决策。

例子:

目标:修复项目中的 Bug

Agent 推理过程:
1. 分析错误日志 → 定位问题文件
2. 查看相关代码 → 理解业务逻辑
3. 搜索解决方案 → 评估可行性
4. 生成修复代码 → 运行测试验证
5. 提交代码变更 → 更新文档

5. 学习能力(Learning)

能够从经验中学习,不断改进表现。

例子:

  • 记住用户偏好
  • 优化工作流程
  • 避免重复错误
  • 适应新场景

AI Agent 的技术架构

一个典型的 AI Agent 包含以下组件:

┌─────────────────────────────────────┐
│         用户目标(Goal)              │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│      规划器(Planner)                │
│  - 任务分解                           │
│  - 策略制定                           │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│      执行器(Executor)               │
│  - 工具调用                           │
│  - 动作执行                           │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│      工具箱(Tools)                  │
│  - 搜索引擎                           │
│  - 代码执行器                         │
│  - 文件系统                           │
│  - API 接口                          │
│  - MCP Servers                       │
└──────────────┬──────────────────────┘
               ↓
┌─────────────────────────────────────┐
│      记忆系统(Memory)               │
│  - 短期记忆(对话上下文)             │
│  - 长期记忆(知识库)                 │
└─────────────────────────────────────┘

核心流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
async function executeAgent(goal) {
// 1. 理解目标
const analysis = await llm.analyze(goal);

// 2. 制定计划
const plan = await planner.createPlan(analysis);

// 3. 执行步骤
for (const step of plan.steps) {
// 3.1 选择合适的工具
const tool = selectTool(step.action);

// 3.2 执行动作
const result = await executor.execute(tool, step.params);

// 3.3 评估结果
if (!result.success) {
// 重新规划或调整策略
await planner.replan(result.error);
}

// 3.4 更新记忆
memory.store(step, result);
}

// 4. 返回最终结果
return summarizeResults();
}

ChatGPT vs AI Agent:十大核心区别

维度 ChatGPT AI Agent
交互模式 问答式对话 目标驱动执行
主动性 被动响应 主动行动
工具使用 有限(内置几个工具) 广泛(可扩展工具集)
任务复杂度 单轮对话任务 多步骤复杂任务
环境感知 无法访问外部环境 可感知和操作环境
执行能力 只能生成文本 可执行实际操作
记忆系统 会话级短期记忆 持久化长期记忆
自主决策 需要用户引导 自主规划和调整
错误处理 报告错误 尝试修复和重试
学习能力 预训练固定 可从使用中学习

详细对比

1. 交互模式

ChatGPT:问答式

用户:Python 中如何读取 CSV 文件?
ChatGPT:你可以使用 pandas 库...
[代码示例]

AI Agent:目标驱动

用户:分析这个 CSV 文件的销售数据,找出表现最好的产品
Agent:
  ✓ 读取 sales.csv 文件
  ✓ 数据清洗和预处理
  ✓ 计算各产品销售指标
  ✓ 生成排行榜
  ✓ 创建可视化图表
  ✓ 输出分析报告

2. 工具使用能力

ChatGPT:

  • 内置工具:网页浏览、代码解释器、DALL-E
  • 工具数量:固定(约 3-5 个)
  • 扩展性:无法添加新工具

AI Agent:

  • 可集成任意工具和 API
  • 通过 MCP、Functions Calling 等协议扩展
  • 工具数量:理论上无限

示例架构对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// ChatGPT 工具调用(有限)
const tools = [
'web_browser',
'code_interpreter',
'dalle_image_generator'
];

// AI Agent 工具调用(可扩展)
const tools = [
// 信息获取
'web_search',
'database_query',
'api_call',
'file_read',

// 内容生成
'code_generator',
'image_generator',
'document_writer',

// 操作执行
'file_system',
'email_sender',
'task_scheduler',
'git_operations',

// 数据处理
'data_analyzer',
'chart_generator',
'ml_predictor',

// 通过 MCP 扩展更多...
];

3. 任务执行流程

ChatGPT 处理复杂任务:

用户:帮我做一个数据分析项目

ChatGPT:
我来帮你规划这个项目:

第一步:数据收集
1. 确定数据源
2. 下载数据文件
...

第二步:数据清洗
1. 处理缺失值
...

[用户需要手动执行每一步]

AI Agent 处理复杂任务:

用户:帮我做一个数据分析项目

Agent:
正在执行数据分析项目...

[Step 1/5] 收集数据
  ✓ 从 API 下载最新数据
  ✓ 保存到 data/raw/

[Step 2/5] 数据清洗  
  ✓ 处理 1,234 个缺失值
  ✓ 移除 56 个重复记录
  ✓ 标准化日期格式

[Step 3/5] 数据分析
  ✓ 计算统计指标
  ✓ 发现 3 个关键趋势

[Step 4/5] 生成报告
  ✓ 创建 5 个可视化图表
  ✓ 编写分析总结

[Step 5/5] 输出结果
  ✓ 报告已保存: reports/analysis_2026-03-02.pdf
  ✓ 图表已保存: charts/

✅ 项目完成!

4. 错误处理机制

ChatGPT:

用户:运行这段代码并修复错误

ChatGPT:执行代码时出现错误:
NameError: name 'data' is not defined

建议修复方案:
1. 检查变量名
2. 确保数据已加载
...

[需要用户手动修复]

AI Agent:

用户:运行这段代码并修复错误

Agent:
[Attempt 1] 执行代码
  ❌ 错误: NameError: name 'data' is not defined

[Analyzing] 分析错误原因
  → 变量 'data' 未定义
  → 可能缺少数据加载步骤

[Attempt 2] 添加数据加载代码
  import pandas as pd
  data = pd.read_csv('data.csv')
  ✓ 代码执行成功

✅ 问题已自动修复

5. 记忆和学习

ChatGPT:

  • 只记住当前对话
  • 新对话无法访问之前的内容
  • 无法学习用户偏好

AI Agent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 持久化记忆系统
const memory = {
// 用户偏好
preferences: {
codingStyle: 'functional',
language: 'TypeScript',
framework: 'React'
},

// 历史任务
taskHistory: [
{
date: '2026-03-01',
task: '创建 API 服务',
solution: '使用 Express + TypeScript',
success: true
}
],

// 上下文知识
projectContext: {
structure: 'monorepo',
testFramework: 'Jest',
cicd: 'GitHub Actions'
}
};

// Agent 利用记忆优化行为
async function createNewService(name) {
// 自动应用用户偏好
const template = memory.preferences.language === 'TypeScript'
? 'typescript-service-template'
: 'javascript-service-template';

// 参考历史成功经验
const bestPractice = memory.taskHistory
.filter(t => t.success && t.task.includes('API'))
.map(t => t.solution);

// 适配项目环境
const config = generateConfig(memory.projectContext);

return buildService(name, template, bestPractice, config);
}

AI Agent 的典型应用场景

1. 编程助手

传统 IDE + ChatGPT:

1. 你:写一个用户认证功能
2. ChatGPT:给你代码
3. 你:复制粘贴代码
4. 你:运行测试,发现错误
5. 你:把错误信息告诉 ChatGPT
6. ChatGPT:给你修复建议
7. 你:再次修改代码
8. 循环...

使用 AI Agent:

你:实现一个带 JWT 的用户认证系统

Agent:
[1/6] 分析需求
  ✓ 识别技术栈: Express + PostgreSQL
  ✓ 确定依赖: jsonwebtoken, bcrypt

[2/6] 创建数据模型
  ✓ users 表结构设计
  ✓ 创建 migration 文件

[3/6] 实现认证逻辑
  ✓ 注册接口: POST /api/auth/register
  ✓ 登录接口: POST /api/auth/login
  ✓ 密码加密处理

[4/6] 编写测试用例
  ✓ 注册流程测试: 5 个用例
  ✓ 登录流程测试: 4 个用例

[5/6] 运行测试
  ✓ 9/9 测试通过

[6/6] 生成文档
  ✓ API 文档: docs/auth-api.md
  ✓ 使用示例: examples/auth-usage.js

✅ 认证系统已完成并通过测试!

2. 数据分析

ChatGPT 方式:

你:分析这个销售数据
ChatGPT:[生成分析代码]
你:[手动运行代码]
你:[遇到数据格式问题]
你:告诉 ChatGPT 问题
ChatGPT:[给出修复代码]
...

AI Agent 方式:

你:分析 Q1 销售数据,找出增长机会

Agent:
📊 正在分析 Q1 销售数据...

[数据加载] 
  ✓ 读取 sales_q1_2026.csv (15,234 条记录)
  ✓ 连接产品数据库
  ✓ 获取客户信息

[数据处理]
  ✓ 清洗: 处理 234 个异常值
  ✓ 转换: 统一货币单位
  ✓ 关联: 合并 3 个数据源

[深度分析]
  ✓ 销售趋势分析
  ✓ 产品类别对比
  ✓ 区域市场分析
  ✓ 客户群体细分

[洞察发现]
  📈 总销售额增长 23.5%
  🏆 表现最佳: A 类产品(+45%)
  ⚠️ 需关注: 西部市场下滑 12%
  💡 机会: Z 世代客户增长潜力大

[可视化生成]
  ✓ 趋势图: charts/trend.png
  ✓ 热力图: charts/heatmap.png
  ✓ 仪表盘: dashboard/q1_analysis.html

[报告生成]
  ✓ 执行摘要: reports/executive_summary.pdf
  ✓ 详细分析: reports/detailed_analysis.pdf
  ✓ 行动建议: reports/action_items.md

✅ 分析完成!发现 5 个增长机会

3. 内容创作与发布

ChatGPT 方式:

你:写一篇产品发布文章
ChatGPT:[生成文章内容]
你:[复制到编辑器]
你:[配图]
你:[发布到各平台]
你:[设置 SEO]
...

AI Agent 方式:

你:为我们的新产品准备一次完整的内容发布

Agent:
📝 正在准备产品发布内容...

[1/8] 收集产品信息
  ✓ 读取产品文档
  ✓ 分析竞品定位
  ✓ 确定目标受众

[2/8] 创作内容
  ✓ 博客文章 (1,500 字)
  ✓ 社交媒体文案 (Twitter, LinkedIn, 微信)
  ✓ 新闻稿
  ✓ FAQ 文档

[3/8] 生成配图
  ✓ 产品宣传图 (3 张)
  ✓ 功能说明图 (5 张)
  ✓ 社交媒体封面

[4/8] 优化 SEO
  ✓ 关键词研究
  ✓ Meta 描述生成
  ✓ 结构化数据标记

[5/8] 多语言翻译
  ✓ 英文版本
  ✓ 日文版本

[6/8] 发布内容
  ✓ WordPress 博客已发布
  ✓ Twitter 已发送
  ✓ LinkedIn 已发布
  ✓ 公众号定时推送已设置

[7/8] 监控反馈
  ✓ 设置 Google Analytics 跟踪
  ✓ 社交媒体监听已启动

[8/8] 生成发布报告
  ✓ 发布清单: checklist.pdf
  ✓ 内容归档: archive/launch_2026-03-02/

✅ 产品发布内容已完成并发布!

4. 客户服务

传统客服 + ChatGPT:

客户:我的订单还没到
客服(用 ChatGPT 辅助回复):请提供订单号
客户:#12345
客服:[手动查询系统]
客服:[咨询物流]
客服:[回复客户]

AI Agent 客服:

客户:我的订单还没到

Agent:
[自动处理中...]

[1/5] 识别客户
  ✓ 客户 ID: 67890
  ✓ 会员等级: 金卡
  ✓ 历史订单: 23 次

[2/5] 查询订单
  ✓ 订单号: #12345
  ✓ 下单时间: 2026-02-28
  ✓ 预计送达: 2026-03-03

[3/5] 追踪物流
  ✓ 当前状态: 运输中
  ✓ 当前位置: 本地分拨中心
  ✓ 预计明天送达

[4/5] 检测异常
  ⚠️ 发现: 超过预期到达时间 1 天

[5/5] 主动补救
  ✓ 申请加急配送
  ✓ 发放补偿优惠券 (20 元)
  ✓ 通知物流加速

回复客户:
「非常抱歉让您久等了!您的订单 #12345 目前在本地分拨中心,
我已为您申请加急配送,预计明天上午送达。

作为歉意,已为您的账户充入 20 元优惠券。
您可以在"我的优惠券"中查看。

实时物流追踪:[链接]
有任何问题随时联系我!」

[后续动作]
  ✓ 设置明日送达提醒
  ✓ 记录问题以优化物流
  ✓ 明天自动回访客户满意度

实现一个简单的 AI Agent

让我们用代码实现一个基础的 AI Agent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
class SimpleAgent {
constructor(llm, tools) {
this.llm = llm; // 大语言模型
this.tools = tools; // 工具集
this.memory = []; // 记忆系统
this.maxSteps = 10; // 最大步骤数
}

async execute(goal) {
console.log(`🎯 目标: ${goal}`);

// 添加目标到记忆
this.memory.push({
role: 'user',
content: goal
});

let step = 0;

while (step < this.maxSteps) {
step++;
console.log(`\n[Step ${step}/${this.maxSteps}]`);

// 1. 让 LLM 决定下一步动作
const decision = await this.decide();

// 2. 如果认为任务已完成
if (decision.action === 'finish') {
console.log('✅ 任务完成!');
return decision.result;
}

// 3. 执行工具
const tool = this.tools[decision.action];
if (!tool) {
console.log(`❌ 工具 ${decision.action} 不存在`);
continue;
}

console.log(`🔧 执行工具: ${decision.action}`);
console.log(`📝 参数: ${JSON.stringify(decision.args)}`);

try {
const result = await tool.execute(decision.args);
console.log(`✓ 结果: ${JSON.stringify(result).slice(0, 100)}...`);

// 4. 将结果添加到记忆
this.memory.push({
role: 'tool',
tool: decision.action,
result: result
});
} catch (error) {
console.log(`❌ 执行失败: ${error.message}`);
this.memory.push({
role: 'tool',
tool: decision.action,
error: error.message
});
}
}

throw new Error('超过最大步骤数');
}

async decide() {
// 构建 prompt
const prompt = this.buildPrompt();

// 调用 LLM
const response = await this.llm.generate(prompt);

// 解析 LLM 的决策
return this.parseDecision(response);
}

buildPrompt() {
const toolDescriptions = Object.entries(this.tools)
.map(([name, tool]) => `- ${name}: ${tool.description}`)
.join('\n');

return `
你是一个 AI Agent,可以使用以下工具:

${toolDescriptions}

对话历史:
${this.memory.map(m => `${m.role}: ${JSON.stringify(m)}`).join('\n')}

请分析当前情况,决定下一步行动。

如果任务已完成,返回:
{
"action": "finish",
"result": "最终结果描述"
}

如果需要使用工具,返回:
{
"action": "工具名称",
"args": { "参数": "值" },
"reason": "为什么使用这个工具"
}

你的决策(JSON格式):
`;
}

parseDecision(response) {
// 提取 JSON
const jsonMatch = response.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
throw new Error('无法解析 LLM 响应');
}

return JSON.parse(jsonMatch[0]);
}
}

// 定义工具
const tools = {
search_web: {
description: '搜索网页内容',
execute: async (args) => {
// 实现网页搜索
const results = await fetch(`https://api.search.com?q=${args.query}`);
return results.json();
}
},

read_file: {
description: '读取文件内容',
execute: async (args) => {
const fs = require('fs').promises;
return await fs.readFile(args.path, 'utf-8');
}
},

write_file: {
description: '写入文件',
execute: async (args) => {
const fs = require('fs').promises;
await fs.writeFile(args.path, args.content);
return { success: true };
}
},

run_code: {
description: '执行 Python 代码',
execute: async (args) => {
// 使用代码执行器
const result = await runPython(args.code);
return result;
}
}
};

// 使用示例
const agent = new SimpleAgent(llm, tools);

await agent.execute(
'搜索今天的天气,然后创建一个 weather.txt 文件保存结果'
);

// 输出:
// 🎯 目标: 搜索今天的天气,然后创建一个 weather.txt 文件保存结果
//
// [Step 1/10]
// 🔧 执行工具: search_web
// 📝 参数: {"query":"今天天气"}
// ✓ 结果: {"temperature": "22°C", "condition": "晴天"}...
//
// [Step 2/10]
// 🔧 执行工具: write_file
// 📝 参数: {"path":"weather.txt","content":"今天天气:22°C,晴天"}
// ✓ 结果: {"success":true}
//
// [Step 3/10]
// ✅ 任务完成!

AI Agent 框架生态

目前主流的 AI Agent 框架:

1. LangChain / LangGraph

特点:

  • Python/JavaScript 双语言支持
  • 丰富的工具集成
  • 强大的链式调用能力

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from langchain.agents import initialize_agent, AgentType
from langchain.tools import Tool
from langchain.llms import OpenAI

# 定义工具
tools = [
Tool(
name="Search",
func=search_tool,
description="搜索网页信息"
),
Tool(
name="Calculator",
func=calculator,
description="执行数学计算"
)
]

# 创建 Agent
agent = initialize_agent(
tools=tools,
llm=OpenAI(temperature=0),
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)

# 执行任务
agent.run("搜索比特币当前价格,然后计算购买 10 个需要多少钱")

2. AutoGPT

特点:

  • 完全自主的 AI Agent
  • 长期目标规划
  • 可以自己创建和执行子任务

3. BabyAGI

特点:

  • 轻量级 Agent 框架
  • 任务优先级管理
  • 简单易理解的架构

4. Microsoft Semantic Kernel

特点:

  • 企业级 Agent 框架
  • 与 Microsoft 生态深度集成
  • 内存和规划能力强

5. Claude + MCP

特点:

  • 标准化工具协议
  • 无需编程接入工具
  • 安全的工具隔离

示例(结合本项目):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// MCP Server 为 Agent 提供工具
const mcpTools = {
search_articles: {
description: '搜索文章',
schema: { ... },
handler: async (args) => {
return await articleService.search(args);
}
},

get_user_stats: {
description: '获取用户统计',
schema: { ... },
handler: async (args) => {
return await userService.getStats(args);
}
}
};

// Claude 作为 Agent 调用这些工具
// 用户:分析一下我们社区的内容质量
// Claude Agent:
// 1. 调用 search_articles 获取最近文章
// 2. 调用 get_user_stats 分析作者活跃度
// 3. 综合分析并生成报告

AI Agent 的挑战与局限

1. 可靠性问题

幻觉(Hallucination):

用户:帮我安装 xyz-super-package
Agent:正在安装...
  ❌ 实际上这个包不存在,但 Agent 可能"假装"安装成功

解决方案:

  • 工具执行结果验证
  • 关键操作需要人工确认
  • 沙盒环境测试

2. 成本控制

每次 Agent 执行可能需要:

  • 多次 LLM 调用(规划、执行、反思)
  • 工具调用费用
  • 计算资源消耗

优化策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 使用缓存减少重复调用
const cache = new Map();

async function cachedToolCall(tool, args) {
const cacheKey = `${tool}_${JSON.stringify(args)}`;

if (cache.has(cacheKey)) {
return cache.get(cacheKey);
}

const result = await tool.execute(args);
cache.set(cacheKey, result);
return result;
}

// 使用更便宜的模型做简单任务
function selectModel(taskComplexity) {
if (taskComplexity === 'simple') {
return 'gpt-3.5-turbo'; // 便宜
} else {
return 'gpt-4'; // 强大但贵
}
}

3. 安全性问题

风险:

  • Agent 可能执行危险操作(删除文件、调用付费 API)
  • 工具调用权限过大
  • 恶意输入注入

安全措施:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class SafeAgent extends SimpleAgent {
constructor(llm, tools, safetyConfig) {
super(llm, tools);
this.safetyConfig = safetyConfig;
}

async execute(goal) {
// 检查目标是否包含危险关键词
if (this.containsDangerousIntent(goal)) {
throw new Error('检测到潜在危险操作,已拒绝执行');
}

return super.execute(goal);
}

async executeTool(tool, args) {
// 工具白名单
if (!this.safetyConfig.allowedTools.includes(tool.name)) {
throw new Error(`工具 ${tool.name} 未授权`);
}

// 关键操作需人工确认
if (this.safetyConfig.requireConfirmation.includes(tool.name)) {
const confirmed = await this.askUserConfirmation(tool, args);
if (!confirmed) {
throw new Error('用户取消操作');
}
}

// 参数校验
this.validateArgs(tool, args);

// 沙盒执行
return await this.sandboxExecute(tool, args);
}

containsDangerousIntent(text) {
const dangerousPatterns = [
/删除.*文件/,
/rm\s+-rf/,
/DROP\s+TABLE/,
/转账/,
/支付/
];

return dangerousPatterns.some(pattern => pattern.test(text));
}
}

const safetyConfig = {
allowedTools: [
'search_web',
'read_file',
'write_file'
],
requireConfirmation: [
'delete_file',
'send_email',
'make_payment'
]
};

const safeAgent = new SafeAgent(llm, tools, safetyConfig);

4. 控制与可解释性

用户需要理解 Agent 在做什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 带解释的 Agent 执行
class ExplainableAgent extends SimpleAgent {
async execute(goal) {
console.log(`\n🎯 收到任务: ${goal}`);
console.log(`\n🤔 让我想想如何完成这个任务...\n`);

// 先生成执行计划
const plan = await this.createPlan(goal);

console.log('📋 执行计划:');
plan.steps.forEach((step, i) => {
console.log(` ${i + 1}. ${step.description}`);
console.log(` 工具: ${step.tool}`);
console.log(` 原因: ${step.reason}`);
});

const approval = await this.askApproval();
if (!approval) {
console.log('❌ 用户取消执行');
return;
}

console.log('\n▶️ 开始执行...\n');

// 执行每一步并解释
for (const [index, step] of plan.steps.entries()) {
console.log(`\n[步骤 ${index + 1}/${plan.steps.length}] ${step.description}`);

const result = await this.executeStep(step);

console.log(`✓ 完成`);
console.log(` 结果: ${this.summarizeResult(result)}`);
console.log(` 下一步: ${this.explainNextStep(index, plan)}`);
}

console.log('\n✅ 所有步骤已完成!');
return this.createFinalReport(plan);
}
}

AI Agent 的未来趋势

1. 多 Agent 协作

未来不是单个 Agent,而是多个专业 Agent 协作:

项目经理 Agent
    ↓
    ├─→ 前端开发 Agent
    ├─→ 后端开发 Agent  
    ├─→ 测试 Agent
    └─→ 部署 Agent

示例场景:

用户:开发一个待办事项应用

项目经理 Agent:
  → 分析需求
  → 分配任务给各个 Agent

前端 Agent:
  → 创建 React 组件
  → 实现 UI 交互

后端 Agent:
  → 设计 API 接口
  → 实现数据库逻辑

测试 Agent:
  → 编写测试用例
  → 执行自动化测试

部署 Agent:
  → 配置 CI/CD
  → 部署到生产环境

项目经理 Agent:
  ✅ 项目完成,所有测试通过,已部署

2. 持续学习能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class LearningAgent extends SimpleAgent {
async execute(goal) {
const result = await super.execute(goal);

// 从执行结果中学习
await this.learn({
task: goal,
steps: this.memory,
result: result,
success: result.success,
userFeedback: await this.getUserFeedback()
});

return result;
}

async learn(experience) {
// 更新策略库
if (experience.success && experience.userFeedback > 4) {
// 这是一个好的解决方案,记住它
this.strategyLibrary.add({
pattern: this.extractPattern(experience.task),
solution: experience.steps,
successRate: 1.0
});
}

// 避免重复错误
if (!experience.success) {
this.errorPatterns.add({
situation: experience.task,
failedApproach: experience.steps,
lesson: await this.analyzeFailure(experience)
});
}
}
}

3. 更强的推理能力

当前 Agent: 基于 ReAct(Reasoning + Acting)
未来 Agent: 
  - Tree of Thoughts(思维树)
  - Self-Refine(自我优化)
  - Reflexion(反思学习)

4. 人机协作模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Human-in-the-Loop Agent
class CollaborativeAgent extends SimpleAgent {
async execute(goal) {
// 1. Agent 提出初步方案
const proposal = await this.createProposal(goal);

console.log('💡 我的建议:');
console.log(proposal);

// 2. 征求人类意见
const feedback = await this.getHumanFeedback();

// 3. 根据反馈调整
const refinedPlan = await this.refinePlan(proposal, feedback);

// 4. 执行,过程中关键点再次确认
return await this.executeWithCheckpoints(refinedPlan);
}
}

总结:从 ChatGPT 到 AI Agent 的跃迁

对比维度 ChatGPT AI Agent 未来展望
核心能力 理解和生成 理解、规划和执行 自主学习和进化
工作方式 被动响应 主动完成目标 预测性主动服务
适用场景 咨询、创作、问答 任务自动化、流程优化 完全替代人工流程
局限性 无法操作外部系统 可靠性和成本 通用人工智能

关键要点

  1. ChatGPT 是大脑:擅长思考和表达
  2. AI Agent 是大脑+双手:不仅能想,还能做
  3. 未来是 Agent 网络:多个专业 Agent 协同工作

何时使用 ChatGPT vs AI Agent

使用 ChatGPT:

  • ✅ 需要创意和灵感
  • ✅ 学习和理解概念
  • ✅ 文本生成和改写
  • ✅ 一次性简单问题

使用 AI Agent:

  • ✅ 需要执行多步骤任务
  • ✅ 需要访问外部系统
  • ✅ 需要自动化流程
  • ✅ 需要持续运行的任务

开始构建你的 AI Agent

如果你想开始构建 AI Agent,推荐学习路径:

  1. 理解基础:学习 Prompt Engineering 和 LLM 原理
  2. 使用框架:从 LangChain 或 Semantic Kernel 开始
  3. 集成工具:通过 MCP、Functions 等协议扩展能力
  4. 实践项目:从简单的自动化任务开始
  5. 关注安全:实现沙盒、权限控制和人工审核

参考资源


AI Agent 时代已经到来,不是替代人类,而是增强人类的能力。

Web 实时通信技术对比:HTTP vs SSE vs WebSocket

Web 实时通信技术对比:HTTP vs SSE vs WebSocket

引言

在现代 Web 应用开发中,客户端与服务器之间的实时通信变得越来越重要。从简单的数据获取到实时聊天、股票行情推送、协作编辑等场景,我们需要根据具体需求选择合适的通信方式。本文将深入探讨三种主流的 Web 通信技术:HTTP、Server-Sent Events (SSE) 和 WebSocket,帮助你在实际项目中做出最佳选择。

HTTP:经典的请求-响应模式

基本原理

HTTP(超文本传输协议)是 Web 的基础协议,采用典型的客户端-服务器模式和请求-响应机制。客户端发起请求,服务器返回响应,一次通信结束后连接即关闭(HTTP/1.0)或可复用(HTTP/1.1+ 的 Keep-Alive)。

核心特点

  • 单向通信:只能由客户端主动发起请求
  • 无状态:每个请求都是独立的,服务器不保存客户端状态
  • 短连接:传统 HTTP 一次请求-响应后即断开
  • 轮询开销:实现”实时”需要不断轮询,效率低下

适用场景

  • 传统页面加载和刷新
  • RESTful API 调用
  • 文件下载上传
  • 不需要实时性的数据获取

代码示例

1
2
3
4
5
6
// 短轮询实现伪实时
setInterval(async () => {
const response = await fetch('/api/messages');
const data = await response.json();
updateUI(data);
}, 3000); // 每 3 秒请求一次

缺点:频繁请求造成大量资源浪费,实时性差。

SSE:服务器向客户端的单向推送

基本原理

Server-Sent Events 是 HTML5 引入的一种服务器推送技术,允许服务器通过 HTTP 连接向客户端持续推送数据。它基于 HTTP 协议,使用特殊的 text/event-stream MIME 类型。

核心特点

  • 单向推送:服务器 → 客户端,客户端只能接收
  • 基于 HTTP:无需特殊协议,防火墙友好
  • 自动重连:连接断开后浏览器会自动尝试重连
  • 事件 ID:支持断线续传,不会丢失消息
  • 轻量简单:比 WebSocket 实现更简单

技术细节

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

data: {"message": "Hello World"}

data: {"message": "Second message"}

id: 12345
event: customEvent
data: {"custom": "data"}

适用场景

  • 股票行情、实时报价推送
  • 新闻订阅、社交媒体更新
  • 服务器日志实时监控
  • 进度条更新(文件处理、任务进度)
  • 通知推送

代码示例

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const eventSource = new EventSource('/api/stream');

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('收到消息:', data);
};

eventSource.addEventListener('customEvent', (event) => {
console.log('自定义事件:', event.data);
});

eventSource.onerror = (error) => {
console.error('连接错误:', error);
};

服务端(Node.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.get('/api/stream', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

const sendEvent = (data) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};

const interval = setInterval(() => {
sendEvent({ time: new Date().toISOString() });
}, 1000);

req.on('close', () => {
clearInterval(interval);
});
});

WebSocket:全双工双向通信

基本原理

WebSocket 是一种独立的、基于 TCP 的协议,通过 HTTP 握手升级后建立持久连接,实现全双工通信。客户端和服务器都可以主动发送消息。

核心特点

  • 双向通信:客户端 ↔ 服务器,双方都可主动推送
  • 持久连接:一次握手,长期保持
  • 低延迟:无需 HTTP 头开销,数据帧轻量
  • 实时性强:毫秒级延迟
  • 二进制支持:可传输文本和二进制数据

连接建立过程

// 1. 客户端发起升级请求
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

// 2. 服务器确认升级
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

适用场景

  • 即时聊天应用
  • 多人在线游戏
  • 协作编辑(Google Docs、Figma)
  • 实时音视频通话信令
  • 物联网设备通信
  • 交易系统

代码示例

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const socket = new WebSocket('ws://example.com/socket');

socket.onopen = () => {
console.log('连接已建立');
socket.send(JSON.stringify({ type: 'join', user: 'Alice' }));
};

socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('收到消息:', data);
};

socket.onclose = () => {
console.log('连接已关闭');
};

socket.onerror = (error) => {
console.error('连接错误:', error);
};

// 发送消息
function sendMessage(text) {
socket.send(JSON.stringify({ type: 'message', text }));
}

服务端(Node.js + ws)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
console.log('新客户端连接');

ws.on('message', (message) => {
console.log('收到:', message);

// 广播给所有客户端
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});

ws.on('close', () => {
console.log('客户端断开');
});
});

三者详细对比

特性 HTTP SSE WebSocket
通信方向 单向(客户端 → 服务器) 单向(服务器 → 客户端) 双向(客户端 ↔ 服务器)
协议 HTTP HTTP(基于 HTTP) 独立协议(基于 TCP)
连接类型 短连接/Keep-Alive 长连接 持久连接
实时性 差(需轮询) 优秀
服务器推送 不支持 支持 支持
浏览器兼容性 所有浏览器 IE 不支持,其他主流浏览器支持 现代浏览器均支持
数据格式 任意 文本(UTF-8) 文本 + 二进制
重连机制 无需 自动重连 需手动实现
协议开销 高(每次请求都有完整 HTTP 头) 中(初始建立连接) 低(握手后仅数据帧)
实现复杂度 简单 简单 中等
防火墙友好 取决于配置
代理支持 完全支持 支持 部分代理可能有问题

性能对比

延迟

  • HTTP 轮询:取决于轮询间隔,通常秒级延迟
  • SSE:毫秒到秒级,接近实时
  • WebSocket:毫秒级,最低延迟

带宽消耗

假设每秒发送一条消息:

HTTP 轮询:
- 请求头: ~800 bytes
- 响应头: ~200 bytes
- 每秒消耗: 1 KB × 2 = 2 KB/s (即使无数据更新)

SSE:
- 初始连接: ~1 KB
- 每条消息: 数据 + "\n\n" ≈ 数据大小
- 每秒消耗: 数据大小

WebSocket:
- 初始握手: ~500 bytes
- 每条消息: 数据 + 2-14 bytes(帧头)
- 每秒消耗: 数据大小 + 最小开销

服务器负载

  • HTTP 轮询:最高(频繁建立连接)
  • SSE:中等(维持长连接)
  • WebSocket:最低(连接复用,轻量数据帧)

如何选择?

选择 HTTP 当:

  • ✅ 不需要实时性(如传统 CRUD 操作)
  • ✅ 简单的 API 调用
  • ✅ 需要最大兼容性
  • ✅ 无状态的请求

选择 SSE 当:

  • ✅ 只需要服务器单向推送
  • ✅ 需要自动重连机制
  • ✅ 追踪事件历史(Event ID)
  • ✅ 实现简单优先
  • ✅ 防火墙/代理环境严格
  • ❌ 需要客户端频繁向服务器发送数据

选择 WebSocket 当:

  • ✅ 需要双向实时通信
  • ✅ 低延迟要求(如游戏、交易)
  • ✅ 高频率消息传输
  • ✅ 需要传输二进制数据
  • ✅ 客户端需要主动向服务器推送
  • ❌ 对老旧浏览器兼容性要求高

实际案例分析

案例 1:社交媒体通知

推荐:SSE

  • 服务器单向推送通知
  • 自动重连确保不丢消息
  • 实现简单,维护成本低

案例 2:在线聊天应用

推荐:WebSocket

  • 用户需要频繁发送和接收消息
  • 低延迟要求
  • 支持图片等二进制内容

案例 3:股票行情显示

推荐:SSE

  • 服务器持续推送价格更新
  • 客户端只需展示,无需发送
  • 断线重连自动恢复

案例 4:多人协作白板

推荐:WebSocket

  • 多个用户同时绘制
  • 需要实时同步每个操作
  • 双向高频通信

案例 5:数据仪表盘

推荐:HTTP + SSE 组合

  • 初始数据加载用 HTTP
  • 后续更新用 SSE 推送
  • 平衡实现复杂度和性能

案例 6:AI 对话系统(ChatGPT、Claude 等)

推荐:SSE

  • 服务器实时流式输出 AI 生成的文本
  • 用户体验更佳,无需等待完整响应
  • 单向推送符合 AI 对话场景
  • 实现简单,成本低

为什么 AI 对话系统选择 SSE?

现代 AI 对话系统(如 ChatGPT、Claude、Gemini 等)普遍采用 SSE 技术实现流式响应,这是因为:

  1. 改善用户体验:AI 模型生成长文本可能需要几秒甚至十几秒,传统 HTTP 请求会让用户等待很久才能看到结果。使用 SSE 可以逐字逐句地流式输出,用户能实时看到生成过程,体验类似打字效果。

  2. 单向通信特性:在对话场景中,用户发送问题后,AI 需要持续输出答案,这是典型的服务器向客户端单向推送场景,SSE 完美匹配。

  3. 自动重连机制:如果网络出现短暂中断,SSE 会自动重连,确保用户不会丢失部分回答。

  4. 实现简单:相比 WebSocket,SSE 不需要处理双向消息协调,代码更简洁,服务器负载更低。

  5. 兼容性好:基于 HTTP 协议,与现有基础设施(负载均衡、CDN、代理服务器)完美兼容。

实际代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// AI 对话客户端实现
async function chatWithAI(userMessage) {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: userMessage })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();
let aiResponse = '';

while (true) {
const { done, value } = await reader.read();
if (done) break;

const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split('\n');

for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') break;

try {
const json = JSON.parse(data);
const token = json.choices[0].delta.content || '';
aiResponse += token;

// 实时更新 UI,逐字显示
updateChatUI(aiResponse);
} catch (e) {
console.error('解析错误:', e);
}
}
}
}
}

// OpenAI 风格的调用方式
const eventSource = new EventSource('/api/chat/stream?prompt=你好');

eventSource.onmessage = (event) => {
if (event.data === '[DONE]') {
eventSource.close();
return;
}

const token = JSON.parse(event.data).token;
appendToMessage(token); // 逐个追加 token
};

服务端流式返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Node.js + Express 实现 AI 流式响应
app.post('/api/chat', async (req, res) => {
const { message } = req.body;

res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

try {
// 调用 AI 模型(如 OpenAI API)
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: message }],
stream: true, // 开启流式模式
});

// 逐个 token 推送给客户端
for await (const chunk of stream) {
const token = chunk.choices[0]?.delta?.content || '';
if (token) {
res.write(`data: ${JSON.stringify({ token })}\n\n`);
}
}

// 发送结束信号
res.write('data: [DONE]\n\n');
res.end();
} catch (error) {
res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
res.end();
}
});

性能优势对比

方式 首字节时间 总响应时间 用户感知
传统 HTTP 10 秒 10 秒 等待 10 秒后一次性显示
SSE 流式 200ms 10 秒 200ms 后开始逐字显示

通过 SSE 流式输出,虽然总响应时间相同,但用户感知到的等待时间大幅降低,交互体验显著提升。

实际应用案例

  • ChatGPT:使用 SSE 实现打字机效果的流式回答
  • Claude:采用类似技术提供实时响应体验
  • GitHub Copilot Chat:代码解释和生成使用流式输出
  • Perplexity AI:搜索结果和答案实时流式展示
  • 各类 AI 编程助手:代码生成过程实时可见

这也是为什么你在使用这些 AI 工具时,能看到文字一个个”打”出来,而不是等待很久后突然出现一大段文本。这种技术选择极大地改善了 AI 交互的用户体验。

进阶话题

HTTP/2 Server Push

HTTP/2 引入了服务器推送功能,但它与 SSE 不同:

  • HTTP/2 Push:主动推送资源(CSS、JS)到客户端缓存
  • SSE:持续推送数据流

两者解决的问题不同,不是替代关系。

混合方案

实际项目中可以组合使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用 HTTP 进行初始化数据加载
const initData = await fetch('/api/init').then(r => r.json());

// 使用 WebSocket 进行实时更新
const ws = new WebSocket('ws://example.com/realtime');
ws.onmessage = (event) => {
updateData(event.data);
};

// 使用 HTTP 进行文件上传
const formData = new FormData();
formData.append('file', file);
await fetch('/api/upload', { method: 'POST', body: formData });

总结

  • HTTP 是 Web 的基石,适合传统请求-响应场景
  • SSE 简单高效,适合服务器向客户端的单向推送
  • WebSocket 强大灵活,适合需要双向实时通信的场景

没有”最好”的技术,只有”最合适”的选择。根据实际需求权衡实时性、复杂度、兼容性和成本,才能做出明智的技术决策。

在实践中,还需要考虑:

  • 服务器架构(是否支持大量长连接)
  • 网络环境(代理、防火墙策略)
  • 浏览器兼容性要求
  • 团队技术栈和维护能力

希望这篇文章能帮助你在下一个项目中选择最合适的通信方案!

Docker 入门指南:从零开始掌握容器化技术

Docker 入门指南:从零开始掌握容器化技术

什么是 Docker?

Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖项打包到一个轻量级、可移植的容器中,然后在任何支持 Docker 的环境中运行。简单来说,Docker 解决了”在我机器上能运行”的经典问题。

为什么选择 Docker?

  • 环境一致性:开发、测试、生产环境完全一致
  • 快速部署:秒级启动,比传统虚拟机快得多
  • 资源高效:容器共享主机内核,占用资源少
  • 易于扩展:轻松实现应用的水平扩展
  • 版本控制:镜像可以像代码一样进行版本管理

核心概念

1. 镜像 (Image)

镜像是一个只读的模板,包含了运行应用所需的所有内容:代码、运行时、库、环境变量和配置文件。

2. 容器 (Container)

容器是镜像的运行实例。你可以创建、启动、停止、移动或删除容器。

3. Dockerfile

一个文本文件,包含了构建 Docker 镜像所需的所有指令。

4. Docker Hub

Docker 的官方镜像仓库,你可以在这里找到和分享镜像。

安装 Docker

Windows/Mac

访问 Docker Desktop 下载并安装。

Linux (Ubuntu)

1
2
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

验证安装:

1
docker --version

基本命令

1. 拉取镜像

1
2
3
4
5
# 从 Docker Hub 拉取官方 nginx 镜像
docker pull nginx

# 拉取特定版本
docker pull nginx:1.21

2. 查看镜像

1
2
3
4
5
# 列出本地所有镜像
docker images

# 查看镜像详细信息
docker inspect nginx

3. 运行容器

1
2
3
4
5
6
7
8
9
10
# 运行一个简单的容器
docker run hello-world

# 运行 nginx 并映射端口
docker run -d -p 8080:80 --name my-nginx nginx

# 参数说明:
# -d: 后台运行
# -p: 端口映射 (主机端口:容器端口)
# --name: 给容器命名

4. 管理容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查看运行中的容器
docker ps

# 查看所有容器(包括停止的)
docker ps -a

# 停止容器
docker stop my-nginx

# 启动容器
docker start my-nginx

# 重启容器
docker restart my-nginx

# 删除容器
docker rm my-nginx

# 强制删除运行中的容器
docker rm -f my-nginx

5. 容器交互

1
2
3
4
5
6
7
8
# 进入运行中的容器
docker exec -it my-nginx bash

# 查看容器日志
docker logs my-nginx

# 实时查看日志
docker logs -f my-nginx

6. 清理资源

1
2
3
4
5
6
7
8
# 删除所有停止的容器
docker container prune

# 删除未使用的镜像
docker image prune

# 删除所有未使用的资源
docker system prune -a

实战案例:运行一个 Node.js 应用

1. 创建应用文件

app.js

1
2
3
4
5
6
7
8
9
10
11
const express = require('express');
const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
res.send('Hello from Docker!');
});

app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});

package.json

1
2
3
4
5
6
7
8
9
10
{
"name": "docker-node-app",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.0"
},
"scripts": {
"start": "node app.js"
}
}

2. 编写 Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 使用官方 Node.js 镜像作为基础镜像
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json
COPY package*.json ./

# 安装依赖
RUN npm install

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 3000

# 启动命令
CMD ["npm", "start"]

3. 构建和运行

1
2
3
4
5
6
7
8
# 构建镜像
docker build -t my-node-app .

# 运行容器
docker run -d -p 3000:3000 --name node-app my-node-app

# 访问应用
curl http://localhost:3000

Docker Compose:管理多容器应用

当应用需要多个容器协同工作时(如前端 + 后端 + 数据库),使用 Docker Compose 可以简化管理。

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: '3.8'

services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=db
depends_on:
- db

db:
image: postgres:14
environment:
- POSTGRES_PASSWORD=secretpassword
- POSTGRES_DB=myapp
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:

运行多容器应用:

1
2
3
4
5
6
7
8
9
10
11
# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f

# 停止所有服务
docker-compose down

数据持久化:使用 Volume

容器删除后数据会丢失,使用 Volume 可以持久化数据:

1
2
3
4
5
6
7
8
9
10
11
# 创建 volume
docker volume create my-data

# 运行容器并挂载 volume
docker run -d -v my-data:/app/data --name my-app nginx

# 查看所有 volumes
docker volume ls

# 删除 volume
docker volume rm my-data

最佳实践

1. 优化镜像大小

  • 使用轻量级基础镜像(如 alpine)
  • 合并 RUN 指令减少层数
  • 使用 .dockerignore 排除不必要的文件

.dockerignore

node_modules
npm-debug.log
.git
.env
*.md

2. 多阶段构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 构建阶段
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

3. 安全建议

  • 不要以 root 用户运行容器
  • 定期更新基础镜像
  • 扫描镜像漏洞
  • 不在镜像中存储敏感信息

4. 健康检查

1
2
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:3000/health || exit 1

常见问题

1. 端口已被占用

1
2
3
4
5
6
# 查看端口占用
netstat -ano | findstr :8080 # Windows
lsof -i :8080 # Linux/Mac

# 使用其他端口
docker run -p 8081:80 nginx

2. 容器无法访问

  • 检查端口映射是否正确
  • 确认防火墙规则
  • 查看容器日志排查错误

3. 镜像构建慢

  • 使用国内镜像源
  • 优化 Dockerfile 层缓存
  • 使用 BuildKit 加速

学习资源

总结

Docker 是现代应用开发和部署的必备工具。通过本文,你应该已经掌握了:

  • Docker 的核心概念
  • 基本命令和操作
  • 如何编写 Dockerfile
  • 如何使用 Docker Compose
  • 最佳实践和常见问题

从零构建前端监控框架:原理与实践

在当今的互联网应用开发中,前端性能和用户体验的重要性不言而喻。为了确保前端应用的高质量运行,前端监控工具成为了开发者的得力助手。本文将深入剖析如何构建一个类似 monitoring-tool 的前端监控框架,包括其实现原理以及详细的构建步骤。

一、前端监控的重要性

在复杂的前端应用中,性能问题可能导致页面加载缓慢、用户操作卡顿,严重影响用户体验,进而导致用户流失。据统计,页面加载时间每延长 1 秒,用户流失率可能增加 10% 以上。错误未及时发现和处理可能引发应用崩溃或功能异常,例如未捕获的 JavaScript 错误可能导致整个页面交互失效。通过前端监控,我们可以实时了解应用的运行状态,及时发现并解决问题,提升应用的稳定性和性能,为用户提供更流畅的体验。


:D 一言句子获取中...