冠军

导航

基于本地 Llama 生成 .NET AI 矢量搜索应用

本文使用运行在本地的 llama 来实现 AI 向量搜索。它使用 OllamaSharp 访问本地的 llama 中运行的模型。

注意:OllamaSharp 5.2.3 可以工作, 但是 OllamaSharp 5.0.4 不行。
会抛出异常:System.MissingMethodException: Method not found: 'Microsoft.Extensions.AI.ChatClientMetadata Microsoft.Extensions.AI.IChatClient.get_Metadata()'.

先决条件

  • .NET 8.0 SDK 或者更高版本

使用的 NuGet 包

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.6.0" />
  <PackageReference Include="Microsoft.Extensions.VectorData.Abstractions" Version="9.6.0" />
  <PackageReference Include="Microsoft.SemanticKernel.Connectors.InMemory" Version="1.58.0-preview" />
  <PackageReference Include="OllamaSharp" Version="5.2.3" />
  <PackageReference Include="System.Linq.AsyncEnumerable" Version="10.0.0-preview.5.25277.114" />
</ItemGroup>

创建应用

1. 创建控制台应用

dotnet new console -o VectorDataAI

2. 将应用目录设为当前目录

cd VectorDataAI

3. 安装所需的 NuGet 包

dotnet add package Microsoft.Extensions.AI.Abstractions
dotnet add package Microsoft.Extensions.VectorData.Abstractions
dotnet add package Microsoft.SemanticKernel.Connectors.InMemory --prerelease
dotnet add package OllamaSharp
dotnet add package System.Linq.AsyncEnumerable --prerelease

示例所涉及的 NuGet 包:

  • Microsoft.Extensions.AI.Abstractions, 为大模型提供 AI 抽象
  • Microsoft.Extensions.VectorData.Abstractions, 启用对矢量存储的 Create-Read-Update-Delete (CRUD) 和搜索操作
  • OllamaSharp, 提供针对 Ollama 的实现支持
  • Microsoft.SemanticKernel.Connectors.InMemory, 供内存中矢量存储类来保存可查询矢量数据记录。

编写代码

1. 创建数据映射类

创建 CloudService.cs 代码文件,其中定义了数据映射。

using Microsoft.Extensions.VectorData;

namespace VectorDataAI;

internal class CloudService
{
    [VectorStoreKey]
    public int Key { get; set; }

    [VectorStoreData]
    public string Name { get; set; }

    [VectorStoreData]
    public string Description { get; set; }

    [VectorStoreVector(
        Dimensions: 384,
        DistanceFunction = DistanceFunction.CosineSimilarity)]
    public ReadOnlyMemory<float> Vector { get; set; }
}

这里的 VectorStoreVector 特性标志用来存储生成的向量,它表示 Description 中文本的语义含义。

2. 创建示例数据

List<CloudService> cloudServices =
[
    new() {
            Key = 0,
            Name = "Azure App Service",
            Description = "Host .NET, Java, Node.js, and Python web applications and APIs in a fully managed Azure service. You only need to deploy your code to Azure. Azure takes care of all the infrastructure management like high availability, load balancing, and autoscaling."
    },
    new() {
            Key = 1,
            Name = "Azure Service Bus",
            Description = "A fully managed enterprise message broker supporting both point to point and publish-subscribe integrations. It's ideal for building decoupled applications, queue-based load leveling, or facilitating communication between microservices."
    },
    new() {
            Key = 2,
            Name = "Azure Blob Storage",
            Description = "Azure Blob Storage allows your applications to store and retrieve files in the cloud. Azure Storage is highly scalable to store massive amounts of data and data is stored redundantly to ensure high availability."
    },
    new() {
            Key = 3,
            Name = "Microsoft Entra ID",
            Description = "Manage user identities and control access to your apps, data, and resources."
    },
    new() {
            Key = 4,
            Name = "Azure Key Vault",
            Description = "Store and access application secrets like connection strings and API keys in an encrypted vault with restricted access to make sure your secrets and your application aren't compromised."
    },
    new() {
            Key = 5,
            Name = "Azure AI Search",
            Description = "Information retrieval at scale for traditional and conversational search applications, with security and options for AI enrichment and vectorization."
    }
];

3. 基于 OllamaSharp 创建使用 Ollama 的向量生成器实例

OllamaApiClient 实现了 3 个接口:

  • IOllamaApiClient
  • IChatClient
  • IEmbeddingGenerator<string, Embedding>

可以直接将 OllamaApiClient 转型为 IEmbeddingGenerator<string, Embedding> 引用。

var uri = "http://localhost:11434";
string model = "deepseek-r1:1.5b";

var client = new OllamaApiClient(uri, model);

// Create the embedding generator.
IEmbeddingGenerator<string, Embedding<float>> generator =
            client as IEmbeddingGenerator<string, Embedding<float>>;

Console.WriteLine($"Using Ollama API at {uri} with model {model}");

4. 使用向量生成器创建并存储向量

首先,创建内存中的向量存储。然后,在内存中的向量存储中创建名为 cloudServices 的向量集合。
最后,使用向量生成器将 Description 中内容向量化并存储。

// Create and populate the vector store.
var vectorStore = new InMemoryVectorStore();
VectorStoreCollection<int, CloudService> cloudServicesStore =
    vectorStore.GetCollection<int, CloudService>("cloudServices");
await cloudServicesStore.EnsureCollectionExistsAsync();

foreach (CloudService service in cloudServices)
{
    service.Vector = await generator.GenerateVectorAsync(service.Description);
    await cloudServicesStore.UpsertAsync(service);
}

5. 在创建的向量上执行向量搜索

// Convert a search query to a vector
// and search the vector store.
string query = "Which Azure service should I use to store my Word documents?";
Console.WriteLine($"Querying: {query}");
ReadOnlyMemory<float> queryEmbedding = await generator.GenerateVectorAsync(query);

IAsyncEnumerable<VectorSearchResult<CloudService>> results =
            cloudServicesStore.SearchAsync(queryEmbedding, top: 1);

await foreach (VectorSearchResult<CloudService> result in results)
{
    Console.WriteLine($"Name: {result.Record.Name}");
    Console.WriteLine($"Description: {result.Record.Description}");
    Console.WriteLine($"Vector match score: {result.Score}");
}

6. 执行程序

> dotnet run
Hello, World!
Using Ollama API at http://localhost:11434 with model deepseek-r1:1.5b
Querying: Which Azure service should I use to store my Word documents?
Name: Microsoft Entra ID
Description: Manage user identities and control access to your apps, data, and resources.
Vector match score: 0.8528178930282593

完整代码

using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using VectorDataAI;
using OllamaSharp;
using OllamaSharp.Models;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.InMemory;

// See https://aka.ms/new-console-template for more information
class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Hello, World!");

        List<CloudService> cloudServices = new List<CloudService>
        {
            new() {
                Key = 0,
                Name = "Azure App Service",
                Description = "Host .NET, Java, Node.js, and Python web applications and APIs in a fully managed Azure service. You only need to deploy your code to Azure. Azure takes care of all the infrastructure management like high availability, load balancing, and autoscaling."
            },
            new() {
                Key = 1,
                Name = "Azure Service Bus",
                Description = "A fully managed enterprise message broker supporting both point to point and publish-subscribe integrations. It's ideal for building decoupled applications, queue-based load leveling, or facilitating communication between microservices."
            },
            new() {
                Key = 2,
                Name = "Azure Blob Storage",
                Description = "Azure Blob Storage allows your applications to store and retrieve files in the cloud. Azure Storage is highly scalable to store massive amounts of data and data is stored redundantly to ensure high availability."
            },
            new() {
                Key = 3,
                Name = "Microsoft Entra ID",
                Description = "Manage user identities and control access to your apps, data, and resources."
            },
            new() {
                Key = 4,
                Name = "Azure Key Vault",
                Description = "Store and access application secrets like connection strings and API keys in an encrypted vault with restricted access to make sure your secrets and your application aren't compromised."
            },
            new() {
                Key = 5,
                Name = "Azure AI Search",
                Description = "Information retrieval at scale for traditional and conversational search applications, with security and options for AI enrichment and vectorization."
            }
        };

        var uri = "http://localhost:11434";
        string model = "deepseek-r1:1.5b";

        var client = new OllamaApiClient(uri, model);

        // Create the embedding generator.
        IEmbeddingGenerator<string, Embedding<float>> generator =
            client as IEmbeddingGenerator<string, Embedding<float>>;

        Console.WriteLine($"Using Ollama API at {uri} with model {model}");

        // Create and populate the vector store.
        var vectorStore = new InMemoryVectorStore();
        VectorStoreCollection<int, CloudService> cloudServicesStore =
            vectorStore.GetCollection<int, CloudService>("cloudServices");
        await cloudServicesStore.EnsureCollectionExistsAsync();

        foreach (CloudService service in cloudServices)
        {
            service.Vector = await generator.GenerateVectorAsync(service.Description);
            await cloudServicesStore.UpsertAsync(service);
        }

        // Convert a search query to a vector
        // and search the vector store.
        string query = "Which Azure service should I use to store my Word documents?";
        Console.WriteLine($"Querying: {query}");
        ReadOnlyMemory<float> queryEmbedding = await generator.GenerateVectorAsync(query);

        IAsyncEnumerable<VectorSearchResult<CloudService>> results =
            cloudServicesStore.SearchAsync(queryEmbedding, top: 1);

        await foreach (VectorSearchResult<CloudService> result in results)
        {
            Console.WriteLine($"Name: {result.Record.Name}");
            Console.WriteLine($"Description: {result.Record.Description}");
            Console.WriteLine($"Vector match score: {result.Score}");
        }
    }
}

执行结果

Hello, World!
Using Ollama API at http://localhost:11434 with model deepseek-r1:1.5b
Querying: Which Azure service should I use to store my Word documents?
Name: Microsoft Entra ID
Description: Manage user identities and control access to your apps, data, and resources.
Vector match score: 0.8528178930282593

这个文档已经过时!
https://learn.microsoft.com/zh-cn/dotnet/ai/quickstarts/build-vector-search-app?pivots=openai

posted on 2025-06-28 19:01  冠军  阅读(72)  评论(0)    收藏  举报