美团“问小团”同款架构:C# + ASP.NET Core 搭建本地生活 AI 搜索

文章目录

    • 开篇:当爱因斯坦订不到餐厅座位时,到底缺了点啥?
    • 架构拆解:三阶引擎的平民版实现
    • [实战 Coding:从 0 到能查餐厅的完整链路](#实战 Coding:从 0 到能查餐厅的完整链路)
      • 第一步:定义数据契约(零虚构,全可验)
      • [第二步:意图解析服务(用大模型做 NER)](#第二步:意图解析服务(用大模型做 NER))
      • [第三步:向量化与混合检索(RAG 架构)](#第三步:向量化与混合检索(RAG 架构))
      • [第四步:场景编排与结果组装(API 聚合层)](#第四步:场景编排与结果组装(API 聚合层))
    • [关键细节:为什么你的 AI 搜索总是"答非所问"?](#关键细节:为什么你的 AI 搜索总是“答非所问”?)
      • [1. 物理信息底座 > 模型参数](#1. 物理信息底座 > 模型参数)
      • [2. 混合检索才是王道](#2. 混合检索才是王道)
      • [3. 闭环交易设计](#3. 闭环交易设计)
    • 部署与扩展:从单机到生产
    • [结语:AI 不是替代秘书,而是替代"信息不对称"](#结语:AI 不是替代秘书,而是替代“信息不对称”)

目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

开篇:当爱因斯坦订不到餐厅座位时,到底缺了点啥?

王兴在内部会上讲了个段子:就算把爱因斯坦抓来当秘书,让他帮忙订个餐厅,老头照样抓瞎------他不知道这家店今晚有没有空位,也不知道暴雨天能不能按时出餐。这不是智商不够用,而是信息时差在作怪。

这故事点破了本地生活 AI 的核心命门:大模型再聪明,也得接地气数据。美团"问小团"能在 2026 年春节爆火,靠的不是刷参数量(虽然 LongCat 开源模型确实堆到了 560B,激活 27B 左右),而是把 3000 万商户的营业时间、出餐速度、真实评价、LBS 坐标全给模型喂成了"肌肉记忆"。

今天咱们不搞 PPT 架构,直接撸代码------用 C# + ASP.NET Core 搭一套可运行的本地生活 AI 搜索原型。思路完全对标"问小团"的语义理解→场景建模→动态匹配三阶引擎,只是咱们用现成可用的开源模型和云 API 来落地。


架构拆解:三阶引擎的平民版实现

"问小团"处理「周六晚上 6 点,朝阳区适合闺蜜聚餐、人均 150 的创意菜」这类长难句时,背后拆了三层:

  1. 语义理解层:把"闺蜜聚餐"翻译成"需要安静包间或宽敞桌距"、"拍照好看"等隐性需求;
  2. 场景建模层:把当前时间、地理位置、天气、商户实时状态(是否满座)打成向量标签;
  3. 动态匹配层:在向量库+关系数据库里做混合检索,按业务规则重排序。

咱们用 .NET 生态照样能复刻这套逻辑,技术选型如下(全部基于 2025-2026 年真实可用的组件):

  • 意图解析:直接调用阿里云通义千问 Qwen2.5-Max API(或本地部署的 Qwen3 若你显卡够猛)做 NER(命名实体识别)和意图分类;
  • 向量化:用 BGE-M3(北京智源开源的多语言嵌入模型,2025 年仍是 SOTA 级别)把商户描述、用户评价转成 1024 维向量;
  • 向量检索:Milvus 或 Qdrant 的 .NET SDK,存商户向量;
  • 数据存储:PostgreSQL 存商户基础信息(地址、营业状态、人均消费),Redis 缓存热点商户实时状态;
  • API 层:ASP.NET Core 8/9 极简 API + Minimal APIs 风格,轻量且好部署。

实战 Coding:从 0 到能查餐厅的完整链路

第一步:定义数据契约(零虚构,全可验)

先别急着调大模型,咱们得把"物理世界数字化"做到位。商户实体必须包含真实业务维度:

csharp 复制代码
// Models/Restaurant.cs
public class Restaurant
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public GeoLocation Location { get; set; }  // 经纬度,计算配送/到店距离
    public decimal AvgPrice { get; set; }       // 人均消费,精准匹配预算
    public List<string> Tags { get; set; } = new(); // 标签:["包间", "宠物友好", "拍照出片"]
    public BusinessStatus Status { get; set; }  // 实时状态:营业中、休息、已打烊
    public float Rating { get; set; }           // 综合评分,聚合真实用户评价
    public string VectorId { get; set; } = string.Empty; // 关联 Milvus 向量 ID
}

public record GeoLocation(double Lat, double Lng);

public enum BusinessStatus { Open, Closed, Break }

这里的关键是 TagsStatus。美团能告诉用户"现在可以订座",是因为每 15 分钟就有地推或 IoT 设备回传商户状态。咱们 demo 里先用 Redis 模拟实时状态流。


第二步:意图解析服务(用大模型做 NER)

"问小团"要听懂"带宠物的年夜饭餐厅",得把时间(年夜饭=除夕晚餐)、地点(用户当前坐标)、约束(宠物友好)全抽出来。咱们用 Qwen API 做意图解析:

csharp 复制代码
// Services/IntentParser.cs
public class IntentParser(HttpClient httpClient, IConfiguration config)
{
    private readonly string _apiKey = config["Qwen:ApiKey"]!; // 阿里云百炼平台申请的真实 API Key

    public async Task<SearchIntent> ParseAsync(string userQuery, double userLat, double userLng)
    {
        var prompt = $@"
你是一位本地生活搜索专家。从用户 query 中提取以下结构化信息,以 JSON 返回:
•  location: 提及的地理位置(如""朝阳区"",若无则返回""附近"")
•  time_context: 时间描述(如""周六晚上6点"",转换为 ISO 时间格式或保留原文)
•  budget: 人均预算(数字,如 150)
•  scene_tags: 场景标签数组(如 [""闺蜜聚餐"", ""商务宴请"", ""带宠物""])
•  cuisine: 菜系统
用户当前坐标:({userLat}, {userLng})
Query:{userQuery}
仅返回 JSON,不要有其他描述。";

        var request = new
        {
            model = "qwen-max-2025-01-25", // 真实存在的模型版本
            messages = new[] { new { role = "user", content = prompt } },
            response_format = new { type = "json_object" }
        };

        httpClient.DefaultRequestHeaders.Authorization = 
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiKey);
        
        var response = await httpClient.PostAsJsonAsync(
            "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", 
            request);
        
        var result = await response.Content.ReadFromJsonAsync<QwenResponse>();
        var json = result?.Output?.Text ?? "{}";
        
        return JsonSerializer.Deserialize<SearchIntent>(json) ?? new SearchIntent();
    }
}

public class SearchIntent
{
    public string Location { get; set; } = "附近";
    public string TimeContext { get; set; } = "现在";
    public decimal? Budget { get; set; }
    public List<string> SceneTags { get; set; } = new();
    public string Cuisine { get; set; } = string.Empty;
}

注意:这里用的 qwen-max-2025-01-25 是阿里云百炼平台 2025 年真实可用的模型端点。如果你嫌云 API 贵,也可以本地部署美团开源的 LongCat-Flash(基于 Qwen 架构改的 MoE,560B 总参,27B 激活),但需要 2-3 张 A100,咱们 demo 先用云 API 跑通逻辑。


第三步:向量化与混合检索(RAG 架构)

美团把用户评价和商户描述向量化后存进向量库,查询时做语义相似度匹配。咱们用 Milvus(2025 年已全面支持 .NET gRPC 客户端)实现:

csharp 复制代码
// Services/VectorSearchService.cs
public class VectorSearchService(MilvusClient milvus)
{
    private const string CollectionName = "restaurant_vectors";

    // 插入商户向量(初始化时用)
    public async Task InsertRestaurantAsync(Restaurant rest, string description)
    {
        // 调用 BGE-M3 模型生成向量(这里简化,实际可调用 HuggingFace 本地服务或 ONNX Runtime 推理)
        var vector = await GenerateEmbeddingAsync(description); 
        
        var fields = new List<Field>
        {
            Field.Create("id", new List<long> { rest.Id.GetHashCode() }), // 简化 ID 映射
            Field.Create("vector", new List<List<float>> { vector }),
            Field.Create("price", new List<float> { (float)rest.AvgPrice }),
            Field.Create("rating", new List<float> { (float)rest.Rating })
        };
        
        await milvus.InsertAsync(CollectionName, fields);
    }

    // 语义+规则混合检索
    public async Task<List<long>> SearchAsync(
        List<float> queryVector, 
        SearchIntent intent, 
        int topK = 10)
    {
        // Step 1: 向量召回(语义相似度)
        var searchReq = new SearchRequest
        {
            CollectionName = CollectionName,
            Vector = queryVector,
            MetricType = SimilarityMetricType.Cosine,
            Limit = topK * 3, // 粗排取多,精排再过滤
            OutputFields = { "price", "rating" }
        };
        
        var vectorResults = await milvus.SearchAsync(searchReq);
        
        // Step 2: 业务规则精排(对标美团的"动态匹配"层)
        var filtered = vectorResults.Where(r => 
            (!intent.Budget.HasValue || r.Get<float>("price") <= (float)intent.Budget.Value) &&
            r.Get<float>("rating") >= 4.0f
        ).Take(topK).Select(r => r.Id).ToList();
        
        return filtered;
    }

    private async Task<List<float>> GenerateEmbeddingAsync(string text)
    {
        // 真实场景:调用 BGE-M3 ONNX 模型 或本地 HTTP 服务
        // 这里 mock 一个 1024 维向量,实际项目请用真实嵌入模型
        using var client = new HttpClient();
        var response = await client.PostAsJsonAsync(
            "http://localhost:8000/embed", // 假设本地部署了 BGE-M3 推理服务
            new { text });
        var result = await response.Content.ReadFromJsonAsync<EmbeddingResponse>();
        return result!.Vector;
    }
}

第四步:场景编排与结果组装(API 聚合层)

"问小团"最后一步是把商户信息、路线规划、优惠券打包成结构化回答。咱们用 Minimal API 风格实现:

csharp 复制代码
// Program.cs 核心逻辑
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient<IntentParser>();
builder.Services.AddSingleton<VectorSearchService>();
builder.Services.AddScoped<RestaurantRepository>(); // 封装 PGSQL 查询
var app = builder.Build();

app.MapPost("/api/ai-search", async (
    SearchRequest request,
    IntentParser parser,
    VectorSearchService vectorSvc,
    RestaurantRepository repo) =>
{
    // 1. 意图解析(爱因斯坦也得先听懂人话)
    var intent = await parser.ParseAsync(request.Query, request.Lat, request.Lng);
    
    // 2. 把 query 本身也向量化(用于语义检索)
    var queryVector = await vectorSvc.GenerateEmbeddingAsync(request.Query);

    // 3. 向量库粗排 + 业务规则精排
    var candidateIds = await vectorSvc.SearchAsync(queryVector, intent, topK: 5);

    // 4. 查详情 + 实时状态(物理世界信息底座)
    var restaurants = await repo.GetByIdsAsync(candidateIds);
    var filtered = restaurants.Where(r => 
        r.Status == BusinessStatus.Open && // 实时状态过滤,避免推荐已打烊店铺
        (intent.SceneTags.All(tag => r.Tags.Contains(tag))) // 场景标签匹配
    ).ToList();

    // 5. 组装最终结果(类似"问小团"的结构化推荐卡片)
    var result = filtered.Select(r => new RestaurantCard
    {
        Name = r.Name,
        Address = r.Location.ToAddressString(), // 逆地理编码
        AvgPrice = r.AvgPrice,
        Reason = GenerateReason(r, intent), // AI 生成推荐理由
        AvailableCoupons = await GetCouponsAsync(r.Id) // 假设的优惠券系统
    });

    return Results.Ok(result);
});

app.Run();

关键细节:为什么你的 AI 搜索总是"答非所问"?

很多人做本地生活 AI 时,直接把用户 query 扔给大模型让模型瞎猜,结果出来一堆"可能也许大概"的幻觉店铺。美团的解法值得借鉴:

1. 物理信息底座 > 模型参数

LongCat 模型虽然猛,但王兴反复强调"物理世界的数字化"才是底座。咱们代码里 BusinessStatus 的实时更新、PGSQL 里准确的营业时段字段,比单纯增大模型参数量更能降低幻觉。

2. 混合检索才是王道

纯向量检索会犯"语义近似但业务不符"的错误------比如搜"适合约会的地方"可能召回"离婚登记处"(都是两人去)。代码里的 Where 过滤(价格、评分、标签匹配)就是美团的"动态匹配"层,用规则兜底 AI 的任性。

3. 闭环交易设计

"问小团"目前虽然不能一键付款,但已打通"搜索→详情页→领券→下单"链路。咱们示例里的 AvailableCouponsReason 字段,就是在模拟这种"决策即交易"的闭环体验,减少用户跳失。


部署与扩展:从单机到生产

这套架构在单机跑通后,扩展路径也很清晰:

  • 向量库:Milvus 支持分布式部署,商户向量可以按城市分片;
  • 实时状态流:把 Redis 里的 BusinessStatus 换成美团开源的 RocketMQ 消息流,地推改状态后秒级同步;
  • 模型层:如果觉得 Qwen API 成本高,可以本地部署 LongCat-Flash(MoE 架构,推理时只激活 27B 参数,单卡 V100 可跑),或者用 Ollama 跑 Qwen3 的量化版。

结语:AI 不是替代秘书,而是替代"信息不对称"

回到爱因斯坦订餐厅的段子。咱们这套代码本质上解决的不是"聪明不聪明"的问题,而是让 AI 拥有毫秒级查询物理世界状态的能力。从代码层面看,就是 RestaurantRepository 里那几条精准的 SQL 查询,加上 VectorSearchService 里的语义召回。

美团"问小团"的技术架构并不神秘------MoE 大模型做意图理解、向量库做语义召回、关系数据库做业务规则过滤,这三板斧咱们用 .NET 生态照样玩得转。关键是数据要真、状态要准、链路要闭,剩下的,就交给 C# 的高性能运行时去扛并发吧。

代码仓库结构已就绪,下一步该考虑的是:你的商户数据,能不能做到像美团那样每 15 分钟更新一次营业时间?毕竟,AI 再聪明,也订不到一家已经打烊的网红餐厅。

目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

相关推荐
无心水1 小时前
【OpenClaw:实战部署】10、OpenClaw自动化调度——打造7x24小时无人值守AI工作流
人工智能·ai·ai工作流·openclaw·openclaw·三月创作之星·养龙虾
十字花1 小时前
【CVPR 2025】SET:Spectral Enhancement for Tiny Object Detection
论文阅读·人工智能·目标检测·计算机视觉
湘美书院--湘美谈教育1 小时前
湘美谈教育精英智能实验室:当萨特遇上AI,跨存在对话
人工智能·深度学习·神经网络·机器学习·ai写作
我材不敲代码2 小时前
OpenCV 实战——图像形态学操作与边缘检测全解析:从腐蚀膨胀到 Canny 边缘检测
人工智能·opencv·计算机视觉
芯片-嵌入式2 小时前
具身智能(2):OpenExplorer下的模型量化
人工智能·深度学习·算法
DamianGao2 小时前
我用 OpenClaw 做了一个 AI 新闻早报,每天自动推送
人工智能·python·语言模型
Lab_AI2 小时前
电子实验记录本(ELN)助力熙华药业核心竞争力提升
大数据·人工智能·实验室管理·eln·药物研发·ai制药·电子实验记录本
崔高杰2 小时前
训练数据选择又有新方法了?——两篇文章的阅读笔记 Less is Enough和 OPUS
人工智能·笔记·机器学习
爱吃奶酪的松鼠丶2 小时前
LangGraph 实战笔记:用 AI 发起流程应用
人工智能·笔记