【案例共创】华为开发者空间云开发环境 x DeepSeek打造全链路高效数据分析工作流

基于华为云与DeepSeek的数据分析工作流

本案例由开发者:熊文涛提供

一. 概述

1. 案例介绍

在当今这个数字经济时代,数据无疑成为企业最核心的资产之一。面对激烈的市场竞争,企业若想精准决策,迅速响应市场变化,就必须依赖高效的数据分析能力。数据分析不仅能够帮助企业洞察市场趋势、预测消费者行为,更可以优化运营效率,降低成本,提升企业的整体竞争力。

本案例通过华为开发者空间云开发环境和DeepSeek打造全链路高效数据分析工作流,帮助开发者和企业在数据驱动的道路上走得更快、更稳。

华为开发者空间是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云主机、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。

2. 适用对象

  • 企业
  • 个人开发者
  • 高校学生

3. 案例时间

本案例总时长预计90分钟。

4. 案例流程

说明: 1. 用户进入华为开发者空间云开发环境; 2. 通过CLI工具连接云开发环境; 3. 安装ollama并启动本地推理模型DeepSeek; 4. 结合Python中丰富的三方库、MySQL、DeepSeek,从数据采集、清洗、建模到可视化展示,构建全链路数据分析工作流。

5. 资源总览

本案例预计花费0元。

资源名称规格单价(元)时长(分钟)
华为开发者空间 - 云开发环境鲲鹏通用计算增强型 kc1 | 2vCPUs | 4G | HCE免费90

二. 云开发环境及开发工具准备

2.1 云开发环境

本案例中,使用华为云《开发者空间云开发环境使用指导》的“三、PC端创建和管理云开发环境”章节完成cli工具安装、环境配置、创建云开发环境、开机、建立隧道连接的功能。

2.2 开发工具准备

本案例中,使用华为云《本地CodeArts IDE基于华为开发者空间云开发环境完成小游戏开发》的“三.本地IDE直连云开发环境完成上传下载”章节完成本地IDE连接远程开发环境。

三. 部署DeepSeek大模型

3.1 下载安装ollama

输入以下命令下载ollama:

curl -fsSL https://dtse-mirrors.obs.cn-north-4.myhuaweicloud.com/case/0035/install.sh | sudo bash

下载完毕之后我们可以借助 Ollama 工具来部署 Deepseek 大模型,部署 deepseek-r1:1.5b 版本,如果硬件支撑可以部署更高效的模型,执行命令:

ollama run deepseek-r1:1.5b

3.2 部署测试模型

以上我们就部署完了,可以尝试输入prompt来测试效果:

通过以下命令,可以查看olloama开放的本地端口:

sudo netstat -tunlp

那么接下来我们可以打开CodeArt IDE for Python,对端口进行通信,完成这一步之后我们可以开始尝试构建智能体。

我们知道 ollama serve 默认监听地址为 http://localhost:11434 ,首先下载requests库:

pip install requests

新建DataAnalysis/src文件夹,用于存放项目源码,src下新建文件main.py:

import requests
def chat_with_ollama(prompt, model="deepseek-r1:1.5b"):
    url = "http://localhost:11434/api/generate"
    headers = {
        "Content-Type": "application/json"
    }
    data = {
        "model": model,
        "prompt": prompt,
        "stream": False # 关闭流式返回,适合简单测试
    }
    try:
        response = requests.post(url, json=data, headers=headers)
        response.raise_for_status()
        result = response.json()
        print("模型回复:", result["response"])
    except requests.exceptions.RequestException as e:
        print("请求出错:", e)
    except Exception as e:
        print("其他错误:", e)

if __name__ == "__main__":
    test_prompt = "你好"
    chat_with_ollama(test_prompt)

我们进入DataAnalysis/src文件夹下,执行python代码:

cd DataAnalysis/src

python main.py

如何能获取到大模型输出,说明我们之前的过程都没有问题:

四. 数据分析工作流项目工程介绍及运行

我们下一步就可以开始全链路高效数据分析工作流搭建了,开始之前,我们首先看下整个项目的目录结构:

项目目录结构.png

4.1 创建项目虚拟环境

因为业务场景的Python开发,多数都是构建一个大型应用程序,并且不希望各种组件的各种版本之间相互冲突,所以需要设置一个虚拟环境。

先需要更新下载源。执行如下命令:

sudo yum -y update
sudo yum -y upgrade

安装virtualenv:

pip3 install virtualenv  -i https://repo.huaweicloud.com/repository/pypi/simple/

创建虚拟环境:

python3 -m venv myenv 

激活环境:

source myenv/bin/activate 

环境激活后,用户名前会有(myenv)字样,如上图所示。

4.2 安装依赖并配置模型

安装依赖之前,更新pip:

python3 -m pip install --upgrade pip -i https://repo.huaweicloud.com/repository/pypi/simple/

使用pip3依次安装pandas、sqlalchemy、pymysql、python-dotenv、requests、matplotlib、plotly模块:

pip3 install pandas==2.2.2 -i https://repo.huaweicloud.com/repository/pypi/simple/

pip3 install sqlalchemy==2.0.32 -i https://repo.huaweicloud.com/repository/pypi/simple/

pip3 install pymysql==1.1.1 -i https://repo.huaweicloud.com/repository/pypi/simple/


pip3 install python-dotenv==1.0.1 -i https://repo.huaweicloud.com/repository/pypi/simple/

pip3 install requests==2.32.3 -i https://repo.huaweicloud.com/repository/pypi/simple/

pip3 install matplotlib==3.9.0 -i https://repo.huaweicloud.com/repository/pypi/simple/

pip3 install plotly==5.23.0 -i https://repo.huaweicloud.com/repository/pypi/simple/

启动本地推理模型:

ollama pull deepseek-r1:1.5b

本地模型配置:

在DataAnalysis目录下,新建.env文件:

LLM_PROVIDER=ollama
LLM_HOST=http://localhost:11434
LLM_MODEL=deepseek-r1:1.5b

4.3 文本预处理(Text Cleaning & 信息抽取)

进行数据清洗及信息抽取,格式化输出数据,便于模型调用。

4.3.1 代码:src/data_cleaning.py

data_cleaning.py:用于数据清洗及信息抽取,便于模型调用。

import os, re, json, requests
from typing import List, Dict, Any
from dotenv import load_dotenv
from typing import Optional, Union

load_dotenv()

class LLMClient:
    def __init__(self):
        self.provider = os.getenv("LLM_PROVIDER", "ollama")
        self.host = os.getenv("LLM_HOST", "http://localhost:11434")
        self.model = os.getenv("LLM_MODEL", "deepseek-r1:1.5b")
        self.api_key = os.getenv("LLM_API_KEY", "")

    def generate(self, prompt: str) -> str:
        if self.provider == "ollama":
            resp = requests.post(f"{self.host}/api/generate", json={
                "model": self.model, "prompt": prompt, "stream": False
            })
            resp.raise_for_status()
            return resp.json().get("response", "").strip()

        else:
            raise ValueError(f"Unsupported LLM provider: {self.provider}")


class DataCleaningAgent:
    def __init__(self, llm: Optional[LLMClient] = None):
        self.llm = llm or LLMClient()

    @staticmethod
    def clean_text(text: str) -> str:
        text = re.sub(r"<[^>]+>", " ", text) # 去HTML
        text = re.sub(r"\s+", " ", text) # 合并空白
        text = re.sub(r"[^\w\s\u4e00-\u9fa5@::,,。.\-—/()()]+", " ", text) # 去特殊符
        return text.strip()

    def extract_fields(self, text: str, instruction: str) -> Dict[str, Any]:
        """
        instruction 示例:
        从文本中提取公司名称(company)、联系人(contact)、电话(phone)。返回JSON,如:
        {"company": "...", "contact": "...", "phone": "..."}
        """
        prompt = f"""你是信息抽取助手。请严格输出JSON。

        文本:{text}

        任务:{instruction}

        注意: 
        1. 只输出一个JSON对象,不要输出多余文字。
        2. 缺失字段请用null。
        """

        raw = self.llm.generate(prompt)

        return parse_llm_json_response(raw)
        # try:
        #     return json.loads(raw)
        # except Exception:
        #     # LLM 偶发输出非纯JSON,兜底提取
        #     m = re.search(r"\{.*\}", raw, re.S)
        #     return json.loads(m.group(0)) if m else {"_raw": raw}

    def batch_process(self, samples: List[str], instruction: str) -> List[Dict[str,Any]]:
        out = []
        for s in samples:
            cleaned = self.clean_text(s)
            extracted = self.extract_fields(cleaned, instruction)
            out.append({"original": s, "cleaned": cleaned, "extracted": extracted})
        return out




def parse_llm_json_response(raw: str) -> Dict[str, Any]:
    """
    解析 LLM 生成的 JSON 响应,带有强大的错误处理和回退机制

    Args:
        raw: LLM 生成的原始响应字符串

    Returns:
        解析后的 JSON 字典,或包含原始响应的字典
    """
    # 首先尝试直接解析
    try:
        return json.loads(raw)
    except json.JSONDecodeError:
        # 如果直接解析失败,尝试提取可能的 JSON 部分
        pass

    # 使用更精确的正则表达式匹配 JSON 对象
    # 改进1: 非贪婪匹配,匹配第一个{到最后一个}之间的内容
    # 改进2: 处理可能的嵌套结构
    json_pattern = r"\{.*\}"
    match = re.search(json_pattern, raw, re.DOTALL)

    if match:
        try:
            return json.loads(match.group())
        except json.JSONDecodeError:
            # 如果提取的内容仍然不是有效 JSON,尝试清理内容
            cleaned_json = clean_json_string(match.group())
            try:
                return json.loads(cleaned_json)
            except json.JSONDecodeError:
                # 最终回退
                pass

    # 如果所有尝试都失败,返回原始文本
    return {"_raw": raw, "_error": "Failed to parse JSON response"}

def clean_json_string(json_str: str) -> str:
    """
    清理 JSON 字符串,尝试修复常见问题

    Args:
        json_str: 需要清理的 JSON 字符串

    Returns:
        清理后的 JSON 字符串
    """
    # 移除尾随逗号(在最后一个元素后)
    cleaned = re.sub(r',\s*}', '}', json_str)
    cleaned = re.sub(r',\s*]', ']', cleaned)

    # 修复单引号(JSON 标准要求双引号)
    cleaned = re.sub(r"'([^']*)'", r'"\1"', cleaned)

    # 移除注释(JSON 不支持注释)
    cleaned = re.sub(r'//.*?$', '', cleaned, flags=re.MULTILINE)
    cleaned = re.sub(r'/\*.*?\*/', '', cleaned, flags=re.DOTALL)

    return cleaned

4.3.2 运行脚本:src/preprocess.py

preprocess.py:数据清洗及信息抽取的执行类,输出清洗后的格式化数据。

import json, os
from pathlib import Path
from data_cleaning import DataCleaningAgent
ROOT = Path(__file__).resolve().parents[2]
RAW_DIR = ROOT / "data" / "raw"
PROC_DIR = ROOT / "data" / "processed"
PROC_DIR.mkdir(parents=True, exist_ok=True)

def read_raw_samples():
    files = sorted(RAW_DIR.glob("*.txt"))
    if not files:
        # 内置两条示例,避免“无数据就跑不起来
        return [
            "联系人:张三,联系电话:123456789,公司:江西省招标有限公司",
            "地址:南昌市东湖区,北京华为技术有限公司;联系人王五,电话:13800001234"
        ]
    samples = []
    for f in files:
        samples.append(f.read_text(encoding="utf-8"))
    return samples

if __name__ == "__main__":
    agent = DataCleaningAgent()
    samples = read_raw_samples()
    instruction = "请提取company(公司名称)、contact(联系人)、phone(电话)。返回JSON。"
    results = agent.batch_process(samples, instruction)
    # 写入两个文件,便于排查与复用
    with open(PROC_DIR / "cleaned.jsonl", "w", encoding="utf-8") as fw1, \
        open(PROC_DIR / "extracted.jsonl", "w", encoding="utf-8") as fw2:
        for r in results:
            fw1.write(json.dumps({"original": r["original"], "cleaned": r["cleaned"]},ensure_ascii=False) + "\n")
            fw2.write(json.dumps(r["extracted"], ensure_ascii=False) + "\n")
    print(f"已输出:{PROC_DIR/'cleaned.jsonl'} 与 {PROC_DIR/'extracted.jsonl'}")

激活python虚拟环境,进入DataAnalysis/src 目录下,执行python文件。

依次执行以下命令:

source myenv/bin/activate 

cd DataAnalysis/

cd src

python preprocess.py

执行成功后,在/home/developer/data/processed目录下生成cleaned.json1和extracted.json1文件,数据清理并提取json数据。

4.4 Text2SQL(自然语言 → SQL → 结果)

自然语言转换成SQL语句,使用SQL语句查询MySQL数据库,返回查询结果。

4.4.1 安装MySQL

更新系统软件包:

sudo yum update

sudo yum upgrade -y

安装MySQL服务器:

sudo yum install mysql-server -y

启动并设置开机自启:

sudo systemctl start mysqld

sudo systemctl enable mysqld

验证 MySQL 运行状态:

sudo systemctl status mysqld

显示 active (running) 则表示成功启动。

安装nano:

sudo yum install nano

先创建目录,再配置MySQL:

sudo mkdir -p /etc/mysql/mysql.conf.d

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
bind-address = 0.0.0.0 # 允许远程连接(生产环境建议注释或设置为服务器IP)
port = 3306
character-set-server = utf8mb4 # 字符集设置
collation-server = utf8mb4_unicode_ci
innodb_buffer_pool_size = 1G # 内存分配(根据服务器总内存调整)
max_connections = 200 # 最大连接数

按下Ctrl+x,再按下Y保存,最后按下Enter键,退出编辑状态。

重启MySQL:

sudo systemctl restart mysqld

使用root用户登录:

sudo mysql -u root

创建数据库和用户:

SELECT VERSION();
SHOW DATABASES;
CREATE DATABASE mydatabase CHARACTER SET utf8mb4;
CREATE USER '用户名'@'localhost' IDENTIFIED BY '密码';
GRANT ALL PRIVILEGES ON mydatabase.* TO '用户名'@'localhost';
FLUSH PRIVILEGES;
EXIT;

注意:用户名和密码要替换成您自己的。

数据库配置:

在DataAnalysis目录下.env文件中,添加数据库配置:

LLM_PROVIDER=ollama
LLM_HOST=http://localhost:11434
LLM_MODEL=deepseek-r1:1.5b

DB_URL=mysql+pymysql://用户名:密码@localhost:3306/mydatabase

注意:用户名和密码要替换成您自己的。

4.4.2 准备演示数据

在data目录下,创建sales.csv文件:

product_name,year,sales_amount,region
产品A,2023,15000000,华东
产品B,2023,12000000,华南
产品C,2023,11000000,华北
产品D,2022, 8000000,华东

4.4.3 代码:src/text2sql.py

text2sql.py:自然语言转换成SQL语句。

import os, sqlite3, pandas as pd, requests
from sqlalchemy import create_engine, text
from dotenv import load_dotenv
load_dotenv()

class SQLRunner:
    def __init__(self, db_url: str):
        self.engine = create_engine(db_url)
    def exec(self, sql: str) -> pd.DataFrame:
        with self.engine.connect() as conn:
            return pd.read_sql_query(text(sql), conn)
    def init_from_csv(self, csv_path: str, table_name: str = "sales"):
        df = pd.read_csv(csv_path)
        with self.engine.connect() as conn:
            df.to_sql(table_name, conn, if_exists="replace", index=False)

class NL2SQLAgent:
    def __init__(self, schema_hint: str = "", provider=None, host=None, model=None,api_key=None):
        self.schema_hint = schema_hint
        self.provider = provider or os.getenv("LLM_PROVIDER", "ollama")
        self.host = host or os.getenv("LLM_HOST", "http://localhost:11434")
        self.model = model or os.getenv("LLM_MODEL", "deepseek-r1:1.5b")
        self.api_key = api_key or os.getenv("LLM_API_KEY", "")

    def _ask(self, prompt: str) -> str:
        if self.provider == "ollama":
            r = requests.post(f"{self.host}/api/generate", json={"model": self.model, "prompt": prompt, "stream": False})
            r.raise_for_status()
            return r.json().get("response", "")
        else:
            # 以 DashScope 为例,其它厂商同理
            headers = {"Authorization": f"Bearer {self.api_key}","Content-Type": "application/json"}
            r = requests.post(f"{self.host}/chat/completions", headers=headers, json={"model": self.model, "messages":[{"role":"user","content":prompt}]})
            r.raise_for_status()
            return r.json()["choices"][0]["message"]["content"]

    def generate_sql(self, question: str) -> str:
        prompt = f"""你是SQL生成助手。根据以下数据库结构和问题,生成可在对应数据库上直接执行的SQL。

        只返回SQL,不要任何解释或注释。
        [数据库结构]{self.schema_hint}
        [问题]{question}
        """

        sql = self._ask(prompt).strip().strip("```").replace("sql", "")
        return sql
4.4.4 运行脚本:src/text2sql_demo.py

text2sql_demo.py:自然语言转换成SQL语句的执行类,输出转换后的SQL语句并操作MySQL数据库。

import os
import re
from pathlib import Path
from dotenv import load_dotenv
from text2sql import SQLRunner, NL2SQLAgent
load_dotenv()
ROOT = Path(__file__).resolve().parents[2]

if __name__ == "__main__":
    db_url = os.getenv("DB_URL", "mysql+pymysql://用户名:密码@localhost:3306/mydatabase")
    csv_path = ROOT / "data" / "sales.csv"
    # 1) 初始化数据库与示例表
    runner = SQLRunner(db_url)
    runner.init_from_csv(str(csv_path), table_name="sales")
    # 2) 提供 schema_hint(强烈建议绑定到你企业真实数据字典)
    schema = """CREATE TABLE sales (product_name TEXT,year INTEGER,sales_amount INTEGER,region TEXT);"""
    agent = NL2SQLAgent(schema_hint=schema)

    # 3) 自然语言问题
    q = "查找2023年所有销售额超过1000万的产品,并按销售额降序排列"
    sql = agent.generate_sql(q)

    # 使用 split() 方法分割字符串,以 "</think>" 为分隔符,并取最后一部分
    parts = sql.split("</think>")
    # 提取最后一部分并去除首尾空格
    real_sql = parts[-1].strip()
    print("生成的SQL:\n", real_sql.strip())

    # 4) 执行与结果
    df = runner.exec(real_sql.strip())
    print("\n查询结果:\n", df.to_string(index=False).strip())


注意:DB_URL中的用户名和密码要替换成您自己的用户名和密码。

安装cryptography库:

pip3 install cryptography -i https://repo.huaweicloud.com/repository/pypi/simple/

进入DataAnalysis/src 目录下,执行python文件。

依次执行以下命令:

cd DataAnalysis/

cd src

python text2sql_demo.py

生成了SQL语句,并根据SQL语句查询了数据库,返回了查询结果。

4.5 可视化智能体(Visualization Agent)

可视化智能体是一种能够分析数据、生成见解并通过可视化方式呈现结果的智能系统。结合 Pandas 进行数据处理和Matplotlib/Seaborn/Plotly 进行可视化,可以构建一个基础的智能体框架。也可以将DataFrame 交给大模型智能体,让它根据数据内容决定可视化方式,并自动生成图表代码(如用 matplotlib/ plotly / seaborn)。这种做法本质上就是构建一个 DataFrame 可视化智能体(Visualization Agent),它能够结合数据结构、字段含义与任务需求,为用户自动设计图表并呈现。具体实现逻辑很简单:DataFrame → LLM → 图表自动生成。

4.5.1 代码:src/viz.py

viz.py:数据分析与可视化。

import pandas as pd
import matplotlib.pyplot as plt

class VizAgent:

    def __init__(self, df: pd.DataFrame):
        self.df = df

    def bar(self, x: str, y: str, title: str = ""):
        plt.figure()
        self.df.plot(kind="bar", x=x, y=y, title=title)
        plt.savefig('bar1.png')

    def line(self, x: str, y: str, title: str = ""):
        plt.figure()
        self.df.plot(kind="line", x=x, y=y, marker="o", title=title)
        plt.savefig('line.png')


    def topk(self, y: str, k: int = 10):
        plt.figure()
        self.df.nlargest(k, y).plot(kind="bar", x=self.df.columns[0], y=y, title=f"Top-{k} by {y}")
        plt.savefig('bar2.png')

4.5.2 运行脚本:src/viz_demo.py

viz_demo:数据分析与可视化的执行类,调用viz.py中的方法,生成可视化图表。

import os
from dotenv import load_dotenv
from text2sql import SQLRunner
from viz import VizAgent

load_dotenv()
if __name__ == "__main__":
    db_url = os.getenv("DB_URL", "mysql+pymysql://用户名:密码@localhost:3306/mydatabase")
    runner = SQLRunner(db_url)

    # 直接查询或接前一节 NL2SQL 的 df
    df = runner.exec("SELECT product_name, sales_amount FROM sales WHERE year=2023 ORDER BY sales_amount DESC;")
    VizAgent(df).bar(x="product_name", y="sales_amount", title="2023 product sales bar chart")

注意:DB_URL中的用户名和密码要替换成您自己的用户名和密码。

进入DataAnalysis/src 目录下,执行python文件。

python viz_demo.py 

执行成功后,在src目录下生成bar1.png图片。

下载到本地打开:

至此,华为开发者空间云开发环境 x DeepSeek打造全链路高效数据分析工作流的案例已全部完成。

反馈改进建议

如您在案例实操过程中遇到问题或有改进建议,可以到论坛帖评论区反馈即可,我们会及时响应处理,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值