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);
}
相关推荐
自己的九又四分之三站台3 小时前
7:大模型资源汇总
ai
毅炼4 小时前
hot100打卡——day14
java·数据结构·算法·leetcode·ai·深度优先·哈希算法
chao_6666666 小时前
Claude Code for vscode 新手入门完整教程
ide·vscode·ai·编辑器·ai编程·claude
GitCode官方7 小时前
openPangu-VL-7B:专为生产线而生的视觉语言多模态模型
ai·开源·atomgit
大海梦想7 小时前
在Trae中使用Pencil MCP
ai·大模型·trae·vibe design·pencil
OceanBase数据库官方博客8 小时前
深度解读 OceanBase 多模一体化能力
数据库·ai·oceanbase·分布式数据库
程序员鱼皮9 小时前
Agent Skills 傻瓜式教程,26 年最火 AI 技术就这?
计算机·ai·程序员·agent·编程经验
DS随心转APP10 小时前
怎么导出豆包聊天记录
人工智能·ai·豆包·deepseek·ds随心转
16Miku10 小时前
使用Gemini3Pro+NanoBananaPro制作高级PPT
ai·ai制作ppt·nanobananapro·gemini3pro