# 本地嵌入模块(DJL + ONNX Runtime + bge-m3)—— 独立模块方案 ## 定位(按你的要求调整) - **完全独立**的新模块,不用 agentscope 任何 API,不接入 `EmbeddingModelFactory`/`agent_model` 表/RAG 流程,前端无感知。这些现有代码**零改动**。 - 对业务暴露一套简洁的 **Java API**(注入 `EmbeddingService` 即用);另附一个极小的调试 HTTP 接口用于人工验证(可随时删)。 - 配置走 `application.yaml`(`zsjz.embedding.*`),与项目 `zsjz.duckdb`/`zsjz.insight` 等段风格一致,不进数据库。 ## 模块结构(新包 `com.zsjz.ai.module.embedding`) ``` module/embedding/ ├── config/EmbeddingProperties.java # @ConfigurationProperties("zsjz.embedding") ├── core/OnnxEmbeddingEngine.java # 分词 + ONNX 推理 + CLS池化 + L2归一化(懒加载) ├── core/EmbeddingException.java # 模块内异常 ├── service/EmbeddingService.java # 业务门面(具体类,风格仿 module/search 的 SearchQueryService) └── controller/EmbeddingDebugController.java # 可选调试接口 ``` ## 业务 API(EmbeddingService,业务代码这样用) ```java float[] embed(String text); // 单文本 → 1024 维归一化向量 List embedBatch(List texts); // 批量(内部按 batch-size 分批推理) double cosineSimilarity(float[] a, float[] b); int getDimension(); // 从模型输出自动探测(1024) boolean isReady(); void warmUp(); // 懒加载状态 / 主动预热 ``` ## 依赖(ai-server/pom.xml,实施时先校验 Maven Central 最新可用版) - `ai.djl.huggingface:tokenizers`(0.36.0,2026-09-10 发布)—— 直接加载 `bge-m3/tokenizer.json`,原生 Rust 分词 - `com.microsoft.onnxruntime:onnxruntime`(1.30.0 左右,校验 metadata 后定版)—— 各平台 CPU native 内置 ## 核心实现要点 1. **配置项** `zsjz.embedding`:`model-path`(默认 `bge-m3`,相对 user.dir)、`max-seq-len`(默认 8192)、`batch-size`(默认 8)、`intra-op-threads`、`opt-level`(默认 BASIC)、`enabled` 2. **引擎懒加载单例**(Spring bean,volatile + synchronized):首次调用才加载 2.3GB 权重,不阻塞启动;session 从**文件路径**创建,天然支持 `onnx/model.onnx + model.onnx_data` 外部权重(找不到 `onnx/model.onnx` 时回退 `model.onnx`) 3. **推理**:tokenizer 逐条编码(截断到 max-seq-len)→ 批内手动 padding(input_ids / attention_mask / token_type_ids 按会话实际输入名动态构建,输入输出名从 session 动态读取)→ 取输出 `last_hidden_state[:, 0]`(CLS)→ L2 归一化(bge-m3 官方 dense 用法) 4. **推理在线程池隔离执行**,避免阻塞调用线程;失败抛 `EmbeddingException`,模型目录缺失给出明确提示 ## 调试接口(验证用,Result 包装,符合项目惯例) `POST /js/a/embedding/debug`,body `{"texts": ["转账给可疑账户", "向陌生账户转移资金"]}` → 返回维度、各向量、两两余弦相似度,用于人工确认语义区分度。 ## 验证步骤 1. `mvn -pl ai-server compile` 通过 2. 启动应用,curl 调试接口:确认返回 1024 维、归一化正确(模长≈1)、相关语句相似度显著高于无关语句、首次调用触发模型加载日志 3. 业务接入示例写入类 Javadoc ## 风险与注意事项 - **内存**:权重在堆外(native),进程 RSS 约 +2.5~3GB;首次加载 20~60 秒 - **CPU 速度**:表结构/短文本(几百 token)毫秒级~秒级;超长文本可通过 `max-seq-len` 控制 - **GPU**:本期 CPU;后续换 `onnxruntime_gpu` 依赖 + ExecutionProvider 配置即可,API 不变