在上一篇《思路探索:当大型语言模型遇见数据分析的现实挑战》中,我们阐述了团队确立的技术路线:利用大型语言模型(LLM)作为自然语言到代码的“翻译器”,并结合Python Pandas库作为后端的高性能“计算核心”。本文将从工程实践的角度,详细拆解该方案的技术实现路径,分享我们如何从零开始,搭建一个稳定、高效且安全的混合式数据分析引擎。
一、 核心组件:本地Pandas API服务的构建
我们的架构基石是一个能够接收数据和代码、执行分析并返回结果的Web服务。为保证轻量化与开发效率,我们选择了Flask作为Web框架,并遵循标准的Python项目管理实践。
1.1 环境隔离:虚拟环境的建立
为避免依赖冲突并确保项目环境的纯净性,我们首先通过venv
模块创建了一个独立的Python虚拟环境。这是所有专业Python开发的标准起点。
# 在项目根目录创建名为venv的虚拟环境
python -m venv venv
# 激活虚拟环境 (Windows PowerShell)
.\venv\Scripts\activate
在激活状态下,所有后续的包安装都将被隔离在此环境中。
1.2 核心依赖安装
我们的API服务仅需两个核心库:Flask
用于构建Web服务,pandas
用于数据处理。
pip install Flask pandas
1.3 API接口设计与实现 (app.py
)
我们设计了一个单一的API端点/execute\_on\_data
,它通过POST方法接收JSON格式的请求体。该请求体包含两个关键字段:code
(由LLM生成的Pandas代码字符串)和csv\_data
(待分析的、CSV格式的完整数据字符串)。
以下是经过多轮迭代后,最终稳定运行的服务端核心代码结构:
from flask import Flask, request, jsonify
import pandas as pd
import io, json, traceback
app = Flask(\_\_name\_\_)
# 关键配置:确保返回的JSON响应能正确显示中文字符
app.json.ensure\_ascii = False
def parse\_and\_clean\_data(raw\_data\_string: str) -> pd.DataFrame:
# 此处省略了我们最终实现的、用于解析Dify传入的
# 多种不规范文本格式(如Markdown表格)的健壮解析函数。
# 其核心是手动进行字符串分割、清理和列名重塑,
# 而非依赖可能出错的pd.read\_csv高级功能。
# ...
# 最终目标是返回一个列名干净、数据正确的DataFrame
pass
@app.route('/execute\_on\_data', methods=['POST'])
def execute\_on\_data():
try:
data = request.get\_json()
code\_to\_execute = data['code']
raw\_data\_string = data['csv\_data']
# 1. 数据解析与清洗
df = parse\_and\_clean\_data(raw\_data\_string)
if df.empty:
return jsonify({"status": "error", "message": "解析后的DataFrame为空"}), 400
# 2. 动态代码执行
local\_vars = {'df': df, 'pd': pd}
exec(code\_to\_execute, globals(), local\_vars)
result = local\_vars.get('result')
# 3. 结果序列化
# to\_json确保了Pandas对象能被正确转换为JSON字符串
# orient='records'生成更易于前端处理的格式
# force\_ascii=False保证了Pandas层面的中文直出
final\_result = result.to\_json(orient='records', force\_ascii=False)
return jsonify({"status": "success", "result": final\_result})
except Exception as e:
# 在调试模式下,打印完整错误堆栈,方便快速定位问题
traceback.print\_exc()
return jsonify({"status": "error", "message": str(e)}), 500
if \_\_name\_\_ == '\_\_main\_\_':
# 启动服务,并开启调试模式
app.run(host='0.0.0.0', port=5000, debug=True)
通过python app.py
启动服务,一个本地计算中心便搭建完成。它不仅提供了计算能力,还通过精细的错误处理和调试模式,为后续的联调提供了极大的便利。
二、 Dify工作流编排:构建自动化的数据处理流水线
在Dify的可视化编排界面,我们将上述API服务作为核心节点,构建了一个端到端的数据分析工作流。
架构核心思想
将复杂任务分解,让每个组件专注于其最擅长的部分。LLM负责语言理解与代码生成,本地API负责数据安全与精确计算。
2.1 流水线节点设计
- 开始节点
配置两个输入变量,一个
File
类型用于用户上传Excel文件,一个
String
类型用于用户输入自然语言分析请求。
- HTTP请求节点 (数据预处理)
此节点调用Dify内置的文件预览API (
/v1/files/preview
),将用户上传的Excel文件转换为CSV格式的文本,并仅截取前10行作为数据样本。这一步是实现“让模型看样本,让代码处理全体”的关键。
- 大型语言模型节点 (代码生成)
此节点是“翻译官”。它接收上一步生成的
数据样本
和用户的
分析请求
,通过一个高度优化的提示词(Prompt)模板,生成纯净、可执行的Pandas代码。
关键Prompt策略 :在规则中以强制性语气指令模型“必须且只能输出纯粹的Python代码,严禁使用任何Markdown标记”,这是确保后端exec()
函数能成功执行的前提。
- HTTP请求节点 (核心计算)
此节点调用我们本地部署的Pandas API。其请求体(Body)中动态地包含了上一个LLM节点生成的
code
,以及“开始”节点上传的
完整文件内容
csv\_data
。
关键网络配置 :当Dify与API服务都通过Docker本地部署时,访问URL需使用Docker内部DNS名称http://host.docker.internal:5000
,而非localhost
,以实现容器间的正确通信。
- 大型语言模型节点 (报告生成)
接收本地API返回的、经过精确计算的JSON格式结果,并根据用户的原始问题,将其组织、解读为一段通俗易懂的分析报告。
三、 关键技术决策与最终成果
在整个实践过程中,我们做出了一些关键的技术决策,这些决策最终保证了系统的稳定性和健壮性:
- 数据处理的归属
坚持将海量原始数据的解析和计算任务保留在本地Python环境中,仅将少量、脱敏的样本数据传递给LLM。这在保障数据安全的同时,也极大地降低了LLM的调用成本和响应延迟。
- API的健壮性设计
在本地API中编写了强大的数据清洗与格式化函数,使其能够容忍Dify端传入的、可能不完全规范的文本数据,从而避免了因上游微小变化导致的后端服务崩溃。
- 调试与日志
在开发阶段,充分利用Flask的
debug=True
模式和
traceback
模块,使得我们能够快速定位到诸如
KeyError
、数据格式不匹配等深层次问题,极大地加速了开发迭代周期。
最终,我们成功构建了一个闭环的、自动化的数据分析系统。用户只需通过自然语言交互,即可在数秒内获得对大型Excel文件的深度分析结果。这套架构不仅验证了我们最初的技术设想,也为未来集成更复杂的数据源(如数据库)和更高级的分析模型(如机器学习)打下了坚实的基础。
希望这份详尽的实践分享,能为正在探索LLM应用边界的同行者们提供一份可供参考的技术蓝图。我们相信,通过将LLM的语言能力与专业工具的计算能力进行创造性地结合,将是未来智能应用发展的核心趋势之一。觉得好,请帮忙点赞在看,也可以留言讨论!