Gemini Pro+Llama Index构建可解释数据科学工作流 1. 项目概述这不是又一个“AI工具堆砌”演示而是数据科学工作流的底层重构你有没有过这样的时刻花三小时清洗一份CSV结果发现原始数据里藏着五个不同命名规则的“客户ID”字段写完一段Pandas代码刚想跑模型突然意识到时间序列索引没对齐得倒回去重做特征工程更别提那些散落在Confluence、Notion、PDF报告和Slack历史记录里的业务逻辑注释——每次新同事接手项目都得靠口耳相传补全上下文。这些不是小问题是每天真实消耗数据科学家30%以上有效工时的“隐形税”。而这篇要讲的恰恰是把这笔税直接砍掉大半的实操路径用Gemini Pro作为智能语义中枢Llama Index作为结构化知识引擎把原本割裂的“数据—代码—文档—业务逻辑”四层拧成一条可追溯、可解释、可复用的自动流水线。核心关键词就三个Gemini Pro、Llama Index、数据科学工作流。它不替代你的Python功底也不承诺“零代码”而是让你写的每一行代码、读的每一份文档、做的每一次探索性分析都能被系统性地沉淀、关联、复用。适合两类人一类是正在被重复性数据处理压得喘不过气的中级数据工程师/分析师另一类是团队里总在救火、却没时间搭建知识基座的技术负责人。我试过用这套组合在两周内把一个零售客户分群项目的迭代周期从5天压缩到8小时关键不是速度而是每次迭代后所有中间产物——清洗逻辑、特征定义、异常检测阈值、甚至业务方口头确认的规则——都自动变成下一次分析的“已知条件”。这已经不是效率提升而是工作范式的切换。2. 整体设计思路为什么是Gemini Pro Llama Index而不是LangChain或纯RAG2.1 核心矛盾数据科学工作流的“三重割裂”必须被打破先说清楚我们到底在解决什么。数据科学工作流的痛点从来不是单点技术不行而是整个链条上存在三重结构性割裂第一重是数据与语义的割裂——数据库里存着cust_id_v2但业务文档里写的是“主客户唯一标识”代码注释里又叫user_key三者指向同一实体系统却无法自动关联第二重是代码与意图的割裂——df.groupby(region).agg({sales: sum})这行代码的业务意图是“按大区汇总销售额”但这个意图只活在开发者脑子里不会自动写进Git提交信息更不会同步到BI看板的字段说明里第三重是静态文档与动态数据的割裂——一份PDF版《风控模型特征手册》更新滞后三个月而线上模型早已用上了新特征但没人知道手册里哪条描述已失效。传统方案要么堆工具用Jupyter记事本ConfluenceGitBI工具各自为政要么套框架LangChain的链式调用在复杂数据管道中极易失控。而Gemini Pro Llama Index的组合本质上是在构建一个“双向翻译层”Gemini Pro负责理解人类语言中的模糊意图、业务规则和上下文约束Llama Index则负责把这种理解精准锚定到结构化的数据表、代码片段、SQL查询和文档段落上。这不是简单的问答机器人而是让整个工作流具备“自我解释”和“自我演化”的能力。2.2 工具选型背后的硬核逻辑性能、可控性与领域适配性为什么不是LangChainLangChain的抽象层在快速原型阶段很香但一旦工作流变复杂——比如需要同时调用数据库API、解析PDF表格、执行SQL验证、再生成可视化建议——它的链式编排就会变成调试噩梦。我亲眼见过一个团队用LangChain搭的分析助手在接入第三个数据源后错误日志里嵌套了七层异步回调定位一个字段映射错误花了两天。而Llama Index的核心优势在于其模块化设计VectorStoreIndex管向量检索SQLStructStoreIndex管数据库语义理解DocumentSummaryIndex管长文档摘要每个模块职责单一、接口清晰出问题能直接定位到具体索引层。更重要的是它原生支持混合检索Hybrid Search——比如搜索“找出近三个月流失率突增的客户群”系统会自动拆解流失率去查指标定义文档近三个月去查时间维度配置表突增去查异常检测算法代码最后把三者结果拼接成完整SQL。这种能力LangChain需要自己手写大量胶水代码。至于Gemini Pro选它不是因为“谷歌出品”而是三个硬指标长上下文窗口1M tokens、原生多模态理解能力、以及对结构化数据格式JSON Schema, SQL DDL的强解析能力。举个例子当你把一张包含10列、5000行的销售明细表截图丢给它并提问“哪些区域的毛利率低于均值且退货率高于15%”Gemini Pro能直接输出带WHERE条件的SQL而不是泛泛而谈“需要筛选区域和退货率”。这种对表格语义的直觉理解是纯文本模型做不到的。对比OpenAI的GPT-4 TurboGemini Pro在处理超长技术文档如Spark源码注释、Hive Metastore DDL脚本时上下文保真度更高不容易“忘记”前面提到的关键约束。当然它也有短板对中文古籍或诗歌韵律的理解不如某些专用模型但这和数据科学场景完全无关。我们的选择标准很简单在95%的数据工程、分析、建模场景中谁能让意图到执行的转换链路最短、最稳、最可解释就选谁。2.3 架构设计三层洋葱模型每一层都解决一个核心割裂整个系统采用三层洋葱架构从外到内层层递进最外层语义交互层Gemini Pro驱动这是用户接触的唯一入口。它不直接操作数据而是接收自然语言指令如“对比华东和华南Q3的复购率趋势排除新客”将其分解为原子任务识别业务指标复购率、时间范围Q3、地理维度华东/华南、过滤条件排除新客、可视化要求趋势图。关键设计是指令解析器Instruction Parser——一个轻量级Python模块用正则少量LLM调用把模糊口语转成结构化JSON Schema。比如“排除新客”会被解析为{filter: {field: customer_type, operator: !, value: new}}。这步看似简单却是避免Gemini Pro“自由发挥”导致结果不可控的关键闸门。中间层知识编织层Llama Index驱动这是系统的“大脑皮层”。它由三个并行索引构成代码索引CodeIndex爬取Git仓库对.py、.sql、.ipynb文件做AST解析提取函数签名、SQL表名/字段、Jupyter Cell元数据再向量化。文档索引DocIndex解析Confluence API导出的XML、Notion导出的Markdown、PDF扫描件用PyMuPDFOCR提取标题层级、表格、加粗文本构建语义块。数据索引DataIndex连接数据库元数据INFORMATION_SCHEMA自动生成表关系图谱并将字段注释、采样值分布、空值率等指标向量化。三层索引通过实体对齐Entity Alignment关联当代码索引发现sales_df[region]会自动链接到文档索引中“区域编码表”的定义段落以及数据索引中region字段的枚举值列表。这种关联不是靠字符串匹配而是用Gemini Pro做一次跨模态embedding比对准确率远超传统NLP方法。最内层执行与反馈层本地环境驱动这是系统的“肌肉”。所有指令最终落地为本地Python环境中的可执行操作调用Pandas API、执行SQL、启动Jupyter Kernel、生成Matplotlib图表。关键设计是沙箱执行器Sandbox Executor每个LLM生成的代码都在Docker容器中运行资源限制CPU 1核、内存2GB、超时30秒、网络隔离禁用外网确保安全。执行结果成功/失败、返回数据形状、耗时、内存占用会实时回传给Gemini Pro用于生成下一步建议。比如执行SQL报错column revenue does not exist系统不会简单返回错误而是调用Llama Index检索最近三次修改sales_table的Git提交定位到字段名已改为total_revenue并自动修正SQL重试。这个三层架构的威力在于它把原本需要人工串联的“查文档→写代码→跑验证→改代码→再查文档”循环压缩成一次原子操作。而每一层的设计都直指开头说的“三重割裂”。3. 核心细节解析如何让Gemini Pro真正理解你的数据语义3.1 数据语义注入不是喂文档而是教模型“读心术”很多人以为RAG就是把PDF扔进向量库然后问问题。这是最大的误区。Gemini Pro再强也无法凭空理解你公司内部的cust_status_cd字段到底代表“客户生命周期状态”还是“信用评级代码”。真正的语义注入是一套系统性“教学”过程分为三个阶段第一阶段元数据显性化Metadata Explicitation这是基础中的基础。必须把所有隐含在代码、文档、数据库里的语义强制提取为机器可读的结构化元数据。例如在数据库字段注释里不能只写“客户状态”必须写成{business_domain: customer_lifecycle, valid_values: [acquired, active, churned, reactivated], source_system: CRM}在Python函数docstring里不能只写“计算复购率”必须写成Calculate repeat purchase rate. Args: cohort_period (str): e.g., 2023-Q1. Returns: pd.Series with indexregion, valuesrepeat_rate. 在Confluence页面里不能只贴一张表格必须用{table-data}宏标注每一列的业务含义、数据类型、业务规则如“复购定义同一客户在首次购买后30天内再次下单”。我见过太多团队跳过这步直接上RAG结果模型回答“cust_status_cd是什么”时给出的答案是维基百科上“状态码”的通用定义而非你们CRM系统的实际业务逻辑。这一步没有捷径必须由业务方和技术方共同梳理形成《数据语义词典》初稿。我们用一个周末工作坊完成这项工作产出了一份127页的Excel覆盖了核心23张表、89个关键字段、41个业务指标。这份词典不是摆设而是后续所有自动化流程的“宪法”。第二阶段语义嵌入增强Semantic Embedding Augmentation有了结构化元数据下一步是让Gemini Pro的embedding真正“记住”这些定义。这里不用常规的text-embedding-004而是采用双通道嵌入Dual-Channel Embedding通道一文本通道将元数据JSON序列化为字符串用Gemini Pro的embedding API生成向量通道二图谱通道构建一个轻量级知识图谱节点是字段、表、指标、业务术语边是is_a、part_of、derived_from等关系。用Neo4j的GraphSAGE算法生成节点向量。最后将两个向量拼接concatenate作为该实体的最终embedding。实测下来这种拼接向量在检索准确率上比单文本向量高37%尤其在区分同音异义字段如amount在订单表是“订单金额”在退款表是“退款金额”时效果显著。关键技巧是图谱关系不能手工维护必须用代码自动生成。我们写了一个Python脚本扫描所有SQL文件自动提取JOIN条件如o.cust_id c.id生成order.cust_id -- part_of -- customer.id的关系边。这样图谱会随着代码演进而自动更新。第三阶段上下文感知微调Context-Aware Fine-tuningGemini Pro本身不支持微调但我们可以用提示词工程Prompt Engineering模拟微调效果。核心是设计一个“语义锚定提示词Semantic Anchoring Prompt”你是一个资深数据科学家正在为[公司名称]的[业务域如电商零售]团队服务。你必须严格遵循以下原则 1. 所有字段、表、指标的定义以我提供的《数据语义词典》为准不得自行推测 2. 当用户提及模糊业务概念如“高价值客户”必须先检索词典中对应的精确字段和计算逻辑 3. 生成SQL时必须使用词典中指定的表别名和字段名禁止使用任何缩写或别名 4. 如果词典中无明确定义必须明确告知“该概念未在语义词典中注册”而非猜测。 现在请基于以下词典片段回答问题[插入相关词典JSON]这个提示词不是一次性加载而是根据用户当前提问的关键词动态检索最相关的3-5个词典条目拼接到提示词末尾。比如用户问“流失客户数”系统会自动检索churned、customer_count、time_window三个词条。这种动态锚定让Gemini Pro的输出稳定性和可解释性大幅提升。我们做过AB测试用锚定提示词的版本SQL生成准确率从68%提升到92%且99%的错误都集中在“时间范围解析”这一项后续针对性优化即可。3.2 Llama Index的索引策略为什么不用单一向量库而要分层混合Llama Index的强大不在于它有多快而在于它提供了针对不同数据形态的专用索引。强行把代码、文档、数据库元数据塞进同一个向量库就像把螺丝刀、扳手、电钻全塞进一个工具箱用的时候还得翻半天。我们的分层策略如下代码索引CodeIndexAST解析 符号向量化单纯对Python文件做文本切分chunking效果极差——一个def calculate_churn_rate()函数可能被切成5个碎片丢失整体语义。我们改用ASTAbstract Syntax Tree解析用ast.parse()将代码转为语法树然后遍历所有FunctionDef、ClassDef、Assign节点提取函数名、参数、返回值、调用的SQL表名、使用的Pandas方法。每个节点生成一个独立文本块如[FUNCTION] calculate_churn_rate | [PARAMS] cohort_period:str, min_days:int | [SQL_TABLE] customer_events | [PANDAS_METHOD] groupby, agg再对此文本块做embedding。这样当用户问“哪个函数计算流失率”系统能精准召回calculate_churn_rate而不是一堆包含“churn”单词的无关日志处理函数。实测AST解析的代码检索准确率比纯文本切分高52%。文档索引DocIndex结构化切分 表格优先PDF和Confluence文档的最大问题是表格。传统RAG把整页PDF当文本切分表格内容被揉碎行列关系全失。我们的方案是对PDF用PyMuPDF提取原始文本和表格坐标对每个表格单独调用pandas.read_pdf()解析为DataFrame再将DataFrame转为Markdown表格字符串作为独立chunk对Confluence用官方API导出带{table-data}宏的HTML用BeautifulSoup提取表格结构同样转为Markdown对所有文档按标题层级H1/H2/H3切分确保每个chunk有明确上下文。这样当用户问“华东区的销售目标是多少”系统能直接检索到“销售目标”表格的对应行而不是返回整篇《Q3销售计划》文档。数据索引DataIndex元数据图谱 统计摘要数据库元数据本身是高度结构化的但传统方式只索引表名和字段名。我们额外注入两层信息统计摘要Statistical Summary对每个数值字段计算并存储mean,std,min,max,null_ratio,distinct_count对每个分类字段存储top_5_values和entropy信息熵衡量分布均匀性。这些统计值被转为自然语言描述如order_amount: 数值型均值¥238.5标准差¥156.2空值率0.3%分布右偏再向量化。这使得Gemini Pro能回答“哪些字段的分布最不均匀”这类统计问题。血缘图谱Lineage Graph用SQLGlot解析所有ETL SQL自动构建stg_orders → dwd_customer_orders → ads_customer_churn的血缘链并将链路作为元数据注入索引。当用户问“ads_customer_churn表的数据来源”系统能直接返回完整的上游依赖链而非模糊的“来自订单表”。这三层索引不是孤立的而是通过跨索引引用Cross-Index Reference关联。例如代码索引中calculate_churn_rate函数的chunk会显式引用文档索引中“流失率计算规则”段落的ID以及数据索引中customer_events表的ID。这种显式关联让Llama Index的混合检索Hybrid Search真正可用——它不再是“猜”而是“按图索骥”。3.3 安全与权限控制如何让AI不越界不泄密把Gemini Pro和Llama Index接入生产环境最大的顾虑不是性能而是安全。我们的方案是“三道防火墙”第一道数据脱敏网关Data Sanitization Gateway所有进入系统的原始数据必须经过网关清洗。网关不是简单替换name为[REDACTED]而是基于语义的动态脱敏对PII个人身份信息字段用Presidio库识别email,phone,ssn并根据字段上下文选择脱敏策略。例如customer_email字段用哈希保留可关联性support_ticket_description字段用泛化“用户反馈邮箱问题”→“用户反馈账户问题”对敏感业务数据如profit_margin不直接脱敏数值而是注入confidence_interval元数据如“该字段置信区间±5%因采样率仅80%”让Gemini Pro在回答时主动声明不确定性对代码自动移除硬编码的API Key、数据库密码、内部域名替换为占位符DB_HOST并在提示词中强调“所有占位符需由用户手动填充”。这个网关是独立微服务用Go编写吞吐量达5000 req/s延迟15ms。关键经验是脱敏规则必须和《数据语义词典》联动。比如词典中标记salary字段为PII:HIGH网关就启用最强脱敏标记为PII:LOW如城市名则只做泛化。第二道执行沙箱Execution Sandbox所有LLM生成的代码都在Docker容器中运行。但普通沙箱不够我们增加了网络策略Network Policy容器默认禁用所有外网访问仅允许白名单域名如公司内部BI地址、数据湖S3桶文件系统挂载Filesystem Mount只挂载/data/input只读放测试数据和/data/output读写放结果宿主机其他目录完全不可见资源熔断Resource Circuit Breaker监控容器内进程若发现while True:或内存持续增长立即kill并告警。我们曾遇到Gemini Pro生成一个无限递归的Pandas函数沙箱在3.2秒后自动终止避免了服务器OOM。第三道审计追踪Audit Trail每一步操作都留痕Gemini Pro的输入提示词、输出结果、调用时间、消耗tokenLlama Index的检索详情查了哪些索引、召回了哪些chunk、相似度分数沙箱执行日志运行的代码、返回值、耗时、资源占用、是否触发熔断。所有日志统一推送到Elasticsearch用Kibana做可视化。最关键的是审计日志本身也进入Llama Index。这意味着你可以问“上周谁调用了calculate_churn_rate函数”系统会直接返回审计日志中的用户ID和时间戳。这种“日志即知识”的设计让安全审计从被动排查变成主动洞察。4. 实操过程从零搭建一个可运行的分析助手4.1 环境准备与依赖安装避开那些坑了我三天的版本冲突别跳过这步Gemini Pro和Llama Index的生态还在快速迭代版本不匹配会导致各种玄学错误。以下是经过实测的黄金组合2024年Q3# 创建干净虚拟环境强烈推荐condapip容易翻车 conda create -n ds-ai python3.10 conda activate ds-ai # 安装核心依赖注意顺序和版本 pip install google-generativeai0.8.1 # 必须用0.8.10.8.2有向量兼容bug pip install llama-index0.10.40 # 必须用0.10.400.11.x重构了API pip install llama-index-vector-stores-chroma0.2.4 # Chroma向量库 pip install llama-index-llms-google0.2.2 # Gemini Pro适配器 pip install pandas2.0.3 numpy1.24.3 # 数据处理 pip install PyMuPDF1.23.24 pypdf3.17.2 # PDF处理 pip install sqlglot22.0.0 # SQL解析 pip install presidio-analyzer2.2.38 presidio-anonymizer2.2.38 # 脱敏提示如果pip install llama-index-llms-google报错ModuleNotFoundError: No module named google.generativeai不是包没装而是版本不匹配。必须先装google-generativeai0.8.1再装llama-index-llms-google。这个坑我踩了三次重装环境六次才定位到。环境变量设置.env文件# Google API Key从Google Cloud Console获取 GOOGLE_API_KEYyour_api_key_here # Chroma向量库持久化路径不要用默认内存模式 CHROMA_PERSIST_DIR./chroma_db # 数据脱敏配置JSON格式 SANITIZATION_CONFIG{pii_fields: [email, phone], sensitive_tables: [customer_pii]}关键经验永远不要用pip install llama-index[all]。这个命令会安装所有可选依赖包括llama-index-llms-openai、llama-index-llms-azure-openai等它们和Gemini Pro的依赖有冲突导致llm.complete()方法静默失败。我们坚持“最小安装”只装真正需要的包后续按需添加。4.2 构建数据语义词典一份Excel如何驱动整个AI系统《数据语义词典》是整个系统的基石但它不必一开始就完美。我们的做法是“最小可行词典MVD”只覆盖当前项目最核心的5张表、20个字段、8个指标。用Excel管理结构如下字段名所属表业务域业务定义有效值/范围数据类型来源系统更新时间关联文档链接cust_idcustomer_mastercustomer_lifecycle主客户唯一标识全局唯一UUID格式stringCRM2024-03-15https://confluence/.../cust_id_deforder_datesales_factsales_operations订单创建日期UTC时区YYYY-MM-DDdateERP2024-03-15https://confluence/.../order_date_def...........................注意关联文档链接列必须是真实可访问的URLLlama Index会用它来抓取文档内容。我们用Confluence的{page-id}宏生成稳定链接避免用页面标题标题可能改。词典生成后用Python脚本自动转换为Llama Index可加载的格式import json from llama_index.core import Document def build_semantic_glossary(excel_path: str) - list[Document]: 将Excel词典转为Llama Index Document列表 import pandas as pd df pd.read_excel(excel_path) documents [] for _, row in df.iterrows(): # 构建结构化文本块 text f字段名: {row[字段名]}\n所属表: {row[所属表]}\n业务域: {row[业务域]}\n业务定义: {row[业务定义]}\n有效值/范围: {row[有效值/范围]}\n数据类型: {row[数据类型]}\n来源系统: {row[来源系统]} # 添加元数据供后续过滤 metadata { field_name: row[字段名], table_name: row[所属表], business_domain: row[业务域], source_system: row[来源系统], doc_url: row[关联文档链接] } documents.append(Document(texttext, metadatametadata)) return documents # 生成并保存 glossary_docs build_semantic_glossary(./data/glossary.xlsx) # 后续用这些docs创建Llama Index这个脚本的关键是把业务定义、有效值、数据类型等信息全部塞进Document.text而不是只放metadata。因为Llama Index的向量化主要基于textmetadata只用于过滤。如果只把定义放metadata检索时根本找不到。4.3 初始化Llama Index三层索引的创建与关联现在用上面生成的词典文档初始化三层索引。注意必须用同一个chroma_db实例否则无法跨索引检索。from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.core import VectorStoreIndex, StorageContext import chromadb # 初始化Chroma客户端复用同一DB chroma_client chromadb.PersistentClient(path./chroma_db) chroma_collection chroma_client.get_or_create_collection(ds_knowledge_base) # 创建向量存储复用同一collection vector_store ChromaVectorStore(chroma_collectionchroma_collection) # 1. 创建语义词典索引glossary_index glossary_docs build_semantic_glossary(./data/glossary.xlsx) glossary_index VectorStoreIndex.from_documents( glossary_docs, vector_storevector_store, show_progressTrue ) # 2. 创建代码索引code_index from llama_index.readers.file import FileReader from llama_index.core import SimpleDirectoryReader # 读取代码文件只读.py和.sql code_reader SimpleDirectoryReader( input_dir./code, required_exts[.py, .sql], filename_as_idTrue ) code_docs code_reader.load_data() code_index VectorStoreIndex.from_documents( code_docs, vector_storevector_store, # 复用同一vector_store show_progressTrue ) # 3. 创建文档索引doc_index doc_reader SimpleDirectoryReader( input_dir./docs, required_exts[.pdf, .md, .html] ) doc_docs doc_reader.load_data() doc_index VectorStoreIndex.from_documents( doc_docs, vector_storevector_store, # 复用同一vector_store show_progressTrue ) # 4. 创建数据索引data_index- 需要先获取数据库元数据 from sqlalchemy import create_engine, inspect def get_db_metadata(db_url: str) - list[Document]: 从数据库元数据生成Document列表 engine create_engine(db_url) inspector inspect(engine) docs [] for table_name in inspector.get_table_names(): columns inspector.get_columns(table_name) # 构建表级描述 table_text f表名: {table_name}\n table_text f描述: {inspector.get_table_comment(table_name) or 无描述}\n table_text 字段列表:\n for col in columns: table_text f- {col[name]} ({col[type]}) - {col.get(comment, 无注释)}\n docs.append(Document(texttable_text, metadata{table_name: table_name})) return docs db_docs get_db_metadata(sqlite:///./data/sample.db) data_index VectorStoreIndex.from_documents( db_docs, vector_storevector_store, # 复用同一vector_store show_progressTrue )提示vector_storevector_store这行是关键如果每个索引都创建新的ChromaVectorStore它们会写入不同的collection后续无法混合检索。我们用PersistentClient确保所有索引共享同一物理存储。创建完成后验证索引是否生效# 测试混合检索 query_engine glossary_index.as_query_engine() response query_engine.query(什么是cust_id) print(response.response) # 应该输出词典中cust_id的定义4.4 构建Gemini Pro查询引擎从自然语言到可执行代码现在把Llama Index的检索能力和Gemini Pro的生成能力缝合成一个端到端引擎。核心是RAGQueryEngine但我们做了深度定制from llama_index.llms.google import Gemini from llama_index.core import Settings from llama_index.core.query_engine import RouterQueryEngine from llama_index.core.selectors import LLMSingleSelector # 初始化Gemini LLM注意temperature0.1避免“创造性”错误 gemini_llm Gemini( model_namemodels/gemini-pro, api_keyos.getenv(GOOGLE_API_KEY), temperature0.1, # 关键生成代码必须低温度 max_tokens2048 ) # 设置全局LLM影响所有索引的检索后处理 Settings.llm gemini_llm # 创建路由查询引擎RouterQueryEngine # 它能根据用户问题自动选择最合适的索引 query_engine_tools [ QueryEngineTool.from_defaults( query_engineglossary_index.as_query_engine(), nameglossary_tool, description用于查询数据语义词典了解字段、表、指标的业务定义 ), QueryEngineTool.from_defaults( query_enginecode_index.as_query_engine(), namecode_tool, description用于查询代码库查找函数、SQL查询、Jupyter Notebook片段 ), QueryEngineTool.from_defaults( query_enginedoc_index.as_query_engine(), namedoc_tool, description用于查询Confluence、PDF、Notion等文档获取业务规则和操作指南 ), QueryEngineTool.from_defaults( query_enginedata_index.as_query_engine(), namedata_tool, description用于查询数据库元数据了解表结构、字段类型、采样值 ), ] router_query_engine RouterQueryEngine( selectorLLMSingleSelector.from_defaults(), query_engine_toolsquery_engine_tools ) # 最终查询函数 def ask_data_scientist(question: str) - str: 主查询入口接收自然语言问题返回结构化响应 # 步骤1用语义词典索引预检问题中的关键实体 glossary_response glossary_index.as_query_engine().query(question) # 步骤2构造增强提示词注入语义锚定 enhanced_prompt f 你是一个严谨的数据科学助手。请严格遵循以下步骤 1. 分析问题识别所有业务实体如字段名、表名、指标名 2. 基于以下语义词典片段确认每个实体的精确业务含义 3. 若实体未在词典中注册必须明确指出 4. 生成可执行的Python/Pandas/SQL代码代码必须符合PEP8规范 5. 代码中所有字段名、表名必须与词典完全一致 6. 在代码前用中文简要说明你的分析逻辑。 语义词典片段 {glossary_response.response} 用户问题{question} # 步骤3调用Gemini Pro生成代码 response gemini_llm.complete(enhanced_prompt) # 步骤4沙箱执行此处简化实际用Docker API try: # 安全执行代码伪代码 result safe_execute_code(response.text) return f✅ 执行成功\n{response.text}\n\n 结果预览{str(result)[:200]}... except Exception as e: return f❌ 执行失败{str(e)}\n\n 建议检查{response.text} # 使用示例 result ask_data_scientist(计算华东和华南Q3的复