在人工智能快速发展的今天,如何高效构建自己的AI Agent成为了开发者们关注的焦点。本文将详细介绍如何利用GitHub Copilot和OpenHands工具快速构建一个基于DeepSeek的AI助手 - Polly。整个过程不仅高效,而且能够体验到 AI 辅助编程的强大能力。
一、使用 OpenHands 方案架构设计
1.1 从Idea到Plan不到一分钟
关于界面:
你的设计思路非常清晰,以下是我的一些建议和扩展想法:
### 基本设计
1. **标题**:`"You can talk with Polly"` 是一个很好的标题,简洁明了。
2. **输入框和发送按钮**:用户可以通过输入框输入问题,点击发送按钮后,向后端的 LLM Service 发送请求并展示回复。
3. **回复展示**:在输入框下方动态展示 Polly 的回复。
### 更加 Fancy 的想法
1. **对话气泡**:
- 将用户输入和 Polly 的回复以对话气泡的形式展示,类似于聊天应用的界面。
- 用户的输入在右侧显示,Polly 的回复在左侧显示。
2. **Polly 的头像**:
- 在每条 Polly 的回复旁边显示一个虚拟数字人的头像,增加互动感。
- 头像可以是一个动态的 3D 模型或 GIF,模拟 Polly 的表情变化。
3. **语音交互**:
- 增加语音输入功能,用户可以通过语音与 Polly 交流。
- Polly 的回复可以通过语音合成(TTS)播放出来。
4. **动画效果**:
- 在 Polly 回复时,显示一个“正在输入...”的动画,增加真实感。
- Polly 的头像可以在回复时做出一些动态效果,比如眨眼或点头。
5. **主题切换**:
- 提供一个按钮,用户可以切换 Polly 的主题,比如“专业模式”、“幽默模式”或“科幻模式”,以改变 Polly 的回复风格。
6. **知识图谱展示**:
- 如果 Polly 的回复涉及到某些知识点,可以在右侧动态生成一个知识图谱,帮助用户更直观地理解。
7. **多语言支持**:
- 提供语言切换功能,用户可以选择与 Polly 用不同的语言交流。
8. **历史记录**:
- 在页面上保留对话历史,用户可以随时回顾之前的对话。
9. **个性化设置**:
- 用户可以自定义 Polly 的名字、头像、语音风格等,增加个性化体验。
### 技术实现
- **前端**:
- 使用 JavaScript(如 Vue.js 或 React)动态更新对话内容。
- 使用 CSS 实现对话气泡和动画效果。
- **后端**:
- 通过 AJAX 或 WebSocket 与 LLM Service 通信,实时获取 Polly 的回复。
- **LLM Service**:
- Polly 的回复可以通过调用 LLM Service 的 API 实现,支持上下文对话。
如果你觉得这些想法不错,我可以帮你实现基础功能,或者进一步设计和实现更 Fancy 的功能!你怎么看?
关于Agent设计:
你的想法非常有创意!通过构建一个 **Polly Profile**,结合 DeepSeek 的服务,可以实现一个高度个性化的数字人。以下是一些改进和扩展的建议,帮助你打造一个更智能、更真实的数字人 Polly:
### 1. **Polly Profile 的设计**
Polly Profile 是数字人的核心,应该包含以下几个方面的信息:
#### **1.1 基础信息**
- **身份**: Polly 的背景信息,例如职业、兴趣、技能等。
- 示例: "我是Polly,一个热爱技术的博主,擅长编程、写作和摄影。"
- **语气和风格**: 定义 Polly 的说话风格(幽默、正式、友好等)。
- 示例: "我喜欢用轻松幽默的方式与人交流。"
#### **1.2 知识领域**
- **专业知识**: 定义 Polly 擅长的领域,例如编程、设计、心理学等。
- 示例: "我对Python编程、前端开发和人工智能有深入了解。"
- **个性化知识**: 包括你的个人经历、观点和兴趣。
- 示例: "我喜欢旅行,尤其是探索自然风光。"
#### **1.3 行为规则**
- **回答策略**: 定义 Polly 如何回答问题。
- 示例: "如果我不知道答案,我会坦诚告诉你,并尝试提供相关资源。"
- **情感模拟**: Polly 如何表现情感,例如高兴、同情、幽默等。
#### **1.4 动态学习**
- **记忆功能**: Polly 可以记住用户的偏好和历史对话。
- 示例: "记住用户喜欢的主题,下次对话时主动提及。"
- **实时更新**: 通过 DeepSeek 的服务,动态获取最新知识。
### 2. **技术实现建议**
为了让 Polly 更加智能和真实,可以从以下几个方面优化技术实现:
#### **2.1 Prompt Engineering**
- **多层Prompt设计**:
- **背景Prompt**: 定义 Polly 的身份和行为规则。
- **上下文Prompt**: 根据用户的输入动态生成上下文。
- **任务Prompt**: 针对特定任务(如技术支持、写作建议)生成专用Prompt。
- **示例Prompt**:
> [毛坯版]你是Polly,一个热爱技术的数字人。你擅长编程、写作和摄影。用友好和幽默的语气回答问题。如果你不知道答案,请坦诚告知并提供相关资源。 用户问题: {用户输入}. Polly的回答:
#### **2.2 DeepSeek 服务集成**
- **知识扩展**: 利用 DeepSeek 的服务,实时获取最新的知识和数据。
- 示例: 用户提问 "最近的AI技术趋势是什么?",Polly 可以通过 DeepSeek 获取最新的技术文章并总结回答。
- **多模态支持**: 如果 DeepSeek 支持图片、视频等多模态数据,可以让 Polly 提供更丰富的回答形式。
#### **2.3 个性化记忆**
- **用户偏好存储**: 使用数据库或文件系统存储用户的偏好和历史对话。
- **动态调整**: 根据用户的反馈调整 Polly 的行为和回答风格。
#### **2.4 多轮对话**
- **上下文管理**: 通过对话历史,保持多轮对话的连贯性。
- 示例: 用户问 "你喜欢什么电影?" 后,接着问 "为什么?",Polly 能理解上下文并回答。
### 3. **用户体验优化**
为了让用户与 Polly 的互动更加自然,可以从以下方面优化用户体验:
#### **3.1 视觉呈现**
- **数字人形象**: 使用 3D 模型或动画,打造一个可视化的 Polly。
- **表情和动作**: 根据对话内容动态调整 Polly 的表情和动作。
#### **3.2 多渠道支持**
- **跨平台交互**: 将 Polly 集成到多个平台,例如网站、移动应用、社交媒体等。
- **语音交互**: 支持语音输入和输出,让用户可以通过语音与 Polly 交流。
#### **3.3 个性化推荐**
- **内容推荐**: 根据用户的兴趣,主动推荐文章、视频或工具。
- **互动游戏**: 提供一些轻松的互动功能,例如问答游戏、心理测试等。
### 4. **扩展功能**
- **情感分析**: 根据用户的语气和内容,判断用户的情绪,并做出相应的回应。
- **知识图谱**: 构建一个知识图谱,帮助 Polly 理解复杂问题并提供更准确的回答。
- **社区互动**: 让用户可以与其他 Polly 用户互动,形成一个社区。
### 5. **示例场景**
以下是一些 Polly 的实际应用场景:
1. **技术支持**: 用户提问 "如何用Python实现一个爬虫?",Polly 提供代码示例和解释。
2. **生活助手**: 用户问 "周末有什么好玩的活动推荐?",Polly 根据用户位置和兴趣推荐活动。
3. **学习伙伴**: 用户学习新知识时,Polly 提供相关资源和练习题。
### 总结
通过构建一个详细的 Polly Profile,并结合 DeepSeek 的服务,你可以打造一个高度个性化、智能化的数字人 Polly。他不仅可以模拟你的知识和个性,还能通过动态学习和实时更新,持续提升自己的能力。希望这些建议对你有所帮助!如果需要进一步的技术支持,我可以协助你实现具体功能。
1.2 架构概述
Polly AI Agent 采用了前后端分离的架构设计,主要包括以下几个部分:
- 前端:基于 OpenHands 构建的聊天界面
- 后端:FastAPI 服务
- 大模型:DeepSeek API
- 部署:Azure Ubuntu 系统服务
1.3 技术栈选择
- 前端:HTML/CSS/JavaScript
- 后端:Python + FastAPI
- API 集成:DeepSeek API
- 开发工具:GitHub Copilot、VS Code、OpenHands
- 部署环境:Ubuntu + Systemd
二、OpenHands 构造网页前端聊天功能
2.1 OpenHands 介绍
OpenHands 是一个开源的 AI 开发工具集,专注于帮助开发者从想法到实现的全过程。通过其强大的功能,帮助我细化了从 Idea 到 Plan 的过程,明确了前端和后端的架构设计,并丰富了 Agent Profile 的内容。
2.2 前端页面构建
首先,我们创建一个基本的 HTML 结构:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Polly AI 助手</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/openhands/dist/openhands.min.css">
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
background-color: #f5f5f5;
}
.chat-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
/* 更多样式... */
</style>
</head>
<body>
<div class="chat-container">
<h1>Polly AI 助手</h1>
<div id="chat-window" class="oh-chat-window"></div>
<div class="oh-input-container">
<input type="text" id="user-input" placeholder="输入您的问题...">
<button id="send-button">发送</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/openhands/dist/openhands.min.js"></script>
<script src="app.js"></script>
</body>
</html>
然后,编写 JavaScript 代码处理消息交互:
// app.js
document.addEventListener('DOMContentLoaded', function() {
const chatWindow = document.getElementById('chat-window');
const userInput = document.getElementById('user-input');
const sendButton = document.getElementById('send-button');
// API 配置
const apiUrl = 'https://xxx.com:50206/api/polly';
const apiKey = 'your_api_key_here';
// 初始化聊天窗口
const chat = new OpenHands.ChatUI({
element: chatWindow,
theme: 'light',
initialMessage: '你好!我是 Polly,有什么我可以帮助你的吗?'
});
// 发送消息处理
function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
// 显示用户消息
chat.addUserMessage(message);
userInput.value = '';
// 显示加载状态
chat.showTyping();
// 发送请求到 API
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ message: message })
})
.then(response => {
if (!response.ok) throw new Error('API 请求失败');
return response.json();
})
.then(data => {
// 隐藏加载状态并显示回复
chat.hideTyping();
chat.addAssistantMessage(data.reply);
})
.catch(error => {
console.error('Error:', error);
chat.hideTyping();
chat.addSystemMessage('抱歉,发生了错误,请稍后再试。');
});
}
// 事件监听器
sendButton.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendMessage();
});
});
2.3 WebSocket 支持
除了基本的 HTTP 请求外,还添加了 WebSocket 支持,实现实时通信:
// WebSocket 连接
function connectWebSocket() {
const ws = new WebSocket(`wss://xxx.com:50206/ws/polly?api_key=${apiKey}`);
ws.onopen = function() {
console.log('WebSocket 连接已建立');
// 发送心跳检测
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'pong') return; // 忽略心跳响应
if (data.reply) {
chat.addAssistantMessage(data.reply);
} else if (data.error) {
chat.addSystemMessage(`错误: ${data.error}`);
}
};
ws.onclose = function() {
console.log('WebSocket 连接已关闭');
// 尝试重新连接
setTimeout(connectWebSocket, 3000);
};
ws.onerror = function(error) {
console.error('WebSocket 错误:', error);
};
return ws;
}
三、OpenHands + GitHub Copilot 搭建 FastAPI 服务
3.1 FastAPI 服务构建
首先,需要安装必要的依赖:
pip install fastapi uvicorn pydantic-settings python-dotenv aiohttp
3.2 配置文件设置
创建 config.py
文件,管理应用配置:
from pydantic_settings import BaseSettings
from typing import List, Optional
class Settings(BaseSettings):
# API 配置
api_key: str
deepseek_api_key: str
deepseek_api_timeout: int = 60 # API 超时时间(秒)
deepseek_max_retries: int = 3 # 最大重试次数
# 应用配置
debug: bool = True
port: int = 50206
host: str = "0.0.0.0"
environment: str = "development"
ssl_certfile: str = "/home/azureuser/FastAPI_Server/certs/fullchain.pem"
ssl_keyfile: str = "/home/azureuser/FastAPI_Server/certs/privkey.pem"
use_https: bool = True
# 安全配置
allowed_origins: List[str] = [
"https://polly2014.github.io",
"http://localhost:1111",
"http://127.0.0.1:1111"
]
# 资源配置
profile_url: str = "https://your-storage.blob.core.windows.net/config/profile_polly.json"
local_profile_path: str = "profile_polly.json"
class Config:
env_file = ".env"
case_sensitive = False
settings = Settings()
3.3 主要服务逻辑
下面是 main.py
文件的核心代码,实现了 REST API 和 WebSocket 端点:
<vscode_codeblock_uri>vscode-remote://ssh-remote%2B20.51.201.85/home/azureuser/FastAPI_Server/main.py</vscode_codeblock_uri>from fastapi import FastAPI, WebSocket, HTTPException, Security, Depends, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import APIKeyHeader
from pydantic import BaseModel, Field
from config import settings
import logging
import aiohttp
import uvicorn
import json
import os
# 配置日志
logger = logging.getLogger(__name__)
logging.basicConfig(
level=logging.WARNING,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.handlers.RotatingFileHandler(
'app.log',
maxBytes=1024*1024,
backupCount=5
),
logging.StreamHandler()
]
)
# 创建 FastAPI 实例
app = FastAPI(
title="Polly AI Agent",
description="Polly AI 聊天服务",
version="1.0.0",
debug=settings.debug
)
# 配置 CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"],
max_age=3600,
)
# API 密钥验证
api_key_header = APIKeyHeader(name="X-API-Key")
async def verify_api_key(api_key: str = Security(api_key_header)):
if api_key != settings.api_key:
logger.warning(f"无效的 API 密钥尝试")
raise HTTPException(
status_code=403,
detail="无效的 API 密钥"
)
return api_key
# 数据模型
class ChatRequest(BaseModel):
message: str = Field(..., min_length=1, max_length=1000)
# 核心 API 路由
@app.post("/api/polly", dependencies=[Depends(verify_api_key)])
async def chat(request: ChatRequest):
try:
profile = await load_polly_profile()
prompt = build_prompt(profile)
reply = await query_deepseek(prompt, request.message)
return {"reply": reply}
except Exception as e:
logger.error(f"处理请求失败: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
# WebSocket 端点
@app.websocket("/ws/polly")
async def websocket_endpoint(websocket: WebSocket):
# WebSocket 处理逻辑...
pass
# 运行服务器
if __name__ == "__main__":
try:
logger.info(f"Starting server on {settings.host}:{settings.port}")
uvicorn.run(
"main:app",
host=settings.host,
port=settings.port,
ssl_certfile=settings.ssl_certfile,
ssl_keyfile=settings.ssl_keyfile,
reload=settings.debug,
log_level="info",
access_log=False
)
except Exception as e:
logger.error(f"Server startup failed: {e}")
3.4 DeepSeek API 集成
async def query_deepseek(prompt: str, user_input: str) -> str:
url = "https://api.deepseek.com/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {settings.deepseek_api_key}"
}
payload = {
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": prompt},
{"role": "user", "content": user_input}
],
"stream": False
}
async with aiohttp.ClientSession() as session:
try:
async with session.post(url, json=payload, headers=headers) as response:
if response.status != 200:
raise HTTPException(status_code=response.status, detail="API调用失败")
result = await response.json()
return result["choices"][0]["message"]["content"].strip()
except Exception as e:
logger.error(f"DeepSeek API调用失败: {str(e)}")
raise HTTPException(status_code=500, detail=f"API调用错误: {str(e)}")
3.5 GitHub Copilot & OpenHands 辅助开发体验
在 Polly AI Agent 的开发过程中,GitHub Copilot 和 OpenHands 成为不可或缺的“智囊团”,它们不仅提升了开发效率,更为整个项目注入了创新的灵感。
GitHub Copilot:智能编程助手
GitHub Copilot 的强大之处在于它能够实时理解开发者的意图,并提供精准的代码建议。在编写复杂逻辑时,Copilot 不仅能补全函数和类,还能根据上下文生成符合项目需求的代码片段。例如:
- WebSocket 逻辑生成:在实现实时通信时,Copilot 自动生成了连接管理、消息处理和错误处理的完整代码框架。
- 错误修复与优化:通过分析代码,Copilot 提供了潜在问题的解决方案,并建议更优雅的实现方式。
- 文档与注释生成:自动生成清晰的函数注释和文档,确保代码的可读性和可维护性。
OpenHands:从创意到实现的桥梁
OpenHands 则在项目的整体规划和架构设计中扮演了重要角色。它帮助我从最初的 Idea 出发,逐步细化为可执行的 Plan,并在以下方面提供了关键支持:
- 架构设计:明确了前后端分离的技术栈选择,以及各模块的职责划分。
- Agent Profile 丰富化:通过 OpenHands 的工具,我得以构建一个高度个性化的 Polly Profile,定义了其知识领域、行为规则和动态学习能力。
- 开发流程优化:OpenHands 提供的模板和最佳实践建议,使得开发过程更加高效和规范。
协同效应:技术与创意的完美结合
GitHub Copilot 和 OpenHands 的结合,不仅是技术的加持,更是创意的催化剂。Copilot 让代码的实现变得轻松,而 OpenHands 则确保了项目的方向和深度。在它们的共同作用下,Polly AI Agent 从一个模糊的想法,蜕变为一个功能完善的数字人助手。
四、前后端对接(配置 SSL、证书等)
4.1 SSL 证书配置
为了确保通信安全,我们使用 Let's Encrypt 提供的免费 SSL 证书:
# 安装 Let's Encrypt 客户端
sudo apt install certbot
# 获取证书
sudo certbot certonly --standalone -d xxx.com
# 创建证书目录
mkdir -p /home/azureuser/FastAPI_Server/certs
# 复制证书文件
sudo cp /etc/letsencrypt/live/xxx.com/fullchain.pem /home/azureuser/FastAPI_Server/certs/
sudo cp /etc/letsencrypt/live/xxx.com/privkey.pem /home/azureuser/FastAPI_Server/certs/
# 设置正确的权限
sudo chown azureuser:azureuser /home/azureuser/FastAPI_Server/certs/*.pem
sudo chmod 644 /home/azureuser/FastAPI_Server/certs/fullchain.pem
sudo chmod 600 /home/azureuser/FastAPI_Server/certs/privkey.pem
4.2 证书自动更新脚本
创建一个脚本以便在证书更新时自动复制到应用目录:
#!/bin/bash
# filepath: /home/azureuser/FastAPI_Server/copy_certs.sh
# 复制更新后的证书
cp /etc/letsencrypt/live/xxx.com/fullchain.pem /home/azureuser/FastAPI_Server/certs/
cp /etc/letsencrypt/live/xxx.com/privkey.pem /home/azureuser/FastAPI_Server/certs/
# 设置权限
chown azureuser:azureuser /home/azureuser/FastAPI_Server/certs/fullchain.pem
chown azureuser:azureuser /home/azureuser/FastAPI_Server/certs/privkey.pem
chmod 644 /home/azureuser/FastAPI_Server/certs/fullchain.pem
chmod 600 /home/azureuser/FastAPI_Server/certs/privkey.pem
# 重启 FastAPI 服务
systemctl restart fastapi
将此脚本链接到 Let's Encrypt 的更新钩子目录:
sudo ln -s /home/azureuser/FastAPI_Server/copy_certs.sh /etc/letsencrypt/renewal-hooks/post/copy_certs_fastapi.sh
4.3 配置为系统服务
创建 systemd 服务文件,使应用能够作为系统服务运行:
<vscode_codeblock_uri>vscode-remote://ssh-remote%2B20.51.201.85/etc/systemd/system/fastapi.service</vscode_codeblock_uri>[Unit]
Description=Polly AI FastAPI Service
After=network.target
[Service]
User=azureuser
Group=azureuser
WorkingDirectory=/home/azureuser/FastAPI_Server
Environment="PATH=/home/azureuser/miniforge3/envs/FastAPI/bin"
ExecStart=/home/azureuser/miniforge3/envs/FastAPI/bin/python /home/azureuser/FastAPI_Server/main.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=fastapi
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
启用并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable fastapi
sudo systemctl start fastapi
4.4 防火墙配置
确保服务端口在防火墙中开放:
sudo ufw allow 50206/tcp
sudo ufw status
五、调试与优化
5.1 日志配置
为了更好地监控应用运行状态,我们精心配置了日志系统:
- 分级日志:区分 ERROR、WARNING、INFO 和 DEBUG 级别
- 日志轮转:防止日志文件过大
- 控制台输出控制:减少非必要的输出
5.2 性能优化
- 异步处理:使用 FastAPI 的异步特性处理并发请求
- 连接池管理:使用 aiohttp 连接池减少重复连接开销
- 缓存策略:针对频繁访问的资源实施缓存
六、成果展示
成功构建了一个完整的 AI 助手系统:
- 前端提供了友好的聊天界面
- 后端实现了安全、高效的 API 服务
- 系统可靠稳定,支持 HTTPS 和 WebSocket
- 全系统支持自动更新和维护
访问地址:https://polly2014.github.io
七、总结与展望
本项目展示了如何利用现代工具快速构建 AI 应用。通过 GitHub Copilot 和 OpenHands 的协助,在短时间内完成一个功能完整的 AI 助手。
未来改进方向:
- 添加多模态支持:图像识别、语音交互
- 记忆功能:通过数据库支持用户对话历史
- 个性化定制:基于用户行为调整回复风格
参考资料: