news 2026/9/15 18:29:50

LangChain Go 使用 Google AlloyDB 持久化 Chat Message History:完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangChain Go 使用 Google AlloyDB 持久化 Chat Message History:完整实战指南

LangChain Go 使用 Google AlloyDB 持久化 Chat Message History:完整实战指南

【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo

本指南围绕 langchaingo 仓库中 google-alloydb-chat-message-history-example 示例,讲解如何将 Google Cloud 的 AlloyDB for PostgreSQL 作为 Go 版 LangChain 对话记忆(ChatMessageHistory)的持久化后端。读完本文,你将掌握从环境配置、连接池初始化、建表到消息增删查改的完整链路,并深入理解memory/alloydbutil/alloydbutil两个包的源码实现原理。

背景:为什么用数据库承载对话记忆

在构建 LLM 应用时,多轮对话需要把历史消息保存下来,才能在下一轮请求中作为上下文提供给模型。LangChain Go 通过 schema.ChatMessageHistory 接口抽象了这一能力,其定义了六个核心方法:

  • AddMessage:追加一条llms.ChatMessage消息;
  • AddUserMessage/AddAIMessage:便捷地追加用户或 AI 消息字符串;
  • Clear:清空全部消息;
  • Messages:取回全部消息;
  • SetMessages:整体替换现有消息。

默认的 memory 实现把消息放在进程内存里,进程重启即丢失。当应用需要多实例共享、会话跨进程恢复时,就需要一个数据库后端。本示例展示的正是将 AlloyDB for PostgreSQL(Google Cloud 的托管 Postgres 兼容数据库)作为该接口实现的存储层。

准备工作:前置条件与运行环境

在运行示例前需要完成以下云环境准备(对应 memory/alloydb/README.md 中的 Quick Start 步骤):

  1. 创建或选择一个 Google Cloud 项目;
  2. 为项目启用结算(billing);
  3. 在控制台启用 AlloyDB API;
  4. 通过gcloud auth application-default login完成 Cloud SDK 认证。

代码层面,examples/go.mod 显示该示例基于go 1.24.3,依赖github.com/tmc/langchaingo v0.1.14-pre.4,并通过cloud.google.com/go/alloydbconn建立安全连接。仓库中memory/alloydb包要求Go 版本不低于 1.22.0。示例的模块声明位于examples/google-alloydb-chat-message-history-example/go.mod,进入该目录即可独立构建运行。

第一步:配置环境变量

示例程序通过环境变量注入连接信息与业务参数,运行时任何一项缺失都会以log.Fatal立即退出(见 getEnvVariables 函数):

export PROJECT_ID=<your project Id> export ALLOYDB_USERNAME=<your user> export ALLOYDB_PASSWORD=<your password> export ALLOYDB_REGION=<your region> export ALLOYDB_CLUSTER=<your cluster> export ALLOYDB_INSTANCE=<your instance> export ALLOYDB_DATABASE=<your database> export ALLOYDB_TABLE=<your tablename> export ALLOYDB_SESSION_ID=<your sessionID>

其中PROJECT_IDALLOYDB_REGIONALLOYDB_CLUSTERALLOYDB_INSTANCE用于定位 AlloyDB 实例,可在 Google Cloud 控制台的 AlloyDB 集群页面找到;ALLOYDB_TABLE指定存放消息的数据表名;ALLOYDB_SESSION_ID用于区分不同的会话,是消息读写隔离的关键。

第二步:初始化 PostgresEngine 连接引擎

连接的核心是alloydbutil.PostgresEngine,它内部持有一个*pgxpool.Pool连接池(见 util/alloydbutil/engine.go)。示例中的初始化方式:

pgEngine, err := alloydbutil.NewPostgresEngine(ctx, alloydbutil.WithUser(username), alloydbutil.WithPassword(password), alloydbutil.WithDatabase(database), alloydbutil.WithAlloyDBInstance(projectID, region, cluster, instance), ) if err != nil { log.Fatal(err) }

底层连接原理

从 createPool 实现 可以看到连接建立的完整逻辑:

  • 使用alloydbconn.NewDialer创建连接拨号器,DSN 为user=... password=... dbname=... sslmode=disable
  • 依据传入的项目、区域、集群、实例拼接出 AlloyDB 实例 URI:projects/<project>/locations/<region>/clusters/<cluster>/instances/<instance>
  • 通过自定义DialFunc调用d.Dial建立安全隧道,默认使用公网 IP(PUBLIC),可通过WithIPType("PRIVATE")切换到私网;
  • 最终基于pgxpool.NewWithConfig生成连接池。

其他可用 Option

util/alloydbutil/options.go 定义了全部引擎选项:

Option作用
WithAlloyDBInstance(project, region, cluster, instance)设置实例定位信息
WithUser/WithPassword设置数据库账号密码
WithDatabase设置目标数据库名
WithPool直接注入外部创建的pgxpool.Pool(适用于 AlloyDB Omni 或自定义连接池)
WithIPType指定公网(PUBLIC,默认)或私网(PRIVATE)连接
WithIAMAccountEmail使用 IAM 账号邮箱认证

关于认证方式,getUser 函数 展示了三种分支:优先使用用户名 + 密码;若提供WithIAMAccountEmail则走 IAM 认证(DSN 中不再含密码,并追加alloydbconn.WithIAMAuthN());若两者皆无,则尝试通过默认凭据获取服务账号邮箱。这意味着示例展示的是最简单的账号密码方式,实际生产环境还可以切换到 IAM 认证以规避口令管理。

第三步:创建消息表

AlloyDB 要求消息表具备固定结构。示例调用:

err = pgEngine.InitChatHistoryTable(ctx, tableName)

对应 InitChatHistoryTable 实现,其生成的 DDL 为:

CREATE TABLE IF NOT EXISTS "<schema>"."<table>" ( id SERIAL PRIMARY KEY, session_id TEXT NOT NULL, data JSONB NOT NULL, type TEXT NOT NULL );

表结构中的四个列与ChatMessageHistory.validateTable的校验逻辑一一对应(见 memory/alloydb/chat_message_history.go):id为整数自增主键(保证消息读取顺序),session_id用于会话隔离,data以 JSONB 存储消息正文,type记录消息类型。创建时默认使用publicschema,也可通过WithSchemaName指定自定义 schema。

第四步:创建 ChatMessageHistory 并验证表结构

cmh, err := alloydb.NewChatMessageHistory(ctx, pgEngine, tableName, sessionID) if err != nil { log.Fatal(err) }

NewChatMessageHistory 会做三件事:

  1. 校验必需参数:连接池非空、表名非空、会话 ID 非空,缺失即返回明确错误(如"table name must be provided""session ID must be provided");
  2. 应用WithSchemaName等可选配置(默认 schema 为public,见 chat_message_history_options.go);
  3. 调用validateTable查询information_schema,确认表存在且四个必需列的名称与类型完全匹配,否则返回形如error, column 'data' is missing in table 'xxx'的错误。

值得注意的是var _ schema.ChatMessageHistory = &ChatMessageHistory{}这一编译期断言(memory/alloydb/chat_message_history.go),它保证alloydb.ChatMessageHistory完整实现了上文提到的标准接口,从而可以无缝嵌入 LangChain Go 的对话链路。

第五步:消息的增、查、改、清

示例随后演示了针对同一sessionID的完整消息生命周期操作。

逐条添加消息

aiMessage := llms.AIChatMessage{Content: "test AI message"} humanMessage := llms.HumanChatMessage{Content: "test HUMAN message"} err = cmh.AddUserMessage(ctx, aiMessage.GetContent()) err = cmh.AddUserMessage(ctx, humanMessage.GetContent()) printMessages(ctx, cmh)

底层 addMessage 先将内容 JSON 序列化,再执行INSERT INTO "<schema>"."<table>" (session_id, data, type) VALUES ($1, $2, $3)。此外还提供AddMessage(接收任意llms.ChatMessage)与AddAIMessage(固定标记为 AI 类型)等便捷方法。

批量添加消息

multipleMessages := []llms.ChatMessage{ llms.AIChatMessage{Content: "first AI test message from AddMessages"}, llms.AIChatMessage{Content: "second AI test message from AddMessages"}, llms.HumanChatMessage{Content: "first HUMAN test message from AddMessages"}, } err = cmh.AddMessages(ctx, multipleMessages)

AddMessages 使用pgx.Batch把所有插入语句打包后经SendBatch一次提交,避免逐条往返的网络开销,是批量写入的高效路径。

查询消息

示例中printMessages辅助函数调用cmh.Messages(ctx)遍历输出。对应的 Messages 实现 执行SELECT ... WHERE session_id = $1 ORDER BY id,确保消息按写入顺序返回;随后反序列化 JSON 内容,并根据type字段还原为AIChatMessageHumanChatMessageSystemChatMessage。若遇到未知类型则返回"unsupported message type"错误。

覆盖消息

overWrittingMessages := []llms.ChatMessage{ llms.AIChatMessage{Content: "overwritten AI test message"}, llms.HumanChatMessage{Content: "overwritten HUMAN test message"}, } err = cmh.SetMessages(ctx, overWrittingMessages)

SetMessages 的语义是"先清空该会话旧消息,再批量写入新消息",实现上先调用Clear再走批量插入,适合重写整段对话上下文的场景。

清空会话消息

err = cmh.Clear(ctx)

Clear 执行DELETE FROM "<schema>"."<table>" WHERE session_id = $1,只删除当前会话的消息,不影响其他会话数据。

运行示例

在配置好环境变量后,进入示例目录执行:

cd examples/google-alloydb-chat-message-history-example go run google_alloydb_chat_message_history_example.go

程序会依次打印三批消息:初始添加的两条、批量追加后的五条(含前两条)、覆盖后的两条,最后清空会话。仓库中的集成测试 memory/alloydb/chat_message_history_test.go 验证了相同路径:测试用例覆盖了"表名缺失报错""会话 ID 缺失报错"以及AddMessageAddAIMessageAddUserMessageClear的正常调用链;由于需要真实数据库,测试在缺少ALLOYDB_USERNAME等环境变量时会自动t.Skip跳过。

关键特性小结

对照原示例文档,这套方案的核心价值可以归纳为:

  • AlloyDB 深度集成alloydbutil负责与 AlloyDB 实例建立安全连接池,memory/alloydb负责消息的存储与管理,职责清晰;
  • 会话级消息管理:所有读写操作都以session_id为维度,天然支持多会话并存与隔离;
  • 完整操作能力:覆盖逐条添加、批量添加、整体覆盖、查询与清空五种操作,满足对话记忆的常见需求;
  • 源码级可靠性:创建时即校验表结构与列类型,接口实现有编译期断言保障,批量操作利用pgx.Batch提升性能。

如需进一步了解引擎 API 的更多细节,可继续阅读 util/alloydbutil/options.go 与 memory/alloydb/chat_message_history_options.go;仓库中还提供了对应的 Postgres Vector Store 示例,可在同一 AlloyDB 实例上同时承载向量检索与对话记忆两类数据。

【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 18:26:27

如何用 PDFPatcher 无损提取 PDF 图片并自定义输出文件命名掩码?

如何用 PDFPatcher 无损提取 PDF 图片并自定义输出文件命名掩码&#xff1f; 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱&#xff0c;可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档&#xff0c;探查文档结构&#xff0c;提取图片、转成图片等等 项目地址: …

作者头像 李华
网站建设 2026/9/15 18:25:46

Matlab频谱与Bode图绘制:从FFT到频响验证的完整指南

简介&#xff1a;面向信号处理、通信工程与控制系统领域的初学者及工程师&#xff0c;提供一套实用的MATLAB频谱分析与Bode图绘制解决方案&#xff0c;专门解决两大高频需求&#xff1a;一是利用pwelch函数完成功率谱密度估计&#xff0c;涵盖数据读取、滤波去噪、窗函数选择与…

作者头像 李华