跳过

本地AI搭建-python示例代码

发布时间: at 15:10
本文收录在以下合集中:

对话API知识点

获取API Key

API Key可以在DeepSeek官网获取。

获取后建议不要写在代码里面,建议使用环境变量保存

首次调用API

DeepSeek API 使用与 OpenAI 兼容的 API 格式,通过修改配置,您可以使用 OpenAI SDK 来访问 DeepSeek API,或使用与 OpenAI API 兼容的软件。

PARAMVALUE
base_url *https://api.deepseek.com
api_keyapply for an API key

调用API示例

curl

curl https://api.deepseek.com/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <DeepSeek API Key>" \
  -d '{
        "model": "deepseek-chat",
        "messages": [
          {"role": "system", "content": "You are a helpful assistant."},
          {"role": "user", "content": "Hello!"}
        ],
        "stream": false
      }'

python

# Please install OpenAI SDK first: `pip3 install openai`
# 需要先安装openai支持: `pip3 install openai`

from openai import OpenAI

client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Hello"},
    ],
    stream=False
)

print(response.choices[0].message.content)

nodejs

// Please install OpenAI SDK first: `npm install openai`
// 需要先安装openai支持: `npm install openai`

import OpenAI from 'openai'

const openai = new OpenAI({
  baseURL: 'https://api.deepseek.com',
  apiKey: '<DeepSeek API Key>',
})

async function main() {
  const completion = await openai.chat.completions.create({
    messages: [{role: 'system', content: 'You are a helpful assistant.'}],
    model: 'deepseek-chat',
  })

  console.log(completion.choices[0].message.content)
}

main()

关于role参数

在AI对话系统中,role参数用于区分对话中不同参与者的身份或角色:

messages.push({role: 'user', content: userMessage})

这里的role可以有以下几种取值,每种都有特定含义:

1. 主要角色类型
角色(role)说明
"system"系统指令,用于设置AI的初始行为或背景
"user"用户发送的消息/问题
"assistant"AI助手的回复
2. 具体解释
  1. system (系统角色)

    • 通常放在对话历史的最开始
    • 用于设定AI的行为模式或对话上下文
    • 例如:
      { role: "system", content: "你是一个专业的医疗助手,用简单易懂的语言回答" }
      
  2. user (用户角色)

    • 代表人类用户输入的内容
    • 例如:
      { role: "user", content: "感冒有哪些症状?" }
      
  3. assistant (助手角色)

    • 代表AI之前的回复内容
    • 用于维持对话上下文
    • 例如:
      { role: "assistant", content: "感冒常见症状包括..." }
      
3. 为什么需要区分角色?
  1. 上下文维护:AI需要知道哪些是用户说的,哪些是自己说过的
  2. 行为控制:系统消息可以指导AI如何回应
  3. 多轮对话:保持对话的自然流畅性
4. 实际对话示例

一个完整的messages数组可能长这样:

;[
  {role: 'system', content: '你是一个有帮助的助手'},
  {role: 'user', content: '你好'},
  {role: 'assistant', content: '你好!有什么可以帮您的吗?'},
  {role: 'user', content: '推荐几本好书'},
]
5. 在你的代码中的作用

当你执行:

messages.push({role: 'user', content: userMessage})

你是在告诉AI: “接下来这条消息是用户(user)发送的,内容是userMessage”

这样当AI处理时,就能正确理解对话的流向和上下文关系。

6. 高级用法

有些API可能还支持其他角色,如:

但在基础对话场景中,主要使用上述三种基本角色。

本地AI对接DeepSeek

首先需要在DeepSeek官网购买API,获取API Key,随后可以使用脚本搭建一个本地对话

from openai import OpenAI
import os

# 初始化对话历史
messages = [
    {"role": "system", "content": "你是一个乐于助人的AI助手"},
]

def main():
    # 建议从环境变量读取API Key
    api_key = os.getenv("DEEPSEEK_API_KEY") or input("请输入DeepSeek API Key: ")

    if not api_key:
        print("API Key不能为空!")
        return

    client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")
    print("请输入任意问题回车发出对话(键入exit退出): ")

    counter = 0

    while True:
        try:
            counter += 1
            user_input = input(f"{counter}.问:")

            if user_input.lower() == "exit":
                break

            messages.append({"role": "user", "content": user_input})

            print(f"{counter}.AI:", end="", flush=True)
            assistant_output = ""

            response = client.chat.completions.create(
                model="deepseek-reasoner",
                messages=messages,
                stream=True,
            )

            for chunk in response:
                if chunk.choices[0].delta.content:
                    content = chunk.choices[0].delta.content
                    assistant_output += content
                    print(content, end="", flush=True)

            print("")  # 换行
            messages.append({"role": "assistant", "content": assistant_output})

        except KeyboardInterrupt:
            print("\n对话已中断")
            break
        except Exception as e:
            print(f"\n发生错误: {str(e)}")
            break

if __name__ == '__main__':
    main()

如果需要UI界面,也可以本地创建一个web服务,加入web服务后完整代码如下

from flask import Flask, render_template_string, request, jsonify
from openai import OpenAI
import os

app = Flask(__name__)

# 初始化对话历史
messages = [
    {"role": "system", "content": "你是一个乐于助人的AI助手"},
]

# 建议从环境变量读取API Key
api_key = os.getenv("DEEPSEEK_API_KEY")
client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")

# HTML模板
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
    <title>AI对话助手</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .chat-container {
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            padding: 20px;
            height: 500px;
            overflow-y: auto;
            margin-bottom: 20px;
        }
        .message {
            margin-bottom: 15px;
            padding: 10px 15px;
            border-radius: 18px;
            max-width: 70%;
            word-wrap: break-word;
        }
        .user-message {
            background-color: #e3f2fd;
            margin-left: auto;
            border-bottom-right-radius: 5px;
        }
        .assistant-message {
            background-color: #f1f1f1;
            margin-right: auto;
            border-bottom-left-radius: 5px;
        }
        #input-form {
            display: flex;
            gap: 10px;
        }
        #user-input {
            flex-grow: 1;
            padding: 10px;
            border-radius: 20px;
            border: 1px solid #ddd;
        }
        button {
            padding: 10px 20px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 20px;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        .typing-indicator {
            display: inline-block;
            padding: 10px 15px;
            background-color: #f1f1f1;
            border-radius: 18px;
            margin-bottom: 15px;
            border-bottom-left-radius: 5px;
        }
        .typing-dot {
            display: inline-block;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background-color: #888;
            margin: 0 2px;
            animation: typing-animation 1.4s infinite ease-in-out;
        }
        .typing-dot:nth-child(1) { animation-delay: 0s; }
        .typing-dot:nth-child(2) { animation-delay: 0.2s; }
        .typing-dot:nth-child(3) { animation-delay: 0.4s; }
        @keyframes typing-animation {
            0%, 60%, 100% { transform: translateY(0); }
            30% { transform: translateY(-5px); }
        }
    </style>
</head>
<body>
    <h1>AI对话助手</h1>
    <div class="chat-container" id="chat-container">
        {% for message in messages %}
            {% if message.role == 'user' %}
                <div class="message user-message">{{ message.content }}</div>
            {% elif message.role == 'assistant' %}
                <div class="message assistant-message">{{ message.content }}</div>
            {% endif %}
        {% endfor %}
        <div id="typing-indicator" style="display: none;">
            <div class="typing-indicator">
                <span class="typing-dot"></span>
                <span class="typing-dot"></span>
                <span class="typing-dot"></span>
            </div>
        </div>
    </div>
    <form id="input-form" onsubmit="sendMessage(); return false;">
        <input type="text" id="user-input" placeholder="输入你的问题..." autocomplete="off">
        <button type="submit">发送</button>
    </form>

    <script>
        function sendMessage() {
            const input = document.getElementById('user-input');
            const message = input.value.trim();
            if (!message) return;

            // 显示用户消息
            const chatContainer = document.getElementById('chat-container');
            const userMessageDiv = document.createElement('div');
            userMessageDiv.className = 'message user-message';
            userMessageDiv.textContent = message;
            chatContainer.appendChild(userMessageDiv);

            // 显示打字指示器
            const typingIndicator = document.getElementById('typing-indicator');
            typingIndicator.style.display = 'block';

            // 清空输入框
            input.value = '';

            // 滚动到底部
            chatContainer.scrollTop = chatContainer.scrollHeight;

            // 发送到服务器
            fetch('/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ message: message })
            })
            .then(response => response.json())
            .then(data => {
                // 隐藏打字指示器
                typingIndicator.style.display = 'none';

                // 显示AI回复
                const assistantMessageDiv = document.createElement('div');
                assistantMessageDiv.className = 'message assistant-message';
                assistantMessageDiv.textContent = data.response;
                chatContainer.appendChild(assistantMessageDiv);

                // 滚动到底部
                chatContainer.scrollTop = chatContainer.scrollHeight;
            })
            .catch(error => {
                console.error('Error:', error);
                typingIndicator.style.display = 'none';

                const errorDiv = document.createElement('div');
                errorDiv.className = 'message assistant-message';
                errorDiv.textContent = '抱歉,发生了错误: ' + error;
                chatContainer.appendChild(errorDiv);

                chatContainer.scrollTop = chatContainer.scrollHeight;
            });
        }

        // 允许按Enter键发送消息
        document.getElementById('user-input').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                sendMessage();
            }
        });
    </script>
</body>
</html>
"""

@app.route('/')
def home():
    return render_template_string(HTML_TEMPLATE, messages=messages[1:])  # 跳过系统消息

@app.route('/chat', methods=['POST'])
def chat():
    user_message = request.json.get('message')
    if not user_message:
        return jsonify({"error": "消息不能为空"}), 400

    # 添加用户消息到历史
    messages.append({"role": "user", "content": user_message})

    try:
        # 获取AI回复
        response = client.chat.completions.create(
            model="deepseek-reasoner",
            messages=messages,
            stream=False,
        )

        assistant_output = response.choices[0].message.content

        # 添加AI回复到历史
        messages.append({"role": "assistant", "content": assistant_output})

        return jsonify({"response": assistant_output})

    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    # 在局域网中运行,host='0.0.0.0' 允许其他设备访问
    app.run(host='0.0.0.0', port=5000, debug=True)

参考资料