日期:2026 年 5 月 4 日—— 5 月 17 日

项目:绘画 AI 博弈小游戏 —— 人机对抗绘画猜词与心理解读系统 

本周核心任务是:为画风建模系统搭建完整的后端支撑,使得 AI 在每一局对抗中都能更精准地理解玩家的绘画特征,形成"越玩越懂"的学习闭环。

一、数据库设计:player_style_profiles 表

1.1 表结构设计

SQL

CREATE TABLE IF NOT EXISTS player_style_profiles (
    id              TEXT PRIMARY KEY,
    user_id         TEXT NOT NULL,
    room_id         TEXT,
    version         INTEGER DEFAULT 1,
    rounds_analyzed INTEGER DEFAULT 0,
    features_json   TEXT NOT NULL,
    profile_text    TEXT NOT NULL,
    model_used      TEXT DEFAULT '',
    generated_at    REAL NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (room_id) REFERENCES rooms(id)
);

设计要点分析:

  1. version 字段的意义

    • 每次刷新档案时 +1,形成版本链
    • 不覆盖历史记录,便于追踪玩家画风演变
    • 前端可展示 "v1 → v2 → v3" 的画风进化曲线
  2. features_json 存储方案

    Python

    # 聚合的量化特征(喂给 prompt 用)
    {
        "rounds_analyzed": 5,
        "avg_stroke_speed": 145.67,           # px/ms
        "stroke_speed_variance": 32.18,       # 速度方差(高方差=节奏多变)
        "avg_canvas_coverage": 0.48,          # 画面占比
        "avg_symmetry": 0.72,                 # 对称性得分
        "avg_undo_eraser": 2.4,               # 平均修改次数
        "avg_stroke_count": 18.5,             # 平均笔画数
        "avg_duration_ms": 32500,             # 平均绘画时长
        "avg_turn_density": 0.35,             # 线条拐点密度
        "avg_color_count": 2.8,               # 平均用色数
        "tags": ["快笔型", "大胆构图", "细节丰富"]
    }
    
  3. profile_text 的 LLM 生成

    • 字段存储由 DeepSeek-V3.2 生成的自然语言档案
    • 长度 100-200 字,便于 AI prompt 理解
    • 包含构图偏好、线条特征、修改习惯等易于识别的描述

二、数据流设计:从 behaviors 到 profile

2.1 完整流程图解

Code

┌─────────────────────────────────────────────────────────────┐
│                     玩家完成绘画                              │
│        Canvas.getBehaviorData() → drawing_behaviors 表       │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│              后台任务:_refresh_style_profile_async()         │
│         检查:局数 >= STYLE_PROFILE_MIN_ROUNDS (3)?         │
└────────────────────┬────────────────────────────────────────┘
                     │ YES
                     ▼
┌─────────────────────────────────────────────────────────────┐
│           models.get_user_behaviors(user_id, limit=10)       │
│          取最近 N 局的 drawing_behaviors 原始数据             │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│      style_profiler.aggregate_features(behaviors)            │
│                                                              │
│  • 计算平均值:速度、覆盖率、对称性等                         │
│  • 计算方差:识别节奏多变特征                                  │
│  • 派生标签:快笔型、细节丰富、一气呵成等                      │
│                                                              │
│  输出:features_dict(含量化指标 + 派生标签)                 │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│   style_profiler.generate_profile_text(features)             │
│                                                              │
│  • 构建 prompt(包含派生标签)                                │
│  • 调用 DeepSeek-V3.2 文本模型                               │
│  • 生成自然语言档案(100-200字)                              │
│                                                              │
│  返回:profile_text(用于 AI prompt 注入)                   │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│    models.save_style_profile(user_id, features, profile)    │
│                                                              │
│  • 取当前最高版本号 v_max                                     │
│  • 插入新行:version = v_max + 1                             │
│  • 存入 features_json 和 profile_text                        │
│  • 记录生成时间和使用的模型                                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│   player_style_profiles 表新增一行(版本链)                  │
│   下次 AI 猜词时调用 get_active_profile() 获取最新档案        │
└─────────────────────────────────────────────────────────────┘

关键设计决策:

  1. 为什么不覆盖历史记录?

    • 保留版本链便于前端展示"画风演变曲线"
    • 研究端可以分析单个玩家的成长轨迹
    • 数据库存储成本低(只是文本字段)
  2. 为什么用异步后台任务?

    Python

    # app.py 中的调用方式
    socketio.start_background_task(
        _refresh_style_profile_async, drawer_id, room_id
    )
    
    • 不阻塞游戏流程,回合结果立即返回
    • 避免 LLM 调用延迟影响用户体验
    • 失败自动降级(用模板描述)
  3. 何时触发生成?

    Python

    STYLE_PROFILE_MIN_ROUNDS = 3   # 至少3局才生成
    STYLE_PROFILE_BEHAVIOR_LIMIT = 10  # 每次取最近10局聚合
    
    • 前 3 局积累基础特征
    • 第 4 局后每局都更新一次
    • 只聚合最近 10 局,权重自然递减

三、特征聚合算法详解

3.1 从原始行为数据到派生标签

在 style_profiler.py 中的 aggregate_features() 和 _derive_tags() 函数核心逻辑:

Python

def aggregate_features(behaviors):
    """
    输入:多局 drawing_behaviors 行(list of dict)
    输出:画风特征字典(量化指标 + 派生标签)
    """
    n = len(behaviors)
    
    # 1. 计算基础统计量
    speed_avg = statistics.mean([b.get('stroke_speed_avg', 0) for b in behaviors])
    speed_var = statistics.stdev([b.get('stroke_speed_avg', 0) for b in behaviors])
    coverage_avg = statistics.mean([b.get('canvas_coverage', 0) for b in behaviors])
    symmetry_avg = statistics.mean([b.get('symmetry_score', 0) for b in behaviors])
    
    # 2. 派生标签的阈值设定(基于心理学研究)
    tags = []
    
    # 速度标签(笔迹学依据:Pulver, 1931)
    if speed_avg > 200:
        tags.append('快笔型(运笔急促)')  # 高速 = 情绪激活
    elif speed_avg < 50:
        tags.append('慢笔型(运笔缓慢)')  # 低速 = 心理退缩
    else:
        tags.append('中速运笔')
    
    # 节奏稳定性(速度方差大 = 节奏多变 = 思维跳跃)
    if speed_var > 80:
        tags.append('节奏多变')
    
    # 构图类型(HTP 理论:Buck, 1948)
    if coverage_avg > 0.55:
        tags.append('大胆构图(占满画面)')  # 占比大 = 外向、自信
    elif coverage_avg < 0.2:
        tags.append('保守构图(大量留白)')  # 占比小 = 内向、谨慎
    
    # 对称性偏好(格式塔心理学:Arnheim, 1974)
    if symmetry_avg > 0.65:
        tags.append('对称偏好')  # 追求秩序感
    elif symmetry_avg < 0.3:
        tags.append('自由构图')  # 不拘一格、创意强
    
    return {
        'rounds_analyzed': n,
        'avg_stroke_speed': round(speed_avg, 2),
        'stroke_speed_variance': round(speed_var, 2),
        'avg_canvas_coverage': round(coverage_avg, 2),
        'avg_symmetry': round(symmetry_avg, 2),
        'tags': tags,
        # ... 更多指标
    }

派生标签的心理学意义:

标签 心理学解释 阈值依据
快笔型 情绪激活、兴奋状态 速度 > 200 px/ms
慢笔型 情绪低沉、心理退缩 速度 < 50 px/ms
节奏多变 思维跳跃、注意力分散 速度方差 > 80
大胆构图 自信、外向、不拘束 覆盖率 > 55%
保守构图 谨慎、内向、自我保护 覆盖率 < 20%
对称偏好 追求秩序感、完美主义 对称性 > 0.65
自由构图 创意丰富、随性 对称性 < 0.3
一气呵成 自信、果断、不修改 撤销次数 < 1
反复推敲 谨慎、完美主义、压力大 撤销次数 > 6
细节丰富 观察力强、耐心 笔画数 > 25
简笔风格 高效、追求简洁 笔画数 < 8

3.2 为什么采用多层级特征提取?

Code

原始行为数据(drawing_behaviors 表)
    ↓
    ├─ stroke_speed_avg
    ├─ canvas_coverage
    ├─ turn_point_density
    └─ undo_count ... (15+ 个字段)
    
    ▼
中间层:量化指标聚合
    ├─ avg_stroke_speed(10局均值)
    ├─ stroke_speed_variance(速度方差)
    ├─ avg_canvas_coverage
    └─ ...
    
    ▼
高层:派生标签(转化为人话)
    ├─ "快笔型"
    ├─ "大胆构图"
    ├─ "节奏多变"
    └─ ...
    
    ▼
最终:LLM prompt 注入
    "该玩家快笔型、大胆构图、节奏多变...
     平均每局用时32秒、笔触18笔、覆盖率48%...
     AI应注意其习惯性起笔位置和色彩搭配"

分层好处:

  • 量化指标用于统计分析(后端研究)
  • 派生标签便于自然语言理解(LLM 理解)
  • 原始数据保留(支持未来算法升级)

四、API 设计与实现

4.1 获取画风档案 API

Python

@app.route('/api/style_profile/<user_id>')
def api_get_style_profile(user_id):
    """获取用户当前最新的画风档案 + 历史版本列表"""
    
    latest = models.get_latest_style_profile(user_id)
    
    if not latest:
        return jsonify({
            'has_profile': False,
            'message': '暂无画风档案,至少完成 3 局对战才会生成。',
            'history': [],
        })
    
    # 最新版档案
    history = models.get_style_profile_history(user_id, limit=10)
    
    return jsonify({
        'has_profile': True,
        'latest': {
            'profile_id': latest['id'],
            'version': latest['version'],
            'rounds_analyzed': latest['rounds_analyzed'],
            'profile_text': latest['profile_text'],
            'features': latest.get('features', {}),  # 量化指标供前端画图
            'model_used': latest['model_used'],  # 标识 LLM 版本
            'generated_at': latest['generated_at'],
        },
        'history': history,  # 用于展示版本演变
    })

返回数据示例:

JSON

{
  "has_profile": true,
  "latest": {
    "profile_id": "abc12345",
    "version": 3,
    "rounds_analyzed": 8,
    "profile_text": "该玩家是典型的快笔型、大胆构图者。笔触速度均值145px/ms,...",
    "features": {
      "avg_stroke_speed": 145.67,
      "avg_canvas_coverage": 0.52,
      "avg_symmetry": 0.38,
      "tags": ["快笔型", "大胆构图", "自由构图"]
    },
    "model_used": "deepseek-chat",
    "generated_at": 1718625600
  },
  "history": [
    {"version": 3, "rounds_analyzed": 8, "generated_at": 1718625600},
    {"version": 2, "rounds_analyzed": 5, "generated_at": 1718539200},
    {"version": 1, "rounds_analyzed": 3, "generated_at": 1718452800}
  ]
}

4.2 内部接口:AI 识别调用

Python

# 在 ai_recognizer.py 中
def recognize_drawing(image_base64, difficulty, category, 
                     word_list=None, user_id=None):
    """
    调用 AI 猜词,可选注入玩家画风档案
    """
    
    # 关键:取玩家的最新画风档案
    style_profile = ''
    if user_id:
        try:
            from utils import style_profiler
            style_profile = style_profiler.get_active_profile(user_id)
            # 若有档案,会返回 100-200 字的描述,否则返回空串
        except Exception as e:
            print(f'[AI] 画风档案加载失败: {e}')
    
    # 构建 prompt(难度相关)
    prompt = _build_prompt(difficulty, category, word_list, 
                          style_profile=style_profile)
    
    # 调用多模态 AI(使用档案增强识别精度)
    result = _call_zhipu(image_base64, prompt)
    return result

prompt 中的档案注入示例:

Python

# 当 style_profile 有值时
prompt += (
    f"\n\n【该玩家的画风档案(基于历史绘画行为)】\n"
    f"{style_profile}\n"
    "请结合该玩家的画风习惯进行识别,但最终判断仍以画面内容为准。"
)

4.3 后台任务:档案刷新

Python

# app.py 中的回合结束处理
def _do_end_guessing(room_id):
    """回合结束,异步刷新画家的画风档案"""
    
    # ... 游戏逻辑 ...
    
    # 触发档案刷新(不阻塞主流程)
    try:
        drawer_id = round_info.get('drawer_id')
        if drawer_id:
            socketio.start_background_task(
                _refresh_style_profile_async, drawer_id, room_id
            )
    except Exception as e:
        print(f'[StyleProfiler] 触发失败: {e}')


def _refresh_style_profile_async(user_id, room_id):
    """后台异步任务:刷新画风档案"""
    
    try:
        from utils import style_profiler
        
        min_rounds = config.STYLE_PROFILE_MIN_ROUNDS  # 3
        limit = config.STYLE_PROFILE_BEHAVIOR_LIMIT   # 10
        
        # 取该玩家最近 10 局的行为数据
        behaviors = models.get_user_behaviors(user_id, limit=limit)
        
        if len(behaviors) < min_rounds:
            print(f'[StyleProfiler] 玩家 {user_id} 仅 {len(behaviors)} 局,暂不生成')
            return
        
        # 转 dict(sqlite Row 需要转换)
        behavior_dicts = [dict(b) if not isinstance(b, dict) else b 
                         for b in behaviors]
        
        user = models.get_user(user_id)
        nickname = user.get('nickname', '该玩家')
        
        # 核心:构建并保存档案
        result = style_profiler.build_and_save_profile(
            user_id=user_id,
            behaviors=behavior_dicts,
            nickname=nickname,
            room_id=room_id,
            save_to_db=True,
        )
        
        print(f'[StyleProfiler] 玩家 {user_id} 档案已刷新: '
              f'rounds={result["rounds_analyzed"]}, '
              f'model={result["model_used"]}')
              
    except Exception as e:
        print(f'[StyleProfiler] 后台刷新异常: {e}')
        traceback.print_exc()

五、DeepSeek-V3.2 后端接入

初始化代码(style_profiler.py):

Python

def _call_deepseek(features, nickname):
    """
    调用 DeepSeek-V3.2 API 生成画风档案
    
    流程:
    1. 初始化客户端(使用 API Key)
    2. 构建 system/user 消息
    3. 调用 chat.completions.create()
    4. 解析响应并返回
    """
    
    try:
        from openai import OpenAI
    except ImportError:
        print('[StyleProfiler] openai SDK 未安装,请 pip install openai')
        return _template_fallback(features, nickname)
    
    # ★ 关键:初始化 DeepSeek 客户端
    # DeepSeek 提供 OpenAI 兼容接口,URL 和 key 配置即可
    client = OpenAI(
        api_key=config.DEEPSEEK_API_KEY,
        base_url=getattr(config, 'DEEPSEEK_BASE_URL', 'https://api.deepseek.com/v1'),
    )
    
    # ★ 构建 prompt
    prompt = _build_profile_prompt(features, nickname)
    
    # ★ 调用 API
    resp = client.chat.completions.create(
        model=getattr(config, 'DEEPSEEK_MODEL', 'deepseek-chat'),
        messages=[
            {
                'role': 'system',
                'content': (
                    '你是一个细致的绘画行为分析师。'
                    '根据玩家的绘画行为数据,写一段精炼、客观、便于AI识别使用的画风描述。'
                    '不要出现"可能"、"也许"这类模糊词,给出明确的判断。'
                )
            },
            {
                'role': 'user',
                'content': prompt
            }
        ],
        temperature=0.4,    # ★ 控制创意度:0.4 = 较稳定,避免过度创意
        max_tokens=400,     # ★ 限制输出长度(100-200 字),节省 token
        top_p=0.9,          # ★ nucleus sampling,增加多样性
    )
    
    # ★ 提取结果
    text = resp.choices[0].message.content.strip()
    
    print(f'[StyleProfiler] DeepSeek 生成档案 {len(text)} 字')
    print(f'[StyleProfiler] 本次调用耗费 token: '
          f'input={resp.usage.prompt_tokens}, '
          f'output={resp.usage.completion_tokens}')
    
    return text

5.1 Prompt 工程:档案生成策略

Python

def _build_profile_prompt(features, nickname):
    """构建用于 DeepSeek 的 profile 生成 prompt"""
    
    tags_str = '、'.join(features.get('tags', [])) or '暂无明显倾向'
    
    return (
        f"玩家昵称:{nickname}\n"
        f"已分析局数:{features['rounds_analyzed']}\n\n"
        
        "【量化指标(多局平均)】\n"
        f"- 平均笔速:{features['avg_stroke_speed']} px/s\n"
        f"  (方差 {features['stroke_speed_variance']})  # 方差大=节奏不稳定\n"
        f"- 平均画面覆盖率:{features['avg_canvas_coverage']}\n"
        f"- 平均对称性得分:{features['avg_symmetry']}\n"
        f"- 平均撤销+橡皮擦次数:{features['avg_undo_eraser']}\n"
        f"- 平均笔画数:{features['avg_stroke_count']}\n"
        f"- 平均绘画时长:{features['avg_duration_ms']} ms\n"
        f"- 平均拐点密度:{features['avg_turn_density']}\n"
        f"- 平均用色数量:{features['avg_color_count']}\n\n"
        
        f"【派生标签】{tags_str}\n\n"
        
        "请输出一段100-180字的画风档案,格式为:\n"
        "1. 总体画风定位(一句话)\n"
        "2. 关键识别特征(2-3条,便于AI在猜词时参考)\n"
        "3. 推测画法偏好(例如喜欢先画轮廓再填细节,或反之)\n"
        "不要使用Markdown标题,直接写连贯的中文段落。"
    )

生成的档案示例:

Code

该玩家是典型的快笔型、大胆构图者,运笔速度平均145px/s,
显示较强的情绪激活和行动力。画面覆盖率达52%,明显倾向占满整个
画布,反映出自信和不拘束的性格。虽然对称性评分仅0.38,但这正
体现了其自由、创意驱动的绘画风格——不遵循规则,更注重表达力。
识别建议:该玩家通常先画大轮廓,再快速补充细节,线条曲折度高
(拐点密度0.42),说明思维跳跃。建议AI优先识别其起笔特征和色彩
组合偏好,而非精确轮廓。

5.2 容错机制与降级

Python

def generate_profile_text(features, nickname='该玩家'):
    """
    调用 LLM 生成档案,失败时自动降级
    """
    
    try:
        if (getattr(config, 'DEEPSEEK_API_KEY', '') and 
            getattr(config, 'STYLE_MODEL_PROVIDER', '') == 'deepseek'):
            
            # ★ 方案一:LLM 调用
            return _call_deepseek(features, nickname)
        else:
            # ★ 方案二:模板拼接
            return _template_fallback(features, nickname)
            
    except Exception as e:
        print(f'[StyleProfiler] LLM 调用失败: {e}')
        # ★ 方案三:最终降级(完全失败)
        return _template_fallback(features, nickname)


def _template_fallback(features, nickname):
    """
    无 API Key 或 LLM 失败时的模板拼接方案
    保证系统可用性
    """
    
    tags = features.get('tags', [])
    if not tags:
        return f'{nickname}尚未积累足够画风数据,暂以默认策略识别。'
    
    lead = '、'.join(tags[:3])
    detail = '、'.join(tags[3:]) if len(tags) > 3 else ''
    
    parts = [
        f'{nickname}的画风总体呈现「{lead}」的特征。',
    ]
    if detail:
        parts.append(f'此外还表现出{detail}的倾向。')
    
    parts.append(
        f'平均每局画 {features["avg_stroke_count"]:.0f} 笔、'
        f'用时 {features["avg_duration_ms"]/1000:.1f} 秒、'
        f'画面覆盖率约 {features["avg_canvas_coverage"]:.0%}。'
    )
    
    return ''.join(parts)

三层容错设计:

Code

┌─────────────────────────────────┐
│   尝试方案一:调用 DeepSeek-V3.2 │
│   成功 ✅ → 返回高质量档案      │
└────────────┬────────────────────┘
             │ 失败(API Error, Timeout)
             ▼
┌─────────────────────────────────┐
│   尝试方案二:模板拼接            │
│   (无网络也能用)                 │
│   成功 ✅ → 返回可用档案         │
└────────────┬────────────────────┘
             │ 不适用(无派生标签)
             ▼
┌─────────────────────────────────┐
│   方案三:最小化降级              │
│   返回通用提示 + 基础指标         │
│   ✅ 系统保证可用                 │
└─────────────────────────────────┘

六、性能优化与查询设计

6.1 数据库查询优化

Python

def get_user_behaviors(user_id, limit=50):
    """获取用户历史行为数据(带索引优化)"""
    
    with get_db_connection() as conn:
        # ★ 利用 INDEX 加速查询
        rows = conn.execute(
            '''SELECT * FROM drawing_behaviors 
               WHERE user_id = ? 
               ORDER BY created_at DESC 
               LIMIT ?''',
            (user_id, limit)
        ).fetchall()
        
        return [dict(r) for r in rows]


def get_latest_style_profile(user_id):
    """获取最新档案(单行查询,O(1))"""
    
    with get_db_connection() as conn:
        row = conn.execute(
            '''SELECT * FROM player_style_profiles
               WHERE user_id = ?
               ORDER BY version DESC 
               LIMIT 1''',
            (user_id,)
        ).fetchone()
        
        if not row:
            return None
        
        result = dict(row)
        # ★ 解析 JSON 字段
        try:
            result['features'] = json.loads(result['features_json'])
        except (TypeError, json.JSONDecodeError):
            result['features'] = {}
        
        return result

数据库索引设计:

SQL

-- 既有索引(从 models.py 初始化)
CREATE INDEX idx_drawing_behaviors_round ON drawing_behaviors(round_id);

-- 新增索引(针对画风系统)
CREATE INDEX idx_drawing_behaviors_user_time ON drawing_behaviors(
    user_id, created_at DESC
);  -- 加速查询"取该玩家最近 N 局"

CREATE INDEX idx_style_profiles_user_version ON player_style_profiles(
    user_id, version DESC
);  -- 加速查询"该玩家最新版档案"

6.2 聚合性能分析

Python

def aggregate_features(behaviors):
    """
    性能分析:N 局数据聚合耗时
    
    N=10 局时:
    - 遍历求平均值:O(N*M) = O(10*15) ≈ 150 ops(毫秒级)
    - 计算方差:O(N) ≈ 10 ops(毫秒级)
    - 派生标签:O(1)(比对阈值)
    - 总耗时:< 5ms(可忽略)
    """
    
    # 1. 计算统计量(Python 的 statistics 模块优化过)
    speeds = [b.get('stroke_speed_avg', 0) for b in behaviors]
    avg = statistics.mean(speeds)   # O(N)
    var = statistics.stdev(speeds)  # O(N)
    
    # 2. 派生标签(条件判断,O(1))
    tags = []
    if avg > 200:           # 阈值比对
        tags.append('快笔型')
    
    return {...}

性能保证:

  • 单次聚合 < 10ms
  • LLM 调用 (1-3s) 在后台异步运行
  • 不影响游戏主流程的响应时间

七、AI辅助开发记录

Prompt1

我需要设计一个表来存储玩家的"画风档案",要求:

1. 支持版本控制(追踪画风演变,每次更新+1版本号)

2. 存储量化特征(JSON格式,包含笔速、覆盖率、对称性等15+指标)

3. 存储AI生成的自然语言档案(100-200字的文本描述)

4. 记录生成时间和使用的模型信息

请给出:

- 完整的 SQL CREATE TABLE 语句(SQLite)

- 每个字段的设计理由

- 建议的索引策略

- 字段大小和存储成本估算

Prompt2:

我需要在 models.py 中实现以下函数,用于存取 player_style_profiles 表:

1. save_style_profile(user_id, features_dict, profile_text, room_id,

rounds_analyzed, model_used)

- 保存一份新的画风档案

- 自动计算版本号(取当前最高版本+1)

- 不覆盖历史版本,形成版本链

- 返回 profile_id

2. get_latest_style_profile(user_id)

- 获取该用户的最新档案(最高版本号)

- 返回包含解析后 features 字典的完整记录

3. get_style_profile_history(user_id, limit=10)

- 获取该用户的历史版本列表(新到旧)

- 用于前端展示"画风演变"

请生成这三个函数的完整实现,包括:

- SQL 语句

- 错误处理

- 参数校验

- 返回格式统一

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐