Qdrant

decade
11
2025-12-24
using System;
using System.ClientModel;
using Microsoft.Extensions.AI;
using OpenAI;
using Qdrant.Client;
using Qdrant.Client.Grpc;

namespace AIRag;

class Program
{
    const string CollectionName = "rag_demo";
    const int VectorSize = 4096;

    static async Task Main(string[] args)
    {
        // ===== Embedding 配置 =====
        string baseUrl = "https://api.siliconflow.cn/v1";
        string apiKey = "sk-pijgepyzxgbsgsvqajnochdixnmzpnvrtbjuttknjsvmtzje";
        string model = "Qwen/Qwen3-Embedding-8B";

        OpenAIClientOptions clientOptions = new()
        {
            Endpoint = new Uri(baseUrl)
        };

        OpenAIClient aiClient =
            new(new ApiKeyCredential(apiKey), clientOptions);

        var embeddingClient = aiClient.GetEmbeddingClient(model);
        IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator =
            embeddingClient.AsIEmbeddingGenerator();

        // ===== Qdrant =====
        var qdrant = new QdrantClient("localhost", 6334);

        await EnsureCollectionAsync(qdrant);

        Console.WriteLine("请选择模式:");
        Console.WriteLine("1 - 存储文本");
        Console.WriteLine("2 - 搜索相似文本 (Top 3)");
        Console.Write("输入 1 或 2:");

        var mode = Console.ReadLine();

        if (mode == "1")
        {
            Console.Write("请输入要存储的文本:");
            var text = Console.ReadLine();

            var vector = await embeddingGenerator.GenerateVectorAsync(text);

            await qdrant.UpsertAsync(
                collectionName: CollectionName,
                points: new[]
                {
                    new PointStruct
                    {
                        Id = Guid.NewGuid(),   // ✅ 正确
                        Vectors = vector.ToArray(),
                        Payload =
                        {
                            ["text"] = text
                        }
                    }
                });

            Console.WriteLine("✅ 已成功存储向量与文本");
        }
        else if (mode == "2")
        {
            Console.Write("请输入查询文本:");
            var query = Console.ReadLine();

            var queryVector =
                await embeddingGenerator.GenerateVectorAsync(query);

            var result = await qdrant.SearchAsync(
                collectionName: CollectionName,
                vector: queryVector.ToArray(),
                limit: 3);

            Console.WriteLine("\n🔍 相似结果:");

            foreach (var point in result)
            {
                var text = point.Payload.TryGetValue("text", out var v)
                    ? v.StringValue
                    : "(无文本)";

                Console.WriteLine($"Score: {point.Score:F4}");
                Console.WriteLine($"Text : {text}");
                Console.WriteLine(new string('-', 40));
            }
        }
        else
        {
            Console.WriteLine("❌ 无效模式");
        }
    }

    /// <summary>
    /// 如果 collection 不存在就创建
    /// </summary>
    static async Task EnsureCollectionAsync(QdrantClient client)
    {
        bool exists = await client.CollectionExistsAsync(CollectionName);

        if (exists)
            return;

        await client.CreateCollectionAsync(
            collectionName: CollectionName,
            vectorsConfig: new VectorParams
            {
                Size = VectorSize,
                Distance = Distance.Cosine
            });

        Console.WriteLine($"📦 已创建 collection: {CollectionName}");
    }
}