当前位置:   article > 正文

Semantic Kernel 入门系列:Memory内存

semantic kernel

ec7cec5ca44d43568a3eaefe354fb441.png

了解的运作原理之后,就可以开始使用Semantic Kernel来制作应用了。

Semantic Kernel将embedding的功能封装到了Memory中,用来存储上下文信息,就好像电脑的内存一样,而LLM就像是CPU一样,我们所需要做的就是从内存中取出相关的信息交给CPU处理就好了。

内存配置

使用Memory需要注册 embedding模型,目前使用的就是 text-embedding-ada-002。同时需要为Kernel添加MemoryStore,用于存储更多的信息,这里Semantic Kernel提供了一个 VolatileMemoryStore,就是一个普通的内存存储的MemoryStore。

  1. var kernel = Kernel.Builder.Configure(c =>
  2. {
  3. c.AddOpenAITextCompletionService("openai", "text-davinci-003", Environment.GetEnvironmentVariable("MY_OPEN_AI_API_KEY"));
  4. c.AddOpenAIEmbeddingGenerationService("openai", "text-embedding-ada-002", Environment.GetEnvironmentVariable("MY_OPEN_AI_API_KEY"));
  5. })
  6. .WithMemoryStorage(new VolatileMemoryStore())
  7. .Build();

信息存储

完成了基础信息的注册后,就可以往Memroy中存储信息了。

  1. const string MemoryCollectionName = "aboutMe";
  2. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea");
  3. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I currently work as a tourist operator");
  4. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I currently live in Seattle and have been living there since 2005");
  5. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015");
  6. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info5", text: "My family is from New York");

SaveInformationAsync 会将text的内容通过 embedding 模型转化为对应的文本向量,存放在的MemoryStore中。其中CollectionName如同数据库的表名,Id就是Id。

语义搜索

完成信息的存储之后,就可以用来语义搜索了。

直接使用Memory.SearchAsync方法,指定对应的Collection,同时提供相应的查询问题,查询问题也会被转化为embedding,再在MemoryStore中计算查找最相似的信息。

  1. var questions = new[]
  2. {
  3. "what is my name?",
  4. "where do I live?",
  5. "where is my family from?",
  6. "where have I travelled?",
  7. "what do I do for work?",
  8. };
  9. foreach (var q in questions)
  10. {
  11. var response = await kernel.Memory.SearchAsync(MemoryCollectionName, q).FirstOrDefaultAsync();
  12. Console.WriteLine(q + " " + response?.Metadata.Text);
  13. }
  14. // output
  15. /*
  16. what is my name? My name is Andrea
  17. where do I live? I currently live in Seattle and have been living there since 2005
  18. where is my family from? My family is from New York
  19. where have I travelled? I visited France and Italy five times since 2015
  20. what do I do for work? I currently work as a tourist operator
  21. */

到这个时候,即便不需要进行总结归纳,光是这样的语义查找,都会很有价值。

引用存储

除了添加信息以外,还可以添加引用,像是非常有用的参考链接之类的。

  1. const string memoryCollectionName = "SKGitHub";
  2. var githubFiles = new Dictionary<string, string>()
  3. {
  4. ["https://github.com/microsoft/semantic-kernel/blob/main/README.md"]
  5. = "README: Installation, getting started, and how to contribute",
  6. ["https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/2-running-prompts-from-file.ipynb"]
  7. = "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function",
  8. ["https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/Getting-Started-Notebook.ipynb"]
  9. = "Jupyter notebook describing how to get started with the Semantic Kernel",
  10. ["https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT"]
  11. = "Sample demonstrating how to create a chat skill interfacing with ChatGPT",
  12. ["https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/Volatile/VolatileMemoryStore.cs"]
  13. = "C# class that defines a volatile embedding store",
  14. ["https://github.com/microsoft/semantic-kernel/tree/main/samples/dotnet/KernelHttpServer/README.md"]
  15. = "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4",
  16. ["https://github.com/microsoft/semantic-kernel/tree/main/samples/apps/chat-summary-webapp-react/README.md"]
  17. = "README: README associated with a sample starter react-based chat summary webapp",
  18. };
  19. foreach (var entry in githubFiles)
  20. {
  21. await kernel.Memory.SaveReferenceAsync(
  22. collection: memoryCollectionName,
  23. description: entry.Value,
  24. text: entry.Value,
  25. externalId: entry.Key,
  26. externalSourceName: "GitHub"
  27. );
  28. }

同样的,使用SearchAsync搜索就行。

  1. string ask = "I love Jupyter notebooks, how should I get started?";
  2. Console.WriteLine("===========================\n" +
  3. "Query: " + ask + "\n");
  4. var memories = kernel.Memory.SearchAsync(memoryCollectionName, ask, limit: 5, minRelevanceScore: 0.77);
  5. var i = 0;
  6. await foreach (MemoryQueryResult memory in memories)
  7. {
  8. Console.WriteLine($"Result {++i}:");
  9. Console.WriteLine(" URL: : " + memory.Metadata.Id);
  10. Console.WriteLine(" Title : " + memory.Metadata.Description);
  11. Console.WriteLine(" ExternalSource: " + memory.Metadata.ExternalSourceName);
  12. Console.WriteLine(" Relevance: " + memory.Relevance);
  13. Console.WriteLine();
  14. }
  15. //output
  16. /*
  17. ===========================
  18. Query: I love Jupyter notebooks, how should I get started?
  19. Result 1:
  20. URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/Getting-Started-Notebook.ipynb
  21. Title : Jupyter notebook describing how to get started with the Semantic Kernel
  22. ExternalSource: GitHub
  23. Relevance: 0.8677381632778319
  24. Result 2:
  25. URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/2-running-prompts-from-file.ipynb
  26. Title : Jupyter notebook describing how to pass prompts from a file to a semantic skill or function
  27. ExternalSource: GitHub
  28. Relevance: 0.8162989178955157
  29. Result 3:
  30. URL: : https://github.com/microsoft/semantic-kernel/blob/main/README.md
  31. Title : README: Installation, getting started, and how to contribute
  32. ExternalSource: GitHub
  33. Relevance: 0.8083238591883483
  34. */

这里多使用了两个参数,一个是limit,用于限制返回信息的条数,只返回最相似的前几条数据,另外一个是minRelevanceScore,限制最小的相关度分数,这个取值范围在0.0 ~ 1.0 之间,1.0意味着完全匹配。

语义问答

将Memory的存储、搜索功能和语义技能相结合,就可以快速的打造一个实用的语义问答的应用了。

只需要将搜索到的相关信息内容填充到 prompt中,然后将内容和问题都抛给LLM,就可以等着得到一个满意的答案了。

  1. const string MemoryCollectionName = "aboutMe";
  2. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea");
  3. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I currently work as a tourist operator");
  4. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I currently live in Seattle and have been living there since 2005");
  5. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015");
  6. await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info5", text: "My family is from New York");
  7. var prompt =
  8. """
  9. It can give explicit instructions or say 'I don't know' if it does not have an answer.
  10. Information about me, from previous conversations:
  11. {{ $fact }}
  12. User: {{ $ask }}
  13. ChatBot:
  14. """;
  15. var skill = kernel.CreateSemanticFunction(prompt);
  16. var ask = "Hello, I think we've met before, remember? my name is...";
  17. var fact = await kernel.Memory.SearchAsync(MemoryCollectionName,ask).FirstOrDefaultAsync();
  18. var context = kernel.CreateNewContext();
  19. context["fact"] = fact?.Metadata?.Text;
  20. context["ask"] = ask;
  21. var resultContext =await skill.InvokeAsync(context);
  22. resultContext.Result.Dump();
  23. //output
  24. /*
  25. Hi there! Yes, I remember you. Your name is Andrea, right?
  26. */

优化搜索过程

由于这种场景太常见了,所以Semantic Kernel中直接提供了一个技能TextMemorySkill,通过Function调用的方式简化了搜索的过程。

  1. // .. SaveInformations
  2. // TextMemorySkill provides the "recall" function
  3. kernel.ImportSkill(new TextMemorySkill());
  4. var prompt =
  5. """
  6. It can give explicit instructions or say 'I don't know' if it does not have an answer.
  7. Information about me, from previous conversations:
  8. {{ recall $ask }}
  9. User: {{ $ask }}
  10. ChatBot:
  11. """;
  12. var skill = kernel.CreateSemanticFunction(prompt);
  13. var ask = "Hello, I think we've met before, remember? my name is...";
  14. var context = kernel.CreateNewContext();
  15. context["ask"] = ask;
  16. context[TextMemorySkill.CollectionParam] = MemoryCollectionName;
  17. var resultContext =await skill.InvokeAsync(context);
  18. resultContext.Result.Dump();
  19. // output
  20. /*
  21. Hi there! Yes, I remember you. Your name is Andrea, right?
  22. */

这里直接使用 recall 方法,将问题传给了 TextMemorySkill,搜索对应得到结果,免去了手动搜索注入得过程。

内存的持久化

VolatileMemoryStore本身也是易丢失的,往往使用到内存的场景,其中的信息都是有可能长期存储的,起码并不会即刻过期。那么将这些信息的 embedding 能够长期存储起来,也是比较划算的事情。毕竟每一次做 embedding的转化也是需要调接口,需要花钱的。

Semantic Kernel库中包含了SQLite、Qdrant和CosmosDB的实现,自行扩展的话,也只需要实现 IMemoryStore 这个接口就可以了。

至于未来,可能就是专用的 Vector Database 了。


参考资料:

  1. https://learn.microsoft.com/en-us/semantic-kernel/concepts-sk/memories

  2. https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/6-memory-and-embeddings.ipynb

  3. https://github.com/johnmaeda/SK-Recipes/blob/main/e4-memories/notebook.ipynb

  4. https://learn.microsoft.com/en-us/semantic-kernel/concepts-ai/vectordb

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/381929
推荐阅读
相关标签
  

闽ICP备14008679号