闽公网安备 35020302035485号

docker pull chromadb/chroma docker run -p 8000:8000 chromadb/chroma成功启动如下所示:


#pragma warning disable SKEXP0003
ISemanticTextMemory? memory;
#pragma warning disable SKEXP0003
var memoryBuilder = new MemoryBuilder();
#pragma warning disable SKEXP0011
memoryBuilder.WithOpenAITextEmbeddingGeneration("text-embedding-ada-002", envVars["OpenAIAPIKey"]);
#pragma warning disable SKEXP0022
var chromaMemoryStore = new ChromaMemoryStore("http://127.0.0.1:8000");
memoryBuilder.WithMemoryStore(chromaMemoryStore);
memory = memoryBuilder.Build();
ISemanticTextMemory:语义记忆的接口,用于创建和调用与文本相关的记忆。 // 创建 OpenFileDialog 对象
OpenFileDialog openFileDialog = new OpenFileDialog();
// 设置文件类型过滤器
openFileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
// 显示文件选择对话框
if (openFileDialog.ShowDialog() == true)
{
// 用户选择了一个文件,你可以通过 openFileDialog.FileName 获取文件的路径
string filePath = openFileDialog.FileName;
HandyControl.Controls.MessageBox.Show($"你选中的路径为{filePath}");
var text = File.ReadAllText(filePath);
const string MemoryCollectionName = "hello2";
var id = Guid.NewGuid().ToString();
await memory.SaveInformationAsync(MemoryCollectionName, id: id, text: text);
HandyControl.Controls.MessageBox.Show($"完成");
这是以选择一个txt文件为例,核心就一行代码:await memory.SaveInformationAsync(MemoryCollectionName, id: id, text: text);将一些信息保存到Semantic Memory中。
Task<string> SaveInformationAsync(string collection, string text, string id, string? description = null, string? additionalMetadata = null, Kernel? kernel = null, CancellationToken cancellationToken = default(CancellationToken));参数及含义:
| 参数名 | 类型 | 含义 |
|---|---|---|
| collection | string | 保存数据的集合名 |
| text | string | 要保存的数据 |
| id | string | 唯一标识符 |
| description | string? | 描述 |
| additionalMetadata | string? | 额外的元数据 |
| kernel | Kernel? | 包含服务、插件和其他状态的内核,供整个操作使用 |
| cancellationToken | CancellationToken | 用于监视取消请求的 CancellationToken。默认值为 None |
const string MemoryCollectionName = "hello2";经过我的测试,集合名要是英文,中文会报错。
/// <summary>
/// 堆代码 duidaima.com
/// TextMemoryPlugin provides a plugin to save or recall information from the long or short term memory.
/// </summary>
[Experimental("SKEXP0003")]
public sealed class TextMemoryPlugin
{
/// <summary>
/// Name used to specify the input text.
/// </summary>
public const string InputParam = "input";
/// <summary>
/// Name used to specify which memory collection to use.
/// </summary>
public const string CollectionParam = "collection";
/// <summary>
/// Name used to specify memory search relevance score.
/// </summary>
public const string RelevanceParam = "relevance";
/// <summary>
/// Name used to specify a unique key associated with stored information.
/// </summary>
public const string KeyParam = "key";
/// <summary>
/// Name used to specify the number of memories to recall
/// </summary>
public const string LimitParam = "limit";
private const string DefaultCollection = "generic";
private const double DefaultRelevance = 0.0;
private const int DefaultLimit = 1;
private readonly ISemanticTextMemory _memory;
private readonly ILogger _logger;
/// <summary>
/// Creates a new instance of the TextMemoryPlugin
/// </summary>
public TextMemoryPlugin(
ISemanticTextMemory memory,
ILoggerFactory? loggerFactory = null)
{
this._memory = memory;
this._logger = loggerFactory?.CreateLogger(typeof(TextMemoryPlugin)) ?? NullLogger.Instance;
}
/// <summary>
/// Key-based lookup for a specific memory
/// </summary>
/// <param name="key">The key associated with the memory to retrieve.</param>
/// <param name="collection">Memories collection associated with the memory to retrieve</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
[KernelFunction, Description("Key-based lookup for a specific memory")]
public async Task<string> RetrieveAsync(
[Description("The key associated with the memory to retrieve")] string key,
[Description("Memories collection associated with the memory to retrieve")] string? collection = DefaultCollection,
CancellationToken cancellationToken = default)
{
if (this._logger.IsEnabled(LogLevel.Debug))
{
this._logger.LogDebug("Recalling memory with key '{0}' from collection '{1}'", key, collection);
}
var memory = await this._memory.GetAsync(collection, key, cancellationToken: cancellationToken).ConfigureAwait(false);
return memory?.Metadata.Text ?? string.Empty;
}
/// <summary>
/// Semantic search and return up to N memories related to the input text
/// </summary>
/// <param name="input">The input text to find related memories for.</param>
/// <param name="collection">Memories collection to search.</param>
/// <param name="relevance">The relevance score, from 0.0 to 1.0, where 1.0 means perfect match.</param>
/// <param name="limit">The maximum number of relevant memories to recall.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
[KernelFunction, Description("Semantic search and return up to N memories related to the input text")]
public async Task<string> RecallAsync(
[Description("The input text to find related memories for")] string input,
[Description("Memories collection to search")] string collection = DefaultCollection,
[Description("The relevance score, from 0.0 to 1.0, where 1.0 means perfect match")] double? relevance = DefaultRelevance,
[Description("The maximum number of relevant memories to recall")] int? limit = DefaultLimit,
CancellationToken cancellationToken = default)
{
relevance ??= DefaultRelevance;
limit ??= DefaultLimit;
if (this._logger.IsEnabled(LogLevel.Debug))
{
this._logger.LogDebug("Searching memories in collection '{0}', relevance '{1}'", collection, relevance);
}
// Search memory
List<MemoryQueryResult> memories = await this._memory
.SearchAsync(collection, input, limit.Value, relevance.Value, cancellationToken: cancellationToken)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
if (memories.Count == 0)
{
if (this._logger.IsEnabled(LogLevel.Warning))
{
this._logger.LogWarning("Memories not found in collection: {0}", collection);
}
return string.Empty;
}
return limit == 1 ? memories[0].Metadata.Text : JsonSerializer.Serialize(memories.Select(x => x.Metadata.Text));
}
/// <summary>
/// Save information to semantic memory
/// </summary>
/// <param name="input">The information to save</param>
/// <param name="key">The key associated with the information to save</param>
/// <param name="collection">Memories collection associated with the information to save</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
[KernelFunction, Description("Save information to semantic memory")]
public async Task SaveAsync(
[Description("The information to save")] string input,
[Description("The key associated with the information to save")] string key,
[Description("Memories collection associated with the information to save")] string collection = DefaultCollection,
CancellationToken cancellationToken = default)
{
if (this._logger.IsEnabled(LogLevel.Debug))
{
this._logger.LogDebug("Saving memory to collection '{0}'", collection);
}
await this._memory.SaveInformationAsync(collection, text: input, id: key, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Remove specific memory
/// </summary>
/// <param name="key">The key associated with the information to save</param>
/// <param name="collection">Memories collection associated with the information to save</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
[KernelFunction, Description("Remove specific memory")]
public async Task RemoveAsync(
[Description("The key associated with the information to save")] string key,
[Description("Memories collection associated with the information to save")] string collection = DefaultCollection,
CancellationToken cancellationToken = default)
{
if (this._logger.IsEnabled(LogLevel.Debug))
{
this._logger.LogDebug("Removing memory from collection '{0}'", collection);
}
await this._memory.RemoveAsync(collection, key, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
比较长,可以以后用到了什么函数再慢慢看,等一会我们就要接触到的函数如下:/// <summary>
/// Semantic search and return up to N memories related to the input text
/// </summary>
/// <param name="input">The input text to find related memories for.</param>
/// <param name="collection">Memories collection to search.</param>
/// <param name="relevance">The relevance score, from 0.0 to 1.0, where 1.0 means perfect match.</param>
/// <param name="limit">The maximum number of relevant memories to recall.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
[KernelFunction, Description("Semantic search and return up to N memories related to the input text")]
public async Task<string> RecallAsync(
[Description("The input text to find related memories for")] string input,
[Description("Memories collection to search")] string collection = DefaultCollection,
[Description("The relevance score, from 0.0 to 1.0, where 1.0 means perfect match")] double? relevance = DefaultRelevance,
[Description("The maximum number of relevant memories to recall")] int? limit = DefaultLimit,
CancellationToken cancellationToken = default)
{
relevance ??= DefaultRelevance;
limit ??= DefaultLimit;
if (this._logger.IsEnabled(LogLevel.Debug))
{
this._logger.LogDebug("Searching memories in collection '{0}', relevance '{1}'", collection, relevance);
}
// Search memory
List<MemoryQueryResult> memories = await this._memory
.SearchAsync(collection, input, limit.Value, relevance.Value, cancellationToken: cancellationToken)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
if (memories.Count == 0)
{
if (this._logger.IsEnabled(LogLevel.Warning))
{
this._logger.LogWarning("Memories not found in collection: {0}", collection);
}
return string.Empty;
}
return limit == 1 ? memories[0].Metadata.Text : JsonSerializer.Serialize(memories.Select(x => x.Metadata.Text));
}
一步一步来看:[KernelFunction, Description("Semantic search and return up to N memories related to the input text")]
KernelFunction是一个特性,可能是用于标记这个方法作为某种内核函数的一部分。具体的含义取决于这个特性是如何在代码中被使用的。public async Task<string> RecallAsync(
[Description("The input text to find related memories for")] string input,
[Description("Memories collection to search")] string collection = DefaultCollection,
[Description("The relevance score, from 0.0 to 1.0, where 1.0 means perfect match")] double? relevance = DefaultRelevance,
[Description("The maximum number of relevant memories to recall")] int? limit = DefaultLimit,
CancellationToken cancellationToken = default)
RecallAsync方法有input、collection、relevance、limit、cancellationToken参数,它们的含义如下:
| 参数名 | 含义 |
|---|---|
| input | 用于查看向量数据库中是否有相关数据的文本 |
| collection | 向量数据库中的集合名 |
| relevance | 相关性,0最低,1最高 |
| limit | 相关数据的最大返回数量 |
| cancellationToken | .NET中用于协调取消长时间运行的操作的结构 |
// Search memory
List<MemoryQueryResult> memories = await this._memory
.SearchAsync(collection, input, limit.Value, relevance.Value, cancellationToken: cancellationToken)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
向kernel导入插件:// TextMemoryPlugin provides the "recall" function kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));开始测试

const string skPrompt = @"
ChatBot can have a conversation with you about any topic.
It can give explicit instructions or say 'I don't know' if it does not have an answer.
Information about me, from previous conversations:
- {{$fact1}} {{recall $fact1}}
- {{$fact2}} {{recall $fact2}}
Chat:
{{$history}}
User: {{$userInput}}
ChatBot: ";
var chatFunction = kernel.CreateFunctionFromPrompt(skPrompt, new OpenAIPromptExecutionSettings { MaxTokens = 200, Temperature = 0.8 });
#pragma warning disable SKEXP0052
var arguments = new KernelArguments();
arguments["fact1"] = "我的名字是什么?";
arguments["fact2"] = "我喜欢什么编程语言?";
arguments[TextMemoryPlugin.CollectionParam] = "hello2";
arguments[TextMemoryPlugin.LimitParam] = "2";
arguments[TextMemoryPlugin.RelevanceParam] = "0.8";
arguments["userInput"] = "我的名字叫什么?";
// Process the user message and get an answer
var answer = await chatFunction.InvokeAsync(kernel, arguments);
Debug.WriteLine(answer);
在查找“我的名字是什么?”时,并没有查找到相关内容:



loadingMemory2.Visibility = Visibility.Visible;
string question = textBoxMemory1.Text;
// Get user input
history.AddUserMessage(question);
const string skPrompt = @"
ChatBot can have a conversation with you about any topic.
It can give explicit instructions or say 'I don't know' if it does not have an answer.
Information about me, from previous conversations:
- {{$fact1}} {{recall $fact1}}
Chat:
{{$history}}
User: {{$userInput}}
ChatBot: ";
var chatFunction = kernel.CreateFunctionFromPrompt(skPrompt, new OpenAIPromptExecutionSettings { MaxTokens = 200, Temperature = 0.8 });
#pragma warning disable SKEXP0052
var arguments = new KernelArguments();
arguments["fact1"] = question;
arguments[TextMemoryPlugin.CollectionParam] = "hello2";
arguments[TextMemoryPlugin.LimitParam] = "2";
arguments[TextMemoryPlugin.RelevanceParam] = "0.6";
arguments["userInput"] = question;
// Process the user message and get an answer
var answer = await chatFunction.InvokeAsync(kernel, arguments);
Debug.WriteLine(answer);
// Print the results
richTextBoxMemory.AppendText(answer + "\r\n");
// Add the message from the agent to the chat history
history.AddMessage(Microsoft.SemanticKernel.ChatCompletion.AuthorRole.System, answer.ToString());
loadingMemory2.Visibility = Visibility.Hidden;
使用gpt-3.5-turbo的效果