如何让AI拥有记忆

  AI是个很笨的东西,做什么是需要我们教的

  AI可以帮我们聚焦需要的信息,但是无法凭空产生,所以怎么让AI记住我们的信息呢?

  先举一个小例子,我们简单调用一下

using Microsoft.Extensions.AI;
using OpenAI.Chat;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StudyAI
{
    public static class AIHelper
    {
        static string apiKey = "";
        static string url = "";//专属
        public static async Task ChatSimple()
        {
            IChatClient client = new ChatClient("qwen3-vl-plus",
                new ApiKeyCredential(apiKey),
                new OpenAI.OpenAIClientOptions() { Endpoint = new Uri(url) }
            ).AsIChatClient();

            while (true)
            {
                Console.Write(">>>>>>");
                var question = Console.ReadLine();
                if (question == null)
                    continue;
                try
                {
                    //同步输出
                    var res = await client.GetResponseAsync(question);
                    Console.WriteLine(res.Text);
                    Console.WriteLine("单次token总消耗" + res.Usage?.TotalTokenCount);

                    //流式输出
                    //await foreach (var update in client.GetStreamingResponseAsync(question))
                    //{
                    //    Console.Write(update.Text);
                    //}
                    //Console.WriteLine();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"发生异常: {ex.Message}");
                }
            }
        }
    }
}

  运行:

>>>>>>我96年出生的
你好!96年出生的话,2025年你就是 **29周岁**(虚岁30岁)??
这个年纪正处于人生很关键又充满可能性的阶段——事业可能刚站稳脚跟,感情、生活、自我成长都在快速变化中。

你最近在关注什么方向呢?比如:
- 职业发展/转行/副业探索?
- 感情状态或人生规划?
- 健康、理财、学习新技能?
- 或者单纯想聊聊“96年这代人”的共同记忆/困惑?

我很乐意陪你一起梳理、分析,或者就当个树洞~ ??
单次token总消耗162

>>>>>>我今年多大了 你好!要确定你今年多大,我需要知道你的出生年份(或者具体出生日期),以及当前的年份。 不过,如果你是在2025年提问(比如今天是2025年4月5日),而你知道自己的出生年份,可以这样简单计算: **年龄 = 当前年份 ? 出生年份** (如果生日还没过,就减1) 例如: - 如果你出生于2000年,且今天已过生日 → 2025 ? 2000 = 25岁 - 如果你出生于2000年,但生日还没到 → 24岁 ?? 注意:我无法直接获取你的个人信息(如出生日期),所以请告诉我你的出生年份或生日,我可以帮你准确计算 ?? 你愿意分享一下吗? 单次token总消耗196

  可以看出,第二次请求到大模型的时候,第一次的信息并没法保留,所以AI并不知道我今年多大了

  如何在第二次请求的时候,把第一次信息作为一个“事实”发给AI

  逻辑是:录入记忆  ->  查询前先查找数据库的相似记忆   ->  带着相似记忆一起发送到大模型

using Microsoft.Extensions.AI;
using OpenAI;
using OpenAI.Chat;
using OpenAI.Embeddings;
using Qdrant.Client;
using Qdrant.Client.Grpc;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ChatMessage = Microsoft.Extensions.AI.ChatMessage;
using EmbeddingGenerationOptions = OpenAI.Embeddings.EmbeddingGenerationOptions;

namespace StudyAI
{
    public static class AIHelper
    {
        static string apiKey = "";
        static string url = "";//专属public static async Task ChatWithMemory()
        {
            IChatClient client = new ChatClient("qwen3-vl-plus",
                new ApiKeyCredential(apiKey),
                new OpenAI.OpenAIClientOptions() { Endpoint = new Uri(url) }
            ).AsIChatClient();
            while (true)
            {
                Console.Write(">>>>>>");
                var txt = Console.ReadLine();
                if (txt == null)
                    continue;
                try
                {
                    List<ChatMessage> messages = new List<ChatMessage>();
                    var points = await GetRelevantMemory(txt);
                    foreach (var point in points)
                    {
                        messages.Add(new ChatMessage(ChatRole.User, point.Payload["txt"].StringValue));
                    }
                    messages.Add(new ChatMessage(ChatRole.User, txt));
                    var res = await client.GetResponseAsync(messages);
                    Console.WriteLine(res.Text);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"发生异常: {ex.Message}");
                }
            }
        }

        /// <summary>
        /// 获取信息向量
        /// </summary>
        /// <param name="txt"></param>
        /// <returns></returns>
        private static async Task<float[]> GetVector(string txt)
        {
            const string modelId = "text-embedding-v4"; // 推荐使用 v4 模型
            var openAiEmbeddingClient = new EmbeddingClient(
                model: modelId,
                credential: new ApiKeyCredential(apiKey),
                options: new OpenAIClientOptions
                {
                    Endpoint = new Uri(url)
                }
            );
            // 调用百炼 Embedding 接口生成向量
            var embeddingResponse = await openAiEmbeddingClient.GenerateEmbeddingAsync(txt, new EmbeddingGenerationOptions { Dimensions = 1536 });
            ReadOnlyMemory<float> vectorMemory = embeddingResponse.Value.ToFloats();
            float[] vector = vectorMemory.ToArray();
            Console.WriteLine($"向量维度: {vector.Length}");
            //Console.WriteLine($"{string.Join(",",vector)}");
            return vector;
        }
        
        /// <summary>
        /// 录入记忆
        /// </summary>
        /// <param name="txt"></param>
        /// <returns></returns>
        public static async Task RememberMe(string txt)
        {
            var vector = await GetVector(txt);
            //写入向量数据库
            var client = new QdrantClient("192.168.232.133", 6334);
            //await client.CreateCollectionAsync(//写之前可以手动创建,也可以代码创建
            //    collectionName: "firstCollection",
            //    vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine }
            //);
            var points = new List<PointStruct>
            {
                new PointStruct
                {
                    Id =  Guid.NewGuid(),
                    Vectors = vector,
                    Payload = { ["txt"] = txt }
                },
            };
            await client.UpsertAsync("firstCollection", points);
            Console.WriteLine("成功写入Qdrant");
        }

        /// <summary>
        /// 获取相关记忆
        /// </summary>
        /// <param name="txt"></param>
        /// <returns></returns>
        public static async Task<IReadOnlyList<ScoredPoint>> GetRelevantMemory(string txt)
        {
            var vector = await GetVector(txt);
            //在向量数据库找到最相似的三条数据
            var client = new QdrantClient("192.168.232.133", 6334);
            var results = await client.SearchAsync(
                collectionName: "firstCollection",
                vector: vector,
                limit: 3,                         // 最多返回3条
                scoreThreshold:  0.5f // 相似度阈值 > 50%
            );
            foreach (var point in results)
            {
                Console.WriteLine($"ID: {point.Id}, Score: {point.Score},txt:{point.Payload["txt"].StringValue}");
            }
            return results;
        }
    }
}

  运行ChatWithMemory,在询问AI之前,会先从Qdrant中查找相关记忆

输入1=记录信息,2=读取记忆,3=对话
1
>>>>>>我是96年出生的
向量维度: 1536
成功写入Qdrant
输入1=记录信息,2=读取记忆,3=对话
3>>>>>>我今年多大了
向量维度: 1536
ID: { "uuid": "0f784446-9c2d-4c4d-a01c-05656d24f781" }, Score: 0.6475532,txt:我是96年出生的
你好!你是1996年出生的,现在是2025年(当前时间为2025年4月),那么:

- 如果你的生日**已经过了**(比如1月1日到4月之前出生),你今年是 **29周岁**- 如果你的生日**还没过**(比如4月之后出生),你今年是 **28周岁**?? 举个例子:
- 如果你出生于1996年3月15日 → 到2025年3月15日已满29岁 → 现在29岁;
- 如果你出生于1996年5月20日 → 要到2025年5月20日才满29岁 → 现在还是28岁。

你可以告诉我你的具体出生月份和日期,我帮你精确计算 ??
>>>>>>现在是26年
向量维度: 1536
ID: { "uuid": "0f784446-9c2d-4c4d-a01c-05656d24f781" }, Score: 0.6133094,txt:我是96年出生的
你好!你提到你是1996年出生的,现在是2026年,那么你的年龄是:

**2026 ? 1996 = 30岁**

所以你现在 **30周岁**(如果已经过了生日),或者即将满30岁(如果还没过生日)。

?? 30岁是一个很特别的里程碑——人生进入更成熟、更有力量的阶段,很多人在这个年纪事业稳步上升、生活逐渐稳定,也有人开始规划家庭或追求新的梦想。无论你现在处于什么状态,都值得为自己感到骄傲!

如果你愿意分享更多(比如职业、兴趣、近况),我很乐意陪你聊聊~ ??

  (大模型秀逗了,以为现在是25年,小问题)

  后续可以继续优化,在Chat的过程中,筛选出更多事实加以记忆

 

posted @ 2026-07-13 22:22  wskxy  阅读(2)  评论(0)    收藏  举报