完整教程:基于多个大模型自己建造一个AI智能助手

基于多个大模型自己建造一个AI智能助手

一、概述

前面在博文 “如何自己建造一个AI智能助手” https://blog.csdn.net/cnds123/article/details/155134935 是基于通义千问(Qwen)API(免费额度可用)构建的AI智能助手。

你只需要一个通义千问的DashScope API Key https://dashscope.console.aliyun.com/apiKey (获取 API Key。阿里云账号免费注册,新用户送额度)。需要用支付宝对账号账号进行实名认证。

下面介绍,基于多个大模型,建造一个AI智能助手。

基于多个大模型自己建造一个AI智能助手,需要获取多个大模型的API Key。这里基于DashScope API Key 和DeepSeek 的API为例演示。

获取 DeepSeek API Key: https://platform.deepseek.com/sign_in

注意:DeepSeek调用 API 服务需要充值。实名认证后再充值,支付金额最少10元。【充值金额仅用于调用 API 服务,网页版及 App 对话免费使用,无需充值。】

需要有一个邮箱验证登录。创建成功后,系统会生成一个以 sk- 开头的 API Key

立即复制并妥善保存这个 Key,因为关闭对话框后通常无法再次查看完整 Key。

编程能力,这里,具体采用

  • 前端:纯 HTML + JavaScript
  • 后端:Python FastAPI
  • AI 模型:调用DashScope API Key 和DeepSeek 的API

  • 输入框改进行:用多行文本域(<textarea>),不仅能输入多行内容,还能保留换行、缩进等格式,特别适合粘贴 Python 代码、JSON、Markdown 等结构化文本。支持 Enter 发送(避免换行冲突,需按 Ctrl+Enter发送)

注意:在运行这个应用时,需要安装这些第三方库。

安装命令:

pip install fastapi uvicorn httpx pydantic dashscope

解释一下这些第三方库的作用:

FastAPI: 构建API的主要框架。其中,FastAPI创建 Web API 应用的主要类;HTTPException用于抛出 HTTP 错误异常;CORSMiddleware:处理跨域资源共享(CORS)的中间件。

pydantic: 通过Python类型注解来进行数据验证和设置管理。其中BaseModel 用于定义数据模型。

httpx: 支持异步的HTTP客户端。用于向 DeepSeek API 发送请求。

uvicorn: 用于运行FastAPI应用的ASGI服务器。运行 FastAPI 应用。

Dashscope:是阿里云推出的 模型即服务(MaaS)平台,提供包括通义千问(Qwen)在内的多种大模型 API,支持文本生成、图像生成、语音识别等。

先看运行效果截图:

​​

二、源码

项目结构

D:/ai-assistant- multiple/
├── backend/
│    └── main.py
└── frontend/
      └── index.html

后端:backend/main.py 文件源码:

# backend/main.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import httpx
import json
from enum import Enum
from typing import Optional
import os  #
# 模型配置
class ModelType(str, Enum):
    DEEPSEEK = "deepseek"
    TONGYI = "tongyi"
    OPENAI = "openai"
# API 配置
API_CONFIG = {
    ModelType.DEEPSEEK: {
        "url": "https://api.deepseek.com/v1/chat/completions",
        #"api_key": "你的 DeepSeek API Key",  # 你的 DeepSeek API Key,从环境变量读取更安全
        "api_key": os.getenv("DEEPSEEK_API_KEY"),  # ← 这行
        "model_name": "deepseek-chat"
    },
    ModelType.TONGYI: {
        "url": "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation",
        #"api_key": "你的 Tongyi API Key", # 你的 Tongyi API Key,从环境变量读取更安全
        "api_key": os.getenv("DASHSCOPE_API_KEY"),  # ← 这行
        "model_name": "qwen-plus"
    }
}
app = FastAPI()
# 允许前端跨域访问
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
class ChatRequest(BaseModel):
    message: str
    model: ModelType = ModelType.DEEPSEEK  # 默认模型
class ModelInfo(BaseModel):
    name: str
    display_name: str
    provider: str
@app.get("/models")
async def get_available_models():
    """获取可用的模型列表"""
    models = [
        ModelInfo(
            name=ModelType.DEEPSEEK,
            display_name="DeepSeek Chat",
            provider="DeepSeek"
        ),
        ModelInfo(
            name=ModelType.TONGYI,
            display_name="通义千问",
            provider="阿里云"
        )
    ]
    return {"models": models}
@app.post("/chat")
async def chat(request: ChatRequest):
    try:
        config = API_CONFIG.get(request.model)
        if not config:
            raise HTTPException(status_code=400, detail="不支持的模型")
        if request.model == ModelType.TONGYI:
            return await call_tongyi_api(request.message, config)
        else:
            return await call_openai_compatible_api(request.message, config, request.model)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
async def call_openai_compatible_api(message: str, config: dict, model_type: ModelType):
    """调用 OpenAI 兼容的 API(DeepSeek、OpenAI)"""
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {config['api_key']}"
    }
    payload = {
        "model": config["model_name"],
        "messages": [
            {
                "role": "user",
                "content": message
            }
        ],
        "stream": False
    }
    async with httpx.AsyncClient() as client:
        response = await client.post(
            config["url"],
            headers=headers,
            json=payload,
            timeout=30.0
        )
        if response.status_code == 200:
            data = response.json()
            return {"reply": data["choices"][0]["message"]["content"]}
        else:
            error_detail = f"{model_type.value} API 错误: {response.status_code} - {response.text}"
            raise HTTPException(status_code=500, detail=error_detail)
async def call_tongyi_api(message: str, config: dict):
    """调用通义千问 API"""
    import dashscope
    from dashscope import Generation
    dashscope.api_key = config["api_key"]
    response = Generation.call(
        model=config["model_name"],
        prompt=message
    )
    if response.status_code == 200:
        return {"reply": response.output.text}
    else:
        raise HTTPException(status_code=500, detail=f"通义千问 API 错误: {response.status_code}")
@app.get("/")
async def root():
    return {"message": "多模型 AI 助手后端服务运行中"}

前端:frontend/index.html文件源码




  
  多模型 AI 助手
  
  


  

多模型 AI 助手

提示:按 Ctrl+Enter(Windows/Linux)或 Cmd+Enter(Mac)快速发送
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.5/purify.min.js"></script> <script> marked.setOptions({ highlight: function(code, lang) { const language = hljs.getLanguage(lang) ? lang : 'plaintext'; return hljs.highlight(code, { language }).value; }, langPrefix: 'hljs language-' }); const chatBox = document.getElementById('chat-box'); const modelSelect = document.getElementById('model-select'); const input = document.getElementById('user-input'); const sendBtn = document.getElementById('send-btn'); // 自动调整 textarea 高度 input.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = Math.min(this.scrollHeight, 200) + 'px'; }); async function sendMessage() { const msg = input.value.trim(); if (!msg) return; const model = modelSelect.value; // 显示用户消息(保留原始格式) const userDiv = document.createElement('div'); userDiv.className = 'message user'; // 使用
 保留换行和空格,但用 DOMPurify 防 XSS
      userDiv.innerHTML = `你:
${DOMPurify.sanitize(msg)}
`; chatBox.appendChild(userDiv); chatBox.scrollTop = chatBox.scrollHeight; input.value = ''; input.style.height = 'auto'; // 重置高度 sendBtn.disabled = true; sendBtn.textContent = '发送中...'; // 显示“思考中” const thinkingDiv = document.createElement('div'); thinkingDiv.className = 'message ai'; thinkingDiv.innerHTML = 'AI: 正在思考…'; chatBox.appendChild(thinkingDiv); chatBox.scrollTop = chatBox.scrollHeight; try { const res = await fetch('http://localhost:8000/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: msg, model: model }) }); const data = await res.json(); if (res.ok) { const cleanHtml = DOMPurify.sanitize(marked.parse(data.reply)); thinkingDiv.innerHTML = `AI: ${cleanHtml}`; } else { thinkingDiv.innerHTML = `AI: ❌ 出错了:${data.detail || '未知错误'}`; } } catch (err) { thinkingDiv.innerHTML = `AI: ⚠️ 无法连接到后端,请确保它正在运行。`; } finally { sendBtn.disabled = false; sendBtn.textContent = '发送'; } } sendBtn.addEventListener('click', sendMessage); // 支持快捷键发送:Ctrl+Enter / Cmd+Enter input.addEventListener('keydown', (e) => { if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); sendMessage(); } }); </script>

提示,可以把 marked.min.js、highlight.min.js、purify.min.js 下载到本地 static/ 目录,改用相对路径。

其中,CDN (Content Delivery Network,内容分发网络)加载 marked 和 highlight.js  用于前端的交互输出格式。让 AI 返回的 代码块、Markdown 格式 能正确显示,并支持 Python 等语言的语法高亮!若缺乏格式输出python代码时就不好用了。

引入purify.min.js,增强安全:purify.min.js 是 DOMPurify 库的压缩版,它的核心作用是: 安全地清理(Sanitize)HTML 字符串,防止 XSS(跨站脚本攻击)。

三、运行步骤

1.启动后端服务

在cmd中(下行若在Windows PowerShell中运行,去掉 /d):

cd /d D:/ai-assistant-multiple/backend 

$env:DASHSCOPE_API_KEY="真实的DASHSCOPE_API_KEY "

$env:DEEPSEEK_API_KEY="真实的DEEPSEEK_API_KEY"

uvicorn main:app --port 8000

如果你嫌输入比较麻烦,可以使用批处理文件(.bat)

在D:\ai-assistant-multiple\backend目录中用记事本建立名称为start_backend.bat批处理文件,以后只需双击这个 .bat 文件就能运行后端,无需手动输入命令。内容如下:

@echo off
cd /d "D:\ai-assistant-multiple\backend"
:: Set API Key
set DASHSCOPE_API_KEY=真实的DASHSCOPE_API_KEY
set DEEPSEEK_API_KEY=真实的DEEPSEEK_API_KEY
echo Starting AI assistant backend...
echo Visit http://localhost:8000 to check status
echo Open frontend/index.html in your browser
echo.
uvicorn main:app --port 8000
pause

注意,在使用时不要关闭后端服务。

2.打开前端

直接双击 frontend/index.html 用浏览器打开

3.聊天

现在可以在前端网页中开始聊天!

可以在同一个界面中体验不同 AI 模型的回答风格和能力了!

输入框改用多行文本域(<textarea>),不仅能输入多行内容,还能保留换行、缩进等格式,特别适合粘贴 Python 代码、JSON、Markdown 等结构化文本。支持 Enter 发送(避免换行冲突,需按 Ctrl+Enter发送)

用户点击“发送” → 立刻看到“正在思考…”,让用户在等待期间知道系统在工作,不会误以为卡死。

未来可以继续扩展高级功能,如:

   · 保存聊天历史

   · 部署到公网,7x24 小时可用,分享链接给任何人

posted on 2025-12-22 20:30  ljbguanli  阅读(2)  评论(0)    收藏  举报