
1. 项目概述当BI遇见AI从“看”数据到“问”数据最近在捣鼓一个叫“AI BI Helper”的玩意儿说白了就是想给传统的商业智能BI工具装上一个“AI大脑”。传统BI很强报表、仪表盘、下钻分析能把数据可视化做得明明白白。但它的交互方式本质上还是“人找数据”——你得知道要什么指标然后去设计查询、拖拽字段、生成图表。如果业务人员突然冒出一个模糊的、复杂的问题比如“上个月华东区哪个产品的客户满意度波动最大可能是什么原因”传统BI就有点力不从心了往往需要分析师写一堆SQL或者构建复杂的模型。“AI BI Helper”想做的就是把这个过程反过来变成“数据找人”或者说“数据回答人”。用户可以用最自然的语言提问系统理解问题后自动从海量数据中找出相关信息组织成结构化的答案甚至直接生成洞察图表。要实现这个愿景核心挑战之一就是让机器理解“问题”和“数据”之间的语义关联。这就引出了我们今天的主题文本向量与Milvus向量数据库的集成。简单来说我们要把用户的问题和数据库里的各种数据描述比如表名、字段名、业务指标注释、历史分析报告片段都转换成数学上的“向量”一串有意义的数字然后通过计算向量之间的“距离”相似度快速找到与当前问题最相关的数据线索。这就像是给所有数据贴上了语义“指纹”检索时不再依赖精确的关键词匹配而是进行“意译”搜索。2. 核心需求解析为什么是向量检索在深入代码之前我们必须先想清楚为什么传统的BI查询方式在这里不够用为什么非得用向量检索2.1 传统BI查询的局限性传统BI的数据查询无论是通过SQL还是可视化拖拽都严重依赖于精确的模式匹配。这带来了几个典型痛点词汇鸿沟用户说“营收”数据库字段可能叫“revenue”、“income”、“销售额”。除非建立完善的同义词库否则系统无法知道它们是同一个意思。语境缺失问题“本月业绩表现如何”中的“业绩”可能指销售额也可能指利润、订单量或用户增长。传统查询无法理解这种模糊性需要人工澄清。复杂意图解析像“找出贡献了80%利润的那20%客户”这类问题背后涉及帕累托分析。用户不可能直接写出对应的SQL需要分析师将自然语言意图“翻译”成复杂的查询逻辑。非结构化数据利用不足BI系统中除了结构化数据表往往还有大量的文本资产市场报告、用户反馈、会议纪要、指标注释。这些数据蕴含丰富语义但传统方法难以将其与结构化查询关联。2.2 向量语义检索的优势向量检索通过语义嵌入Embedding技术将文本映射到高维向量空间。在这个空间里语义相近的文本其向量在空间中的位置也接近。这带来了根本性的改变语义相似性匹配搜索“营收”也能找到“销售额”、“收入”相关的数据源因为它们对应的向量距离很近。意图理解系统通过计算问题向量与各种数据元信息表描述、字段注释向量的相似度来“猜测”用户可能想查询哪些数据实体即使表述方式不同。多模态检索基础向量是一种统一的数据表示。未来不仅可以处理文本问题还可以将图表、图像也嵌入到同一空间实现“用图搜图”、“用文搜图”等更高级的BI交互。因此为AI BI Helper构建一个高效、可靠的向量检索后端是实现智能问答的第一步。而Milvus正是专为海量向量数据管理而生的数据库。3. 技术选型为什么选择Milvus市面上能做向量检索的工具不少比如直接用PostgreSQL的pgvector插件或者Elasticsearch的密集向量功能。我们选择Milvus是基于以下几个针对AI BI Helper场景的考量3.1 Milvus的核心特性与优势专为向量设计性能极致Milvus从底层架构就是为向量操作优化的。它内置了多种近似最近邻ANN搜索算法如IVF_FLAT、HNSW、SCANN并支持GPU加速。对于BI场景数据量可能从百万到十亿级查询延迟要求高最好在百毫秒内Milvus的专门优化至关重要。海量向量管理Milvus采用存储计算分离架构能轻松横向扩展。BI系统的数据资产会随时间不断增长Milvus可以方便地通过增加节点来应对数据量和并发查询的增长。丰富的索引与距离度量支持L2、内积IP、余弦相似度Cosine等多种距离度量方式。对于文本向量我们通常使用余弦相似度来衡量语义相关性。Milvus允许在创建索引时指定距离类型查询时自动计算非常方便。数据持久化与高可用作为数据库Milvus提供了可靠的数据持久化机制依托对象存储和元数据数据库以及容灾方案这是很多单纯的向量检索库如FAISS所不具备的对于生产环境的BI系统是必须的。多语言SDK与活跃生态Milvus提供了Python、Java、Go、Node.js等主流语言的SDK集成方便。社区活跃遇到问题容易找到解决方案。3.2 与其他方案的对比vs pgvectorpgvector的优势是与PostgreSQL生态无缝集成如果你的结构化数据就在PostgreSQL里且向量数据量不大千万以下查询QPS不高pgvector是简单可行的选择。但对于追求极致向量检索性能、需要处理更大数据量、未来可能需要独立扩展向量服务的场景Milvus是更专业的工具。vs ElasticsearchES的强项在于全文检索和复杂的过滤聚合。其向量功能是作为插件存在的在纯向量相似度搜索的效率和性能上通常不如Milvus。我们的核心需求是语义搜索Milvus更对症下药。注意技术选型没有绝对的对错只有适合与否。对于AI BI Helper我们预见到未来需要处理海量的数据实体表、字段、报表、文档片段向量且对查询响应速度有较高要求因此选择了专精于此的Milvus。4. 环境准备与Milvus部署工欲善其事必先利其器。第一步是把Milvus运行起来。这里我强烈推荐使用Docker Compose进行部署这是最快、最不容易出错的方式特别适合开发和测试环境。4.1 部署架构简述一个最小化的Milvus集群通常包含四个组件Milvus Node提供向量检索服务的主体。etcd用于服务发现和元数据存储。MinIO用于存储向量索引文件和数据段Milvus默认的对象存储。MySQL用于存储集合Collection、分区Partition、字段模式Schema等元数据生产环境建议换为PostgreSQL。Docker Compose会把这四个服务编排起来一键启动。4.2 详细部署步骤安装前提确保你的机器上已经安装了Docker和Docker Compose。下载配置文件# 创建一个项目目录 mkdir ai-bi-helper cd ai-bi-helper # 下载最新的docker-compose.yml文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -O docker-compose.yml这里以v2.4.0为例你可以去Milvus的GitHub Release页面获取最新版本。启动Milvussudo docker-compose up -d执行后Docker会拉取镜像并启动所有服务。你可以用docker-compose ps查看服务状态直到所有容器都显示为“Up”。验证安装检查端口Milvus默认服务端口是19530你可以用netstat -tlnp | grep 19530查看是否监听。使用Attu进行可视化验证可选但推荐Attu是Milvus官方图形化管理工具。同样用Docker运行docker run -p 8000:3000 -e MILVUS_URL你的服务器IP:19530 zilliz/attu:latest然后在浏览器访问http://你的服务器IP:8000如果能连接上Milvus服务器说明部署成功。实操心得在Linux服务器上部署时务必注意/tmp目录的权限因为MinIO默认会使用它。如果启动失败查看docker-compose logs日志常见问题是端口冲突或磁盘空间不足。生产环境部署请务必参考官方文档考虑数据持久化卷、资源限制和高可用架构。5. 文本向量化从文字到数学向量数据库存的是向量那么第一步就是要将我们的“文本”——无论是用户问题还是数据资产描述——转换成向量。这个过程叫做“文本嵌入”Text Embedding。5.1 嵌入模型的选择选择一个合适的嵌入模型是关键。模型决定了向量捕捉语义信息的能力。对于BI场景我们需要一个在通用语义相似度任务上表现良好的模型。开源模型如BAAI/bge-large-zh智源研究院的中文模型、sentence-transformers/all-MiniLM-L6-v2轻量级英文模型。它们效果不错可以本地部署数据隐私有保障。云服务API如OpenAI的text-embedding-3-small、text-embedding-3-large百度千帆的Embedding API等。它们省心效果稳定但会产生API调用费用和数据出境风险。我们的选择考虑到AI BI Helper可能涉及企业内部敏感数据我们优先选择开源模型。这里以BAAI/bge-large-zh为例它在中文语义匹配任务上名列前茅。对于纯英文环境all-MiniLM-L6-v2是一个快速且高效的起点。5.2 使用Sentence Transformers生成向量sentence-transformers库封装了使用Transformer模型生成句子向量的便捷方法。首先安装库并下载模型pip install sentence-transformers torch然后编写向量生成函数from sentence_transformers import SentenceTransformer import numpy as np class TextEmbedder: def __init__(self, model_nameBAAI/bge-large-zh): # 加载模型首次运行会自动下载 self.model SentenceTransformer(model_name) # 该模型需要指令前缀以获得最佳效果 self.instruction 为这个句子生成表示以用于检索相关文章 def encode(self, texts): 将文本列表转换为向量列表。 Args: texts: list of str, 输入文本列表。 Returns: np.ndarray, 形状为 (len(texts), embedding_dim) 的向量数组。 if isinstance(texts, str): texts [texts] # 为BGE模型添加指令前缀 if bge in self.model_name: texts [self.instruction t for t in texts] # 生成向量 embeddings self.model.encode(texts, normalize_embeddingsTrue, # 归一化方便使用余弦相似度 show_progress_barFalse) return embeddings.astype(np.float32) # Milvus通常要求float32 # 初始化嵌入器 embedder TextEmbedder() # 示例生成BI元数据的向量 data_assets [ “销售事实表包含日期、产品ID、客户ID、销售额、数量等字段” “客户维度表包含客户ID、客户名称、所在区域、客户等级” “月度营收报告主要分析各产品线的收入构成和环比增长” “用户满意度调查原始数据包含评分和文本反馈” ] vectors embedder.encode(data_assets) print(f“生成了 {len(vectors)} 个向量每个维度为 {vectors[0].shape[0]}”)关键参数解析normalize_embeddingsTrue将向量归一化为单位长度模长为1。这样向量点积就等于余弦相似度计算更高效也是Milvus计算余弦相似度的前提。.astype(np.float32)Milvus对插入的向量数据类型有要求通常是float32。注意事项模型推理有一定耗时。在实际应用中可以考虑对相对静态的数据资产如表结构描述进行预计算并存入Milvus。对于用户的实时提问则需要在线计算其向量。6. Milvus集成实战连接、定义与插入现在我们有了向量也有了运行中的Milvus。接下来就是用Python把它们连接起来。6.1 连接Milvus与集合Collection设计首先安装Milvus的Python SDKpip install pymilvus然后建立连接并设计我们的“数据资产知识库”集合from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility # 1. 连接到Milvus服务器 connections.connect(alias“default”, host‘localhost’, # 如果你的Milvus在远程改为其IP port‘19530’) # 2. 定义字段Schema # 这是一个典型的设计包含ID、原始文本、文本向量和其他可能用于过滤的属性 fields [ FieldSchema(name“id”, dtypeDataType.INT64, is_primaryTrue, auto_idTrue), FieldSchema(name“asset_text”, dtypeDataType.VARCHAR, max_length1000), # 存储原始描述文本 FieldSchema(name“asset_type”, dtypeDataType.VARCHAR, max_length50), # 类型如’table‘ ’report‘ ’column‘ FieldSchema(name“related_entity”, dtypeDataType.VARCHAR, max_length200), # 关联实体如表名’sales_fact‘ FieldSchema(name“embedding”, dtypeDataType.FLOAT_VECTOR, dim1024) # 向量字段维度需与模型输出一致 ] # 3. 定义集合Schema schema CollectionSchema(fieldsfields, description“AI BI Helper 数据资产语义知识库”) # 4. 创建集合 collection_name “bi_asset_knowledge_base” if utility.has_collection(collection_name): utility.drop_collection(collection_name) # 如果已存在先删除仅测试用 collection Collection(namecollection_name, schemaschema) print(f“集合 ‘{collection_name}’ 创建成功。”)设计思路解析id主键使用auto_id让Milvus自动生成唯一ID省心。asset_text存储原始的文本描述这是我们的“源材料”。asset_type和related_entity这些是标量字段。未来进行向量搜索时我们可能想加上过滤条件比如“只在table类型的资产中搜索”或者“只搜索与customer表相关的”。Milvus支持在向量相似度搜索的同时进行标量过滤非常强大。embedding核心的向量字段。dim1024必须与你选用的嵌入模型输出维度一致BAAI/bge-large-zh是1024维。务必核对准确6.2 构建索引与加载集合向量数据如果不建索引Milvus就只能进行暴力全表扫描速度极慢。建索引是为了加速近似最近邻搜索。# 1. 为向量字段创建索引 index_params { “index_type”: “IVF_FLAT”, # 一种基于量化的索引在精度和速度间取得平衡 “metric_type”: “IP”, # 内积Inner Product。因为我们使用了归一化向量内积等价于余弦相似度。 “params”: {“nlist”: 128} # 聚类中心数。值越大搜索越精确但耗时也越长。通常建议设为 sqrt(数据量) 附近。 } # 在embedding字段上创建索引 collection.create_index(field_name“embedding”, index_paramsindex_params, index_name“embedding_idx”) print(“向量索引创建成功。”) # 2. 加载集合到内存 # 只有加载后的集合才能进行搜索 collection.load() print(“集合加载到内存成功。”)索引参数选择心得IVF_FLAT是Milvus最经典的索引类型适合大多数场景。它先对向量空间进行聚类nlist个类搜索时只查找最可能的几个类大大减少了计算量。HNSW基于图算法的索引通常召回率找到最近邻的能力更高但构建索引更慢内存消耗更大。适合对搜索质量要求极高数据量不是特别大的场景。nlist这是IVF_FLAT的关键参数。对于100万左右的数据128或256是个不错的起点。你可以用小批量数据测试不同nlist值下的搜索精度和速度来调优。metric_type这里是个关键点。我们生成向量时做了归一化因此IP内积和COSINE余弦相似度在数学上是等价的cos(A,B) A·B当|A||B|1时。但有些模型输出可能未归一化这时就需要根据情况选择。Milvus的COSINE计算会先做归一化但IP计算更快。6.3 插入向量数据现在我们将之前准备好的数据资产文本和向量插入到集合中。# 准备插入数据注意数据类型和顺序要与Schema定义一致 # 假设我们已经有 texts_list文本列表 vectors_array对应的向量数组 asset_types_list, related_entities_list # 这里用模拟数据演示 num_entities 1000 texts_list [f“模拟数据资产描述 {i}” for i in range(num_entities)] asset_types_list [“table” if i % 3 0 else “report” if i % 3 1 else “column” for i in range(num_entities)] related_entities_list [f“entity_{i%100}” for i in range(num_entities)] # 生成模拟向量 (1024维) import numpy as np np.random.seed(42) vectors_array np.random.randn(num_entities, 1024).astype(np.float32) # 模拟归一化实际应从embedder获取 norms np.linalg.norm(vectors_array, axis1, keepdimsTrue) vectors_array vectors_array / norms # 构造插入数据 entities [ texts_list, # asset_text asset_types_list, # asset_type related_entities_list, # related_entity vectors_array # embedding ] # 执行插入 insert_result collection.insert(entities) print(f“成功插入 {insert_result.insert_count} 条数据。”) print(f“插入数据的ID范围: {insert_result.primary_keys[:5]} ...”) # 查看前5个自动生成的ID # 重要插入数据后确保数据持久化并创建索引如果之前没建 # 对于已有索引的集合新插入的数据会在后台自动构建索引异步也可以手动触发flush collection.flush()踩坑提醒维度对齐最常见的错误是插入的向量维度与集合Schema中定义的dim不匹配。务必用vectors_array.shape[1]检查维度。数据类型确保向量是np.float32。插入性能批量插入如每次几百到几千条远比单条插入高效。但单次批量不宜过大以免内存溢出或超时。索引构建新数据插入后索引需要更新。flush()操作会将数据持久化并触发索引更新。在搜索前最好确认一下索引构建进度可通过utility.index_building_progress(collection_name)查询。7. 语义搜索实现让BI理解你的问题核心功能来了接收用户的自然语言问题找到最相关的数据资产。7.1 执行向量相似度搜索def semantic_search(query_text, top_k5, filter_conditionNone): 在知识库中语义搜索与问题最相关的数据资产。 Args: query_text: str, 用户输入的自然语言问题。 top_k: int, 返回最相似的结果数量。 filter_condition: str, 可选的标量过滤表达式如 asset_type table。 Returns: list, 包含搜索结果的列表每个结果是一个字典。 # 1. 将问题文本转换为向量 query_vector embedder.encode(query_text) # shape: (1, dim) # 2. 定义搜索参数 search_params { “metric_type”: “IP”, # 必须与索引的metric_type一致 “params”: {“nprobe”: 10} # 搜索时探查的聚类中心数。nprobe越大搜索越精细越慢。 } # 3. 执行搜索 # 指定输出字段 results collection.search( dataquery_vector, anns_field“embedding”, paramsearch_params, limittop_k, exprfilter_condition, # 应用标量过滤 output_fields[“asset_text”, “asset_type”, “related_entity”], # 指定要返回的字段 consistency_level“Strong” ) # 4. 整理并返回结果 ret [] for hits in results: for hit in hits: ret.append({ “id”: hit.id, “asset_text”: hit.entity.get(“asset_text”), “asset_type”: hit.entity.get(“asset_type”), “related_entity”: hit.entity.get(“related_entity”), “score”: hit.score, # 相似度分数IP模式下是内积值归一化后即余弦相似度 }) return ret # 示例搜索 user_question “帮我分析一下上个月各区域的销售利润情况” search_results semantic_search(user_question, top_k3) print(“ 语义搜索结果 ”) for i, res in enumerate(search_results): print(f“{i1}. [相似度: {res[‘score’]:.4f}] [{res[‘asset_type’]}] {res[‘asset_text’]} (关联: {res[‘related_entity’]})”)搜索参数详解nprobe这是IVF_FLAT索引搜索时最重要的参数之一。它决定了搜索时探查多少个聚类中心。nprobe值越大搜索范围越广结果越准确但耗时越长。它通常设置为nlist的一小部分如1/10到1/20。需要根据数据量和性能要求进行权衡测试。expr这是Milvus非常强大的功能允许你在向量搜索的基础上进行标量字段的过滤。例如expr“asset_type in [‘table‘ ’report‘]”可以只搜索表和报告类型的资产。output_fields指定需要返回的字段避免不必要的数据传输。7.2 结合标量过滤的混合搜索在实际BI场景中纯向量搜索可能返回一些语义相关但类型不符的结果。混合搜索能极大提升准确性。# 场景用户可能只想查找具体的“数据表”来描述利润 question_for_table “利润相关的数据表有哪些” results_with_filter semantic_search(question_for_table, top_k5, filter_condition“asset_type ‘table’”) print(“\n 过滤后结果仅数据表”) for res in results_with_filter: print(f“- {res[‘asset_text’]}”) # 更复杂的过滤表达式 complex_filter “asset_type ‘report’ and related_entity like ‘%sales%’” # 这将搜索报告类型且关联实体包含‘sales’的资产8. 系统优化与生产环境考量一个能跑通的Demo和一个健壮的生产系统之间还有不少距离。以下是一些关键的优化和考量点。8.1 性能调优实践索引参数调优nlist和nprobe是平衡精度、速度和资源的关键。基准测试从你的数据中采样一个查询集如100个问题。固定nlist如256逐渐增加nprobe8, 16, 32, 64记录搜索耗时和召回率与暴力搜索结果的对比。找到满足你最低召回率要求下的最小nprobe。内存与精度权衡nlist越大索引越精细但构建索引越慢占用内存越多。对于十亿级数据可能需要使用IVF_SQ8或IVF_PQ这类有损压缩的索引来节省内存。分区Partition策略如果数据资产有明显类别如按业务域财务、销售、供应链可以按asset_type或业务域创建分区。搜索时指定分区能大幅缩小搜索范围提升性能。# 创建分区 collection.create_partition(partition_name“finance_assets”) # 向指定分区插入数据 collection.insert(entities, partition_name“finance_assets”) # 在指定分区搜索 results collection.search(..., partition_names[“finance_assets”])批量搜索如果需要同时处理多个用户问题使用collection.search的批量接口data传入二维数组比循环调用单次搜索效率高得多。8.2 数据更新与一致性增量更新新的数据资产如新增报表描述需要生成向量并插入集合。Milvus支持增量插入索引会自动更新异步。注意频繁的小批量插入可能影响查询性能可以设定一个时间窗口进行批量操作。删除与更新Milvus支持通过主键ID或复杂表达式删除实体。但更新Update操作在向量字段上受限通常需要先删后插。对于asset_text等标量字段的更新可以使用upsert操作Milvus 2.3。一致性级别在search和query操作中可以设置consistency_level。“Strong”确保能读到最新写入的数据但延迟高“Bounded”或“Eventually”提供更高性能但可能有短暂的数据延迟。根据业务对一致性的要求选择。8.3 资源监控与运维监控指标需要监控Milvus集群的健康状态包括查询延迟Query LatencyP95/P99延迟是否在SLA内。QPS每秒查询数当前负载。内存/CPU使用率防止资源耗尽。磁盘使用率特别是MinIO的存储空间。备份与恢复定期对Milvus的元数据MySQL/PostgreSQL和对象存储MinIO进行备份。熟悉Milvus的数据恢复流程。9. 踩坑实录与常见问题排查在实际集成过程中我遇到了不少问题这里把典型的几个列出来方便大家避坑。问题现象可能原因排查步骤与解决方案连接Milvus失败超时或拒绝连接1. Milvus服务未启动。2. 防火墙或安全组阻止了端口19530。3. 连接参数host, port错误。1.docker-compose ps检查服务状态。2.telnet host 19530测试端口连通性。3. 确认连接代码中的host是否为容器IP或宿主机IP从容器内连接用服务名如milvus-standalone。插入数据时报错dimension mismatch插入的向量维度与集合Schema中定义的dim不匹配。1. 打印vectors_array.shape确认第二维是否等于Schema的dim。2. 检查嵌入模型的输出维度并相应修改Schema或调整模型。搜索返回结果分数异常如全为1或0或结果完全随机1. 搜索的metric_type与创建索引时的metric_type不一致。2. 插入的向量未归一化但使用了IP或COSINE度量。3. 索引未成功构建或集合未加载。1.务必确保collection.create_index的metric_type与collection.search的metric_type完全一致。2. 检查向量生成代码确认是否做了归一化normalize_embeddingsTrue。3. 插入数据后执行了collection.flush()吗搜索前执行了collection.load()吗用utility.index_building_progress检查索引状态。搜索速度非常慢1. 数据量大了但没建索引在进行暴力搜索。2.nprobe参数设置过大。3. 集合未加载到内存每次搜索都从磁盘加载。1. 确认已为向量字段创建了索引collection.indexes。2. 适当降低nprobe值在精度可接受范围内提升速度。3. 确保在长期服务中集合保持在加载状态collection.load()。内存占用过高1. 向量数据量巨大全量加载内存不足。2. 索引类型选择不当如HNSW内存消耗大。1. 考虑使用支持磁盘ANN的索引类型如DISKANNMilvus 2.4实验性支持。2. 使用量化索引如IVF_SQ8减少内存占用。3. 升级硬件或采用集群分片部署。无法根据标量字段过滤过滤表达式语法错误或字段名错误。1. 过滤表达式是字符串字段名和值需用引号。如expr“asset_type ‘table‘”。2. 确认过滤字段已定义在Schema中且名称拼写正确。3. 对于IN操作使用expr“asset_type in [‘table‘ ’report‘]”。一个典型的调试流程当搜索不出预期结果时1) 先检查连接和集合加载状态2) 用collection.num_entities确认数据已插入3) 尝试一个简单的基于主键的querycollection.query(expr“id in [1,2,3]”)来确认数据可访问4) 检查向量和索引的metric_type5) 用一个小型的、已知相似度的测试向量集进行搜索验证。10. 展望从检索到真正的AI BI助手至此我们已经完成了AI BI Helper最基础也是最核心的“大脑皮层”——语义检索层的构建。用户的问题现在可以被理解并关联到相关的数据资产。但这仅仅是第一步。一个完整的AI BI助手还需要意图识别与SQL生成检索到相关表、字段后需要将自然语言问题解析成具体的、可执行的查询逻辑如SQL。这需要结合大语言模型LLM和预定义的业务规则。数据查询与执行生成的SQL需要在真实的数据仓库或湖仓中执行获取结果数据。结果解释与可视化将查询到的原始数据通过LLM总结成文字洞察并自动调用图表库生成合适的可视化。多轮对话与上下文管理用户可能会基于上一个回答进行追问如“那么利润率呢”系统需要记住之前的上下文。向量数据库Milvus在这里扮演了“长期记忆”和“知识索引”的角色它让LLM能够快速、准确地访问到庞大的、非结构化的BI元数据知识。而LLM则扮演了“推理引擎”和“交互界面”的角色。两者的结合才能实现从“检索相关信息”到“解答业务问题”的飞跃。在接下来的开发实录中我计划深入如何利用检索增强生成RAG技术将我们这里构建的语义检索能力与LLM例如ChatGLM、Qwen等本地化模型或经过合规审核的API相结合一步步拼凑出AI BI Helper的全貌。你会发现有了一个稳定高效的向量检索底座后续的每一步都会走得更加扎实。