这篇博文介绍了如何使用 Azure Cosmos DB 为 NoSQL Go SDK 和 LangChainGo 构建聊天记录实现。如果您对 Go SDK 还不熟悉,博文中提供的示例聊天机器人应用程序可作为实际介绍,涵盖了诸如读取、更新等基本操作。它还演示了如何使用 Azure Cosmos DB 基于 Linux 的模拟器(在撰写时处于预览阶段)与 Testcontainers 用于 Go 的集成测试。
Go 开发人员想要构建 AI 应用程序可以使用 LangChainGo,这是一个用于 LLM 动力应用的框架。它为向量存储、嵌入、加载文档、链(用于组合多个操作)、聊天记录等组件提供了可插拔的 API。
在深入讨论之前,让我们退一步了解基础知识。
什么是聊天记录,它对现代 AI 应用程序为何重要?
对话式 AI 应用程序的一个常见要求是能够存储和检索作为对话一部分交换的消息。这通常被称为“聊天记录”。如果您曾使用过类似 ChatGPT(顺便提一句,它也使用了 Azure Cosmos DB!)的应用程序,您可能对这个概念很熟悉。
当用户登录时,他们可以开始聊天,交流的消息将作为对话的一部分被保存。当他们再次登录时,可以看到之前的对话,并可以继续未完成的内容。
聊天记录显然对应用程序的终端用户非常重要,但我们也不能忘记大型语言模型(LLM)!尽管大型语言模型看起来很聪明,但由于缺乏内置记忆(至少目前是这样),它们无法回忆过去的互动。使用聊天记录可以弥补这一差距,通过提供之前的对话作为额外的上下文,使大型语言模型能够生成更相关和高质量的回应。这增强了对话的自然流畅性,并显著改善了用户体验。
一个简单的例子说明了这一点:假设你通过API问一个大型语言模型,“告诉我关于Azure Cosmos DB的事情”,它会回复你一段冗长的文字。如果你随后发出另一个API调用,要求“将其分解为项目符号以便更易阅读”,大型语言模型可能会感到困惑,因为它缺乏之前互动的上下文。
然而,如果你在第二个API调用中将早先的消息作为上下文的一部分包含进去,那么大型语言模型更可能提供准确的回应(尽管不能保证,因为大型语言模型的输出本质上是非确定性的)。
如何运行聊天机器人
正如我之前提到的,示例应用程序是您探索langchaingo
、Azure Cosmos DB 聊天记录实现以及Go SDK的有用方式。
在探索实现细节之前,看一看应用程序运行起来是个好主意。请参阅 GitHub 存储库的README 部分,其中提供了有关如何配置、运行并开始与聊天机器人对话的说明。
应用程序概述
聊天应用程序遵循一个简单的领域模型:用户可以发起多个对话,每个对话可以包含多条消息。该应用程序使用 Go 构建,包括后端和前端组件。
后端
它有多个子部分:
- Azure Cosmos DB 聊天历史实现。
- 通过 REST API 公开的核心操作,如开始对话、发送/接收消息和检索对话历史。
- REST API利用
langchaingo
链来处理用户消息。该链自动将聊天历史纳入,以确保过去的对话被发送到LLM。langchaingo
处理所有编排 – LLM调用、聊天历史包含等,无需手动实现。
前端
它是使用JavaScript、HTML和CSS构建的。它作为Go web服务器的一部分(使用嵌入包)打包,并在用户交互时调用后端REST API。
使用Azure Cosmos DB实现聊天历史记录
LangChainGo是一个可插拔的框架,其中包括聊天历史(或内存)组件。要集成Azure Cosmos DB,您需要实现schema.ChatMessageHistory
接口,该接口提供管理聊天历史记录的方法:
AddMessage
用于将消息添加到对话中(或启动新对话)。Messages
用于检索对话的所有消息。Clear
用于删除对话中的所有消息。
虽然您可以直接实例化CosmosDBChatMessageHistory
实例并使用这些方法,但建议的方法是将其整合到langchaingo
应用程序中。以下是一个在Azure Cosmos DB聊天历史记录与LLMChain
一起使用的示例:
// 创建一个聊天历史实例
cosmosChatHistory, err := cosmosdb.NewCosmosDBChatMessageHistory(cosmosClient, databaseName, containerName, req.SessionID, req.UserID)
if err != nil {
log.Printf("Error creating chat history: %v", err)
sendErrorResponse(w, "Failed to create chat session", http.StatusInternalServerError)
return
}
// 使用聊天历史创建一个内存
chatMemory := memory.NewConversationBuffer(
memory.WithMemoryKey("chat_history"),
memory.WithChatHistory(cosmosChatHistory),
)
// 创建一个LLM链
chain := chains.LLMChain{
Prompt: promptsTemplate,
LLM: llm,
Memory: chatMemory,
OutputParser: outputparser.NewSimple(),
OutputKey: "text",
}
从Azure Cosmos DB的角度来看,在这个示例中的实现只是众多可能选项之一。这里展示的是基于用户ID作为分区键,并且会话ID(有时也称为会话ID)作为唯一键(Azure Cosmos DB项的id
)的组合。
这使得应用程序可以:
- 获取特定会话的所有消息。这是使用唯一ID(会话ID)和分区键(用户ID)进行的点读取。
- 向对话添加新消息。它使用upsert操作(而不是create)以避免在写入之前需要read。
- 删除特定对话。它使用delete操作来删除对话(及其所有消息)。
尽管
langchaingo
接口没有公开,但在将其集成作为应用程序的一部分时,您还可以发出单独的查询以获取用户的所有对话。这也是高效的,因为它限制在单个分区内。
使用Azure Cosmos DB模拟器和Testcontainers简化测试
示例应用程序包括Azure Cosmos DB聊天记录和主应用程序的基本测试用例。值得一提的是使用testcontainers-go来集成Azure Cosmos DB基于Linux的模拟器 Docker容器。
这对于集成测试非常有用,因为数据库在本地可用,测试运行速度更快(也不要忘记节省成本!)。更棒的是,您无需手动管理Docker容器的生命周期。这是测试套件的一部分,感谢testcontainers-go API
,它方便地在测试运行之前启动容器,并在测试完成后终止容器。
您可以查看示例应用程序中的测试用例以获取更多详细信息。以下是如何使用testcontainers-go
的片段:
func setupCosmosEmulator(ctx context.Context) (testcontainers.Container, error) {
req := testcontainers.ContainerRequest{
Image: emulatorImage,
ExposedPorts: []string{emulatorPort + ":8081", "1234:1234"},
WaitingFor: wait.ForListeningPort(nat.Port(emulatorPort)),
}
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
return nil, fmt.Errorf("failed to start container: %w", err)
}
// 给模拟器更多时间完全初始化
time.Sleep(5 * time.Second)
return container, nil
}
如果您有兴趣在CI流水线中使用Azure Cosmos DB模拟器,请查看博客文章。
总结
能够存储聊天记录是对话式人工智能应用程序的重要组成部分。它们可以作为现有技术(如RAG(检索增强生成))的一个很好的补充。请尝试聊天机器人应用程序,并告诉我们您的想法!
虽然示例应用程序中的实现相对简单,但您如何建模聊天记录数据取决于需求。一个这样的场景是这篇精彩的博客文章,关于如何使用Azure Cosmos DB使微软Copilot扩展到数百万用户。
您的一些需求可能包括:
- 存储元数据,例如反应(除了消息之外)
- 显示最近的前N条消息
- 考虑聊天记录数据的保留期限(使用TTL)
- 基于聊天记录数据整合额外的分析(关于用户交互)等。
无论实现如何,始终确保遵循数据建模的最佳实践。有关指南,请参见这里。
您是否已经在使用或计划在您的Go应用程序中利用Azure Cosmos DB?我们很乐意听取您的意见!请将您的问题和反馈发送给我们。
Source:
https://dzone.com/articles/chat-history-ai-applications-azure-cosmos-db-go-sdk