Enhance impact analysis and configuration for vector persistence and API integration. Update main.spec to clarify data handling for ChromaDB, ensuring vector directories are excluded from packaging. Modify Text2SQLOrchestrator to unify question normalization for consistent SQL generation across languages. Introduce SchemaIndexer improvements for persistent vector storage and optimize embedding retrieval processes. Update documentation and comments for clarity on configuration changes and behavior adjustments.
This commit is contained in:
@@ -206,3 +206,165 @@
|
||||
|-------------|------|
|
||||
| `USE_LOCAL_EMBEDDING`、`EMBEDDING_MODEL_PATH` | 代码不再读取;`.env` 中可删去以免误解。 |
|
||||
| CLI `--embedding-model` | 已删除。 |
|
||||
|
||||
---
|
||||
|
||||
# Impact Analysis Report — main.spec:向量持久化目录不落包(追加)
|
||||
|
||||
## 1. 改动概览
|
||||
|
||||
- **背景与目标**:在 PyInstaller 配置中明确约定「业务侧 Chroma/向量持久化目录」不加入 `datas`,避免误将 `data/embeddings` 等打入 onefile;实际打包行为与此前一致(`datas` 中本未包含上述目录)。
|
||||
- **涉及模块**:`main.spec`。
|
||||
- **改动类型**:配置说明 / 文档化。
|
||||
|
||||
## 2. 方法级改动
|
||||
|
||||
| 位置 | 变更 |
|
||||
|------|------|
|
||||
| `main.spec` 顶部注释与 `datas` | 写明 `VECTOR_DB_PATH`、`FEWSHOT_CHROMA_PATH` 对应目录外置;区分 chromadb **wheel 依赖**与**用户向量库文件**;`EXE` 处注释澄清 `a.datas` 含义。 |
|
||||
|
||||
## 3. 调用方与影响范围
|
||||
|
||||
- **调用方**:仅 `pyinstaller main.spec` 打包流程;运行时仍依赖环境变量或旁路目录提供向量库(与代码逻辑无变更)。
|
||||
- **破坏性变更**:否。
|
||||
|
||||
## 4. 风险与回滚
|
||||
|
||||
- **风险级别**:低。
|
||||
- **回滚**:还原 `main.spec` 对应注释块。
|
||||
|
||||
**回滚方式是否简单**:是。
|
||||
|
||||
## 5. 验证与测试
|
||||
|
||||
- 打包前确认 `datas` 无 `data/embeddings` 等元组;打包后 exe 旁按需放置向量目录并配置 `.env`。
|
||||
|
||||
---
|
||||
|
||||
# Impact Analysis Report — 前端默认 NL API 地址(追加)
|
||||
|
||||
## 1. 改动概览
|
||||
|
||||
- **目标**:前端开发与 UAT 打包默认后端 origin 改为 `http://0.0.0.0:8041`;同 host 解析时默认端口改为 `8041`。
|
||||
- **涉及模块**:`ai-g3sb-backman-web/vite.config.ts`(`VITE_DEV_API_TARGET` 默认值)、`ai-g3sb-backman-web/src/api/packagedOrigin.ts`、`ai-g3sb-backman-web/src/api/config.ts`;`src/locales/{zh,tw,en}.ts` 中管理端 API 占位示例同步。
|
||||
- **改动类型**:配置默认值变更。
|
||||
|
||||
## 2. 调用方与破坏性变更
|
||||
|
||||
- **调用方**:Vite 开发代理 `/g3sb`;非 test 构建注入的 `window.__BACKMAN_API_ORIGIN__` 与 `apiBase()` 默认打包 origin。
|
||||
- **破坏性变更**:否(仍可通过环境变量 `VITE_DEV_API_TARGET`、`VITE_PACKAGED_API_ORIGIN`、`VITE_PACKAGED_API_PORT` 覆盖)。
|
||||
|
||||
## 3. 风险与回滚
|
||||
|
||||
- **风险级别**:低。说明:浏览器直连 `0.0.0.0` 在部分环境下可能不如 `127.0.0.1` 可靠;若遇连接问题可改用 `VITE_*` 覆盖为实际可访问地址。
|
||||
- **回滚**:还原上述三处默认值或设置环境变量覆盖。
|
||||
|
||||
**回滚方式是否简单**:是。
|
||||
|
||||
## 4. 配置变更
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| `VITE_DEV_API_TARGET`(可选) | 未设置时默认 `http://0.0.0.0:8041`。 |
|
||||
| `PACKAGED_API_ORIGIN` / `VITE_PACKAGED_API_ORIGIN` | 代码内默认改为 `http://0.0.0.0:8041`。 |
|
||||
| `VITE_PACKAGED_API_PORT`(可选) | `same-host`/`auto` 时未设置则默认 `8041`。 |
|
||||
|
||||
---
|
||||
|
||||
# Impact Analysis Report — SchemaIndexer 持久化 Chroma(追加)
|
||||
|
||||
## 1. 改动概览
|
||||
|
||||
- **背景与目标**:原先 `SchemaIndexer` 固定使用 `EphemeralClient`,进程内集合恒为空,每次请求粗筛都会全量计算约 2500+ 张表的 embedding;用户已在 `data/embeddings/chroma` 等目录落盘向量库,应直接复用。
|
||||
- **涉及模块**:`backend/schema/indexer.py`、`backend/agents/orchestrator.py`(日志与 `force_rebuild`)、`backend/utils/fewshot_chroma_store.py`(注释)、`main.spec`(打包说明注释)。
|
||||
- **改动类型**:缺陷修复 / 行为优化(性能与成本)。
|
||||
|
||||
## 2. 方法级改动
|
||||
|
||||
| 位置 | 变更 |
|
||||
|------|------|
|
||||
| `SchemaIndexer.__init__` | 默认 `chromadb.PersistentClient(path=persist_dir)`,创建目录;`SCHEMA_INDEXER_EPHEMERAL=true` 或 `use_ephemeral=True` 时仍为 `EphemeralClient`。默认 `persist_dir` 与 `VECTOR_DB_PATH` 对齐为 `./data/embeddings/chroma`。 |
|
||||
| `SchemaIndexer.get_statistics` | `chroma_mode` 区分 `persistent` / `memory`。 |
|
||||
| `Text2SQLOrchestrator._coarse_filter` | 每次粗筛前调用 `SchemaIndexer.ensure_index_for_schema`:索引条数与当前 Schema 表数一致则跳过向量化;空库则构建;不一致则 `force_rebuild` 重建。 |
|
||||
| `SchemaIndexer.ensure_index_for_schema`(新) | 对比 `collection.count()` 与 `len(schema_manager.get_tables())`,避免无意义重复向量化,并在 Schema 增删表后自动重载索引。 |
|
||||
|
||||
## 3. 调用方与影响范围
|
||||
|
||||
- **调用方**:`Text2SQLOrchestrator._get_vector_index()` 传入的 `persist_dir` 仍为 `vector_db_path` / 环境变量 `VECTOR_DB_PATH`;向量粗筛路径经 `ensure_index_for_schema`。
|
||||
- **破坏性变更**:否。若依赖「每次进程冷启动强制空向量库」的测试,需设置 `SCHEMA_INDEXER_EPHEMERAL=true`。
|
||||
|
||||
## 4. 风险与回滚
|
||||
|
||||
- **风险级别**:低。说明:Embedding 模型或维度变更时,旧持久化向量与当前 encoder 不一致可能导致检索质量下降,需删除目录或调用带 `force_rebuild` 的构建逻辑重建。
|
||||
- **回滚**:还原 `indexer.py` 相关提交或设置 `SCHEMA_INDEXER_EPHEMERAL=true`。
|
||||
|
||||
**回滚方式是否简单**:是。
|
||||
|
||||
## 5. 配置变更
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| `VECTOR_DB_PATH` | 既有;默认 `./data/embeddings/chroma`,现为 Schema Chroma 真实持久化根路径。 |
|
||||
| `SCHEMA_INDEXER_EPHEMERAL`(可选) | 设为 `true`/`1`/`yes` 时使用内存 Chroma(与旧行为一致)。 |
|
||||
|
||||
---
|
||||
|
||||
# Impact Analysis Report — 中英文问句归一以提升 SQL 一致性(追加)
|
||||
|
||||
## 1. 改动概览
|
||||
|
||||
- **背景与目标**:同一业务语义分别用中文、英文提问时,原先仅对「纯英文」问句做英译中,中文问句原样进入检索/生成,导致与英文路径的表述不一致,向量粗筛与 SQL 可能分叉。
|
||||
- **涉及模块**:`backend/config/prompts.py`(归一提示词 + SQL_GENERATOR 约束)、`backend/llm/deepseek_client.py`、`backend/agents/orchestrator.py`、`backend/main.py`(CLI 帮助文案)。
|
||||
- **改动类型**:行为优化;默认仍受 `TRANSLATE_EN_TO_ZH` / `--no-translate-en` 控制。
|
||||
|
||||
## 2. 方法级改动
|
||||
|
||||
| 位置 | 变更 |
|
||||
|------|------|
|
||||
| `DeepSeekClient.normalize_nl_question_for_text2sql` | 新增:`temperature=0` 下将中/英问句归一为一句中文。 |
|
||||
| `DeepSeekClient.translate_nl_question_to_zh` | 改为委托上述方法(兼容旧名)。 |
|
||||
| `Text2SQLOrchestrator.generate` | 当 `translate_english_to_zh` 为 True 时,对**所有**非空问句调用归一(不再仅限 `looks_like_english_only`)。 |
|
||||
| `SQL_GENERATOR_SYSTEM` | 新增硬性约束第 6 条:中英文同义时 SQL 逻辑须一致。 |
|
||||
|
||||
## 3. 调用方与破坏性变更
|
||||
|
||||
- **调用方**:所有经 `generate()` 的 Text2SQL 请求(含 `api_server` 默认 `TRANSLATE_EN_TO_ZH` 开启时)。
|
||||
- **破坏性变更**:否。关闭归一:`TRANSLATE_EN_TO_ZH=false` 或 `--no-translate-en` / `Args.no_translate_en`,行为与改动前「中文不归一、英文仍可不译」一致。
|
||||
|
||||
## 4. 风险与回滚
|
||||
|
||||
- **风险级别**:低~中。每次成功归一增加一次 LLM 调用(延迟与 token);归一失败时回退原文(与旧失败策略一致)。
|
||||
- **回滚**:关闭环境变量或还原相关文件。
|
||||
|
||||
**回滚方式是否简单**:是。
|
||||
|
||||
## 5. 配置变更
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| `TRANSLATE_EN_TO_ZH` | 语义扩展为「是否做问句归一中文」;`false` 关闭额外 LLM 归一步骤。 |
|
||||
|
||||
---
|
||||
|
||||
# Impact Analysis Report — Few-shot Chroma 默认读盘(追加)
|
||||
|
||||
## 1. 改动概览
|
||||
|
||||
- **问题**:`FEWSHOT_USE_CHROMA=true` 时 `FewShotChromaStore` 仍默认 `EphemeralClient`,进程内 `count` 恒为 0,每次启动从 JSONL 重算 embedding,忽略已灌库的 `data/embeddings/chroma_fewshot`。
|
||||
- **模块**:`backend/utils/fewshot_chroma_store.py`。
|
||||
- **类型**:缺陷修复。
|
||||
|
||||
## 2. 行为变更
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| 默认 | `persist_to_disk=None` 时默认使用 `PersistentClient`(`FEWSHOT_CHROMA_PATH` 或 `./data/embeddings/chroma_fewshot`)。 |
|
||||
| 退出 | `FEWSHOT_CHROMA_EPHEMERAL=true` 或构造参数 `persist_to_disk=False` 时仍为内存 Chroma。 |
|
||||
|
||||
## 3. 破坏性变更
|
||||
|
||||
- **否**。灌库脚本显式 `persist_to_disk=True` 不变。
|
||||
|
||||
## 4. 配置
|
||||
|
||||
| `FEWSHOT_CHROMA_EPHEMERAL` | 可选;`true` 时与旧版「仅内存」行为一致。 |
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -66,7 +66,9 @@ class Text2SQLOrchestrator:
|
||||
vector_db_path: 向量数据库路径
|
||||
max_retry: 最大重试次数(包含首次生成)
|
||||
use_vector_search: 是否使用向量检索粗筛
|
||||
translate_english_to_zh: 无中日韩字符的英文问句是否先译为中文再走检索与生成
|
||||
translate_english_to_zh: 为 True 时(默认)对**所有**非空问句做一次 LLM 归一(temperature=0),
|
||||
输出一句标准中文供检索与生成;使同一语义的中英文表述对齐,从而 SQL 一致。为 False 时
|
||||
不做归一(原样英文/中文)。环境变量 ``TRANSLATE_EN_TO_ZH=false`` 可关闭。
|
||||
"""
|
||||
self.schema_manager = schema_manager
|
||||
self.max_retry = max_retry
|
||||
@@ -120,7 +122,7 @@ class Text2SQLOrchestrator:
|
||||
f"[OK] Text2SQLOrchestrator初始化完成: "
|
||||
f"max_retry={max_retry}, use_vector_search={use_vector_search}"
|
||||
+ (f", fewshot=on" if self.fewshot_enabled else "")
|
||||
+ (", en→zh=on" if self.translate_english_to_zh else ", en→zh=off")
|
||||
+ (", nl→zh_norm=on" if self.translate_english_to_zh else ", nl→zh_norm=off")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -174,12 +176,7 @@ class Text2SQLOrchestrator:
|
||||
|
||||
try:
|
||||
indexer = self._get_vector_index()
|
||||
|
||||
# 确保索引已构建
|
||||
if indexer.count() == 0:
|
||||
logger.info("向量索引为空,正在构建...")
|
||||
indexer.build_index(self.schema_manager, force_rebuild=True)
|
||||
logger.info(f"[OK] 索引构建完成,共 {indexer.count()} 张表")
|
||||
indexer.ensure_index_for_schema(self.schema_manager)
|
||||
|
||||
# 检索
|
||||
logger.info(f"[Orchestrator] 开始向量检索: query='{question[:50]}...'")
|
||||
@@ -585,26 +582,24 @@ class Text2SQLOrchestrator:
|
||||
Returns:
|
||||
GenerationResult对象
|
||||
"""
|
||||
from utils.question_locale import looks_like_english_only
|
||||
|
||||
original_question = (question or "").strip()
|
||||
translation_meta: Dict = {}
|
||||
work_question = original_question
|
||||
if self.translate_english_to_zh and looks_like_english_only(original_question):
|
||||
if self.translate_english_to_zh and original_question:
|
||||
try:
|
||||
zh = self.deepseek.translate_nl_question_to_zh(original_question).strip()
|
||||
zh = self.deepseek.normalize_nl_question_for_text2sql(original_question).strip()
|
||||
if zh and len(zh) >= 2:
|
||||
work_question = zh
|
||||
translation_meta["question_original"] = original_question
|
||||
translation_meta["question_zh_normalized"] = zh
|
||||
logger.info(
|
||||
"[GEN] 英文已译为中文:%s",
|
||||
"[GEN] 问句已归一中文:%s",
|
||||
zh[:120] + ("…" if len(zh) > 120 else ""),
|
||||
)
|
||||
else:
|
||||
logger.warning("[GEN] 英译中结果为空或过短,使用原文")
|
||||
logger.warning("[GEN] 归一结果为空或过短,使用原文")
|
||||
except Exception as e:
|
||||
logger.warning("[GEN] 英译中失败,使用原文: %s", e)
|
||||
logger.warning("[GEN] 问句归一失败,使用原文: %s", e)
|
||||
|
||||
question = work_question
|
||||
dc_raw = (dialog_context or "").strip()
|
||||
|
||||
Binary file not shown.
@@ -67,6 +67,7 @@ SQL_GENERATOR_SYSTEM = """你是一个精通SQL的数据库专家,有10年以
|
||||
- **方言(T-SQL)**:字符串用 `+` 拼接;「今日」用 `CAST(GETDATE() AS DATE)`;标识符冲突用方括号 `[]`;非关键字尽量不加引号。不要用 MySQL 反引号或 `CURDATE()`。
|
||||
4. **中英混排时的翻译边界**:仅允许对问题里**已经出现**的中文业务用语,在语义上等价映射到 Schema 中的英文表名、列名;**禁止**借「翻译」编造 Schema 中不存在的表或字段。
|
||||
5. **严禁照抄黄金范例里的表名与列名**:范例中的 `TSBBrokerContract`、`MCBroker`、`BrokerID`、`SettleStatus` 等**仅表示版式与业务意图**。**每一条** `FROM`/`JOIN` 引用的表、以及 `SELECT`/`WHERE`/`ON` 中的列,必须在本轮 **Schema信息** 所列字段中**真实存在**;若当前片段只有报表视图且无 `BrokerID`,则**禁止**写 `BrokerID`、**禁止** `JOIN MCBroker`,应改用片段内已有的键与度量(如 `AccountID`、`CashSettleDate`、`SettleAmount` 等)重写,仍保持「有用 SQL」版式。
|
||||
6. **中英文同义一致**:用户问题可能已由上游归一为中文。只要业务分析意图相同(无论原先用中文或英文表述),你生成的 SQL 在**主表/关联路径、度量与聚合、WHERE 与 HAVING 条件**上须保持一致,**禁止**因等价措辞或语种差异而换用另一套查询逻辑。
|
||||
|
||||
**原则**:
|
||||
1. 只输出SQL语句,不要解释、注释或其他内容(除非SQL内注释)
|
||||
@@ -369,6 +370,23 @@ TRANSLATE_NL_TO_ZH_USER = """原句:
|
||||
|
||||
仅输出一句中文:"""
|
||||
|
||||
# ========== NL 归一中文(中英文 → 同一表述,检索/SQL 一致)==========
|
||||
CANONICALIZE_NL_FOR_TEXT2SQL_SYSTEM = """你是证券/期货类数据仓库 Text2SQL 的「问句归一」模块。
|
||||
|
||||
读入用户的自然语言(可为**中文**、**英文**或中英混写),输出**唯一一句**中文自然语言问题,供向量检索、选表与 SQL 生成使用。
|
||||
|
||||
必须遵守:
|
||||
1. **语义等价**:不得增加、删除或弱化任何筛选条件、时间范围、数值阈值、分组/排序/去重意图;不得臆造用户未提及的维度。
|
||||
2. **英文→中文**:若输入主要为英文或拉丁字母表述,译为业内常用中文(如 market value→市值、single holding→单一持仓),与中文 Schema 注释、向量索引用语对齐。
|
||||
3. **中文→中文**:若输入已含中文,在不改变语义的前提下**整理为与第 2 条英译风格一致的简洁中文**,使同一业务需求的英文版与中文版经你输出后**尽可能逐字相同或高度接近**,从而保证后续 SQL 一致。
|
||||
4. 保留阿拉伯数字、日期、币种/市场代码、证券代码;原句中的英文表名、字段名保持不译。
|
||||
5. **只输出一句中文问句**,不要引号、前后缀或解释。"""
|
||||
|
||||
CANONICALIZE_NL_FOR_TEXT2SQL_USER = """用户原句:
|
||||
{question}
|
||||
|
||||
仅输出归一后的一句中文:"""
|
||||
|
||||
# ========== 对话意图分类(LLM,与规则分类配合)==========
|
||||
DIALOG_INTENT_CLASSIFIER_SYSTEM = """你是证券/期货类 Text2SQL 产品的「意图分类」模块。
|
||||
|
||||
|
||||
Binary file not shown.
@@ -325,25 +325,34 @@ class DeepSeekClient:
|
||||
kwargs.setdefault("top_p", 1.0)
|
||||
return self.chat_with_json(messages, **kwargs)
|
||||
|
||||
def translate_nl_question_to_zh(self, question: str) -> str:
|
||||
def normalize_nl_question_for_text2sql(self, question: str) -> str:
|
||||
"""
|
||||
将主要为英文的自然语言分析问题译为中文,便于与中文 Schema 注释 / 向量索引对齐。
|
||||
将中文/英文问句归一为**一句**标准中文(temperature=0),使同一语义的中英表述
|
||||
走同一套向量检索与 SQL 生成路径。
|
||||
"""
|
||||
from config.prompts import TRANSLATE_NL_TO_ZH_SYSTEM, TRANSLATE_NL_TO_ZH_USER
|
||||
from config.prompts import (
|
||||
CANONICALIZE_NL_FOR_TEXT2SQL_SYSTEM,
|
||||
CANONICALIZE_NL_FOR_TEXT2SQL_USER,
|
||||
)
|
||||
|
||||
q = (question or "").strip()
|
||||
if not q:
|
||||
return ""
|
||||
messages = [
|
||||
{"role": "system", "content": TRANSLATE_NL_TO_ZH_SYSTEM},
|
||||
{"role": "user", "content": TRANSLATE_NL_TO_ZH_USER.format(question=q)},
|
||||
{"role": "system", "content": CANONICALIZE_NL_FOR_TEXT2SQL_SYSTEM},
|
||||
{"role": "user", "content": CANONICALIZE_NL_FOR_TEXT2SQL_USER.format(question=q)},
|
||||
]
|
||||
msg = self.chat(messages, temperature=0.0, top_p=1.0, max_tokens=512)
|
||||
text = (msg.content or "").strip()
|
||||
# 只取首行,避免模型附加说明
|
||||
line = text.splitlines()[0].strip() if text else ""
|
||||
return line.strip("「」\"'“”")
|
||||
|
||||
def translate_nl_question_to_zh(self, question: str) -> str:
|
||||
"""
|
||||
兼容旧名:与 :meth:`normalize_nl_question_for_text2sql` 相同(不再仅限英文)。
|
||||
"""
|
||||
return self.normalize_nl_question_for_text2sql(question)
|
||||
|
||||
|
||||
class AsyncDeepSeekClient:
|
||||
"""
|
||||
|
||||
+1
-1
@@ -377,7 +377,7 @@ def main():
|
||||
parser.add_argument(
|
||||
"--no-translate-en",
|
||||
action="store_true",
|
||||
help="关闭英文问句自动译为中文(默认开启;也可用 TRANSLATE_EN_TO_ZH=false)",
|
||||
help="关闭问句归一中文(默认开启:中英均先归一句中文以利 SQL 一致;也可用 TRANSLATE_EN_TO_ZH=false)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
Binary file not shown.
+71
-10
@@ -2,11 +2,13 @@
|
||||
Schema向量索引构建器 - 基于ChromaDB
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import chromadb
|
||||
from chromadb.config import Settings as ChromaSettings
|
||||
from typing import Any, List, Dict, Optional
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from schema.manager import SchemaManager
|
||||
|
||||
@@ -20,31 +22,50 @@ class SchemaIndexer:
|
||||
功能:
|
||||
1. 为表结构构建向量索引
|
||||
2. 基于问题的表检索
|
||||
3. Chroma 使用内存模式(EphemeralClient),进程退出后不保留;``persist_dir`` 仅作配置/统计引用
|
||||
3. 默认使用 Chroma ``PersistentClient``,数据落在 ``persist_dir``(与 ``VECTOR_DB_PATH`` 一致);
|
||||
仅当环境变量 ``SCHEMA_INDEXER_EPHEMERAL=true`` 或构造参数 ``use_ephemeral=True`` 时使用内存客户端。
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
embedder: Any,
|
||||
persist_dir: str = "./data/embeddings",
|
||||
persist_dir: str = "./data/embeddings/chroma",
|
||||
collection_name: str = "schema_tables",
|
||||
*,
|
||||
use_ephemeral: Optional[bool] = None,
|
||||
):
|
||||
"""
|
||||
初始化索引器
|
||||
|
||||
Args:
|
||||
embedder: Embedding模型实例
|
||||
persist_dir: 历史配置中的向量库路径(仅展示与统计,不落盘)
|
||||
persist_dir: Chroma 持久化目录(默认与编排器 ``vector_db_path`` / ``VECTOR_DB_PATH`` 一致)
|
||||
collection_name: 集合名称
|
||||
use_ephemeral: 为 True 时使用内存 Chroma;为 None 时读环境变量 SCHEMA_INDEXER_EPHEMERAL
|
||||
"""
|
||||
self.embedder = embedder
|
||||
self.persist_dir = Path(persist_dir)
|
||||
self.collection_name = collection_name
|
||||
|
||||
# 内存 Chroma:不落盘,每次进程需重新 build_index
|
||||
env_ephemeral = os.getenv("SCHEMA_INDEXER_EPHEMERAL", "").lower() in (
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
)
|
||||
self._chroma_ephemeral = bool(use_ephemeral) if use_ephemeral is not None else env_ephemeral
|
||||
|
||||
if self._chroma_ephemeral:
|
||||
self.client = chromadb.EphemeralClient(
|
||||
settings=ChromaSettings(anonymized_telemetry=False),
|
||||
)
|
||||
backend_desc = "Chroma内存"
|
||||
else:
|
||||
self.persist_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.client = chromadb.PersistentClient(
|
||||
path=str(self.persist_dir),
|
||||
settings=ChromaSettings(anonymized_telemetry=False),
|
||||
)
|
||||
backend_desc = f"Chroma磁盘 path={self.persist_dir}"
|
||||
|
||||
# 获取或创建集合
|
||||
self.collection = self.client.get_or_create_collection(
|
||||
@@ -53,10 +74,50 @@ class SchemaIndexer:
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"[OK] 初始化SchemaIndexer(Chroma内存): collection={self.collection_name}, "
|
||||
f"配置路径引用={self.persist_dir}"
|
||||
f"[OK] 初始化SchemaIndexer({backend_desc}): collection={self.collection_name}, "
|
||||
f"count={self.collection.count()}"
|
||||
)
|
||||
|
||||
def ensure_index_for_schema(
|
||||
self,
|
||||
schema_manager: SchemaManager,
|
||||
batch_size: int = 32,
|
||||
) -> None:
|
||||
"""
|
||||
每次使用向量粗筛前调用:若持久化集合中表条数与当前 Schema 一致且非空,则跳过向量化;
|
||||
若为空则全量构建;若条数不一致则强制重建(Schema 变更后重新加载)。
|
||||
"""
|
||||
expected = len(schema_manager.get_tables())
|
||||
indexed = self.count()
|
||||
|
||||
if expected == 0:
|
||||
if indexed > 0:
|
||||
logger.warning("当前 Schema 无表但向量索引非空,已清空索引")
|
||||
self.clear()
|
||||
return
|
||||
|
||||
if indexed == expected:
|
||||
logger.info(
|
||||
"Schema 向量索引已就绪(%s 张表),跳过向量化",
|
||||
indexed,
|
||||
)
|
||||
return
|
||||
|
||||
if indexed == 0:
|
||||
logger.info(
|
||||
"向量索引为空,开始构建共 %s 张表(向量化)...",
|
||||
expected,
|
||||
)
|
||||
self.build_index(schema_manager, batch_size=batch_size, force_rebuild=False)
|
||||
return
|
||||
|
||||
logger.info(
|
||||
"向量索引与当前 Schema 不一致(索引 %s 张,Schema %s 张),重新向量化并加载...",
|
||||
indexed,
|
||||
expected,
|
||||
)
|
||||
self.build_index(schema_manager, batch_size=batch_size, force_rebuild=True)
|
||||
|
||||
def build_index(
|
||||
self,
|
||||
schema_manager: SchemaManager,
|
||||
@@ -250,5 +311,5 @@ class SchemaIndexer:
|
||||
"total_columns": total_columns,
|
||||
"avg_columns": total_columns / count if count > 0 else 0,
|
||||
"persist_dir": str(self.persist_dir),
|
||||
"chroma_mode": "memory",
|
||||
"chroma_mode": "memory" if self._chroma_ephemeral else "persistent",
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,9 @@
|
||||
"""
|
||||
Few-shot 经验样本的 Chroma 向量库存储与检索。
|
||||
|
||||
与 SchemaIndexer 一致:使用项目统一 ``get_embedder()``;默认 Chroma 为内存
|
||||
(``EphemeralClient``)。离线灌库脚本可设 ``persist_to_disk=True`` 写入磁盘。
|
||||
与 SchemaIndexer 共用 ``get_embedder()``。Few-shot 默认使用 ``PersistentClient``
|
||||
(``FEWSHOT_CHROMA_PATH`` / ``./data/embeddings/chroma_fewshot``),与灌库脚本写入目录一致;
|
||||
仅当 ``FEWSHOT_CHROMA_EPHEMERAL=true`` 或显式 ``persist_to_disk=False`` 时使用内存 Chroma。
|
||||
集合名默认 ``fewshot_samples``。
|
||||
"""
|
||||
|
||||
@@ -36,14 +37,15 @@ class FewShotChromaStore:
|
||||
persist_dir: Optional[str] = None,
|
||||
collection_name: Optional[str] = None,
|
||||
*,
|
||||
persist_to_disk: bool = False,
|
||||
persist_to_disk: Optional[bool] = None,
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
embedder: 编码器实例。
|
||||
persist_dir: 磁盘模式下的持久化目录;内存模式下仍解析为配置引用路径。
|
||||
persist_dir: Chroma 持久化根目录;内存模式下仍解析为配置引用路径。
|
||||
collection_name: 集合名;可空,空则读环境变量或默认。
|
||||
persist_to_disk: 为 True 时使用 ``PersistentClient`` 落盘(如灌库脚本)。
|
||||
persist_to_disk: 为 True/False 时强制磁盘或内存;为 None 时默认磁盘,除非环境变量
|
||||
``FEWSHOT_CHROMA_EPHEMERAL`` 为真。
|
||||
"""
|
||||
self.embedder = embedder
|
||||
# Chroma 的 collection 名;显式参数优先,否则读 FEWSHOT_CHROMA_COLLECTION,再回退默认
|
||||
@@ -53,8 +55,16 @@ class FewShotChromaStore:
|
||||
self.persist_dir = Path(
|
||||
(persist_dir or os.getenv("FEWSHOT_CHROMA_PATH") or DEFAULT_FEWSHOT_CHROMA_DIR).strip()
|
||||
)
|
||||
self.persist_to_disk = persist_to_disk
|
||||
if persist_to_disk:
|
||||
env_ephemeral = os.getenv("FEWSHOT_CHROMA_EPHEMERAL", "").lower() in (
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
)
|
||||
if persist_to_disk is None:
|
||||
self.persist_to_disk = not env_ephemeral
|
||||
else:
|
||||
self.persist_to_disk = bool(persist_to_disk)
|
||||
if self.persist_to_disk:
|
||||
self.persist_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.client = chromadb.PersistentClient(
|
||||
path=str(self.persist_dir),
|
||||
@@ -68,7 +78,11 @@ class FewShotChromaStore:
|
||||
name=self.collection_name,
|
||||
metadata={"hnsw:space": "cosine"},
|
||||
)
|
||||
backend = f"磁盘 {self.persist_dir}" if persist_to_disk else f"内存(配置路径={self.persist_dir})"
|
||||
backend = (
|
||||
f"磁盘 {self.persist_dir}"
|
||||
if self.persist_to_disk
|
||||
else f"内存(配置路径={self.persist_dir})"
|
||||
)
|
||||
logger.info(
|
||||
f"[OK] FewShotChromaStore: {backend} collection={self.collection_name} "
|
||||
f"count={self.collection.count()}"
|
||||
|
||||
@@ -9,17 +9,26 @@ import sys
|
||||
_REPO_DIR = Path(os.getcwd()).resolve()
|
||||
|
||||
# 根目录执行:pyinstaller --clean main.spec
|
||||
# 收集配置文件夹和数据文件
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
# 向量「数据库文件」/ 业务数据 —— 明确不打入 onefile EXE
|
||||
# ---------------------------------------------------------------------------
|
||||
# 下列目录为运行时读写或外置分发的数据,禁止加入下方 ``datas``(勿取消注释):
|
||||
# - Schema 侧:环境变量 VECTOR_DB_PATH(默认如 ./data/embeddings/chroma)
|
||||
# - Few-shot 侧:FEWSHOT_CHROMA_PATH(默认如 ./data/embeddings/chroma_fewshot)
|
||||
# 部署:将上述目录放在 exe 同目录旁,或通过 .env 指向可写绝对路径。
|
||||
# SchemaIndexer 默认使用 PersistentClient(VECTOR_DB_PATH);仅 SCHEMA_INDEXER_EPHEMERAL=true 时为内存索引。
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# 可选:仅当需要把 Schema JSON 等打进包时再取消注释(向量库目录仍不要加)
|
||||
datas = [
|
||||
# 所有数据文件都不打包,从外部读取
|
||||
# ('.env', '.'),
|
||||
# ('data/schemas', 'data/schemas'),
|
||||
# ('data/embeddings', 'data/embeddings'),
|
||||
# ('data/experiences', 'data/experiences'),
|
||||
# 勿打包 data/embeddings、data/experiences(向量库与样本数据外置)
|
||||
]
|
||||
|
||||
# ChromaDB 在 Windows 单文件 exe 下如缺少 native 动态库,可能在持久化访问时直接“硬退出”
|
||||
# 这里显式收集 chromadb 与 hnswlib(向量索引)的动态库/二进制依赖
|
||||
# Chroma **Python 包**在 Windows 单文件 exe 下如缺少 native 动态库,可能在初始化时直接退出
|
||||
# 这里收集的是 chromadb / hnswlib 的 **wheel 内 DLL**,不是用户磁盘上的 Chroma 持久化目录
|
||||
binaries = []
|
||||
try:
|
||||
binaries += collect_dynamic_libs("chromadb")
|
||||
@@ -30,7 +39,7 @@ try:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 某些 chromadb 版本会依赖包内数据文件(如 migrations/默认配置等),一并收集更稳妥
|
||||
# chromadb 包自带的非 Python 资源(如 migrations),非业务向量库文件
|
||||
try:
|
||||
datas += collect_data_files("chromadb")
|
||||
except Exception:
|
||||
@@ -148,7 +157,7 @@ exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas, # 单文件模式:将数据文件打包进 exe
|
||||
a.datas, # 单文件:仅打包 spec 中 datas(chromadb 包资源等),不含业务向量持久化目录
|
||||
[],
|
||||
name='Backman_Text2SQL_Server',
|
||||
debug=False,
|
||||
|
||||
Reference in New Issue
Block a user