9:大模型向量的使用

1. 三年前的"智能客服":以"推荐问题卡片"为中心的交互范式

大约在 2023 年前后(以 2026 年回看约三年前),多数企业平台的"智能客服"已经成为标配。但当时的智能客服形态与今天的"自然对话式 Agent"不完全一样,典型产品打开后,会出现类似截图所示的对话框首页

  • 左侧是"了解产品"一类的分类入口
  • 右侧是"推荐解决方案"一类的引导入口
  • 每个入口下方给出若干条高频问题(FAQ/场景问题)
  • 用户点击任意一条问题,系统会自动在对话窗口中展示一段标准答案,并可继续引导下一步操作

这种设计在当时非常常见,原因很现实:

  1. 降低用户输入成本:用户不需要组织语言,点一下就能得到结果。
  2. 降低系统理解难度:后台可以把点击行为直接映射到"固定意图(Intent)/固定答案"。
  3. 风险更可控:输出来自知识库的标准内容,避免"自由生成"导致不一致或不合规。
  4. 运营更容易:产品经理可以通过后台配置卡片与答案,做 A/B、调整排序、做热点问题运营。

但随着业务复杂度上升,这类"卡片式 FAQ"会遇到一个瓶颈:用户真实表达往往不是标准问题,而是自然语言的"变体"。


2. 为什么必须引入向量(Embedding):因为用户表达是自然语言的"海量变体"

当用户不点卡片、而是直接输入时,问题就来了:

  • "ECS 有什么优势?"
  • "云服务器性能怎么样?"
  • "我想上云买主机,怎么选?"
  • "弹性计算适合什么场景?"

它们本质上可能指向同一类知识,但字面差异很大。

如果你仍然用三年前常见的做法(关键词匹配/正则/简单意图分类),会出现典型问题:

  1. 同义表达覆盖困难:需要维护大量词典与规则。
  2. 语序与口语化导致命中率下降:用户一句话里掺杂背景、抱怨、目标。
  3. 长文本与多意图难处理:一句话包含多个诉求,规则体系容易崩。
  4. 冷启动成本高:新产品、新功能上线,规则与训练集需要重新积累。

而 Embedding 的价值在于:

它把自然语言映射为高维向量,使"语义相似"变成可计算的距离(比如余弦相似度)。

于是后台可以从"字符串相等/关键词命中"升级为:

输入问题 → 向量化 → 与知识库问题/段落向量做相似度检索 → 返回最相关的答案

这一步,就是从"卡片式智能客服"走向"语义检索式智能客服"的关键拐点。


3. 从"卡片点击直出答案"到"语义检索返回答案":系统结构怎么变

你可以这样描述演进路径(非常贴合实际落地):

  • 阶段 A:纯卡片/纯意图

    • 点击卡片 = 命中固定意图 = 返回固定答案
  • 阶段 B:卡片 + 文本输入,但规则匹配为主

    • 用户输入 → 关键词/规则 → 命中 FAQ 条目
  • 阶段 C:Embedding 驱动的语义检索(你这段代码对应的能力)

    • 用户输入 → Embedding → TopK 相似问题/相似段落 → 返回答案/拼接上下文
  • 阶段 D:RAG/对话式生成

    • 在阶段 C 的基础上,把召回内容交给 LLM 进行更自然的组织与回答(同时保留引用与可追溯)

你的代码正好就是阶段 C 的"最小闭环 Demo"。


4. 代码引入:Embedding 相似度检索 Demo(C#)

C# 复制代码
using System.ClientModel;
using OpenAI;
using OpenAI.Embeddings;

Console.WriteLine("=== Embedding Similarity Demo ===\n");

//var apiKey = Environment.GetEnvironmentVariable("AI__EmbeddingApiKey");
var apiKey = "*****************************";
var endpoint =
     // "https://personalopenai1.openai.azure.com/openai/v1/"; 
     "https://dashscope.aliyuncs.com/compatible-mode/v1/";
//var deploymentName = "text-embedding-3-large";
var deploymentName = "text-embedding-v4";

if (string.IsNullOrEmpty(apiKey))
{
    Console.WriteLine("Error: AI__EmbeddingApiKey environment variable not set.");
    return;
}

// Initialize embedding client
var openAiClient = new OpenAIClient(
    new ApiKeyCredential(apiKey),
    new OpenAIClientOptions { Endpoint = new Uri(endpoint) }
);
var embeddingClient = openAiClient.GetEmbeddingClient(deploymentName);

// Sample texts on different topics
var sampleTexts = new[]
{
    "C# 是一种在数据科学和机器学习领域广泛使用的编程语言。",
    "我喜欢用新鲜的番茄和罗勒来烹饪意大利面。",
    "这场足球比赛非常精彩,最终比分是 3 比 2。",
    "机器学习算法可以在大型数据集中识别模式。",
    "这个食谱需要两杯面粉和三个鸡蛋。",
    "篮球运动需要良好的协调能力和团队合作精神。",
    "神经网络的设计灵感来源于生物大脑结构。",
    "在家烘焙面包需要耐心以及合适的温度。",
    "这支足球队经过数月训练后赢得了冠军。",
    "深度学习已经彻底改变了计算机视觉和自然语言处理领域。"
};

Console.WriteLine("Generating embeddings for sample texts...\n");

// Generate and store embeddings
var textEmbeddings = new List<(string text, float[] embedding)>();

foreach (var text in sampleTexts)
{
    ClientResult<OpenAIEmbedding> embeddingResult = await embeddingClient.GenerateEmbeddingAsync(text);
    float[] embedding = embeddingResult.Value.ToFloats().ToArray();
    textEmbeddings.Add((text, embedding));
    Console.WriteLine($"✓ {text}");
}

Console.WriteLine(
    $"\nStored {textEmbeddings.Count} text embeddings (dimension: {textEmbeddings[0].embedding.Length})\n");

// Interactive query loop
while (true)
{
    Console.WriteLine("\n" + new string('-', 70));
    Console.Write("Enter your query (or 'quit' to exit): ");
    var query = Console.ReadLine();

    if (string.IsNullOrWhiteSpace(query) || query.ToLower() == "quit")
    {
        Console.WriteLine("Goodbye!");
        break;
    }

    Console.WriteLine($"\nSearching for: \"{query}\"");
    Console.WriteLine("Generating query embedding...");

    // Generate embedding for query
    var queryEmbeddingResult = await embeddingClient.GenerateEmbeddingAsync(query);
    var queryEmbedding = queryEmbeddingResult.Value.ToFloats().ToArray();
    Console.WriteLine(queryEmbedding.Length);
    Console.WriteLine(string.Join(',', queryEmbedding));
    // Calculate similarities
    var similarities = new List<(string text, double similarity)>();

    foreach (var (text, embedding) in textEmbeddings)
    {
        var similarity = CalculateCosineSimilarity(queryEmbedding, embedding);
        similarities.Add((text, similarity));
    }

    // Sort by similarity (highest first)
    var topResults = similarities.OrderByDescending(x => x.similarity).Take(3).ToList();

    Console.WriteLine("\nTop 3 Most Similar Texts:");
    Console.WriteLine(new string('=', 70));

    for (int i = 0; i < topResults.Count; i++)
    {
        var (text, similarity) = topResults[i];
        Console.WriteLine($"\n{i + 1}. Similarity: {similarity:F4} ({similarity * 100:F2}%)");
        Console.WriteLine($"   Text: {text}");
    }
}

// Helper function to calculate cosine similarity
static double CalculateCosineSimilarity(float[] vector1, float[] vector2)
{
    if (vector1.Length != vector2.Length)
    {
        throw new ArgumentException("Vectors must have the same dimension");
    }

    double dotProduct = 0;
    double magnitude1 = 0;
    double magnitude2 = 0;

    for (int i = 0; i < vector1.Length; i++)
    {
        dotProduct += vector1[i] * vector2[i];
        magnitude1 += vector1[i] * vector1[i];
        magnitude2 += vector2[i] * vector2[i];
    }

    magnitude1 = Math.Sqrt(magnitude1);
    magnitude2 = Math.Sqrt(magnitude2);

    if (magnitude1 == 0 || magnitude2 == 0)
    {
        return 0;
    }

    return dotProduct / (magnitude1 * magnitude2);
}
相关推荐
Java后端的Ai之路9 分钟前
【AI大模型开发】-AI 大模型原理深度解析与 API 实战(建议收藏!!!)
人工智能·ai·科普·ai大模型·llm大模型
一切尽在,你来18 分钟前
1.3 环境搭建
人工智能·ai·langchain·ai编程
AI绘画哇哒哒9 小时前
【干货收藏】深度解析AI Agent框架:设计原理+主流选型+项目实操,一站式学习指南
人工智能·学习·ai·程序员·大模型·产品经理·转行
程序设计实验室9 小时前
AMD显卡也能畅玩AI画图!ROCm+ComfyUI部署全指南
ai·ai画图
bruce_哈哈哈12 小时前
Claude Code--Feishu-Skill-demo
ai
User_芊芊君子13 小时前
HCCL高性能通信库编程指南:构建多卡并行训练系统
人工智能·游戏·ai·agent·测评
慢半拍iii13 小时前
对比源码解读:ops-nn中卷积算子的硬件加速实现原理
人工智能·深度学习·ai·cann
慢半拍iii13 小时前
CANN算子开发实战:手把手教你基于ops-nn仓库编写Broadcast广播算子
人工智能·计算机网络·ai
User_芊芊君子14 小时前
CANN数学计算基石ops-math深度解析:高性能科学计算与AI模型加速的核心引擎
人工智能·深度学习·神经网络·ai
程序员泠零澪回家种桔子14 小时前
Spring AI框架全方位详解
java·人工智能·后端·spring·ai·架构