Ollama配置Qwen3-Embedding-8B

🎨 Class Qwen3: 多模态对话视觉黑板报

Class Qwen3: 多模态对话视觉黑板报 是一款将顶尖视觉大模型 (Qwen3-VL) 与 怀旧动漫校园风 完美融合的 AI 对话终端。我们抛弃了传统 AI 工具厚重的控制面板,采用了类似于 DeepSeek 的极简布局,让您在清新、自然的黑板手绘氛围中,开启一段智能化的视觉探索之旅。

1.Qwen3-Embedding介绍

Qwen3-Embedding嵌入模型是 Qwen 系列的最新(2025年6月)专有模型,专为文本嵌入和排序任务而设计。该系列基于 Qwen3 系列的密集基础模型,提供了全面的文本嵌入和重排序模型,支持各种规模(0.6B、4B 和 8B)。Qwen3嵌入模型继承了基础模型卓越的多语言能力、长文本理解和推理能力。Qwen3 嵌入模型系列在文本检索、代码检索、文本分类、文本聚类和双文本挖掘等多项文本嵌入和排序任务方面取得了显著进展。

越的多功能性:嵌入模型在广泛的下游应用评估中取得了卓越的性能。8B 大小的嵌入模型在 MTEB 多语言排行榜中排名第一(截至 2025 年 6 月 5 日,得分70.58),而重排序模型在各种文本检索场景中表现出色。

全面的灵活性:Qwen3 Embedding 系列为 Embedding 和 Reranking 模型提供了从 0.6B 到 8B 的全尺寸范围,可满足注重效率和有效性的各种用例。开发者可以无缝组合这两个模块。此外,Embedding 模型允许在所有维度上灵活地定义向量,Embedding 和 Reranking 模型均支持用户自定义指令,以增强特定任务、语言或场景的性能。

多语言功能:得益于 Qwen3 模型的多语言功能,Qwen3 嵌入式系列支持超过 100 种语言。这涵盖了各种编程语言,并提供强大的多语言、跨语言和代码检索功能。

Qwen3-Embedding-8B具有以下特点:

模型类型:文本嵌入
支持的语言:100多种语言
参数数量:8B
上下文长度:32k
嵌入维度:最大支持4096,支持32~4096自定义输出维度

2.Ollama部署模型

2.1 Ollama下载

1)Github 下载安装

https://github.com/ollama/ollama/

下载 OllamaSetup.exe

双击 OllamaSetup.exe,直接点击“install”按钮即可,一般默认安装到C盘。

安装好后,Ollama 界面如下

在cmd查看是否安装成功,输入“ollama --version”

表示安装成功

终端调用

2.2 模型调用 基于Python sdk

首先本地启动ollama server

ollama serve

ollama show dengcao/qwen3-embedding-8b:q5_k_m
  Model
    architecture        qwen3
    parameters          7.6B
    context length      40960
    embedding length    4096
    quantization        Q5_K_M

  Capabilities
    completion
    tools
    thinking

  Parameters
    repeat_penalty    1
    stop              "<|im_start|>"
    stop              "<|im_end|>"
    temperature       0.6
    top_k             20
    top_p             0.95

  License
    Apache License
    Version 2.0, January 2004
    ...

Qwen3-Embedding-8B "model does not support embeddings" · Issue #12757 · ollama/ollama

在python虚拟环境安装ollama库

pip install ollama

通过 request 调用

import requests
import json


def generate_embedding_api(text: str, model_name: str = "dengcao/Qwen3-Embedding-8B:Q4_K_M") -> list[float]:
    base_url = "http://localhost:11434/api"
    endpoint = f"{base_url}/embed"

    payload = {"model": model_name, "input": text}

    try:
        # 关键改动:添加 proxies 参数,禁用此请求的代理
        response = requests.post(endpoint, json=payload, proxies={"http": None, "https": None})  # <--- 在这里禁用代理

        response.raise_for_status()  # 如果请求失败(如404、500),会抛出异常

        data = response.json()
        return data["embeddings"]

    except requests.exceptions.RequestException as e:
        print(f"调用 API 时发生错误: {e}")
        return []


# --- 示例用法 ---
if __name__ == "__main__":
    sample_text = "向量数据库是存储和检索高维向量的专用数据库。"

    print(f"正在通过 API 为文本生成嵌入向量: '{sample_text}'")

    embedding_vector = generate_embedding_api(sample_text)

    if embedding_vector:
        print("\n成功生成嵌入向量!")
        print(f"嵌入向量 (前 10 个值): {embedding_vector[0][:10]}")
        print(f"向量维度: {len(embedding_vector[0])}")

调整输出的向量维度

输出:

正在通过 API 为文本生成嵌入向量: '向量数据库是存储和检索高维向量的专用数据库。'

成功生成嵌入向量!
嵌入向量 (前 10 个值): [0.018521862, -0.0074915513, 0.0005131165, -0.028763987, -0.008424981, 0.012031712, -0.029843202, 0.004524749, 0.036058832, 0.008791029]
向量维度: 4096

3.lightRAG

import os
import asyncio
import inspect
import logging
import logging.config
import requests
import json
from lightrag import LightRAG, QueryParam
from lightrag.llm.openai import openai_complete_if_cache
from lightrag.llm.openai import openai_embed
from lightrag.utils import EmbeddingFunc, logger, set_verbose_debug
from lightrag.kg.shared_storage import initialize_pipeline_status

from dotenv import load_dotenv

load_dotenv(dotenv_path=".env", override=False)

WORKING_DIR = "LightRAG\\myproject\\demo\\dickens_2"

# 配置您的API密钥
LLM_API_KEY = os.getenv("LLM_BINDING_API_KEY", "xxxxxxxxxxxxxxxxxxxxxxxxxx")  # 大模型API密钥


# 大模型API配置
LLM_API_URL = os.getenv(
    "LLM_BINDING_HOST",
    "大模型api",
)
LLM_MODEL = os.getenv("LLM_MODEL", "Qwen3-32B")

EMBEDDING_API_URL = os.getenv(
    "EMBEDDING_BINDING_HOST",
    "http://localhost:11434/api/embed",
)
EMBEDDING_MODEL = "dengcao/Qwen3-Embedding-8B:Q4_K_M"


class TokenTracker:
    """Token消耗跟踪器"""

    def __init__(self):
        self.token_usage = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
        self._initial_usage = self.token_usage.copy()

    def add_usage(self, usage_dict):
        """添加token使用量"""
        self.token_usage["prompt_tokens"] += usage_dict.get("prompt_tokens", 0)
        self.token_usage["completion_tokens"] += usage_dict.get("completion_tokens", 0)
        self.token_usage["total_tokens"] += usage_dict.get("total_tokens", 0)

    def get_usage(self):
        """获取累计的token使用量"""
        return self.token_usage.copy()

    def reset(self):
        """重置token使用量统计"""
        self.token_usage = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
        self._initial_usage = self.token_usage.copy()

    def __enter__(self):
        """上下文管理器入口"""
        self.reset()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        print(f"\n=== Token使用统计 ===")
        print(f"Prompt tokens: {self.token_usage['prompt_tokens']}")
        print(f"Completion tokens: {self.token_usage['completion_tokens']}")
        print(f"Total tokens: {self.token_usage['total_tokens']}")
        print("====================\n")
        return False


# 创建全局TokenTracker实例
token_tracker = TokenTracker()


def configure_logging():
    """Configure logging for the application"""

    # Reset any existing handlers to ensure clean configuration
    for logger_name in ["uvicorn", "uvicorn.access", "uvicorn.error", "lightrag"]:
        logger_instance = logging.getLogger(logger_name)
        logger_instance.handlers = []
        logger_instance.filters = []

    # Get log directory path from environment variable or use current directory
    log_dir = os.getenv("LOG_DIR", os.getcwd())
    log_file_path = os.path.abspath(os.path.join(log_dir, "lightrag_compatible_demo_2.log"))

    print(f"\nLightRAG compatible demo log file: {log_file_path}\n")
    os.makedirs(os.path.dirname(log_dir), exist_ok=True)

    # Get log file max size and backup count from environment variables
    log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760))  # Default 10MB
    log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5))  # Default 5 backups

    logging.config.dictConfig(
        {
            "version": 1,
            "disable_existing_loggers": False,
            "formatters": {
                "default": {
                    "format": "%(levelname)s: %(message)s",
                },
                "detailed": {
                    "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
                },
            },
            "handlers": {
                "console": {
                    "formatter": "default",
                    "class": "logging.StreamHandler",
                    "stream": "ext://sys.stderr",
                },
                "file": {
                    "formatter": "detailed",
                    "class": "logging.handlers.RotatingFileHandler",
                    "filename": log_file_path,
                    "maxBytes": log_max_bytes,
                    "backupCount": log_backup_count,
                    "encoding": "utf-8",
                },
            },
            "loggers": {
                "lightrag": {
                    "handlers": ["console", "file"],
                    "level": "INFO",
                    "propagate": False,
                },
            },
        }
    )

    # Set the logger level to INFO
    logger.setLevel(logging.INFO)
    # Enable verbose debug if needed
    set_verbose_debug(os.getenv("VERBOSE_DEBUG", "false").lower() == "true")


if not os.path.exists(WORKING_DIR):
    os.mkdir(WORKING_DIR)


async def llm_model_func(prompt, system_prompt=None, history_messages=[], keyword_extraction=False, **kwargs) -> str:
    """
    使用自定义API调用大模型
    """
    headers = {"Content-Type": "application/json", "Authorization": f"Bearer {LLM_API_KEY}"}

    messages = []
    if system_prompt:
        messages.append({"role": "system", "content": system_prompt})
    messages.extend(history_messages)
    messages.append({"role": "user", "content": prompt})

    payload = {
        "model": LLM_MODEL,
        "stream": False,
        "temperature": 0.6,
        "chat_template_kwargs": {"enable_thinking": True},
        "messages": messages,
    }

    try:
        response = requests.post(LLM_API_URL, headers=headers, data=json.dumps(payload))
        response.raise_for_status()

        result = response.json()
        if "choices" in result and len(result["choices"]) > 0:
            # 尝试提取token使用信息
            usage_info = result.get("usage", {})
            token_counts = {
                "prompt_tokens": usage_info.get("prompt_tokens", 0),
                "completion_tokens": usage_info.get("completion_tokens", 0),
                "total_tokens": usage_info.get("total_tokens", 0),
            }

            # 添加到token追踪器
            token_tracker.add_usage(token_counts)

            return result["choices"][0]["message"]["content"]
        else:
            raise Exception("Invalid response format from LLM API")
    except requests.exceptions.RequestException as e:
        logger.error(f"LLM API调用失败: {e}")
        raise
    except json.JSONDecodeError as e:
        logger.error(f"解析LLM响应JSON失败: {e}")
        raise
    except Exception as e:
        logger.error(f"处理LLM响应时出错: {e}")
        raise


async def embedding_func(texts):
    """
    使用自定义API调用Embedding模型
    """
    headers = {"Content-Type": "application/json"}

    payload = {"model": EMBEDDING_MODEL, "input": texts}

    try:
        response = requests.post(EMBEDDING_API_URL, headers=headers, data=json.dumps(payload))
        response.raise_for_status()

        result = response.json()
        if "embeddings" in result:
            # 提取嵌入向量
            embeddings = result["embeddings"]
            import numpy as np

            return np.array(embeddings, dtype=np.float32)
        else:
            raise Exception("Invalid response format from Embedding API")
    except requests.exceptions.RequestException as e:
        logger.error(f"Embedding API调用失败: {e}")
        raise
    except json.JSONDecodeError as e:
        logger.error(f"解析Embedding响应JSON失败: {e}")
        raise
    except Exception as e:
        logger.error(f"处理Embedding响应时出错: {e}")
        raise


async def print_stream(stream):
    async for chunk in stream:
        if chunk:
            print(chunk, end="", flush=True)


async def initialize_rag():
    rag = LightRAG(
        working_dir=WORKING_DIR,
        llm_model_func=llm_model_func,
        embedding_func=EmbeddingFunc(
            embedding_dim=int(os.getenv("EMBEDDING_DIM", "4096")),  # 修改为4096以匹配Qwen3-Embedding-8B模型
            max_token_size=int(os.getenv("MAX_EMBED_TOKENS", "8192")),
            func=embedding_func,
        ),
        addon_params={
            "language": "Simplified Chinese",
        },
    )

    await rag.initialize_storages()
    await initialize_pipeline_status()

    return rag


async def main():
    try:
        # Clear old data files
        files_to_delete = [
            "graph_chunk_entity_relation.graphml",
            "kv_store_doc_status.json",
            "kv_store_full_docs.json",
            "kv_store_text_chunks.json",
            "vdb_chunks.json",
            "vdb_entities.json",
            "vdb_relationships.json",
        ]

        for file in files_to_delete:
            file_path = os.path.join(WORKING_DIR, file)
            if os.path.exists(file_path):
                os.remove(file_path)
                print(f"Deleting old file:: {file_path}")

        # Initialize RAG instance
        rag = await initialize_rag()

        # Test embedding function
        test_text = ["This is a test string for embedding."]
        embedding = await rag.embedding_func(test_text)
        embedding_dim = embedding.shape[1]
        print("\n=======================")
        print("Test embedding function")
        print("========================")
        print(f"Test dict: {test_text}")
        print(f"Detected embedding dimension: {embedding_dim}\n\n")

        with open("book.txt", "r", encoding="utf-8") as f:
            await rag.ainsert(f.read())

        # 使用TokenTracker上下文管理器来跟踪查询过程中的token消耗
        with token_tracker:
            # Perform naive search
            print("\n=====================")
            print("Query mode: naive")
            print("=====================")
            resp = await rag.aquery(
                "养心推荐哪几种草药?",
                param=QueryParam(mode="naive", stream=True),
            )
            if inspect.isasyncgen(resp):
                await print_stream(resp)
            else:
                print(resp)

            # Perform local search
            print("\n=====================")
            print("Query mode: local")
            print("=====================")
            resp = await rag.aquery(
                "养心推荐哪几种草药?",
                param=QueryParam(mode="local", stream=True),
            )
            if inspect.isasyncgen(resp):
                await print_stream(resp)
            else:
                print(resp)

            # Perform global search
            print("\n=====================")
            print("Query mode: global")
            print("=====================")
            resp = await rag.aquery(
                "养心推荐哪几种草药?",
                param=QueryParam(mode="global", stream=True),
            )
            if inspect.isasyncgen(resp):
                await print_stream(resp)
            else:
                print(resp)

            # Perform hybrid search
            print("\n=====================")
            print("Query mode: hybrid")
            print("=====================")
            resp = await rag.aquery(
                "养心推荐哪几种草药?",
                param=QueryParam(mode="hybrid", stream=True),
            )
            if inspect.isasyncgen(resp):
                await print_stream(resp)
            else:
                print(resp)
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        if "rag" in locals():
            await rag.finalize_storages()


if __name__ == "__main__":
    # Configure logging before running the main function
    configure_logging()
    asyncio.run(main())
    print("\nDone!")

LightRAG ollama线程数

LightRAG\lightrag\llm\binding_options.py 处修改

Ollama暂不支持reranker模型

dengcao/Qwen3-Reranker-8B

您可能感兴趣的与本文相关的镜像

🎨 Class Qwen3: 多模态对话视觉黑板报

🎨 Class Qwen3: 多模态对话视觉黑板报

图文对话
Qwen
Qwen3

Class Qwen3: 多模态对话视觉黑板报 是一款将顶尖视觉大模型 (Qwen3-VL) 与 怀旧动漫校园风 完美融合的 AI 对话终端。我们抛弃了传统 AI 工具厚重的控制面板,采用了类似于 DeepSeek 的极简布局,让您在清新、自然的黑板手绘氛围中,开启一段智能化的视觉探索之旅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值