|
|
# 使用 AI 构建聊天助手
|
|
|
|
|
|
还记得《星际迷航》里,船员们随意与飞船计算机聊天,提出复杂问题并得到深思熟虑的回答吗? 在20世纪60年代这似乎纯属科幻的场景,现在你可以使用已掌握的网页技术来实现。
|
|
|
|
|
|
在本课中,我们将使用 HTML、CSS、JavaScript 以及一些后端集成创建一个 AI 聊天助手。你将发现,所学技能如何连接到强大的 AI 服务,这些服务能够理解上下文并生成有意义的回答。
|
|
|
|
|
|
可以把 AI 想象成拥有访问一个庞大图书馆的能力,它不仅能查找信息,还能将信息综合成符合你特定问题的连贯答案。你无需翻阅成千上万页,只需获得直接且有上下文的回应。
|
|
|
|
|
|
这一集成通过熟悉的网页技术协同工作完成。HTML 创建聊天界面,CSS 处理视觉设计,JavaScript 管理用户交互,后端 API 连接 AI 服务。类似管弦乐队不同部门协作演奏交响乐。
|
|
|
|
|
|
我们实际上是在搭建一座桥梁,连接自然的人类交流和机器处理。你将学习 AI 服务集成的技术实现,也将掌握让交互感觉直观的设计模式。
|
|
|
|
|
|
到本课结束时,AI 集成不再神秘,而是另一个你可以操作的 API。你将理解 ChatGPT 和 Claude 等应用背后的基础模式,使用你一直学习的网页开发原理。
|
|
|
|
|
|
## ⚡ 接下来5分钟你能做什么
|
|
|
|
|
|
**为忙碌开发者准备的快速入门路径**
|
|
|
|
|
|
```mermaid
|
|
|
flowchart LR
|
|
|
A[⚡ 5 分钟] --> B[获取 GitHub 令牌]
|
|
|
B --> C[测试 AI 操作台]
|
|
|
C --> D[复制 Python 代码]
|
|
|
D --> E[查看 AI 响应]
|
|
|
```
|
|
|
- **第1分钟**:访问 [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground),创建个人访问令牌
|
|
|
- **第2分钟**:在演示界面直接测试 AI 交互
|
|
|
- **第3分钟**:点击“Code”标签,复制 Python 代码片段
|
|
|
- **第4分钟**:携带你的令牌本地运行代码:`GITHUB_TOKEN=your_token python test.py`
|
|
|
- **第5分钟**:观看你的代码首次生成的 AI 回应
|
|
|
|
|
|
**快速测试代码**:
|
|
|
```python
|
|
|
import os
|
|
|
from openai import OpenAI
|
|
|
|
|
|
client = OpenAI(
|
|
|
base_url="https://models.github.ai/inference",
|
|
|
api_key="your_token_here"
|
|
|
)
|
|
|
|
|
|
response = client.chat.completions.create(
|
|
|
messages=[{"role": "user", "content": "Hello AI!"}],
|
|
|
model="openai/gpt-4o-mini"
|
|
|
)
|
|
|
|
|
|
print(response.choices[0].message.content)
|
|
|
```
|
|
|
|
|
|
**为何重要**:5分钟内,你将体验编程式 AI 交互的神奇。这是支撑所有你使用的 AI 应用的基本构建模块。
|
|
|
|
|
|
这是你完成项目后的效果:
|
|
|
|
|
|

|
|
|
|
|
|
## 🗺️ 你的 AI 应用开发学习之旅
|
|
|
|
|
|
```mermaid
|
|
|
journey
|
|
|
title 从网页开发到AI集成
|
|
|
section 理解AI基础
|
|
|
发现生成型AI概念: 4: You
|
|
|
探索GitHub模型平台: 6: You
|
|
|
掌握AI参数和提示: 8: You
|
|
|
section 后端集成
|
|
|
构建Python API服务器: 5: You
|
|
|
实现AI函数调用: 7: You
|
|
|
处理异步操作: 8: You
|
|
|
section 前端开发
|
|
|
创建现代聊天界面: 6: You
|
|
|
掌握实时交互: 8: You
|
|
|
构建响应式用户体验: 9: You
|
|
|
section 专业应用
|
|
|
部署完整AI系统: 7: You
|
|
|
优化性能模式: 8: You
|
|
|
创建生产就绪应用: 9: You
|
|
|
```
|
|
|
**你的目标**:完成本课后,你将构建完整的 AI 驱动应用,使用驱动现代 AI 助手(如 ChatGPT、Claude 和 Google Bard)的相同技术和模式。
|
|
|
|
|
|
## 认识 AI:从神秘到精通
|
|
|
|
|
|
在深入代码前,先理解我们要处理的内容。若你用过 API,知道基本模式:发送请求,接收响应。
|
|
|
|
|
|
AI API 也遵循类似结构,但它不是从数据库读取预存数据,而是基于海量文本学习的模式生成全新回应。可以把它想像成图书馆目录系统和通晓多源信息的博学图书管理员之间的区别。
|
|
|
|
|
|
### 什么是真正的“生成式 AI”?
|
|
|
|
|
|
想象罗塞塔石碑如何帮助学者通过已知和未知语言间的关系理解埃及象形文字。AI 模型的工作方式类似——它们通过大量文本找到语言的规律,再用这些规律生成对新问题的恰当回答。
|
|
|
|
|
|
**简单类比说明:**
|
|
|
- **传统数据库**:就像索取你的出生证明文件——每次都是同一个文件
|
|
|
- **搜索引擎**:像请图书管理员帮你找关于猫的书——他们展示现有资料
|
|
|
- **生成式 AI**:像问一个博学的朋友关于猫的知识——他们用自己的话,针对你想知道的内容讲述有趣的知识
|
|
|
|
|
|
```mermaid
|
|
|
graph LR
|
|
|
A[你的问题] --> B[AI模型]
|
|
|
B --> C[模式识别]
|
|
|
C --> D[内容生成]
|
|
|
D --> E[上下文响应]
|
|
|
|
|
|
F[训练数据<br/>书籍,文章,网络] --> B
|
|
|
```
|
|
|
### AI 模型如何学习(简化说明)
|
|
|
|
|
|
AI 模型通过接触包含书籍、文章和对话文本的巨大数据集学习。在此过程中,它们识别出:
|
|
|
- 思维在书面交流中的构造方式
|
|
|
- 通常一起出现的词汇
|
|
|
- 对话的典型流转
|
|
|
- 正式与非正式交流的上下文差异
|
|
|
|
|
|
**这类似考古学家解码古代语言**:他们分析数千个实例,理解语法、词汇和文化背景,最终能够运用学到的模式解读新文本。
|
|
|
|
|
|
### 为什么选用 GitHub Models?
|
|
|
|
|
|
我们使用 GitHub Models 非常实用——它让我们无需自行搭建 AI 基础设施(相信我,你现在不想这么做!)即可使用企业级 AI。就像使用天气 API 而不是自己到处布置气象站预测天气。
|
|
|
|
|
|
它基本上是“AI 即服务”,好处是可以免费开始尝试,不用担心产生高昂费用。
|
|
|
|
|
|
```mermaid
|
|
|
graph LR
|
|
|
A[前端聊天界面] --> B[您的后端API]
|
|
|
B --> C[GitHub模型API]
|
|
|
C --> D[AI模型处理]
|
|
|
D --> C
|
|
|
C --> B
|
|
|
B --> A
|
|
|
```
|
|
|
我们将用 GitHub Models 做后端集成,通过为开发者优化的界面访问专业级 AI 功能。 [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground) 是测试环境,你可以尝试不同 AI 模型,理解其能力后再在代码中实现它们。
|
|
|
|
|
|
## 🧠 AI 应用开发生态系统
|
|
|
|
|
|
```mermaid
|
|
|
mindmap
|
|
|
root((AI 开发))
|
|
|
Understanding AI
|
|
|
Generative Models
|
|
|
Pattern Recognition
|
|
|
Content Generation
|
|
|
Context Understanding
|
|
|
Response Synthesis
|
|
|
AI Parameters
|
|
|
Temperature Control
|
|
|
Token Limits
|
|
|
Top-p Filtering
|
|
|
System Prompts
|
|
|
Backend Architecture
|
|
|
API Integration
|
|
|
GitHub Models
|
|
|
Authentication
|
|
|
Request Handling
|
|
|
Error Management
|
|
|
Python Infrastructure
|
|
|
FastAPI Framework
|
|
|
Async Operations
|
|
|
Environment Security
|
|
|
CORS Configuration
|
|
|
Frontend Experience
|
|
|
Chat Interface
|
|
|
Real-time Updates
|
|
|
Message History
|
|
|
User Feedback
|
|
|
Loading States
|
|
|
Modern Web Tech
|
|
|
ES6 Classes
|
|
|
Async/Await
|
|
|
DOM Manipulation
|
|
|
Event Handling
|
|
|
Professional Patterns
|
|
|
Security Best Practices
|
|
|
Token Management
|
|
|
Input Validation
|
|
|
XSS Prevention
|
|
|
Error Boundaries
|
|
|
Production Readiness
|
|
|
Performance Optimization
|
|
|
Responsive Design
|
|
|
Accessibility
|
|
|
Testing Strategies
|
|
|
```
|
|
|
**核心原则**:AI 应用开发融合传统网页开发技能与 AI 服务集成,创建感觉自然且响应迅速的智能应用。
|
|
|
|
|
|

|
|
|
|
|
|
**Playground 超有用的原因:**
|
|
|
- **试用** 不同 AI 模型如 GPT-4o-mini、Claude 等(全都免费!)
|
|
|
- **测试** 你的想法和提示,代码编写前先验
|
|
|
- **获取** 适用你喜好编程语言的示例代码
|
|
|
- **调整** 创造力水平和响应长度等设置,观察输出变化
|
|
|
|
|
|
玩过后,直接点“Code”标签选你要的编程语言,拿到实现代码。
|
|
|
|
|
|

|
|
|
|
|
|
## 配置 Python 后端集成
|
|
|
|
|
|
现在用 Python 实现 AI 集成。Python 因语法简单且库强大,非常适合 AI 应用。我们将从 GitHub Models playground 的代码开始,然后重构成可复用、适用于生产的函数。
|
|
|
|
|
|
### 理解基础实现
|
|
|
|
|
|
从 playground 获取的 Python 代码大致如下。别担心开始时代码看起来复杂——我们逐步讲解:
|
|
|
|
|
|
```python
|
|
|
"""Run this model in Python
|
|
|
|
|
|
> pip install openai
|
|
|
"""
|
|
|
import os
|
|
|
from openai import OpenAI
|
|
|
|
|
|
# 要与模型进行身份验证,您需要在GitHub设置中生成个人访问令牌(PAT)。
|
|
|
# 按照此处的说明创建您的PAT令牌:https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
|
|
|
client = OpenAI(
|
|
|
base_url="https://models.github.ai/inference",
|
|
|
api_key=os.environ["GITHUB_TOKEN"],
|
|
|
)
|
|
|
|
|
|
response = client.chat.completions.create(
|
|
|
messages=[
|
|
|
{
|
|
|
"role": "system",
|
|
|
"content": "",
|
|
|
},
|
|
|
{
|
|
|
"role": "user",
|
|
|
"content": "What is the capital of France?",
|
|
|
}
|
|
|
],
|
|
|
model="openai/gpt-4o-mini",
|
|
|
temperature=1,
|
|
|
max_tokens=4096,
|
|
|
top_p=1
|
|
|
)
|
|
|
|
|
|
print(response.choices[0].message.content)
|
|
|
```
|
|
|
|
|
|
**代码中的关键操作:**
|
|
|
- **导入** 需要的工具:`os` 用于读取环境变量,`OpenAI` 用于与 AI 通讯
|
|
|
- **设置** OpenAI 客户端,指向 GitHub 的 AI 服务器而非直接 OpenAI
|
|
|
- **验证** 采用特殊的 GitHub 令牌(稍后详述!)
|
|
|
- **构造** 多角色对话结构——可想象成为戏剧布置场景
|
|
|
- **发送** 请求至 AI,带有微调参数
|
|
|
- **提取** 返回数据中的实际回应文本
|
|
|
|
|
|
### 理解消息角色:AI 对话框架
|
|
|
|
|
|
AI 对话采用特定结构,包含不同“角色”以实现各自功能:
|
|
|
|
|
|
```python
|
|
|
messages=[
|
|
|
{
|
|
|
"role": "system",
|
|
|
"content": "You are a helpful assistant who explains things simply."
|
|
|
},
|
|
|
{
|
|
|
"role": "user",
|
|
|
"content": "What is machine learning?"
|
|
|
}
|
|
|
]
|
|
|
```
|
|
|
|
|
|
**就像导演排戏:**
|
|
|
- **System 角色**:给演员的舞台指导——告诉 AI 如何表现、具备什么个性和应答方式
|
|
|
- **User 角色**:使用者的问题或信息
|
|
|
- **Assistant 角色**:AI 的回答(你不会发送,出现在对话历史中)
|
|
|
|
|
|
**现实模拟**:想象你在派对介绍朋友:
|
|
|
- **系统消息**:“这是我的朋友 Sarah,她是位医生,擅长用简单语言解释医学概念”
|
|
|
- **用户消息**:“你能解释疫苗如何工作吗?”
|
|
|
- **助手回应**:Sarah 以友好的医生身份作答,而非律师或厨师身份
|
|
|
|
|
|
### 理解 AI 参数:微调应答行为
|
|
|
|
|
|
AI API 中的数值参数控制模型生成回答的方式。这些设置能让你根据不同场景调整 AI 行为:
|
|
|
|
|
|
#### Temperature(0.0 到 2.0):创造力旋钮
|
|
|
|
|
|
**作用**:控制 AI 回答的创造力或可预测性。
|
|
|
|
|
|
**想象一名爵士乐手的即兴水平:**
|
|
|
- **Temperature = 0.1**:每次演奏完全相同旋律(非常可预测)
|
|
|
- **Temperature = 0.7**:带有适度变化,既可识别又有创意(均衡创造力)
|
|
|
- **Temperature = 1.5**:完全实验性爵士,大量意外转折(高度不可预测)
|
|
|
|
|
|
```python
|
|
|
# 非常可预测的回答(适合事实性问题)
|
|
|
response = client.chat.completions.create(
|
|
|
messages=[{"role": "user", "content": "What is 2+2?"}],
|
|
|
temperature=0.1 # 几乎总是会说“4”
|
|
|
)
|
|
|
|
|
|
# 有创意的回答(适合头脑风暴)
|
|
|
response = client.chat.completions.create(
|
|
|
messages=[{"role": "user", "content": "Write a creative story opening"}],
|
|
|
temperature=1.2 # 会生成独特且出乎意料的故事
|
|
|
)
|
|
|
```
|
|
|
|
|
|
#### Max Tokens(1 到 4096+):回答长度控制器
|
|
|
|
|
|
**作用**:设置 AI 回答的最长长度限制。
|
|
|
|
|
|
**Token 大致等同于单词**(英文约1个 token = 0.75个词):
|
|
|
- **max_tokens=50**:简短回复(类似短信)
|
|
|
- **max_tokens=500**:一两段合适长度的段落
|
|
|
- **max_tokens=2000**:含示例的详细解释
|
|
|
|
|
|
```python
|
|
|
# 简短,精炼的回答
|
|
|
response = client.chat.completions.create(
|
|
|
messages=[{"role": "user", "content": "Explain JavaScript"}],
|
|
|
max_tokens=100 # 强制简短解释
|
|
|
)
|
|
|
|
|
|
# 详细,全面的回答
|
|
|
response = client.chat.completions.create(
|
|
|
messages=[{"role": "user", "content": "Explain JavaScript"}],
|
|
|
max_tokens=1500 # 允许详细的解释和示例
|
|
|
)
|
|
|
```
|
|
|
|
|
|
#### Top_p(0.0 到 1.0):专注度参数
|
|
|
|
|
|
**作用**:控制 AI 在生成回答时集中在概率最高的词汇程度。
|
|
|
|
|
|
**想象 AI 拥有庞大词汇表,按词出现概率排序:**
|
|
|
- **top_p=0.1**:只考虑概率最高的10%词汇(非常集中)
|
|
|
- **top_p=0.9**:考虑90%的可能词汇(更多创意)
|
|
|
- **top_p=1.0**:考虑所有词汇(最大多样性)
|
|
|
|
|
|
**举例**:你问 “天空通常是……”
|
|
|
- **低 top_p**:几乎肯定回答“蓝色”
|
|
|
- **高 top_p**:可能回答“蓝色”、“多云”、“辽阔”、“变化多端”、“美丽”等
|
|
|
|
|
|
### 综合应用:针对不同场景的参数组合
|
|
|
|
|
|
```python
|
|
|
# 用于提供事实性、一致性的答案(如文档机器人)
|
|
|
factual_params = {
|
|
|
"temperature": 0.2,
|
|
|
"max_tokens": 300,
|
|
|
"top_p": 0.3
|
|
|
}
|
|
|
|
|
|
# 用于创意写作辅助
|
|
|
creative_params = {
|
|
|
"temperature": 1.1,
|
|
|
"max_tokens": 1000,
|
|
|
"top_p": 0.9
|
|
|
}
|
|
|
|
|
|
# 用于对话式、有帮助的回复(平衡型)
|
|
|
conversational_params = {
|
|
|
"temperature": 0.7,
|
|
|
"max_tokens": 500,
|
|
|
"top_p": 0.8
|
|
|
}
|
|
|
```
|
|
|
|
|
|
```mermaid
|
|
|
quadrantChart
|
|
|
title AI 参数优化矩阵
|
|
|
x-axis 低创造力 --> 高创造力
|
|
|
y-axis 短响应 --> 长响应
|
|
|
|
|
|
quadrant-1 创意内容
|
|
|
quadrant-2 详细分析
|
|
|
quadrant-3 快速事实
|
|
|
quadrant-4 会话式 AI
|
|
|
|
|
|
Documentation Bot: [0.2, 0.3]
|
|
|
Customer Service: [0.4, 0.4]
|
|
|
General Assistant: [0.7, 0.5]
|
|
|
Creative Writer: [0.9, 0.9]
|
|
|
Brainstorming Tool: [0.8, 0.8]
|
|
|
```
|
|
|
**为什么参数重要**:不同应用需要不同类型的回答。例如客户服务机器人需要稳定且事实性强的回答(低 Temperature),而创意写作助手则需富有想象力(高 Temperature)。掌握这些参数让你能塑造 AI 个性和回应风格。
|
|
|
```
|
|
|
|
|
|
**Here's what's happening in this code:**
|
|
|
- **We import** the tools we need: `os` for reading environment variables and `OpenAI` for talking to the AI
|
|
|
- **We set up** the OpenAI client to point to GitHub's AI servers instead of OpenAI directly
|
|
|
- **We authenticate** using a special GitHub token (more on that in a minute!)
|
|
|
- **We structure** our conversation with different "roles" – think of it like setting the scene for a play
|
|
|
- **We send** our request to the AI with some fine-tuning parameters
|
|
|
- **We extract** the actual response text from all the data that comes back
|
|
|
|
|
|
> 🔐 **Security Note**: Never hardcode API keys in your source code! Always use environment variables to store sensitive credentials like your `GITHUB_TOKEN`.
|
|
|
|
|
|
### Creating a Reusable AI Function
|
|
|
|
|
|
Let's refactor this code into a clean, reusable function that we can easily integrate into our web application:
|
|
|
|
|
|
```python
|
|
|
import asyncio
|
|
|
from openai import AsyncOpenAI
|
|
|
|
|
|
# Use AsyncOpenAI for better performance
|
|
|
client = AsyncOpenAI(
|
|
|
base_url="https://models.github.ai/inference",
|
|
|
api_key=os.environ["GITHUB_TOKEN"],
|
|
|
)
|
|
|
|
|
|
async def call_llm_async(prompt: str, system_message: str = "You are a helpful assistant."):
|
|
|
"""
|
|
|
Sends a prompt to the AI model asynchronously and returns the response.
|
|
|
|
|
|
Args:
|
|
|
prompt: The user's question or message
|
|
|
system_message: Instructions that define the AI's behavior and personality
|
|
|
|
|
|
Returns:
|
|
|
str: The AI's response to the prompt
|
|
|
"""
|
|
|
try:
|
|
|
response = await client.chat.completions.create(
|
|
|
messages=[
|
|
|
{
|
|
|
"role": "system",
|
|
|
"content": system_message,
|
|
|
},
|
|
|
{
|
|
|
"role": "user",
|
|
|
"content": prompt,
|
|
|
}
|
|
|
],
|
|
|
model="openai/gpt-4o-mini",
|
|
|
temperature=1,
|
|
|
max_tokens=4096,
|
|
|
top_p=1
|
|
|
)
|
|
|
return response.choices[0].message.content
|
|
|
except Exception as e:
|
|
|
logger.error(f"AI API error: {str(e)}")
|
|
|
return "I'm sorry, I'm having trouble processing your request right now."
|
|
|
|
|
|
# Backward compatibility function for synchronous calls
|
|
|
def call_llm(prompt: str, system_message: str = "You are a helpful assistant."):
|
|
|
"""Synchronous wrapper for async AI calls."""
|
|
|
return asyncio.run(call_llm_async(prompt, system_message))
|
|
|
```
|
|
|
|
|
|
**理解此改进函数:**
|
|
|
- **接收**两个参数:用户提示和可选的系统消息
|
|
|
- **提供**默认系统消息以控制一般助理行为
|
|
|
- **使用**恰当的 Python 类型注解,增强代码可读性
|
|
|
- **包含**详细文档字符串说明函数目的及参数
|
|
|
- **只返回**响应内容,便于在 Web API 中使用
|
|
|
- **保持**模型参数不变,保证 AI 行为一致
|
|
|
|
|
|
### 系统提示的魔力:编程 AI 个性
|
|
|
|
|
|
如果参数控制 AI 如何“思考”,系统提示控制 AI “认为自己是谁”。这真是 AI 工作中最酷的部分之一——你实际上是在赋予 AI 完整个性、专业水平和沟通风格。
|
|
|
|
|
|
**把系统提示想象成为不同角色选角**:你不必只有一位通用助理,可创建适用于不同场合的专家。需要耐心老师?创造性头脑风暴伙伴?直截了当的商业顾问?只需更改系统提示即可!
|
|
|
|
|
|
#### 系统提示为何如此强大
|
|
|
|
|
|
有趣的是:AI 模型经过无数对话训练,人们在对话中扮演不同角色和展现不同专业水平。给 AI 明确的角色相当于开关,激活这些学习到的模式。
|
|
|
|
|
|
**这就像 AI 的方法派演技**:告诉演员“你是位睿智老教授”,观察他们如何自动调整姿态、用词和举止。AI 用语言模式做同样操作。
|
|
|
|
|
|
#### 打造有效系统提示的艺术与科学
|
|
|
|
|
|
**一个优质系统提示的结构:**
|
|
|
1. **角色/身份**:AI 是谁?
|
|
|
2. **专业领域**:懂什么?
|
|
|
3. **沟通风格**:如何说话?
|
|
|
4. **具体指令**:专注什么?
|
|
|
|
|
|
```python
|
|
|
# ❌ 模糊的系统提示
|
|
|
"You are helpful."
|
|
|
|
|
|
# ✅ 详细且有效的系统提示
|
|
|
"You are Dr. Sarah Chen, a senior software engineer with 15 years of experience at major tech companies. You explain programming concepts using real-world analogies and always provide practical examples. You're patient with beginners and enthusiastic about helping them understand complex topics."
|
|
|
```
|
|
|
|
|
|
#### 系统提示示例及上下文
|
|
|
|
|
|
看看不同系统提示如何塑造截然不同的 AI 个性:
|
|
|
|
|
|
```python
|
|
|
# 示例 1:耐心的老师
|
|
|
teacher_prompt = """
|
|
|
You are an experienced programming instructor who has taught thousands of students.
|
|
|
You break down complex concepts into simple steps, use analogies from everyday life,
|
|
|
and always check if the student understands before moving on. You're encouraging
|
|
|
and never make students feel bad for not knowing something.
|
|
|
"""
|
|
|
|
|
|
# 示例 2:富有创意的合作者
|
|
|
creative_prompt = """
|
|
|
You are a creative writing partner who loves brainstorming wild ideas. You're
|
|
|
enthusiastic, imaginative, and always build on the user's ideas rather than
|
|
|
replacing them. You ask thought-provoking questions to spark creativity and
|
|
|
offer unexpected perspectives that make stories more interesting.
|
|
|
"""
|
|
|
|
|
|
# 示例 3:战略商业顾问
|
|
|
business_prompt = """
|
|
|
You are a strategic business consultant with an MBA and 20 years of experience
|
|
|
helping startups scale. You think in frameworks, provide structured advice,
|
|
|
and always consider both short-term tactics and long-term strategy. You ask
|
|
|
probing questions to understand the full business context before giving advice.
|
|
|
"""
|
|
|
```
|
|
|
|
|
|
#### 观察系统提示的实际效果
|
|
|
|
|
|
用不同系统提示测试同一问题,感受区别:
|
|
|
|
|
|
**问题**:“我如何处理我的网页应用中的用户认证?”
|
|
|
|
|
|
```python
|
|
|
# 使用教师提示:
|
|
|
teacher_response = call_llm(
|
|
|
"How do I handle user authentication in my web app?",
|
|
|
teacher_prompt
|
|
|
)
|
|
|
# 典型回复:“好问题!让我们将身份验证拆解成简单的步骤。
|
|
|
# 把它想象成夜总会保安检查身份证……”
|
|
|
|
|
|
# 使用商业提示:
|
|
|
business_response = call_llm(
|
|
|
"How do I handle user authentication in my web app?",
|
|
|
business_prompt
|
|
|
)
|
|
|
# 典型回复:“从战略角度来看,身份验证对于用户
|
|
|
# 信任和合规性至关重要。让我概述一个考虑安全性、
|
|
|
# 用户体验和可扩展性的框架……”
|
|
|
```
|
|
|
|
|
|
#### 高级系统提示技巧
|
|
|
|
|
|
**1. 上下文设定**:给 AI 背景信息
|
|
|
```python
|
|
|
system_prompt = """
|
|
|
You are helping a junior developer who just started their first job at a startup.
|
|
|
They know basic HTML/CSS/JavaScript but are new to backend development and databases.
|
|
|
Be encouraging and explain things step-by-step without being condescending.
|
|
|
"""
|
|
|
```
|
|
|
|
|
|
**2. 输出格式**:告诉 AI 如何结构化响应
|
|
|
```python
|
|
|
system_prompt = """
|
|
|
You are a technical mentor. Always structure your responses as:
|
|
|
1. Quick Answer (1-2 sentences)
|
|
|
2. Detailed Explanation
|
|
|
3. Code Example
|
|
|
4. Common Pitfalls to Avoid
|
|
|
5. Next Steps for Learning
|
|
|
"""
|
|
|
```
|
|
|
|
|
|
**3. 约束设置**:定义 AI 不应该做什么
|
|
|
```python
|
|
|
system_prompt = """
|
|
|
You are a coding tutor focused on teaching best practices. Never write complete
|
|
|
solutions for the user - instead, guide them with hints and questions so they
|
|
|
learn by doing. Always explain the 'why' behind coding decisions.
|
|
|
"""
|
|
|
```
|
|
|
|
|
|
#### 为什么这对于您的聊天助手很重要
|
|
|
|
|
|
理解系统提示让您拥有强大能力,创建专业的 AI 助手:
|
|
|
- **客服机器人**:有帮助、耐心、了解政策
|
|
|
- **学习导师**:鼓励、循序渐进、检查理解情况
|
|
|
- **创意伙伴**:富有想象力、构建想法、提出“如果怎样?”
|
|
|
- **技术专家**:精准、详尽,注重安全
|
|
|
|
|
|
**关键洞见**:您不仅仅是在调用 AI API——您正在创建一个为您的特定用例服务的定制 AI 个性。这就是现代 AI 应用感觉定制且有用,而非泛泛之辈的原因。
|
|
|
|
|
|
### 🎯 教学检查:AI 个性编程
|
|
|
|
|
|
**暂停反思**:您刚刚学习了通过系统提示编程 AI 个性。这是现代 AI 应用开发的基本技能。
|
|
|
|
|
|
**快速自我评估**:
|
|
|
- 您能解释系统提示与普通用户消息有何不同吗?
|
|
|
- temperature 和 top_p 参数有何区别?
|
|
|
- 您如何为特定用例(如编程导师)创建系统提示?
|
|
|
|
|
|
**现实世界联系**:您学习的系统提示技术应用在所有主要的 AI 应用中——从 GitHub Copilot 的代码辅助到 ChatGPT 的对话界面。您正在掌握大型科技公司 AI 产品团队使用的相同模式。
|
|
|
|
|
|
**挑战问题**:您如何为不同用户类型(初学者 vs 专家)设计不同的 AI 个性?考虑如何通过提示工程让同一个底层 AI 模型服务不同受众。
|
|
|
|
|
|
## 使用 FastAPI 构建 Web API:您的高性能 AI 通信中枢
|
|
|
|
|
|
现在让我们构建连接前端与 AI 服务的后端。我们将使用 FastAPI,这是一款现代 Python 框架,擅长构建 AI 应用的 API。
|
|
|
|
|
|
FastAPI 为此类项目提供了多项优势:内置异步支持处理并发请求、自动生成 API 文档以及卓越性能。您的 FastAPI 服务器充当中介,接收来自前端的请求,调用 AI 服务,并返回格式化响应。
|
|
|
|
|
|
### 为什么选择 FastAPI 用于 AI 应用?
|
|
|
|
|
|
您可能会想:“我不是可以直接用前端 JavaScript 调用 AI 吗?”或“为什么用 FastAPI,而不是 Flask 或 Django?”好问题!
|
|
|
|
|
|
**FastAPI 之所以适合我们的构建,原因如下:**
|
|
|
- **默认异步**:可以同时处理多个 AI 请求,不会卡住
|
|
|
- **自动文档**:访问 `/docs` 即可免费获得漂亮且交互式的 API 文档页面
|
|
|
- **内置验证**:在出现问题前捕获错误
|
|
|
- **速度快**:Python 框架中速度最快之一
|
|
|
- **现代 Python**:利用所有最新最棒的 Python 特性
|
|
|
|
|
|
**而我们为什么需要后端:**
|
|
|
|
|
|
**安全**:您的 AI API 密钥就像密码——如果放在前端 JavaScript 中,任何查看您网站源码的人都能窃取并使用您的 AI 配额。后端可以保护秘密凭据。
|
|
|
|
|
|
**限流与控制**:后端允许您控制用户请求频率,实施用户认证,并添加日志记录以追踪使用情况。
|
|
|
|
|
|
**数据处理**:您可能想保存对话、过滤不当内容或组合多个 AI 服务。后端是这些逻辑所在。
|
|
|
|
|
|
**架构类似客户端-服务器模型:**
|
|
|
- **前端**:交互的用户界面层
|
|
|
- **后端 API**:请求处理和路由层
|
|
|
- **AI 服务**:外部计算与响应生成
|
|
|
- **环境变量**:安全配置和凭据存储
|
|
|
|
|
|
### 理解请求-响应流程
|
|
|
|
|
|
让我们追踪用户发送一条消息时的过程:
|
|
|
|
|
|
```mermaid
|
|
|
sequenceDiagram
|
|
|
participant User as 👤 用户
|
|
|
participant Frontend as 🌐 前端
|
|
|
participant API as 🔧 FastAPI 服务器
|
|
|
participant AI as 🤖 AI 服务
|
|
|
|
|
|
User->>Frontend: 输入 "你好 AI!"
|
|
|
Frontend->>API: POST /hello {"message": "你好 AI!"}
|
|
|
Note over API: 验证请求<br/>添加系统提示
|
|
|
API->>AI: 发送格式化请求
|
|
|
AI->>API: 返回 AI 响应
|
|
|
Note over API: 处理响应<br/>记录对话
|
|
|
API->>Frontend: {"response": "你好!我能帮您什么?"}
|
|
|
Frontend->>User: 显示 AI 消息
|
|
|
```
|
|
|
**理解每一步:**
|
|
|
1. **用户交互**:人在聊天界面输入
|
|
|
2. **前端处理**:JavaScript 捕获输入并格式化为 JSON
|
|
|
3. **API 验证**:FastAPI 使用 Pydantic 模型自动验证请求
|
|
|
4. **AI 集成**:后端添加上下文(系统提示)并调用 AI 服务
|
|
|
5. **响应处理**:API 接收 AI 响应并根据需要修改
|
|
|
6. **前端显示**:JavaScript 在聊天界面显示响应
|
|
|
|
|
|
### 理解 API 架构
|
|
|
|
|
|
```mermaid
|
|
|
sequenceDiagram
|
|
|
participant Frontend
|
|
|
participant FastAPI
|
|
|
participant AI Function
|
|
|
participant GitHub Models
|
|
|
|
|
|
Frontend->>FastAPI: POST /hello {"message": "你好 AI!"}
|
|
|
FastAPI->>AI Function: call_llm(message, system_prompt)
|
|
|
AI Function->>GitHub Models: API 请求
|
|
|
GitHub Models->>AI Function: AI 响应
|
|
|
AI Function->>FastAPI: 响应文本
|
|
|
FastAPI->>Frontend: {"response": "你好!我能帮你什么?"}
|
|
|
```
|
|
|
```mermaid
|
|
|
flowchart TD
|
|
|
A[用户输入] --> B[前端校验]
|
|
|
B --> C[HTTP POST 请求]
|
|
|
C --> D[FastAPI 路由]
|
|
|
D --> E[Pydantic 校验]
|
|
|
E --> F[AI 函数调用]
|
|
|
F --> G[GitHub 模型 API]
|
|
|
G --> H[响应处理]
|
|
|
H --> I[JSON 响应]
|
|
|
I --> J[前端更新]
|
|
|
|
|
|
subgraph "安全层"
|
|
|
K[CORS 中间件]
|
|
|
L[环境变量]
|
|
|
M[错误处理]
|
|
|
end
|
|
|
|
|
|
D --> K
|
|
|
F --> L
|
|
|
H --> M
|
|
|
```
|
|
|
### 创建 FastAPI 应用
|
|
|
|
|
|
让我们一步步构建 API。创建文件 `api.py`,内容如下:
|
|
|
|
|
|
```python
|
|
|
# api.py
|
|
|
from fastapi import FastAPI, HTTPException
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
from pydantic import BaseModel
|
|
|
from llm import call_llm
|
|
|
import logging
|
|
|
|
|
|
# 配置日志记录
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# 创建FastAPI应用
|
|
|
app = FastAPI(
|
|
|
title="AI Chat API",
|
|
|
description="A high-performance API for AI-powered chat applications",
|
|
|
version="1.0.0"
|
|
|
)
|
|
|
|
|
|
# 配置跨域资源共享(CORS)
|
|
|
app.add_middleware(
|
|
|
CORSMiddleware,
|
|
|
allow_origins=["*"], # 为生产环境进行适当配置
|
|
|
allow_credentials=True,
|
|
|
allow_methods=["*"],
|
|
|
allow_headers=["*"],
|
|
|
)
|
|
|
|
|
|
# 用于请求/响应验证的Pydantic模型
|
|
|
class ChatMessage(BaseModel):
|
|
|
message: str
|
|
|
|
|
|
class ChatResponse(BaseModel):
|
|
|
response: str
|
|
|
|
|
|
@app.get("/")
|
|
|
async def root():
|
|
|
"""Root endpoint providing API information."""
|
|
|
return {
|
|
|
"message": "Welcome to the AI Chat API",
|
|
|
"docs": "/docs",
|
|
|
"health": "/health"
|
|
|
}
|
|
|
|
|
|
@app.get("/health")
|
|
|
async def health_check():
|
|
|
"""Health check endpoint."""
|
|
|
return {"status": "healthy", "service": "ai-chat-api"}
|
|
|
|
|
|
@app.post("/hello", response_model=ChatResponse)
|
|
|
async def chat_endpoint(chat_message: ChatMessage):
|
|
|
"""Main chat endpoint that processes messages and returns AI responses."""
|
|
|
try:
|
|
|
# 提取并验证消息
|
|
|
message = chat_message.message.strip()
|
|
|
if not message:
|
|
|
raise HTTPException(status_code=400, detail="Message cannot be empty")
|
|
|
|
|
|
logger.info(f"Processing message: {message[:50]}...")
|
|
|
|
|
|
# 调用AI服务(注意:call_llm应当异步调用以提升性能)
|
|
|
ai_response = await call_llm_async(message, "You are a helpful and friendly assistant.")
|
|
|
|
|
|
logger.info("AI response generated successfully")
|
|
|
return ChatResponse(response=ai_response)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
logger.error(f"Error processing chat message: {str(e)}")
|
|
|
raise HTTPException(status_code=500, detail="Internal server error")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
import uvicorn
|
|
|
uvicorn.run(app, host="0.0.0.0", port=5000, reload=True)
|
|
|
```
|
|
|
|
|
|
**理解 FastAPI 实现:**
|
|
|
- **导入** FastAPI 实现现代 Web 框架功能,和 Pydantic 用于数据验证
|
|
|
- **创建** 自动 API 文档(服务器运行时可在 `/docs` 访问)
|
|
|
- **启用** CORS 中间件允许来自不同来源的前端请求
|
|
|
- **定义** Pydantic 模型,实现自动请求/响应验证与文档生成
|
|
|
- **使用** 异步端点以提升并发请求的性能
|
|
|
- **实现** 正确的 HTTP 状态码和错误处理,使用 HTTPException
|
|
|
- **包含** 结构化日志以便监控和调试
|
|
|
- **提供** 健康检查端点用于监控服务状态
|
|
|
|
|
|
**FastAPI 相比传统框架的优势:**
|
|
|
- **自动验证**:Pydantic 模型保证处理前数据完整性
|
|
|
- **交互文档**:访问 `/docs` 获取自动生成的、可测试 API 文档
|
|
|
- **类型安全**:Python 类型提示防止运行时错误,提高代码质量
|
|
|
- **异步支持**:无阻塞地同时处理多个 AI 请求
|
|
|
- **性能优越**:实时应用请求处理速度显著提升
|
|
|
|
|
|
### 理解 CORS:网络的安全守护
|
|
|
|
|
|
CORS(跨源资源共享)就像建筑物门口的保安,检查访客是否获准入内。让我们了解其重要性以及如何影响应用。
|
|
|
|
|
|
#### 什么是 CORS 及其存在原因?
|
|
|
|
|
|
**问题**:假设任何网站都能无许可代表您向银行网站发请求,那将是安全灾难!浏览器默认通过 “同源策略” 来防止这种情况。
|
|
|
|
|
|
**同源策略**:浏览器只允许网页向加载该页面的相同域、端口和协议发请求。
|
|
|
|
|
|
**形象比喻**:这就像公寓楼保安——默认只有住户(同源)能进入楼内。若您想让朋友(异源)访问,需明确告知保安。
|
|
|
|
|
|
#### 开发环境中的 CORS
|
|
|
|
|
|
开发时前后端运行在不同端口:
|
|
|
- 前端:`http://localhost:3000`(或者直接打开 HTML 是 file://)
|
|
|
- 后端:`http://localhost:5000`
|
|
|
|
|
|
即使都在同一台电脑上,仍被视为“不同来源”!
|
|
|
|
|
|
```python
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
|
|
app = FastAPI(__name__)
|
|
|
CORS(app) # 这告诉浏览器:“允许其他来源对这个API发起请求”
|
|
|
```
|
|
|
|
|
|
**CORS 配置的实际作用:**
|
|
|
- **添加** 特殊 HTTP 头,告知浏览器“此跨源请求被允许”
|
|
|
- **处理** “预检”请求(浏览器有时先核查权限再发正式请求)
|
|
|
- **防止** 浏览器控制台出现可恶的 “被 CORS 策略阻止” 错误
|
|
|
|
|
|
#### CORS 安全性:开发 vs 生产
|
|
|
|
|
|
```python
|
|
|
# 🚨 开发:允许所有来源(方便但不安全)
|
|
|
CORS(app)
|
|
|
|
|
|
# ✅ 生产:仅允许您的特定前端域名
|
|
|
CORS(app, origins=["https://yourdomain.com", "https://www.yourdomain.com"])
|
|
|
|
|
|
# 🔒 高级:不同环境不同来源
|
|
|
if app.debug: # 开发模式
|
|
|
CORS(app, origins=["http://localhost:3000", "http://127.0.0.1:3000"])
|
|
|
else: # 生产模式
|
|
|
CORS(app, origins=["https://yourdomain.com"])
|
|
|
```
|
|
|
|
|
|
**重要性说明**:开发阶段,`CORS(app)` 就像没锁前门——方便但不安全。生产环境应明确指定允许访问 API 的网站。
|
|
|
|
|
|
#### 常见 CORS 场景与解决方案
|
|
|
|
|
|
| 场景 | 问题 | 解决方案 |
|
|
|
|--------------------|----------------------------|------------------------------|
|
|
|
| **本地开发** | 前端无法访问后端 | 为 FastAPI 添加 CORSMiddleware |
|
|
|
| **GitHub Pages + Heroku** | 部署的前端无法访问 API | 将 GitHub Pages URL 添加到 CORS origins |
|
|
|
| **自定义域名** | 生产环境出现 CORS 错误 | 更新 CORS origins 以匹配域名 |
|
|
|
| **移动应用** | 应用无法访问 Web API | 添加应用域名,或谨慎使用 `*` |
|
|
|
|
|
|
**专家提示**:您可以在浏览器开发者工具的网络 (Network) 标签页检查 CORS 头。查看响应中的 `Access-Control-Allow-Origin` 等头信息。
|
|
|
|
|
|
### 错误处理和验证
|
|
|
|
|
|
注意我们的 API 包含了完整的错误处理:
|
|
|
|
|
|
```python
|
|
|
# 验证我们是否收到了消息
|
|
|
if not message:
|
|
|
return jsonify({"error": "Message field is required"}), 400
|
|
|
```
|
|
|
|
|
|
**关键验证原则:**
|
|
|
- **检查** 请求中的必填字段
|
|
|
- **返回** 有意义的错误信息(JSON 格式)
|
|
|
- **使用** 合适的 HTTP 状态码(400 表示请求错误)
|
|
|
- **提供** 清晰反馈,帮助前端开发调试问题
|
|
|
|
|
|
## 设置和运行您的后端
|
|
|
|
|
|
现在 AI 集成和 FastAPI 服务器都准备好了,让我们启动一切。设置过程包括安装 Python 依赖、配置环境变量和启动开发服务器。
|
|
|
|
|
|
### Python 环境设置
|
|
|
|
|
|
让我们搭建 Python 开发环境。虚拟环境就像曼哈顿计划中的隔离工作——每个项目拥有独立空间,使用特定工具和依赖,避免不同项目间冲突。
|
|
|
|
|
|
```bash
|
|
|
# 导航到你的后端目录
|
|
|
cd backend
|
|
|
|
|
|
# 创建一个虚拟环境(就像为你的项目创建一个洁净室)
|
|
|
python -m venv venv
|
|
|
|
|
|
# 激活它(Linux/Mac)
|
|
|
source ./venv/bin/activate
|
|
|
|
|
|
# 在Windows上,使用:
|
|
|
# venv\Scripts\activate
|
|
|
|
|
|
# 安装好东西
|
|
|
pip install openai fastapi uvicorn python-dotenv
|
|
|
```
|
|
|
|
|
|
**我们刚做了什么:**
|
|
|
- **创建** 自己的小 Python “泡泡”,安装包不会影响其他环境
|
|
|
- **激活** 该环境,让终端知道使用的是这个隔离空间
|
|
|
- **安装** 必要依赖:OpenAI 让 AI 变魔法,FastAPI 搭建网页 API,Uvicorn 运行服务器,python-dotenv 处理安全密钥
|
|
|
|
|
|
**核心依赖解释:**
|
|
|
- **FastAPI**:现代快速的 Web 框架,自动生成 API 文档
|
|
|
- **Uvicorn**:超快的 ASGI 服务器,运行 FastAPI 应用
|
|
|
- **OpenAI**:官方库,集成 GitHub 模型及 OpenAI API
|
|
|
- **python-dotenv**:从 .env 文件安全加载环境变量
|
|
|
|
|
|
### 环境配置:保护您的秘密
|
|
|
|
|
|
在启动 API 之前,有个最重要的课程:如何真正保护您的秘密。环境变量就像保险箱,只有您的应用能访问。
|
|
|
|
|
|
#### 什么是环境变量?
|
|
|
|
|
|
**把环境变量想象成保险箱**——您把贵重物品放进去,只有您(和应用)有钥匙取出。与把敏感信息直接写在代码(任何人都能看到)不同,环境变量可以安全存储。
|
|
|
|
|
|
**区别在于:**
|
|
|
- **错误的做法**:把密码写在便利贴贴在显示器上
|
|
|
- **正确的做法**:用密码管理器安全保管,只有您能访问
|
|
|
|
|
|
#### 为什么环境变量很重要
|
|
|
|
|
|
```python
|
|
|
# 🚨 绝不要这样做 - API密钥对所有人可见
|
|
|
client = OpenAI(
|
|
|
api_key="ghp_1234567890abcdef...", # 任何人都可以窃取它!
|
|
|
base_url="https://models.github.ai/inference"
|
|
|
)
|
|
|
|
|
|
# ✅ 这样做 - API密钥安全存储
|
|
|
client = OpenAI(
|
|
|
api_key=os.environ["GITHUB_TOKEN"], # 只有您的应用可以访问它
|
|
|
base_url="https://models.github.ai/inference"
|
|
|
)
|
|
|
```
|
|
|
|
|
|
**硬编码密钥的后果:**
|
|
|
1. **版本控制泄露**:有权访问 Git 仓库的人都看到您的 API 密钥
|
|
|
2. **公开仓库风险**:推送到 GitHub,密钥对全网公开
|
|
|
3. **团队共享问题**:其他开发者获得您的个人密钥
|
|
|
4. **安全漏洞**:密钥被盗后,别人滥用您的 AI 配额
|
|
|
|
|
|
#### 设置您的环境文件
|
|
|
|
|
|
在后端目录中创建 `.env` 文件,存放本地密钥:
|
|
|
|
|
|
```bash
|
|
|
# .env 文件 - 绝不应提交到 Git
|
|
|
GITHUB_TOKEN=your_github_personal_access_token_here
|
|
|
FASTAPI_DEBUG=True
|
|
|
ENVIRONMENT=development
|
|
|
```
|
|
|
|
|
|
**.env 文件说明:**
|
|
|
- **每行一个密钥**,格式为 `KEY=value`
|
|
|
- **等号两边无空格**
|
|
|
- **数值通常不需要引号**
|
|
|
- **注释以 `#` 开始**
|
|
|
|
|
|
#### 创建 GitHub 个人访问令牌
|
|
|
|
|
|
GitHub 令牌就像特殊密码,允许您的应用使用 GitHub 的 AI 服务:
|
|
|
|
|
|
**创建令牌步骤:**
|
|
|
1. 进入 GitHub 设置 → 开发者设置 → 个人访问令牌 → 经典令牌
|
|
|
2. 点击“生成新令牌(经典)”
|
|
|
3. 设置到期时间(测试用 30 天,生产环境可更长)
|
|
|
4. 选择权限范围:勾选 “repo” 及需要的其他权限
|
|
|
5. 生成令牌并立即复制(之后无法再次查看)
|
|
|
6. 粘贴到您的 `.env` 文件中
|
|
|
|
|
|
```bash
|
|
|
# 你的令牌样例(这是假的!)
|
|
|
GITHUB_TOKEN=ghp_1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R
|
|
|
```
|
|
|
|
|
|
#### 在 Python 中加载环境变量
|
|
|
|
|
|
```python
|
|
|
import os
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
# 从.env文件加载环境变量
|
|
|
load_dotenv()
|
|
|
|
|
|
# 现在你可以安全地访问它们
|
|
|
api_key = os.environ.get("GITHUB_TOKEN")
|
|
|
if not api_key:
|
|
|
raise ValueError("GITHUB_TOKEN not found in environment variables!")
|
|
|
|
|
|
client = OpenAI(
|
|
|
api_key=api_key,
|
|
|
base_url="https://models.github.ai/inference"
|
|
|
)
|
|
|
```
|
|
|
|
|
|
**这段代码做了什么:**
|
|
|
- **加载** .env 文件,并让变量可用
|
|
|
- **检查** 必需的令牌是否存在(良好错误管理)
|
|
|
- **缺失时抛出明确错误**
|
|
|
- **安全使用令牌,不暴露在代码里**
|
|
|
|
|
|
#### Git 安全:.gitignore 文件
|
|
|
|
|
|
`.gitignore` 文件告诉 Git 哪些文件永远不做跟踪或上传:
|
|
|
|
|
|
```bash
|
|
|
# .gitignore - 添加这些行
|
|
|
.env
|
|
|
*.env
|
|
|
.env.local
|
|
|
.env.production
|
|
|
__pycache__/
|
|
|
venv/
|
|
|
.vscode/
|
|
|
```
|
|
|
|
|
|
**重要性**:加 `.env` 到 `.gitignore`,Git 会忽略您的环境文件,防止意外把秘密上传到 GitHub。
|
|
|
|
|
|
#### 不同环境,不同密钥
|
|
|
|
|
|
专业应用在不同环境使用不同 API 密钥:
|
|
|
|
|
|
```bash
|
|
|
# .env.development
|
|
|
GITHUB_TOKEN=your_development_token
|
|
|
DEBUG=True
|
|
|
|
|
|
# .env.production
|
|
|
GITHUB_TOKEN=your_production_token
|
|
|
DEBUG=False
|
|
|
```
|
|
|
|
|
|
**意义**:避免开发实验影响生产配额,并为不同环境设定不同安全等级。
|
|
|
|
|
|
### 启动开发服务器:让您的 FastAPI 运行起来
|
|
|
现在到了令人激动的时刻——启动你的 FastAPI 开发服务器,看到你的 AI 集成活灵活现地展现出来!FastAPI 使用 Uvicorn,这是一款专为异步 Python 应用设计的超快速 ASGI 服务器。
|
|
|
|
|
|
#### 了解 FastAPI 服务器启动过程
|
|
|
|
|
|
```bash
|
|
|
# 方法1:直接使用Python执行(包括自动重载)
|
|
|
python api.py
|
|
|
|
|
|
# 方法2:直接使用Uvicorn(更多控制)
|
|
|
uvicorn api:app --host 0.0.0.0 --port 5000 --reload
|
|
|
```
|
|
|
|
|
|
当你运行此命令时,后台发生的事情如下:
|
|
|
|
|
|
**1. Python 加载你的 FastAPI 应用**:
|
|
|
- 导入所有必需的库(FastAPI、Pydantic、OpenAI 等)
|
|
|
- 从 `.env` 文件加载环境变量
|
|
|
- 创建带有自动文档的 FastAPI 应用实例
|
|
|
|
|
|
**2. Uvicorn 配置 ASGI 服务器**:
|
|
|
- 绑定到 5000 端口,支持异步请求处理
|
|
|
- 设置请求路由并自动验证
|
|
|
- 开启热重载功能(文件更改时自动重启)
|
|
|
- 生成交互式 API 文档
|
|
|
|
|
|
**3. 服务器开始监听**:
|
|
|
- 终端显示:`INFO: Uvicorn running on http://0.0.0.0:5000`
|
|
|
- 服务器可处理多个并发 AI 请求
|
|
|
- 你的 API 准备就绪,自动文档地址为 `http://localhost:5000/docs`
|
|
|
|
|
|
#### 正常工作时你应该看到的内容
|
|
|
|
|
|
```bash
|
|
|
$ python api.py
|
|
|
INFO: Will watch for changes in these directories: ['/your/project/path']
|
|
|
INFO: Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)
|
|
|
INFO: Started reloader process [12345] using WatchFiles
|
|
|
INFO: Started server process [12346]
|
|
|
INFO: Waiting for application startup.
|
|
|
INFO: Application startup complete.
|
|
|
```
|
|
|
|
|
|
**理解 FastAPI 输出:**
|
|
|
- **正在监听更改**:开发模式下启用自动重载
|
|
|
- **Uvicorn 运行中**:高性能 ASGI 服务器处于活动状态
|
|
|
- **已启动重载进程**:文件监视器自动重启
|
|
|
- **应用启动完成**:FastAPI 应用成功初始化
|
|
|
- **交互文档可用**:访问 `/docs` 查看自动生成的 API 文档
|
|
|
|
|
|
#### 测试你的 FastAPI:多种强大方式
|
|
|
|
|
|
FastAPI 提供了多种便捷的测试 API 的方法,包括自动生成的交互式文档:
|
|
|
|
|
|
**方法 1:交互式 API 文档(推荐)**
|
|
|
1. 打开浏览器,访问 `http://localhost:5000/docs`
|
|
|
2. 你会看到 Swagger UI,所有端点文档齐全
|
|
|
3. 点击 `/hello` → “Try it out” → 输入测试消息 → “Execute”
|
|
|
4. 在浏览器中直接看到格式化良好的响应
|
|
|
|
|
|
**方法 2:基础浏览器测试**
|
|
|
1. 访问 `http://localhost:5000` 查看根端点
|
|
|
2. 访问 `http://localhost:5000/health` 检查服务器健康状态
|
|
|
3. 以此确认 FastAPI 服务器运行正常
|
|
|
|
|
|
**方法 2:命令行测试(高级)**
|
|
|
```bash
|
|
|
# 使用 curl 进行测试(如果可用)
|
|
|
curl -X POST http://localhost:5000/hello \
|
|
|
-H "Content-Type: application/json" \
|
|
|
-d '{"message": "Hello AI!"}'
|
|
|
|
|
|
# 预期响应:
|
|
|
# {"response": "您好!我是您的 AI 助手。今天我能帮您什么忙?"}
|
|
|
```
|
|
|
|
|
|
**方法 3:Python 测试脚本**
|
|
|
```python
|
|
|
# test_api.py - 创建此文件以测试您的API
|
|
|
import requests
|
|
|
import json
|
|
|
|
|
|
# 测试API端点
|
|
|
url = "http://localhost:5000/hello"
|
|
|
data = {"message": "Tell me a joke about programming"}
|
|
|
|
|
|
response = requests.post(url, json=data)
|
|
|
if response.status_code == 200:
|
|
|
result = response.json()
|
|
|
print("AI Response:", result['response'])
|
|
|
else:
|
|
|
print("Error:", response.status_code, response.text)
|
|
|
```
|
|
|
|
|
|
#### 常见启动问题排查
|
|
|
|
|
|
| 错误信息 | 含义 | 解决方法 |
|
|
|
|---------------|---------------|------------|
|
|
|
| `ModuleNotFoundError: No module named 'fastapi'` | FastAPI 未安装 | 在虚拟环境中运行 `pip install fastapi uvicorn` |
|
|
|
| `ModuleNotFoundError: No module named 'uvicorn'` | ASGI 服务器未安装 | 在虚拟环境中运行 `pip install uvicorn` |
|
|
|
| `KeyError: 'GITHUB_TOKEN'` | 环境变量未找到 | 检查 `.env` 文件和 `load_dotenv()` 调用 |
|
|
|
| `Address already in use` | 端口 5000 被占用 | 终止占用端口的进程或更改端口号 |
|
|
|
| `ValidationError` | 请求数据与 Pydantic 模型不符 | 检查请求格式是否符合预期模式 |
|
|
|
| `HTTPException 422` | 无法处理的实体 | 请求验证失败,检查 `/docs` 的正确格式 |
|
|
|
| `OpenAI API error` | AI 服务认证失败 | 确认 GitHub 令牌正确且权限充足 |
|
|
|
|
|
|
#### 开发最佳实践
|
|
|
|
|
|
**热重载**:FastAPI 配合 Uvicorn 可在你保存 Python 文件后自动重载,无需手动重启,方便快速测试代码修改。
|
|
|
|
|
|
```python
|
|
|
# 明确启用热重载
|
|
|
if __name__ == "__main__":
|
|
|
app.run(host="0.0.0.0", port=5000, debug=True) # debug=True 启用热重载
|
|
|
```
|
|
|
|
|
|
**开发时添加日志**:
|
|
|
|
|
|
```python
|
|
|
import logging
|
|
|
|
|
|
# 设置日志记录
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@app.route("/hello", methods=["POST"])
|
|
|
def hello():
|
|
|
data = request.get_json()
|
|
|
message = data.get("message", "")
|
|
|
|
|
|
logger.info(f"Received message: {message}")
|
|
|
|
|
|
if not message:
|
|
|
logger.warning("Empty message received")
|
|
|
return jsonify({"error": "Message field is required"}), 400
|
|
|
|
|
|
try:
|
|
|
response = call_llm(message, "You are a helpful and friendly assistant.")
|
|
|
logger.info(f"AI response generated successfully")
|
|
|
return jsonify({"response": response})
|
|
|
except Exception as e:
|
|
|
logger.error(f"AI API error: {str(e)}")
|
|
|
return jsonify({"error": "AI service temporarily unavailable"}), 500
|
|
|
```
|
|
|
|
|
|
**日志的重要性**:在开发过程中,你可以清晰看到接收到的请求、AI 的响应及错误位置,极大加快调试效率。
|
|
|
|
|
|
### 配置 GitHub Codespaces:轻松实现云端开发
|
|
|
|
|
|
GitHub Codespaces 就像是云上强大的开发电脑,任何浏览器都能访问。如果你在 Codespaces 中开发,需要做一些额外配置以让后端对前端可访问。
|
|
|
|
|
|
#### 了解 Codespaces 网络环境
|
|
|
|
|
|
本地开发环境中,一切都在同一台电脑运行:
|
|
|
- 后端:`http://localhost:5000`
|
|
|
- 前端:`http://localhost:3000`(或 file://)
|
|
|
|
|
|
而在 Codespaces 中,开发环境运行在 GitHub 服务器上,“localhost” 含义不同。GitHub 会自动创建服务的公共 URL,但你需要正确配置它们。
|
|
|
|
|
|
#### Codespaces 配置步骤
|
|
|
|
|
|
**1. 启动你的后端服务器**:
|
|
|
```bash
|
|
|
cd backend
|
|
|
python api.py
|
|
|
```
|
|
|
|
|
|
你会看到熟悉的 FastAPI/Uvicorn 启动信息,但它是在 Codespace 环境内运行。
|
|
|
|
|
|
**2. 配置端口可见性**:
|
|
|
- 在 VS Code 底部面板找到“Ports”标签
|
|
|
- 在列表中找到 5000 端口
|
|
|
- 右键点击 5000 端口
|
|
|
- 选择“Port Visibility” → “Public”
|
|
|
|
|
|
**为什么要公开端口?** 默认情况下,Codespace 端口是私有的(仅自己访问)。公开端口后,你的前端(运行于浏览器)才能与后端通信。
|
|
|
|
|
|
**3. 获取公共 URL**:
|
|
|
公开端口后,看到一个类似这样的 URL:
|
|
|
```
|
|
|
https://your-codespace-name-5000.app.github.dev
|
|
|
```
|
|
|
|
|
|
**4. 更新前端配置**:
|
|
|
```javascript
|
|
|
// 在你的前端 app.js 中,更新 BASE_URL:
|
|
|
this.BASE_URL = "https://your-codespace-name-5000.app.github.dev";
|
|
|
```
|
|
|
|
|
|
#### 了解 Codespace URL
|
|
|
|
|
|
Codespace URL 遵循可预测的格式:
|
|
|
```
|
|
|
https://[codespace-name]-[port].app.github.dev
|
|
|
```
|
|
|
|
|
|
**解析如下:**
|
|
|
- `codespace-name`:你的 Codespace 唯一标识(一般含用户名)
|
|
|
- `port`:服务运行的端口(本例中是 5000)
|
|
|
- `app.github.dev`:GitHub Codespace 应用的域名
|
|
|
|
|
|
#### 测试你的 Codespace 配置
|
|
|
|
|
|
**1. 直接测试后端**:
|
|
|
在新浏览器标签打开公共 URL,你应该看到:
|
|
|
```
|
|
|
Welcome to the AI Chat API. Send POST requests to /hello with JSON payload containing 'message' field.
|
|
|
```
|
|
|
|
|
|
**2. 使用浏览器开发工具测试**:
|
|
|
```javascript
|
|
|
// 打开浏览器控制台并测试您的API
|
|
|
fetch('https://your-codespace-name-5000.app.github.dev/hello', {
|
|
|
method: 'POST',
|
|
|
headers: {'Content-Type': 'application/json'},
|
|
|
body: JSON.stringify({message: 'Hello from Codespaces!'})
|
|
|
})
|
|
|
.then(response => response.json())
|
|
|
.then(data => console.log(data));
|
|
|
```
|
|
|
|
|
|
#### Codespaces 与本地开发对比
|
|
|
|
|
|
| 方面 | 本地开发 | GitHub Codespaces |
|
|
|
|--------|-------------------|-------------------|
|
|
|
| **配置时间** | 较长(安装 Python、依赖等) | 即刻可用(预配置环境) |
|
|
|
| **URL 访问** | `http://localhost:5000` | `https://xyz-5000.app.github.dev` |
|
|
|
| **端口配置** | 自动 | 手动(需公开端口) |
|
|
|
| **文件持久化** | 本地机器 | GitHub 仓库 |
|
|
|
| **协作** | 共享环境困难 | 轻松分享 Codespace 链接 |
|
|
|
| **网络依赖** | 仅 AI API 调用 | 一切操作均需联网 |
|
|
|
|
|
|
#### Codespace 开发小贴士
|
|
|
|
|
|
**Codespaces 中的环境变量**:
|
|
|
你的 `.env` 文件在 Codespaces 中同样生效,也可以直接在 Codespace 设置环境变量:
|
|
|
|
|
|
```bash
|
|
|
# 为当前会话设置环境变量
|
|
|
export GITHUB_TOKEN="your_token_here"
|
|
|
|
|
|
# 或添加到你的 .bashrc 以保持永久有效
|
|
|
echo 'export GITHUB_TOKEN="your_token_here"' >> ~/.bashrc
|
|
|
```
|
|
|
|
|
|
**端口管理**:
|
|
|
- Codespaces 自动检测你的应用监听的端口
|
|
|
- 可同时转发多个端口(未来添加数据库时很有用)
|
|
|
- 只要 Codespace 运行,端口就持续可用
|
|
|
|
|
|
**开发流程**:
|
|
|
1. 在 VS Code 修改代码
|
|
|
2. FastAPI 自动重载(依赖 Uvicorn 重载模式)
|
|
|
3. 通过公共 URL 即时测试更改
|
|
|
4. 准备好后提交并推送代码
|
|
|
|
|
|
> 💡 **小贴士**:开发期间收藏你的 Codespace 后端 URL。Codespace 名称稳定,URL 只要不换 Codespace 就不会变。
|
|
|
|
|
|
## 创建前端聊天界面:人与 AI 的交汇点
|
|
|
|
|
|
现在开始构建用户界面——决定人与 AI 助理如何交互的部分。就像最初 iPhone 界面设计一样,我们专注于让复杂技术变得直观自然。
|
|
|
|
|
|
### 了解现代前端架构
|
|
|
|
|
|
我们的聊天界面将是所谓的“单页应用”(SPA)。与传统每次点击都会加载新页面不同,我们的应用更新流畅且即时:
|
|
|
|
|
|
**旧网站**:像读纸质书——翻到全新页面
|
|
|
**我们的聊天应用**:像用手机——内容流畅更新无阻
|
|
|
|
|
|
```mermaid
|
|
|
graph TD
|
|
|
A[用户输入消息] --> B[JavaScript 捕获输入]
|
|
|
B --> C[验证并格式化数据]
|
|
|
C --> D[发送到后端 API]
|
|
|
D --> E[显示加载状态]
|
|
|
E --> F[接收 AI 响应]
|
|
|
F --> G[更新聊天界面]
|
|
|
G --> H[准备接收下一条消息]
|
|
|
```
|
|
|
```mermaid
|
|
|
classDiagram
|
|
|
class ChatApp {
|
|
|
+messages: HTMLElement
|
|
|
+form: HTMLElement
|
|
|
+input: HTMLElement
|
|
|
+sendButton: HTMLElement
|
|
|
+BASE_URL: string
|
|
|
+API_ENDPOINT: string
|
|
|
|
|
|
+constructor()
|
|
|
+initializeEventListeners()
|
|
|
+handleSubmit(event)
|
|
|
+callAPI(message)
|
|
|
+appendMessage(text, role)
|
|
|
+escapeHtml(text)
|
|
|
+scrollToBottom()
|
|
|
+setLoading(isLoading)
|
|
|
}
|
|
|
|
|
|
ChatApp --> DOM : 操作
|
|
|
ChatApp --> FastAPI : 发送请求
|
|
|
```
|
|
|
### 前端开发的三大支柱
|
|
|
|
|
|
每个前端应用——从简单网站到像 Discord 或 Slack 这样复杂的应用——都基于三大核心技术。可以把它们看作你看到并互动的所有网页的基础:
|
|
|
|
|
|
**HTML(结构)**:这是你的基础
|
|
|
- 决定页面有哪些元素(按钮、文本框、容器等)
|
|
|
- 赋予内容含义(这是标题、这是表单等)
|
|
|
- 创建所有其他部分构筑的基本结构
|
|
|
|
|
|
**CSS(表现)**:这是你的室内设计师
|
|
|
- 让一切美观(颜色、字体、布局)
|
|
|
- 适配不同屏幕(手机、笔记本、平板)
|
|
|
- 制造平滑动画和视觉反馈
|
|
|
|
|
|
**JavaScript(行为)**:这是你的大脑
|
|
|
- 响应用户操作(点击、输入、滚动)
|
|
|
- 与后端通信并更新页面
|
|
|
- 让一切变得互动和动态
|
|
|
|
|
|
**可以把它们想象成建筑设计:**
|
|
|
- **HTML**:结构蓝图(定义空间和关系)
|
|
|
- **CSS**:美学及环境设计(视觉风格和用户体验)
|
|
|
- **JavaScript**:机械系统(功能和交互)
|
|
|
|
|
|
### 现代 JavaScript 架构的重要性
|
|
|
|
|
|
我们的聊天应用将使用你在专业应用中会见到的现代 JavaScript 模式。理解这些概念将帮助你成长为开发者:
|
|
|
|
|
|
**基于类的架构**:我们会将代码组织成类,类似于对象蓝图
|
|
|
**Async/Await**:处理耗时操作(如 API 调用)的现代方法
|
|
|
**事件驱动编程**:应用响应用户操作(点击、按键),而非持续循环运行
|
|
|
**DOM 操作**:根据用户交互和 API 响应动态更新网页内容
|
|
|
|
|
|
### 项目结构设置
|
|
|
|
|
|
创建一个 frontend 目录,结构如下有序组织:
|
|
|
|
|
|
```text
|
|
|
frontend/
|
|
|
├── index.html # Main HTML structure
|
|
|
├── app.js # JavaScript functionality
|
|
|
└── styles.css # Visual styling
|
|
|
```
|
|
|
|
|
|
**架构说明:**
|
|
|
- **分离**结构(HTML)、行为(JavaScript)和表现(CSS)
|
|
|
- **维护**简单易读的文件结构,易于导航和修改
|
|
|
- **遵循**网页开发最佳实践,增强组织性和可维护性
|
|
|
|
|
|
### 构建 HTML 基础:语义结构与可访问性
|
|
|
|
|
|
先从 HTML 结构开始。现代网页开发强调“语义 HTML”——使用明确定义用途的元素,而非仅仅控制外观。这使得应用更易被屏幕阅读器、搜索引擎等工具识别。
|
|
|
|
|
|
**为什么语义 HTML 重要**:想象你跟别人电话描述你的聊天应用,你会说“有个带标题的头部,一个显示对话的主体区域,底部是输入消息的表单”。语义 HTML 用的正是对应这种自然描述的元素。
|
|
|
|
|
|
创建 `index.html`,内容采用以下深思熟虑的语义标记:
|
|
|
|
|
|
```html
|
|
|
<!DOCTYPE html>
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>AI Chat Assistant</title>
|
|
|
<link rel="stylesheet" href="styles.css">
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="chat-container">
|
|
|
<header class="chat-header">
|
|
|
<h1>AI Chat Assistant</h1>
|
|
|
<p>Ask me anything!</p>
|
|
|
</header>
|
|
|
|
|
|
<main class="chat-messages" id="messages" role="log" aria-live="polite">
|
|
|
<!-- Messages will be dynamically added here -->
|
|
|
</main>
|
|
|
|
|
|
<form class="chat-form" id="chatForm">
|
|
|
<div class="input-group">
|
|
|
<input
|
|
|
type="text"
|
|
|
id="messageInput"
|
|
|
placeholder="Type your message here..."
|
|
|
required
|
|
|
aria-label="Chat message input"
|
|
|
>
|
|
|
<button type="submit" id="sendBtn" aria-label="Send message">
|
|
|
Send
|
|
|
</button>
|
|
|
</div>
|
|
|
</form>
|
|
|
</div>
|
|
|
<script src="app.js"></script>
|
|
|
</body>
|
|
|
</html>
|
|
|
```
|
|
|
|
|
|
**理解每个 HTML 元素及其作用:**
|
|
|
|
|
|
#### 文档结构
|
|
|
- **`<!DOCTYPE html>`**:告诉浏览器这是现代的 HTML5
|
|
|
- **`<html lang="en">`**:指定页面语言,方便屏幕阅读器和翻译工具
|
|
|
- **`<meta charset="UTF-8">`**:确保支持国际字符编码
|
|
|
- **`<meta name="viewport"...>`**:控制缩放和尺寸,提升移动端响应
|
|
|
|
|
|
#### 语义元素
|
|
|
- **`<header>`**:清晰标明顶部区域,含标题和描述
|
|
|
- **`<main>`**:指定主体内容区域(对话显示区)
|
|
|
- **`<form>`**:语义正确的用户输入区域,支持键盘导航
|
|
|
|
|
|
#### 可访问性功能
|
|
|
- **`role="log"`**:告诉屏幕阅读器这里是按时间顺序的消息日志
|
|
|
- **`aria-live="polite"`**:新消息优雅通知屏幕阅读器,无打断
|
|
|
- **`aria-label`**:为表单控件提供描述标签
|
|
|
- **`required`**:浏览器必须验证用户输入消息后才允许发送
|
|
|
|
|
|
#### CSS 和 JavaScript 集成
|
|
|
- **`class` 属性**:为 CSS 提供样式钩子(如 `chat-container`、`input-group`)
|
|
|
- **`id` 属性**:方便 JavaScript 查找和操作特定元素
|
|
|
- **脚本位置**:JavaScript 文件加载放末尾,确保 HTML 先加载完成
|
|
|
|
|
|
**为何此结构有效:**
|
|
|
- **逻辑流畅**:Header → 主体内容 → 输入表单,符合自然阅读顺序
|
|
|
- **键盘可操作**:用户可用 Tab 键顺序访问所有交互元素
|
|
|
- **屏幕阅读友好**:清晰区域标识和描述,方便视障用户
|
|
|
- **移动响应**:视口元标签支持响应设计
|
|
|
- **渐进增强**:即使 CSS 或 JavaScript 失败,结构仍能工作
|
|
|
|
|
|
### 增加交互式 JavaScript:现代网页应用逻辑
|
|
|
|
|
|
现在让我们构建使我们的聊天界面栩栩如生的 JavaScript。我们将使用现代 JavaScript 模式,这些模式在专业的 Web 开发中会遇到,包括 ES6 类、async/await 和事件驱动编程。
|
|
|
|
|
|
#### 理解现代 JavaScript 架构
|
|
|
|
|
|
我们不会编写过程式代码(一系列按顺序运行的函数),而是创建一个**基于类的架构**。可以把类想象成创建对象的蓝图——就像建筑师的蓝图可以用来建造多栋房子。
|
|
|
|
|
|
**为什么在网络应用中使用类?**
|
|
|
- **组织性**:所有相关功能都被归类在一起
|
|
|
- **可重用性**:你可以在同一页面创建多个聊天实例
|
|
|
- **可维护性**:更容易调试和修改特定功能
|
|
|
- **行业标准**:这种模式被 React、Vue 和 Angular 等框架使用
|
|
|
|
|
|
创建 `app.js`,使用这种现代且结构良好的 JavaScript:
|
|
|
|
|
|
```javascript
|
|
|
// app.js - 现代聊天应用逻辑
|
|
|
|
|
|
class ChatApp {
|
|
|
constructor() {
|
|
|
// 获取我们需要操作的DOM元素引用
|
|
|
this.messages = document.getElementById("messages");
|
|
|
this.form = document.getElementById("chatForm");
|
|
|
this.input = document.getElementById("messageInput");
|
|
|
this.sendButton = document.getElementById("sendBtn");
|
|
|
|
|
|
// 在这里配置你的后端URL
|
|
|
this.BASE_URL = "http://localhost:5000"; // 根据你的环境更新此处
|
|
|
this.API_ENDPOINT = `${this.BASE_URL}/hello`;
|
|
|
|
|
|
// 在聊天应用创建时设置事件监听器
|
|
|
this.initializeEventListeners();
|
|
|
}
|
|
|
|
|
|
initializeEventListeners() {
|
|
|
// 监听表单提交(当用户点击发送或按下回车)
|
|
|
this.form.addEventListener("submit", (e) => this.handleSubmit(e));
|
|
|
|
|
|
// 也监听输入字段中的回车键(更好的用户体验)
|
|
|
this.input.addEventListener("keypress", (e) => {
|
|
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
|
e.preventDefault();
|
|
|
this.handleSubmit(e);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
async handleSubmit(event) {
|
|
|
event.preventDefault(); // 阻止表单刷新页面
|
|
|
|
|
|
const messageText = this.input.value.trim();
|
|
|
if (!messageText) return; // 不发送空消息
|
|
|
|
|
|
// 向用户反馈正在发生的事情
|
|
|
this.setLoading(true);
|
|
|
|
|
|
// 立即将用户消息添加到聊天(乐观UI)
|
|
|
this.appendMessage(messageText, "user");
|
|
|
|
|
|
// 清空输入字段,便于用户输入下一条消息
|
|
|
this.input.value = '';
|
|
|
|
|
|
try {
|
|
|
// 调用AI接口并等待响应
|
|
|
const reply = await this.callAPI(messageText);
|
|
|
|
|
|
// 将AI响应添加到聊天中
|
|
|
this.appendMessage(reply, "assistant");
|
|
|
} catch (error) {
|
|
|
console.error('API Error:', error);
|
|
|
this.appendMessage("Sorry, I'm having trouble connecting right now. Please try again.", "error");
|
|
|
} finally {
|
|
|
// 无论成功或失败都重新启用界面
|
|
|
this.setLoading(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async callAPI(message) {
|
|
|
const response = await fetch(this.API_ENDPOINT, {
|
|
|
method: "POST",
|
|
|
headers: {
|
|
|
"Content-Type": "application/json"
|
|
|
},
|
|
|
body: JSON.stringify({ message })
|
|
|
});
|
|
|
|
|
|
if (!response.ok) {
|
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
}
|
|
|
|
|
|
const data = await response.json();
|
|
|
return data.response;
|
|
|
}
|
|
|
|
|
|
appendMessage(text, role) {
|
|
|
const messageElement = document.createElement("div");
|
|
|
messageElement.className = `message ${role}`;
|
|
|
messageElement.innerHTML = `
|
|
|
<div class="message-content">
|
|
|
<span class="message-text">${this.escapeHtml(text)}</span>
|
|
|
<span class="message-time">${new Date().toLocaleTimeString()}</span>
|
|
|
</div>
|
|
|
`;
|
|
|
|
|
|
this.messages.appendChild(messageElement);
|
|
|
this.scrollToBottom();
|
|
|
}
|
|
|
|
|
|
escapeHtml(text) {
|
|
|
const div = document.createElement('div');
|
|
|
div.textContent = text;
|
|
|
return div.innerHTML;
|
|
|
}
|
|
|
|
|
|
scrollToBottom() {
|
|
|
this.messages.scrollTop = this.messages.scrollHeight;
|
|
|
}
|
|
|
|
|
|
setLoading(isLoading) {
|
|
|
this.sendButton.disabled = isLoading;
|
|
|
this.input.disabled = isLoading;
|
|
|
this.sendButton.textContent = isLoading ? "Sending..." : "Send";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 页面加载时初始化聊天应用
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
|
new ChatApp();
|
|
|
});
|
|
|
```
|
|
|
|
|
|
#### 理解每个 JavaScript 概念
|
|
|
|
|
|
**ES6 类结构**:
|
|
|
```javascript
|
|
|
class ChatApp {
|
|
|
constructor() {
|
|
|
// 当你创建一个新的 ChatApp 实例时运行
|
|
|
// 它就像你的聊天的“设置”函数
|
|
|
}
|
|
|
|
|
|
methodName() {
|
|
|
// 方法是属于类的函数
|
|
|
// 它们可以使用“this”访问类的属性
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**Async/Await 模式**:
|
|
|
```javascript
|
|
|
// 旧方法(回调地狱):
|
|
|
fetch(url)
|
|
|
.then(response => response.json())
|
|
|
.then(data => console.log(data))
|
|
|
.catch(error => console.error(error));
|
|
|
|
|
|
// 现代方法(异步/等待):
|
|
|
try {
|
|
|
const response = await fetch(url);
|
|
|
const data = await response.json();
|
|
|
console.log(data);
|
|
|
} catch (error) {
|
|
|
console.error(error);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**事件驱动编程**:
|
|
|
我们不是不断检查是否发生了某事,而是“监听”事件:
|
|
|
```javascript
|
|
|
// 当表单提交时,运行 handleSubmit
|
|
|
this.form.addEventListener("submit", (e) => this.handleSubmit(e));
|
|
|
|
|
|
// 当按下回车键时,也运行 handleSubmit
|
|
|
this.input.addEventListener("keypress", (e) => { /* ... */ });
|
|
|
```
|
|
|
|
|
|
**DOM 操作**:
|
|
|
```javascript
|
|
|
// 创建新元素
|
|
|
const messageElement = document.createElement("div");
|
|
|
|
|
|
// 修改它们的属性
|
|
|
messageElement.className = "message user";
|
|
|
messageElement.innerHTML = "Hello world!";
|
|
|
|
|
|
// 添加到页面中
|
|
|
this.messages.appendChild(messageElement);
|
|
|
```
|
|
|
|
|
|
#### 安全与最佳实践
|
|
|
|
|
|
**XSS 防护**:
|
|
|
```javascript
|
|
|
escapeHtml(text) {
|
|
|
const div = document.createElement('div');
|
|
|
div.textContent = text; // 这会自动转义HTML
|
|
|
return div.innerHTML;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**为什么这很重要**:如果用户输入 `<script>alert('hack')</script>`,该函数确保它以文本形式显示,而不是执行代码。
|
|
|
|
|
|
**错误处理**:
|
|
|
```javascript
|
|
|
try {
|
|
|
const reply = await this.callAPI(messageText);
|
|
|
this.appendMessage(reply, "assistant");
|
|
|
} catch (error) {
|
|
|
// 显示用户友好的错误而不是让应用崩溃
|
|
|
this.appendMessage("Sorry, I'm having trouble...", "error");
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**用户体验考虑**:
|
|
|
- **乐观 UI**:立即添加用户消息,不用等待服务器响应
|
|
|
- **加载状态**:等待时禁用按钮并显示“发送中...”
|
|
|
- **自动滚动**:保持最新消息可见
|
|
|
- **输入验证**:不发送空消息
|
|
|
- **键盘快捷键**:按回车发送消息(如真实聊天应用)
|
|
|
|
|
|
#### 理解应用流程
|
|
|
|
|
|
1. **页面加载** → 触发 `DOMContentLoaded` 事件 → 创建 `new ChatApp()`
|
|
|
2. **构造函数运行** → 获取 DOM 元素引用 → 设置事件监听器
|
|
|
3. **用户输入消息** → 按回车或点击发送 → 运行 `handleSubmit`
|
|
|
4. **handleSubmit** → 验证输入 → 显示加载状态 → 调用 API
|
|
|
5. **API 响应** → 把 AI 消息添加到聊天 → 重新启用界面
|
|
|
6. **准备下一条消息** → 用户继续聊天
|
|
|
|
|
|
这种架构具有可扩展性 — 你可以轻松添加消息编辑、文件上传或多对话线程等功能,而不必重写核心结构。
|
|
|
|
|
|
### 🎯 教学检查:现代前端架构
|
|
|
|
|
|
**架构理解**:你已经使用现代 JavaScript 模式实现了完整的单页应用。这代表了专业级的前端开发。
|
|
|
|
|
|
**掌握的关键概念**:
|
|
|
- **ES6 类架构**:组织良好且易维护的代码结构
|
|
|
- **Async/Await 模式**:现代异步编程
|
|
|
- **事件驱动编程**:响应式用户界面设计
|
|
|
- **安全最佳实践**:XSS 防护和输入验证
|
|
|
|
|
|
**行业联系**:你学到的模式(基于类的架构、异步操作、DOM 操作)是现代框架(如 React、Vue 和 Angular)的基础。你正在使用生产应用中相同的架构思维进行构建。
|
|
|
|
|
|
**反思问题**:你如何扩展此聊天应用以处理多个对话或用户身份验证?考虑架构变化及类结构如何演进。
|
|
|
|
|
|
### 为聊天界面添加样式
|
|
|
|
|
|
现在我们来用 CSS 创建一个现代且视觉吸引力强的聊天界面。良好的样式让应用看起来专业并提升整体用户体验。我们将使用现代 CSS 特性如 Flexbox、CSS Grid 和自定义属性以实现响应式和无障碍设计。
|
|
|
|
|
|
创建 `styles.css`,使用以下全面样式:
|
|
|
|
|
|
```css
|
|
|
/* styles.css - Modern chat interface styling */
|
|
|
|
|
|
:root {
|
|
|
--primary-color: #2563eb;
|
|
|
--secondary-color: #f1f5f9;
|
|
|
--user-color: #3b82f6;
|
|
|
--assistant-color: #6b7280;
|
|
|
--error-color: #ef4444;
|
|
|
--text-primary: #1e293b;
|
|
|
--text-secondary: #64748b;
|
|
|
--border-radius: 12px;
|
|
|
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
* {
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
body {
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
min-height: 100vh;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
padding: 20px;
|
|
|
}
|
|
|
|
|
|
.chat-container {
|
|
|
width: 100%;
|
|
|
max-width: 800px;
|
|
|
height: 600px;
|
|
|
background: white;
|
|
|
border-radius: var(--border-radius);
|
|
|
box-shadow: var(--shadow);
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.chat-header {
|
|
|
background: var(--primary-color);
|
|
|
color: white;
|
|
|
padding: 20px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.chat-header h1 {
|
|
|
font-size: 1.5rem;
|
|
|
margin-bottom: 5px;
|
|
|
}
|
|
|
|
|
|
.chat-header p {
|
|
|
opacity: 0.9;
|
|
|
font-size: 0.9rem;
|
|
|
}
|
|
|
|
|
|
.chat-messages {
|
|
|
flex: 1;
|
|
|
padding: 20px;
|
|
|
overflow-y: auto;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 15px;
|
|
|
background: var(--secondary-color);
|
|
|
}
|
|
|
|
|
|
.message {
|
|
|
display: flex;
|
|
|
max-width: 80%;
|
|
|
animation: slideIn 0.3s ease-out;
|
|
|
}
|
|
|
|
|
|
.message.user {
|
|
|
align-self: flex-end;
|
|
|
}
|
|
|
|
|
|
.message.user .message-content {
|
|
|
background: var(--user-color);
|
|
|
color: white;
|
|
|
border-radius: var(--border-radius) var(--border-radius) 4px var(--border-radius);
|
|
|
}
|
|
|
|
|
|
.message.assistant {
|
|
|
align-self: flex-start;
|
|
|
}
|
|
|
|
|
|
.message.assistant .message-content {
|
|
|
background: white;
|
|
|
color: var(--text-primary);
|
|
|
border-radius: var(--border-radius) var(--border-radius) var(--border-radius) 4px;
|
|
|
border: 1px solid #e2e8f0;
|
|
|
}
|
|
|
|
|
|
.message.error .message-content {
|
|
|
background: var(--error-color);
|
|
|
color: white;
|
|
|
border-radius: var(--border-radius);
|
|
|
}
|
|
|
|
|
|
.message-content {
|
|
|
padding: 12px 16px;
|
|
|
box-shadow: var(--shadow);
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.message-text {
|
|
|
display: block;
|
|
|
line-height: 1.5;
|
|
|
word-wrap: break-word;
|
|
|
}
|
|
|
|
|
|
.message-time {
|
|
|
display: block;
|
|
|
font-size: 0.75rem;
|
|
|
opacity: 0.7;
|
|
|
margin-top: 5px;
|
|
|
}
|
|
|
|
|
|
.chat-form {
|
|
|
padding: 20px;
|
|
|
border-top: 1px solid #e2e8f0;
|
|
|
background: white;
|
|
|
}
|
|
|
|
|
|
.input-group {
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
#messageInput {
|
|
|
flex: 1;
|
|
|
padding: 12px 16px;
|
|
|
border: 2px solid #e2e8f0;
|
|
|
border-radius: var(--border-radius);
|
|
|
font-size: 1rem;
|
|
|
outline: none;
|
|
|
transition: border-color 0.2s ease;
|
|
|
}
|
|
|
|
|
|
#messageInput:focus {
|
|
|
border-color: var(--primary-color);
|
|
|
}
|
|
|
|
|
|
#messageInput:disabled {
|
|
|
background: #f8fafc;
|
|
|
opacity: 0.6;
|
|
|
cursor: not-allowed;
|
|
|
}
|
|
|
|
|
|
#sendBtn {
|
|
|
padding: 12px 24px;
|
|
|
background: var(--primary-color);
|
|
|
color: white;
|
|
|
border: none;
|
|
|
border-radius: var(--border-radius);
|
|
|
font-size: 1rem;
|
|
|
font-weight: 600;
|
|
|
cursor: pointer;
|
|
|
transition: background-color 0.2s ease;
|
|
|
min-width: 80px;
|
|
|
}
|
|
|
|
|
|
#sendBtn:hover:not(:disabled) {
|
|
|
background: #1d4ed8;
|
|
|
}
|
|
|
|
|
|
#sendBtn:disabled {
|
|
|
background: #94a3b8;
|
|
|
cursor: not-allowed;
|
|
|
}
|
|
|
|
|
|
@keyframes slideIn {
|
|
|
from {
|
|
|
opacity: 0;
|
|
|
transform: translateY(10px);
|
|
|
}
|
|
|
to {
|
|
|
opacity: 1;
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Responsive design for mobile devices */
|
|
|
@media (max-width: 768px) {
|
|
|
body {
|
|
|
padding: 10px;
|
|
|
}
|
|
|
|
|
|
.chat-container {
|
|
|
height: calc(100vh - 20px);
|
|
|
border-radius: 8px;
|
|
|
}
|
|
|
|
|
|
.message {
|
|
|
max-width: 90%;
|
|
|
}
|
|
|
|
|
|
.input-group {
|
|
|
flex-direction: column;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
#messageInput {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
#sendBtn {
|
|
|
width: 100%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Accessibility improvements */
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
|
.message {
|
|
|
animation: none;
|
|
|
}
|
|
|
|
|
|
* {
|
|
|
transition: none !important;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Dark mode support */
|
|
|
@media (prefers-color-scheme: dark) {
|
|
|
.chat-container {
|
|
|
background: #1e293b;
|
|
|
color: #f1f5f9;
|
|
|
}
|
|
|
|
|
|
.chat-messages {
|
|
|
background: #0f172a;
|
|
|
}
|
|
|
|
|
|
.message.assistant .message-content {
|
|
|
background: #334155;
|
|
|
color: #f1f5f9;
|
|
|
border-color: #475569;
|
|
|
}
|
|
|
|
|
|
.chat-form {
|
|
|
background: #1e293b;
|
|
|
border-color: #475569;
|
|
|
}
|
|
|
|
|
|
#messageInput {
|
|
|
background: #334155;
|
|
|
color: #f1f5f9;
|
|
|
border-color: #475569;
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**理解 CSS 架构:**
|
|
|
- **使用** CSS 自定义属性(变量)保持主题一致且易维护
|
|
|
- **采用** Flexbox 布局实现响应式设计和正确的对齐
|
|
|
- **包含** 消息出现的平滑动画且不分散注意力
|
|
|
- **提供** 用户消息、AI 回复和错误状态的视觉区分
|
|
|
- **支持** 适用于桌面和移动设备的响应设计
|
|
|
- **考虑** 减少动画偏好和合适对比度的无障碍需求
|
|
|
- **提供** 根据用户系统偏好自动切换暗模式
|
|
|
|
|
|
### 配置后端 URL
|
|
|
|
|
|
最后一步是将 JavaScript 中的 `BASE_URL` 更新为你的后端服务器地址:
|
|
|
|
|
|
```javascript
|
|
|
// 用于本地开发
|
|
|
this.BASE_URL = "http://localhost:5000";
|
|
|
|
|
|
// 用于 GitHub Codespaces(替换为您的实际 URL)
|
|
|
this.BASE_URL = "https://your-codespace-name-5000.app.github.dev";
|
|
|
```
|
|
|
|
|
|
**确定你的后端 URL:**
|
|
|
- **本地开发**:如果前后端都在本地运行,使用 `http://localhost:5000`
|
|
|
- **Codespaces**:端口 5000 公开后,在 Ports 标签页找到后端 URL
|
|
|
- **生产环境**:部署到托管服务时替换为实际域名
|
|
|
|
|
|
> 💡 **测试技巧**:你可以直接在浏览器中访问根 URL 测试后端。应该能看到 FastAPI 服务器的欢迎消息。
|
|
|
|
|
|
|
|
|
|
|
|
## 测试与部署
|
|
|
|
|
|
现在你已构建好前后端组件,让我们测试它们是否协同工作,并探索将聊天助手分享给他人的部署方案。
|
|
|
|
|
|
### 本地测试流程
|
|
|
|
|
|
按以下步骤测试完整应用:
|
|
|
|
|
|
```mermaid
|
|
|
graph TD
|
|
|
A[启动后台服务器] --> B[配置环境变量]
|
|
|
B --> C[测试API端点]
|
|
|
C --> D[在浏览器中打开前端]
|
|
|
D --> E[测试聊天功能]
|
|
|
E --> F[调试任何问题]
|
|
|
```
|
|
|
**分步测试流程:**
|
|
|
|
|
|
1. **启动后端服务器**:
|
|
|
```bash
|
|
|
cd backend
|
|
|
source venv/bin/activate # 或在 Windows 上使用 venv\Scripts\activate
|
|
|
python api.py
|
|
|
```
|
|
|
|
|
|
2. **确认 API 正常工作**:
|
|
|
- 在浏览器打开 `http://localhost:5000`
|
|
|
- 应该能看到来自 FastAPI 服务器的欢迎消息
|
|
|
|
|
|
3. **打开前端**:
|
|
|
- 进入前端目录
|
|
|
- 用浏览器打开 `index.html`
|
|
|
- 或使用 VS Code 的 Live Server 插件获得更好开发体验
|
|
|
|
|
|
4. **测试聊天功能**:
|
|
|
- 在输入框输入消息
|
|
|
- 点击“发送”或按回车
|
|
|
- 确认 AI 回复正常
|
|
|
- 检查浏览器控制台是否有 JavaScript 错误
|
|
|
|
|
|
### 常见问题排查
|
|
|
|
|
|
| 问题 | 症状 | 解决方案 |
|
|
|
|---------|----------|----------|
|
|
|
| **跨域错误(CORS)** | 前端无法访问后端 | 确保 FastAPI 的 CORSMiddleware 配置正确 |
|
|
|
| **API 密钥错误** | 返回 401 未授权 | 检查环境变量 `GITHUB_TOKEN` |
|
|
|
| **连接拒绝** | 前端出现网络错误 | 验证后端 URL 并确保服务端运行 |
|
|
|
| **无 AI 回复** | 响应为空或错误 | 查看后端日志中 API 配额或认证问题 |
|
|
|
|
|
|
**常见调试步骤:**
|
|
|
- **检查** 浏览器开发者工具控制台的 JavaScript 错误
|
|
|
- **确认** 网络面板显示 API 请求和响应成功
|
|
|
- **查看** 后端终端输出是否有 Python 错误或 API 问题
|
|
|
- **确认** 环境变量已正确加载并可访问
|
|
|
|
|
|
## 📈 你的 AI 应用开发掌握时间线
|
|
|
|
|
|
```mermaid
|
|
|
timeline
|
|
|
title 完整的AI应用开发旅程
|
|
|
|
|
|
section AI基础
|
|
|
了解生成式AI
|
|
|
: 掌握模式识别概念
|
|
|
: 精通AI参数控制
|
|
|
: 学习提示工程技术
|
|
|
|
|
|
GitHub模型集成
|
|
|
: 导航AI服务平台
|
|
|
: 安全处理认证
|
|
|
: 优化模型参数
|
|
|
|
|
|
section 后端开发
|
|
|
Python API架构
|
|
|
: 构建FastAPI应用
|
|
|
: 实现异步操作
|
|
|
: 创建安全端点
|
|
|
|
|
|
AI服务集成
|
|
|
: 连接外部AI API
|
|
|
: 处理速率限制
|
|
|
: 实现错误边界
|
|
|
|
|
|
section 前端精通
|
|
|
现代JavaScript模式
|
|
|
: 精通ES6类架构
|
|
|
: 实现async/await流程
|
|
|
: 构建响应式界面
|
|
|
|
|
|
实时用户体验
|
|
|
: 创建动态聊天界面
|
|
|
: 处理加载状态
|
|
|
: 优化用户交互
|
|
|
|
|
|
section 生产准备
|
|
|
安全与性能
|
|
|
: 实现安全令牌管理
|
|
|
: 防止XSS漏洞
|
|
|
: 优化API性能
|
|
|
|
|
|
专业部署
|
|
|
: 构建可扩展架构
|
|
|
: 创建可维护代码
|
|
|
: 记录开发流程
|
|
|
```
|
|
|
**🎓 毕业里程碑**:你已成功构建一个完整的 AI 驱动应用,使用了支撑现代 AI 助手的技术与架构模式。这些技能代表了传统 Web 开发与前沿 AI 集成的交汇点。
|
|
|
|
|
|
**🔄 下一阶段能力:**
|
|
|
- 探索高级 AI 框架(LangChain、LangGraph)
|
|
|
- 构建多模态 AI 应用(文本、图像、语音)
|
|
|
- 实现向量数据库和检索系统
|
|
|
- 为机器学习和 AI 模型微调打好基础
|
|
|
|
|
|
## GitHub Copilot Agent 挑战 🚀
|
|
|
|
|
|
使用 Agent 模式完成以下挑战:
|
|
|
|
|
|
**描述:** 通过添加会话历史和消息持久化增强聊天助手。该挑战将帮助你理解如何管理聊天应用中的状态并实现数据存储,以改善用户体验。
|
|
|
|
|
|
**任务提示:** 修改聊天应用以包含跨会话持久化的会话历史。添加功能将聊天消息保存到本地存储,页面加载时显示会话历史,并添加“清除历史”按钮。同时实现正在输入指示器和消息时间戳,使聊天体验更真实。
|
|
|
|
|
|
了解更多关于 [agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
|
|
|
|
|
|
## 任务:构建你的个人 AI 助手
|
|
|
|
|
|
现在你将创建自己的 AI 助手实现。这不仅是简单复刻教程代码,而是一个应用学到的概念,同时反映你自己的兴趣和使用场景的机会。
|
|
|
|
|
|
### 项目要求
|
|
|
|
|
|
让我们用清晰、组织良好的结构来设置项目:
|
|
|
|
|
|
```text
|
|
|
my-ai-assistant/
|
|
|
├── backend/
|
|
|
│ ├── api.py # Your FastAPI server
|
|
|
│ ├── llm.py # AI integration functions
|
|
|
│ ├── .env # Your secrets (keep this safe!)
|
|
|
│ └── requirements.txt # Python dependencies
|
|
|
├── frontend/
|
|
|
│ ├── index.html # Your chat interface
|
|
|
│ ├── app.js # The JavaScript magic
|
|
|
│ └── styles.css # Make it look amazing
|
|
|
└── README.md # Tell the world about your creation
|
|
|
```
|
|
|
|
|
|
### 核心实现任务
|
|
|
|
|
|
**后端开发:**
|
|
|
- **基于** 我们的 FastAPI 代码打造独一无二的实现
|
|
|
- **创建** 独特的 AI 个性——比如有用的烹饪助手、创意写作伙伴或学习伴侣?
|
|
|
- **添加** 可靠的错误处理,防止应用崩溃
|
|
|
- **撰写** 清晰的文档,让任何人都能理解你的 API 工作原理
|
|
|
|
|
|
**前端开发:**
|
|
|
- **构建** 直观且让人感到友好的聊天界面
|
|
|
- **编写** 干净现代的 JavaScript,让其他开发者也会赞赏
|
|
|
- **设计** 反映你 AI 个性的定制样式——有趣多彩?干净简约?随你选择!
|
|
|
- **确保** 在手机和电脑上都运行良好
|
|
|
|
|
|
**个性化要求:**
|
|
|
- **选择** AI 助手独特的名字和个性——最好能反映你的兴趣或你想解决的问题
|
|
|
- **定制** 视觉设计以匹配助手的氛围
|
|
|
- **撰写** 让人想开始聊天的吸引人欢迎消息
|
|
|
- **测试** 用不同类型的问题验证助手的响应
|
|
|
|
|
|
### 增强想法(可选)
|
|
|
|
|
|
想让项目更上一层楼?这里有一些有趣的思路可以尝试:
|
|
|
|
|
|
| 功能 | 描述 | 你将练习的技能 |
|
|
|
|---------|-------------|------------------------|
|
|
|
| **消息历史** | 即使刷新页面也能记住对话 | 使用 localStorage,JSON 处理 |
|
|
|
| **输入指示器** | 等待回复时显示“AI正在输入...” | CSS 动画,异步编程 |
|
|
|
| **消息时间戳** | 显示每条消息发送时间 | 日期/时间格式化,用户体验设计 |
|
|
|
| **导出聊天** | 允许用户下载对话内容 | 文件处理,数据导出 |
|
|
|
| **主题切换** | 明暗模式切换 | CSS 变量,用户偏好设置 |
|
|
|
| **语音输入** | 添加语音转文本功能 | Web API,无障碍性 |
|
|
|
|
|
|
### 测试与文档
|
|
|
|
|
|
**质量保障:**
|
|
|
- **测试** 各种输入类型和边界情况
|
|
|
- **确认** 响应式设计适用于不同屏幕尺寸
|
|
|
- **检查** 使用键盘导航和屏幕阅读器的无障碍性
|
|
|
- **验证** HTML 和 CSS 符合标准
|
|
|
|
|
|
**文档要求:**
|
|
|
- **撰写** README.md,说明项目及运行方式
|
|
|
- **附带** 聊天界面运行截图
|
|
|
- **记录** 任何独特功能或自定义内容
|
|
|
- **提供** 清晰的安装指引供其他开发者参考
|
|
|
|
|
|
### 提交指南
|
|
|
|
|
|
**项目提交物:**
|
|
|
1. 含所有源代码的完整项目文件夹
|
|
|
2. 含项目描述和安装指南的 README.md
|
|
|
3. 展示聊天助理运行效果的截图
|
|
|
4. 一篇简短的学习心得与遇到的挑战总结
|
|
|
|
|
|
**评估标准:**
|
|
|
- **功能性**:聊天助手能否按预期操作?
|
|
|
- **代码质量**:代码是否组织良好、注释充分且易维护?
|
|
|
- **设计**:界面是否视觉吸引且用户友好?
|
|
|
- **创造力**:实现的独特性和个性化程度?
|
|
|
- **文档**:安装指南是否清晰完整?
|
|
|
|
|
|
> 💡 **成功建议**:先实现基本需求,再逐步添加增强功能。聚焦打造打磨度高的核心体验,然后再开发高级特性。
|
|
|
|
|
|
## 解决方案
|
|
|
|
|
|
[Solution](./solution/README.md)
|
|
|
|
|
|
## 额外挑战
|
|
|
|
|
|
准备提升你的 AI 助手了吗?试试这些高阶挑战,加深你对 AI 集成和网页开发的理解。
|
|
|
|
|
|
### 个性化定制
|
|
|
|
|
|
真正的魔力在于赋予 AI 助手独特的个性。尝试不同的系统提示,打造特定领域的助手:
|
|
|
|
|
|
**专业助理示例:**
|
|
|
```python
|
|
|
call_llm(message, "You are a professional business consultant with 20 years of experience. Provide structured, actionable advice with specific steps and considerations.")
|
|
|
```
|
|
|
|
|
|
**创意写作助手示例:**
|
|
|
```python
|
|
|
call_llm(message, "You are an enthusiastic creative writing coach. Help users develop their storytelling skills with imaginative prompts and constructive feedback.")
|
|
|
```
|
|
|
|
|
|
**技术导师示例:**
|
|
|
```python
|
|
|
call_llm(message, "You are a patient senior developer who explains complex programming concepts using simple analogies and practical examples.")
|
|
|
```
|
|
|
|
|
|
### 前端增强
|
|
|
|
|
|
用这些视觉和功能改进来变革你的聊天界面:
|
|
|
|
|
|
**高级 CSS 特性:**
|
|
|
- **实现** 平滑的消息动画和过渡效果
|
|
|
- **添加** CSS 形状和渐变打造定制聊天气泡设计
|
|
|
- **创建** AI“正在思考”时的输入指示动画
|
|
|
- **设计** 表情反应或消息评分系统
|
|
|
|
|
|
**JavaScript 增强:**
|
|
|
- **添加** 键盘快捷键(Ctrl+Enter 发送,Esc 清除输入)
|
|
|
- **实现** 消息搜索和过滤功能
|
|
|
- **创建** 会话导出功能(下载为文本或 JSON)
|
|
|
- **添加** 自动保存到 localStorage,防止消息丢失
|
|
|
|
|
|
### 高级 AI 集成
|
|
|
|
|
|
**多重 AI 个性:**
|
|
|
- **创建** 下拉菜单切换不同 AI 个性
|
|
|
- **保存** 用户偏好的个性到 localStorage
|
|
|
- **实现** 上下文切换,保持对话流畅
|
|
|
|
|
|
**智能响应功能:**
|
|
|
- **添加** 会话上下文感知(AI 记住之前的消息)
|
|
|
- **根据对话主题** 实现智能建议
|
|
|
- **为常见问题** 创建快速回复按钮
|
|
|
|
|
|
> 🎯 **学习目标**:这些额外挑战帮助你理解生产应用中使用的高级网页开发模式和 AI 集成技术。
|
|
|
|
|
|
## 总结与下一步
|
|
|
|
|
|
恭喜你!你已成功从零构建了一个完整的 AI 驱动聊天助手。本项目让你获得了现代网页开发技术和 AI 集成的实战经验——这些技能在当今科技领域日益重要。
|
|
|
|
|
|
### 你所完成的工作
|
|
|
|
|
|
在本课中,你掌握了几个关键技术和概念:
|
|
|
|
|
|
**后端开发:**
|
|
|
- **整合** GitHub Models API 以实现 AI 功能
|
|
|
- **构建** 使用 Flask 的 RESTful API 并具备完善的错误处理
|
|
|
- **实现** 使用环境变量的安全认证
|
|
|
- **配置** 跨源请求的 CORS 以实现前后端通信
|
|
|
|
|
|
**前端开发:**
|
|
|
- **创建** 使用语义化 HTML 的响应式聊天界面
|
|
|
- **应用** 现代 JavaScript 异步/await 和基于类的架构
|
|
|
- **设计** 使用 CSS Grid、Flexbox 及动画的吸引人用户界面
|
|
|
- **添加** 无障碍功能及响应式设计原则
|
|
|
|
|
|
**全栈集成:**
|
|
|
- **连接** 前端和后端通过 HTTP API 调用
|
|
|
- **处理** 实时用户交互及异步数据流
|
|
|
- **实现** 错误处理和用户反馈贯穿应用
|
|
|
- **测试** 完整的应用流程,从用户输入到 AI 响应
|
|
|
|
|
|
### 关键学习成果
|
|
|
|
|
|
```mermaid
|
|
|
mindmap
|
|
|
root((AI 聊天应用技能))
|
|
|
API Integration
|
|
|
Authentication
|
|
|
Error Handling
|
|
|
Async Programming
|
|
|
Web Development
|
|
|
HTML5 语义
|
|
|
现代 CSS
|
|
|
ES6+ JavaScript
|
|
|
User Experience
|
|
|
响应式设计
|
|
|
无障碍
|
|
|
实时交互
|
|
|
AI Understanding
|
|
|
提示工程
|
|
|
模型参数
|
|
|
对话流程
|
|
|
```
|
|
|
本项目向你介绍了构建 AI 驱动应用的基础,这代表了网页开发的未来。你现在理解如何将 AI 功能集成至传统网页应用,创造智能且响应迅速的互动体验。
|
|
|
|
|
|
### 职业应用
|
|
|
|
|
|
你在本课中所培养的技能直接适用于现代软件开发职业:
|
|
|
|
|
|
- 使用现代框架和 API 的全栈网页开发
|
|
|
- 网页应用和移动应用中的 AI 集成
|
|
|
- 微服务架构中的 API 设计与开发
|
|
|
- 专注于无障碍和响应式设计的用户界面开发
|
|
|
- 包括环境配置和部署的 DevOps 实践
|
|
|
|
|
|
### 继续你的 AI 开发之旅
|
|
|
|
|
|
**下一学习步骤:**
|
|
|
- **探索** 更高级的 AI 模型和 API(如 GPT-4、Claude、Gemini)
|
|
|
- **学习** 提示工程技术以获得更佳的 AI 响应
|
|
|
- **研究** 对话设计和聊天机器人用户体验原则
|
|
|
- **调查** AI 安全、伦理和负责的 AI 开发实践
|
|
|
- **构建** 具备对话记忆和上下文感知的复杂应用
|
|
|
|
|
|
**高级项目建议:**
|
|
|
- 支持多用户的 AI 监管聊天室
|
|
|
- AI 驱动的客户服务聊天机器人
|
|
|
- 个性化学习的教育辅导助手
|
|
|
- 具有不同 AI 个性的创意写作合作者
|
|
|
- 面向开发者的技术文档助手
|
|
|
|
|
|
## 从 GitHub Codespaces 开始
|
|
|
|
|
|
想在云开发环境中尝试本项目?GitHub Codespaces 提供浏览器中的完整开发环境,非常适合无本地设置要求地试验 AI 应用。
|
|
|
|
|
|
### 设置你的开发环境
|
|
|
|
|
|
**步骤 1:从模板创建**
|
|
|
- **访问** [Web Dev For Beginners 仓库](https://github.com/microsoft/Web-Dev-For-Beginners)
|
|
|
- **点击** 右上角的“Use this template”(确保已登录 GitHub)
|
|
|
|
|
|

|
|
|
|
|
|
**步骤 2:启动 Codespaces**
|
|
|
- **打开** 你刚创建的仓库
|
|
|
- **点击** 绿色“Code”按钮,选择“Codespaces”
|
|
|
- **选择** “Create codespace on main” 启动开发环境
|
|
|
|
|
|

|
|
|
|
|
|
**步骤 3:环境配置**
|
|
|
Codespace 加载完成后,你将获得:
|
|
|
- **预装** Python、Node.js 及所有必需的开发工具
|
|
|
- **VS Code 界面** 并配有网页开发扩展
|
|
|
- **终端访问** 可运行后端和前端服务器
|
|
|
- **端口转发** 用于测试应用
|
|
|
|
|
|
**Codespaces 提供的优势:**
|
|
|
- **消除** 本地环境搭建和配置问题
|
|
|
- **提供** 跨设备统一开发环境
|
|
|
- **集成** 已预配置的网页开发工具和扩展
|
|
|
- **无缝连接** GitHub 做版本控制与协作
|
|
|
|
|
|
> 🚀 **专业提示**:Codespaces 非常适合学习和原型设计 AI 应用,它自动处理复杂环境设置,让你专注于构建和学习,而非配置故障排查。
|
|
|
|
|
|
---
|
|
|
|
|
|
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
|
|
|
**免责声明**:
|
|
|
本文档由 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意,自动翻译可能包含错误或不准确之处。原始文档的原始语言版本应被视为权威来源。对于重要信息,建议寻求专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
|
|
|
<!-- CO-OP TRANSLATOR DISCLAIMER END --> |